From 5190ffea97f528bf732af663e08d4d32580a2d4d Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 24 Mar 2016 21:10:20 +0800 Subject: [PATCH 001/173] =?UTF-8?q?lua5.3.2=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clib/mime/mime.vcxproj | 2 +- deps/lua/Makefile | 146 ++--- deps/lua/lapi.c | 603 +++++++++---------- deps/lua/lapi.h | 2 +- deps/lua/lauxlib.c | 343 ++++++----- deps/lua/lauxlib.h | 96 +++- deps/lua/lbaselib.c | 223 +++++--- deps/lua/lbitlib.c | 111 ++-- deps/lua/lcode.c | 238 +++++--- deps/lua/lcode.h | 12 +- deps/lua/lcorolib.c | 31 +- deps/lua/lctype.c | 5 +- deps/lua/lctype.h | 2 +- deps/lua/ldblib.c | 230 +++++--- deps/lua/ldebug.c | 228 +++++--- deps/lua/ldebug.h | 19 +- deps/lua/ldo.c | 380 +++++++----- deps/lua/ldo.h | 28 +- deps/lua/ldump.c | 302 +++++----- deps/lua/lfunc.c | 119 ++-- deps/lua/lfunc.h | 38 +- deps/lua/lgc.c | 925 ++++++++++++++---------------- deps/lua/lgc.h | 112 ++-- deps/lua/linit.c | 41 +- deps/lua/liolib.c | 295 ++++++---- deps/lua/llex.c | 296 ++++++---- deps/lua/llex.h | 16 +- deps/lua/llimits.h | 280 ++++----- deps/lua/lmathlib.c | 336 +++++++---- deps/lua/lmem.c | 23 +- deps/lua/lmem.h | 30 +- deps/lua/loadlib.c | 258 +++++---- deps/lua/lobject.c | 320 ++++++++--- deps/lua/lobject.h | 401 ++++++------- deps/lua/lopcodes.c | 25 +- deps/lua/lopcodes.h | 39 +- deps/lua/loslib.c | 185 ++++-- deps/lua/lparser.c | 188 +++--- deps/lua/lparser.h | 27 +- deps/lua/lprefix.h | 45 ++ deps/lua/lstate.c | 120 ++-- deps/lua/lstate.h | 157 +++-- deps/lua/lstring.c | 217 ++++--- deps/lua/lstring.h | 21 +- deps/lua/lstrlib.c | 860 ++++++++++++++++++++++------ deps/lua/ltable.c | 427 ++++++++------ deps/lua/ltable.h | 25 +- deps/lua/ltablib.c | 400 +++++++++---- deps/lua/ltm.c | 96 +++- deps/lua/ltm.h | 28 +- deps/lua/lua.c | 518 ++++++++++------- deps/lua/lua.h | 178 +++--- deps/lua/lua.vcxproj | 2 +- deps/lua/luac.c | 49 +- deps/lua/luaconf.h | 700 +++++++++++++++-------- deps/lua/lualib.h | 5 +- deps/lua/lundump.c | 428 +++++++------- deps/lua/lundump.h | 26 +- deps/lua/lutf8lib.c | 256 +++++++++ deps/lua/lvm.c | 1240 +++++++++++++++++++++++++++------------- deps/lua/lvm.h | 100 +++- deps/lua/lzio.c | 20 +- deps/lua/lzio.h | 11 +- node-lua.vcxproj | 2 +- 64 files changed, 8127 insertions(+), 4759 deletions(-) create mode 100644 deps/lua/lprefix.h create mode 100644 deps/lua/lutf8lib.c diff --git a/clib/mime/mime.vcxproj b/clib/mime/mime.vcxproj index a99b86d..ecf0c47 100644 --- a/clib/mime/mime.vcxproj +++ b/clib/mime/mime.vcxproj @@ -57,7 +57,7 @@ NotUsing Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LUA_CORE;LUA_BUILD_AS_DLL;LUA_COMPAT_MODULE;MIME_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;LUA_CORE;LUA_BUILD_AS_DLL;LUA_COMPAT_5_2;LUA_COMPAT_5_1;MIME_EXPORTS;%(PreprocessorDefinitions) true ..\..\deps\lua; diff --git a/deps/lua/Makefile b/deps/lua/Makefile index d6f872e..d445ce9 100644 --- a/deps/lua/Makefile +++ b/deps/lua/Makefile @@ -6,8 +6,8 @@ # Your platform. See PLATS for possible values. PLAT= none -CC= gcc -CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS) +CC= gcc -std=gnu99 +CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_COMPAT_5_1 $(SYSCFLAGS) $(MYCFLAGS) LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS) LIBS= -lm $(SYSLIBS) $(MYLIBS) @@ -26,7 +26,7 @@ MYOBJS= # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= -PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris +PLATS= aix c89 bsd freebsd generic linux macosx mingw posix solaris LUA_A= libnlua.a LUA_SO= libnlua.so @@ -34,7 +34,7 @@ CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ ltm.o lundump.o lvm.o lzio.o LIB_O= lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \ - lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o + lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS) LUA_T= lua @@ -95,12 +95,16 @@ none: aix: $(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall" -ansi: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_ANSI" - bsd: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E" +c89: + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89" + @echo '' + @echo '*** C89 does not guarantee 64-bit integers for Lua.' + @echo '' + + freebsd: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline" @@ -113,7 +117,7 @@ macosx: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc mingw: - $(MAKE) "LUA_A=nlua52.dll" "LUA_T=lua.exe" \ + $(MAKE) "LUA_A=nlua.dll" "LUA_T=lua.exe" \ "AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \ "SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe $(MAKE) "LUAC_T=luac.exe" luac.exe @@ -122,70 +126,76 @@ posix: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX" solaris: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl" # list targets that do not create files (but not all makes understand .PHONY) .PHONY: all $(PLATS) default o a clean depend echo none # DO NOT DELETE -lapi.o: lapi.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ - lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h ltable.h lundump.h \ +lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ + lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \ + ltable.h lundump.h lvm.h +lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h +lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +lbitlib.o: lbitlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \ + llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \ + ldo.h lgc.h lstring.h ltable.h lvm.h +lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h +ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ + lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \ + ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h +ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ + lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \ + lparser.h lstring.h ltable.h lundump.h lvm.h +ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \ + ltm.h lzio.h lmem.h lundump.h +lfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \ + lgc.h lstate.h ltm.h lzio.h lmem.h +lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ + llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h +linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h +liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \ + lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \ + lstring.h ltable.h +lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ + llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h +loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \ + ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \ lvm.h -lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h -lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h -lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h -lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ - lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \ - lstring.h ltable.h lvm.h -lcorolib.o: lcorolib.c lua.h luaconf.h lauxlib.h lualib.h -lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h -ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h -ldebug.o: ldebug.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \ - ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h ldebug.h ldo.h \ - lfunc.h lstring.h lgc.h ltable.h lvm.h -ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \ - lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \ - lstring.h ltable.h lundump.h lvm.h -ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \ - lzio.h lmem.h lundump.h -lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \ - lstate.h ltm.h lzio.h lmem.h -lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ - lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h -linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h -liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h -llex.o: llex.c lua.h luaconf.h lctype.h llimits.h ldo.h lobject.h \ - lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h -lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h -lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lgc.h -loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h -lobject.o: lobject.c lua.h luaconf.h lctype.h llimits.h ldebug.h lstate.h \ - lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lvm.h -lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h -loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h -lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \ - lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lfunc.h \ - lstring.h lgc.h ltable.h -lstate.o: lstate.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \ - ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \ - ltable.h -lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \ - ltm.h lzio.h lstring.h lgc.h -lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h -ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \ - ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h -ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h -ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \ - lmem.h lstring.h lgc.h ltable.h -lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h -luac.o: luac.c lua.h luaconf.h lauxlib.h lobject.h llimits.h lstate.h \ - ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h -lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \ - llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h -lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \ - lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h -lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \ - lzio.h - +lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h +loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \ + llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \ + ldo.h lfunc.h lstring.h lgc.h ltable.h +lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ + lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \ + lstring.h ltable.h +lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \ + lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h +lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ + llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h +ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ + llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h +lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h lobject.h llimits.h \ + lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h +lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \ + lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \ + lundump.h +lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h +lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ + llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \ + ltable.h lvm.h +lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \ + lobject.h ltm.h lzio.h + +# (end of Makefile) diff --git a/deps/lua/lapi.c b/deps/lua/lapi.c index b2510ab..38c7ec8 100644 --- a/deps/lua/lapi.c +++ b/deps/lua/lapi.c @@ -1,16 +1,18 @@ /* -** $Id: lapi.c,v 2.171.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lapi.c,v 2.257 2015/11/02 18:48:07 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ +#define lapi_c +#define LUA_CORE + +#include "lprefix.h" + #include #include -#define lapi_c -#define LUA_CORE - #include "lua.h" #include "lapi.h" @@ -26,6 +28,7 @@ #include "ltm.h" #include "lundump.h" #include "lvm.h" +#include "lfunc.h" @@ -43,13 +46,16 @@ const char lua_ident[] = /* test for pseudo index */ #define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) +/* test for upvalue */ +#define isupvalue(i) ((i) < LUA_REGISTRYINDEX) + /* test for valid but not pseudo index */ #define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) -#define api_checkvalidindex(L, o) api_check(L, isvalid(o), "invalid index") +#define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index") -#define api_checkstackindex(L, i, o) \ - api_check(L, isstackindex(i, o), "index not in the stack") +#define api_checkstackindex(l, i, o) \ + api_check(l, isstackindex(i, o), "index not in the stack") static TValue *index2addr (lua_State *L, int idx) { @@ -89,21 +95,22 @@ static void growstack (lua_State *L, void *ud) { } -LUA_API int lua_checkstack (lua_State *L, int size) { +LUA_API int lua_checkstack (lua_State *L, int n) { int res; CallInfo *ci = L->ci; lua_lock(L); - if (L->stack_last - L->top > size) /* stack large enough? */ + api_check(L, n >= 0, "negative 'n'"); + if (L->stack_last - L->top > n) /* stack large enough? */ res = 1; /* yes; check is OK */ else { /* no; need to grow stack */ int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; - if (inuse > LUAI_MAXSTACK - size) /* can grow without overflow? */ + if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ res = 0; /* no */ else /* try to grow stack */ - res = (luaD_rawrunprotected(L, &growstack, &size) == LUA_OK); + res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); } - if (res && ci->top < L->top + size) - ci->top = L->top + size; /* adjust frame top */ + if (res && ci->top < L->top + n) + ci->top = L->top + n; /* adjust frame top */ lua_unlock(L); return res; } @@ -115,10 +122,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { lua_lock(to); api_checknelems(from, n); api_check(from, G(from) == G(to), "moving among independent states"); - api_check(from, to->ci->top - to->top >= n, "not enough elements to move"); + api_check(from, to->ci->top - to->top >= n, "stack overflow"); from->top -= n; for (i = 0; i < n; i++) { - setobj2s(to, to->top++, from->top + i); + setobj2s(to, to->top, from->top + i); + to->top++; /* stack already checked by previous 'api_check' */ } lua_unlock(to); } @@ -153,7 +161,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) { LUA_API int lua_absindex (lua_State *L, int idx) { return (idx > 0 || ispseudo(idx)) ? idx - : cast_int(L->top - L->ci->func + idx); + : cast_int(L->top - L->ci->func) + idx; } @@ -173,61 +181,56 @@ LUA_API void lua_settop (lua_State *L, int idx) { } else { api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); - L->top += idx+1; /* `subtract' index (index is negative) */ + L->top += idx+1; /* 'subtract' index (index is negative) */ } lua_unlock(L); } -LUA_API void lua_remove (lua_State *L, int idx) { - StkId p; - lua_lock(L); - p = index2addr(L, idx); - api_checkstackindex(L, idx, p); - while (++p < L->top) setobjs2s(L, p-1, p); - L->top--; - lua_unlock(L); +/* +** Reverse the stack segment from 'from' to 'to' +** (auxiliary to 'lua_rotate') +*/ +static void reverse (lua_State *L, StkId from, StkId to) { + for (; from < to; from++, to--) { + TValue temp; + setobj(L, &temp, from); + setobjs2s(L, from, to); + setobj2s(L, to, &temp); + } } -LUA_API void lua_insert (lua_State *L, int idx) { - StkId p; - StkId q; +/* +** Let x = AB, where A is a prefix of length 'n'. Then, +** rotate x n == BA. But BA == (A^r . B^r)^r. +*/ +LUA_API void lua_rotate (lua_State *L, int idx, int n) { + StkId p, t, m; lua_lock(L); - p = index2addr(L, idx); + t = L->top - 1; /* end of stack segment being rotated */ + p = index2addr(L, idx); /* start of segment */ api_checkstackindex(L, idx, p); - for (q = L->top; q > p; q--) /* use L->top as a temporary */ - setobjs2s(L, q, q - 1); - setobjs2s(L, p, L->top); + api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); + m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ + reverse(L, p, m); /* reverse the prefix with length 'n' */ + reverse(L, m + 1, t); /* reverse the suffix */ + reverse(L, p, t); /* reverse the entire segment */ lua_unlock(L); } -static void moveto (lua_State *L, TValue *fr, int idx) { - TValue *to = index2addr(L, idx); +LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { + TValue *fr, *to; + lua_lock(L); + fr = index2addr(L, fromidx); + to = index2addr(L, toidx); api_checkvalidindex(L, to); setobj(L, to, fr); - if (idx < LUA_REGISTRYINDEX) /* function upvalue? */ + if (isupvalue(toidx)) /* function upvalue? */ luaC_barrier(L, clCvalue(L->ci->func), fr); /* LUA_REGISTRYINDEX does not need gc barrier (collector revisits it before finishing collection) */ -} - - -LUA_API void lua_replace (lua_State *L, int idx) { - lua_lock(L); - api_checknelems(L, 1); - moveto(L, L->top - 1, idx); - L->top--; - lua_unlock(L); -} - - -LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { - TValue *fr; - lua_lock(L); - fr = index2addr(L, fromidx); - moveto(L, fr, toidx); lua_unlock(L); } @@ -248,12 +251,13 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return (isvalid(o) ? ttypenv(o) : LUA_TNONE); + return (isvalid(o) ? ttnov(o) : LUA_TNONE); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); + api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); return ttypename(t); } @@ -264,22 +268,28 @@ LUA_API int lua_iscfunction (lua_State *L, int idx) { } +LUA_API int lua_isinteger (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return ttisinteger(o); +} + + LUA_API int lua_isnumber (lua_State *L, int idx) { - TValue n; + lua_Number n; const TValue *o = index2addr(L, idx); return tonumber(o, &n); } LUA_API int lua_isstring (lua_State *L, int idx) { - int t = lua_type(L, idx); - return (t == LUA_TSTRING || t == LUA_TNUMBER); + const TValue *o = index2addr(L, idx); + return (ttisstring(o) || cvt2str(o)); } LUA_API int lua_isuserdata (lua_State *L, int idx) { const TValue *o = index2addr(L, idx); - return (ttisuserdata(o) || ttislightuserdata(o)); + return (ttisfulluserdata(o) || ttislightuserdata(o)); } @@ -291,24 +301,17 @@ LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { LUA_API void lua_arith (lua_State *L, int op) { - StkId o1; /* 1st operand */ - StkId o2; /* 2nd operand */ lua_lock(L); - if (op != LUA_OPUNM) /* all other operations expect two operands */ - api_checknelems(L, 2); - else { /* for unary minus, add fake 2nd operand */ + if (op != LUA_OPUNM && op != LUA_OPBNOT) + api_checknelems(L, 2); /* all other operations expect two operands */ + else { /* for unary operations, add fake 2nd operand */ api_checknelems(L, 1); setobjs2s(L, L->top, L->top - 1); - L->top++; - } - o1 = L->top - 2; - o2 = L->top - 1; - if (ttisnumber(o1) && ttisnumber(o2)) { - setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); + api_incr_top(L); } - else - luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD)); - L->top--; + /* first operand at top - 2, second at top - 1; result go to top - 2 */ + luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); + L->top--; /* remove second operand */ lua_unlock(L); } @@ -321,7 +324,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { o2 = index2addr(L, index2); if (isvalid(o1) && isvalid(o2)) { switch (op) { - case LUA_OPEQ: i = equalobj(L, o1, o2); break; + case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; default: api_check(L, 0, "invalid option"); @@ -332,51 +335,33 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { } -LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *isnum) { - TValue n; - const TValue *o = index2addr(L, idx); - if (tonumber(o, &n)) { - if (isnum) *isnum = 1; - return nvalue(o); - } - else { - if (isnum) *isnum = 0; - return 0; - } +LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { + size_t sz = luaO_str2num(s, L->top); + if (sz != 0) + api_incr_top(L); + return sz; } -LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum) { - TValue n; +LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { + lua_Number n; const TValue *o = index2addr(L, idx); - if (tonumber(o, &n)) { - lua_Integer res; - lua_Number num = nvalue(o); - lua_number2integer(res, num); - if (isnum) *isnum = 1; - return res; - } - else { - if (isnum) *isnum = 0; - return 0; - } + int isnum = tonumber(o, &n); + if (!isnum) + n = 0; /* call to 'tonumber' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return n; } -LUA_API lua_Unsigned lua_tounsignedx (lua_State *L, int idx, int *isnum) { - TValue n; +LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { + lua_Integer res; const TValue *o = index2addr(L, idx); - if (tonumber(o, &n)) { - lua_Unsigned res; - lua_Number num = nvalue(o); - lua_number2unsigned(res, num); - if (isnum) *isnum = 1; - return res; - } - else { - if (isnum) *isnum = 0; - return 0; - } + int isnum = tointeger(o, &res); + if (!isnum) + res = 0; /* call to 'tointeger' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return res; } @@ -389,25 +374,27 @@ LUA_API int lua_toboolean (lua_State *L, int idx) { LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { StkId o = index2addr(L, idx); if (!ttisstring(o)) { - lua_lock(L); /* `luaV_tostring' may create a new string */ - if (!luaV_tostring(L, o)) { /* conversion failed? */ + if (!cvt2str(o)) { /* not convertible? */ if (len != NULL) *len = 0; - lua_unlock(L); return NULL; } + lua_lock(L); /* 'luaO_tostring' may create a new string */ luaC_checkGC(L); o = index2addr(L, idx); /* previous call may reallocate the stack */ + luaO_tostring(L, o); lua_unlock(L); } - if (len != NULL) *len = tsvalue(o)->len; + if (len != NULL) + *len = vslen(o); return svalue(o); } LUA_API size_t lua_rawlen (lua_State *L, int idx) { StkId o = index2addr(L, idx); - switch (ttypenv(o)) { - case LUA_TSTRING: return tsvalue(o)->len; + switch (ttype(o)) { + case LUA_TSHRSTR: return tsvalue(o)->shrlen; + case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); default: return 0; @@ -426,8 +413,8 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { LUA_API void *lua_touserdata (lua_State *L, int idx) { StkId o = index2addr(L, idx); - switch (ttypenv(o)) { - case LUA_TUSERDATA: return (rawuvalue(o) + 1); + switch (ttnov(o)) { + case LUA_TUSERDATA: return getudatamem(uvalue(o)); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } @@ -448,9 +435,8 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) { case LUA_TCCL: return clCvalue(o); case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - return lua_touserdata(L, idx); + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } } @@ -472,9 +458,7 @@ LUA_API void lua_pushnil (lua_State *L) { LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { lua_lock(L); - setnvalue(L->top, n); - luai_checknum(L, L->top, - luaG_runerror(L, "C API - attempt to push a signaling NaN")); + setfltvalue(L->top, n); api_incr_top(L); lua_unlock(L); } @@ -482,27 +466,22 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { lua_lock(L); - setnvalue(L->top, cast_num(n)); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushunsigned (lua_State *L, lua_Unsigned u) { - lua_Number n; - lua_lock(L); - n = lua_unsigned2number(u); - setnvalue(L->top, n); + setivalue(L->top, n); api_incr_top(L); lua_unlock(L); } +/* +** Pushes on the stack a string with given length. Avoid using 's' when +** 'len' == 0 (as 's' can be NULL in that case), due to later use of +** 'memcmp' and 'memcpy'. +*/ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { TString *ts; lua_lock(L); luaC_checkGC(L); - ts = luaS_newlstr(L, s, len); + ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); setsvalue2s(L, L->top, ts); api_incr_top(L); lua_unlock(L); @@ -511,20 +490,19 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { LUA_API const char *lua_pushstring (lua_State *L, const char *s) { - if (s == NULL) { - lua_pushnil(L); - return NULL; - } + lua_lock(L); + if (s == NULL) + setnilvalue(L->top); else { TString *ts; - lua_lock(L); luaC_checkGC(L); ts = luaS_new(L, s); setsvalue2s(L, L->top, ts); - api_incr_top(L); - lua_unlock(L); - return getstr(ts); + s = getstr(ts); /* internal copy's address */ } + api_incr_top(L); + lua_unlock(L); + return s; } @@ -558,15 +536,17 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { setfvalue(L->top, fn); } else { - Closure *cl; + CClosure *cl; api_checknelems(L, n); api_check(L, n <= MAXUPVAL, "upvalue index too large"); luaC_checkGC(L); cl = luaF_newCclosure(L, n); - cl->c.f = fn; + cl->f = fn; L->top -= n; - while (n--) - setobj2n(L, &cl->c.upvalue[n], L->top + n); + while (n--) { + setobj2n(L, &cl->upvalue[n], L->top + n); + /* does not need barrier because closure is white */ + } setclCvalue(L, L->top, cl); } api_incr_top(L); @@ -605,48 +585,77 @@ LUA_API int lua_pushthread (lua_State *L) { */ -LUA_API void lua_getglobal (lua_State *L, const char *var) { +static int auxgetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *aux; + TString *str = luaS_new(L, k); + if (luaV_fastget(L, t, str, aux, luaH_getstr)) { + setobj2s(L, L->top, aux); + api_incr_top(L); + } + else { + setsvalue2s(L, L->top, str); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, aux); + } + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_getglobal (lua_State *L, const char *name) { Table *reg = hvalue(&G(L)->l_registry); - const TValue *gt; /* global table */ lua_lock(L); - gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - setsvalue2s(L, L->top++, luaS_new(L, var)); - luaV_gettable(L, gt, L->top - 1, L->top - 1); - lua_unlock(L); + return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } -LUA_API void lua_gettable (lua_State *L, int idx) { +LUA_API int lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { +LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { + lua_lock(L); + return auxgetstr(L, index2addr(L, idx), k); +} + + +LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { StkId t; + const TValue *aux; lua_lock(L); t = index2addr(L, idx); - setsvalue2s(L, L->top, luaS_new(L, k)); - api_incr_top(L); - luaV_gettable(L, t, L->top - 1, L->top - 1); + if (luaV_fastget(L, t, n, aux, luaH_getint)) { + setobj2s(L, L->top, aux); + api_incr_top(L); + } + else { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, aux); + } lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API void lua_rawget (lua_State *L, int idx) { +LUA_API int lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { +LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { StkId t; lua_lock(L); t = index2addr(L, idx); @@ -654,10 +663,11 @@ LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { setobj2s(L, L->top, luaH_getint(hvalue(t), n)); api_incr_top(L); lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) { +LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { StkId t; TValue k; lua_lock(L); @@ -667,6 +677,7 @@ LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) { setobj2s(L, L->top, luaH_get(hvalue(t), &k)); api_incr_top(L); lua_unlock(L); + return ttnov(L->top - 1); } @@ -685,11 +696,11 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { LUA_API int lua_getmetatable (lua_State *L, int objindex) { const TValue *obj; - Table *mt = NULL; - int res; + Table *mt; + int res = 0; lua_lock(L); obj = index2addr(L, objindex); - switch (ttypenv(obj)) { + switch (ttnov(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; break; @@ -697,12 +708,10 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { mt = uvalue(obj)->metatable; break; default: - mt = G(L)->mt[ttypenv(obj)]; + mt = G(L)->mt[ttnov(obj)]; break; } - if (mt == NULL) - res = 0; - else { + if (mt != NULL) { sethvalue(L, L->top, mt); api_incr_top(L); res = 1; @@ -712,17 +721,15 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { } -LUA_API void lua_getuservalue (lua_State *L, int idx) { +LUA_API int lua_getuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); - api_check(L, ttisuserdata(o), "userdata expected"); - if (uvalue(o)->env) { - sethvalue(L, L->top, uvalue(o)->env); - } else - setnilvalue(L->top); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + getuservalue(L, uvalue(o), L->top); api_incr_top(L); lua_unlock(L); + return ttnov(L->top - 1); } @@ -730,17 +737,29 @@ LUA_API void lua_getuservalue (lua_State *L, int idx) { ** set functions (stack -> Lua) */ +/* +** t[k] = value at the top of the stack (where 'k' is a string) +*/ +static void auxsetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *aux; + TString *str = luaS_new(L, k); + api_checknelems(L, 1); + if (luaV_fastset(L, t, str, aux, luaH_getstr, L->top - 1)) + L->top--; /* pop value */ + else { + setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, aux); + L->top -= 2; /* pop value and key */ + } + lua_unlock(L); /* lock done by caller */ +} -LUA_API void lua_setglobal (lua_State *L, const char *var) { + +LUA_API void lua_setglobal (lua_State *L, const char *name) { Table *reg = hvalue(&G(L)->l_registry); - const TValue *gt; /* global table */ - lua_lock(L); - api_checknelems(L, 1); - gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - setsvalue2s(L, L->top++, luaS_new(L, var)); - luaV_settable(L, gt, L->top - 1, L->top - 2); - L->top -= 2; /* pop value and key */ - lua_unlock(L); + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } @@ -756,54 +775,69 @@ LUA_API void lua_settable (lua_State *L, int idx) { LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, index2addr(L, idx), k); +} + + +LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { StkId t; + const TValue *aux; lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); - setsvalue2s(L, L->top++, luaS_new(L, k)); - luaV_settable(L, t, L->top - 1, L->top - 2); - L->top -= 2; /* pop value and key */ + if (luaV_fastset(L, t, n, aux, luaH_getint, L->top - 1)) + L->top--; /* pop value */ + else { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, aux); + L->top -= 2; /* pop value and key */ + } lua_unlock(L); } LUA_API void lua_rawset (lua_State *L, int idx) { - StkId t; + StkId o; + TValue *slot; lua_lock(L); api_checknelems(L, 2); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); - invalidateTMcache(hvalue(t)); - luaC_barrierback(L, gcvalue(t), L->top-1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + slot = luaH_set(L, hvalue(o), L->top - 2); + setobj2t(L, slot, L->top - 1); + invalidateTMcache(hvalue(o)); + luaC_barrierback(L, hvalue(o), L->top-1); L->top -= 2; lua_unlock(L); } -LUA_API void lua_rawseti (lua_State *L, int idx, int n) { - StkId t; +LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { + StkId o; lua_lock(L); api_checknelems(L, 1); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - luaH_setint(L, hvalue(t), n, L->top - 1); - luaC_barrierback(L, gcvalue(t), L->top-1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + luaH_setint(L, hvalue(o), n, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { - StkId t; - TValue k; + StkId o; + TValue k, *slot; lua_lock(L); api_checknelems(L, 1); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); setpvalue(&k, cast(void *, p)); - setobj2t(L, luaH_set(L, hvalue(t), &k), L->top - 1); - luaC_barrierback(L, gcvalue(t), L->top - 1); + slot = luaH_set(L, hvalue(o), &k); + setobj2t(L, slot, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top - 1); L->top--; lua_unlock(L); } @@ -821,11 +855,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { api_check(L, ttistable(L->top - 1), "table expected"); mt = hvalue(L->top - 1); } - switch (ttypenv(obj)) { + switch (ttnov(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) { - luaC_objbarrierback(L, gcvalue(obj), mt); + luaC_objbarrier(L, gcvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); } break; @@ -833,13 +867,13 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; if (mt) { - luaC_objbarrier(L, rawuvalue(obj), mt); + luaC_objbarrier(L, uvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); } break; } default: { - G(L)->mt[ttypenv(obj)] = mt; + G(L)->mt[ttnov(obj)] = mt; break; } } @@ -854,21 +888,16 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); - api_check(L, ttisuserdata(o), "userdata expected"); - if (ttisnil(L->top - 1)) - uvalue(o)->env = NULL; - else { - api_check(L, ttistable(L->top - 1), "table expected"); - uvalue(o)->env = hvalue(L->top - 1); - luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); - } + api_check(L, ttisfulluserdata(o), "full userdata expected"); + setuservalue(L, uvalue(o), L->top - 1); + luaC_barrier(L, gcvalue(o), L->top - 1); L->top--; lua_unlock(L); } /* -** `load' and `call' functions (run Lua code) +** 'load' and 'call' functions (run Lua code) */ @@ -877,17 +906,8 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) { "results from function overflow current stack size") -LUA_API int lua_getctx (lua_State *L, int *ctx) { - if (L->ci->callstatus & CIST_YIELDED) { - if (ctx) *ctx = L->ci->u.c.ctx; - return L->ci->u.c.status; - } - else return LUA_OK; -} - - -LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, - lua_CFunction k) { +LUA_API void lua_callk (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k) { StkId func; lua_lock(L); api_check(L, k == NULL || !isLua(L->ci), @@ -899,10 +919,10 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ L->ci->u.c.k = k; /* save continuation */ L->ci->u.c.ctx = ctx; /* save context */ - luaD_call(L, func, nresults, 1); /* do the call */ + luaD_call(L, func, nresults); /* do the call */ } else /* no continuation or no yieldable */ - luaD_call(L, func, nresults, 0); /* just do the call */ + luaD_callnoyield(L, func, nresults); /* just do the call */ adjustresults(L, nresults); lua_unlock(L); } @@ -912,7 +932,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, /* ** Execute a protected call. */ -struct CallS { /* data to `f_call' */ +struct CallS { /* data to 'f_call' */ StkId func; int nresults; }; @@ -920,13 +940,13 @@ struct CallS { /* data to `f_call' */ static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); - luaD_call(L, c->func, c->nresults, 0); + luaD_callnoyield(L, c->func, c->nresults); } LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, - int ctx, lua_CFunction k) { + lua_KContext ctx, lua_KFunction k) { struct CallS c; int status; ptrdiff_t func; @@ -954,12 +974,11 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, ci->u.c.ctx = ctx; /* save context */ /* save information for error recovery */ ci->extra = savestack(L, c.func); - ci->u.c.old_allowhook = L->allowhook; ci->u.c.old_errfunc = L->errfunc; L->errfunc = func; - /* mark that function may do error recovery */ - ci->callstatus |= CIST_YPCALL; - luaD_call(L, c.func, nresults, 1); /* do the call */ + setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ + ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ + luaD_call(L, c.func, nresults); /* do the call */ ci->callstatus &= ~CIST_YPCALL; L->errfunc = ci->u.c.old_errfunc; status = LUA_OK; /* if it is here, there were no errors */ @@ -980,13 +999,13 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, status = luaD_protectedparser(L, &z, chunkname, mode); if (status == LUA_OK) { /* no errors? */ LClosure *f = clLvalue(L->top - 1); /* get newly created function */ - if (f->nupvalues == 1) { /* does it have one upvalue? */ + if (f->nupvalues >= 1) { /* does it have an upvalue? */ /* get global table from registry */ Table *reg = hvalue(&G(L)->l_registry); const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ setobj(L, f->upvals[0]->v, gt); - luaC_barrier(L, f->upvals[0], gt); + luaC_upvalbarrier(L, f->upvals[0]); } } lua_unlock(L); @@ -1022,9 +1041,8 @@ cloneproto (lua_State *L, const Proto *src) { } LUA_API void lua_clonefunction (lua_State *L, const void * fp) { - int i; - Closure *cl; - const LClosure *f = cast(const LClosure *, fp); + LClosure *cl; + LClosure *f = cast(LClosure *, fp); lua_lock(L); if (f->p->sp->l_G == G(L)) { setclLvalue(L,L->top,f); @@ -1033,21 +1051,18 @@ LUA_API void lua_clonefunction (lua_State *L, const void * fp) { return; } cl = luaF_newLclosure(L,f->nupvalues); - cl->l.p = cloneproto(L, f->p); + cl->p = cloneproto(L, f->p); setclLvalue(L,L->top,cl); api_incr_top(L); - for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ - UpVal *up = luaF_newupval(L); - cl->l.upvals[i] = up; - luaC_objbarrier(L, cl, up); - } - if (f->nupvalues == 1) { /* does it have one upvalue? */ + luaF_initupvals(L, cl); + + if (cl->nupvalues >= 1) { /* does it have an upvalue? */ /* get global table from registry */ Table *reg = hvalue(&G(L)->l_registry); const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - /* set global table as 1st upvalue of 'cl' (may be LUA_ENV) */ - setobj(L, cl->l.upvals[0]->v, gt); - luaC_barrier(L, cl->l.upvals[0], gt); + /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ + setobj(L, cl->upvals[0]->v, gt); + luaC_upvalbarrier(L, cl->upvals[0]); } lua_unlock(L); } @@ -1057,16 +1072,14 @@ lua_initsharedproto(lua_State *L, Proto *p, const TValue *val, const TValue *gt) int i; TValue cl; UpVal *up; - Closure *pcl = luaF_newLclosure(L, 1); - pcl->l.p = p; + LClosure *pcl = luaF_newLclosure(L, 1); + pcl->p = p; p->sp->refnum = 2; //initial as 2 p->sp->closure = pcl; - up = luaF_newupval(L); - pcl->l.upvals[0] = up; - luaC_objbarrier(L, pcl, up); - setobj(L, up->v, gt); - luaC_barrier(L, up, gt); + luaF_initupvals(L, pcl); + setobj(L, pcl->upvals[0]->v, gt); + luaC_upvalbarrier(L, pcl->upvals[0]); setclLvalue(L, &cl, pcl); setobj2t(L, luaH_set(L, hvalue(gt), &cl), val); @@ -1197,14 +1210,14 @@ LUA_API void lua_unrefsharedclosure(void *f) { } #endif -LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { int status; TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; if (isLfunction(o)) - status = luaU_dump(L, getproto(o), writer, data, 0); + status = luaU_dump(L, getproto(o), writer, data, strip); else status = 1; lua_unlock(L); @@ -1250,19 +1263,21 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCSTEP: { - if (g->gckind == KGC_GEN) { /* generational mode? */ - res = (g->GCestimate == 0); /* true if it will do major collection */ - luaC_forcestep(L); /* do a single step */ + l_mem debt = 1; /* =1 to signal that it did an actual step */ + lu_byte oldrunning = g->gcrunning; + g->gcrunning = 1; /* allow GC to run */ + if (data == 0) { + luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ + luaC_step(L); } - else { - lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE; - if (g->gcrunning) - debt += g->GCdebt; /* include current debt */ - luaE_setdebt(g, debt); - luaC_forcestep(L); - if (g->gcstate == GCSpause) /* end of cycle? */ - res = 1; /* signal it */ + else { /* add 'data' to total debt */ + debt = cast(l_mem, data) * 1024 + g->GCdebt; + luaE_setdebt(g, debt); + luaC_checkGC(L); } + g->gcrunning = oldrunning; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ break; } case LUA_GCSETPAUSE: { @@ -1270,13 +1285,9 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g->gcpause = data; break; } - case LUA_GCSETMAJORINC: { - res = g->gcmajorinc; - g->gcmajorinc = data; - break; - } case LUA_GCSETSTEPMUL: { res = g->gcstepmul; + if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ g->gcstepmul = data; break; } @@ -1284,14 +1295,6 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { res = g->gcrunning; break; } - case LUA_GCGEN: { /* change collector to generational mode */ - luaC_changemode(L, KGC_GEN); - break; - } - case LUA_GCINC: { /* change collector to incremental mode */ - luaC_changemode(L, KGC_NORMAL); - break; - } default: res = -1; /* invalid option */ } lua_unlock(L); @@ -1379,23 +1382,23 @@ LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); - u = luaS_newudata(L, size, NULL); + u = luaS_newudata(L, size); setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); - return u + 1; + return getudatamem(u); } static const char *aux_upvalue (StkId fi, int n, TValue **val, - GCObject **owner) { + CClosure **owner, UpVal **uv) { switch (ttype(fi)) { case LUA_TCCL: { /* C closure */ CClosure *f = clCvalue(fi); if (!(1 <= n && n <= f->nupvalues)) return NULL; *val = &f->upvalue[n-1]; - if (owner) *owner = obj2gco(f); + if (owner) *owner = f; return ""; } case LUA_TLCL: { /* Lua closure */ @@ -1404,9 +1407,9 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, SharedProto *p = f->p->sp; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->upvals[n-1]->v; - if (owner) *owner = obj2gco(f->upvals[n - 1]); + if (uv) *uv = f->upvals[n - 1]; name = p->upvalues[n-1].name; - return (name == NULL) ? "" : getstr(name); + return (name == NULL) ? "(*no name)" : getstr(name); } default: return NULL; /* not a closure */ } @@ -1417,7 +1420,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val = NULL; /* to avoid warnings */ lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -1430,16 +1433,18 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val = NULL; /* to avoid warnings */ - GCObject *owner = NULL; /* to avoid warnings */ + CClosure *owner = NULL; + UpVal *uv = NULL; StkId fi; lua_lock(L); fi = index2addr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val, &owner); + name = aux_upvalue(fi, n, &val, &owner, &uv); if (name) { L->top--; setobj(L, val, L->top); - luaC_barrier(L, owner, L->top); + if (owner) { luaC_barrier(L, owner, L->top); } + else if (uv) { luaC_upvalbarrier(L, uv); } } lua_unlock(L); return name; @@ -1451,7 +1456,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { StkId fi = index2addr(L, fidx); api_check(L, ttisLclosure(fi), "Lua function expected"); f = clLvalue(fi); - api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); + api_check(L, (1 <= n && n <= f->p->sp->sizeupvalues), "invalid upvalue index"); if (pf) *pf = f; return &f->upvals[n - 1]; /* get its upvalue pointer */ } @@ -1481,7 +1486,11 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, LClosure *f1; UpVal **up1 = getupvalref(L, fidx1, n1, &f1); UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + luaC_upvdeccount(L, *up1); *up1 = *up2; - luaC_objbarrier(L, f1, *up2); + (*up1)->refcount++; + if (upisopen(*up1)) (*up1)->u.open.touched = 1; + luaC_upvalbarrier(L, *up1); } + diff --git a/deps/lua/lapi.h b/deps/lua/lapi.h index c7d34ad..6d36dee 100644 --- a/deps/lua/lapi.h +++ b/deps/lua/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ diff --git a/deps/lua/lauxlib.c b/deps/lua/lauxlib.c index a0e09ca..0915e33 100644 --- a/deps/lua/lauxlib.c +++ b/deps/lua/lauxlib.c @@ -1,9 +1,14 @@ /* -** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lauxlib.c,v 1.284 2015/11/19 19:16:22 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ +#define lauxlib_c +#define LUA_LIB + +#include "lprefix.h" + #include #include @@ -16,9 +21,6 @@ ** Any function declared here could be written as an application function. */ -#define lauxlib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -31,8 +33,8 @@ */ -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ +#define LEVELS1 10 /* size of the first part of the stack */ +#define LEVELS2 11 /* size of the second part of the stack */ @@ -64,11 +66,20 @@ static int findfield (lua_State *L, int objidx, int level) { } +/* +** Search for a name for a function in all loaded modules +** (registry._LOADED). +*/ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ - lua_pushglobaltable(L); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); if (findfield(L, top + 1, 2)) { + const char *name = lua_tostring(L, -1); + if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ + lua_pushstring(L, name + 3); /* push name without prefix */ + lua_remove(L, -2); /* remove original name */ + } lua_copy(L, -1, top + 1); /* move name to proper place */ lua_pop(L, 2); /* remove pushed values */ return 1; @@ -81,24 +92,22 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { static void pushfuncname (lua_State *L, lua_Debug *ar) { - if (*ar->namewhat != '\0') /* is there a name? */ - lua_pushfstring(L, "function " LUA_QS, ar->name); + if (pushglobalfuncname(L, ar)) { /* try first a global name */ + lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else if (*ar->namewhat != '\0') /* is there a name from code? */ + lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ else if (*ar->what == 'm') /* main? */ lua_pushliteral(L, "main chunk"); - else if (*ar->what == 'C') { - if (pushglobalfuncname(L, ar)) { - lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); - lua_remove(L, -2); /* remove name */ - } - else - lua_pushliteral(L, "?"); - } - else + else if (*ar->what != 'C') /* for Lua functions, use */ lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); + else /* nothing left... */ + lua_pushliteral(L, "?"); } -static int countlevels (lua_State *L) { +static int lastlevel (lua_State *L) { lua_Debug ar; int li = 1, le = 1; /* find an upper bound */ @@ -117,14 +126,16 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level) { lua_Debug ar; int top = lua_gettop(L); - int numlevels = countlevels(L1); - int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; - if (msg) lua_pushfstring(L, "%s\n", msg); + int last = lastlevel(L1); + int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; + if (msg) + lua_pushfstring(L, "%s\n", msg); + luaL_checkstack(L, 10, NULL); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { - if (level == mark) { /* too many levels? */ + if (n1-- == 0) { /* too many levels? */ lua_pushliteral(L, "\n\t..."); /* add a '...' */ - level = numlevels - LEVELS2; /* and skip to last ones */ + level = last - LEVELS2 + 1; /* and skip to last ones */ } else { lua_getinfo(L1, "Slnt", &ar); @@ -150,33 +161,40 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, ** ======================================================= */ -LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { +LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ - return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); + return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { - narg--; /* do not count `self' */ - if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling " LUA_QS " on bad self (%s)", + arg--; /* do not count 'self' */ + if (arg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling '%s' on bad self (%s)", ar.name, extramsg); } if (ar.name == NULL) ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; - return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", - narg, ar.name, extramsg); + return luaL_error(L, "bad argument #%d to '%s' (%s)", + arg, ar.name, extramsg); } -static int typeerror (lua_State *L, int narg, const char *tname) { - const char *msg = lua_pushfstring(L, "%s expected, got %s", - tname, luaL_typename(L, narg)); - return luaL_argerror(L, narg, msg); +static int typeerror (lua_State *L, int arg, const char *tname) { + const char *msg; + const char *typearg; /* name for the type of the actual argument */ + if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) + typearg = lua_tostring(L, -1); /* use the given type name */ + else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) + typearg = "light userdata"; /* special name for messages */ + else + typearg = luaL_typename(L, arg); /* standard name */ + msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); + return luaL_argerror(L, arg, msg); } -static void tag_error (lua_State *L, int narg, int tag) { - typeerror(L, narg, lua_typename(L, tag)); +static void tag_error (lua_State *L, int arg, int tag) { + typeerror(L, arg, lua_typename(L, tag)); } @@ -222,7 +240,7 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { } -#if !defined(inspectstat) /* { */ +#if !defined(l_inspectstat) /* { */ #if defined(LUA_USE_POSIX) @@ -231,13 +249,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { /* ** use appropriate macros to interpret 'pclose' return status */ -#define inspectstat(stat,what) \ +#define l_inspectstat(stat,what) \ if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } #else -#define inspectstat(stat,what) /* no op */ +#define l_inspectstat(stat,what) /* no op */ #endif @@ -249,7 +267,7 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) { if (stat == -1) /* error? */ return luaL_fileresult(L, 0, NULL); else { - inspectstat(stat, what); /* interpret result */ + l_inspectstat(stat, what); /* interpret result */ if (*what == 'e' && stat == 0) /* successful termination? */ lua_pushboolean(L, 1); else @@ -270,11 +288,12 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) { */ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - luaL_getmetatable(L, tname); /* try to get metatable */ - if (!lua_isnil(L, -1)) /* name already in use? */ + if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); - lua_newtable(L); /* create metatable */ + lua_createtable(L, 0, 2); /* create metatable */ + lua_pushstring(L, tname); + lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; @@ -317,16 +336,16 @@ LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { ** ======================================================= */ -LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, +LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, narg, def) : - luaL_checkstring(L, narg); + const char *name = (def) ? luaL_optstring(L, arg, def) : + luaL_checkstring(L, arg); int i; for (i=0; lst[i]; i++) if (strcmp(lst[i], name) == 0) return i; - return luaL_argerror(L, narg, - lua_pushfstring(L, "invalid option " LUA_QS, name)); + return luaL_argerror(L, arg, + lua_pushfstring(L, "invalid option '%s'", name)); } @@ -342,77 +361,71 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { } -LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { - if (lua_type(L, narg) != t) - tag_error(L, narg, t); +LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { + if (lua_type(L, arg) != t) + tag_error(L, arg, t); } -LUALIB_API void luaL_checkany (lua_State *L, int narg) { - if (lua_type(L, narg) == LUA_TNONE) - luaL_argerror(L, narg, "value expected"); +LUALIB_API void luaL_checkany (lua_State *L, int arg) { + if (lua_type(L, arg) == LUA_TNONE) + luaL_argerror(L, arg, "value expected"); } -LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { - const char *s = lua_tolstring(L, narg, len); - if (!s) tag_error(L, narg, LUA_TSTRING); +LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { + const char *s = lua_tolstring(L, arg, len); + if (!s) tag_error(L, arg, LUA_TSTRING); return s; } -LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, +LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, const char *def, size_t *len) { - if (lua_isnoneornil(L, narg)) { + if (lua_isnoneornil(L, arg)) { if (len) *len = (def ? strlen(def) : 0); return def; } - else return luaL_checklstring(L, narg, len); + else return luaL_checklstring(L, arg, len); } -LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { int isnum; - lua_Number d = lua_tonumberx(L, narg, &isnum); + lua_Number d = lua_tonumberx(L, arg, &isnum); if (!isnum) - tag_error(L, narg, LUA_TNUMBER); + tag_error(L, arg, LUA_TNUMBER); return d; } -LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { - return luaL_opt(L, luaL_checknumber, narg, def); +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, arg, def); } -LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { - int isnum; - lua_Integer d = lua_tointegerx(L, narg, &isnum); - if (!isnum) - tag_error(L, narg, LUA_TNUMBER); - return d; +static void interror (lua_State *L, int arg) { + if (lua_isnumber(L, arg)) + luaL_argerror(L, arg, "number has no integer representation"); + else + tag_error(L, arg, LUA_TNUMBER); } -LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) { +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { int isnum; - lua_Unsigned d = lua_tounsignedx(L, narg, &isnum); - if (!isnum) - tag_error(L, narg, LUA_TNUMBER); + lua_Integer d = lua_tointegerx(L, arg, &isnum); + if (!isnum) { + interror(L, arg); + } return d; } -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, lua_Integer def) { - return luaL_opt(L, luaL_checkinteger, narg, def); -} - - -LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg, - lua_Unsigned def) { - return luaL_opt(L, luaL_checkunsigned, narg, def); + return luaL_opt(L, luaL_checkinteger, arg, def); } /* }====================================================== */ @@ -424,6 +437,47 @@ LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg, ** ======================================================= */ +/* userdata to box arbitrary data */ +typedef struct UBox { + void *box; + size_t bsize; +} UBox; + + +static void *resizebox (lua_State *L, int idx, size_t newsize) { + void *ud; + lua_Alloc allocf = lua_getallocf(L, &ud); + UBox *box = (UBox *)lua_touserdata(L, idx); + void *temp = allocf(ud, box->box, box->bsize, newsize); + if (temp == NULL && newsize > 0) { /* allocation error? */ + resizebox(L, idx, 0); /* free buffer */ + luaL_error(L, "not enough memory for buffer allocation"); + } + box->box = temp; + box->bsize = newsize; + return temp; +} + + +static int boxgc (lua_State *L) { + resizebox(L, 1, 0); + return 0; +} + + +static void *newbox (lua_State *L, size_t newsize) { + UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox)); + box->box = NULL; + box->bsize = 0; + if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */ + lua_pushcfunction(L, boxgc); + lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */ + } + lua_setmetatable(L, -2); + return resizebox(L, -1, newsize); +} + + /* ** check whether buffer is using a userdata on the stack as a temporary ** buffer @@ -444,11 +498,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { if (newsize < B->n || newsize - B->n < sz) luaL_error(L, "buffer too large"); /* create larger buffer */ - newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char)); - /* move content to new buffer */ - memcpy(newbuff, B->b, B->n * sizeof(char)); if (buffonstack(B)) - lua_remove(L, -2); /* remove old buffer */ + newbuff = (char *)resizebox(L, -1, newsize); + else { /* no buffer yet */ + newbuff = (char *)newbox(L, newsize); + memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ + } B->b = newbuff; B->size = newsize; } @@ -457,9 +512,11 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - char *b = luaL_prepbuffsize(B, l); - memcpy(b, s, l * sizeof(char)); - luaL_addsize(B, l); + if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ + char *b = luaL_prepbuffsize(B, l); + memcpy(b, s, l * sizeof(char)); + luaL_addsize(B, l); + } } @@ -471,8 +528,10 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { LUALIB_API void luaL_pushresult (luaL_Buffer *B) { lua_State *L = B->L; lua_pushlstring(L, B->b, B->n); - if (buffonstack(B)) - lua_remove(L, -2); /* remove old buffer */ + if (buffonstack(B)) { + resizebox(L, -2, 0); /* delete old buffer */ + lua_remove(L, -2); /* remove its header from the stack */ + } } @@ -523,7 +582,7 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* `nil' has a unique fixed reference */ + return LUA_REFNIL; /* 'nil' has a unique fixed reference */ } t = lua_absindex(L, t); lua_rawgeti(L, t, freelist); /* get first free element */ @@ -562,7 +621,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { typedef struct LoadF { int n; /* number of pre-read characters */ FILE *f; /* file being read */ - char buff[LUAL_BUFFERSIZE]; /* area for reading file */ + char buff[BUFSIZ]; /* area for reading file */ } LoadF; @@ -594,7 +653,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) { static int skipBOM (LoadF *lf) { - const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */ + const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ int c; lf->n = 0; do { @@ -654,7 +713,7 @@ static int luaL_loadfilex_raw (lua_State *L, const char *filename, const char *m readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { - lua_settop(L, fnameindex); /* ignore results from `lua_load' */ + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ return errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); @@ -697,23 +756,23 @@ LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ - return 0; - lua_pushstring(L, event); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { - lua_pop(L, 2); /* remove metatable and metafield */ - return 0; - } + return LUA_TNIL; else { - lua_remove(L, -2); /* remove only metatable */ - return 1; + int tt; + lua_pushstring(L, event); + tt = lua_rawget(L, -2); + if (tt == LUA_TNIL) /* is metafield nil? */ + lua_pop(L, 2); /* remove metatable and metafield */ + else + lua_remove(L, -2); /* remove only metatable */ + return tt; /* return metafield type */ } } LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { obj = lua_absindex(L, obj); - if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ + if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ return 0; lua_pushvalue(L, obj); lua_call(L, 1, 1); @@ -721,13 +780,13 @@ LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { } -LUALIB_API int luaL_len (lua_State *L, int idx) { - int l; +LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { + lua_Integer l; int isnum; lua_len(L, idx); - l = (int)lua_tointegerx(L, -1, &isnum); + l = lua_tointegerx(L, -1, &isnum); if (!isnum) - luaL_error(L, "object length is not a number"); + luaL_error(L, "object length is not an integer"); lua_pop(L, 1); /* remove object */ return l; } @@ -736,7 +795,13 @@ LUALIB_API int luaL_len (lua_State *L, int idx) { LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ switch (lua_type(L, idx)) { - case LUA_TNUMBER: + case LUA_TNUMBER: { + if (lua_isinteger(L, idx)) + lua_pushfstring(L, "%I", lua_tointeger(L, idx)); + else + lua_pushfstring(L, "%f", lua_tonumber(L, idx)); + break; + } case LUA_TSTRING: lua_pushvalue(L, idx); break; @@ -771,8 +836,7 @@ static const char *luaL_findtable (lua_State *L, int idx, e = strchr(fname, '.'); if (e == NULL) e = fname + strlen(fname); lua_pushlstring(L, fname, e - fname); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { /* no such field? */ + if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */ lua_pop(L, 1); /* remove this nil */ lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ lua_pushlstring(L, fname, e - fname); @@ -809,13 +873,12 @@ static int libsize (const luaL_Reg *l) { LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, int sizehint) { luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ - lua_getfield(L, -1, modname); /* get _LOADED[modname] */ - if (!lua_istable(L, -1)) { /* not found? */ + if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ lua_pushglobaltable(L); if (luaL_findtable(L, 0, modname, sizehint) != NULL) - luaL_error(L, "name conflict for module " LUA_QS, modname); + luaL_error(L, "name conflict for module '%s'", modname); lua_pushvalue(L, -1); lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */ } @@ -845,7 +908,6 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, ** Returns with only the table at the stack. */ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkversion(L); luaL_checkstack(L, nup, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; @@ -863,8 +925,8 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { ** into the stack */ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { - lua_getfield(L, idx, fname); - if (lua_istable(L, -1)) return 1; /* table already there */ + if (lua_getfield(L, idx, fname) == LUA_TTABLE) + return 1; /* table already there */ else { lua_pop(L, 1); /* remove previous result */ idx = lua_absindex(L, idx); @@ -877,22 +939,26 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { /* -** stripped-down 'require'. Calls 'openf' to open a module, -** registers the result in 'package.loaded' table and, if 'glb' -** is true, also registers the result in the global table. +** Stripped-down 'require': After checking "loaded" table, calls 'openf' +** to open a module, registers the result in 'package.loaded' table and, +** if 'glb' is true, also registers the result in the global table. ** Leaves resulting module on the top. */ LUALIB_API void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb) { - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); /* argument to open function */ - lua_call(L, 1, 1); /* open module */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_pushvalue(L, -2); /* make copy of module (call result) */ - lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ - lua_pop(L, 1); /* remove _LOADED table */ + lua_getfield(L, -1, modname); /* _LOADED[modname] */ + if (!lua_toboolean(L, -1)) { /* package not already loaded? */ + lua_pop(L, 1); /* remove field */ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* call 'openf' to open module */ + lua_pushvalue(L, -1); /* make copy of module (call result) */ + lua_setfield(L, -3, modname); /* _LOADED[modname] = module */ + } + lua_remove(L, -2); /* remove _LOADED table */ if (glb) { - lua_pushvalue(L, -1); /* copy of 'mod' */ + lua_pushvalue(L, -1); /* copy of module */ lua_setglobal(L, modname); /* _G[modname] = module */ } } @@ -907,7 +973,7 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, while ((wild = strstr(s, p)) != NULL) { luaL_addlstring(&b, s, wild - s); /* push prefix */ luaL_addstring(&b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after `p' */ + s = wild + l; /* continue after 'p' */ } luaL_addstring(&b, s); /* push last suffix */ luaL_pushresult(&b); @@ -927,8 +993,8 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { static int panic (lua_State *L) { - luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", - lua_tostring(L, -1)); + lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); return 0; /* return to Lua to abort */ } @@ -940,20 +1006,15 @@ LUALIB_API lua_State *luaL_newstate (void) { } -LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) { +LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { const lua_Number *v = lua_version(L); + if (sz != LUAL_NUMSIZES) /* check numeric types */ + luaL_error(L, "core and library have incompatible numeric types"); if (v != lua_version(NULL)) luaL_error(L, "multiple Lua VMs detected"); else if (*v != ver) luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", ver, *v); - /* check conversions number -> integer types */ - lua_pushnumber(L, -(lua_Number)0x1234); - if (lua_tointeger(L, -1) != -0x1234 || - lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234) - luaL_error(L, "bad conversion number->int;" - " must recompile Lua with proper settings"); - lua_pop(L, 1); } //added by xdczju@sina.com diff --git a/deps/lua/lauxlib.h b/deps/lua/lauxlib.h index eef6e06..0c9f0e1 100644 --- a/deps/lua/lauxlib.h +++ b/deps/lua/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.120.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -16,7 +16,7 @@ -/* extra error code for `luaL_load' */ +/* extra error code for 'luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) @@ -26,30 +26,30 @@ typedef struct luaL_Reg { } luaL_Reg; -LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); -#define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) +#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) + +LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); +#define luaL_checkversion(L) \ + luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); -LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); -LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, +LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, size_t *l); -LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, const char *def, size_t *l); -LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); -LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); -LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); -LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, lua_Integer def); -LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg); -LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg, - lua_Unsigned def); LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); -LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); -LUALIB_API void (luaL_checkany) (lua_State *L, int narg); +LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int arg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); @@ -59,13 +59,13 @@ LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); -LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, +LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, const char *const lst[]); LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); LUALIB_API int (luaL_execresult) (lua_State *L, int stat); -/* pre-defined references */ +/* predefined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) @@ -85,7 +85,7 @@ LUALIB_API lua_State *(luaL_newstate) (void); LUALIB_API lua_State *(luaL_newstateex) (void* ud); -LUALIB_API int (luaL_len) (lua_State *L, int idx); +LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); @@ -110,16 +110,13 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, #define luaL_newlibtable(L,l) \ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) -#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) +#define luaL_newlib(L,l) \ + (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) -#define luaL_argcheck(L, cond,numarg,extramsg) \ - ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) +#define luaL_argcheck(L, cond,arg,extramsg) \ + ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) -#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) -#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) -#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) -#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) @@ -208,6 +205,53 @@ LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, #endif + +/* +** {================================================================== +** "Abstraction Layer" for basic report of messages and errors +** =================================================================== +*/ + +/* print a string */ +#if !defined(lua_writestring) +#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#endif + +/* print a newline and flush the output */ +#if !defined(lua_writeline) +#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) +#endif + +/* print an error message */ +#if !defined(lua_writestringerror) +#define lua_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) +#endif + +/* }================================================================== */ + + +/* +** {============================================================ +** Compatibility with deprecated conversions +** ============================================================= +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) +#define luaL_optunsigned(L,a,d) \ + ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) + +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) + +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#endif +/* }============================================================ */ + + #if defined(LUA_USE_SHARED_PROTO) LUALIB_API int (luaL_closesharedclosure) (); #endif diff --git a/deps/lua/lbaselib.c b/deps/lua/lbaselib.c index 5255b3c..861823d 100644 --- a/deps/lua/lbaselib.c +++ b/deps/lua/lbaselib.c @@ -1,9 +1,13 @@ /* -** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lbaselib.c,v 1.312 2015/10/29 15:21:04 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ +#define lbaselib_c +#define LUA_LIB + +#include "lprefix.h" #include @@ -11,9 +15,6 @@ #include #include -#define lbaselib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -32,62 +33,74 @@ static int luaB_print (lua_State *L) { lua_call(L, 1, 1); s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) - return luaL_error(L, - LUA_QL("tostring") " must return a string to " LUA_QL("print")); - if (i>1) luai_writestring("\t", 1); - luai_writestring(s, l); + return luaL_error(L, "'tostring' must return a string to 'print'"); + if (i>1) lua_writestring("\t", 1); + lua_writestring(s, l); lua_pop(L, 1); /* pop result */ } - luai_writeline(); + lua_writeline(); return 0; } #define SPACECHARS " \f\n\r\t\v" +static const char *b_str2int (const char *s, int base, lua_Integer *pn) { + lua_Unsigned n = 0; + int neg = 0; + s += strspn(s, SPACECHARS); /* skip initial spaces */ + if (*s == '-') { s++; neg = 1; } /* handle signal */ + else if (*s == '+') s++; + if (!isalnum((unsigned char)*s)) /* no digit? */ + return NULL; + do { + int digit = (isdigit((unsigned char)*s)) ? *s - '0' + : (toupper((unsigned char)*s) - 'A') + 10; + if (digit >= base) return NULL; /* invalid numeral */ + n = n * base + digit; + s++; + } while (isalnum((unsigned char)*s)); + s += strspn(s, SPACECHARS); /* skip trailing spaces */ + *pn = (lua_Integer)((neg) ? (0u - n) : n); + return s; +} + + static int luaB_tonumber (lua_State *L) { - if (lua_isnoneornil(L, 2)) { /* standard conversion */ - int isnum; - lua_Number n = lua_tonumberx(L, 1, &isnum); - if (isnum) { - lua_pushnumber(L, n); - return 1; - } /* else not a number; must be something */ + if (lua_isnoneornil(L, 2)) { /* standard conversion? */ luaL_checkany(L, 1); + if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ + lua_settop(L, 1); /* yes; return it */ + return 1; + } + else { + size_t l; + const char *s = lua_tolstring(L, 1, &l); + if (s != NULL && lua_stringtonumber(L, s) == l + 1) + return 1; /* successful conversion to number */ + /* else not a number */ + } } else { size_t l; - const char *s = luaL_checklstring(L, 1, &l); - const char *e = s + l; /* end point for 's' */ - int base = luaL_checkint(L, 2); - int neg = 0; + const char *s; + lua_Integer n = 0; /* to avoid warnings */ + lua_Integer base = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ + s = lua_tolstring(L, 1, &l); luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); - s += strspn(s, SPACECHARS); /* skip initial spaces */ - if (*s == '-') { s++; neg = 1; } /* handle signal */ - else if (*s == '+') s++; - if (isalnum((unsigned char)*s)) { - lua_Number n = 0; - do { - int digit = (isdigit((unsigned char)*s)) ? *s - '0' - : toupper((unsigned char)*s) - 'A' + 10; - if (digit >= base) break; /* invalid numeral; force a fail */ - n = n * (lua_Number)base + (lua_Number)digit; - s++; - } while (isalnum((unsigned char)*s)); - s += strspn(s, SPACECHARS); /* skip trailing spaces */ - if (s == e) { /* no invalid trailing characters? */ - lua_pushnumber(L, (neg) ? -n : n); - return 1; - } /* else not a number */ + if (b_str2int(s, (int)base, &n) == s + l) { + lua_pushinteger(L, n); + return 1; } /* else not a number */ - } + } /* else not a number */ lua_pushnil(L); /* not a number */ return 1; } static int luaB_error (lua_State *L) { - int level = luaL_optint(L, 2, 1); + int level = (int)luaL_optinteger(L, 2, 1); lua_settop(L, 1); if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); @@ -114,7 +127,7 @@ static int luaB_setmetatable (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); - if (luaL_getmetafield(L, 1, "__metatable")) + if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) return luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); @@ -160,19 +173,18 @@ static int luaB_rawset (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", "step", "setpause", "setstepmul", - "setmajorinc", "isrunning", "generational", "incremental", NULL}; + "isrunning", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, - LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; + LUA_GCISRUNNING}; int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; - int ex = luaL_optint(L, 2, 0); + int ex = (int)luaL_optinteger(L, 2, 0); int res = lua_gc(L, o, ex); switch (o) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); - lua_pushnumber(L, res + ((lua_Number)b/1024)); - lua_pushinteger(L, b); - return 2; + lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); + return 1; } case LUA_GCSTEP: case LUA_GCISRUNNING: { lua_pushboolean(L, res); @@ -187,15 +199,16 @@ static int luaB_collectgarbage (lua_State *L) { static int luaB_type (lua_State *L) { - luaL_checkany(L, 1); - lua_pushstring(L, luaL_typename(L, 1)); + int t = lua_type(L, 1); + luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); + lua_pushstring(L, lua_typename(L, t)); return 1; } static int pairsmeta (lua_State *L, const char *method, int iszero, lua_CFunction iter) { - if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */ + if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ lua_pushcfunction(L, iter); /* will return generator, */ lua_pushvalue(L, 1); /* state, */ @@ -227,18 +240,31 @@ static int luaB_pairs (lua_State *L) { } +/* +** Traversal function for 'ipairs' +*/ static int ipairsaux (lua_State *L) { - int i = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - i++; /* next value */ + lua_Integer i = luaL_checkinteger(L, 2) + 1; lua_pushinteger(L, i); - lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1)) ? 1 : 2; + return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; } +/* +** This function will use either 'ipairsaux' or 'ipairsaux_raw' to +** traverse a table, depending on whether the table has metamethods +** that can affect the traversal. +*/ static int luaB_ipairs (lua_State *L) { +#if defined(LUA_COMPAT_IPAIRS) return pairsmeta(L, "__ipairs", 1, ipairsaux); +#else + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ + return 3; +#endif } @@ -284,7 +310,7 @@ static int luaB_loadfile (lua_State *L) { /* -** Reader for generic `load' function: `lua_load' uses the +** Reader for generic 'load' function: 'lua_load' uses the ** stack for internal stuff, so the reader cannot change the ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. @@ -328,7 +354,8 @@ static int luaB_load (lua_State *L) { /* }====================================================== */ -static int dofilecont (lua_State *L) { +static int dofilecont (lua_State *L, int d1, lua_KContext d2) { + (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ return lua_gettop(L) - 1; } @@ -339,14 +366,20 @@ static int luaB_dofile (lua_State *L) { if (luaL_loadfile(L, fname) != LUA_OK) return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); - return dofilecont(L); + return dofilecont(L, 0, 0); } static int luaB_assert (lua_State *L) { - if (!lua_toboolean(L, 1)) - return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); - return lua_gettop(L); + if (lua_toboolean(L, 1)) /* condition is true? */ + return lua_gettop(L); /* return all arguments */ + else { /* error */ + luaL_checkany(L, 1); /* there must be a condition */ + lua_remove(L, 1); /* remove it */ + lua_pushliteral(L, "assertion failed!"); /* default message */ + lua_settop(L, 1); /* leave only message (default if no other one) */ + return luaB_error(L); /* call 'error' */ + } } @@ -357,53 +390,57 @@ static int luaB_select (lua_State *L) { return 1; } else { - int i = luaL_checkint(L, 1); + lua_Integer i = luaL_checkinteger(L, 1); if (i < 0) i = n + i; else if (i > n) i = n; luaL_argcheck(L, 1 <= i, 1, "index out of range"); - return n - i; + return n - (int)i; } } -static int finishpcall (lua_State *L, int status) { - if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */ - lua_settop(L, 0); /* create space for return values */ - lua_pushboolean(L, 0); - lua_pushstring(L, "stack overflow"); +/* +** Continuation function for 'pcall' and 'xpcall'. Both functions +** already pushed a 'true' before doing the call, so in case of success +** 'finishpcall' only has to return everything in the stack minus +** 'extra' values (where 'extra' is exactly the number of items to be +** ignored). +*/ +static int finishpcall (lua_State *L, int status, lua_KContext extra) { + if (status != LUA_OK && status != LUA_YIELD) { /* error? */ + lua_pushboolean(L, 0); /* first result (false) */ + lua_pushvalue(L, -2); /* error message */ return 2; /* return false, msg */ } - lua_pushboolean(L, status); /* first result (status) */ - lua_replace(L, 1); /* put first result in first slot */ - return lua_gettop(L); -} - - -static int pcallcont (lua_State *L) { - int status = lua_getctx(L, NULL); - return finishpcall(L, (status == LUA_YIELD)); + else + return lua_gettop(L) - (int)extra; /* return all results */ } static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); - lua_pushnil(L); - lua_insert(L, 1); /* create space for status result */ - status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont); - return finishpcall(L, (status == LUA_OK)); + lua_pushboolean(L, 1); /* first result if no errors */ + lua_insert(L, 1); /* put it in place */ + status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); + return finishpcall(L, status, 0); } +/* +** Do a protected call with error handling. After 'lua_rotate', the +** stack will have ; so, the function passes +** 2 to 'finishpcall' to skip the 2 first values when returning results. +*/ static int luaB_xpcall (lua_State *L) { int status; int n = lua_gettop(L); - luaL_argcheck(L, n >= 2, 2, "value expected"); - lua_pushvalue(L, 1); /* exchange function... */ - lua_copy(L, 2, 1); /* ...and error handler */ - lua_replace(L, 2); - status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont); - return finishpcall(L, (status == LUA_OK)); + luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ + lua_pushboolean(L, 1); /* first result */ + lua_pushvalue(L, 1); /* function */ + lua_rotate(L, 3, 2); /* move them below function's arguments */ + status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); + return finishpcall(L, status, 2); } @@ -440,19 +477,23 @@ static const luaL_Reg base_funcs[] = { {"tostring", luaB_tostring}, {"type", luaB_type}, {"xpcall", luaB_xpcall}, + /* placeholders */ + {"_G", NULL}, + {"_VERSION", NULL}, {NULL, NULL} }; LUAMOD_API int luaopen_base (lua_State *L) { - /* set global _G */ - lua_pushglobaltable(L); - lua_pushglobaltable(L); - lua_setfield(L, -2, "_G"); /* open lib into global table */ + lua_pushglobaltable(L); luaL_setfuncs(L, base_funcs, 0); + /* set global _G */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_G"); + /* set global _VERSION */ lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ + lua_setfield(L, -2, "_VERSION"); return 1; } diff --git a/deps/lua/lbitlib.c b/deps/lua/lbitlib.c index 31c7b66..1cb1d5b 100644 --- a/deps/lua/lbitlib.c +++ b/deps/lua/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $ +** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -7,20 +7,36 @@ #define lbitlib_c #define LUA_LIB +#include "lprefix.h" + + #include "lua.h" #include "lauxlib.h" #include "lualib.h" +#if defined(LUA_COMPAT_BITLIB) /* { */ + + +#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) + + /* number of bits to consider in a number */ #if !defined(LUA_NBITS) #define LUA_NBITS 32 #endif +/* +** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must +** be made in two parts to avoid problems when LUA_NBITS is equal to the +** number of bits in a lua_Unsigned.) +*/ #define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) + /* macro to trim extra bits */ #define trim(x) ((x) & ALLONES) @@ -29,28 +45,25 @@ #define mask(n) (~((ALLONES << 1) << ((n) - 1))) -typedef lua_Unsigned b_uint; - - -static b_uint andaux (lua_State *L) { +static lua_Unsigned andaux (lua_State *L) { int i, n = lua_gettop(L); - b_uint r = ~(b_uint)0; + lua_Unsigned r = ~(lua_Unsigned)0; for (i = 1; i <= n; i++) - r &= luaL_checkunsigned(L, i); + r &= checkunsigned(L, i); return trim(r); } static int b_and (lua_State *L) { - b_uint r = andaux(L); - lua_pushunsigned(L, r); + lua_Unsigned r = andaux(L); + pushunsigned(L, r); return 1; } static int b_test (lua_State *L) { - b_uint r = andaux(L); + lua_Unsigned r = andaux(L); lua_pushboolean(L, r != 0); return 1; } @@ -58,32 +71,32 @@ static int b_test (lua_State *L) { static int b_or (lua_State *L) { int i, n = lua_gettop(L); - b_uint r = 0; + lua_Unsigned r = 0; for (i = 1; i <= n; i++) - r |= luaL_checkunsigned(L, i); - lua_pushunsigned(L, trim(r)); + r |= checkunsigned(L, i); + pushunsigned(L, trim(r)); return 1; } static int b_xor (lua_State *L) { int i, n = lua_gettop(L); - b_uint r = 0; + lua_Unsigned r = 0; for (i = 1; i <= n; i++) - r ^= luaL_checkunsigned(L, i); - lua_pushunsigned(L, trim(r)); + r ^= checkunsigned(L, i); + pushunsigned(L, trim(r)); return 1; } static int b_not (lua_State *L) { - b_uint r = ~luaL_checkunsigned(L, 1); - lua_pushunsigned(L, trim(r)); + lua_Unsigned r = ~checkunsigned(L, 1); + pushunsigned(L, trim(r)); return 1; } -static int b_shift (lua_State *L, b_uint r, int i) { +static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { if (i < 0) { /* shift right? */ i = -i; r = trim(r); @@ -95,54 +108,54 @@ static int b_shift (lua_State *L, b_uint r, int i) { else r <<= i; r = trim(r); } - lua_pushunsigned(L, r); + pushunsigned(L, r); return 1; } static int b_lshift (lua_State *L) { - return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2)); + return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); } static int b_rshift (lua_State *L) { - return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2)); + return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); } static int b_arshift (lua_State *L) { - b_uint r = luaL_checkunsigned(L, 1); - int i = luaL_checkint(L, 2); - if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1)))) + lua_Unsigned r = checkunsigned(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) return b_shift(L, r, -i); else { /* arithmetic shift for 'negative' number */ if (i >= LUA_NBITS) r = ALLONES; else - r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */ - lua_pushunsigned(L, r); + r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ + pushunsigned(L, r); return 1; } } -static int b_rot (lua_State *L, int i) { - b_uint r = luaL_checkunsigned(L, 1); - i &= (LUA_NBITS - 1); /* i = i % NBITS */ +static int b_rot (lua_State *L, lua_Integer d) { + lua_Unsigned r = checkunsigned(L, 1); + int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ r = trim(r); if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ r = (r << i) | (r >> (LUA_NBITS - i)); - lua_pushunsigned(L, trim(r)); + pushunsigned(L, trim(r)); return 1; } static int b_lrot (lua_State *L) { - return b_rot(L, luaL_checkint(L, 2)); + return b_rot(L, luaL_checkinteger(L, 2)); } static int b_rrot (lua_State *L) { - return b_rot(L, -luaL_checkint(L, 2)); + return b_rot(L, -luaL_checkinteger(L, 2)); } @@ -153,36 +166,35 @@ static int b_rrot (lua_State *L) { ** 'width' being used uninitialized.) */ static int fieldargs (lua_State *L, int farg, int *width) { - int f = luaL_checkint(L, farg); - int w = luaL_optint(L, farg + 1, 1); + lua_Integer f = luaL_checkinteger(L, farg); + lua_Integer w = luaL_optinteger(L, farg + 1, 1); luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); if (f + w > LUA_NBITS) luaL_error(L, "trying to access non-existent bits"); - *width = w; - return f; + *width = (int)w; + return (int)f; } static int b_extract (lua_State *L) { int w; - b_uint r = luaL_checkunsigned(L, 1); + lua_Unsigned r = trim(checkunsigned(L, 1)); int f = fieldargs(L, 2, &w); r = (r >> f) & mask(w); - lua_pushunsigned(L, r); + pushunsigned(L, r); return 1; } static int b_replace (lua_State *L) { int w; - b_uint r = luaL_checkunsigned(L, 1); - b_uint v = luaL_checkunsigned(L, 2); + lua_Unsigned r = trim(checkunsigned(L, 1)); + lua_Unsigned v = trim(checkunsigned(L, 2)); int f = fieldargs(L, 3, &w); - int m = mask(w); - v &= m; /* erase bits outside given width */ - r = (r & ~(m << f)) | (v << f); - lua_pushunsigned(L, r); + lua_Unsigned m = mask(w); + r = (r & ~(m << f)) | ((v & m) << f); + pushunsigned(L, r); return 1; } @@ -210,3 +222,12 @@ LUAMOD_API int luaopen_bit32 (lua_State *L) { return 1; } + +#else /* }{ */ + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + return luaL_error(L, "library 'bit32' has been deprecated"); +} + +#endif /* } */ diff --git a/deps/lua/lcode.c b/deps/lua/lcode.c index 5ba570e..e86b1ca 100644 --- a/deps/lua/lcode.c +++ b/deps/lua/lcode.c @@ -1,15 +1,18 @@ /* -** $Id: lcode.c,v 2.62.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lcode.c,v 2.103 2015/11/19 19:16:22 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ - -#include - #define lcode_c #define LUA_CORE +#include "lprefix.h" + + +#include +#include + #include "lua.h" #include "lcode.h" @@ -26,11 +29,25 @@ #include "lvm.h" +/* Maximum number of registers in a Lua function (must fit in 8 bits) */ +#define MAXREGS 255 + + #define hasjumps(e) ((e)->t != (e)->f) -static int isnumeral(expdesc *e) { - return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); +static int tonumeral(expdesc *e, TValue *v) { + if (hasjumps(e)) + return 0; /* not a numeral */ + switch (e->k) { + case VKINT: + if (v) setivalue(v, e->u.ival); + return 1; + case VKFLT: + if (v) setfltvalue(v, e->u.nval); + return 1; + default: return 0; + } } @@ -88,7 +105,7 @@ static void fixjump (FuncState *fs, int pc, int dest) { /* -** returns current `pc' and marks it as a jump target (to avoid wrong +** returns current 'pc' and marks it as a jump target (to avoid wrong ** optimizations with consecutive instructions not in the same basic block). */ int luaK_getlabel (FuncState *fs) { @@ -176,7 +193,7 @@ void luaK_patchlist (FuncState *fs, int list, int target) { } -LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) { +void luaK_patchclose (FuncState *fs, int list, int level) { level++; /* argument is +1 to reserve 0 as non-op */ while (list != NO_JUMP) { int next = getjump(fs, list); @@ -211,7 +228,7 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { static int luaK_code (FuncState *fs, Instruction i) { SharedProto *f = fs->f->sp; - dischargejpc(fs); /* `pc' will change */ + dischargejpc(fs); /* 'pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "opcodes"); @@ -261,8 +278,9 @@ int luaK_codek (FuncState *fs, int reg, int k) { void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->sp->maxstacksize) { - if (newstack >= MAXSTACK) - luaX_syntaxerror(fs->ls, "function or expression too complex"); + if (newstack >= MAXREGS) + luaX_syntaxerror(fs->ls, + "function or expression needs too many registers"); fs->f->sp->maxstacksize = cast_byte(newstack); } } @@ -288,25 +306,28 @@ static void freeexp (FuncState *fs, expdesc *e) { } +/* +** Use scanner's table to cache position of constants in constant list +** and try to reuse constants +*/ static int addk (FuncState *fs, TValue *key, TValue *v) { lua_State *L = fs->ls->L; - TValue *idx = luaH_set(L, fs->h, key); Proto *f = fs->f; + TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ int k, oldsize; - if (ttisnumber(idx)) { - lua_Number n = nvalue(idx); - lua_number2int(k, n); - if (luaV_rawequalobj(&f->k[k], v)) - return k; - /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); - go through and create a new entry for this value */ + if (ttisinteger(idx)) { /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && + luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ } /* constant not found; create a new entry */ oldsize = f->sp->sizek; k = fs->nk; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ - setnvalue(idx, cast_num(k)); + setivalue(idx, k); luaM_growvector(L, f->k, k, f->sp->sizek, TValue, MAXARG_Ax, "constants"); while (oldsize < f->sp->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[k], v); @@ -323,20 +344,23 @@ int luaK_stringK (FuncState *fs, TString *s) { } -int luaK_numberK (FuncState *fs, lua_Number r) { - int n; - lua_State *L = fs->ls->L; +/* +** Integers use userdata as keys to avoid collision with floats with same +** value; conversion to 'void*' used only for hashing, no "precision" +** problems +*/ +int luaK_intK (FuncState *fs, lua_Integer n) { + TValue k, o; + setpvalue(&k, cast(void*, cast(size_t, n))); + setivalue(&o, n); + return addk(fs, &k, &o); +} + + +static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; - setnvalue(&o, r); - if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ - /* use raw representation as key to avoid numeric problems */ - setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r))); - n = addk(fs, L->top - 1, &o); - L->top--; - } - else - n = addk(fs, &o, &o); /* regular case */ - return n; + setfltvalue(&o, r); + return addk(fs, &o, &o); } @@ -351,7 +375,7 @@ static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); /* cannot use nil as key; instead use table itself to represent nil */ - sethvalue(fs->ls->L, &k, fs->h); + sethvalue(fs->ls->L, &k, fs->ls->h); return addk(fs, &k, &v); } @@ -433,10 +457,14 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_codek(fs, reg, e->u.info); break; } - case VKNUM: { + case VKFLT: { luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); break; } + case VKINT: { + luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); + break; + } case VRELOCABLE: { Instruction *pc = &getcode(fs, e); SETARG_A(*pc, reg); @@ -468,7 +496,7 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) { static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) - luaK_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */ + luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ @@ -538,13 +566,19 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { } else break; } - case VKNUM: { + case VKINT: { + e->u.info = luaK_intK(fs, e->u.ival); + e->k = VK; + goto vk; + } + case VKFLT: { e->u.info = luaK_numberK(fs, e->u.nval); e->k = VK; - /* go through */ } + /* FALLTHROUGH */ case VK: { - if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */ + vk: + if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ return RKASK(e->u.info); else break; } @@ -627,7 +661,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { pc = e->u.info; break; } - case VK: case VKNUM: case VTRUE: { + case VK: case VKFLT: case VKINT: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } @@ -636,7 +670,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { break; } } - luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ + luaK_concat(fs, &e->f, pc); /* insert last jump in 'f' list */ luaK_patchtohere(fs, e->t); e->t = NO_JUMP; } @@ -659,7 +693,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) { break; } } - luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ + luaK_concat(fs, &e->t, pc); /* insert last jump in 't' list */ luaK_patchtohere(fs, e->f); e->f = NO_JUMP; } @@ -672,7 +706,7 @@ static void codenot (FuncState *fs, expdesc *e) { e->k = VTRUE; break; } - case VK: case VKNUM: case VTRUE: { + case VK: case VKFLT: case VKINT: case VTRUE: { e->k = VFALSE; break; } @@ -710,25 +744,70 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { } -static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { - lua_Number r; - if (!isnumeral(e1) || !isnumeral(e2)) return 0; - if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0) - return 0; /* do not attempt to divide by 0 */ - r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval); - e1->u.nval = r; +/* +** return false if folding can raise an error +*/ +static int validop (int op, TValue *v1, TValue *v2) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ + lua_Integer i; + return (tointeger(v1, &i) && tointeger(v2, &i)); + } + case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ + return (nvalue(v2) != 0); + default: return 1; /* everything else is valid */ + } +} + + +/* +** Try to "constant-fold" an operation; return 1 iff successful +*/ +static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) { + TValue v1, v2, res; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) + return 0; /* non-numeric operands or not safe to fold */ + luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ + if (ttisinteger(&res)) { + e1->k = VKINT; + e1->u.ival = ivalue(&res); + } + else { /* folds neither NaN nor 0.0 (to avoid collapsing with -0.0) */ + lua_Number n = fltvalue(&res); + if (luai_numisnan(n) || n == 0) + return 0; + e1->k = VKFLT; + e1->u.nval = n; + } return 1; } -static void codearith (FuncState *fs, OpCode op, - expdesc *e1, expdesc *e2, int line) { - if (constfolding(op, e1, e2)) - return; +/* +** Code for binary and unary expressions that "produce values" +** (arithmetic operations, bitwise operations, concat, length). First +** try to do constant folding (only for numeric [arithmetic and +** bitwise] operations, which is what 'lua_arith' accepts). +** Expression to produce final result will be encoded in 'e1'. +*/ +static void codeexpval (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int line) { + lua_assert(op >= OP_ADD); + if (op <= OP_BNOT && constfolding(fs, (op - OP_ADD) + LUA_OPADD, e1, e2)) + return; /* result has been folded */ else { - int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; - int o1 = luaK_exp2RK(fs, e1); - if (o1 > o2) { + int o1, o2; + /* move operands to registers (if needed) */ + if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */ + o2 = 0; /* no second expression */ + o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */ + } + else { /* regular case (binary operators) */ + o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ + o1 = luaK_exp2RK(fs, e1); + } + if (o1 > o2) { /* free registers in proper order */ freeexp(fs, e1); freeexp(fs, e2); } @@ -736,8 +815,8 @@ static void codearith (FuncState *fs, OpCode op, freeexp(fs, e2); freeexp(fs, e1); } - e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); - e1->k = VRELOCABLE; + e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */ + e1->k = VRELOCABLE; /* all those operations are relocatable */ luaK_fixline(fs, line); } } @@ -750,7 +829,7 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, freeexp(fs, e2); freeexp(fs, e1); if (cond == 0 && op != OP_EQ) { - int temp; /* exchange args to replace by `<' or `<=' */ + int temp; /* exchange args to replace by '<' or '<=' */ temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ cond = 1; } @@ -761,23 +840,13 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { expdesc e2; - e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; + e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0; switch (op) { - case OPR_MINUS: { - if (isnumeral(e)) /* minus constant? */ - e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */ - else { - luaK_exp2anyreg(fs, e); - codearith(fs, OP_UNM, e, &e2, line); - } + case OPR_MINUS: case OPR_BNOT: case OPR_LEN: { + codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line); break; } case OPR_NOT: codenot(fs, e); break; - case OPR_LEN: { - luaK_exp2anyreg(fs, e); /* cannot operate on constants */ - codearith(fs, OP_LEN, e, &e2, line); - break; - } default: lua_assert(0); } } @@ -794,12 +863,15 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { break; } case OPR_CONCAT: { - luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ + luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ break; } - case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_MOD: case OPR_POW: { - if (!isnumeral(v)) luaK_exp2RK(fs, v); + case OPR_ADD: case OPR_SUB: + case OPR_MUL: case OPR_DIV: case OPR_IDIV: + case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v); break; } default: { @@ -837,21 +909,23 @@ void luaK_posfix (FuncState *fs, BinOpr op, } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codearith(fs, OP_CONCAT, e1, e2, line); + codeexpval(fs, OP_CONCAT, e1, e2, line); } break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_MOD: case OPR_POW: { - codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line); + case OPR_IDIV: case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line); break; } case OPR_EQ: case OPR_LT: case OPR_LE: { - codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2); + codecomp(fs, cast(OpCode, (op - OPR_EQ) + OP_EQ), 1, e1, e2); break; } case OPR_NE: case OPR_GT: case OPR_GE: { - codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2); + codecomp(fs, cast(OpCode, (op - OPR_NE) + OP_EQ), 0, e1, e2); break; } default: lua_assert(0); diff --git a/deps/lua/lcode.h b/deps/lua/lcode.h index 5a8e0b8..b4c865f 100644 --- a/deps/lua/lcode.h +++ b/deps/lua/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.58.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -24,7 +24,11 @@ ** grep "ORDER OPR" if you change these enums (ORDER OP) */ typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, + OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, + OPR_DIV, + OPR_IDIV, + OPR_BAND, OPR_BOR, OPR_BXOR, + OPR_SHL, OPR_SHR, OPR_CONCAT, OPR_EQ, OPR_LT, OPR_LE, OPR_NE, OPR_GT, OPR_GE, @@ -33,7 +37,7 @@ typedef enum BinOpr { } BinOpr; -typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; +typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define getcode(fs,e) ((fs)->f->sp->code[(e)->u.info]) @@ -52,7 +56,7 @@ LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); -LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); +LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); diff --git a/deps/lua/lcorolib.c b/deps/lua/lcorolib.c index ce4f6ad..0c0b7fa 100644 --- a/deps/lua/lcorolib.c +++ b/deps/lua/lcorolib.c @@ -1,15 +1,16 @@ /* -** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ +#define lcorolib_c +#define LUA_LIB -#include +#include "lprefix.h" -#define lcorolib_c -#define LUA_LIB +#include #include "lua.h" @@ -17,6 +18,13 @@ #include "lualib.h" +static lua_State *getco (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "thread expected"); + return co; +} + + static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) { @@ -47,9 +55,8 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { static int luaB_coresume (lua_State *L) { - lua_State *co = lua_tothread(L, 1); + lua_State *co = getco(L); int r; - luaL_argcheck(L, co, 1, "coroutine expected"); r = auxresume(L, co, lua_gettop(L) - 1); if (r < 0) { lua_pushboolean(L, 0); @@ -59,7 +66,7 @@ static int luaB_coresume (lua_State *L) { else { lua_pushboolean(L, 1); lua_insert(L, -(r + 1)); - return r + 1; /* return true + `resume' returns */ + return r + 1; /* return true + 'resume' returns */ } } @@ -102,8 +109,7 @@ static int luaB_yield (lua_State *L) { static int luaB_costatus (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); + lua_State *co = getco(L); if (L == co) lua_pushliteral(L, "running"); else { switch (lua_status(co)) { @@ -129,6 +135,12 @@ static int luaB_costatus (lua_State *L) { } +static int luaB_yieldable (lua_State *L) { + lua_pushboolean(L, lua_isyieldable(L)); + return 1; +} + + static int luaB_corunning (lua_State *L) { int ismain = lua_pushthread(L); lua_pushboolean(L, ismain); @@ -143,6 +155,7 @@ static const luaL_Reg co_funcs[] = { {"status", luaB_costatus}, {"wrap", luaB_cowrap}, {"yield", luaB_yield}, + {"isyieldable", luaB_yieldable}, {NULL, NULL} }; diff --git a/deps/lua/lctype.c b/deps/lua/lctype.c index 93f8cad..ae9367e 100644 --- a/deps/lua/lctype.c +++ b/deps/lua/lctype.c @@ -1,5 +1,5 @@ /* -** $Id: lctype.c,v 1.11.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ @@ -7,6 +7,9 @@ #define lctype_c #define LUA_CORE +#include "lprefix.h" + + #include "lctype.h" #if !LUA_USE_CTYPE /* { */ diff --git a/deps/lua/lctype.h b/deps/lua/lctype.h index b09b21a..99c7d12 100644 --- a/deps/lua/lctype.h +++ b/deps/lua/lctype.h @@ -1,5 +1,5 @@ /* -** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ diff --git a/deps/lua/ldblib.c b/deps/lua/ldblib.c index 84fe3c7..786f6cd 100644 --- a/deps/lua/ldblib.c +++ b/deps/lua/ldblib.c @@ -1,26 +1,42 @@ /* -** $Id: ldblib.c,v 1.132.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ +#define ldblib_c +#define LUA_LIB + +#include "lprefix.h" + #include #include #include -#define ldblib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" #include "lualib.h" -#define HOOKKEY "_HKEY" +/* +** The hook table at registry[&HOOKKEY] maps threads to their current +** hook function. (We only need the unique address of 'HOOKKEY'.) +*/ +static const int HOOKKEY = 0; +/* +** If L1 != L, L1 can be in any state, and therefore there are no +** guarantees about its stack space; any push in L1 must be +** checked. +*/ +static void checkstack (lua_State *L, lua_State *L1, int n) { + if (L != L1 && !lua_checkstack(L1, n)) + luaL_error(L, "stack overflow"); +} + static int db_getregistry (lua_State *L) { lua_pushvalue(L, LUA_REGISTRYINDEX); @@ -57,35 +73,20 @@ static int db_getuservalue (lua_State *L) { static int db_setuservalue (lua_State *L) { - if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) - luaL_argerror(L, 1, "full userdata expected, got light userdata"); luaL_checktype(L, 1, LUA_TUSERDATA); - if (!lua_isnoneornil(L, 2)) - luaL_checktype(L, 2, LUA_TTABLE); + luaL_checkany(L, 2); lua_settop(L, 2); lua_setuservalue(L, 1); return 1; } -static void settabss (lua_State *L, const char *i, const char *v) { - lua_pushstring(L, v); - lua_setfield(L, -2, i); -} - - -static void settabsi (lua_State *L, const char *i, int v) { - lua_pushinteger(L, v); - lua_setfield(L, -2, i); -} - - -static void settabsb (lua_State *L, const char *i, int v) { - lua_pushboolean(L, v); - lua_setfield(L, -2, i); -} - - +/* +** Auxiliary function used by several library functions: check for +** an optional thread as function's first argument and set 'arg' with +** 1 if this argument is present (so that functions can skip it to +** access their other arguments) +*/ static lua_State *getthread (lua_State *L, int *arg) { if (lua_isthread(L, 1)) { *arg = 1; @@ -93,44 +94,74 @@ static lua_State *getthread (lua_State *L, int *arg) { } else { *arg = 0; - return L; + return L; /* function will operate over current thread */ } } +/* +** Variations of 'lua_settable', used by 'db_getinfo' to put results +** from 'lua_getinfo' into result table. Key is always a string; +** value can be a string, an int, or a boolean. +*/ +static void settabss (lua_State *L, const char *k, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, k); +} + +static void settabsi (lua_State *L, const char *k, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, k); +} + +static void settabsb (lua_State *L, const char *k, int v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, k); +} + + +/* +** In function 'db_getinfo', the call to 'lua_getinfo' may push +** results on the stack; later it creates the result table to put +** these objects. Function 'treatstackoption' puts the result from +** 'lua_getinfo' on top of the result table so that it can call +** 'lua_setfield'. +*/ static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { - if (L == L1) { - lua_pushvalue(L, -2); - lua_remove(L, -3); - } + if (L == L1) + lua_rotate(L, -2, 1); /* exchange object and table */ else - lua_xmove(L1, L, 1); - lua_setfield(L, -2, fname); + lua_xmove(L1, L, 1); /* move object to the "main" stack */ + lua_setfield(L, -2, fname); /* put object into table */ } +/* +** Calls 'lua_getinfo' and collects all results in a new table. +** L1 needs stack space for an optional input (function) plus +** two optional outputs (function and line table) from function +** 'lua_getinfo'. +*/ static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnStu"); - if (lua_isnumber(L, arg+1)) { - if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { + checkstack(L, L1, 3); + if (lua_isfunction(L, arg + 1)) { /* info about a function? */ + options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ + lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ + lua_xmove(L, L1, 1); + } + else { /* stack level */ + if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } - else if (lua_isfunction(L, arg+1)) { - lua_pushfstring(L, ">%s", options); - options = lua_tostring(L, -1); - lua_pushvalue(L, arg+1); - lua_xmove(L, L1, 1); - } - else - return luaL_argerror(L, arg+1, "function or level expected"); if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); - lua_createtable(L, 0, 2); + lua_newtable(L); /* table to collect results */ if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); @@ -164,20 +195,22 @@ static int db_getlocal (lua_State *L) { lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; - int nvar = luaL_checkint(L, arg+2); /* local-variable index */ + int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ if (lua_isfunction(L, arg + 1)) { /* function argument? */ lua_pushvalue(L, arg + 1); /* push function */ lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ - return 1; + return 1; /* return only name (there is no value) */ } else { /* stack-level argument */ - if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + int level = (int)luaL_checkinteger(L, arg + 1); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); + checkstack(L, L1, 1); name = lua_getlocal(L1, &ar, nvar); if (name) { - lua_xmove(L1, L, 1); /* push local value */ + lua_xmove(L1, L, 1); /* move local value */ lua_pushstring(L, name); /* push name */ - lua_pushvalue(L, -2); /* re-order */ + lua_rotate(L, -2, 1); /* re-order */ return 2; } else { @@ -190,26 +223,36 @@ static int db_getlocal (lua_State *L) { static int db_setlocal (lua_State *L) { int arg; + const char *name; lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + int level = (int)luaL_checkinteger(L, arg + 1); + int nvar = (int)luaL_checkinteger(L, arg + 2); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); luaL_checkany(L, arg+3); lua_settop(L, arg+3); + checkstack(L, L1, 1); lua_xmove(L, L1, 1); - lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); + name = lua_setlocal(L1, &ar, nvar); + if (name == NULL) + lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lua_pushstring(L, name); return 1; } +/* +** get (if 'get' is true) or set an upvalue from a closure +*/ static int auxupvalue (lua_State *L, int get) { const char *name; - int n = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TFUNCTION); + int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ + luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); - lua_insert(L, -(get+1)); + lua_insert(L, -(get+1)); /* no-op if get is false */ return get + 1; } @@ -225,13 +268,15 @@ static int db_setupvalue (lua_State *L) { } +/* +** Check whether a given upvalue from a given closure exists and +** returns its index +*/ static int checkupval (lua_State *L, int argf, int argnup) { - lua_Debug ar; - int nup = luaL_checkint(L, argnup); - luaL_checktype(L, argf, LUA_TFUNCTION); - lua_pushvalue(L, argf); - lua_getinfo(L, ">u", &ar); - luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index"); + int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ + luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ + luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, + "invalid upvalue index"); return nup; } @@ -253,26 +298,29 @@ static int db_upvaluejoin (lua_State *L) { } -#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY) - - +/* +** Call hook function registered at hook table for the current +** thread (if there is one) +*/ static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail call"}; - gethooktable(L); + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); lua_pushthread(L); - lua_rawget(L, -2); - if (lua_isfunction(L, -1)) { - lua_pushstring(L, hooknames[(int)ar->event]); + if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ + lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ if (ar->currentline >= 0) - lua_pushinteger(L, ar->currentline); + lua_pushinteger(L, ar->currentline); /* push current line */ else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); - lua_call(L, 2, 0); + lua_call(L, 2, 0); /* call hook function */ } } +/* +** Convert a string mask (for 'sethook') into a bit mask +*/ static int makemask (const char *smask, int count) { int mask = 0; if (strchr(smask, 'c')) mask |= LUA_MASKCALL; @@ -283,6 +331,9 @@ static int makemask (const char *smask, int count) { } +/* +** Convert a bit mask (for 'gethook') into a string mask +*/ static char *unmakemask (int mask, char *smask) { int i = 0; if (mask & LUA_MASKCALL) smask[i++] = 'c'; @@ -297,26 +348,30 @@ static int db_sethook (lua_State *L) { int arg, mask, count; lua_Hook func; lua_State *L1 = getthread(L, &arg); - if (lua_isnoneornil(L, arg+1)) { + if (lua_isnoneornil(L, arg+1)) { /* no hook? */ lua_settop(L, arg+1); func = NULL; mask = 0; count = 0; /* turn off hooks */ } else { const char *smask = luaL_checkstring(L, arg+2); luaL_checktype(L, arg+1, LUA_TFUNCTION); - count = luaL_optint(L, arg+3, 0); + count = (int)luaL_optinteger(L, arg + 3, 0); func = hookf; mask = makemask(smask, count); } - if (gethooktable(L) == 0) { /* creating hook table? */ + if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) { + lua_createtable(L, 0, 2); /* create a hook table */ + lua_pushvalue(L, -1); + lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ lua_pushstring(L, "k"); lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ lua_pushvalue(L, -1); lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ } - lua_pushthread(L1); lua_xmove(L1, L, 1); - lua_pushvalue(L, arg+1); - lua_rawset(L, -3); /* set new hook */ - lua_sethook(L1, func, mask, count); /* set hooks */ + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ + lua_pushvalue(L, arg + 1); /* value (hook function) */ + lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ + lua_sethook(L1, func, mask, count); return 0; } @@ -327,16 +382,19 @@ static int db_gethook (lua_State *L) { char buff[5]; int mask = lua_gethookmask(L1); lua_Hook hook = lua_gethook(L1); - if (hook != NULL && hook != hookf) /* external hook? */ + if (hook == NULL) /* no hook? */ + lua_pushnil(L); + else if (hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); - else { - gethooktable(L); + else { /* hook table must exist */ + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); + checkstack(L, L1, 1); lua_pushthread(L1); lua_xmove(L1, L, 1); - lua_rawget(L, -2); /* get hook */ + lua_rawget(L, -2); /* 1st result = hooktable[L1] */ lua_remove(L, -2); /* remove hook table */ } - lua_pushstring(L, unmakemask(mask, buff)); - lua_pushinteger(L, lua_gethookcount(L1)); + lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ + lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ return 3; } @@ -344,13 +402,13 @@ static int db_gethook (lua_State *L) { static int db_debug (lua_State *L) { for (;;) { char buffer[250]; - luai_writestringerror("%s", "lua_debug> "); + lua_writestringerror("%s", "lua_debug> "); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || lua_pcall(L, 0, 0, 0)) - luai_writestringerror("%s\n", lua_tostring(L, -1)); + lua_writestringerror("%s\n", lua_tostring(L, -1)); lua_settop(L, 0); /* remove eventual returns */ } } @@ -363,7 +421,7 @@ static int db_traceback (lua_State *L) { if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ lua_pushvalue(L, arg + 1); /* return it untouched */ else { - int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0); + int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); luaL_traceback(L, L1, msg, level); } return 1; diff --git a/deps/lua/ldebug.c b/deps/lua/ldebug.c index 9097f67..8f692a8 100644 --- a/deps/lua/ldebug.c +++ b/deps/lua/ldebug.c @@ -1,18 +1,19 @@ /* -** $Id: ldebug.c,v 2.90.1.3 2013/05/16 16:04:15 roberto Exp $ +** $Id: ldebug.c,v 2.117 2015/11/02 18:48:07 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ +#define ldebug_c +#define LUA_CORE + +#include "lprefix.h" + #include #include #include - -#define ldebug_c -#define LUA_CORE - #include "lua.h" #include "lapi.h" @@ -33,6 +34,10 @@ #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue((ci)->func)) + + static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); @@ -47,10 +52,26 @@ static int currentline (CallInfo *ci) { } +/* +** If function yielded, its 'func' can be in the 'extra' field. The +** next function restores 'func' to its correct value for debugging +** purposes. (It exchanges 'func' and 'extra'; so, when called again, +** after debugging, it also "re-restores" ** 'func' to its altered value. +*/ +static void swapextra (lua_State *L) { + if (L->status == LUA_YIELD) { + CallInfo *ci = L->ci; /* get function that yielded */ + StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ + ci->func = restorestack(L, ci->extra); + ci->extra = savestack(L, temp); + } +} + + /* ** this function can be called asynchronous (e.g. during a signal) */ -LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { +LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { if (func == NULL || mask == 0) { /* turn off hooks? */ mask = 0; func = NULL; @@ -61,7 +82,6 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { L->basehookcount = count; resethookcount(L); L->hookmask = cast_byte(mask); - return 1; } @@ -106,7 +126,7 @@ static const char *upvalname (Proto *p, int uv) { static const char *findvararg (CallInfo *ci, int n, StkId *pos) { int nparams = clLvalue(ci->func)->p->sp->numparams; - if (n >= ci->u.l.base - ci->func - nparams) + if (n >= cast_int(ci->u.l.base - ci->func) - nparams) return NULL; /* no such vararg */ else { *pos = ci->func + nparams + n; @@ -144,6 +164,7 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n, LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { const char *name; lua_lock(L); + swapextra(L); if (ar == NULL) { /* information about non-active function? */ if (!isLfunction(L->top - 1)) /* not a Lua function? */ name = NULL; @@ -151,25 +172,30 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); } else { /* active function; get information through 'ar' */ - StkId pos = 0; /* to avoid warnings */ + StkId pos = NULL; /* to avoid warnings */ name = findlocal(L, ar->i_ci, n, &pos); if (name) { setobj2s(L, L->top, pos); api_incr_top(L); } } + swapextra(L); lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - StkId pos = 0; /* to avoid warnings */ - const char *name = findlocal(L, ar->i_ci, n, &pos); + StkId pos = NULL; /* to avoid warnings */ + const char *name; lua_lock(L); - if (name) + swapextra(L); + name = findlocal(L, ar->i_ci, n, &pos); + if (name) { setobjs2s(L, pos, L->top - 1); - L->top--; /* pop value */ + L->top--; /* pop value */ + } + swapextra(L); lua_unlock(L); return name; } @@ -269,6 +295,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { CallInfo *ci; StkId func; lua_lock(L); + swapextra(L); if (*what == '>') { ci = NULL; func = L->top - 1; @@ -287,6 +314,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { setobjs2s(L, L->top, func); api_incr_top(L); } + swapextra(L); /* correct before option 'L', which can raise a mem. error */ if (strchr(what, 'L')) collectvalidlines(L, cl); lua_unlock(L); @@ -366,18 +394,13 @@ static int findsetreg (Proto *p, int lastpc, int reg) { case OP_JMP: { int b = GETARG_sBx(i); int dest = pc + 1 + b; - /* jump is forward and do not skip `lastpc'? */ + /* jump is forward and do not skip 'lastpc'? */ if (pc < dest && dest <= lastpc) { if (dest > jmptarget) jmptarget = dest; /* update 'jmptarget' */ } break; } - case OP_TEST: { - if (reg == a) /* jumped code can change 'a' */ - setreg = filterpc(pc, jmptarget); - break; - } default: if (testAMode(op) && reg == a) /* any instruction that set A */ setreg = filterpc(pc, jmptarget); @@ -397,7 +420,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg, /* else try symbolic execution */ pc = findsetreg(p, lastpc, reg); if (pc != -1) { /* could find instruction? */ - Instruction i = p->sp->code[pc]; + Instruction i = p->sp->code[pc]; OpCode op = GET_OPCODE(i); switch (op) { case OP_MOVE: { @@ -443,10 +466,14 @@ static const char *getobjname (Proto *p, int lastpc, int reg, static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { - TMS tm; + TMS tm = (TMS)0; /* to avoid warnings */ Proto *p = ci_func(ci)->p; /* calling function */ int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->sp->code[pc]; /* calling instruction */ + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: /* get function name */ @@ -456,25 +483,27 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { return "for iterator"; } /* all other instructions can call only through metamethods */ - case OP_SELF: - case OP_GETTABUP: - case OP_GETTABLE: tm = TM_INDEX; break; - case OP_SETTABUP: - case OP_SETTABLE: tm = TM_NEWINDEX; break; - case OP_EQ: tm = TM_EQ; break; - case OP_ADD: tm = TM_ADD; break; - case OP_SUB: tm = TM_SUB; break; - case OP_MUL: tm = TM_MUL; break; - case OP_DIV: tm = TM_DIV; break; - case OP_MOD: tm = TM_MOD; break; - case OP_POW: tm = TM_POW; break; + case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: + tm = TM_INDEX; + break; + case OP_SETTABUP: case OP_SETTABLE: + tm = TM_NEWINDEX; + break; + case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: + case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: + case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { + int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ + tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ + break; + } case OP_UNM: tm = TM_UNM; break; + case OP_BNOT: tm = TM_BNOT; break; case OP_LEN: tm = TM_LEN; break; + case OP_CONCAT: tm = TM_CONCAT; break; + case OP_EQ: tm = TM_EQ; break; case OP_LT: tm = TM_LT; break; case OP_LE: tm = TM_LE; break; - case OP_CONCAT: tm = TM_CONCAT; break; - default: - return NULL; /* else no useful name can be found */ + default: lua_assert(0); /* other instructions cannot call a function */ } *name = getstr(G(L)->tmname[tm]); return "metamethod"; @@ -485,17 +514,21 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { /* -** only ANSI way to check whether a pointer points to an array -** (used only for error messages, so efficiency is not a big concern) +** The subtraction of two potentially unrelated pointers is +** not ISO C, but it should not crash a program; the subsequent +** checks are ISO C and ensure a correct result. */ static int isinstack (CallInfo *ci, const TValue *o) { - StkId p; - for (p = ci->u.l.base; p < ci->top; p++) - if (o == p) return 1; - return 0; + ptrdiff_t i = o - ci->u.l.base; + return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); } +/* +** Checks whether value 'o' came from an upvalue. (That can only happen +** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on +** upvalues.) +*/ static const char *getupvalname (CallInfo *ci, const TValue *o, const char **name) { LClosure *c = ci_func(ci); @@ -510,10 +543,9 @@ static const char *getupvalname (CallInfo *ci, const TValue *o, } -l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { +static const char *varinfo (lua_State *L, const TValue *o) { + const char *name = NULL; /* to avoid warnings */ CallInfo *ci = L->ci; - const char *name = NULL; - const char *t = objtypename(o); const char *kind = NULL; if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ @@ -521,26 +553,39 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { kind = getobjname(ci_func(ci)->p, currentpc(ci), cast_int(o - ci->u.l.base), &name); } - if (kind) - luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", - op, kind, name, t); - else - luaG_runerror(L, "attempt to %s a %s value", op, t); + return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; } -l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) { - if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; - lua_assert(!ttisstring(p1) && !ttisnumber(p1)); +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + const char *t = objtypename(o); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); +} + + +l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { + if (ttisstring(p1) || cvt2str(p1)) p1 = p2; luaG_typeerror(L, p1, "concatenate"); } -l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { - TValue temp; - if (luaV_tonumber(p1, &temp) == NULL) - p2 = p1; /* first operand is wrong */ - luaG_typeerror(L, p2, "perform arithmetic on"); +l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, const char *msg) { + lua_Number temp; + if (!tonumber(p1, &temp)) /* first operand is wrong? */ + p2 = p1; /* now second is wrong */ + luaG_typeerror(L, p2, msg); +} + + +/* +** Error when both values are convertible to numbers, but not to integers +*/ +l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { + lua_Integer temp; + if (!tointeger(p1, &temp)) + p2 = p1; + luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); } @@ -554,40 +599,75 @@ l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { } -static void addinfo (lua_State *L, const char *msg) { - CallInfo *ci = L->ci; - if (isLua(ci)) { /* is Lua code? */ - char buff[LUA_IDSIZE]; /* add file:line information */ - int line = currentline(ci); - TString *src = ci_func(ci)->p->sp->source; - if (src) - luaO_chunkid(buff, getstr(src), LUA_IDSIZE); - else { /* no source available; use "?" instead */ - buff[0] = '?'; buff[1] = '\0'; - } - luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); +/* add src:line information to 'msg' */ +const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, + int line) { + char buff[LUA_IDSIZE]; + if (src) + luaO_chunkid(buff, getstr(src), LUA_IDSIZE); + else { /* no source available; use "?" instead */ + buff[0] = '?'; buff[1] = '\0'; } + return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } l_noret luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); - if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ - L->top++; - luaD_call(L, L->top - 2, 1, 0); /* call it */ + L->top++; /* assume EXTRA_STACK */ + luaD_callnoyield(L, L->top - 2, 1); /* call it */ } luaD_throw(L, LUA_ERRRUN); } l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { + CallInfo *ci = L->ci; + const char *msg; va_list argp; va_start(argp, fmt); - addinfo(L, luaO_pushvfstring(L, fmt, argp)); + msg = luaO_pushvfstring(L, fmt, argp); /* format message */ va_end(argp); + if (isLua(ci)) /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->sp->source, currentline(ci)); luaG_errormsg(L); } + +void luaG_traceexec (lua_State *L) { + CallInfo *ci = L->ci; + lu_byte mask = L->hookmask; + int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + if (counthook) + resethookcount(L); /* reset count */ + else if (!(mask & LUA_MASKLINE)) + return; /* no line hook and count != 0; nothing to be done */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return; /* do not call hook again (VM yielded, so it did not move) */ + } + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ + if (mask & LUA_MASKLINE) { + Proto *p = ci_func(ci)->p; + int npc = pcRel(ci->u.l.savedpc, p); + int newline = getfuncline(p, npc); + if (npc == 0 || /* call linehook when enter a new function, */ + ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ + newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ + luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ + } + L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ + ci->func = L->top - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } +} + diff --git a/deps/lua/ldebug.h b/deps/lua/ldebug.h index 04d646d..0579311 100644 --- a/deps/lua/ldebug.h +++ b/deps/lua/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -13,22 +13,27 @@ #define pcRel(pc, p) (cast(int, (pc) - (p)->sp->code) - 1) -#define getfuncline(f,pc) (((f)->sp->lineinfo) ? (f)->sp->lineinfo[pc] : 0) +#define getfuncline(f,pc) (((f)->sp->lineinfo) ? (f)->sp->lineinfo[pc] : -1) #define resethookcount(L) (L->hookcount = L->basehookcount) -/* Active Lua function (given call info) */ -#define ci_func(ci) (clLvalue((ci)->func)) - LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *opname); -LUAI_FUNC l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2); -LUAI_FUNC l_noret luaG_aritherror (lua_State *L, const TValue *p1, +LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, + const char *msg); +LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, + TString *src, int line); LUAI_FUNC l_noret luaG_errormsg (lua_State *L); +LUAI_FUNC void luaG_traceexec (lua_State *L); + #endif diff --git a/deps/lua/ldo.c b/deps/lua/ldo.c index a66d7e4..8aa3473 100644 --- a/deps/lua/ldo.c +++ b/deps/lua/ldo.c @@ -1,17 +1,19 @@ /* -** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $ +** $Id: ldo.c,v 2.150 2015/11/19 19:16:22 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ +#define ldo_c +#define LUA_CORE + +#include "lprefix.h" + #include #include #include -#define ldo_c -#define LUA_CORE - #include "lua.h" #include "lapi.h" @@ -33,6 +35,8 @@ +#define errorstatus(s) ((s) > LUA_YIELD) + /* ** {====================================================== @@ -46,30 +50,33 @@ ** C++ code, with _longjmp/_setjmp when asked to use them, and with ** longjmp/setjmp otherwise. */ -#if !defined(LUAI_THROW) +#if !defined(LUAI_THROW) /* { */ + +#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ -#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) \ try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ -#elif defined(LUA_USE_ULONGJMP) -/* in Unix, try _longjmp/_setjmp (more efficient) */ +#elif defined(LUA_USE_POSIX) /* }{ */ + +/* in POSIX, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf -#else -/* default handling with long jumps */ +#else /* }{ */ + +/* ISO C handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf -#endif +#endif /* } */ -#endif +#endif /* } */ @@ -106,15 +113,19 @@ l_noret luaD_throw (lua_State *L, int errcode) { LUAI_THROW(L, L->errorJmp); /* jump to it */ } else { /* thread has no error handler */ + global_State *g = G(L); L->status = cast_byte(errcode); /* mark it as dead */ - if (G(L)->mainthread->errorJmp) { /* main thread has a handler? */ - setobjs2s(L, G(L)->mainthread->top++, L->top - 1); /* copy error obj. */ - luaD_throw(G(L)->mainthread, errcode); /* re-throw in main thread */ + if (g->mainthread->errorJmp) { /* main thread has a handler? */ + setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ + luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ } else { /* no handler at all; abort */ - if (G(L)->panic) { /* panic function? */ + if (g->panic) { /* panic function? */ + seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ + if (L->ci->top < L->top) + L->ci->top = L->top; /* pushing msg. can break this invariant */ lua_unlock(L); - G(L)->panic(L); /* call it (last chance to jump out) */ + g->panic(L); /* call panic function (last chance to jump out) */ } abort(); } @@ -139,12 +150,17 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { /* }====================================================== */ +/* +** {================================================================== +** Stack reallocation +** =================================================================== +*/ static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; - GCObject *up; + UpVal *up; L->top = (L->top - oldstack) + L->stack; - for (up = L->openupval; up != NULL; up = up->gch.next) - gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v = (up->v - oldstack) + L->stack; for (ci = L->ci; ci != NULL; ci = ci->previous) { ci->top = (ci->top - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; @@ -206,14 +222,26 @@ void luaD_shrinkstack (lua_State *L) { int inuse = stackinuse(L); int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; - if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */ - goodsize >= L->stacksize) /* would grow instead of shrink? */ - condmovestack(L); /* don't change stack (change only for debugging) */ + if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */ + luaE_freeCI(L); /* free all CIs (list grew because of an error) */ else + luaE_shrinkCI(L); /* shrink list */ + if (inuse <= LUAI_MAXSTACK && /* not handling stack overflow? */ + goodsize < L->stacksize) /* trying to shrink? */ luaD_reallocstack(L, goodsize); /* shrink it */ + else + condmovestack(L,,); /* don't change stack (change only for debugging) */ } +void luaD_inctop (lua_State *L) { + luaD_checkstack(L, 1); + L->top++; +} + +/* }================================================================== */ + + void luaD_hook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; if (hook && L->allowhook) { @@ -258,31 +286,34 @@ static StkId adjust_varargs (lua_State *L, SharedProto *p, int actual) { int i; int nfixargs = p->numparams; StkId base, fixed; - lua_assert(actual >= nfixargs); /* move fixed parameters to final position */ - luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ - for (i=0; itop++, fixed + i); - setnilvalue(fixed + i); + setnilvalue(fixed + i); /* erase original copy (for GC) */ } + for (; i < nfixargs; i++) + setnilvalue(L->top++); /* complete missing arguments */ return base; } -static StkId tryfuncTM (lua_State *L, StkId func) { +/* +** Check whether __call metafield of 'func' is a function. If so, put +** it in stack below original 'func' so that 'luaD_precall' can call +** it. Raise an error if __call metafield is not a function. +*/ +static void tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; - ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); - /* Open a hole inside the stack at `func' */ - for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); - incr_top(L); - func = restorestack(L, funcr); /* previous call may change stack */ + /* Open a hole inside the stack at 'func' */ + for (p = L->top; p > func; p--) + setobjs2s(L, p, p-1); + L->top++; /* slot ensured by caller */ setobj2s(L, func, tm); /* tag method is the new function to be called */ - return func; } @@ -290,79 +321,133 @@ static StkId tryfuncTM (lua_State *L, StkId func) { #define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) +/* macro to check stack size, preserving 'p' */ +#define checkstackp(L,n,p) \ + luaD_checkstackaux(L, n, \ + ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ + luaC_checkGC(L), /* stack grow uses memory */ \ + p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ + + /* -** returns true if function has been executed (C function) +** Prepares a function call: checks the stack, creates a new CallInfo +** entry, fills in the relevant information, calls hook if needed. +** If function is a C function, does the call, too. (Otherwise, leave +** the execution ('luaV_execute') to the caller, to allow stackless +** calls.) Returns true iff function has been executed (C function). */ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_CFunction f; CallInfo *ci; - int n; /* number of arguments (Lua) or returns (C) */ - ptrdiff_t funcr = savestack(L, func); switch (ttype(func)) { + case LUA_TCCL: /* C closure */ + f = clCvalue(func)->f; + goto Cfunc; case LUA_TLCF: /* light C function */ f = fvalue(func); - goto Cfunc; - case LUA_TCCL: { /* C closure */ - f = clCvalue(func)->f; - Cfunc: - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + Cfunc: { + int n; /* number of returns */ + checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; - ci->func = restorestack(L, funcr); + ci->func = func; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); ci->callstatus = 0; - luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*f)(L); /* do the actual call */ lua_lock(L); api_checknelems(L, n); - luaD_poscall(L, L->top - n); + luaD_poscall(L, ci, L->top - n, n); return 1; } case LUA_TLCL: { /* Lua function: prepare its call */ StkId base; SharedProto *p = clLvalue(func)->p->sp; - n = cast_int(L->top - func) - 1; /* number of real arguments */ - luaD_checkstack(L, p->maxstacksize); - for (; n < p->numparams; n++) - setnilvalue(L->top++); /* complete missing arguments */ - if (!p->is_vararg) { - func = restorestack(L, funcr); + int n = cast_int(L->top - func) - 1; /* number of real arguments */ + int fsize = p->maxstacksize; /* frame size */ + checkstackp(L, fsize, func); + if (p->is_vararg != 1) { /* do not use vararg? */ + for (; n < p->numparams; n++) + setnilvalue(L->top++); /* complete missing arguments */ base = func + 1; } - else { + else base = adjust_varargs(L, p, n); - func = restorestack(L, funcr); /* previous call can change stack */ - } ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; ci->func = func; ci->u.l.base = base; - ci->top = base + p->maxstacksize; + L->top = ci->top = base + fsize; lua_assert(ci->top <= L->stack_last); ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus = CIST_LUA; - L->top = ci->top; - luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) callhook(L, ci); return 0; } default: { /* not a function */ - func = tryfuncTM(L, func); /* retry with 'function' tag method */ + checkstackp(L, 1, func); /* ensure space for metamethod */ + tryfuncTM(L, func); /* try to get '__call' metamethod */ return luaD_precall(L, func, nresults); /* now it must be a function */ } } } -int luaD_poscall (lua_State *L, StkId firstResult) { +/* +** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. +** Handle most typical cases (zero results for commands, one result for +** expressions, multiple results for tail calls/single parameters) +** separated. +*/ +static int moveresults (lua_State *L, const TValue *firstResult, StkId res, + int nres, int wanted) { + switch (wanted) { /* handle typical cases separately */ + case 0: break; /* nothing to move */ + case 1: { /* one result needed */ + if (nres == 0) /* no results? */ + firstResult = luaO_nilobject; /* adjust with nil */ + setobjs2s(L, res, firstResult); /* move it to proper place */ + break; + } + case LUA_MULTRET: { + int i; + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + L->top = res + nres; + return 0; /* wanted == LUA_MULTRET */ + } + default: { + int i; + if (wanted <= nres) { /* enough results? */ + for (i = 0; i < wanted; i++) /* move wanted results to correct place */ + setobjs2s(L, res + i, firstResult + i); + } + else { /* not enough results; use all of them plus nils */ + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + for (; i < wanted; i++) /* complete wanted number of results */ + setnilvalue(res + i); + } + break; + } + } + L->top = res + wanted; /* top points after the last result */ + return 1; +} + + +/* +** Finishes a function call: calls hook if necessary, removes CallInfo, +** moves current number of results to proper place; returns 0 iff call +** wanted multiple (variable number of) results. +*/ +int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { StkId res; - int wanted, i; - CallInfo *ci = L->ci; + int wanted = ci->nresults; if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { if (L->hookmask & LUA_MASKRET) { ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ @@ -372,15 +457,24 @@ int luaD_poscall (lua_State *L, StkId firstResult) { L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ } res = ci->func; /* res == final position of 1st result */ - wanted = ci->nresults; - L->ci = ci = ci->previous; /* back to caller */ - /* move results to correct place */ - for (i = wanted; i != 0 && firstResult < L->top; i--) - setobjs2s(L, res++, firstResult++); - while (i-- > 0) - setnilvalue(res++); - L->top = res; - return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ + L->ci = ci->previous; /* back to caller */ + /* move results to proper place */ + return moveresults(L, firstResult, res, nres, wanted); +} + + +/* +** Check appropriate error for stack overflow ("regular" overflow or +** overflow while handling stack overflow). If 'nCalls' is larger than +** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but +** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to +** allow overflow handling to work) +*/ +static void stackerror (lua_State *L) { + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } @@ -390,53 +484,67 @@ int luaD_poscall (lua_State *L, StkId firstResult) { ** When returns, all the results are on the stack, starting at the original ** function position. */ -void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { - if (++L->nCcalls >= LUAI_MAXCCALLS) { - if (L->nCcalls == LUAI_MAXCCALLS) - luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ - } - if (!allowyield) L->nny++; +void luaD_call (lua_State *L, StkId func, int nResults) { + if (++L->nCcalls >= LUAI_MAXCCALLS) + stackerror(L); if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ luaV_execute(L); /* call it */ - if (!allowyield) L->nny--; L->nCcalls--; } -static void finishCcall (lua_State *L) { +/* +** Similar to 'luaD_call', but does not allow yields during the call +*/ +void luaD_callnoyield (lua_State *L, StkId func, int nResults) { + L->nny++; + luaD_call(L, func, nResults); + L->nny--; +} + + +/* +** Completes the execution of an interrupted C function, calling its +** continuation function. +*/ +static void finishCcall (lua_State *L, int status) { CallInfo *ci = L->ci; int n; - lua_assert(ci->u.c.k != NULL); /* must have a continuation */ - lua_assert(L->nny == 0); + /* must have a continuation and must be able to call it */ + lua_assert(ci->u.c.k != NULL && L->nny == 0); + /* error status can only happen in a protected call */ + lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ L->errfunc = ci->u.c.old_errfunc; } - /* finish 'lua_callk'/'lua_pcall' */ + /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already + handled */ adjustresults(L, ci->nresults); /* call continuation function */ - if (!(ci->callstatus & CIST_STAT)) /* no call status? */ - ci->u.c.status = LUA_YIELD; /* 'default' status */ - lua_assert(ci->u.c.status != LUA_OK); - ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED; lua_unlock(L); - n = (*ci->u.c.k)(L); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); lua_lock(L); api_checknelems(L, n); /* finish 'luaD_precall' */ - luaD_poscall(L, L->top - n); + luaD_poscall(L, ci, L->top - n, n); } +/* +** Executes "full continuation" (everything in the stack) of a +** previously interrupted coroutine until the stack is empty (or another +** interruption long-jumps out of the loop). If the coroutine is +** recovering from an error, 'ud' points to the error status, which must +** be passed to the first continuation function (otherwise the default +** status is LUA_YIELD). +*/ static void unroll (lua_State *L, void *ud) { - UNUSED(ud); - for (;;) { - if (L->ci == &L->base_ci) /* stack is empty? */ - return; /* coroutine finished normally */ + if (ud != NULL) /* error status? */ + finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ + while (L->ci != &L->base_ci) { /* something in the stack */ if (!isLua(L->ci)) /* C function? */ - finishCcall(L); + finishCcall(L, LUA_YIELD); /* complete its execution */ else { /* Lua function */ luaV_finishOp(L); /* finish interrupted instruction */ luaV_execute(L); /* execute down to higher C 'boundary' */ @@ -446,7 +554,8 @@ static void unroll (lua_State *L, void *ud) { /* -** check whether thread has a suspended protected call +** Try to find a suspended protected call (a "recover point") for the +** given thread. */ static CallInfo *findpcall (lua_State *L) { CallInfo *ci; @@ -458,6 +567,11 @@ static CallInfo *findpcall (lua_State *L) { } +/* +** Recovers from an error in a coroutine. Finds a recover point (if +** there is one) and completes the execution of the interrupted +** 'luaD_pcall'. If there is no recover point, returns zero. +*/ static int recover (lua_State *L, int status) { StkId oldtop; CallInfo *ci = findpcall(L); @@ -467,12 +581,10 @@ static int recover (lua_State *L, int status) { luaF_close(L, oldtop); seterrorobj(L, status, oldtop); L->ci = ci; - L->allowhook = ci->u.c.old_allowhook; + L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ L->nny = 0; /* should be zero to be yieldable */ luaD_shrinkstack(L); L->errfunc = ci->u.c.old_errfunc; - ci->callstatus |= CIST_STAT; /* call has error status */ - ci->u.c.status = status; /* (here it is) */ return 1; /* continue running the coroutine */ } @@ -491,11 +603,16 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { /* -** do the work for 'lua_resume' in protected mode +** Do the work for 'lua_resume' in protected mode. Most of the work +** depends on the status of the coroutine: initial state, suspended +** inside a hook, or regularly suspended (optionally with a continuation +** function), plus erroneous cases: non-suspended coroutine or dead +** coroutine. */ static void resume (lua_State *L, void *ud) { int nCcalls = L->nCcalls; - StkId firstArg = cast(StkId, ud); + int n = *(cast(int*, ud)); /* number of arguments */ + StkId firstArg = L->top - n; /* first argument */ CallInfo *ci = L->ci; if (nCcalls >= LUAI_MAXCCALLS) resume_error(L, "C stack overflow", firstArg); @@ -509,24 +626,21 @@ static void resume (lua_State *L, void *ud) { else if (L->status != LUA_YIELD) resume_error(L, "cannot resume dead coroutine", firstArg); else { /* resuming from previous yield */ - L->status = LUA_OK; + L->status = LUA_OK; /* mark that it is running (again) */ ci->func = restorestack(L, ci->extra); if (isLua(ci)) /* yielded inside a hook? */ luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ - if (ci->u.c.k != NULL) { /* does it have a continuation? */ - int n; - ci->u.c.status = LUA_YIELD; /* 'default' status */ - ci->callstatus |= CIST_YIELDED; + if (ci->u.c.k != NULL) { /* does it have a continuation function? */ lua_unlock(L); - n = (*ci->u.c.k)(L); /* call continuation */ + n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ lua_lock(L); api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } - luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ + luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ } - unroll(L, NULL); + unroll(L, NULL); /* run continuation */ } lua_assert(nCcalls == L->nCcalls); } @@ -534,27 +648,26 @@ static void resume (lua_State *L, void *ud) { LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { int status; - int oldnny = L->nny; /* save 'nny' */ + unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ lua_lock(L); luai_userstateresume(L, nargs); L->nCcalls = (from) ? from->nCcalls + 1 : 1; L->nny = 0; /* allow yields */ api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); - status = luaD_rawrunprotected(L, resume, L->top - nargs); + status = luaD_rawrunprotected(L, resume, &nargs); if (status == -1) /* error calling 'lua_resume'? */ status = LUA_ERRRUN; - else { /* yield or regular error */ - while (status != LUA_OK && status != LUA_YIELD) { /* error? */ - if (recover(L, status)) /* recover point? */ - status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */ - else { /* unrecoverable error */ - L->status = cast_byte(status); /* mark thread as `dead' */ - seterrorobj(L, status, L->top); - L->ci->top = L->top; - break; - } + else { /* continue running after recoverable errors */ + while (errorstatus(status) && recover(L, status)) { + /* unroll continuation */ + status = luaD_rawrunprotected(L, unroll, &status); } - lua_assert(status == L->status); + if (errorstatus(status)) { /* unrecoverable error? */ + L->status = cast_byte(status); /* mark thread as 'dead' */ + seterrorobj(L, status, L->top); /* push error message */ + L->ci->top = L->top; + } + else lua_assert(status == L->status); /* normal end or yield */ } L->nny = oldnny; /* restore 'nny' */ L->nCcalls--; @@ -564,7 +677,13 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { } -LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { +LUA_API int lua_isyieldable (lua_State *L) { + return (L->nny == 0); +} + + +LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k) { CallInfo *ci = L->ci; luai_userstateyield(L, nresults); lua_lock(L); @@ -624,7 +743,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, /* ** Execute a protected parser. */ -struct SParser { /* data to `f_parser' */ +struct SParser { /* data to 'f_parser' */ ZIO *z; Mbuffer buff; /* dynamic structure used by the scanner */ Dyndata dyd; /* dynamic structures used by the parser */ @@ -636,31 +755,26 @@ struct SParser { /* data to `f_parser' */ static void checkmode (lua_State *L, const char *mode, const char *x) { if (mode && strchr(mode, x[0]) == NULL) { luaO_pushfstring(L, - "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode); + "attempt to load a %s chunk (mode is '%s')", x, mode); luaD_throw(L, LUA_ERRSYNTAX); } } static void f_parser (lua_State *L, void *ud) { - int i; - Closure *cl; + LClosure *cl; struct SParser *p = cast(struct SParser *, ud); int c = zgetc(p->z); /* read first character */ if (c == LUA_SIGNATURE[0]) { checkmode(L, p->mode, "binary"); - cl = luaU_undump(L, p->z, &p->buff, p->name); + cl = luaU_undump(L, p->z, p->name); } else { checkmode(L, p->mode, "text"); cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); } - lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); - for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ - UpVal *up = luaF_newupval(L); - cl->l.upvals[i] = up; - luaC_objbarrier(L, cl, up); - } + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); } diff --git a/deps/lua/ldo.h b/deps/lua/ldo.h index d3d3082..80582dc 100644 --- a/deps/lua/ldo.h +++ b/deps/lua/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.20.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ldo.h,v 2.28 2015/11/23 11:29:43 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -13,31 +13,43 @@ #include "lzio.h" -#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \ - luaD_growstack(L, n); else condmovestack(L); +/* +** Macro to check stack size and grow stack if needed. Parameters +** 'pre'/'pos' allow the macro to preserve a pointer into the +** stack across reallocations, doing the work only when needed. +** 'condmovestack' is used in heavy tests to force a stack reallocation +** at every check. +*/ +#define luaD_checkstackaux(L,n,pre,pos) \ + if (L->stack_last - L->top <= (n)) \ + { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } + +/* In general, 'pre'/'pos' are empty (nothing to save) */ +#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,,) -#define incr_top(L) {L->top++; luaD_checkstack(L,0);} #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) -/* type of protected functions, to be ran by `runprotected' */ +/* type of protected functions, to be ran by 'runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode); LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); -LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults, - int allowyield); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); -LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); +LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, + int nres); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_shrinkstack (lua_State *L); +LUAI_FUNC void luaD_inctop (lua_State *L); LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); diff --git a/deps/lua/ldump.c b/deps/lua/ldump.c index dd232ec..0621acb 100644 --- a/deps/lua/ldump.c +++ b/deps/lua/ldump.c @@ -1,174 +1,216 @@ /* -** $Id: ldump.c,v 2.17.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ -#include - #define ldump_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lundump.h" + typedef struct { - lua_State* L; - lua_Writer writer; - void* data; - int strip; - int status; + lua_State *L; + lua_Writer writer; + void *data; + int strip; + int status; } DumpState; -#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) -#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) - -static void DumpBlock(const void* b, size_t size, DumpState* D) -{ - if (D->status==0) - { - lua_unlock(D->L); - D->status=(*D->writer)(D->L,b,size,D->data); - lua_lock(D->L); - } + +/* +** All high-level dumps go through DumpVector; you can change it to +** change the endianness of the result +*/ +#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) + +#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) + + +static void DumpBlock (const void *b, size_t size, DumpState *D) { + if (D->status == 0 && size > 0) { + lua_unlock(D->L); + D->status = (*D->writer)(D->L, b, size, D->data); + lua_lock(D->L); + } } -static void DumpChar(int y, DumpState* D) -{ - char x=(char)y; - DumpVar(x,D); + +#define DumpVar(x,D) DumpVector(&x,1,D) + + +static void DumpByte (int y, DumpState *D) { + lu_byte x = (lu_byte)y; + DumpVar(x, D); } -static void DumpInt(int x, DumpState* D) -{ - DumpVar(x,D); + +static void DumpInt (int x, DumpState *D) { + DumpVar(x, D); } -static void DumpNumber(lua_Number x, DumpState* D) -{ - DumpVar(x,D); + +static void DumpNumber (lua_Number x, DumpState *D) { + DumpVar(x, D); } -static void DumpVector(const void* b, int n, size_t size, DumpState* D) -{ - DumpInt(n,D); - DumpMem(b,n,size,D); + +static void DumpInteger (lua_Integer x, DumpState *D) { + DumpVar(x, D); } -static void DumpString(const TString* s, DumpState* D) -{ - if (s==NULL) - { - size_t size=0; - DumpVar(size,D); - } - else - { - size_t size=s->tsv.len+1; /* include trailing '\0' */ - DumpVar(size,D); - DumpBlock(getstr(s),size*sizeof(char),D); - } + +static void DumpString (const TString *s, DumpState *D) { + if (s == NULL) + DumpByte(0, D); + else { + size_t size = tsslen(s) + 1; /* include trailing '\0' */ + const char *str = getstr(s); + if (size < 0xFF) + DumpByte(cast_int(size), D); + else { + DumpByte(0xFF, D); + DumpVar(size, D); + } + DumpVector(str, size - 1, D); /* no need to save '\0' */ + } } -#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) - -static void DumpFunction(const Proto* f, DumpState* D); - -static void DumpConstants(const Proto* f, DumpState* D) -{ - int i,n=f->sp->sizek; - DumpInt(n,D); - for (i=0; ik[i]; - DumpChar(ttypenv(o),D); - switch (ttypenv(o)) - { - case LUA_TNIL: - break; - case LUA_TBOOLEAN: - DumpChar(bvalue(o),D); - break; - case LUA_TNUMBER: - DumpNumber(nvalue(o),D); - break; - case LUA_TSTRING: - DumpString(rawtsvalue(o),D); - break; - default: lua_assert(0); + +static void DumpCode (const SharedProto *f, DumpState *D) { + DumpInt(f->sizecode, D); + DumpVector(f->code, f->sizecode, D); +} + + +static void DumpFunction(const Proto *f, TString *psource, DumpState *D); + +static void DumpConstants (const Proto *f, DumpState *D) { + int i; + int n = f->sp->sizek; + DumpInt(n, D); + for (i = 0; i < n; i++) { + const TValue *o = &f->k[i]; + DumpByte(ttype(o), D); + switch (ttype(o)) { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpByte(bvalue(o), D); + break; + case LUA_TNUMFLT: + DumpNumber(fltvalue(o), D); + break; + case LUA_TNUMINT: + DumpInteger(ivalue(o), D); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + DumpString(tsvalue(o), D); + break; + default: + lua_assert(0); + } } - } - n=f->sp->sizep; - DumpInt(n,D); - for (i=0; ip[i],D); } -static void DumpUpvalues(const Proto* f, DumpState* D) -{ - int i,n=f->sp->sizeupvalues; - DumpInt(n,D); - for (i=0; isp->upvalues[i].instack,D); - DumpChar(f->sp->upvalues[i].idx,D); - } + +static void DumpProtos (const Proto *f, DumpState *D) { + int i; + int n = f->sp->sizep; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpFunction(f->p[i], f->sp->source, D); +} + + +static void DumpUpvalues (const Proto *f, DumpState *D) { + int i, n = f->sp->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpByte(f->sp->upvalues[i].instack, D); + DumpByte(f->sp->upvalues[i].idx, D); + } } -static void DumpDebug(const SharedProto* f, DumpState* D) -{ - int i,n; - DumpString((D->strip) ? NULL : f->source,D); - n= (D->strip) ? 0 : f->sizelineinfo; - DumpVector(f->lineinfo,n,sizeof(int),D); - n= (D->strip) ? 0 : f->sizelocvars; - DumpInt(n,D); - for (i=0; ilocvars[i].varname,D); - DumpInt(f->locvars[i].startpc,D); - DumpInt(f->locvars[i].endpc,D); - } - n= (D->strip) ? 0 : f->sizeupvalues; - DumpInt(n,D); - for (i=0; iupvalues[i].name,D); + +static void DumpDebug (const SharedProto *f, DumpState *D) { + int i, n; + n = (D->strip) ? 0 : f->sizelineinfo; + DumpInt(n, D); + DumpVector(f->lineinfo, n, D); + n = (D->strip) ? 0 : f->sizelocvars; + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpString(f->locvars[i].varname, D); + DumpInt(f->locvars[i].startpc, D); + DumpInt(f->locvars[i].endpc, D); + } + n = (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpString(f->upvalues[i].name, D); } -static void DumpFunction(const Proto* f, DumpState* D) -{ - const SharedProto *sp = f->sp; - DumpInt(sp->linedefined,D); - DumpInt(sp->lastlinedefined,D); - DumpChar(sp->numparams,D); - DumpChar(sp->is_vararg,D); - DumpChar(sp->maxstacksize,D); - DumpCode(sp,D); - DumpConstants(f,D); - DumpUpvalues(f,D); - DumpDebug(sp,D); + +static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { + const SharedProto *sp = f->sp; + if (D->strip || sp->source == psource) + DumpString(NULL, D); /* no debug info or same source as its parent */ + else + DumpString(sp->source, D); + DumpInt(sp->linedefined, D); + DumpInt(sp->lastlinedefined, D); + DumpByte(sp->numparams, D); + DumpByte(sp->is_vararg, D); + DumpByte(sp->maxstacksize, D); + DumpCode(sp, D); + DumpConstants(f, D); + DumpUpvalues(f, D); + DumpProtos(f, D); + DumpDebug(sp, D); } -static void DumpHeader(DumpState* D) -{ - lu_byte h[LUAC_HEADERSIZE]; - luaU_header(h); - DumpBlock(h,LUAC_HEADERSIZE,D); + +static void DumpHeader (DumpState *D) { + DumpLiteral(LUA_SIGNATURE, D); + DumpByte(LUAC_VERSION, D); + DumpByte(LUAC_FORMAT, D); + DumpLiteral(LUAC_DATA, D); + DumpByte(sizeof(int), D); + DumpByte(sizeof(size_t), D); + DumpByte(sizeof(Instruction), D); + DumpByte(sizeof(lua_Integer), D); + DumpByte(sizeof(lua_Number), D); + DumpInteger(LUAC_INT, D); + DumpNumber(LUAC_NUM, D); } + /* ** dump Lua function as precompiled chunk */ -int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) -{ - DumpState D; - D.L=L; - D.writer=w; - D.data=data; - D.strip=strip; - D.status=0; - DumpHeader(&D); - DumpFunction(f,&D); - return D.status; +int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, + int strip) { + DumpState D; + D.L = L; + D.writer = w; + D.data = data; + D.strip = strip; + D.status = 0; + DumpHeader(&D); + DumpByte(f->sp->sizeupvalues, &D); + DumpFunction(f, NULL, &D); + return D.status; } + diff --git a/deps/lua/lfunc.c b/deps/lua/lfunc.c index d7f83d8..d4bde84 100644 --- a/deps/lua/lfunc.c +++ b/deps/lua/lfunc.c @@ -1,15 +1,17 @@ /* -** $Id: lfunc.c,v 2.30.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ - -#include - #define lfunc_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "lfunc.h" @@ -20,95 +22,83 @@ -Closure *luaF_newCclosure (lua_State *L, int n) { - Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl; - c->c.nupvalues = cast_byte(n); +CClosure *luaF_newCclosure (lua_State *L, int n) { + GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); + CClosure *c = gco2ccl(o); + c->nupvalues = cast_byte(n); return c; } -Closure *luaF_newLclosure (lua_State *L, int n) { - Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl; - c->l.p = NULL; - c->l.nupvalues = cast_byte(n); - while (n--) c->l.upvals[n] = NULL; +LClosure *luaF_newLclosure (lua_State *L, int n) { + GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); + LClosure *c = gco2lcl(o); + c->p = NULL; + c->nupvalues = cast_byte(n); + while (n--) c->upvals[n] = NULL; return c; } - -UpVal *luaF_newupval (lua_State *L) { - UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv; - uv->v = &uv->u.value; - setnilvalue(uv->v); - return uv; +/* +** fill a closure with new closed upvalues +*/ +void luaF_initupvals (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = luaM_new(L, UpVal); + uv->refcount = 1; + uv->v = &uv->u.value; /* make it closed */ + setnilvalue(uv->v); + cl->upvals[i] = uv; + } } UpVal *luaF_findupval (lua_State *L, StkId level) { - global_State *g = G(L); - GCObject **pp = &L->openupval; + UpVal **pp = &L->openupval; UpVal *p; UpVal *uv; - while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { - GCObject *o = obj2gco(p); - lua_assert(p->v != &p->u.value); - lua_assert(!isold(o) || isold(obj2gco(L))); - if (p->v == level) { /* found a corresponding upvalue? */ - if (isdead(g, o)) /* is it dead? */ - changewhite(o); /* resurrect it */ - return p; - } - pp = &p->next; + lua_assert(isintwups(L) || L->openupval == NULL); + while (*pp != NULL && (p = *pp)->v >= level) { + lua_assert(upisopen(p)); + if (p->v == level) /* found a corresponding upvalue? */ + return p; /* return it */ + pp = &p->u.open.next; } - /* not found: create a new one */ - uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; + /* not found: create a new upvalue */ + uv = luaM_new(L, UpVal); + uv->refcount = 0; + uv->u.open.next = *pp; /* link it to list of open upvalues */ + uv->u.open.touched = 1; + *pp = uv; uv->v = level; /* current value lives in the stack */ - uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ - uv->u.l.next = g->uvhead.u.l.next; - uv->u.l.next->u.l.prev = uv; - g->uvhead.u.l.next = uv; - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ + L->twups = G(L)->twups; /* link it to the list */ + G(L)->twups = L; + } return uv; } -static void unlinkupval (UpVal *uv) { - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); - uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ - uv->u.l.prev->u.l.next = uv->u.l.next; -} - - -void luaF_freeupval (lua_State *L, UpVal *uv) { - if (uv->v != &uv->u.value) /* is it open? */ - unlinkupval(uv); /* remove from open list */ - luaM_free(L, uv); /* free upvalue */ -} - - void luaF_close (lua_State *L, StkId level) { UpVal *uv; - global_State *g = G(L); - while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { - GCObject *o = obj2gco(uv); - lua_assert(!isblack(o) && uv->v != &uv->u.value); - L->openupval = uv->next; /* remove from `open' list */ - if (isdead(g, o)) - luaF_freeupval(L, uv); /* free upvalue */ + while (L->openupval != NULL && (uv = L->openupval)->v >= level) { + lua_assert(upisopen(uv)); + L->openupval = uv->u.open.next; /* remove from 'open' list */ + if (uv->refcount == 0) /* no references? */ + luaM_free(L, uv); /* free upvalue */ else { - unlinkupval(uv); /* remove upvalue from 'uvhead' list */ setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ uv->v = &uv->u.value; /* now current value lives here */ - gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ - g->allgc = o; - luaC_checkupvalcolor(g, uv); + luaC_upvalbarrier(L, uv); } } } Proto *luaF_newproto (lua_State *L, SharedProto *sp) { - Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p; + GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); + Proto *f = gco2p(o); f->k = NULL; f->sp = NULL; f->p = NULL; @@ -169,9 +159,8 @@ void luaF_freeproto (lua_State *L, Proto *f) { luaM_free(L, f); } - /* -** Look for n-th local variable at line `line' in function `func'. +** Look for n-th local variable at line 'line' in function 'func'. ** Returns NULL if not found. */ const char *luaF_getlocalname (const Proto *fp, int local_number, int pc) { diff --git a/deps/lua/lfunc.h b/deps/lua/lfunc.h index ba31596..21cbe34 100644 --- a/deps/lua/lfunc.h +++ b/deps/lua/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.8.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -18,14 +18,42 @@ cast(int, sizeof(TValue *)*((n)-1))) +/* test whether thread is in 'twups' list */ +#define isintwups(L) (L->twups != L) + + +/* +** maximum number of upvalues in a closure (both C and Lua). (Value +** must fit in a VM register.) +*/ +#define MAXUPVAL 255 + + +/* +** Upvalues for Lua closures +*/ +struct UpVal { + TValue *v; /* points to stack or to its own value */ + lu_mem refcount; /* reference counter */ + union { + struct { /* (when open) */ + UpVal *next; /* linked list */ + int touched; /* mark to avoid cycles with dead threads */ + } open; + TValue value; /* the value (when closed) */ + } u; +}; + +#define upisopen(up) ((up)->v != &(up)->u.value) + + LUAI_FUNC Proto *luaF_newproto (lua_State *L, SharedProto *sp); -LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); -LUAI_FUNC UpVal *luaF_newupval (lua_State *L); +LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); +LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); +LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); -LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, int pc); diff --git a/deps/lua/lgc.c b/deps/lua/lgc.c index c0f2858..c2d2a7d 100644 --- a/deps/lua/lgc.c +++ b/deps/lua/lgc.c @@ -1,14 +1,17 @@ /* -** $Id: lgc.c,v 2.140.1.2 2013/04/26 18:22:05 roberto Exp $ +** $Id: lgc.c,v 2.210 2015/11/03 18:10:44 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ -#include - #define lgc_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "ldebug.h" @@ -23,6 +26,11 @@ #include "ltm.h" +/* +** internal state for collector while inside the atomic phase. The +** collector should never be in this state while running regular code. +*/ +#define GCSinsideatomic (GCSpause + 1) /* ** cost of sweeping one element (the size of a small object divided @@ -33,8 +41,8 @@ /* maximum number of elements to sweep in each single step */ #define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) -/* maximum number of finalizers to call in each GC step */ -#define GCFINALIZENUM 4 +/* cost of calling one finalizer */ +#define GCFINALIZECOST GCSWEEPCOST /* @@ -52,18 +60,18 @@ /* -** 'makewhite' erases all color bits plus the old bit and then -** sets only the current white bit +** 'makewhite' erases all color bits then sets only the current white +** bit */ -#define maskcolors (~(bit2mask(BLACKBIT, OLDBIT) | WHITEBITS)) +#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) #define makewhite(g,x) \ - (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) + (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) -#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) -#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) +#define white2gray(x) resetbits(x->marked, WHITEBITS) +#define black2gray(x) resetbit(x->marked, BLACKBIT) -#define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT) +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) #define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) @@ -75,8 +83,13 @@ #define markvalue(g,o) { checkconsistency(o); \ if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } -#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ - reallymarkobject(g, obj2gco(t)); } +#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } + +/* +** mark an object that can be NULL (either because it is really optional, +** or it was stripped as debug info, or inside an uncompleted structure) +*/ +#define markobjectN(g,t) { if (t) markobject(g,t); } static void reallymarkobject (global_State *g, GCObject *o); @@ -95,33 +108,38 @@ static void reallymarkobject (global_State *g, GCObject *o); /* -** link table 'h' into list pointed by 'p' +** link collectable object 'o' into list pointed by 'p' */ -#define linktable(h,p) ((h)->gclist = *(p), *(p) = obj2gco(h)) +#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) /* -** if key is not marked, mark its entry as dead (therefore removing it -** from the table) +** If key is not marked, mark its entry as dead. This allows key to be +** collected, but keeps its entry in the table. A dead node is needed +** when Lua looks up for a key (it may be part of a chain) and when +** traversing a weak table (key might be removed from the table during +** traversal). Other places never manipulate dead keys, because its +** associated nil value is enough to signal that the entry is logically +** empty. */ static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (valiswhite(gkey(n))) - setdeadvalue(gkey(n)); /* unused and unmarked key; remove it */ + setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ } /* ** tells whether a key or value can be cleared from a weak ** table. Non-collectable objects are never removed from weak -** tables. Strings behave as `values', so are never removed too. for +** tables. Strings behave as 'values', so are never removed too. for ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values */ static int iscleared (global_State *g, const TValue *o) { if (!iscollectable(o)) return 0; else if (ttisstring(o)) { - markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */ + markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ return 0; } else return iswhite(gcvalue(o)); @@ -130,14 +148,14 @@ static int iscleared (global_State *g, const TValue *o) { /* ** barrier that moves collector forward, that is, mark the white object -** being pointed by a black object. +** being pointed by a black object. (If in sweep phase, clear the black +** object to white [sweep it] to avoid other barrier calls for this +** same object.) */ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcstate != GCSpause); - lua_assert(gch(o)->tt != LUA_TTABLE); - if (keepinvariantout(g)) /* must keep invariant? */ + if (keepinvariant(g)) /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ else { /* sweep phase */ lua_assert(issweepphase(g)); @@ -148,78 +166,52 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { /* ** barrier that moves collector backward, that is, mark the black object -** pointing to a white object as gray again. (Current implementation -** only works for tables; access to 'gclist' is not uniform across -** different types.) +** pointing to a white object as gray again. */ -void luaC_barrierback_ (lua_State *L, GCObject *o) { +void luaC_barrierback_ (lua_State *L, Table *t) { global_State *g = G(L); - lua_assert(isblack(o) && !isdead(g, o) && gch(o)->tt == LUA_TTABLE); - black2gray(o); /* make object gray (again) */ - gco2t(o)->gclist = g->grayagain; - g->grayagain = o; + lua_assert(isblack(t) && !isdead(g, t)); + black2gray(t); /* make table gray (again) */ + linkgclist(t, g->grayagain); } /* -** barrier for prototypes. When creating first closure (cache is -** NULL), use a forward barrier; this may be the only closure of the -** prototype (if it is a "regular" function, with a single instance) -** and the prototype may be big, so it is better to avoid traversing -** it again. Otherwise, use a backward barrier, to avoid marking all -** possible instances. +** barrier for assignments to closed upvalues. Because upvalues are +** shared among closures, it is impossible to know the color of all +** closures pointing to it. So, we assume that the object being assigned +** must be marked. */ -LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c) { +void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { global_State *g = G(L); - lua_assert(isblack(obj2gco(p))); - if (p->cache == NULL) { /* first time? */ - luaC_objbarrier(L, p, c); - } - else { /* use a backward barrier */ - black2gray(obj2gco(p)); /* make prototype gray (again) */ - p->gclist = g->grayagain; - g->grayagain = obj2gco(p); - } + GCObject *o = gcvalue(uv->v); + lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ + if (keepinvariant(g)) + markobject(g, o); } -/* -** check color (and invariants) for an upvalue that was closed, -** i.e., moved into the 'allgc' list -*/ -void luaC_checkupvalcolor (global_State *g, UpVal *uv) { - GCObject *o = obj2gco(uv); - lua_assert(!isblack(o)); /* open upvalues are never black */ - if (isgray(o)) { - if (keepinvariant(g)) { - resetoldbit(o); /* see MOVE OLD rule */ - gray2black(o); /* it is being visited now */ - markvalue(g, uv->v); - } - else { - lua_assert(issweepphase(g)); - makewhite(g, o); - } - } +void luaC_fix (lua_State *L, GCObject *o) { + global_State *g = G(L); + lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ + white2gray(o); /* they will be gray forever */ + g->allgc = o->next; /* remove object from 'allgc' list */ + o->next = g->fixedgc; /* link it to 'fixedgc' list */ + g->fixedgc = o; } /* ** create a new collectable object (with given type and size) and link -** it to '*list'. 'offset' tells how many bytes to allocate before the -** object itself (used only by states). +** it to 'allgc' list. */ -GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, - int offset) { +GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { global_State *g = G(L); - char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz)); - GCObject *o = obj2gco(raw + offset); - if (list == NULL) - list = &g->allgc; /* standard list for collectable objects */ - gch(o)->marked = luaC_white(g); - gch(o)->tt = tt; - gch(o)->next = *list; - *list = o; + GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); + o->marked = luaC_white(g); + o->tt = tt; + o->next = g->allgc; + g->allgc = o; return o; } @@ -241,57 +233,53 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, ** upvalues are already linked in 'headuv' list.) */ static void reallymarkobject (global_State *g, GCObject *o) { - lu_mem size; + reentry: white2gray(o); - switch (gch(o)->tt) { - case LUA_TSHRSTR: - case LUA_TLNGSTR: { - size = sizestring(gco2ts(o)); - break; /* nothing else to mark; make it black */ + switch (o->tt) { + case LUA_TSHRSTR: { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); + break; } - case LUA_TUSERDATA: { - Table *mt = gco2u(o)->metatable; - markobject(g, mt); - markobject(g, gco2u(o)->env); - size = sizeudata(gco2u(o)); + case LUA_TLNGSTR: { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); break; } - case LUA_TUPVAL: { - UpVal *uv = gco2uv(o); - markvalue(g, uv->v); - if (uv->v != &uv->u.value) /* open? */ - return; /* open upvalues remain gray */ - size = sizeof(UpVal); + case LUA_TUSERDATA: { + TValue uvalue; + markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ + gray2black(o); + g->GCmemtrav += sizeudata(gco2u(o)); + getuservalue(g->mainthread, gco2u(o), &uvalue); + if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ + o = gcvalue(&uvalue); + goto reentry; + } break; } case LUA_TLCL: { - gco2lcl(o)->gclist = g->gray; - g->gray = o; - return; + linkgclist(gco2lcl(o), g->gray); + break; } case LUA_TCCL: { - gco2ccl(o)->gclist = g->gray; - g->gray = o; - return; + linkgclist(gco2ccl(o), g->gray); + break; } case LUA_TTABLE: { - linktable(gco2t(o), &g->gray); - return; + linkgclist(gco2t(o), g->gray); + break; } case LUA_TTHREAD: { - gco2th(o)->gclist = g->gray; - g->gray = o; - return; + linkgclist(gco2th(o), g->gray); + break; } case LUA_TPROTO: { - gco2p(o)->gclist = g->gray; - g->gray = o; - return; + linkgclist(gco2p(o), g->gray); + break; } - default: lua_assert(0); return; + default: lua_assert(0); break; } - gray2black(o); - g->GCmemtrav += size; } @@ -301,7 +289,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { static void markmt (global_State *g) { int i; for (i=0; i < LUA_NUMTAGS; i++) - markobject(g, g->mt[i]); + markobjectN(g, g->mt[i]); } @@ -310,29 +298,41 @@ static void markmt (global_State *g) { */ static void markbeingfnz (global_State *g) { GCObject *o; - for (o = g->tobefnz; o != NULL; o = gch(o)->next) { - makewhite(g, o); - reallymarkobject(g, o); - } + for (o = g->tobefnz; o != NULL; o = o->next) + markobject(g, o); } /* -** mark all values stored in marked open upvalues. (See comment in -** 'lstate.h'.) +** Mark all values stored in marked open upvalues from non-marked threads. +** (Values from marked threads were already marked when traversing the +** thread.) Remove from the list threads that no longer have upvalues and +** not-marked threads. */ static void remarkupvals (global_State *g) { - UpVal *uv; - for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { - if (isgray(obj2gco(uv))) - markvalue(g, uv->v); + lua_State *thread; + lua_State **p = &g->twups; + while ((thread = *p) != NULL) { + lua_assert(!isblack(thread)); /* threads are never black */ + if (isgray(thread) && thread->openupval != NULL) + p = &thread->twups; /* keep marked thread with upvalues in the list */ + else { /* thread is not marked or without upvalues */ + UpVal *uv; + *p = thread->twups; /* remove thread from the list */ + thread->twups = thread; /* mark that it is out of list */ + for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { + if (uv->u.open.touched) { + markvalue(g, uv->v); /* remark upvalue's value */ + uv->u.open.touched = 0; + } + } + } } } /* -** mark root set and reset all gray lists, to start a new -** incremental (or full) collection +** mark root set and reset all gray lists, to start a new collection */ static void restartcollection (global_State *g) { g->gray = g->grayagain = NULL; @@ -352,12 +352,18 @@ static void restartcollection (global_State *g) { ** ======================================================= */ +/* +** Traverse a table with weak values and link it to proper list. During +** propagate phase, keep it in 'grayagain' list, to be revisited in the +** atomic phase. In the atomic phase, if table has any white value, +** put it in 'weak' list, to be cleared. +*/ static void traverseweakvalue (global_State *g, Table *h) { Node *n, *limit = gnodelast(h); - /* if there is array part, assume it may have white values (do not - traverse it just to check) */ + /* if there is array part, assume it may have white values (it is not + worth traversing it now just to check) */ int hasclears = (h->sizearray > 0); - for (n = gnode(h, 0); n < limit; n++) { + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ @@ -368,20 +374,30 @@ static void traverseweakvalue (global_State *g, Table *h) { hasclears = 1; /* table will have to be cleared */ } } - if (hasclears) - linktable(h, &g->weak); /* has to be cleared later */ - else /* no white values */ - linktable(h, &g->grayagain); /* no need to clean */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasclears) + linkgclist(h, g->weak); /* has to be cleared later */ } +/* +** Traverse an ephemeron table and link it to proper list. Returns true +** iff any object was marked during this traversal (which implies that +** convergence has to continue). During propagation phase, keep table +** in 'grayagain' list, to be visited again in the atomic phase. In +** the atomic phase, if table has any white->white entry, it has to +** be revisited during ephemeron convergence (as that key may turn +** black). Otherwise, if it has any white key, table has to be cleared +** (in the atomic phase). +*/ static int traverseephemeron (global_State *g, Table *h) { int marked = 0; /* true if an object is marked in this traversal */ int hasclears = 0; /* true if table has white keys */ - int prop = 0; /* true if table has entry "white-key -> white-value" */ + int hasww = 0; /* true if table has entry "white-key -> white-value" */ Node *n, *limit = gnodelast(h); - int i; - /* traverse array part (numeric keys are 'strong') */ + unsigned int i; + /* traverse array part */ for (i = 0; i < h->sizearray; i++) { if (valiswhite(&h->array[i])) { marked = 1; @@ -396,26 +412,27 @@ static int traverseephemeron (global_State *g, Table *h) { else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ hasclears = 1; /* table must be cleared */ if (valiswhite(gval(n))) /* value not marked yet? */ - prop = 1; /* must propagate again */ + hasww = 1; /* white-white entry */ } else if (valiswhite(gval(n))) { /* value not marked yet? */ marked = 1; reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ } } - if (prop) - linktable(h, &g->ephemeron); /* have to propagate again */ - else if (hasclears) /* does table have white keys? */ - linktable(h, &g->allweak); /* may have to clean white keys */ - else /* no white keys */ - linktable(h, &g->grayagain); /* no need to clean */ + /* link table into proper list */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasww) /* table has white->white entries? */ + linkgclist(h, g->ephemeron); /* have to propagate again */ + else if (hasclears) /* table has white keys? */ + linkgclist(h, g->allweak); /* may have to clean white keys */ return marked; } static void traversestrongtable (global_State *g, Table *h) { Node *n, *limit = gnodelast(h); - int i; + unsigned int i; for (i = 0; i < h->sizearray; i++) /* traverse array part */ markvalue(g, &h->array[i]); for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ @@ -434,18 +451,18 @@ static void traversestrongtable (global_State *g, Table *h) { static lu_mem traversetable (global_State *g, Table *h) { const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); - markobject(g, h->metatable); + markobjectN(g, h->metatable); if (mode && ttisstring(mode) && /* is there a weak mode? */ ((weakkey = strchr(svalue(mode), 'k')), (weakvalue = strchr(svalue(mode), 'v')), (weakkey || weakvalue))) { /* is really weak? */ - black2gray(obj2gco(h)); /* keep table gray */ + black2gray(h); /* keep table gray */ if (!weakkey) /* strong keys? */ traverseweakvalue(g, h); else if (!weakvalue) /* strong values? */ traverseephemeron(g, h); else /* all weak */ - linktable(h, &g->allweak); /* nothing to traverse now */ + linkgclist(h, g->allweak); /* nothing to traverse now */ } else /* not weak */ traversestrongtable(g, h); @@ -458,32 +475,35 @@ marksharedproto (global_State *g, SharedProto *f) { int i; if (g != f->l_G) return 0; - markobject(g, f->source); + markobjectN(g, f->source); for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ - markobject(g, f->upvalues[i].name); + markobjectN(g, f->upvalues[i].name); for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ - markobject(g, f->locvars[i].varname); + markobjectN(g, f->locvars[i].varname); return sizeof(Instruction) * f->sizecode + sizeof(int) * f->sizelineinfo + sizeof(LocVar) * f->sizelocvars + sizeof(Upvaldesc) * f->sizeupvalues; } - +/* +** Traverse a prototype. (While a prototype is being build, its +** arrays can be larger than needed; the extra slots are filled with +** NULL, so the use of 'markobjectN') +*/ static int traverseproto (global_State *g, Proto *f) { int i; - if (f->cache && iswhite(obj2gco(f->cache))) + if (f->cache && iswhite(f->cache)) f->cache = NULL; /* allow cache to be collected */ for (i = 0; i < f->sp->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i = 0; i < f->sp->sizep; i++) /* mark nested protos */ - markobject(g, f->p[i]); + markobjectN(g, f->p[i]); return sizeof(Proto) + sizeof(Proto *) * f->sp->sizep + sizeof(TValue) * f->sp->sizek + marksharedproto(g, f->sp); } - static lu_mem traverseCclosure (global_State *g, CClosure *cl) { int i; for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ @@ -491,34 +511,50 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { return sizeCclosure(cl->nupvalues); } +/* +** open upvalues point to values in a thread, so those values should +** be marked when the thread is traversed except in the atomic phase +** (because then the value cannot be changed by the thread and the +** thread may not be traversed again) +*/ static lu_mem traverseLclosure (global_State *g, LClosure *cl) { int i; - markobject(g, cl->p); /* mark its prototype */ - for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ - markobject(g, cl->upvals[i]); + markobjectN(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ + UpVal *uv = cl->upvals[i]; + if (uv != NULL) { + if (upisopen(uv) && g->gcstate != GCSinsideatomic) + uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ + else + markvalue(g, uv->v); + } + } return sizeLclosure(cl->nupvalues); } -static lu_mem traversestack (global_State *g, lua_State *th) { - int n = 0; +static lu_mem traversethread (global_State *g, lua_State *th) { StkId o = th->stack; if (o == NULL) return 1; /* stack not completely built yet */ + lua_assert(g->gcstate == GCSinsideatomic || + th->openupval == NULL || isintwups(th)); for (; o < th->top; o++) /* mark live elements in the stack */ markvalue(g, o); - if (g->gcstate == GCSatomic) { /* final traversal? */ + if (g->gcstate == GCSinsideatomic) { /* final traversal? */ StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); + /* 'remarkupvals' may have removed thread from 'twups' list */ + if (!isintwups(th) && th->openupval != NULL) { + th->twups = g->twups; /* link it back to the list */ + g->twups = th; + } } - else { /* count call infos to compute size */ - CallInfo *ci; - for (ci = &th->base_ci; ci != th->ci; ci = ci->next) - n++; - } - return sizeof(lua_State) + sizeof(TValue) * th->stacksize + - sizeof(CallInfo) * n; + else if (g->gckind != KGC_EMERGENCY) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->nci); } @@ -531,7 +567,7 @@ static void propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); - switch (gch(o)->tt) { + switch (o->tt) { case LUA_TTABLE: { Table *h = gco2t(o); g->gray = h->gclist; /* remove from 'gray' list */ @@ -553,10 +589,9 @@ static void propagatemark (global_State *g) { case LUA_TTHREAD: { lua_State *th = gco2th(o); g->gray = th->gclist; /* remove from 'gray' list */ - th->gclist = g->grayagain; - g->grayagain = o; /* insert into 'grayagain' list */ + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ black2gray(o); - size = traversestack(g, th); + size = traversethread(g, th); break; } case LUA_TPROTO: { @@ -576,35 +611,12 @@ static void propagateall (global_State *g) { } -static void propagatelist (global_State *g, GCObject *l) { - lua_assert(g->gray == NULL); /* no grays left */ - g->gray = l; - propagateall(g); /* traverse all elements from 'l' */ -} - -/* -** retraverse all gray lists. Because tables may be reinserted in other -** lists when traversed, traverse the original lists to avoid traversing -** twice the same table (which is not wrong, but inefficient) -*/ -static void retraversegrays (global_State *g) { - GCObject *weak = g->weak; /* save original lists */ - GCObject *grayagain = g->grayagain; - GCObject *ephemeron = g->ephemeron; - g->weak = g->grayagain = g->ephemeron = NULL; - propagateall(g); /* traverse main gray list */ - propagatelist(g, grayagain); - propagatelist(g, weak); - propagatelist(g, ephemeron); -} - - static void convergeephemerons (global_State *g) { int changed; do { GCObject *w; GCObject *next = g->ephemeron; /* get ephemeron list */ - g->ephemeron = NULL; /* tables will return to this list when traversed */ + g->ephemeron = NULL; /* tables may return to this list when traversed */ changed = 0; while ((w = next) != NULL) { next = gco2t(w)->gclist; @@ -652,7 +664,7 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); - int i; + unsigned int i; for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; if (iscleared(g, o)) /* value was collected? */ @@ -668,26 +680,45 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { } +void luaC_upvdeccount (lua_State *L, UpVal *uv) { + lua_assert(uv->refcount > 0); + uv->refcount--; + if (uv->refcount == 0 && !upisopen(uv)) + luaM_free(L, uv); +} + + +static void freeLclosure (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = cl->upvals[i]; + if (uv) + luaC_upvdeccount(L, uv); + } + luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); +} + + static void freeobj (lua_State *L, GCObject *o) { - switch (gch(o)->tt) { + switch (o->tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TLCL: { - luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); + freeLclosure(L, gco2lcl(o)); break; } case LUA_TCCL: { luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); break; } - case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2t(o)); break; case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; case LUA_TSHRSTR: - G(L)->strt.nuse--; - /* go through */ + luaS_remove(L, gco2ts(o)); /* remove it from hash table */ + luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); + break; case LUA_TLNGSTR: { - luaM_freemem(L, o, sizestring(gco2ts(o))); + luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); break; } default: lua_assert(0); @@ -699,61 +730,27 @@ static void freeobj (lua_State *L, GCObject *o) { static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); -/* -** sweep the (open) upvalues of a thread and resize its stack and -** list of call-info structures. -*/ -static void sweepthread (lua_State *L, lua_State *L1) { - if (L1->stack == NULL) return; /* stack not completely built yet */ - sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ - luaE_freeCI(L1); /* free extra CallInfo slots */ - /* should not change the stack during an emergency gc cycle */ - if (G(L)->gckind != KGC_EMERGENCY) - luaD_shrinkstack(L1); -} - - /* ** sweep at most 'count' elements from a list of GCObjects erasing dead -** objects, where a dead (not alive) object is one marked with the "old" -** (non current) white and not fixed. -** In non-generational mode, change all non-dead objects back to white, -** preparing for next collection cycle. -** In generational mode, keep black objects black, and also mark them as -** old; stop when hitting an old object, as all objects after that -** one will be old too. -** When object is a thread, sweep its list of open upvalues too. +** objects, where a dead object is one marked with the old (non current) +** white; change all non-dead objects back to white, preparing for next +** collection cycle. Return where to continue the traversal or NULL if +** list is finished. */ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { global_State *g = G(L); int ow = otherwhite(g); - int toclear, toset; /* bits to clear and to set in all live objects */ - int tostop; /* stop sweep when this is true */ - if (isgenerational(g)) { /* generational mode? */ - toclear = ~0; /* clear nothing */ - toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ - tostop = bitmask(OLDBIT); /* do not sweep old generation */ - } - else { /* normal mode */ - toclear = maskcolors; /* clear all color bits + old bit */ - toset = luaC_white(g); /* make object white */ - tostop = 0; /* do not stop */ - } + int white = luaC_white(g); /* current white */ while (*p != NULL && count-- > 0) { GCObject *curr = *p; - int marked = gch(curr)->marked; + int marked = curr->marked; if (isdeadm(ow, marked)) { /* is 'curr' dead? */ - *p = gch(curr)->next; /* remove 'curr' from list */ + *p = curr->next; /* remove 'curr' from list */ freeobj(L, curr); /* erase 'curr' */ } - else { - if (testbits(marked, tostop)) - return NULL; /* stop sweeping this list */ - if (gch(curr)->tt == LUA_TTHREAD) - sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ - /* update marks */ - gch(curr)->marked = cast_byte((marked & toclear) | toset); - p = &gch(curr)->next; /* go to next element */ + else { /* change mark to 'white' */ + curr->marked = cast_byte((marked & maskcolors) | white); + p = &curr->next; /* go to next element */ } } return (*p == NULL) ? NULL : p; @@ -764,7 +761,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { ** sweep a list until a live object (or end of list) */ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { - GCObject ** old = p; + GCObject **old = p; int i = 0; do { i++; @@ -783,26 +780,27 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { ** ======================================================= */ -static void checkSizes (lua_State *L) { - global_State *g = G(L); - if (g->gckind != KGC_EMERGENCY) { /* do not change sizes in emergency */ - int hs = g->strt.size / 2; /* half the size of the string table */ - if (g->strt.nuse < cast(lu_int32, hs)) /* using less than that half? */ - luaS_resize(L, hs); /* halve its size */ - luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */ +/* +** If possible, shrink string table +*/ +static void checkSizes (lua_State *L, global_State *g) { + if (g->gckind != KGC_EMERGENCY) { + l_mem olddebt = g->GCdebt; + if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ + luaS_resize(L, g->strt.size / 2); /* shrink it a little */ + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ } } static GCObject *udata2finalize (global_State *g) { GCObject *o = g->tobefnz; /* get first element */ - lua_assert(isfinalized(o)); - g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ - gch(o)->next = g->allgc; /* return it to 'allgc' list */ + lua_assert(tofinalize(o)); + g->tobefnz = o->next; /* remove it from 'tobefnz' list */ + o->next = g->allgc; /* return it to 'allgc' list */ g->allgc = o; - resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */ - lua_assert(!isold(o)); /* see MOVE OLD rule */ - if (!keepinvariantout(g)) /* not keeping invariant? */ + resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ + if (issweepphase(g)) makewhite(g, o); /* "sweep" object */ return o; } @@ -810,7 +808,7 @@ static GCObject *udata2finalize (global_State *g) { static void dothecall (lua_State *L, void *ud) { UNUSED(ud); - luaD_call(L, L->top - 2, 0, 0); + luaD_callnoyield(L, L->top - 2, 0); } @@ -846,29 +844,58 @@ static void GCTM (lua_State *L, int propagateerrors) { } +/* +** call a few (up to 'g->gcfinnum') finalizers +*/ +static int runafewfinalizers (lua_State *L) { + global_State *g = G(L); + unsigned int i; + lua_assert(!g->tobefnz || g->gcfinnum > 0); + for (i = 0; g->tobefnz && i < g->gcfinnum; i++) + GCTM(L, 1); /* call one finalizer */ + g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ + : g->gcfinnum * 2; /* else call a few more next time */ + return i; +} + + +/* +** call all pending finalizers +*/ +static void callallpendingfinalizers (lua_State *L, int propagateerrors) { + global_State *g = G(L); + while (g->tobefnz) + GCTM(L, propagateerrors); +} + + +/* +** find last 'next' field in list 'p' list (to add elements in its end) +*/ +static GCObject **findlast (GCObject **p) { + while (*p != NULL) + p = &(*p)->next; + return p; +} + + /* ** move all unreachable objects (or 'all' objects) that need ** finalization from list 'finobj' to list 'tobefnz' (to be finalized) */ -static void separatetobefnz (lua_State *L, int all) { - global_State *g = G(L); - GCObject **p = &g->finobj; +static void separatetobefnz (global_State *g, int all) { GCObject *curr; - GCObject **lastnext = &g->tobefnz; - /* find last 'next' field in 'tobefnz' list (to add elements in its end) */ - while (*lastnext != NULL) - lastnext = &gch(*lastnext)->next; + GCObject **p = &g->finobj; + GCObject **lastnext = findlast(&g->tobefnz); while ((curr = *p) != NULL) { /* traverse all finalizable objects */ - lua_assert(!isfinalized(curr)); - lua_assert(testbit(gch(curr)->marked, SEPARATED)); + lua_assert(tofinalize(curr)); if (!(iswhite(curr) || all)) /* not being collected? */ - p = &gch(curr)->next; /* don't bother with it */ + p = &curr->next; /* don't bother with it */ else { - l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ - *p = gch(curr)->next; /* remove 'curr' from 'finobj' list */ - gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ + *p = curr->next; /* remove 'curr' from 'finobj' list */ + curr->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; - lastnext = &gch(curr)->next; + lastnext = &curr->next; } } } @@ -880,33 +907,29 @@ static void separatetobefnz (lua_State *L, int all) { */ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { global_State *g = G(L); - if (testbit(gch(o)->marked, SEPARATED) || /* obj. is already separated... */ - isfinalized(o) || /* ... or is finalized... */ - gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ + if (tofinalize(o) || /* obj. is already marked... */ + gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ return; /* nothing to be done */ else { /* move 'o' to 'finobj' list */ GCObject **p; - GCheader *ho = gch(o); - if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ - lua_assert(issweepphase(g)); - g->sweepgc = sweeptolive(L, g->sweepgc, NULL); + if (issweepphase(g)) { + makewhite(g, o); /* "sweep" object 'o' */ + if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ + g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */ } /* search for pointer pointing to 'o' */ - for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } - *p = ho->next; /* remove 'o' from root list */ - ho->next = g->finobj; /* link it in list 'finobj' */ + for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } + *p = o->next; /* remove 'o' from 'allgc' list */ + o->next = g->finobj; /* link it in 'finobj' list */ g->finobj = o; - l_setbit(ho->marked, SEPARATED); /* mark it as such */ - if (!keepinvariantout(g)) /* not keeping invariant? */ - makewhite(g, o); /* "sweep" object */ - else - resetoldbit(o); /* see MOVE OLD rule */ + l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ } } /* }====================================================== */ + /* ** {====================================================== ** GC control @@ -915,195 +938,168 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { /* -** set a reasonable "time" to wait before starting a new GC cycle; -** cycle will start when memory use hits threshold +** Set a reasonable "time" to wait before starting a new GC cycle; cycle +** will start when memory use hits threshold. (Division by 'estimate' +** should be OK: it cannot be zero (because Lua cannot even start with +** less than PAUSEADJ bytes). */ -static void setpause (global_State *g, l_mem estimate) { - l_mem debt, threshold; - estimate = estimate / PAUSEADJ; /* adjust 'estimate' */ +static void setpause (global_State *g) { + l_mem threshold, debt; + l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ + lua_assert(estimate > 0); threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ ? estimate * g->gcpause /* no overflow */ : MAX_LMEM; /* overflow; truncate to maximum */ - debt = -cast(l_mem, threshold - gettotalbytes(g)); + debt = gettotalbytes(g) - threshold; luaE_setdebt(g, debt); } -#define sweepphases \ - (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) - - /* -** enter first sweep phase (strings) and prepare pointers for other -** sweep phases. The calls to 'sweeptolive' make pointers point to an -** object inside the list (instead of to the header), so that the real -** sweep do not need to skip objects created between "now" and the start -** of the real sweep. +** Enter first sweep phase. +** The call to 'sweeptolive' makes pointer point to an object inside +** the list (instead of to the header), so that the real sweep do not +** need to skip objects created between "now" and the start of the real +** sweep. ** Returns how many objects it swept. */ static int entersweep (lua_State *L) { global_State *g = G(L); int n = 0; - g->gcstate = GCSsweepstring; - lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); - /* prepare to sweep strings, finalizable objects, and regular objects */ - g->sweepstrgc = 0; - g->sweepfin = sweeptolive(L, &g->finobj, &n); + g->gcstate = GCSswpallgc; + lua_assert(g->sweepgc == NULL); g->sweepgc = sweeptolive(L, &g->allgc, &n); return n; } -/* -** change GC mode -*/ -void luaC_changemode (lua_State *L, int mode) { - global_State *g = G(L); - if (mode == g->gckind) return; /* nothing to change */ - if (mode == KGC_GEN) { /* change to generational mode */ - /* make sure gray lists are consistent */ - luaC_runtilstate(L, bitmask(GCSpropagate)); - g->GCestimate = gettotalbytes(g); - g->gckind = KGC_GEN; - } - else { /* change to incremental mode */ - /* sweep all objects to turn them back to white - (as white has not changed, nothing extra will be collected) */ - g->gckind = KGC_NORMAL; - entersweep(L); - luaC_runtilstate(L, ~sweepphases); - } -} - - -/* -** call all pending finalizers -*/ -static void callallpendingfinalizers (lua_State *L, int propagateerrors) { - global_State *g = G(L); - while (g->tobefnz) { - resetoldbit(g->tobefnz); - GCTM(L, propagateerrors); - } -} - - void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); - int i; - separatetobefnz(L, 1); /* separate all objects with finalizers */ + separatetobefnz(g, 1); /* separate all objects with finalizers */ lua_assert(g->finobj == NULL); callallpendingfinalizers(L, 0); + lua_assert(g->tobefnz == NULL); g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->gckind = KGC_NORMAL; - sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ + sweepwholelist(L, &g->finobj); sweepwholelist(L, &g->allgc); - for (i = 0; i < g->strt.size; i++) /* free all string lists */ - sweepwholelist(L, &g->strt.hash[i]); + sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ lua_assert(g->strt.nuse == 0); } static l_mem atomic (lua_State *L) { global_State *g = G(L); - l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ + l_mem work; GCObject *origweak, *origall; - lua_assert(!iswhite(obj2gco(g->mainthread))); + GCObject *grayagain = g->grayagain; /* save original list */ + lua_assert(g->ephemeron == NULL && g->weak == NULL); + lua_assert(!iswhite(g->mainthread)); + g->gcstate = GCSinsideatomic; + g->GCmemtrav = 0; /* start counting work */ markobject(g, L); /* mark running thread */ /* registry and global metatables may be changed by API */ markvalue(g, &g->l_registry); - markmt(g); /* mark basic metatables */ + markmt(g); /* mark global metatables */ /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); propagateall(g); /* propagate changes */ - work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ - /* traverse objects caught by write barrier and by 'remarkupvals' */ - retraversegrays(g); - work -= g->GCmemtrav; /* restart counting */ + work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ + g->gray = grayagain; + propagateall(g); /* traverse 'grayagain' list */ + g->GCmemtrav = 0; /* restart counting */ convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ - /* clear values from weak tables, before checking finalizers */ + /* Clear values from weak tables, before checking finalizers */ clearvalues(g, g->weak, NULL); clearvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; work += g->GCmemtrav; /* stop counting (objects being finalized) */ - separatetobefnz(L, 0); /* separate objects to be finalized */ + separatetobefnz(g, 0); /* separate objects to be finalized */ + g->gcfinnum = 1; /* there may be objects to be finalized */ markbeingfnz(g); /* mark objects that will be finalized */ - propagateall(g); /* remark, to propagate `preserveness' */ - work -= g->GCmemtrav; /* restart counting */ + propagateall(g); /* remark, to propagate 'resurrection' */ + g->GCmemtrav = 0; /* restart counting */ convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ - clearkeys(g, g->allweak, NULL); /* clear keys from all allweak tables */ + clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ /* clear values from resurrected weak tables */ clearvalues(g, g->weak, origweak); clearvalues(g, g->allweak, origall); + luaS_clearcache(g); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ work += g->GCmemtrav; /* complete counting */ return work; /* estimate of memory marked by 'atomic' */ } +static lu_mem sweepstep (lua_State *L, global_State *g, + int nextstate, GCObject **nextlist) { + if (g->sweepgc) { + l_mem olddebt = g->GCdebt; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + if (g->sweepgc) /* is there still something to sweep? */ + return (GCSWEEPMAX * GCSWEEPCOST); + } + /* else enter next state */ + g->gcstate = nextstate; + g->sweepgc = nextlist; + return 0; +} + + static lu_mem singlestep (lua_State *L) { global_State *g = G(L); switch (g->gcstate) { case GCSpause: { - /* start to count memory traversed */ g->GCmemtrav = g->strt.size * sizeof(GCObject*); - lua_assert(!isgenerational(g)); restartcollection(g); g->gcstate = GCSpropagate; return g->GCmemtrav; } case GCSpropagate: { - if (g->gray) { - lu_mem oldtrav = g->GCmemtrav; - propagatemark(g); - return g->GCmemtrav - oldtrav; /* memory traversed in this step */ - } - else { /* no more `gray' objects */ - lu_mem work; - int sw; - g->gcstate = GCSatomic; /* finish mark phase */ - g->GCestimate = g->GCmemtrav; /* save what was counted */; - work = atomic(L); /* add what was traversed by 'atomic' */ - g->GCestimate += work; /* estimate of total memory traversed */ - sw = entersweep(L); - return work + sw * GCSWEEPCOST; - } + g->GCmemtrav = 0; + lua_assert(g->gray); + propagatemark(g); + if (g->gray == NULL) /* no more gray objects? */ + g->gcstate = GCSatomic; /* finish propagate phase */ + return g->GCmemtrav; /* memory traversed in this step */ } - case GCSsweepstring: { - int i; - for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++) - sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]); - g->sweepstrgc += i; - if (g->sweepstrgc >= g->strt.size) /* no more strings to sweep? */ - g->gcstate = GCSsweepudata; - return i * GCSWEEPCOST; + case GCSatomic: { + lu_mem work; + int sw; + propagateall(g); /* make sure gray list is empty */ + work = atomic(L); /* work is what was traversed by 'atomic' */ + sw = entersweep(L); + g->GCestimate = gettotalbytes(g); /* first estimate */; + return work + sw * GCSWEEPCOST; } - case GCSsweepudata: { - if (g->sweepfin) { - g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX); - return GCSWEEPMAX*GCSWEEPCOST; - } - else { - g->gcstate = GCSsweep; - return 0; - } + case GCSswpallgc: { /* sweep "regular" objects */ + return sweepstep(L, g, GCSswpfinobj, &g->finobj); + } + case GCSswpfinobj: { /* sweep objects with finalizers */ + return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); + } + case GCSswptobefnz: { /* sweep objects to be finalized */ + return sweepstep(L, g, GCSswpend, NULL); } - case GCSsweep: { - if (g->sweepgc) { - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - return GCSWEEPMAX*GCSWEEPCOST; + case GCSswpend: { /* finish sweeps */ + makewhite(g, g->mainthread); /* sweep main thread */ + checkSizes(L, g); + g->gcstate = GCScallfin; + return 0; + } + case GCScallfin: { /* call remaining finalizers */ + if (g->tobefnz && g->gckind != KGC_EMERGENCY) { + int n = runafewfinalizers(L); + return (n * GCFINALIZECOST); } - else { - /* sweep main thread */ - GCObject *mt = obj2gco(g->mainthread); - sweeplist(L, &mt, 1); - checkSizes(L); + else { /* emergency mode or no more finalizers */ g->gcstate = GCSpause; /* finish collection */ - return GCSWEEPCOST; + return 0; } } default: lua_assert(0); return 0; @@ -1122,105 +1118,70 @@ void luaC_runtilstate (lua_State *L, int statesmask) { } -static void generationalcollection (lua_State *L) { - global_State *g = G(L); - lua_assert(g->gcstate == GCSpropagate); - if (g->GCestimate == 0) { /* signal for another major collection? */ - luaC_fullgc(L, 0); /* perform a full regular collection */ - g->GCestimate = gettotalbytes(g); /* update control */ - } +/* +** get GC debt and convert it from Kb to 'work units' (avoid zero debt +** and overflows) +*/ +static l_mem getdebt (global_State *g) { + l_mem debt = g->GCdebt; + int stepmul = g->gcstepmul; + if (debt <= 0) return 0; /* minimal debt */ else { - lu_mem estimate = g->GCestimate; - luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */ - g->gcstate = GCSpropagate; /* skip restart */ - if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) - g->GCestimate = 0; /* signal for a major collection */ - else - g->GCestimate = estimate; /* keep estimate from last major coll. */ - + debt = (debt / STEPMULADJ) + 1; + debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; + return debt; } - setpause(g, gettotalbytes(g)); - lua_assert(g->gcstate == GCSpropagate); } - -static void incstep (lua_State *L) { +/* +** performs a basic GC step when collector is running +*/ +void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem debt = g->GCdebt; - int stepmul = g->gcstepmul; - if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */ - /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */ - debt = (debt / STEPMULADJ) + 1; - debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; - do { /* always perform at least one single step */ - lu_mem work = singlestep(L); /* do some work */ + l_mem debt = getdebt(g); /* GC deficit (be paid now) */ + if (!g->gcrunning) { /* not running? */ + luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ + return; + } + do { /* repeat until pause or enough "credit" (negative debt) */ + lu_mem work = singlestep(L); /* perform one single step */ debt -= work; } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); if (g->gcstate == GCSpause) - setpause(g, g->GCestimate); /* pause until next cycle */ + setpause(g); /* pause until next cycle */ else { - debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */ + debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ luaE_setdebt(g, debt); + runafewfinalizers(L); } } /* -** performs a basic GC step -*/ -void luaC_forcestep (lua_State *L) { - global_State *g = G(L); - int i; - if (isgenerational(g)) generationalcollection(L); - else incstep(L); - /* run a few finalizers (or all of them at the end of a collect cycle) */ - for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) - GCTM(L, 1); /* call one finalizer */ -} - - -/* -** performs a basic GC step only if collector is running -*/ -void luaC_step (lua_State *L) { - global_State *g = G(L); - if (g->gcrunning) luaC_forcestep(L); - else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */ -} - - - -/* -** performs a full GC cycle; if "isemergency", does not call -** finalizers (which could change stack positions) +** Performs a full GC cycle; if 'isemergency', set a flag to avoid +** some operations which could change the interpreter state in some +** unexpected ways (running finalizers and shrinking some structures). +** Before running the collection, check 'keepinvariant'; if it is true, +** there may be some objects marked as black, so the collector has +** to sweep all objects to turn them back to white (as white has not +** changed, nothing will be collected). */ void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); - int origkind = g->gckind; - lua_assert(origkind != KGC_EMERGENCY); - if (isemergency) /* do not run finalizers during emergency GC */ - g->gckind = KGC_EMERGENCY; - else { - g->gckind = KGC_NORMAL; - callallpendingfinalizers(L, 1); - } - if (keepinvariant(g)) { /* may there be some black objects? */ - /* must sweep all objects to turn them back to white - (as white has not changed, nothing will be collected) */ - entersweep(L); + lua_assert(g->gckind == KGC_NORMAL); + if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ + if (keepinvariant(g)) { /* black objects? */ + entersweep(L); /* sweep everything to turn them back to white */ } /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ - luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */ - if (origkind == KGC_GEN) { /* generational mode? */ - /* generational mode must be kept in propagate phase */ - luaC_runtilstate(L, bitmask(GCSpropagate)); - } - g->gckind = origkind; - setpause(g, gettotalbytes(g)); - if (!isemergency) /* do not run finalizers during emergency GC */ - callallpendingfinalizers(L, 1); + luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ + /* estimate must be correct after a full GC cycle */ + lua_assert(g->GCestimate == gettotalbytes(g)); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + g->gckind = KGC_NORMAL; + setpause(g); } /* }====================================================== */ diff --git a/deps/lua/lgc.h b/deps/lua/lgc.h index 84bb1cd..1775ca4 100644 --- a/deps/lua/lgc.h +++ b/deps/lua/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lgc.h,v 2.90 2015/10/21 18:15:15 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -38,36 +38,27 @@ */ #define GCSpropagate 0 #define GCSatomic 1 -#define GCSsweepstring 2 -#define GCSsweepudata 3 -#define GCSsweep 4 -#define GCSpause 5 +#define GCSswpallgc 2 +#define GCSswpfinobj 3 +#define GCSswptobefnz 4 +#define GCSswpend 5 +#define GCScallfin 6 +#define GCSpause 7 #define issweepphase(g) \ - (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) + (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) -#define isgenerational(g) ((g)->gckind == KGC_GEN) /* -** macros to tell when main invariant (white objects cannot point to black -** ones) must be kept. During a non-generational collection, the sweep +** macro to tell when main invariant (white objects cannot point to black +** ones) must be kept. During a collection, the sweep ** phase may break the invariant, as objects turned white may point to ** still-black objects. The invariant is restored when sweep ends and -** all objects are white again. During a generational collection, the -** invariant must be kept all times. +** all objects are white again. */ -#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) - - -/* -** Outside the collector, the state in generational mode is kept in -** 'propagate', so 'keepinvariant' is always true. -*/ -#define keepinvariantout(g) \ - check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \ - g->gcstate <= GCSatomic) +#define keepinvariant(g) ((g)->gcstate <= GCSatomic) /* @@ -83,75 +74,74 @@ #define testbit(x,b) testbits(x, bitmask(b)) -/* Layout for bit use in `marked' field: */ +/* Layout for bit use in 'marked' field: */ #define WHITE0BIT 0 /* object is white (type 0) */ #define WHITE1BIT 1 /* object is white (type 1) */ #define BLACKBIT 2 /* object is black */ -#define FINALIZEDBIT 3 /* object has been separated for finalization */ -#define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */ -#define FIXEDBIT 5 /* object is fixed (should not be collected) */ -#define OLDBIT 6 /* object is old (only in generational mode) */ +#define FINALIZEDBIT 3 /* object has been marked for finalization */ /* bit 7 is currently used by tests (luaL_checkmemory) */ #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) -#define iswhite(x) testbits((x)->gch.marked, WHITEBITS) -#define isblack(x) testbit((x)->gch.marked, BLACKBIT) +#define iswhite(x) testbits((x)->marked, WHITEBITS) +#define isblack(x) testbit((x)->marked, BLACKBIT) #define isgray(x) /* neither white nor black */ \ - (!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT))) - -#define isold(x) testbit((x)->gch.marked, OLDBIT) + (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) -/* MOVE OLD rule: whenever an object is moved to the beginning of - a GC list, its old bit must be cleared */ -#define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT) +#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) -#define otherwhite(g) (g->currentwhite ^ WHITEBITS) +#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) -#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) +#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) -#define changewhite(x) ((x)->gch.marked ^= WHITEBITS) -#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) - -#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) +#define changewhite(x) ((x)->marked ^= WHITEBITS) +#define gray2black(x) l_setbit((x)->marked, BLACKBIT) #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) -#define luaC_condGC(L,c) \ - {if (G(L)->GCdebt > 0) {c;}; condchangemem(L);} -#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);) +/* +** Does one step of collection when debt becomes positive. 'pre'/'pos' +** allows some adjustments to be done only when needed. macro +** 'condchangemem' is used only for heavy tests (forcing a full +** GC cycle on every opportunity) +*/ +#define luaC_condGC(L,pre,pos) \ + { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ + condchangemem(L,pre,pos); } +/* more often than not, 'pre'/'pos' are empty */ +#define luaC_checkGC(L) luaC_condGC(L,,) -#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ - luaC_barrier_(L,obj2gco(p),gcvalue(v)); } -#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ - luaC_barrierback_(L,p); } +#define luaC_barrier(L,p,v) ( \ + (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ + luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) -#define luaC_objbarrier(L,p,o) \ - { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ - luaC_barrier_(L,obj2gco(p),obj2gco(o)); } +#define luaC_barrierback(L,p,v) ( \ + (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ + luaC_barrierback_(L,p) : cast_void(0)) -#define luaC_objbarrierback(L,p,o) \ - { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); } +#define luaC_objbarrier(L,p,o) ( \ + (isblack(p) && iswhite(o)) ? \ + luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) -#define luaC_barrierproto(L,p,c) \ - { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); } +#define luaC_upvalbarrier(L,uv) ( \ + (iscollectable((uv)->v) && !upisopen(uv)) ? \ + luaC_upvalbarrier_(L,uv) : cast_void(0)) +LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); -LUAI_FUNC void luaC_forcestep (lua_State *L); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); -LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, - GCObject **list, int offset); +LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); -LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); -LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c); +LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); +LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); -LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); -LUAI_FUNC void luaC_changemode (lua_State *L, int mode); +LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); + #endif diff --git a/deps/lua/linit.c b/deps/lua/linit.c index a8dc239..7d3b806 100644 --- a/deps/lua/linit.c +++ b/deps/lua/linit.c @@ -1,20 +1,33 @@ /* -** $Id: linit.c,v 1.32.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ +#define linit_c +#define LUA_LIB + /* ** If you embed Lua in your program and need to open the standard ** libraries, call luaL_openlibs in your program. If you need a ** different set of libraries, copy this file to your project and edit ** it to suit your needs. +** +** You can also *preload* libraries, so that a later 'require' can +** open the library, which is already linked to the application. +** For that, do the following code: +** +** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); +** lua_pushcfunction(L, luaopen_modname); +** lua_setfield(L, -2, modname); +** lua_pop(L, 1); // remove _PRELOAD table */ +#include "lprefix.h" -#define linit_c -#define LUA_LIB + +#include #include "lua.h" @@ -34,9 +47,12 @@ static const luaL_Reg loadedlibs[] = { {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, - {LUA_BITLIBNAME, luaopen_bit32}, {LUA_MATHLIBNAME, luaopen_math}, + {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, +#if defined(LUA_COMPAT_BITLIB) + {LUA_BITLIBNAME, luaopen_bit32}, +#endif #if defined(LUA_CACHELIB) {LUA_CACHELIB, luaopen_cache}, #endif @@ -44,27 +60,12 @@ static const luaL_Reg loadedlibs[] = { }; -/* -** these libs are preloaded and must be required before used -*/ -static const luaL_Reg preloadedlibs[] = { - {NULL, NULL} -}; - - LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; - /* call open functions from 'loadedlibs' and set results to global table */ + /* "require" functions from 'loadedlibs' and set results to global table */ for (lib = loadedlibs; lib->func; lib++) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } - /* add open functions from 'preloadedlibs' into 'package.preload' table */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); - for (lib = preloadedlibs; lib->func; lib++) { - lua_pushcfunction(L, lib->func); - lua_setfield(L, -2, lib->name); - } - lua_pop(L, 1); /* remove _PRELOAD table */ } diff --git a/deps/lua/liolib.c b/deps/lua/liolib.c index 2a4ec4a..a91ba39 100644 --- a/deps/lua/liolib.c +++ b/deps/lua/liolib.c @@ -1,120 +1,139 @@ /* -** $Id: liolib.c,v 2.112.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: liolib.c,v 2.148 2015/11/23 11:36:11 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ +#define liolib_c +#define LUA_LIB -/* -** This definition must come before the inclusion of 'stdio.h'; it -** should not affect non-POSIX systems -*/ -#if !defined(_FILE_OFFSET_BITS) -#define _LARGEFILE_SOURCE 1 -#define _FILE_OFFSET_BITS 64 -#endif +#include "lprefix.h" +#include #include +#include #include #include #include -#define liolib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" #include "lualib.h" -#if !defined(lua_checkmode) + /* -** Check whether 'mode' matches '[rwa]%+?b?'. ** Change this macro to accept other modes for 'fopen' besides ** the standard ones. */ -#define lua_checkmode(mode) \ +#if !defined(l_checkmode) + +/* accepted extensions to 'mode' in 'fopen' */ +#if !defined(L_MODEEXT) +#define L_MODEEXT "b" +#endif + +/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ +#define l_checkmode(mode) \ (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ - (*mode != '+' || ++mode) && /* skip if char is '+' */ \ - (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \ - (*mode == '\0')) + (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ \ + (strspn(mode, L_MODEEXT) == strlen(mode))) #endif /* ** {====================================================== -** lua_popen spawns a new process connected to the current +** l_popen spawns a new process connected to the current ** one through the file streams. ** ======================================================= */ -#if !defined(lua_popen) /* { */ - -#if defined(LUA_USE_POPEN) /* { */ +#if !defined(l_popen) /* { */ -#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) -#define lua_pclose(L,file) ((void)L, pclose(file)) +#if defined(LUA_USE_POSIX) /* { */ -#elif defined(LUA_WIN) /* }{ */ +#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) +#define l_pclose(L,file) (pclose(file)) -#define lua_popen(L,c,m) ((void)L, _popen(c,m)) -#define lua_pclose(L,file) ((void)L, _pclose(file)) +#elif defined(LUA_USE_WINDOWS) /* }{ */ +#define l_popen(L,c,m) (_popen(c,m)) +#define l_pclose(L,file) (_pclose(file)) #else /* }{ */ -#define lua_popen(L,c,m) ((void)((void)c, m), \ - luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) -#define lua_pclose(L,file) ((void)((void)L, file), -1) - +/* ISO C definitions */ +#define l_popen(L,c,m) \ + ((void)((void)c, m), \ + luaL_error(L, "'popen' not supported"), \ + (FILE*)0) +#define l_pclose(L,file) ((void)L, (void)file, -1) #endif /* } */ -#endif /* } */ +#endif /* } */ /* }====================================================== */ +#if !defined(l_getc) /* { */ + +#if defined(LUA_USE_POSIX) +#define l_getc(f) getc_unlocked(f) +#define l_lockfile(f) flockfile(f) +#define l_unlockfile(f) funlockfile(f) +#else +#define l_getc(f) getc(f) +#define l_lockfile(f) ((void)0) +#define l_unlockfile(f) ((void)0) +#endif + +#endif /* } */ + + /* ** {====================================================== -** lua_fseek: configuration for longer offsets +** l_fseek: configuration for longer offsets ** ======================================================= */ -#if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */ +#if !defined(l_fseek) /* { */ #if defined(LUA_USE_POSIX) /* { */ +#include + #define l_fseek(f,o,w) fseeko(f,o,w) #define l_ftell(f) ftello(f) #define l_seeknum off_t -#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \ +#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ -/* Windows (but not DDK) and Visual C++ 2005 or higher */ +/* Windows (but not DDK) and Visual C++ 2005 or higher */ #define l_fseek(f,o,w) _fseeki64(f,o,w) #define l_ftell(f) _ftelli64(f) #define l_seeknum __int64 -#endif /* } */ - -#endif /* } */ - +#else /* }{ */ -#if !defined(l_fseek) /* default definitions */ +/* ISO C definitions */ #define l_fseek(f,o,w) fseek(f,o,w) #define l_ftell(f) ftell(f) #define l_seeknum long -#endif + +#endif /* } */ + +#endif /* } */ /* }====================================================== */ #define IO_PREFIX "_IO_" +#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) #define IO_INPUT (IO_PREFIX "input") #define IO_OUTPUT (IO_PREFIX "output") @@ -161,9 +180,9 @@ static FILE *tofile (lua_State *L) { /* -** When creating file handles, always creates a `closed' file handle +** When creating file handles, always creates a 'closed' file handle ** before opening the actual file; so, if there is a memory error, the -** file is not left opened. +** handle is in a consistent state. */ static LStream *newprefile (lua_State *L) { LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); @@ -173,9 +192,14 @@ static LStream *newprefile (lua_State *L) { } +/* +** Calls the 'close' function from a file handle. The 'volatile' avoids +** a bug in some versions of the Clang compiler (e.g., clang 3.0 for +** 32 bits). +*/ static int aux_close (lua_State *L) { LStream *p = tolstream(L); - lua_CFunction cf = p->closef; + volatile lua_CFunction cf = p->closef; p->closef = NULL; /* mark stream as closed */ return (*cf)(L); /* close it */ } @@ -219,7 +243,7 @@ static void opencheck (lua_State *L, const char *fname, const char *mode) { LStream *p = newfile(L); p->f = fopen(fname, mode); if (p->f == NULL) - luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno)); + luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); } @@ -228,7 +252,7 @@ static int io_open (lua_State *L) { const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newfile(L); const char *md = mode; /* to traverse/check mode */ - luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode"); + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } @@ -239,7 +263,7 @@ static int io_open (lua_State *L) { */ static int io_pclose (lua_State *L) { LStream *p = tolstream(L); - return luaL_execresult(L, lua_pclose(L, p->f)); + return luaL_execresult(L, l_pclose(L, p->f)); } @@ -247,7 +271,7 @@ static int io_popen (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newprefile(L); - p->f = lua_popen(L, filename, mode); + p->f = l_popen(L, filename, mode); p->closef = &io_pclose; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } @@ -265,7 +289,7 @@ static FILE *getiofile (lua_State *L, const char *findex) { lua_getfield(L, LUA_REGISTRYINDEX, findex); p = (LStream *)lua_touserdata(L, -1); if (isclosed(p)) - luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX)); + luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); return p->f; } @@ -300,15 +324,18 @@ static int io_output (lua_State *L) { static int io_readline (lua_State *L); +/* +** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit +** in the limit for upvalues of a closure) +*/ +#define MAXARGLINE 250 + static void aux_lines (lua_State *L, int toclose) { - int i; int n = lua_gettop(L) - 1; /* number of arguments to read */ - /* ensure that arguments will fit here and into 'io_readline' stack */ - luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options"); - lua_pushvalue(L, 1); /* file handle */ + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); lua_pushinteger(L, n); /* number of arguments to read */ lua_pushboolean(L, toclose); /* close/not close file when finished */ - for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */ + lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ lua_pushcclosure(L, io_readline, 3 + n); } @@ -347,13 +374,88 @@ static int io_lines (lua_State *L) { */ -static int read_number (lua_State *L, FILE *f) { - lua_Number d; - if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { - lua_pushnumber(L, d); - return 1; +/* maximum length of a numeral */ +#define MAXRN 200 + +/* auxiliary structure used by 'read_number' */ +typedef struct { + FILE *f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[MAXRN + 1]; /* +1 for ending '\0' */ +} RN; + + +/* +** Add current char to buffer (if not out of space) and read next one +*/ +static int nextc (RN *rn) { + if (rn->n >= MAXRN) { /* buffer overflow? */ + rn->buff[0] = '\0'; /* invalidate result */ + return 0; /* fail */ } else { + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; + } +} + + +/* +** Accept current char if it is in 'set' (of size 1 or 2) +*/ +static int test2 (RN *rn, const char *set) { + if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0')) + return nextc(rn); + else return 0; +} + + +/* +** Read a sequence of (hex)digits +*/ +static int readdigits (RN *rn, int hex) { + int count = 0; + while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; +} + + +/* +** Read a number: first reads a valid prefix of a numeral into a buffer. +** Then it calls 'lua_stringtonumber' to check whether the format is +** correct and to convert it to a Lua number +*/ +static int read_number (lua_State *L, FILE *f) { + RN rn; + int count = 0; + int hex = 0; + char decp[2]; + rn.f = f; rn.n = 0; + decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ + decp[1] = '\0'; + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional signal */ + if (test2(&rn, "0")) { + if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(&rn, hex); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hex); /* fractional part */ + if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ + test2(&rn, "-+"); /* exponent signal */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ + return 1; /* ok */ + else { /* invalid format */ lua_pushnil(L); /* "result" to be removed */ return 0; /* read fails */ } @@ -362,48 +464,42 @@ static int read_number (lua_State *L, FILE *f) { static int test_eof (lua_State *L, FILE *f) { int c = getc(f); - ungetc(c, f); - lua_pushlstring(L, NULL, 0); + ungetc(c, f); /* no-op when c == EOF */ + lua_pushliteral(L, ""); return (c != EOF); } static int read_line (lua_State *L, FILE *f, int chop) { luaL_Buffer b; + int c = '\0'; luaL_buffinit(L, &b); - for (;;) { - size_t l; - char *p = luaL_prepbuffer(&b); - if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ - luaL_pushresult(&b); /* close buffer */ - return (lua_rawlen(L, -1) > 0); /* check whether read something */ - } - l = strlen(p); - if (l == 0 || p[l-1] != '\n') - luaL_addsize(&b, l); - else { - luaL_addsize(&b, l - chop); /* chop 'eol' if needed */ - luaL_pushresult(&b); /* close buffer */ - return 1; /* read at least an `eol' */ - } + while (c != EOF && c != '\n') { /* repeat until end of line */ + char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ + int i = 0; + l_lockfile(f); /* no memory errors can happen inside the lock */ + while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') + buff[i++] = c; + l_unlockfile(f); + luaL_addsize(&b, i); } + if (!chop && c == '\n') /* want a newline and have one? */ + luaL_addchar(&b, c); /* add ending newline to result */ + luaL_pushresult(&b); /* close buffer */ + /* return ok if read something (either a newline or something else) */ + return (c == '\n' || lua_rawlen(L, -1) > 0); } -#define MAX_SIZE_T (~(size_t)0) - static void read_all (lua_State *L, FILE *f) { - size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */ + size_t nr; luaL_Buffer b; luaL_buffinit(L, &b); - for (;;) { - char *p = luaL_prepbuffsize(&b, rlen); - size_t nr = fread(p, sizeof(char), rlen, f); + do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ + char *p = luaL_prepbuffer(&b); + nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); luaL_addsize(&b, nr); - if (nr < rlen) break; /* eof? */ - else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */ - rlen *= 2; /* double buffer size at each iteration */ - } + } while (nr == LUAL_BUFFERSIZE); luaL_pushresult(&b); /* close buffer */ } @@ -435,13 +531,13 @@ static int g_read (lua_State *L, FILE *f, int first) { success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)lua_tointeger(L, n); + size_t l = (size_t)luaL_checkinteger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { - const char *p = lua_tostring(L, n); - luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); - switch (p[1]) { + const char *p = luaL_checkstring(L, n); + if (*p == '*') p++; /* skip optional '*' (for compatibility) */ + switch (*p) { case 'n': /* number */ success = read_number(L, f); break; @@ -488,11 +584,12 @@ static int io_readline (lua_State *L) { if (isclosed(p)) /* file is already closed? */ return luaL_error(L, "file is already closed"); lua_settop(L , 1); + luaL_checkstack(L, n, "too many arguments"); for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ lua_pushvalue(L, lua_upvalueindex(3 + i)); n = g_read(L, p->f, 2); /* 'n' is number of results */ lua_assert(n > 0); /* should return at least a nil */ - if (!lua_isnil(L, -n)) /* read at least one value? */ + if (lua_toboolean(L, -n)) /* read at least one value? */ return n; /* return them */ else { /* first result is nil: EOF or error */ if (n > 1) { /* is there error information? */ @@ -517,8 +614,10 @@ static int g_write (lua_State *L, FILE *f, int arg) { for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ - status = status && - fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; + int len = lua_isinteger(L, arg) + ? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) + : fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)); + status = status && (len > 0); } else { size_t l; @@ -548,15 +647,15 @@ static int f_seek (lua_State *L) { static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Number p3 = luaL_optnumber(L, 3, 0); + lua_Integer p3 = luaL_optinteger(L, 3, 0); l_seeknum offset = (l_seeknum)p3; - luaL_argcheck(L, (lua_Number)offset == p3, 3, + luaL_argcheck(L, (lua_Integer)offset == p3, 3, "not an integer in proper range"); op = l_fseek(f, offset, mode[op]); if (op) return luaL_fileresult(L, 0, NULL); /* error */ else { - lua_pushnumber(L, (lua_Number)l_ftell(f)); + lua_pushinteger(L, (lua_Integer)l_ftell(f)); return 1; } } @@ -568,7 +667,7 @@ static int f_setvbuf (lua_State *L) { FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], sz); + int res = setvbuf(f, NULL, mode[op], (size_t)sz); return luaL_fileresult(L, res == 0, NULL); } diff --git a/deps/lua/llex.c b/deps/lua/llex.c index c4b820e..16ea3eb 100644 --- a/deps/lua/llex.c +++ b/deps/lua/llex.c @@ -1,20 +1,24 @@ /* -** $Id: llex.c,v 2.63.1.2 2013/08/30 15:49:41 roberto Exp $ +** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ +#define llex_c +#define LUA_CORE + +#include "lprefix.h" + #include #include -#define llex_c -#define LUA_CORE - #include "lua.h" #include "lctype.h" +#include "ldebug.h" #include "ldo.h" +#include "lgc.h" #include "llex.h" #include "lobject.h" #include "lparser.h" @@ -38,8 +42,9 @@ static const char *const luaX_tokens [] = { "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", - "..", "...", "==", ">=", "<=", "~=", "::", "", - "", "", "" + "//", "..", "...", "==", ">=", "<=", "~=", + "<<", ">>", "::", "", + "", "", "", "" }; @@ -53,7 +58,7 @@ static void save (LexState *ls, int c) { Mbuffer *b = ls->buff; if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { size_t newsize; - if (luaZ_sizebuffer(b) >= MAX_SIZET/2) + if (luaZ_sizebuffer(b) >= MAX_SIZE/2) lexerror(ls, "lexical element too long", 0); newsize = luaZ_sizebuffer(b) * 2; luaZ_resizebuffer(ls->L, b, newsize); @@ -64,24 +69,25 @@ static void save (LexState *ls, int c) { void luaX_init (lua_State *L) { int i; + TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ + luaC_fix(L, obj2gco(e)); /* never collect this name */ for (i=0; itsv.extra = cast_byte(i+1); /* reserved word */ + luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */ + ts->extra = cast_byte(i+1); /* reserved word */ } } const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { /* single-byte symbols? */ - lua_assert(token == cast(unsigned char, token)); - return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) : - luaO_pushfstring(ls->L, "char(%d)", token); + lua_assert(token == cast_uchar(token)); + return luaO_pushfstring(ls->L, "'%c'", token); } else { const char *s = luaX_tokens[token - FIRST_RESERVED]; if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ - return luaO_pushfstring(ls->L, LUA_QS, s); + return luaO_pushfstring(ls->L, "'%s'", s); else /* names, strings, and numerals */ return s; } @@ -90,11 +96,10 @@ const char *luaX_token2str (LexState *ls, int token) { static const char *txtToken (LexState *ls, int token) { switch (token) { - case TK_NAME: - case TK_STRING: - case TK_NUMBER: + case TK_NAME: case TK_STRING: + case TK_FLT: case TK_INT: save(ls, '\0'); - return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff)); + return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); default: return luaX_token2str(ls, token); } @@ -102,9 +107,7 @@ static const char *txtToken (LexState *ls, int token) { static l_noret lexerror (LexState *ls, const char *msg, int token) { - char buff[LUA_IDSIZE]; - luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE); - msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); + msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); if (token) luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); @@ -117,24 +120,24 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) { /* -** creates a new string and anchors it in function's table so that -** it will not be collected until the end of the function's compilation -** (by that time it should be anchored in function's prototype) +** creates a new string and anchors it in scanner's table so that +** it will not be collected until the end of the compilation +** (by that time it should be anchored somewhere) */ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; - TValue *o; /* entry for `str' */ + TValue *o; /* entry for 'str' */ TString *ts = luaS_newlstr(L, str, l); /* create new string */ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_set(L, ls->fs->h, L->top - 1); - if (ttisnil(o)) { /* not in use yet? (see 'addK') */ + o = luaH_set(L, ls->h, L->top - 1); + if (ttisnil(o)) { /* not in use yet? */ /* boolean value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setbvalue(o, 1); /* t[string] = true */ luaC_checkGC(L); } else { /* string already present */ - ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */ + ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ } L->top--; /* remove string from stack */ return ts; @@ -148,16 +151,17 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { static void inclinenumber (LexState *ls) { int old = ls->current; lua_assert(currIsNewline(ls)); - next(ls); /* skip `\n' or `\r' */ + next(ls); /* skip '\n' or '\r' */ if (currIsNewline(ls) && ls->current != old) - next(ls); /* skip `\n\r' or `\r\n' */ + next(ls); /* skip '\n\r' or '\r\n' */ if (++ls->linenumber >= MAX_INT) - luaX_syntaxerror(ls, "chunk has too many lines"); + lexerror(ls, "chunk has too many lines", 0); } void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, int firstchar) { + ls->t.token = 0; ls->decpoint = '.'; ls->L = L; ls->current = firstchar; @@ -167,8 +171,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, ls->linenumber = 1; ls->lastline = 1; ls->source = source; - ls->envn = luaS_new(L, LUA_ENV); /* create env name */ - luaS_fix(ls->envn); /* never collect this name */ + ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ } @@ -181,12 +184,26 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, */ +static int check_next1 (LexState *ls, int c) { + if (ls->current == c) { + next(ls); + return 1; + } + else return 0; +} + -static int check_next (LexState *ls, const char *set) { - if (ls->current == '\0' || !strchr(set, ls->current)) - return 0; - save_and_next(ls); - return 1; +/* +** Check whether current char is in set 'set' (with two chars) and +** saves it +*/ +static int check_next2 (LexState *ls, const char *set) { + lua_assert(set[2] == '\0'); + if (ls->current == set[0] || ls->current == set[1]) { + save_and_next(ls); + return 1; + } + else return 0; } @@ -194,65 +211,73 @@ static int check_next (LexState *ls, const char *set) { ** change all characters 'from' in buffer to 'to' */ static void buffreplace (LexState *ls, char from, char to) { - size_t n = luaZ_bufflen(ls->buff); - char *p = luaZ_buffer(ls->buff); - while (n--) - if (p[n] == from) p[n] = to; + if (from != to) { + size_t n = luaZ_bufflen(ls->buff); + char *p = luaZ_buffer(ls->buff); + while (n--) + if (p[n] == from) p[n] = to; + } } -#if !defined(getlocaledecpoint) -#define getlocaledecpoint() (localeconv()->decimal_point[0]) -#endif - - -#define buff2d(b,e) luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e) - /* ** in case of format error, try to change decimal point separator to ** the one defined in the current locale and check again */ -static void trydecpoint (LexState *ls, SemInfo *seminfo) { +static void trydecpoint (LexState *ls, TValue *o) { char old = ls->decpoint; - ls->decpoint = getlocaledecpoint(); + ls->decpoint = lua_getlocaledecpoint(); buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ - if (!buff2d(ls->buff, &seminfo->r)) { + if (luaO_str2num(luaZ_buffer(ls->buff), o) == 0) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ - lexerror(ls, "malformed number", TK_NUMBER); + lexerror(ls, "malformed number", TK_FLT); } } /* LUA_NUMBER */ /* -** this function is quite liberal in what it accepts, as 'luaO_str2d' +** this function is quite liberal in what it accepts, as 'luaO_str2num' ** will reject ill-formed numerals. */ -static void read_numeral (LexState *ls, SemInfo *seminfo) { +static int read_numeral (LexState *ls, SemInfo *seminfo) { + TValue obj; const char *expo = "Ee"; int first = ls->current; lua_assert(lisdigit(ls->current)); save_and_next(ls); - if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ + if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ expo = "Pp"; for (;;) { - if (check_next(ls, expo)) /* exponent part? */ - check_next(ls, "+-"); /* optional exponent sign */ - if (lisxdigit(ls->current) || ls->current == '.') + if (check_next2(ls, expo)) /* exponent part? */ + check_next2(ls, "-+"); /* optional exponent sign */ + if (lisxdigit(ls->current)) + save_and_next(ls); + else if (ls->current == '.') save_and_next(ls); - else break; + else break; } save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ - if (!buff2d(ls->buff, &seminfo->r)) /* format error? */ - trydecpoint(ls, seminfo); /* try to update decimal point separator */ + if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ + trydecpoint(ls, &obj); /* try to update decimal point separator */ + if (ttisinteger(&obj)) { + seminfo->i = ivalue(&obj); + return TK_INT; + } + else { + lua_assert(ttisfloat(&obj)); + seminfo->r = fltvalue(&obj); + return TK_FLT; + } } /* -** skip a sequence '[=*[' or ']=*]' and return its number of '='s or -** -1 if sequence is malformed +** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return +** its number of '='s; otherwise, return a negative number (-1 iff there +** are no '='s after initial bracket) */ static int skip_sep (LexState *ls) { int count = 0; @@ -268,18 +293,22 @@ static int skip_sep (LexState *ls) { static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { - save_and_next(ls); /* skip 2nd `[' */ + int line = ls->linenumber; /* initial line (for error message) */ + save_and_next(ls); /* skip 2nd '[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ for (;;) { switch (ls->current) { - case EOZ: - lexerror(ls, (seminfo) ? "unfinished long string" : - "unfinished long comment", TK_EOS); + case EOZ: { /* error */ + const char *what = (seminfo ? "string" : "comment"); + const char *msg = luaO_pushfstring(ls->L, + "unfinished long %s (starting at line %d)", what, line); + lexerror(ls, msg, TK_EOS); break; /* to avoid warnings */ + } case ']': { if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd `]' */ + save_and_next(ls); /* skip 2nd ']' */ goto endloop; } break; @@ -302,40 +331,65 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } -static void escerror (LexState *ls, int *c, int n, const char *msg) { - int i; - luaZ_resetbuffer(ls->buff); /* prepare error message */ - save(ls, '\\'); - for (i = 0; i < n && c[i] != EOZ; i++) - save(ls, c[i]); - lexerror(ls, msg, TK_STRING); +static void esccheck (LexState *ls, int c, const char *msg) { + if (!c) { + if (ls->current != EOZ) + save_and_next(ls); /* add current to buffer for error message */ + lexerror(ls, msg, TK_STRING); + } +} + + +static int gethexa (LexState *ls) { + save_and_next(ls); + esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); + return luaO_hexavalue(ls->current); } static int readhexaesc (LexState *ls) { - int c[3], i; /* keep input for error message */ - int r = 0; /* result accumulator */ - c[0] = 'x'; /* for error message */ - for (i = 1; i < 3; i++) { /* read two hexadecimal digits */ - c[i] = next(ls); - if (!lisxdigit(c[i])) - escerror(ls, c, i + 1, "hexadecimal digit expected"); - r = (r << 4) + luaO_hexavalue(c[i]); + int r = gethexa(ls); + r = (r << 4) + gethexa(ls); + luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ + return r; +} + + +static unsigned long readutf8esc (LexState *ls) { + unsigned long r; + int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ + save_and_next(ls); /* skip 'u' */ + esccheck(ls, ls->current == '{', "missing '{'"); + r = gethexa(ls); /* must have at least one digit */ + while ((save_and_next(ls), lisxdigit(ls->current))) { + i++; + r = (r << 4) + luaO_hexavalue(ls->current); + esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); } + esccheck(ls, ls->current == '}', "missing '}'"); + next(ls); /* skip '}' */ + luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ return r; } +static void utf8esc (LexState *ls) { + char buff[UTF8BUFFSZ]; + int n = luaO_utf8esc(buff, readutf8esc(ls)); + for (; n > 0; n--) /* add 'buff' to string */ + save(ls, buff[UTF8BUFFSZ - n]); +} + + static int readdecesc (LexState *ls) { - int c[3], i; + int i; int r = 0; /* result accumulator */ for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ - c[i] = ls->current; - r = 10*r + c[i] - '0'; - next(ls); + r = 10*r + ls->current - '0'; + save_and_next(ls); } - if (r > UCHAR_MAX) - escerror(ls, c, i, "decimal escape too large"); + esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); + luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ return r; } @@ -353,7 +407,7 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { break; /* to avoid warnings */ case '\\': { /* escape sequences */ int c; /* final character to be saved */ - next(ls); /* do not save the `\' */ + save_and_next(ls); /* keep '\\' for error messages */ switch (ls->current) { case 'a': c = '\a'; goto read_save; case 'b': c = '\b'; goto read_save; @@ -363,12 +417,14 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { case 't': c = '\t'; goto read_save; case 'v': c = '\v'; goto read_save; case 'x': c = readhexaesc(ls); goto read_save; + case 'u': utf8esc(ls); goto no_save; case '\n': case '\r': inclinenumber(ls); c = '\n'; goto only_save; case '\\': case '\"': case '\'': c = ls->current; goto read_save; case EOZ: goto no_save; /* will raise an error next loop */ case 'z': { /* zap following span of spaces */ + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ next(ls); /* skip the 'z' */ while (lisspace(ls->current)) { if (currIsNewline(ls)) inclinenumber(ls); @@ -377,15 +433,18 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { goto no_save; } default: { - if (!lisdigit(ls->current)) - escerror(ls, &ls->current, 1, "invalid escape sequence"); - /* digital escape \ddd */ - c = readdecesc(ls); + esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); + c = readdecesc(ls); /* digital escape '\ddd' */ goto only_save; } } - read_save: next(ls); /* read next character */ - only_save: save(ls, c); /* save 'c' */ + read_save: + next(ls); + /* go through */ + only_save: + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + save(ls, c); + /* go through */ no_save: break; } default: @@ -417,7 +476,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { next(ls); if (ls->current == '[') { /* long comment? */ int sep = skip_sep(ls); - luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ + luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ if (sep >= 0) { read_long_string(ls, NULL, sep); /* skip long comment */ luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ @@ -435,33 +494,41 @@ static int llex (LexState *ls, SemInfo *seminfo) { read_long_string(ls, seminfo, sep); return TK_STRING; } - else if (sep == -1) return '['; - else lexerror(ls, "invalid long string delimiter", TK_STRING); + else if (sep != -1) /* '[=...' missing second bracket */ + lexerror(ls, "invalid long string delimiter", TK_STRING); + return '['; } case '=': { next(ls); - if (ls->current != '=') return '='; - else { next(ls); return TK_EQ; } + if (check_next1(ls, '=')) return TK_EQ; + else return '='; } case '<': { next(ls); - if (ls->current != '=') return '<'; - else { next(ls); return TK_LE; } + if (check_next1(ls, '=')) return TK_LE; + else if (check_next1(ls, '<')) return TK_SHL; + else return '<'; } case '>': { next(ls); - if (ls->current != '=') return '>'; - else { next(ls); return TK_GE; } + if (check_next1(ls, '=')) return TK_GE; + else if (check_next1(ls, '>')) return TK_SHR; + else return '>'; + } + case '/': { + next(ls); + if (check_next1(ls, '/')) return TK_IDIV; + else return '/'; } case '~': { next(ls); - if (ls->current != '=') return '~'; - else { next(ls); return TK_NE; } + if (check_next1(ls, '=')) return TK_NE; + else return '~'; } case ':': { next(ls); - if (ls->current != ':') return ':'; - else { next(ls); return TK_DBCOLON; } + if (check_next1(ls, ':')) return TK_DBCOLON; + else return ':'; } case '"': case '\'': { /* short literal strings */ read_string(ls, ls->current, seminfo); @@ -469,18 +536,17 @@ static int llex (LexState *ls, SemInfo *seminfo) { } case '.': { /* '.', '..', '...', or number */ save_and_next(ls); - if (check_next(ls, ".")) { - if (check_next(ls, ".")) + if (check_next1(ls, '.')) { + if (check_next1(ls, '.')) return TK_DOTS; /* '...' */ else return TK_CONCAT; /* '..' */ } else if (!lisdigit(ls->current)) return '.'; - /* else go through */ + else return read_numeral(ls, seminfo); } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { - read_numeral(ls, seminfo); - return TK_NUMBER; + return read_numeral(ls, seminfo); } case EOZ: { return TK_EOS; @@ -495,7 +561,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { luaZ_bufflen(ls->buff)); seminfo->ts = ts; if (isreserved(ts)) /* reserved word? */ - return ts->tsv.extra - 1 + FIRST_RESERVED; + return ts->extra - 1 + FIRST_RESERVED; else { return TK_NAME; } diff --git a/deps/lua/llex.h b/deps/lua/llex.h index a4acdd3..afb40b5 100644 --- a/deps/lua/llex.h +++ b/deps/lua/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.72.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -14,6 +14,10 @@ #define FIRST_RESERVED 257 +#if !defined(LUA_ENV) +#define LUA_ENV "_ENV" +#endif + /* * WARNING: if you change the order of this enumeration, @@ -26,8 +30,10 @@ enum RESERVED { TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ - TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_DBCOLON, TK_EOS, - TK_NUMBER, TK_NAME, TK_STRING + TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, + TK_SHL, TK_SHR, + TK_DBCOLON, TK_EOS, + TK_FLT, TK_INT, TK_NAME, TK_STRING }; /* number of reserved words */ @@ -36,6 +42,7 @@ enum RESERVED { typedef union { lua_Number r; + lua_Integer i; TString *ts; } SemInfo; /* semantics information */ @@ -51,13 +58,14 @@ typedef struct Token { typedef struct LexState { int current; /* current character (charint) */ int linenumber; /* input line counter */ - int lastline; /* line of last token `consumed' */ + int lastline; /* line of last token 'consumed' */ Token t; /* current token */ Token lookahead; /* look ahead token */ struct FuncState *fs; /* current function (parser) */ struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ + Table *h; /* to avoid collection/reuse strings */ struct Dyndata *dyd; /* dynamic structures used by the parser */ TString *source; /* current source name */ TString *envn; /* environment variable name */ diff --git a/deps/lua/llimits.h b/deps/lua/llimits.h index 152dd05..f21377f 100644 --- a/deps/lua/llimits.h +++ b/deps/lua/llimits.h @@ -1,6 +1,6 @@ /* -** $Id: llimits.h,v 1.103.1.1 2013/04/12 18:48:47 roberto Exp $ -** Limits, basic types, and some other `installation-dependent' definitions +** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $ +** Limits, basic types, and some other 'installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -14,54 +14,77 @@ #include "lua.h" - -typedef unsigned LUA_INT32 lu_int32; - +/* +** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count +** the total memory used by Lua (in bytes). Usually, 'size_t' and +** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. +*/ +#if defined(LUAI_MEM) /* { external definitions? */ typedef LUAI_UMEM lu_mem; - typedef LUAI_MEM l_mem; +#elif LUAI_BITSINT >= 32 /* }{ */ +typedef size_t lu_mem; +typedef ptrdiff_t l_mem; +#else /* 16-bit ints */ /* }{ */ +typedef unsigned long lu_mem; +typedef long l_mem; +#endif /* } */ - -/* chars used as small naturals (so that `char' is reserved for characters) */ +/* chars used as small naturals (so that 'char' is reserved for characters) */ typedef unsigned char lu_byte; -#define MAX_SIZET ((size_t)(~(size_t)0)-2) +/* maximum value for size_t */ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +/* maximum size visible for Lua (must be representable in a lua_Integer */ +#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ + : (size_t)(LUA_MAXINTEGER)) + -#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) -#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2)) +#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) -#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ +#define MAX_INT INT_MAX /* maximum value of an int */ + /* -** conversion of pointer to integer +** conversion of pointer to unsigned integer: ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ -#define IntPoint(p) ((unsigned int)(lu_mem)(p)) +#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) /* type to ensure maximum alignment */ -#if !defined(LUAI_USER_ALIGNMENT_T) -#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } +#if defined(LUAI_USER_ALIGNMENT_T) +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; +#else +typedef union { + lua_Number n; + double u; + void *s; + lua_Integer i; + long l; +} L_Umaxalign; #endif -typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; -/* result of a `usual argument conversion' over lua_Number */ +/* types of 'usual argument conversions' for lua_Number and lua_Integer */ typedef LUAI_UACNUMBER l_uacNumber; +typedef LUAI_UACINT l_uacInt; /* internal assertions for in-house debugging */ #if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) /* to avoid problems with conditions too long */ -#define lua_longassert(c) { if (!(c)) lua_assert(0); } +#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) #else #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) @@ -72,38 +95,49 @@ typedef LUAI_UACNUMBER l_uacNumber; ** assertion for checking API calls */ #if !defined(luai_apicheck) - -#if defined(LUA_USE_APICHECK) -#include -#define luai_apicheck(L,e) assert(e) -#else -#define luai_apicheck(L,e) lua_assert(e) -#endif - +#define luai_apicheck(l,e) lua_assert(e) #endif #define api_check(l,e,msg) luai_apicheck(l,(e) && msg) +/* macro to avoid warnings about unused variables */ #if !defined(UNUSED) -#define UNUSED(x) ((void)(x)) /* to avoid warnings */ +#define UNUSED(x) ((void)(x)) #endif +/* type casts (a macro highlights casts in the code) */ #define cast(t, exp) ((t)(exp)) +#define cast_void(i) cast(void, (i)) #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) #define cast_uchar(i) cast(unsigned char, (i)) +/* cast a signed lua_Integer to lua_Unsigned */ +#if !defined(l_castS2U) +#define l_castS2U(i) ((lua_Unsigned)(i)) +#endif + +/* +** cast a lua_Unsigned to a signed lua_Integer; this cast is +** not strict ISO C, but two-complement architectures should +** work fine. +*/ +#if !defined(l_castU2S) +#define l_castU2S(i) ((lua_Integer)(i)) +#endif + + /* ** non-return type */ #if defined(__GNUC__) #define l_noret void __attribute__((noreturn)) -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && _MSC_VER >= 1200 #define l_noret void __declspec(noreturn) #else #define l_noret void @@ -119,29 +153,50 @@ typedef LUAI_UACNUMBER l_uacNumber; #define LUAI_MAXCCALLS 200 #endif -/* -** maximum number of upvalues in a closure (both C and Lua). (Value -** must fit in an unsigned char.) -*/ -#define MAXUPVAL UCHAR_MAX /* -** type for virtual-machine instructions +** type for virtual-machine instructions; ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ -typedef lu_int32 Instruction; - +#if LUAI_BITSINT >= 32 +typedef unsigned int Instruction; +#else +typedef unsigned long Instruction; +#endif -/* maximum stack for a Lua function */ -#define MAXSTACK 250 +/* +** Maximum length for short strings, that is, strings that are +** internalized. (Cannot be smaller than reserved words or tags for +** metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#if !defined(LUAI_MAXSHORTLEN) +#define LUAI_MAXSHORTLEN 40 +#endif -/* minimum size for the string table (must be power of 2) */ +/* +** Initial size for the string table (must be power of 2). +** The Lua core alone registers ~50 strings (reserved words + +** metaevent keys + a few others). Libraries would typically add +** a few dozens more. +*/ #if !defined(MINSTRTABSIZE) -#define MINSTRTABSIZE 32 +#define MINSTRTABSIZE 128 +#endif + + +/* +** Size of cache for strings in the API. 'N' is the number of +** sets (better be a prime) and "M" is the size of each set (M == 1 +** makes a direct cache.) +*/ +#if !defined(STRCACHE_N) +#define STRCACHE_N 53 +#define STRCACHE_M 2 #endif @@ -151,13 +206,21 @@ typedef lu_int32 Instruction; #endif +/* +** macros that are executed whenever program enters the Lua core +** ('lua_lock') and leaves the core ('lua_unlock') +*/ #if !defined(lua_lock) -#define lua_lock(L) ((void) 0) -#define lua_unlock(L) ((void) 0) +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) #endif +/* +** macro executed during Lua functions at points where the +** function can yield. +*/ #if !defined(luai_threadyield) -#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} #endif @@ -183,127 +246,78 @@ typedef lu_int32 Instruction; #endif #if !defined(luai_userstateresume) -#define luai_userstateresume(L,n) ((void)L) +#define luai_userstateresume(L,n) ((void)L) #endif #if !defined(luai_userstateyield) -#define luai_userstateyield(L,n) ((void)L) +#define luai_userstateyield(L,n) ((void)L) #endif -/* -** lua_number2int is a macro to convert lua_Number to int. -** lua_number2integer is a macro to convert lua_Number to lua_Integer. -** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned. -** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number. -** luai_hashnum is a macro to hash a lua_Number value into an integer. -** The hash must be deterministic and give reasonable values for -** both small and large values (outside the range of integers). -*/ - -#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */ -/* trick with Microsoft assembler for X86 */ - -#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} -#define lua_number2integer(i,n) lua_number2int(i, n) -#define lua_number2unsigned(i,n) \ - {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} - - -#elif defined(LUA_IEEE754TRICK) /* }{ */ -/* the next trick should work on any machine using IEEE754 with - a 32-bit int type */ - -union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; - -#if !defined(LUA_IEEEENDIAN) /* { */ -#define LUAI_EXTRAIEEE \ - static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; -#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33) -#else -#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN -#define LUAI_EXTRAIEEE /* empty */ -#endif /* } */ -#define lua_number2int32(i,n,t) \ - { LUAI_EXTRAIEEE \ - volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ - (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; } -#define luai_hashnum(i,n) \ - { volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \ - (i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */ - -#define lua_number2int(i,n) lua_number2int32(i, n, int) -#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned) +/* +** The luai_num* macros define the primitive operations over numbers. +*/ -/* the trick can be expanded to lua_Integer when it is a 32-bit value */ -#if defined(LUA_IEEELL) -#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) +/* floor division (defined as 'floor(a/b)') */ +#if !defined(luai_numidiv) +#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) #endif -#endif /* } */ - - -/* the following definitions always work, but may be slow */ - -#if !defined(lua_number2int) -#define lua_number2int(i,n) ((i)=(int)(n)) +/* float division */ +#if !defined(luai_numdiv) +#define luai_numdiv(L,a,b) ((a)/(b)) #endif -#if !defined(lua_number2integer) -#define lua_number2integer(i,n) ((i)=(lua_Integer)(n)) +/* +** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when +** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of +** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b) +** ~= floor(a/b)'. That happens when the division has a non-integer +** negative result, which is equivalent to the test below. +*/ +#if !defined(luai_nummod) +#define luai_nummod(L,a,b,m) \ + { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } #endif -#if !defined(lua_number2unsigned) /* { */ -/* the following definition assures proper modulo behavior */ -#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT) -#include -#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1) -#define lua_number2unsigned(i,n) \ - ((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED)) -#else -#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n)) +/* exponentiation */ +#if !defined(luai_numpow) +#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) #endif -#endif /* } */ - -#if !defined(lua_unsigned2number) -/* on several machines, coercion from unsigned to double is slow, - so it may be worth to avoid */ -#define lua_unsigned2number(u) \ - (((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u)) +/* the others are quite standard operations */ +#if !defined(luai_numadd) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numunm(L,a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) #endif -#if defined(ltable_c) && !defined(luai_hashnum) - -#include -#include - -#define luai_hashnum(i,n) { int e; \ - n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ - lua_number2int(i, n); i += e; } - -#endif - /* ** macro to control inclusion of some hard tests on stack reallocation */ #if !defined(HARDSTACKTESTS) -#define condmovestack(L) ((void)0) +#define condmovestack(L,pre,pos) ((void)0) #else /* realloc stack keeping its size */ -#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize) +#define condmovestack(L,pre,pos) \ + { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; } #endif #if !defined(HARDMEMTESTS) -#define condchangemem(L) condmovestack(L) +#define condchangemem(L,pre,pos) ((void)0) #else -#define condchangemem(L) \ - ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1))) +#define condchangemem(L,pre,pos) \ + { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } #endif #endif diff --git a/deps/lua/lmathlib.c b/deps/lua/lmathlib.c index fe9fc54..94815f1 100644 --- a/deps/lua/lmathlib.c +++ b/deps/lua/lmathlib.c @@ -1,16 +1,18 @@ /* -** $Id: lmathlib.c,v 1.83.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lmathlib.c,v 1.117 2015/10/02 15:39:23 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ +#define lmathlib_c +#define LUA_LIB + +#include "lprefix.h" + #include #include -#define lmathlib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -18,13 +20,30 @@ #undef PI -#define PI ((lua_Number)(3.1415926535897932384626433832795)) -#define RADIANS_PER_DEGREE ((lua_Number)(PI/180.0)) - +#define PI (l_mathop(3.141592653589793238462643383279502884)) + + +#if !defined(l_rand) /* { */ +#if defined(LUA_USE_POSIX) +#define l_rand() random() +#define l_srand(x) srandom(x) +#define L_RANDMAX 2147483647 /* (2^31 - 1), following POSIX */ +#else +#define l_rand() rand() +#define l_srand(x) srand(x) +#define L_RANDMAX RAND_MAX +#endif +#endif /* } */ static int math_abs (lua_State *L) { - lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); + if (lua_isinteger(L, 1)) { + lua_Integer n = lua_tointeger(L, 1); + if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); + lua_pushinteger(L, n); + } + else + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); return 1; } @@ -33,31 +52,16 @@ static int math_sin (lua_State *L) { return 1; } -static int math_sinh (lua_State *L) { - lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); - return 1; -} - static int math_cos (lua_State *L) { lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); return 1; } -static int math_cosh (lua_State *L) { - lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); - return 1; -} - static int math_tan (lua_State *L) { lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); return 1; } -static int math_tanh (lua_State *L) { - lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); - return 1; -} - static int math_asin (lua_State *L) { lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); return 1; @@ -69,49 +73,106 @@ static int math_acos (lua_State *L) { } static int math_atan (lua_State *L) { - lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1))); + lua_Number y = luaL_checknumber(L, 1); + lua_Number x = luaL_optnumber(L, 2, 1); + lua_pushnumber(L, l_mathop(atan2)(y, x)); return 1; } -static int math_atan2 (lua_State *L) { - lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); + +static int math_toint (lua_State *L) { + int valid; + lua_Integer n = lua_tointegerx(L, 1, &valid); + if (valid) + lua_pushinteger(L, n); + else { + luaL_checkany(L, 1); + lua_pushnil(L); /* value is not convertible to integer */ + } return 1; } -static int math_ceil (lua_State *L) { - lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1))); - return 1; + +static void pushnumint (lua_State *L, lua_Number d) { + lua_Integer n; + if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ + lua_pushinteger(L, n); /* result is integer */ + else + lua_pushnumber(L, d); /* result is float */ } + static int math_floor (lua_State *L) { - lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1))); + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own floor */ + else { + lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_ceil (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own ceil */ + else { + lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } return 1; } + static int math_fmod (lua_State *L) { - lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); + if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { + lua_Integer d = lua_tointeger(L, 2); + if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ + luaL_argcheck(L, d != 0, 2, "zero"); + lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ + } + else + lua_pushinteger(L, lua_tointeger(L, 1) % d); + } + else + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); return 1; } + +/* +** next function does not use 'modf', avoiding problems with 'double*' +** (which is not compatible with 'float*') when lua_Number is not +** 'double'. +*/ static int math_modf (lua_State *L) { - lua_Number ip; - lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip); - lua_pushnumber(L, ip); - lua_pushnumber(L, fp); + if (lua_isinteger(L ,1)) { + lua_settop(L, 1); /* number is its own integer part */ + lua_pushnumber(L, 0); /* no fractional part */ + } + else { + lua_Number n = luaL_checknumber(L, 1); + /* integer part (rounds toward zero) */ + lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); + pushnumint(L, ip); + /* fractional part (test needed for inf/-inf) */ + lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); + } return 2; } + static int math_sqrt (lua_State *L) { lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); return 1; } -static int math_pow (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - lua_Number y = luaL_checknumber(L, 2); - lua_pushnumber(L, l_mathop(pow)(x, y)); + +static int math_ult (lua_State *L) { + lua_Integer a = luaL_checkinteger(L, 1); + lua_Integer b = luaL_checkinteger(L, 2); + lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); return 1; } @@ -122,145 +183,208 @@ static int math_log (lua_State *L) { res = l_mathop(log)(x); else { lua_Number base = luaL_checknumber(L, 2); - if (base == (lua_Number)10.0) res = l_mathop(log10)(x); +#if !defined(LUA_USE_C89) + if (base == 2.0) res = l_mathop(log2)(x); else +#endif + if (base == 10.0) res = l_mathop(log10)(x); else res = l_mathop(log)(x)/l_mathop(log)(base); } lua_pushnumber(L, res); return 1; } -#if defined(LUA_COMPAT_LOG10) -static int math_log10 (lua_State *L) { - lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); - return 1; -} -#endif - static int math_exp (lua_State *L) { lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); return 1; } static int math_deg (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); + lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); return 1; } static int math_rad (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); - return 1; -} - -static int math_frexp (lua_State *L) { - int e; - lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); - lua_pushinteger(L, e); - return 2; -} - -static int math_ldexp (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - int ep = luaL_checkint(L, 2); - lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); return 1; } - static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ - lua_Number dmin = luaL_checknumber(L, 1); + int imin = 1; /* index of current minimum value */ int i; - for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); - if (d < dmin) - dmin = d; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, i, imin, LUA_OPLT)) + imin = i; } - lua_pushnumber(L, dmin); + lua_pushvalue(L, imin); return 1; } static int math_max (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ - lua_Number dmax = luaL_checknumber(L, 1); + int imax = 1; /* index of current maximum value */ int i; - for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); - if (d > dmax) - dmax = d; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, imax, i, LUA_OPLT)) + imax = i; } - lua_pushnumber(L, dmax); + lua_pushvalue(L, imax); return 1; } - +/* +** This function uses 'double' (instead of 'lua_Number') to ensure that +** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0' +** will keep full precision (ensuring that 'r' is always less than 1.0.) +*/ static int math_random (lua_State *L) { - /* the `%' avoids the (rare) case of r==1, and is needed also because on - some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ - lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; + lua_Integer low, up; + double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0)); switch (lua_gettop(L)) { /* check number of arguments */ case 0: { /* no arguments */ - lua_pushnumber(L, r); /* Number between 0 and 1 */ - break; + lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ + return 1; } case 1: { /* only upper limit */ - lua_Number u = luaL_checknumber(L, 1); - luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty"); - lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */ + low = 1; + up = luaL_checkinteger(L, 1); break; } case 2: { /* lower and upper limits */ - lua_Number l = luaL_checknumber(L, 1); - lua_Number u = luaL_checknumber(L, 2); - luaL_argcheck(L, l <= u, 2, "interval is empty"); - lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */ + low = luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 2); break; } default: return luaL_error(L, "wrong number of arguments"); } + /* random integer in the interval [low, up] */ + luaL_argcheck(L, low <= up, 1, "interval is empty"); + luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, + "interval too large"); + r *= (double)(up - low) + 1.0; + lua_pushinteger(L, (lua_Integer)r + low); return 1; } static int math_randomseed (lua_State *L) { - srand(luaL_checkunsigned(L, 1)); - (void)rand(); /* discard first value to avoid undesirable correlations */ + l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); + (void)l_rand(); /* discard first value to avoid undesirable correlations */ return 0; } +static int math_type (lua_State *L) { + if (lua_type(L, 1) == LUA_TNUMBER) { + if (lua_isinteger(L, 1)) + lua_pushliteral(L, "integer"); + else + lua_pushliteral(L, "float"); + } + else { + luaL_checkany(L, 1); + lua_pushnil(L); + } + return 1; +} + + +/* +** {================================================================== +** Deprecated functions (for compatibility only) +** =================================================================== +*/ +#if defined(LUA_COMPAT_MATHLIB) + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number y = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(pow)(x, y)); + return 1; +} + +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + int ep = (int)luaL_checkinteger(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + return 1; +} + +static int math_log10 (lua_State *L) { + lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); + return 1; +} + +#endif +/* }================================================================== */ + + + static const luaL_Reg mathlib[] = { {"abs", math_abs}, {"acos", math_acos}, {"asin", math_asin}, - {"atan2", math_atan2}, {"atan", math_atan}, {"ceil", math_ceil}, - {"cosh", math_cosh}, {"cos", math_cos}, {"deg", math_deg}, {"exp", math_exp}, + {"tointeger", math_toint}, {"floor", math_floor}, {"fmod", math_fmod}, - {"frexp", math_frexp}, - {"ldexp", math_ldexp}, -#if defined(LUA_COMPAT_LOG10) - {"log10", math_log10}, -#endif + {"ult", math_ult}, {"log", math_log}, {"max", math_max}, {"min", math_min}, {"modf", math_modf}, - {"pow", math_pow}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, - {"sinh", math_sinh}, {"sin", math_sin}, {"sqrt", math_sqrt}, - {"tanh", math_tanh}, {"tan", math_tan}, + {"type", math_type}, +#if defined(LUA_COMPAT_MATHLIB) + {"atan2", math_atan}, + {"cosh", math_cosh}, + {"sinh", math_sinh}, + {"tanh", math_tanh}, + {"pow", math_pow}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"log10", math_log10}, +#endif + /* placeholders */ + {"pi", NULL}, + {"huge", NULL}, + {"maxinteger", NULL}, + {"mininteger", NULL}, {NULL, NULL} }; @@ -272,8 +396,12 @@ LUAMOD_API int luaopen_math (lua_State *L) { luaL_newlib(L, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); - lua_pushnumber(L, HUGE_VAL); + lua_pushnumber(L, (lua_Number)HUGE_VAL); lua_setfield(L, -2, "huge"); + lua_pushinteger(L, LUA_MAXINTEGER); + lua_setfield(L, -2, "maxinteger"); + lua_pushinteger(L, LUA_MININTEGER); + lua_setfield(L, -2, "mininteger"); return 1; } diff --git a/deps/lua/lmem.c b/deps/lua/lmem.c index ee343e3..0a0476c 100644 --- a/deps/lua/lmem.c +++ b/deps/lua/lmem.c @@ -1,15 +1,17 @@ /* -** $Id: lmem.c,v 1.84.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ - -#include - #define lmem_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "ldebug.h" @@ -24,15 +26,15 @@ /* ** About the realloc function: ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); -** (`osize' is the old size, `nsize' is the new size) +** ('osize' is the old size, 'nsize' is the new size) ** -** * frealloc(ud, NULL, x, s) creates a new block of size `s' (no +** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no ** matter 'x'). ** -** * frealloc(ud, p, x, 0) frees the block `p' +** * frealloc(ud, p, x, 0) frees the block 'p' ** (in this specific case, frealloc must return NULL); ** particularly, frealloc(ud, NULL, 0, 0) does nothing -** (which is equivalent to free(NULL) in ANSI C) +** (which is equivalent to free(NULL) in ISO C) ** ** frealloc returns NULL if it cannot create or reallocate the area ** (any reallocation to an equal or smaller size cannot fail!) @@ -83,9 +85,8 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { #endif newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { - api_check(L, nsize > realosize, - "realloc cannot fail when shrinking a block"); - if (g->gcrunning) { + lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ + if (g->version) { /* is state fully built? */ luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } diff --git a/deps/lua/lmem.h b/deps/lua/lmem.h index bd4f4e0..30f4848 100644 --- a/deps/lua/lmem.h +++ b/deps/lua/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -15,20 +15,32 @@ /* -** This macro avoids the runtime division MAX_SIZET/(e), as 'e' is -** always constant. -** The macro is somewhat complex to avoid warnings: -** +1 avoids warnings of "comparison has constant result"; -** cast to 'void' avoids warnings of "value unused". +** This macro reallocs a vector 'b' from 'on' to 'n' elements, where +** each element has size 'e'. In case of arithmetic overflow of the +** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because +** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). +** +** (The macro is somewhat complex to avoid warnings: The 'sizeof' +** comparison avoids a runtime comparison when overflow cannot occur. +** The compiler should be able to optimize the real test by itself, but +** when it does it, it may give a warning about "comparison is always +** false due to limited range of data type"; the +1 tricks the compiler, +** avoiding this warning but also this optimization.) */ #define luaM_reallocv(L,b,on,n,e) \ - (cast(void, \ - (cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \ + (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ + ? luaM_toobig(L) : cast_void(0)) , \ luaM_realloc_(L, (b), (on)*(e), (n)*(e))) +/* +** Arrays of chars do not need any test +*/ +#define luaM_reallocvchar(L,b,on,n) \ + cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) + #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) -#define luaM_freearray(L, b, n) luaM_reallocv(L, (b), n, 0, sizeof((b)[0])) +#define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) #define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) diff --git a/deps/lua/loadlib.c b/deps/lua/loadlib.c index bedbea3..7911928 100644 --- a/deps/lua/loadlib.c +++ b/deps/lua/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.111.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: loadlib.c,v 1.127 2015/11/23 11:30:45 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -8,22 +8,16 @@ ** systems. */ +#define loadlib_c +#define LUA_LIB -/* -** if needed, includes windows header before everything else -*/ -#if defined(_WIN32) -#include -#endif +#include "lprefix.h" +#include #include #include - -#define loadlib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -31,21 +25,21 @@ /* -** LUA_PATH and LUA_CPATH are the names of the environment +** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment ** variables that Lua check to set its paths. */ -#if !defined(LUA_PATH) -#define LUA_PATH "LUA_PATH" +#if !defined(LUA_PATH_VAR) +#define LUA_PATH_VAR "LUA_PATH" #endif -#if !defined(LUA_CPATH) -#define LUA_CPATH "LUA_CPATH" +#if !defined(LUA_CPATH_VAR) +#define LUA_CPATH_VAR "LUA_CPATH" #endif #define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR -#define LUA_PATHVERSION LUA_PATH LUA_PATHSUFFIX -#define LUA_CPATHVERSION LUA_CPATH LUA_PATHSUFFIX +#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX +#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX /* ** LUA_PATH_SEP is the character that separates templates in a path. @@ -92,29 +86,45 @@ #define LUA_OFSEP "_" -/* table (in the registry) that keeps handles for all loaded C libraries */ -#define CLIBS "_CLIBS" +/* +** unique key for table in the registry that keeps handles +** for all loaded C libraries +*/ +static const int CLIBS = 0; #define LIB_FAIL "open" - -/* error codes for ll_loadfunc */ -#define ERRLIB 1 -#define ERRFUNC 2 - #define setprogdir(L) ((void)0) /* ** system-dependent functions */ -static void ll_unloadlib (void *lib); -static void *ll_load (lua_State *L, const char *path, int seeglb); -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); +/* +** unload library 'lib' +*/ +static void lsys_unloadlib (void *lib); + +/* +** load C library in file 'path'. If 'seeglb', load with all names in +** the library global. +** Returns the library; in case of error, returns NULL plus an +** error string in the stack. +*/ +static void *lsys_load (lua_State *L, const char *path, int seeglb); + +/* +** Try to find a function named 'sym' in library 'lib'. +** Returns the function; in case of error, returns NULL plus an +** error string in the stack. +*/ +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); -#if defined(LUA_USE_DLOPEN) + + +#if defined(LUA_USE_DLOPEN) /* { */ /* ** {======================================================================== ** This is an implementation of loadlib based on the dlfcn interface. @@ -126,20 +136,32 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); #include -static void ll_unloadlib (void *lib) { +/* +** Macro to convert pointer-to-void* to pointer-to-function. This cast +** is undefined according to ISO C, but POSIX assumes that it works. +** (The '__extension__' in gnu compilers is only to avoid warnings.) +*/ +#if defined(__GNUC__) +#define cast_func(p) (__extension__ (lua_CFunction)(p)) +#else +#define cast_func(p) ((lua_CFunction)(p)) +#endif + + +static void lsys_unloadlib (void *lib) { dlclose(lib); } -static void *ll_load (lua_State *L, const char *path, int seeglb) { +static void *lsys_load (lua_State *L, const char *path, int seeglb) { void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); if (lib == NULL) lua_pushstring(L, dlerror()); return lib; } -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = (lua_CFunction)dlsym(lib, sym); +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = cast_func(dlsym(lib, sym)); if (f == NULL) lua_pushstring(L, dlerror()); return f; } @@ -148,13 +170,15 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { -#elif defined(LUA_DL_DLL) +#elif defined(LUA_DL_DLL) /* }{ */ /* ** {====================================================================== ** This is an implementation of loadlib for Windows using native functions. ** ======================================================================= */ +#include + #undef setprogdir /* @@ -190,12 +214,12 @@ static void pusherror (lua_State *L) { lua_pushfstring(L, "system error %d\n", error); } -static void ll_unloadlib (void *lib) { +static void lsys_unloadlib (void *lib) { FreeLibrary((HMODULE)lib); } -static void *ll_load (lua_State *L, const char *path, int seeglb) { +static void *lsys_load (lua_State *L, const char *path, int seeglb) { HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); (void)(seeglb); /* not used: symbols are 'global' by default */ if (lib == NULL) pusherror(L); @@ -203,7 +227,7 @@ static void *ll_load (lua_State *L, const char *path, int seeglb) { } -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); if (f == NULL) pusherror(L); return f; @@ -212,7 +236,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { /* }====================================================== */ -#else +#else /* }{ */ /* ** {====================================================== ** Fallback for other systems @@ -226,31 +250,34 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #define DLMSG "dynamic libraries not enabled; check your Lua installation" -static void ll_unloadlib (void *lib) { +static void lsys_unloadlib (void *lib) { (void)(lib); /* not used */ } -static void *ll_load (lua_State *L, const char *path, int seeglb) { +static void *lsys_load (lua_State *L, const char *path, int seeglb) { (void)(path); (void)(seeglb); /* not used */ lua_pushliteral(L, DLMSG); return NULL; } -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { (void)(lib); (void)(sym); /* not used */ lua_pushliteral(L, DLMSG); return NULL; } /* }====================================================== */ -#endif +#endif /* } */ -static void *ll_checkclib (lua_State *L, const char *path) { +/* +** return registry.CLIBS[path] +*/ +static void *checkclib (lua_State *L, const char *path) { void *plib; - lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); lua_getfield(L, -1, path); plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ lua_pop(L, 2); /* pop CLIBS table and 'plib' */ @@ -258,8 +285,12 @@ static void *ll_checkclib (lua_State *L, const char *path) { } -static void ll_addtoclib (lua_State *L, const char *path, void *plib) { - lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); +/* +** registry.CLIBS[path] = plib -- for queries +** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries +*/ +static void addtoclib (lua_State *L, const char *path, void *plib) { + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); lua_pushlightuserdata(L, plib); lua_pushvalue(L, -1); lua_setfield(L, -3, path); /* CLIBS[path] = plib */ @@ -269,33 +300,49 @@ static void ll_addtoclib (lua_State *L, const char *path, void *plib) { /* -** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib +** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib ** handles in list CLIBS */ static int gctm (lua_State *L) { - int n = luaL_len(L, 1); + lua_Integer n = luaL_len(L, 1); for (; n >= 1; n--) { /* for each handle, in reverse order */ lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ - ll_unloadlib(lua_touserdata(L, -1)); + lsys_unloadlib(lua_touserdata(L, -1)); lua_pop(L, 1); /* pop handle */ } return 0; } -static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { - void *reg = ll_checkclib(L, path); /* check loaded C libraries */ + +/* error codes for 'lookforfunc' */ +#define ERRLIB 1 +#define ERRFUNC 2 + +/* +** Look for a C function named 'sym' in a dynamically loaded library +** 'path'. +** First, check whether the library is already loaded; if not, try +** to load it. +** Then, if 'sym' is '*', return true (as library has been loaded). +** Otherwise, look for symbol 'sym' in the library and push a +** C function with that symbol. +** Return 0 and 'true' or a function in the stack; in case of +** errors, return an error code and an error message in the stack. +*/ +static int lookforfunc (lua_State *L, const char *path, const char *sym) { + void *reg = checkclib(L, path); /* check loaded C libraries */ if (reg == NULL) { /* must load library? */ - reg = ll_load(L, path, *sym == '*'); + reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ if (reg == NULL) return ERRLIB; /* unable to load library */ - ll_addtoclib(L, path, reg); + addtoclib(L, path, reg); } if (*sym == '*') { /* loading only library (no function)? */ lua_pushboolean(L, 1); /* return 'true' */ return 0; /* no errors */ } else { - lua_CFunction f = ll_sym(L, reg, sym); + lua_CFunction f = lsys_sym(L, reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); /* else create new function */ @@ -307,7 +354,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); - int stat = ll_loadfunc(L, path, init); + int stat = lookforfunc(L, path, init); if (stat == 0) /* no errors? */ return 1; /* return the loaded function */ else { /* error; error message is on stack top */ @@ -360,7 +407,7 @@ static const char *searchpath (lua_State *L, const char *name, lua_remove(L, -2); /* remove path template */ if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ - lua_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_pushfstring(L, "\n\tno file '%s'", filename); lua_remove(L, -2); /* remove file name */ luaL_addvalue(&msg); /* concatenate error msg. entry */ } @@ -390,7 +437,7 @@ static const char *findfile (lua_State *L, const char *name, lua_getfield(L, lua_upvalueindex(1), pname); path = lua_tostring(L, -1); if (path == NULL) - luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + luaL_error(L, "'package.%s' must be a string", pname); return searchpath(L, name, path, ".", dirsep); } @@ -401,8 +448,7 @@ static int checkload (lua_State *L, int stat, const char *filename) { return 2; /* return open function and file name */ } else - return luaL_error(L, "error loading module " LUA_QS - " from file " LUA_QS ":\n\t%s", + return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); } @@ -416,21 +462,29 @@ static int searcher_Lua (lua_State *L) { } +/* +** Try to find a load function for module 'modname' at file 'filename'. +** First, change '.' to '_' in 'modname'; then, if 'modname' has +** the form X-Y (that is, it has an "ignore mark"), build a function +** name "luaopen_X" and look for it. (For compatibility, if that +** fails, it also tries "luaopen_Y".) If there is no ignore mark, +** look for a function named "luaopen_modname". +*/ static int loadfunc (lua_State *L, const char *filename, const char *modname) { - const char *funcname; + const char *openfunc; const char *mark; modname = luaL_gsub(L, modname, ".", LUA_OFSEP); mark = strchr(modname, *LUA_IGMARK); if (mark) { int stat; - funcname = lua_pushlstring(L, modname, mark - modname); - funcname = lua_pushfstring(L, LUA_POF"%s", funcname); - stat = ll_loadfunc(L, filename, funcname); + openfunc = lua_pushlstring(L, modname, mark - modname); + openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); + stat = lookforfunc(L, filename, openfunc); if (stat != ERRFUNC) return stat; modname = mark + 1; /* else go ahead and try old-style name */ } - funcname = lua_pushfstring(L, LUA_POF"%s", modname); - return ll_loadfunc(L, filename, funcname); + openfunc = lua_pushfstring(L, LUA_POF"%s", modname); + return lookforfunc(L, filename, openfunc); } @@ -455,8 +509,7 @@ static int searcher_Croot (lua_State *L) { if (stat != ERRFUNC) return checkload(L, 0, filename); /* real error */ else { /* open function not found */ - lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, - name, filename); + lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); return 1; } } @@ -468,8 +521,7 @@ static int searcher_Croot (lua_State *L) { static int searcher_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); - lua_getfield(L, -1, name); - if (lua_isnil(L, -1)) /* not found? */ + if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ lua_pushfstring(L, "\n\tno field package.preload['%s']", name); return 1; } @@ -479,17 +531,15 @@ static void findloader (lua_State *L, const char *name) { int i; luaL_Buffer msg; /* to build error message */ luaL_buffinit(L, &msg); - lua_getfield(L, lua_upvalueindex(1), "searchers"); /* will be at index 3 */ - if (!lua_istable(L, 3)) - luaL_error(L, LUA_QL("package.searchers") " must be a table"); + /* push 'package.searchers' to index 3 in the stack */ + if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) + luaL_error(L, "'package.searchers' must be a table"); /* iterate over available searchers to find a loader */ for (i = 1; ; i++) { - lua_rawgeti(L, 3, i); /* get a searcher */ - if (lua_isnil(L, -1)) { /* no more searchers? */ + if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ lua_pop(L, 1); /* remove nil */ luaL_pushresult(&msg); /* create error message */ - luaL_error(L, "module " LUA_QS " not found:%s", - name, lua_tostring(L, -1)); + luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); } lua_pushstring(L, name); lua_call(L, 1, 2); /* call it */ @@ -520,8 +570,7 @@ static int ll_require (lua_State *L) { lua_call(L, 2, 1); /* run loader to load module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ - lua_getfield(L, 2, name); - if (lua_isnil(L, -1)) { /* module did not set a value? */ + if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ lua_pushboolean(L, 1); /* use true as result */ lua_pushvalue(L, -1); /* extra copy to be returned */ lua_setfield(L, 2, name); /* _LOADED[name] = true */ @@ -548,7 +597,7 @@ static void set_env (lua_State *L) { if (lua_getstack(L, 1, &ar) == 0 || lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ lua_iscfunction(L, -1)) - luaL_error(L, LUA_QL("module") " not called from a Lua function"); + luaL_error(L, "'module' not called from a Lua function"); lua_pushvalue(L, -2); /* copy new environment table to top */ lua_setupvalue(L, -2, 1); lua_pop(L, 1); /* remove function */ @@ -587,9 +636,8 @@ static int ll_module (lua_State *L) { int lastarg = lua_gettop(L); /* last parameter */ luaL_pushmodule(L, modname, 1); /* get/create module table */ /* check whether table already has a _NAME field */ - lua_getfield(L, -1, "_NAME"); - if (!lua_isnil(L, -1)) /* is table an initialized module? */ - lua_pop(L, 1); + if (lua_getfield(L, -1, "_NAME") != LUA_TNIL) + lua_pop(L, 1); /* table is an initialized module */ else { /* no; initialize it */ lua_pop(L, 1); modinit(L, modname); @@ -659,6 +707,12 @@ static const luaL_Reg pk_funcs[] = { #if defined(LUA_COMPAT_MODULE) {"seeall", ll_seeall}, #endif + /* placeholders */ + {"preload", NULL}, + {"cpath", NULL}, + {"path", NULL}, + {"searchers", NULL}, + {"loaded", NULL}, {NULL, NULL} }; @@ -678,42 +732,50 @@ static void createsearcherstable (lua_State *L) { int i; /* create 'searchers' table */ lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); - /* fill it with pre-defined searchers */ + /* fill it with predefined searchers */ for (i=0; searchers[i] != NULL; i++) { lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ lua_pushcclosure(L, searchers[i], 1); lua_rawseti(L, -2, i+1); } +#if defined(LUA_COMPAT_LOADERS) + lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ + lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */ +#endif + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ } -LUAMOD_API int luaopen_package (lua_State *L) { - /* create table CLIBS to keep track of loaded C libraries */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); - lua_createtable(L, 0, 1); /* metatable for CLIBS */ +/* +** create table CLIBS to keep track of loaded C libraries, +** setting a finalizer to close all libraries when closing state. +*/ +static void createclibstable (lua_State *L) { + lua_newtable(L); /* create CLIBS table */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ lua_pushcfunction(L, gctm); lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ lua_setmetatable(L, -2); - /* create `package' table */ - luaL_newlib(L, pk_funcs); + lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + createclibstable(L); + luaL_newlib(L, pk_funcs); /* create 'package' table */ createsearcherstable(L); -#if defined(LUA_COMPAT_LOADERS) - lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ - lua_setfield(L, -3, "loaders"); /* put it in field `loaders' */ -#endif - lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ /* set field 'path' */ - setpath(L, "path", LUA_PATHVERSION, LUA_PATH, LUA_PATH_DEFAULT); + setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT); /* set field 'cpath' */ - setpath(L, "cpath", LUA_CPATHVERSION, LUA_CPATH, LUA_CPATH_DEFAULT); + setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT); /* store config information */ lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); lua_setfield(L, -2, "config"); - /* set field `loaded' */ + /* set field 'loaded' */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); - /* set field `preload' */ + /* set field 'preload' */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_setfield(L, -2, "preload"); lua_pushglobaltable(L); diff --git a/deps/lua/lobject.c b/deps/lua/lobject.c index 882d994..e24723f 100644 --- a/deps/lua/lobject.c +++ b/deps/lua/lobject.c @@ -1,17 +1,22 @@ /* -** $Id: lobject.c,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lobject.c,v 2.108 2015/11/02 16:09:30 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ +#define lobject_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include #include #include #include #include -#define lobject_c -#define LUA_CORE - #include "lua.h" #include "lctype.h" @@ -36,8 +41,12 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; int luaO_int2fb (unsigned int x) { int e = 0; /* exponent */ if (x < 8) return x; - while (x >= 0x10) { - x = (x+1) >> 1; + while (x >= (8 << 4)) { /* coarse steps */ + x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ + e += 4; + } + while (x >= (8 << 1)) { /* fine steps */ + x = (x + 1) >> 1; /* x = ceil(x / 2) */ e++; } return ((e+1) << 3) | (cast_int(x) - 8); @@ -46,14 +55,15 @@ int luaO_int2fb (unsigned int x) { /* converts back */ int luaO_fb2int (int x) { - int e = (x >> 3) & 0x1f; - if (e == 0) return x; - else return ((x & 7) + 8) << (e - 1); + return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); } +/* +** Computes ceil(log2(x)) +*/ int luaO_ceillog2 (unsigned int x) { - static const lu_byte log_2[256] = { + static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, @@ -70,29 +80,90 @@ int luaO_ceillog2 (unsigned int x) { } -lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { +static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, + lua_Integer v2) { switch (op) { - case LUA_OPADD: return luai_numadd(NULL, v1, v2); - case LUA_OPSUB: return luai_numsub(NULL, v1, v2); - case LUA_OPMUL: return luai_nummul(NULL, v1, v2); - case LUA_OPDIV: return luai_numdiv(NULL, v1, v2); - case LUA_OPMOD: return luai_nummod(NULL, v1, v2); - case LUA_OPPOW: return luai_numpow(NULL, v1, v2); - case LUA_OPUNM: return luai_numunm(NULL, v1); + case LUA_OPADD: return intop(+, v1, v2); + case LUA_OPSUB:return intop(-, v1, v2); + case LUA_OPMUL:return intop(*, v1, v2); + case LUA_OPMOD: return luaV_mod(L, v1, v2); + case LUA_OPIDIV: return luaV_div(L, v1, v2); + case LUA_OPBAND: return intop(&, v1, v2); + case LUA_OPBOR: return intop(|, v1, v2); + case LUA_OPBXOR: return intop(^, v1, v2); + case LUA_OPSHL: return luaV_shiftl(v1, v2); + case LUA_OPSHR: return luaV_shiftl(v1, -v2); + case LUA_OPUNM: return intop(-, 0, v1); + case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); default: lua_assert(0); return 0; } } -int luaO_hexavalue (int c) { - if (lisdigit(c)) return c - '0'; - else return ltolower(c) - 'a' + 10; +static lua_Number numarith (lua_State *L, int op, lua_Number v1, + lua_Number v2) { + switch (op) { + case LUA_OPADD: return luai_numadd(L, v1, v2); + case LUA_OPSUB: return luai_numsub(L, v1, v2); + case LUA_OPMUL: return luai_nummul(L, v1, v2); + case LUA_OPDIV: return luai_numdiv(L, v1, v2); + case LUA_OPPOW: return luai_numpow(L, v1, v2); + case LUA_OPIDIV: return luai_numidiv(L, v1, v2); + case LUA_OPUNM: return luai_numunm(L, v1); + case LUA_OPMOD: { + lua_Number m; + luai_nummod(L, v1, v2, m); + return m; + } + default: lua_assert(0); return 0; + } } -#if !defined(lua_strx2number) +void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, + TValue *res) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: + case LUA_OPBNOT: { /* operate only on integers */ + lua_Integer i1; lua_Integer i2; + if (tointeger(p1, &i1) && tointeger(p2, &i2)) { + setivalue(res, intarith(L, op, i1, i2)); + return; + } + else break; /* go to the end */ + } + case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ + lua_Number n1; lua_Number n2; + if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + default: { /* other operations */ + lua_Number n1; lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2)) { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return; + } + else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + } + /* could not perform raw operation; try metamethod */ + lua_assert(L != NULL); /* should not fail when folding (compile time) */ + luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); +} -#include + +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else return (ltolower(c) - 'a') + 10; +} static int isneg (const char **s) { @@ -102,86 +173,191 @@ static int isneg (const char **s) { } -static lua_Number readhexa (const char **s, lua_Number r, int *count) { - for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ - r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s))); - (*count)++; - } - return r; -} +/* +** {================================================================== +** Lua's implementation for 'lua_strx2number' +** =================================================================== +*/ + +#if !defined(lua_strx2number) + +/* maximum number of significant digits to read (to avoid overflows + even with single floats) */ +#define MAXSIGDIG 30 /* ** convert an hexadecimal numeric string to a number, following ** C99 specification for 'strtod' */ static lua_Number lua_strx2number (const char *s, char **endptr) { - lua_Number r = 0.0; - int e = 0, i = 0; - int neg = 0; /* 1 if number is negative */ + int dot = lua_getlocaledecpoint(); + lua_Number r = 0.0; /* result (accumulator) */ + int sigdig = 0; /* number of significant digits */ + int nosigdig = 0; /* number of non-significant digits */ + int e = 0; /* exponent correction */ + int neg; /* 1 if number is negative */ + int hasdot = 0; /* true after seen a dot */ *endptr = cast(char *, s); /* nothing is valid yet */ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); /* check signal */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ return 0.0; /* invalid format (no '0x') */ - s += 2; /* skip '0x' */ - r = readhexa(&s, r, &i); /* read integer part */ - if (*s == '.') { - s++; /* skip dot */ - r = readhexa(&s, r, &e); /* read fractional part */ + for (s += 2; ; s++) { /* skip '0x' and read numeral */ + if (*s == dot) { + if (hasdot) break; /* second dot? stop loop */ + else hasdot = 1; + } + else if (lisxdigit(cast_uchar(*s))) { + if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ + nosigdig++; + else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ + r = (r * cast_num(16.0)) + luaO_hexavalue(*s); + else e++; /* too many digits; ignore, but still count for exponent */ + if (hasdot) e--; /* decimal digit? correct exponent */ + } + else break; /* neither a dot nor a digit */ } - if (i == 0 && e == 0) - return 0.0; /* invalid format (no digit) */ - e *= -4; /* each fractional digit divides value by 2^-4 */ + if (nosigdig + sigdig == 0) /* no digits? */ + return 0.0; /* invalid format */ *endptr = cast(char *, s); /* valid up to here */ + e *= 4; /* each digit multiplies/divides value by 2^4 */ if (*s == 'p' || *s == 'P') { /* exponent part? */ - int exp1 = 0; - int neg1; + int exp1 = 0; /* exponent value */ + int neg1; /* exponent signal */ s++; /* skip 'p' */ neg1 = isneg(&s); /* signal */ if (!lisdigit(cast_uchar(*s))) - goto ret; /* must have at least one digit */ + return 0.0; /* invalid; must have at least one digit */ while (lisdigit(cast_uchar(*s))) /* read exponent */ exp1 = exp1 * 10 + *(s++) - '0'; if (neg1) exp1 = -exp1; e += exp1; + *endptr = cast(char *, s); /* valid up to here */ } - *endptr = cast(char *, s); /* valid up to here */ - ret: if (neg) r = -r; return l_mathop(ldexp)(r, e); } #endif +/* }====================================================== */ -int luaO_str2d (const char *s, size_t len, lua_Number *result) { +static const char *l_str2d (const char *s, lua_Number *result) { char *endptr; if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ - return 0; - else if (strpbrk(s, "xX")) /* hexa? */ + return NULL; + else if (strpbrk(s, "xX")) /* hex? */ *result = lua_strx2number(s, &endptr); else *result = lua_str2number(s, &endptr); - if (endptr == s) return 0; /* nothing recognized */ + if (endptr == s) return NULL; /* nothing recognized */ while (lisspace(cast_uchar(*endptr))) endptr++; - return (endptr == s + len); /* OK if no trailing characters */ + return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */ +} + + +static const char *l_str2int (const char *s, lua_Integer *result) { + lua_Unsigned a = 0; + int empty = 1; + int neg; + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); + if (s[0] == '0' && + (s[1] == 'x' || s[1] == 'X')) { /* hex? */ + s += 2; /* skip '0x' */ + for (; lisxdigit(cast_uchar(*s)); s++) { + a = a * 16 + luaO_hexavalue(*s); + empty = 0; + } + } + else { /* decimal */ + for (; lisdigit(cast_uchar(*s)); s++) { + a = a * 10 + *s - '0'; + empty = 0; + } + } + while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ + if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ + else { + *result = l_castU2S((neg) ? 0u - a : a); + return s; + } +} + + +size_t luaO_str2num (const char *s, TValue *o) { + lua_Integer i; lua_Number n; + const char *e; + if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ + setivalue(o, i); + } + else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ + setfltvalue(o, n); + } + else + return 0; /* conversion failed */ + return (e - s) + 1; /* success; return string size */ +} + + +int luaO_utf8esc (char *buff, unsigned long x) { + int n = 1; /* number of bytes put in buffer (backwards) */ + lua_assert(x <= 0x10FFFF); + if (x < 0x80) /* ascii? */ + buff[UTF8BUFFSZ - 1] = cast(char, x); + else { /* need continuation bytes */ + unsigned int mfb = 0x3f; /* maximum that fits in first byte */ + do { /* add continuation bytes */ + buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); + x >>= 6; /* remove added bits */ + mfb >>= 1; /* now there is one less bit available in first byte */ + } while (x > mfb); /* still needs continuation byte? */ + buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ + } + return n; } +/* maximum length of the conversion of a number to a string */ +#define MAXNUMBER2STR 50 + + +/* +** Convert a number object to a string +*/ +void luaO_tostring (lua_State *L, StkId obj) { + char buff[MAXNUMBER2STR]; + size_t len; + lua_assert(ttisnumber(obj)); + if (ttisinteger(obj)) + len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); + else { + len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); +#if !defined(LUA_COMPAT_FLOATSTRING) + if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ + buff[len++] = lua_getlocaledecpoint(); + buff[len++] = '0'; /* adds '.0' to result */ + } +#endif + } + setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); +} + static void pushstr (lua_State *L, const char *str, size_t l) { - setsvalue2s(L, L->top++, luaS_newlstr(L, str, l)); + setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); + luaD_inctop(L); } -/* this function handles only `%d', `%c', %f, %p, and `%s' formats */ +/* this function handles only '%d', '%c', '%f', '%p', and '%s' + conventional formats, plus Lua-specific '%I' and '%U' */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 0; for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; - luaD_checkstack(L, 2); /* fmt + item */ pushstr(L, fmt, e - fmt); switch (*(e+1)) { case 's': { @@ -191,33 +367,47 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { break; } case 'c': { - char buff; - buff = cast(char, va_arg(argp, int)); - pushstr(L, &buff, 1); + char buff = cast(char, va_arg(argp, int)); + if (lisprint(cast_uchar(buff))) + pushstr(L, &buff, 1); + else /* non-printable character; print its code */ + luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); break; } case 'd': { - setnvalue(L->top++, cast_num(va_arg(argp, int))); - break; + setivalue(L->top, va_arg(argp, int)); + goto top2str; + } + case 'I': { + setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); + goto top2str; } case 'f': { - setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber))); + setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + top2str: + luaD_inctop(L); + luaO_tostring(L, L->top - 1); break; } case 'p': { - char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ - int l = sprintf(buff, "%p", va_arg(argp, void *)); + char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ + int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); pushstr(L, buff, l); break; } + case 'U': { + char buff[UTF8BUFFSZ]; + int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); + pushstr(L, buff + UTF8BUFFSZ - l, l); + break; + } case '%': { pushstr(L, "%", 1); break; } default: { - luaG_runerror(L, - "invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"), - *(e + 1)); + luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", + *(e + 1)); } } n += 2; diff --git a/deps/lua/lobject.h b/deps/lua/lobject.h index 4b8fe6c..6f5ecf8 100644 --- a/deps/lua/lobject.h +++ b/deps/lua/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.71.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -19,14 +19,13 @@ /* ** Extra tags for non-values */ -#define LUA_TPROTO LUA_NUMTAGS -#define LUA_TUPVAL (LUA_NUMTAGS+1) -#define LUA_TDEADKEY (LUA_NUMTAGS+2) +#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */ +#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */ /* ** number of all possible tags (including LUA_TNONE but excluding DEADKEY) */ -#define LUA_TOTALTAGS (LUA_TUPVAL+2) +#define LUA_TOTALTAGS (LUA_TPROTO + 2) /* @@ -36,8 +35,6 @@ ** bit 6: whether value is collectable */ -#define VARBITS (3 << 4) - /* ** LUA_TFUNCTION variants: @@ -57,6 +54,11 @@ #define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ +/* Variant tags for numbers */ +#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */ +#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */ + + /* Bit mark for collectable types */ #define BIT_ISCOLLECTABLE (1 << 6) @@ -65,9 +67,9 @@ /* -** Union of all collectable objects +** Common type for all collectable objects */ -typedef union GCObject GCObject; +typedef struct GCObject GCObject; /* @@ -78,21 +80,12 @@ typedef union GCObject GCObject; /* -** Common header in struct form +** Common type has only the common header */ -typedef struct GCheader { +struct GCObject { CommonHeader; -} GCheader; - - - -/* -** Union of all Lua values -*/ -typedef union Value Value; - +}; -#define numfield lua_Number n; /* numbers */ @@ -101,9 +94,26 @@ typedef union Value Value; ** an actual value plus a tag with its type. */ +/* +** Union of all Lua values +*/ +typedef union Value { + GCObject *gc; /* collectable objects */ + void *p; /* light userdata */ + int b; /* booleans */ + lua_CFunction f; /* light C functions */ + lua_Integer i; /* integer numbers */ + lua_Number n; /* float numbers */ +} Value; + + #define TValuefields Value value_; int tt_ -typedef struct lua_TValue TValue; + +typedef struct lua_TValue { + TValuefields; +} TValue; + /* macro defining a nil value */ @@ -111,7 +121,6 @@ typedef struct lua_TValue TValue; #define val_(o) ((o)->value_) -#define num_(o) (val_(o).n) /* raw type tag of a TValue */ @@ -124,13 +133,15 @@ typedef struct lua_TValue TValue; #define ttype(o) (rttype(o) & 0x3F) /* type tag of a TValue with no variants (bits 0-3) */ -#define ttypenv(o) (novariant(rttype(o))) +#define ttnov(o) (novariant(rttype(o))) /* Macros to test type */ #define checktag(o,t) (rttype(o) == (t)) -#define checktype(o,t) (ttypenv(o) == (t)) -#define ttisnumber(o) checktag((o), LUA_TNUMBER) +#define checktype(o,t) (ttnov(o) == (t)) +#define ttisnumber(o) checktype((o), LUA_TNUMBER) +#define ttisfloat(o) checktag((o), LUA_TNUMFLT) +#define ttisinteger(o) checktag((o), LUA_TNUMINT) #define ttisnil(o) checktag((o), LUA_TNIL) #define ttisboolean(o) checktag((o), LUA_TBOOLEAN) #define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) @@ -143,27 +154,27 @@ typedef struct lua_TValue TValue; #define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) #define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) #define ttislcf(o) checktag((o), LUA_TLCF) -#define ttisuserdata(o) checktag((o), ctb(LUA_TUSERDATA)) +#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) #define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) #define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) -#define ttisequal(o1,o2) (rttype(o1) == rttype(o2)) /* Macros to access values */ -#define nvalue(o) check_exp(ttisnumber(o), num_(o)) +#define ivalue(o) check_exp(ttisinteger(o), val_(o).i) +#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) +#define nvalue(o) check_exp(ttisnumber(o), \ + (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o))) #define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) #define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) -#define rawtsvalue(o) check_exp(ttisstring(o), &val_(o).gc->ts) -#define tsvalue(o) (&rawtsvalue(o)->tsv) -#define rawuvalue(o) check_exp(ttisuserdata(o), &val_(o).gc->u) -#define uvalue(o) (&rawuvalue(o)->uv) -#define clvalue(o) check_exp(ttisclosure(o), &val_(o).gc->cl) -#define clLvalue(o) check_exp(ttisLclosure(o), &val_(o).gc->cl.l) -#define clCvalue(o) check_exp(ttisCclosure(o), &val_(o).gc->cl.c) +#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) +#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) +#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) +#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) +#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) #define fvalue(o) check_exp(ttislcf(o), val_(o).f) -#define hvalue(o) check_exp(ttistable(o), &val_(o).gc->h) +#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) #define bvalue(o) check_exp(ttisboolean(o), val_(o).b) -#define thvalue(o) check_exp(ttisthread(o), &val_(o).gc->th) +#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) /* a dead value may get the 'gc' field, but cannot access its contents */ #define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) @@ -174,18 +185,27 @@ typedef struct lua_TValue TValue; /* Macros for internal tests */ -#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) +#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) -#define checkliveness(g,obj) \ +#define checkliveness(L,obj) \ lua_longassert(!iscollectable(obj) || \ - (righttt(obj) && !isdead(g,gcvalue(obj)))) + (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))) /* Macros to set values */ #define settt_(o,t) ((o)->tt_=(t)) -#define setnvalue(obj,x) \ - { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); } +#define setfltvalue(obj,x) \ + { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); } + +#define chgfltvalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); } + +#define setivalue(obj,x) \ + { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); } + +#define chgivalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); } #define setnilvalue(obj) settt_(obj, LUA_TNIL) @@ -199,48 +219,46 @@ typedef struct lua_TValue TValue; { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); } #define setgcovalue(L,obj,x) \ - { TValue *io=(obj); GCObject *i_g=(x); \ - val_(io).gc=i_g; settt_(io, ctb(gch(i_g)->tt)); } + { TValue *io = (obj); GCObject *i_g=(x); \ + val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); } #define setsvalue(L,obj,x) \ - { TValue *io=(obj); \ - TString *x_ = (x); \ - val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); TString *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ + checkliveness(L,io); } #define setuvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TUSERDATA)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); Udata *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \ + checkliveness(L,io); } #define setthvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTHREAD)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); lua_State *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \ + checkliveness(L,io); } #define setclLvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TLCL)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); LClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \ + checkliveness(L,io); } #define setclCvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TCCL)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); CClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \ + checkliveness(L,io); } #define sethvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); Table *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ + checkliveness(L,io); } #define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) #define setobj(L,obj1,obj2) \ - { const TValue *io2=(obj2); TValue *io1=(obj1); \ - io1->value_ = io2->value_; io1->tt_ = io2->tt_; \ - checkliveness(G(L),io1); } + { TValue *io1=(obj1); *io1 = *(obj2); \ + (void)L; checkliveness(L,io1); } /* @@ -256,196 +274,118 @@ typedef struct lua_TValue TValue; #define setptvalue2s setptvalue /* from table to same table */ #define setobjt2t setobj -/* to table */ -#define setobj2t setobj /* to new object */ #define setobj2n setobj #define setsvalue2n setsvalue +/* to table (define it as an expression to be used in macros) */ +#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1))) + -/* check whether a number is valid (useful only for NaN trick) */ -#define luai_checknum(L,o,c) { /* empty */ } /* ** {====================================================== -** NaN Trick +** types and prototypes ** ======================================================= */ -#if defined(LUA_NANTRICK) - -/* -** numbers are represented in the 'd_' field. All other values have the -** value (NNMARK | tag) in 'tt__'. A number with such pattern would be -** a "signaled NaN", which is never generated by regular operations by -** the CPU (nor by 'strtod') -*/ - -/* allows for external implementation for part of the trick */ -#if !defined(NNMARK) /* { */ - - -#if !defined(LUA_IEEEENDIAN) -#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN' -#endif - - -#define NNMARK 0x7FF7A500 -#define NNMASK 0x7FFFFF00 - -#undef TValuefields -#undef NILCONSTANT - -#if (LUA_IEEEENDIAN == 0) /* { */ - -/* little endian */ -#define TValuefields \ - union { struct { Value v__; int tt__; } i; double d__; } u -#define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}} -/* field-access macros */ -#define v_(o) ((o)->u.i.v__) -#define d_(o) ((o)->u.d__) -#define tt_(o) ((o)->u.i.tt__) -#else /* }{ */ -/* big endian */ -#define TValuefields \ - union { struct { int tt__; Value v__; } i; double d__; } u -#define NILCONSTANT {{tag2tt(LUA_TNIL), {NULL}}} -/* field-access macros */ -#define v_(o) ((o)->u.i.v__) -#define d_(o) ((o)->u.d__) -#define tt_(o) ((o)->u.i.tt__) - -#endif /* } */ - -#endif /* } */ - - -/* correspondence with standard representation */ -#undef val_ -#define val_(o) v_(o) -#undef num_ -#define num_(o) d_(o) - - -#undef numfield -#define numfield /* no such field; numbers are the entire struct */ - -/* basic check to distinguish numbers from non-numbers */ -#undef ttisnumber -#define ttisnumber(o) ((tt_(o) & NNMASK) != NNMARK) - -#define tag2tt(t) (NNMARK | (t)) - -#undef rttype -#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : tt_(o) & 0xff) - -#undef settt_ -#define settt_(o,t) (tt_(o) = tag2tt(t)) +typedef TValue *StkId; /* index to stack elements */ -#undef setnvalue -#define setnvalue(obj,x) \ - { TValue *io_=(obj); num_(io_)=(x); lua_assert(ttisnumber(io_)); } -#undef setobj -#define setobj(L,obj1,obj2) \ - { const TValue *o2_=(obj2); TValue *o1_=(obj1); \ - o1_->u = o2_->u; \ - checkliveness(G(L),o1_); } /* -** these redefinitions are not mandatory, but these forms are more efficient +** Header for string value; string bytes follow the end of this structure +** (aligned according to 'UTString'; see next). */ - -#undef checktag -#undef checktype -#define checktag(o,t) (tt_(o) == tag2tt(t)) -#define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS)) - -#undef ttisequal -#define ttisequal(o1,o2) \ - (ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) - - -#undef luai_checknum -#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; } - -#endif -/* }====================================================== */ - +typedef struct TString { + CommonHeader; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ + lu_byte shrlen; /* length for short strings */ + unsigned int hash; + union { + size_t lnglen; /* length for long strings */ + struct TString *hnext; /* linked list for hash table */ + } u; +} TString; /* -** {====================================================== -** types and prototypes -** ======================================================= +** Ensures that address after this type is always fully aligned. */ +typedef union UTString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + TString tsv; +} UTString; -union Value { - GCObject *gc; /* collectable objects */ - void *p; /* light userdata */ - int b; /* booleans */ - lua_CFunction f; /* light C functions */ - numfield /* numbers */ -}; - - -struct lua_TValue { - TValuefields; -}; +/* +** Get the actual string (array of bytes) from a 'TString'. +** (Access to 'extra' ensures that value is really a 'TString'.) +*/ +#define getstr(ts) \ + check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString)) -typedef TValue *StkId; /* index to stack elements */ +/* get the actual string (array of bytes) from a Lua value */ +#define svalue(o) getstr(tsvalue(o)) +/* get string length from 'TString *s' */ +#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen) +/* get string length from 'TValue *o' */ +#define vslen(o) tsslen(tsvalue(o)) /* -** Header for string value; string bytes follow the end of this structure +** Header for userdata; memory area follows the end of this structure +** (aligned according to 'UUdata'; see next). */ -typedef union TString { - L_Umaxalign dummy; /* ensures maximum alignment for strings */ - struct { - CommonHeader; - lu_byte extra; /* reserved words for short strings; "has hash" for longs */ - unsigned int hash; - size_t len; /* number of characters in string */ - } tsv; -} TString; - +typedef struct Udata { + CommonHeader; + lu_byte ttuv_; /* user value's tag */ + struct Table *metatable; + size_t len; /* number of bytes */ + union Value user_; /* user value */ +} Udata; -/* get the actual string (array of bytes) from a TString */ -#define getstr(ts) cast(const char *, (ts) + 1) -/* get the actual string (array of bytes) from a Lua value */ -#define svalue(o) getstr(rawtsvalue(o)) +/* +** Ensures that address after this type is always fully aligned. +*/ +typedef union UUdata { + L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ + Udata uv; +} UUdata; /* -** Header for userdata; memory area follows the end of this structure +** Get the address of memory block inside 'Udata'. +** (Access to 'ttuv_' ensures that value is really a 'Udata'.) */ -typedef union Udata { - L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ - struct { - CommonHeader; - struct Table *metatable; - struct Table *env; - size_t len; /* number of bytes */ - } uv; -} Udata; +#define getudatamem(u) \ + check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata))) + +#define setuservalue(L,u,o) \ + { const TValue *io=(o); Udata *iu = (u); \ + iu->user_ = io->value_; iu->ttuv_ = rttype(io); \ + checkliveness(L,io); } +#define getuservalue(L,u,o) \ + { TValue *io=(o); const Udata *iu = (u); \ + io->value_ = iu->user_; settt_(io, iu->ttuv_); \ + checkliveness(L,io); } + /* ** Description of an upvalue for function prototypes */ typedef struct Upvaldesc { TString *name; /* upvalue name (for debug information) */ - lu_byte instack; /* whether it is in stack */ + lu_byte instack; /* whether it is in stack (register) */ lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ } Upvaldesc; @@ -494,24 +434,15 @@ typedef struct Proto { TValue *k; /* constants used by the function */ struct SharedProto *sp; struct Proto **p; /* functions defined inside the function */ - union Closure *cache; /* last created closure with this prototype */ + struct LClosure *cache; /* last-created closure with this prototype */ GCObject *gclist; } Proto; + /* ** Lua Upvalues */ -typedef struct UpVal { - CommonHeader; - TValue *v; /* points to stack or to its own value */ - union { - TValue value; /* the value (when closed) */ - struct { /* double linked list (when open) */ - struct UpVal *prev; - struct UpVal *next; - } l; - } u; -} UpVal; +typedef struct UpVal UpVal; /* @@ -553,12 +484,19 @@ typedef union Closure { typedef union TKey { struct { TValuefields; - struct Node *next; /* for chaining */ + int next; /* for chaining (offset for next node) */ } nk; TValue tvk; } TKey; +/* copy a value into a key without messing up field 'next' */ +#define setnodekey(L,key,obj) \ + { TKey *k_=(key); const TValue *io_=(obj); \ + k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ + (void)L; checkliveness(L,io_); } + + typedef struct Node { TValue i_val; TKey i_key; @@ -568,19 +506,19 @@ typedef struct Node { typedef struct Table { CommonHeader; lu_byte flags; /* 1<

#include "lopcodes.h" @@ -31,10 +34,17 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "ADD", "SUB", "MUL", - "DIV", "MOD", "POW", + "DIV", + "IDIV", + "BAND", + "BOR", + "BXOR", + "SHL", + "SHR", "UNM", + "BNOT", "NOT", "LEN", "CONCAT", @@ -79,10 +89,17 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ diff --git a/deps/lua/lopcodes.h b/deps/lua/lopcodes.h index 51f5791..864b8e4 100644 --- a/deps/lua/lopcodes.h +++ b/deps/lua/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.142.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lopcodes.h,v 1.148 2014/10/25 11:50:46 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -14,12 +14,12 @@ We assume that instructions are unsigned numbers. All instructions have an opcode in the first 6 bits. Instructions can have the following fields: - `A' : 8 bits - `B' : 9 bits - `C' : 9 bits + 'A' : 8 bits + 'B' : 9 bits + 'C' : 9 bits 'Ax' : 26 bits ('A', 'B', and 'C' together) - `Bx' : 18 bits (`B' and `C' together) - `sBx' : signed Bx + 'Bx' : 18 bits ('B' and 'C' together) + 'sBx' : signed Bx A signed argument is represented in excess K; that is, the number value is the unsigned value minus K. K is exactly the maximum value @@ -58,7 +58,7 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ */ #if SIZE_Bx < LUAI_BITSINT-1 #define MAXARG_Bx ((1<>1) /* `sBx' is signed */ +#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ #else #define MAXARG_Bx MAX_INT #define MAXARG_sBx MAX_INT @@ -76,10 +76,10 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ #define MAXARG_C ((1<> RK(C) */ OP_UNM,/* A B R(A) := -R(B) */ +OP_BNOT,/* A B R(A) := ~R(B) */ OP_NOT,/* A B R(A) := not R(B) */ OP_LEN,/* A B R(A) := length of R(B) */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ -OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */ +OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ @@ -231,16 +238,16 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ /*=========================================================================== Notes: - (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is + (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is set to last_result+1, so next open instruction (OP_CALL, OP_RETURN, - OP_SETLIST) may use `top'. + OP_SETLIST) may use 'top'. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and set top (like in OP_CALL with C == 0). - (*) In OP_RETURN, if (B == 0) then return up to `top'. + (*) In OP_RETURN, if (B == 0) then return up to 'top'. - (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next + (*) In OP_SETLIST, if (B == 0) then B = 'top'; if (C == 0) then next 'instruction' is EXTRAARG(real C). (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG. @@ -248,7 +255,7 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ (*) For comparisons, A specifies what condition the test should accept (true or false). - (*) All `skips' (pc++) assume that next instruction is a jump. + (*) All 'skips' (pc++) assume that next instruction is a jump. ===========================================================================*/ diff --git a/deps/lua/loslib.c b/deps/lua/loslib.c index 052ba17..7dae533 100644 --- a/deps/lua/loslib.c +++ b/deps/lua/loslib.c @@ -1,9 +1,14 @@ /* -** $Id: loslib.c,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: loslib.c,v 1.60 2015/11/19 19:16:22 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ +#define loslib_c +#define LUA_LIB + +#include "lprefix.h" + #include #include @@ -11,9 +16,6 @@ #include #include -#define loslib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -21,60 +23,108 @@ /* +** {================================================================== ** list of valid conversion specifiers for the 'strftime' function +** =================================================================== */ -#if !defined(LUA_STRFTIMEOPTIONS) +#if !defined(LUA_STRFTIMEOPTIONS) /* { */ -#if !defined(LUA_USE_POSIX) +#if defined(LUA_USE_C89) #define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } -#else +#else /* C99 specification */ #define LUA_STRFTIMEOPTIONS \ - { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \ - "", "E", "cCxXyY", \ + { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ + "E", "cCxXyY", \ "O", "deHImMSuUVwWy" } #endif -#endif - +#endif /* } */ +/* }================================================================== */ /* -** By default, Lua uses tmpnam except when POSIX is available, where it -** uses mkstemp. +** {================================================================== +** Configuration for time-related stuff +** =================================================================== */ -#if defined(LUA_USE_MKSTEMP) -#include -#define LUA_TMPNAMBUFSIZE 32 -#define lua_tmpnam(b,e) { \ - strcpy(b, "/tmp/lua_XXXXXX"); \ - e = mkstemp(b); \ - if (e != -1) close(e); \ - e = (e == -1); } -#elif !defined(lua_tmpnam) +#if !defined(l_time_t) /* { */ +/* +** type to represent time_t in Lua +*/ +#define l_timet lua_Integer +#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } +static time_t l_checktime (lua_State *L, int arg) { + lua_Integer t = luaL_checkinteger(L, arg); + luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); + return (time_t)t; +} -#endif +#endif /* } */ +#if !defined(l_gmtime) /* { */ /* ** By default, Lua uses gmtime/localtime, except when POSIX is available, ** where it uses gmtime_r/localtime_r */ -#if defined(LUA_USE_GMTIME_R) + +#if defined(LUA_USE_POSIX) /* { */ #define l_gmtime(t,r) gmtime_r(t,r) #define l_localtime(t,r) localtime_r(t,r) -#elif !defined(l_gmtime) +#else /* }{ */ + +/* ISO C definitions */ +#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) +#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) + +#endif /* } */ + +#endif /* } */ + +/* }================================================================== */ + -#define l_gmtime(t,r) ((void)r, gmtime(t)) -#define l_localtime(t,r) ((void)r, localtime(t)) +/* +** {================================================================== +** Configuration for 'tmpnam': +** By default, Lua uses tmpnam except when POSIX is available, where +** it uses mkstemp. +** =================================================================== +*/ +#if !defined(lua_tmpnam) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include + +#define LUA_TMPNAMBUFSIZE 32 +#if !defined(LUA_TMPNAMTEMPLATE) +#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" #endif +#define lua_tmpnam(b,e) { \ + strcpy(b, LUA_TMPNAMTEMPLATE); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#else /* }{ */ + +/* ISO C definitions */ +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif /* } */ + +#endif /* } */ +/* }================================================================== */ + + static int os_execute (lua_State *L) { @@ -147,24 +197,35 @@ static void setboolfield (lua_State *L, const char *key, int value) { static int getboolfield (lua_State *L, const char *key) { int res; - lua_getfield(L, -1, key); - res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); lua_pop(L, 1); return res; } -static int getfield (lua_State *L, const char *key, int d) { - int res, isnum; - lua_getfield(L, -1, key); - res = (int)lua_tointegerx(L, -1, &isnum); - if (!isnum) { - if (d < 0) - return luaL_error(L, "field " LUA_QS " missing in date table", key); +/* maximum value for date fields (to avoid arithmetic overflows with 'int') */ +#if !defined(L_MAXDATEFIELD) +#define L_MAXDATEFIELD (INT_MAX / 2) +#endif + +static int getfield (lua_State *L, const char *key, int d, int delta) { + int isnum; + int t = lua_getfield(L, -1, key); + lua_Integer res = lua_tointegerx(L, -1, &isnum); + if (!isnum) { /* field is not a number? */ + if (t != LUA_TNIL) /* some other value? */ + return luaL_error(L, "field '%s' not an integer", key); + else if (d < 0) /* absent field; no default? */ + return luaL_error(L, "field '%s' missing in date table", key); res = d; } + else { + if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) + return luaL_error(L, "field '%s' out-of-bounds", key); + res -= delta; + } lua_pop(L, 1); - return res; + return (int)res; } @@ -192,19 +253,23 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) { } +/* maximum size for an individual 'strftime' item */ +#define SIZETIMEFMT 250 + + static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); - time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); + time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); struct tm tmr, *stm; if (*s == '!') { /* UTC? */ stm = l_gmtime(&t, &tmr); - s++; /* skip `!' */ + s++; /* skip '!' */ } else stm = l_localtime(&t, &tmr); if (stm == NULL) /* invalid date? */ - lua_pushnil(L); - else if (strcmp(s, "*t") == 0) { + luaL_error(L, "time result cannot be represented in this installation"); + if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); @@ -222,14 +287,14 @@ static int os_date (lua_State *L) { cc[0] = '%'; luaL_buffinit(L, &b); while (*s) { - if (*s != '%') /* no conversion specifier? */ + if (*s != '%') /* not a conversion specifier? */ luaL_addchar(&b, *s++); else { size_t reslen; - char buff[200]; /* should be big enough for any conversion result */ + char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); s = checkoption(L, s + 1, cc); - reslen = strftime(buff, sizeof(buff), cc, stm); - luaL_addlstring(&b, buff, reslen); + reslen = strftime(buff, SIZETIMEFMT, cc, stm); + luaL_addsize(&b, reslen); } } luaL_pushresult(&b); @@ -246,26 +311,26 @@ static int os_time (lua_State *L) { struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0); - ts.tm_min = getfield(L, "min", 0); - ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -1); - ts.tm_mon = getfield(L, "month", -1) - 1; - ts.tm_year = getfield(L, "year", -1) - 1900; + ts.tm_sec = getfield(L, "sec", 0, 0); + ts.tm_min = getfield(L, "min", 0, 0); + ts.tm_hour = getfield(L, "hour", 12, 0); + ts.tm_mday = getfield(L, "day", -1, 0); + ts.tm_mon = getfield(L, "month", -1, 1); + ts.tm_year = getfield(L, "year", -1, 1900); ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); } - if (t == (time_t)(-1)) - lua_pushnil(L); - else - lua_pushnumber(L, (lua_Number)t); + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + luaL_error(L, "time result cannot be represented in this installation"); + l_pushtime(L, t); return 1; } static int os_difftime (lua_State *L) { - lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), - (time_t)(luaL_optnumber(L, 2, 0)))); + time_t t1 = l_checktime(L, 1); + time_t t2 = l_checktime(L, 2); + lua_pushnumber(L, (lua_Number)difftime(t1, t2)); return 1; } @@ -289,7 +354,7 @@ static int os_exit (lua_State *L) { if (lua_isboolean(L, 1)) status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); else - status = luaL_optint(L, 1, EXIT_SUCCESS); + status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); if (lua_toboolean(L, 2)) lua_close(L); if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ diff --git a/deps/lua/lparser.c b/deps/lua/lparser.c index a8e37fd..880e5c2 100644 --- a/deps/lua/lparser.c +++ b/deps/lua/lparser.c @@ -1,15 +1,17 @@ /* -** $Id: lparser.c,v 2.130.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lparser.c,v 2.149 2015/11/02 16:09:30 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ - -#include - #define lparser_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "lcode.h" @@ -35,17 +37,21 @@ #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) +/* because all strings are unified by the scanner, the parser + can use pointer equality for string equality */ +#define eqstr(a,b) ((a) == (b)) + /* ** nodes for block list (list of active blocks) */ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ - short firstlabel; /* index of first label in this block */ - short firstgoto; /* index of first pending goto in this block */ + int firstlabel; /* index of first label in this block */ + int firstgoto; /* index of first pending goto in this block */ lu_byte nactvar; /* # active locals outside the block */ lu_byte upval; /* true if some variable in the block is an upvalue */ - lu_byte isloop; /* true if `block' is a loop */ + lu_byte isloop; /* true if 'block' is a loop */ } BlockCnt; @@ -57,19 +63,9 @@ static void statement (LexState *ls); static void expr (LexState *ls, expdesc *v); -static void anchor_token (LexState *ls) { - /* last token from outer function must be EOS */ - lua_assert(ls->fs != NULL || ls->t.token == TK_EOS); - if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { - TString *ts = ls->t.seminfo.ts; - luaX_newstring(ls, getstr(ts), ts->tsv.len); - } -} - - /* semantic error */ static l_noret semerror (LexState *ls, const char *msg) { - ls->t.token = 0; /* remove 'near to' from final message */ + ls->t.token = 0; /* remove "near " from final message */ luaX_syntaxerror(ls, msg); } @@ -223,7 +219,7 @@ static int searchupvalue (FuncState *fs, TString *name) { int i; Upvaldesc *up = fs->f->sp->upvalues; for (i = 0; i < fs->nups; i++) { - if (luaS_eqstr(up[i].name, name)) return i; + if (eqstr(up[i].name, name)) return i; } return -1; /* not found */ } @@ -248,7 +244,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { static int searchvar (FuncState *fs, TString *n) { int i; for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { - if (luaS_eqstr(n, getlocvar(fs, i)->varname)) + if (eqstr(n, getlocvar(fs, i)->varname)) return i; } return -1; /* not found */ @@ -344,11 +340,11 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) { FuncState *fs = ls->fs; Labellist *gl = &ls->dyd->gt; Labeldesc *gt = &gl->arr[g]; - lua_assert(luaS_eqstr(gt->name, label->name)); + lua_assert(eqstr(gt->name, label->name)); if (gt->nactvar < label->nactvar) { TString *vname = getlocvar(fs, gt->nactvar)->varname; const char *msg = luaO_pushfstring(ls->L, - " at line %d jumps into the scope of local " LUA_QS, + " at line %d jumps into the scope of local '%s'", getstr(gt->name), gt->line, getstr(vname)); semerror(ls, msg); } @@ -371,7 +367,7 @@ static int findlabel (LexState *ls, int g) { /* check labels in current block for a match */ for (i = bl->firstlabel; i < dyd->label.n; i++) { Labeldesc *lb = &dyd->label.arr[i]; - if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */ + if (eqstr(lb->name, gt->name)) { /* correct label? */ if (gt->nactvar > lb->nactvar && (bl->upval || dyd->label.n > bl->firstlabel)) luaK_patchclose(ls->fs, gt->pc, lb->nactvar); @@ -392,7 +388,7 @@ static int newlabelentry (LexState *ls, Labellist *l, TString *name, l->arr[n].line = line; l->arr[n].nactvar = ls->fs->nactvar; l->arr[n].pc = pc; - l->n++; + l->n = n + 1; return n; } @@ -405,7 +401,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) { Labellist *gl = &ls->dyd->gt; int i = ls->fs->bl->firstgoto; while (i < gl->n) { - if (luaS_eqstr(gl->arr[i].name, lb->name)) + if (eqstr(gl->arr[i].name, lb->name)) closegoto(ls, i, lb); else i++; @@ -414,7 +410,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) { /* -** "export" pending gotos to outer level, to check them against +** export pending gotos to outer level, to check them against ** outer labels; if the block being exited has upvalues, and ** the goto exits the scope of any variable (which can be the ** upvalue), close those variables being exited. @@ -450,7 +446,7 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { /* -** create a label named "break" to resolve break statements +** create a label named 'break' to resolve break statements */ static void breaklabel (LexState *ls) { TString *n = luaS_new(ls->L, "break"); @@ -465,7 +461,7 @@ static void breaklabel (LexState *ls) { static l_noret undefgoto (LexState *ls, Labeldesc *gt) { const char *msg = isreserved(gt->name) ? "<%s> at line %d not inside a loop" - : "no visible label " LUA_QS " for at line %d"; + : "no visible label '%s' for at line %d"; msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); semerror(ls, msg); } @@ -527,7 +523,6 @@ static void codeclosure (LexState *ls, expdesc *v) { static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { - lua_State *L = ls->L; SharedProto *f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; @@ -546,10 +541,6 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { f = fs->f->sp; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ - fs->h = luaH_new(L); - /* anchor table of constants (to avoid being collected) */ - sethvalue2s(L, L->top, fs->h); - incr_top(L); enterblock(fs, bl, 0); } @@ -575,9 +566,6 @@ static void close_func (LexState *ls) { sp->sizeupvalues = fs->nups; lua_assert(fs->bl == NULL); ls->fs = fs->prev; - /* last token read was anchored in defunct function; must re-anchor it */ - anchor_token(ls); - L->top--; /* pop table of constants */ luaC_checkGC(L); } @@ -591,7 +579,7 @@ static void close_func (LexState *ls) { /* ** check whether current token is in the follow set of a block. ** 'until' closes syntactical blocks, but do not close scope, -** so it handled in separate. +** so it is handled in separate. */ static int block_follow (LexState *ls, int withuntil) { switch (ls->t.token) { @@ -605,7 +593,7 @@ static int block_follow (LexState *ls, int withuntil) { static void statlist (LexState *ls) { - /* statlist -> { stat [`;'] } */ + /* statlist -> { stat [';'] } */ while (!block_follow(ls, 1)) { if (ls->t.token == TK_RETURN) { statement(ls); @@ -646,14 +634,14 @@ static void yindex (LexState *ls, expdesc *v) { struct ConsControl { expdesc v; /* last list item read */ expdesc *t; /* table descriptor */ - int nh; /* total number of `record' elements */ + int nh; /* total number of 'record' elements */ int na; /* total number of array elements */ int tostore; /* number of array elements pending to be stored */ }; static void recfield (LexState *ls, struct ConsControl *cc) { - /* recfield -> (NAME | `['exp1`]') = exp1 */ + /* recfield -> (NAME | '['exp1']') = exp1 */ FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; @@ -760,12 +748,12 @@ static void constructor (LexState *ls, expdesc *t) { static void parlist (LexState *ls) { - /* parlist -> [ param { `,' param } ] */ + /* parlist -> [ param { ',' param } ] */ FuncState *fs = ls->fs; SharedProto *f = fs->f->sp; int nparams = 0; f->is_vararg = 0; - if (ls->t.token != ')') { /* is `parlist' not empty? */ + if (ls->t.token != ')') { /* is 'parlist' not empty? */ do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ @@ -773,12 +761,12 @@ static void parlist (LexState *ls) { nparams++; break; } - case TK_DOTS: { /* param -> `...' */ + case TK_DOTS: { /* param -> '...' */ luaX_next(ls); - f->is_vararg = 1; + f->is_vararg = 2; /* declared vararg */ break; } - default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); + default: luaX_syntaxerror(ls, " or '...' expected"); } } while (!f->is_vararg && testnext(ls, ',')); } @@ -789,7 +777,7 @@ static void parlist (LexState *ls) { static void body (LexState *ls, expdesc *e, int ismethod, int line) { - /* body -> `(' parlist `)' block END */ + /* body -> '(' parlist ')' block END */ FuncState new_fs; BlockCnt bl; new_fs.f = addprototype(ls); @@ -811,7 +799,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) { static int explist (LexState *ls, expdesc *v) { - /* explist -> expr { `,' expr } */ + /* explist -> expr { ',' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { @@ -828,7 +816,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) { expdesc args; int base, nparams; switch (ls->t.token) { - case '(': { /* funcargs -> `(' [ explist ] `)' */ + case '(': { /* funcargs -> '(' [ explist ] ')' */ luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; @@ -845,7 +833,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) { } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); - luaX_next(ls); /* must use `seminfo' before `next' */ + luaX_next(ls); /* must use 'seminfo' before 'next' */ break; } default: { @@ -911,14 +899,14 @@ static void suffixedexp (LexState *ls, expdesc *v) { fieldsel(ls, v); break; } - case '[': { /* `[' exp1 `]' */ + case '[': { /* '[' exp1 ']' */ expdesc key; luaK_exp2anyregup(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } - case ':': { /* `:' NAME funcargs */ + case ':': { /* ':' NAME funcargs */ expdesc key; luaX_next(ls); checkname(ls, &key); @@ -938,14 +926,19 @@ static void suffixedexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | + /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | constructor | FUNCTION body | suffixedexp */ switch (ls->t.token) { - case TK_NUMBER: { - init_exp(v, VKNUM, 0); + case TK_FLT: { + init_exp(v, VKFLT, 0); v->u.nval = ls->t.seminfo.r; break; } + case TK_INT: { + init_exp(v, VKINT, 0); + v->u.ival = ls->t.seminfo.i; + break; + } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); break; @@ -965,7 +958,8 @@ static void simpleexp (LexState *ls, expdesc *v) { case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->sp->is_vararg, - "cannot use " LUA_QL("...") " outside a vararg function"); + "cannot use '...' outside a vararg function"); + fs->f->sp->is_vararg = 1; /* function actually uses vararg */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } @@ -991,6 +985,7 @@ static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; + case '~': return OPR_BNOT; case '#': return OPR_LEN; default: return OPR_NOUNOPR; } @@ -1002,9 +997,15 @@ static BinOpr getbinopr (int op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MUL; - case '/': return OPR_DIV; case '%': return OPR_MOD; case '^': return OPR_POW; + case '/': return OPR_DIV; + case TK_IDIV: return OPR_IDIV; + case '&': return OPR_BAND; + case '|': return OPR_BOR; + case '~': return OPR_BXOR; + case TK_SHL: return OPR_SHL; + case TK_SHR: return OPR_SHR; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; @@ -1023,19 +1024,24 @@ static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `*' `/' `%' */ - {10, 9}, {5, 4}, /* ^, .. (right associative) */ - {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ - {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ - {2, 2}, {1, 1} /* and, or */ + {10, 10}, {10, 10}, /* '+' '-' */ + {11, 11}, {11, 11}, /* '*' '%' */ + {14, 13}, /* '^' (right associative) */ + {11, 11}, {11, 11}, /* '/' '//' */ + {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ + {7, 7}, {7, 7}, /* '<<' '>>' */ + {9, 8}, /* '..' (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ }; -#define UNARY_PRIORITY 8 /* priority for unary operators */ +#define UNARY_PRIORITY 12 /* priority for unary operators */ /* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } -** where `binop' is any binary operator with a priority higher than `limit' +** where 'binop' is any binary operator with a priority higher than 'limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { BinOpr op; @@ -1049,7 +1055,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { luaK_prefix(ls->fs, uop, v, line); } else simpleexp(ls, v); - /* expand while operators have priorities higher than `limit' */ + /* expand while operators have priorities higher than 'limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; @@ -1149,7 +1155,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { "C levels"); assignment(ls, &nv, nvars+1); } - else { /* assignment -> `=' explist */ + else { /* assignment -> '=' explist */ int nexps; checknext(ls, '='); nexps = explist(ls, &e); @@ -1173,7 +1179,7 @@ static int cond (LexState *ls) { /* cond -> exp */ expdesc v; expr(ls, &v); /* read condition */ - if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ + if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ luaK_goiftrue(ls->fs, &v); return v.f; } @@ -1198,9 +1204,9 @@ static void gotostat (LexState *ls, int pc) { static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { int i; for (i = fs->bl->firstlabel; i < ll->n; i++) { - if (luaS_eqstr(label, ll->arr[i].name)) { + if (eqstr(label, ll->arr[i].name)) { const char *msg = luaO_pushfstring(fs->ls->L, - "label " LUA_QS " already defined on line %d", + "label '%s' already defined on line %d", getstr(label), ll->arr[i].line); semerror(fs->ls, msg); } @@ -1324,7 +1330,7 @@ static void fornum (LexState *ls, TString *varname, int line) { if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ - luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1)); + luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); @@ -1362,15 +1368,15 @@ static void forstat (LexState *ls, int line) { TString *varname; BlockCnt bl; enterblock(fs, &bl, 1); /* scope for loop and control variables */ - luaX_next(ls); /* skip `for' */ + luaX_next(ls); /* skip 'for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; - default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); + default: luaX_syntaxerror(ls, "'=' or 'in' expected"); } check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); /* loop scope (`break' jumps to this point) */ + leaveblock(fs); /* loop scope ('break' jumps to this point) */ } @@ -1400,7 +1406,7 @@ static void test_then_block (LexState *ls, int *escapelist) { enterblock(fs, &bl, 0); jf = v.f; } - statlist(ls); /* `then' part */ + statlist(ls); /* 'then' part */ leaveblock(fs); if (ls->t.token == TK_ELSE || ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ @@ -1417,7 +1423,7 @@ static void ifstat (LexState *ls, int line) { while (ls->t.token == TK_ELSEIF) test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ if (testnext(ls, TK_ELSE)) - block(ls); /* `else' part */ + block(ls); /* 'else' part */ check_match(ls, TK_END, TK_IF, line); luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ } @@ -1435,7 +1441,7 @@ static void localfunc (LexState *ls) { static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */ + /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ int nvars = 0; int nexps; expdesc e; @@ -1455,7 +1461,7 @@ static void localstat (LexState *ls) { static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {fieldsel} [`:' NAME] */ + /* funcname -> NAME {fieldsel} [':' NAME] */ int ismethod = 0; singlevar(ls, v); while (ls->t.token == '.') @@ -1476,7 +1482,7 @@ static void funcstat (LexState *ls, int line) { ismethod = funcname(ls, &v); body(ls, &b, ismethod, line); luaK_storevar(ls->fs, &v, &b); - luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ + luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ } @@ -1518,8 +1524,8 @@ static void retstat (LexState *ls) { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { - luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ - first = fs->nactvar; /* return all `active' values */ + luaK_exp2nextreg(fs, &e); /* values must go to the stack */ + first = fs->nactvar; /* return all active values */ lua_assert(nret == fs->freereg - first); } } @@ -1591,7 +1597,7 @@ static void statement (LexState *ls) { break; } } - lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && + lua_assert(ls->fs->f->sp->maxstacksize >= ls->fs->freereg && ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ leavelevel(ls); @@ -1608,7 +1614,7 @@ static void mainfunc (LexState *ls, FuncState *fs) { BlockCnt bl; expdesc v; open_func(ls, fs, &bl); - fs->f->sp->is_vararg = 1; /* main function is always vararg */ + fs->f->sp->is_vararg = 2; /* main function is always declared vararg */ init_exp(&v, VLOCAL, 0); /* create and... */ newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ luaX_next(ls); /* read first token */ @@ -1618,16 +1624,19 @@ static void mainfunc (LexState *ls, FuncState *fs) { } -Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar) { +LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { LexState lexstate; FuncState funcstate; - Closure *cl = luaF_newLclosure(L, 1); /* create main closure */ - /* anchor closure (to avoid being collected) */ - setclLvalue(L, L->top, cl); - incr_top(L); - funcstate.f = cl->l.p = luaF_newproto(L, NULL); + LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + lexstate.h = luaH_new(L); /* create table for scanner */ + sethvalue(L, L->top, lexstate.h); /* anchor it */ + luaD_inctop(L); + funcstate.f = cl->p = luaF_newproto(L, NULL); funcstate.f->sp->source = luaS_new(L, name); /* create and anchor TString */ + lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ lexstate.buff = buff; lexstate.dyd = dyd; dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; @@ -1636,6 +1645,7 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); /* all scopes should be correctly finished */ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); - return cl; /* it's on the stack too */ + L->top--; /* remove scanner's table */ + return cl; /* closure is on the stack, too */ } diff --git a/deps/lua/lparser.h b/deps/lua/lparser.h index 0346e3c..62c50ca 100644 --- a/deps/lua/lparser.h +++ b/deps/lua/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.70.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -21,8 +21,9 @@ typedef enum { VNIL, VTRUE, VFALSE, - VK, /* info = index of constant in `k' */ - VKNUM, /* nval = numerical value */ + VK, /* info = index of constant in 'k' */ + VKFLT, /* nval = numerical float value */ + VKINT, /* nval = numerical integer value */ VNONRELOC, /* info = result register */ VLOCAL, /* info = local register */ VUPVAL, /* info = index of upvalue in 'upvalues' */ @@ -46,10 +47,11 @@ typedef struct expdesc { lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ } ind; int info; /* for generic use */ - lua_Number nval; /* for VKNUM */ + lua_Number nval; /* for VKFLT */ + lua_Integer ival; /* for VKINT */ } u; - int t; /* patch list of `exit when true' */ - int f; /* patch list of `exit when false' */ + int t; /* patch list of 'exit when true' */ + int f; /* patch list of 'exit when false' */ } expdesc; @@ -95,15 +97,14 @@ struct BlockCnt; /* defined in lparser.c */ /* state needed to generate code for a given function */ typedef struct FuncState { Proto *f; /* current function header */ - Table *h; /* table to find (and reuse) elements in `k' */ struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ struct BlockCnt *bl; /* chain of current blocks */ - int pc; /* next position to code (equivalent to `ncode') */ + int pc; /* next position to code (equivalent to 'ncode') */ int lasttarget; /* 'label' of last 'jump label' */ - int jpc; /* list of pending jumps to `pc' */ - int nk; /* number of elements in `k' */ - int np; /* number of elements in `p' */ + int jpc; /* list of pending jumps to 'pc' */ + int nk; /* number of elements in 'k' */ + int np; /* number of elements in 'p' */ int firstlocal; /* index of first local var (in Dyndata array) */ short nlocvars; /* number of elements in 'f->locvars' */ lu_byte nactvar; /* number of active local variables */ @@ -112,8 +113,8 @@ typedef struct FuncState { } FuncState; -LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar); +LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); #endif diff --git a/deps/lua/lprefix.h b/deps/lua/lprefix.h new file mode 100644 index 0000000..02daa83 --- /dev/null +++ b/deps/lua/lprefix.h @@ -0,0 +1,45 @@ +/* +** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ +** Definitions for Lua code that must come before any other header file +** See Copyright Notice in lua.h +*/ + +#ifndef lprefix_h +#define lprefix_h + + +/* +** Allows POSIX/XSI stuff +*/ +#if !defined(LUA_USE_C89) /* { */ + +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 +#elif _XOPEN_SOURCE == 0 +#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ +#endif + +/* +** Allows manipulation of large files in gcc and some other compilers +*/ +#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#endif + +#endif /* } */ + + +/* +** Windows stuff +*/ +#if defined(_WIN32) /* { */ + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ +#endif + +#endif /* } */ + +#endif + diff --git a/deps/lua/lstate.c b/deps/lua/lstate.c index c7f2672..9194ac3 100644 --- a/deps/lua/lstate.c +++ b/deps/lua/lstate.c @@ -1,16 +1,18 @@ /* -** $Id: lstate.c,v 2.99.1.2 2013/11/08 17:45:31 roberto Exp $ +** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ +#define lstate_c +#define LUA_CORE + +#include "lprefix.h" + #include #include -#define lstate_c -#define LUA_CORE - #include "lua.h" #include "lapi.h" @@ -30,18 +32,11 @@ #define LUAI_GCPAUSE 200 /* 200% */ #endif -#if !defined(LUAI_GCMAJOR) -#define LUAI_GCMAJOR 200 /* 200% */ -#endif - #if !defined(LUAI_GCMUL) #define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ #endif -#define MEMERRMSG "not enough memory" - - /* ** a macro to help the creation of a unique random seed when a state is ** created; the seed is used to randomize hashes. @@ -57,9 +52,7 @@ ** thread state + extra space */ typedef struct LX { -#if defined(LUAI_EXTRASPACE) - char buff[LUAI_EXTRASPACE]; -#endif + lu_byte extra_[LUA_EXTRASPACE]; lua_State l; } LX; @@ -78,13 +71,12 @@ typedef struct LG { /* -** Compute an initial seed as random as possible. In ANSI, rely on -** Address Space Layout Randomization (if present) to increase -** randomness.. +** Compute an initial seed as random as possible. Rely on Address Space +** Layout Randomization (if present) to increase randomness.. */ #define addbuff(b,p,e) \ { size_t t = cast(size_t, e); \ - memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); } + memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } static unsigned int makeseed (lua_State *L) { char buff[4 * sizeof(size_t)]; @@ -101,10 +93,14 @@ static unsigned int makeseed (lua_State *L) { /* ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) -** invariant +** invariant (and avoiding underflows in 'totalbytes') */ void luaE_setdebt (global_State *g, l_mem debt) { - g->totalbytes -= (debt - g->GCdebt); + l_mem tb = gettotalbytes(g); + lua_assert(tb > 0); + if (debt < tb - MAX_LMEM) + debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ + g->totalbytes = tb - debt; g->GCdebt = debt; } @@ -115,10 +111,14 @@ CallInfo *luaE_extendCI (lua_State *L) { L->ci->next = ci; ci->previous = L->ci; ci->next = NULL; + L->nci++; return ci; } +/* +** free all CallInfo structures not in use by a thread +*/ void luaE_freeCI (lua_State *L) { CallInfo *ci = L->ci; CallInfo *next = ci->next; @@ -126,6 +126,24 @@ void luaE_freeCI (lua_State *L) { while ((ci = next) != NULL) { next = ci->next; luaM_free(L, ci); + L->nci--; + } +} + + +/* +** free half of the CallInfo structures not in use by a thread +*/ +void luaE_shrinkCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next2; /* next's next */ + /* while there are two nexts */ + while (ci->next != NULL && (next2 = ci->next->next) != NULL) { + luaM_free(L, ci->next); /* free next */ + L->nci--; + ci->next = next2; /* remove 'next' from the list */ + next2->previous = ci; + ci = next2; /* keep next's next */ } } @@ -155,6 +173,7 @@ static void freestack (lua_State *L) { return; /* stack not completely built yet */ L->ci = &L->base_ci; /* free the entire 'ci' list */ luaE_freeCI(L); + lua_assert(L->nci == 0); luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ } @@ -163,34 +182,32 @@ static void freestack (lua_State *L) { ** Create registry table and its predefined values */ static void init_registry (lua_State *L, global_State *g) { - TValue mt; + TValue temp; /* create registry */ Table *registry = luaH_new(L); sethvalue(L, &g->l_registry, registry); luaH_resize(L, registry, LUA_RIDX_LAST, 0); /* registry[LUA_RIDX_MAINTHREAD] = L */ - setthvalue(L, &mt, L); - luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt); + setthvalue(L, &temp, L); /* temp = L */ + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); /* registry[LUA_RIDX_GLOBALS] = table of globals */ - sethvalue(L, &mt, luaH_new(L)); - luaH_setint(L, registry, LUA_RIDX_GLOBALS, &mt); + sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ + luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); } /* -** open parts of the state that may cause memory-allocation errors +** open parts of the state that may cause memory-allocation errors. +** ('g->version' != NULL flags that the state was completely build) */ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ init_registry(L, g); - luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + luaS_init(L); luaT_init(L); luaX_init(L); - /* pre-create memory-error message */ - g->memerrmsg = luaS_newliteral(L, MEMERRMSG); - luaS_fix(g->memerrmsg); /* it should never be collected */ g->gcrunning = 1; /* allow gc */ g->version = lua_version(NULL); luai_userstateopen(L); @@ -198,14 +215,16 @@ static void f_luaopen (lua_State *L, void *ud) { /* -** preinitialize a state with consistent values without allocating +** preinitialize a thread with consistent values without allocating ** any memory (to avoid errors) */ -static void preinit_state (lua_State *L, global_State *g) { +static void preinit_thread (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; L->ci = NULL; + L->nci = 0; L->stacksize = 0; + L->twups = L; /* thread has no upvalues */ L->errorJmp = NULL; L->nCcalls = 0; L->hook = NULL; @@ -227,7 +246,6 @@ static void close_state (lua_State *L) { if (g->version) /* closing a fully built state? */ luai_userstateclose(L); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); - luaZ_freebuffer(L, &g->buff); freestack(L); lua_assert(gettotalbytes(g) == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ @@ -235,17 +253,28 @@ static void close_state (lua_State *L) { LUA_API lua_State *lua_newthread (lua_State *L) { + global_State *g = G(L); lua_State *L1; lua_lock(L); luaC_checkGC(L); - L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th; + /* create new thread */ + L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; + L1->marked = luaC_white(g); + L1->tt = LUA_TTHREAD; + /* link it on list 'allgc' */ + L1->next = g->allgc; + g->allgc = obj2gco(L1); + /* anchor it on L stack */ setthvalue(L, L->top, L1); api_incr_top(L); - preinit_state(L1, G(L)); + preinit_thread(L1, g); L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); + /* initialize L1 extra space */ + memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), + LUA_EXTRASPACE); luai_userstatethread(L, L1); stack_init(L1, L); /* init stack */ lua_unlock(L); @@ -273,36 +302,31 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g = &l->g; L->next = NULL; L->tt = LUA_TTHREAD; - g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); + g->currentwhite = bitmask(WHITE0BIT); L->marked = luaC_white(g); - g->gckind = KGC_NORMAL; - preinit_state(L, g); + preinit_thread(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; g->seed = makeseed(L); - g->uvhead.u.l.prev = &g->uvhead; - g->uvhead.u.l.next = &g->uvhead; g->gcrunning = 0; /* no GC while building state */ g->GCestimate = 0; - g->strt.size = 0; - g->strt.nuse = 0; + g->strt.size = g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(&g->l_registry); - luaZ_initbuffer(L, &g->buff); g->panic = NULL; g->version = NULL; g->gcstate = GCSpause; - g->allgc = NULL; - g->finobj = NULL; - g->tobefnz = NULL; - g->sweepgc = g->sweepfin = NULL; + g->gckind = KGC_NORMAL; + g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; + g->sweepgc = NULL; g->gray = g->grayagain = NULL; g->weak = g->ephemeron = g->allweak = NULL; + g->twups = NULL; g->totalbytes = sizeof(LG); g->GCdebt = 0; + g->gcfinnum = 0; g->gcpause = LUAI_GCPAUSE; - g->gcmajorinc = LUAI_GCMAJOR; g->gcstepmul = LUAI_GCMUL; for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { diff --git a/deps/lua/lstate.h b/deps/lua/lstate.h index daffd9a..65c914d 100644 --- a/deps/lua/lstate.h +++ b/deps/lua/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.82.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lstate.h,v 2.128 2015/11/13 12:16:51 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -16,25 +16,16 @@ /* -** Some notes about garbage-collected objects: All objects in Lua must -** be kept somehow accessible until being freed. +** Some notes about garbage-collected objects: All objects in Lua must +** be kept somehow accessible until being freed, so all objects always +** belong to one (and only one) of these lists, using field 'next' of +** the 'CommonHeader' for the link: ** -** Lua keeps most objects linked in list g->allgc. The link uses field -** 'next' of the CommonHeader. -** -** Strings are kept in several lists headed by the array g->strt.hash. -** -** Open upvalues are not subject to independent garbage collection. They -** are collected together with their respective threads. Lua keeps a -** double-linked list with all open upvalues (g->uvhead) so that it can -** mark objects referred by them. (They are always gray, so they must -** be remarked in the atomic step. Usually their contents would be marked -** when traversing the respective threads, but the thread may already be -** dead, while the upvalue is still accessible through closures.) -** -** Objects with finalizers are kept in the list g->finobj. -** -** The list g->tobefnz links all objects being finalized. +** 'allgc': all objects not marked for finalization; +** 'finobj': all objects marked for finalization; +** 'tobefnz': all objects ready to be finalized; +** 'fixedgc': all objects that are not to be collected (currently +** only small strings, such as reserved words). */ @@ -53,66 +44,72 @@ struct lua_longjmp; /* defined in ldo.c */ /* kinds of Garbage Collection */ #define KGC_NORMAL 0 #define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ -#define KGC_GEN 2 /* generational collection */ typedef struct stringtable { - GCObject **hash; - lu_int32 nuse; /* number of elements */ + TString **hash; + int nuse; /* number of elements */ int size; } stringtable; /* -** information about a call +** Information about a call. +** When a thread yields, 'func' is adjusted to pretend that the +** top function has only the yielded values in its stack; in that +** case, the actual 'func' value is saved in field 'extra'. +** When a function calls another with a continuation, 'extra' keeps +** the function index so that, in case of errors, the continuation +** function can be called with the correct top. */ typedef struct CallInfo { StkId func; /* function index in the stack */ StkId top; /* top for this function */ struct CallInfo *previous, *next; /* dynamic call link */ - short nresults; /* expected number of results from this function */ - lu_byte callstatus; - ptrdiff_t extra; union { struct { /* only for Lua functions */ StkId base; /* base for this function */ const Instruction *savedpc; } l; struct { /* only for C functions */ - int ctx; /* context info. in case of yields */ - lua_CFunction k; /* continuation in case of yields */ + lua_KFunction k; /* continuation in case of yields */ ptrdiff_t old_errfunc; - lu_byte old_allowhook; - lu_byte status; + lua_KContext ctx; /* context info. in case of yields */ } c; } u; + ptrdiff_t extra; + short nresults; /* expected number of results from this function */ + lu_byte callstatus; } CallInfo; /* ** Bits in CallInfo status */ -#define CIST_LUA (1<<0) /* call is running a Lua function */ -#define CIST_HOOKED (1<<1) /* call is running a debug hook */ -#define CIST_REENTRY (1<<2) /* call is running on same invocation of - luaV_execute of previous call */ -#define CIST_YIELDED (1<<3) /* call reentered after suspension */ +#define CIST_OAH (1<<0) /* original value of 'allowhook' */ +#define CIST_LUA (1<<1) /* call is running a Lua function */ +#define CIST_HOOKED (1<<2) /* call is running a debug hook */ +#define CIST_FRESH (1<<3) /* call is running on a fresh invocation + of luaV_execute */ #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ -#define CIST_STAT (1<<5) /* call has an error status (pcall) */ -#define CIST_TAIL (1<<6) /* call was tail called */ -#define CIST_HOOKYIELD (1<<7) /* last hook called yielded */ - +#define CIST_TAIL (1<<5) /* call was tail called */ +#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ +#define CIST_LEQ (1<<7) /* using __lt for __le */ #define isLua(ci) ((ci)->callstatus & CIST_LUA) +/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ +#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) +#define getoah(st) ((st) & CIST_OAH) + /* -** `global state', shared by all threads of this state +** 'global state', shared by all threads of this state */ typedef struct global_State { lua_Alloc frealloc; /* function to reallocate memory */ - void *ud; /* auxiliary data to `frealloc' */ - lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ + void *ud; /* auxiliary data to 'frealloc' */ + l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ lu_mem GCmemtrav; /* memory traversed by the GC */ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ @@ -123,36 +120,36 @@ typedef struct global_State { lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ lu_byte gcrunning; /* true if GC is running */ - int sweepstrgc; /* position of sweep in `strt' */ GCObject *allgc; /* list of all collectable objects */ + GCObject **sweepgc; /* current position of sweep in list */ GCObject *finobj; /* list of collectable objects with finalizers */ - GCObject **sweepgc; /* current position of sweep in list 'allgc' */ - GCObject **sweepfin; /* current position of sweep in list 'finobj' */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of tables with weak values */ GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ GCObject *allweak; /* list of all-weak tables */ GCObject *tobefnz; /* list of userdata to be GC */ - UpVal uvhead; /* head of double-linked list of all open upvalues */ - Mbuffer buff; /* temporary buffer for string concatenation */ + GCObject *fixedgc; /* list of objects not to be collected */ + struct lua_State *twups; /* list of threads with open upvalues */ + unsigned int gcfinnum; /* number of finalizers to call in each GC step */ int gcpause; /* size of pause between successive GCs */ - int gcmajorinc; /* pause between major collections (only in gen. mode) */ - int gcstepmul; /* GC `granularity' */ + int gcstepmul; /* GC 'granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ struct lua_State *mainthread; const lua_Number *version; /* pointer to version number */ TString *memerrmsg; /* memory-error message */ TString *tmname[TM_N]; /* array with tag-method names */ struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ + TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ } global_State; /* -** `per thread' state +** 'per thread' state */ struct lua_State { CommonHeader; + unsigned short nci; /* number of items in 'ci' list */ lu_byte status; StkId top; /* first free slot in the stack */ global_State *l_G; @@ -160,19 +157,20 @@ struct lua_State { const Instruction *oldpc; /* last pc traced */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ + UpVal *openupval; /* list of open upvalues in this stack */ + GCObject *gclist; + struct lua_State *twups; /* list of threads with open upvalues */ + struct lua_longjmp *errorJmp; /* current error recover point */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ + lua_Hook hook; + ptrdiff_t errfunc; /* current error handling function (stack index) */ int stacksize; + int basehookcount; + int hookcount; unsigned short nny; /* number of non-yieldable calls in stack */ unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; - int basehookcount; - int hookcount; - lua_Hook hook; - GCObject *openupval; /* list of open upvalues in this stack */ - GCObject *gclist; - struct lua_longjmp *errorJmp; /* current error recover point */ - ptrdiff_t errfunc; /* current error handling function (stack index) */ - CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ }; @@ -180,48 +178,47 @@ struct lua_State { /* -** Union of all collectable objects +** Union of all collectable objects (only for conversions) */ -union GCObject { - GCheader gch; /* common header */ - union TString ts; - union Udata u; +union GCUnion { + GCObject gc; /* common header */ + struct TString ts; + struct Udata u; union Closure cl; struct Table h; struct Proto p; - struct UpVal uv; struct lua_State th; /* thread */ }; -#define gch(o) (&(o)->gch) +#define cast_u(o) cast(union GCUnion *, (o)) /* macros to convert a GCObject into a specific value */ -#define rawgco2ts(o) \ - check_exp(novariant((o)->gch.tt) == LUA_TSTRING, &((o)->ts)) -#define gco2ts(o) (&rawgco2ts(o)->tsv) -#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) -#define gco2u(o) (&rawgco2u(o)->uv) -#define gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l)) -#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c)) +#define gco2ts(o) \ + check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) +#define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u)) +#define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l)) +#define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c)) #define gco2cl(o) \ - check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) -#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) -#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) -#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) -#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) + check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) +#define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) +#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) +#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) + -/* macro to convert any Lua object into a GCObject */ -#define obj2gco(v) (cast(GCObject *, (v))) +/* macro to convert a Lua object into a GCObject */ +#define obj2gco(v) \ + check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc))) /* actual number of total bytes allocated */ -#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt) +#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC void luaE_freeCI (lua_State *L); +LUAI_FUNC void luaE_shrinkCI (lua_State *L); #endif diff --git a/deps/lua/lstring.c b/deps/lua/lstring.c index af96c89..9351766 100644 --- a/deps/lua/lstring.c +++ b/deps/lua/lstring.c @@ -1,23 +1,30 @@ /* -** $Id: lstring.c,v 2.26.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ - -#include - #define lstring_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" +#include "ldebug.h" +#include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" +#define MEMERRMSG "not enough memory" + + /* ** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to ** compute its hash @@ -31,99 +38,126 @@ ** equality for long strings */ int luaS_eqlngstr (TString *a, TString *b) { - size_t len = a->tsv.len; - lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR); + size_t len = a->u.lnglen; + lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); return (a == b) || /* same instance or... */ - ((len == b->tsv.len) && /* equal length and ... */ + ((len == b->u.lnglen) && /* equal length and ... */ (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ } -/* -** equality for strings -*/ -int luaS_eqstr (TString *a, TString *b) { - return (a->tsv.tt == b->tsv.tt) && - (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b)); -} - - unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { unsigned int h = seed ^ cast(unsigned int, l); - size_t l1; size_t step = (l >> LUAI_HASHLIMIT) + 1; - for (l1 = l; l1 >= step; l1 -= step) - h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1])); + for (; l >= step; l -= step) + h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); return h; } +unsigned int luaS_hashlongstr (TString *ts) { + lua_assert(ts->tt == LUA_TLNGSTR); + if (ts->extra == 0) { /* no hash? */ + ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); + ts->extra = 1; /* now it has its hash */ + } + return ts->hash; +} + + /* ** resizes the string table */ void luaS_resize (lua_State *L, int newsize) { int i; stringtable *tb = &G(L)->strt; - /* cannot resize while GC is traversing strings */ - luaC_runtilstate(L, ~bitmask(GCSsweepstring)); - if (newsize > tb->size) { - luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); - for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL; + if (newsize > tb->size) { /* grow table if needed */ + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); + for (i = tb->size; i < newsize; i++) + tb->hash[i] = NULL; } - /* rehash */ - for (i=0; isize; i++) { - GCObject *p = tb->hash[i]; + for (i = 0; i < tb->size; i++) { /* rehash */ + TString *p = tb->hash[i]; tb->hash[i] = NULL; while (p) { /* for each node in the list */ - GCObject *next = gch(p)->next; /* save next */ - unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ - gch(p)->next = tb->hash[h]; /* chain it */ + TString *hnext = p->u.hnext; /* save next */ + unsigned int h = lmod(p->hash, newsize); /* new position */ + p->u.hnext = tb->hash[h]; /* chain it */ tb->hash[h] = p; - resetoldbit(p); /* see MOVE OLD rule */ - p = next; + p = hnext; } } - if (newsize < tb->size) { - /* shrinking slice must be empty */ + if (newsize < tb->size) { /* shrink table if needed */ + /* vanishing slice should be empty */ lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); - luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); } tb->size = newsize; } +/* +** Clear API string cache. (Entries cannot be empty, so fill them with +** a non-collectable string.) +*/ +void luaS_clearcache (global_State *g) { + int i, j; + for (i = 0; i < STRCACHE_N; i++) + for (j = 0; j < STRCACHE_M; j++) { + if (iswhite(g->strcache[i][j])) /* will entry be collected? */ + g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ + } +} + + +/* +** Initialize the string table and the string cache +*/ +void luaS_init (lua_State *L) { + global_State *g = G(L); + int i, j; + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ + for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ + for (j = 0; j < STRCACHE_M; j++) + g->strcache[i][j] = g->memerrmsg; +} + + + /* ** creates a new string object */ -static TString *createstrobj (lua_State *L, const char *str, size_t l, - int tag, unsigned int h, GCObject **list) { +static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { TString *ts; + GCObject *o; size_t totalsize; /* total size of TString object */ - totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); - ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts; - ts->tsv.len = l; - ts->tsv.hash = h; - ts->tsv.extra = 0; - memcpy(ts+1, str, l*sizeof(char)); - ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + totalsize = sizelstring(l); + o = luaC_newobj(L, tag, totalsize); + ts = gco2ts(o); + ts->hash = h; + ts->extra = 0; + getstr(ts)[l] = '\0'; /* ending 0 */ return ts; } -/* -** creates a new short string, inserting it into string table -*/ -static TString *newshrstr (lua_State *L, const char *str, size_t l, - unsigned int h) { - GCObject **list; /* (pointer to) list where it will be inserted */ +TString *luaS_createlngstrobj (lua_State *L, size_t l) { + TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); + ts->u.lnglen = l; + return ts; +} + + +void luaS_remove (lua_State *L, TString *ts) { stringtable *tb = &G(L)->strt; - TString *s; - if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) - luaS_resize(L, tb->size*2); /* too crowded */ - list = &tb->hash[lmod(h, tb->size)]; - s = createstrobj(L, str, l, LUA_TSHRSTR, h, list); - tb->nuse++; - return s; + TString **p = &tb->hash[lmod(ts->hash, tb->size)]; + while (*p != ts) /* find previous element */ + p = &(*p)->u.hnext; + *p = (*p)->u.hnext; /* remove element from its list */ + tb->nuse--; } @@ -131,22 +165,31 @@ static TString *newshrstr (lua_State *L, const char *str, size_t l, ** checks whether short string exists and reuses it or creates a new one */ static TString *internshrstr (lua_State *L, const char *str, size_t l) { - GCObject *o; + TString *ts; global_State *g = G(L); unsigned int h = luaS_hash(str, l, g->seed); - for (o = g->strt.hash[lmod(h, g->strt.size)]; - o != NULL; - o = gch(o)->next) { - TString *ts = rawgco2ts(o); - if (h == ts->tsv.hash && - l == ts->tsv.len && + TString **list = &g->strt.hash[lmod(h, g->strt.size)]; + lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ + for (ts = *list; ts != NULL; ts = ts->u.hnext) { + if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { - if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ - changewhite(o); /* resurrect it */ + /* found! */ + if (isdead(g, ts)) /* dead (but not collected yet)? */ + changewhite(ts); /* resurrect it */ return ts; } } - return newshrstr(L, str, l, h); /* not found; create a new string */ + if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { + luaS_resize(L, g->strt.size * 2); + list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ + } + ts = createstrobj(L, l, LUA_TSHRSTR, h); + memcpy(getstr(ts), str, l * sizeof(char)); + ts->shrlen = cast_byte(l); + ts->u.hnext = *list; + *list = ts; + g->strt.nuse++; + return ts; } @@ -157,29 +200,49 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { if (l <= LUAI_MAXSHORTLEN) /* short string? */ return internshrstr(L, str, l); else { - if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + TString *ts; + if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) luaM_toobig(L); - return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL); + ts = luaS_createlngstrobj(L, l); + memcpy(getstr(ts), str, l * sizeof(char)); + return ts; } } /* -** new zero-terminated string +** Create or reuse a zero-terminated string, first checking in the +** cache (using the string address as a key). The cache can contain +** only zero-terminated strings, so it is safe to use 'strcmp' to +** check hits. */ TString *luaS_new (lua_State *L, const char *str) { - return luaS_newlstr(L, str, strlen(str)); + unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ + int j; + TString **p = G(L)->strcache[i]; + for (j = 0; j < STRCACHE_M; j++) { + if (strcmp(str, getstr(p[j])) == 0) /* hit? */ + return p[j]; /* that is it */ + } + /* normal route */ + for (j = STRCACHE_M - 1; j > 0; j--) + p[j] = p[j - 1]; /* move out last element */ + /* new element is first in the list */ + p[0] = luaS_newlstr(L, str, strlen(str)); + return p[0]; } -Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { +Udata *luaS_newudata (lua_State *L, size_t s) { Udata *u; - if (s > MAX_SIZET - sizeof(Udata)) + GCObject *o; + if (s > MAX_SIZE - sizeof(Udata)) luaM_toobig(L); - u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u; - u->uv.len = s; - u->uv.metatable = NULL; - u->uv.env = e; + o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); + u = gco2u(o); + u->len = s; + u->metatable = NULL; + setuservalue(L, u, luaO_nilobject); return u; } diff --git a/deps/lua/lstring.h b/deps/lua/lstring.h index 260e7f1..27efd20 100644 --- a/deps/lua/lstring.h +++ b/deps/lua/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -12,35 +12,38 @@ #include "lstate.h" -#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) +#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) -#define sizeudata(u) (sizeof(union Udata)+(u)->len) +#define sizeludata(l) (sizeof(union UUdata) + (l)) +#define sizeudata(u) sizeludata((u)->len) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) -#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) - /* ** test whether a string is a reserved word */ -#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0) +#define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) /* ** equality for short strings, which are always internalized */ -#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b)) +#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); -LUAI_FUNC int luaS_eqstr (TString *a, TString *b); LUAI_FUNC void luaS_resize (lua_State *L, int newsize); -LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); +LUAI_FUNC void luaS_clearcache (global_State *g); +LUAI_FUNC void luaS_init (lua_State *L); +LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); +LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); #endif diff --git a/deps/lua/lstrlib.c b/deps/lua/lstrlib.c index 9261fd2..fe30e34 100644 --- a/deps/lua/lstrlib.c +++ b/deps/lua/lstrlib.c @@ -1,19 +1,23 @@ /* -** $Id: lstrlib.c,v 1.178.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lstrlib.c,v 1.239 2015/11/25 16:28:17 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ +#define lstrlib_c +#define LUA_LIB + +#include "lprefix.h" + #include +#include +#include #include #include #include #include -#define lstrlib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -29,10 +33,21 @@ #endif -/* macro to `unsign' a character */ +/* macro to 'unsign' a character */ #define uchar(c) ((unsigned char)(c)) +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + + + static int str_len (lua_State *L) { size_t l; @@ -43,22 +58,22 @@ static int str_len (lua_State *L) { /* translate a relative string position: negative means back from end */ -static size_t posrelat (ptrdiff_t pos, size_t len) { - if (pos >= 0) return (size_t)pos; +static lua_Integer posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; else if (0u - (size_t)pos > len) return 0; - else return len - ((size_t)-pos) + 1; + else return (lua_Integer)len + pos + 1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - size_t start = posrelat(luaL_checkinteger(L, 2), l); - size_t end = posrelat(luaL_optinteger(L, 3, -1), l); + lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); + lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; - if (end > l) end = l; + if (end > (lua_Integer)l) end = l; if (start <= end) - lua_pushlstring(L, s + start - 1, end - start + 1); + lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); else lua_pushliteral(L, ""); return 1; } @@ -102,25 +117,23 @@ static int str_upper (lua_State *L) { } -/* reasonable limit to avoid arithmetic overflow */ -#define MAXSIZE ((~(size_t)0) >> 1) - static int str_rep (lua_State *L) { size_t l, lsep; const char *s = luaL_checklstring(L, 1, &l); - int n = luaL_checkint(L, 2); + lua_Integer n = luaL_checkinteger(L, 2); const char *sep = luaL_optlstring(L, 3, "", &lsep); if (n <= 0) lua_pushliteral(L, ""); - else if (l + lsep < l || l + lsep >= MAXSIZE / n) /* may overflow? */ + else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ return luaL_error(L, "resulting string too large"); else { - size_t totallen = n * l + (n - 1) * lsep; + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ memcpy(p, s, l * sizeof(char)); p += l; - if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */ - memcpy(p, sep, lsep * sizeof(char)); p += lsep; + if (lsep > 0) { /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; } } memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ @@ -133,15 +146,15 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - size_t posi = posrelat(luaL_optinteger(L, 2, 1), l); - size_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); + lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; if (posi < 1) posi = 1; - if (pose > l) pose = l; + if (pose > (lua_Integer)l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ - n = (int)(pose - posi + 1); - if (posi + n <= pose) /* (size_t -> int) overflow? */ + if (pose - posi >= INT_MAX) /* arithmetic overflow? */ return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; luaL_checkstack(L, n, "string slice too long"); for (i=0; ip_end) - luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); + luaL_error(ms->L, "malformed pattern (ends with '%%')"); return p+1; } case '[': { if (*p == '^') p++; - do { /* look for a `]' */ + do { /* look for a ']' */ if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); + luaL_error(ms->L, "malformed pattern (missing ']')"); if (*(p++) == L_ESC && p < ms->p_end) - p++; /* skip escapes (e.g. `%]') */ + p++; /* skip escapes (e.g. '%]') */ } while (*p != ']'); return p+1; } @@ -287,7 +313,7 @@ static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; - p++; /* skip the `^' */ + p++; /* skip the '^' */ } while (++p < ec) { if (*p == L_ESC) { @@ -325,8 +351,7 @@ static int singlematch (MatchState *ms, const char *s, const char *p, static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (p >= ms->p_end - 1) - luaL_error(ms->L, "malformed pattern " - "(missing arguments to " LUA_QL("%%b") ")"); + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); if (*s != *p) return NULL; else { int b = *p; @@ -425,7 +450,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { break; } case '$': { - if ((p + 1) != ms->p_end) /* is the `$' the last char in pattern? */ + if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ goto dflt; /* no; go to default */ s = (s == ms->src_end) ? s : NULL; /* check end of string */ break; @@ -443,8 +468,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { const char *ep; char previous; p += 2; if (*p != '[') - luaL_error(ms->L, "missing " LUA_QL("[") " after " - LUA_QL("%%f") " in pattern"); + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s - 1); if (!matchbracketclass(uchar(previous), p, ep - 1) && @@ -478,6 +502,8 @@ static const char *match (MatchState *ms, const char *s, const char *p) { s = NULL; /* fail */ } else { /* matched once */ + if (ms->nrep-- == 0) + luaL_error(ms->L, "pattern too complex"); switch (*ep) { /* handle optional suffix */ case '?': { /* optional */ const char *res; @@ -490,7 +516,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { } case '+': /* 1 or more repetitions */ s++; /* 1 match already done */ - /* go through */ + /* FALLTHROUGH */ case '*': /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; @@ -514,16 +540,16 @@ static const char *match (MatchState *ms, const char *s, const char *p) { static const char *lmemfind (const char *s1, size_t l1, const char *s2, size_t l2) { if (l2 == 0) return s1; /* empty strings are everywhere */ - else if (l2 > l1) return NULL; /* avoids a negative `l1' */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ else { - const char *init; /* to search for a `*s2' inside `s1' */ - l2--; /* 1st char will be checked by `memchr' */ - l1 = l1-l2; /* `s2' cannot be found after that */ + const char *init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1-l2; /* 's2' cannot be found after that */ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { init++; /* 1st char is already checked */ if (memcmp(init, s2+1, l2) == 0) return init-1; - else { /* correct `l1' and `s1' to try again */ + else { /* correct 'l1' and 's1' to try again */ l1 -= init-s1; s1 = init; } @@ -539,13 +565,13 @@ static void push_onecapture (MatchState *ms, int i, const char *s, if (i == 0) /* ms->level == 0, too */ lua_pushlstring(ms->L, s, e - s); /* add whole match */ else - luaL_error(ms->L, "invalid capture index"); + luaL_error(ms->L, "invalid capture index %%%d", i + 1); } else { ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) - lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } @@ -574,23 +600,43 @@ static int nospecials (const char *p, size_t l) { } +static void prepstate (MatchState *ms, lua_State *L, + const char *s, size_t ls, const char *p, size_t lp) { + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; + if (ls < (MAX_SIZET - B_REPS) / A_REPS) + ms->nrep = A_REPS * ls + B_REPS; + else /* overflow (very long subject) */ + ms->nrep = MAX_SIZET; /* no limit */ +} + + +static void reprepstate (MatchState *ms) { + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); +} + + static int str_find_aux (lua_State *L, int find) { size_t ls, lp; const char *s = luaL_checklstring(L, 1, &ls); const char *p = luaL_checklstring(L, 2, &lp); - size_t init = posrelat(luaL_optinteger(L, 3, 1), ls); + lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); if (init < 1) init = 1; - else if (init > ls + 1) { /* start after string's end? */ + else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ lua_pushnil(L); /* cannot find anything */ return 1; } /* explicit request or no special characters? */ if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { /* do a plain search */ - const char *s2 = lmemfind(s + init - 1, ls - init + 1, p, lp); + const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); if (s2) { - lua_pushinteger(L, s2 - s + 1); - lua_pushinteger(L, s2 - s + lp); + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); return 2; } } @@ -601,18 +647,13 @@ static int str_find_aux (lua_State *L, int find) { if (anchor) { p++; lp--; /* skip anchor character */ } - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = s; - ms.src_end = s + ls; - ms.p_end = p + lp; + prepstate(&ms, L, s, ls, p, lp); do { const char *res; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); + reprepstate(&ms); if ((res=match(&ms, s1, p)) != NULL) { if (find) { - lua_pushinteger(L, s1 - s + 1); /* start */ + lua_pushinteger(L, (s1 - s) + 1); /* start */ lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } @@ -636,29 +677,26 @@ static int str_match (lua_State *L) { } +/* state for 'gmatch' */ +typedef struct GMatchState { + const char *src; /* current position */ + const char *p; /* pattern */ + MatchState ms; /* match state */ +} GMatchState; + + static int gmatch_aux (lua_State *L) { - MatchState ms; - size_t ls, lp; - const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); - const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); + GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); const char *src; - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = s; - ms.src_end = s+ls; - ms.p_end = p + lp; - for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); - src <= ms.src_end; - src++) { + for (src = gm->src; src <= gm->ms.src_end; src++) { const char *e; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); - if ((e = match(&ms, src, p)) != NULL) { - lua_Integer newstart = e-s; - if (e == src) newstart++; /* empty match? go at least one position */ - lua_pushinteger(L, newstart); - lua_replace(L, lua_upvalueindex(3)); - return push_captures(&ms, src, e); + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL) { + if (e == src) /* empty match? */ + gm->src =src + 1; /* go at least one position */ + else + gm->src = e; + return push_captures(&gm->ms, src, e); } } return 0; /* not found */ @@ -666,10 +704,14 @@ static int gmatch_aux (lua_State *L) { static int gmatch (lua_State *L) { - luaL_checkstring(L, 1); - luaL_checkstring(L, 2); - lua_settop(L, 2); - lua_pushinteger(L, 0); + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + GMatchState *gm; + lua_settop(L, 2); /* keep them on closure to avoid being collected */ + gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s; gm->p = p; lua_pushcclosure(L, gmatch_aux, 3); return 1; } @@ -678,7 +720,8 @@ static int gmatch (lua_State *L) { static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; - const char *news = lua_tolstring(ms->L, 3, &l); + lua_State *L = ms->L; + const char *news = lua_tolstring(L, 3, &l); for (i = 0; i < l; i++) { if (news[i] != L_ESC) luaL_addchar(b, news[i]); @@ -686,14 +729,15 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) { if (news[i] != L_ESC) - luaL_error(ms->L, "invalid use of " LUA_QL("%c") - " in replacement string", L_ESC); + luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); luaL_addchar(b, news[i]); } else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { push_onecapture(ms, news[i] - '1', s, e); + luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ + lua_remove(L, -2); /* remove original value */ luaL_addvalue(b); /* add capture to accumulated result */ } } @@ -737,9 +781,9 @@ static int str_gsub (lua_State *L) { const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checklstring(L, 2, &lp); int tr = lua_type(L, 3); - size_t max_s = luaL_optinteger(L, 4, srcl+1); + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); int anchor = (*p == '^'); - size_t n = 0; + lua_Integer n = 0; MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || @@ -749,17 +793,11 @@ static int str_gsub (lua_State *L) { if (anchor) { p++; lp--; /* skip anchor character */ } - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = src; - ms.src_end = src+srcl; - ms.p_end = p + lp; + prepstate(&ms, L, src, srcl, p, lp); while (n < max_s) { const char *e; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); - e = match(&ms, src, p); - if (e) { + reprepstate(&ms); + if ((e = match(&ms, src, p)) != NULL) { n++; add_value(&ms, &b, src, e, tr); } @@ -786,48 +824,102 @@ static int str_gsub (lua_State *L) { ** ======================================================= */ +#if !defined(lua_number2strx) /* { */ + /* -** LUA_INTFRMLEN is the length modifier for integer conversions in -** 'string.format'; LUA_INTFRM_T is the integer type corresponding to -** the previous length +** Hexadecimal floating-point formatter */ -#if !defined(LUA_INTFRMLEN) /* { */ -#if defined(LUA_USE_LONGLONG) -#define LUA_INTFRMLEN "ll" -#define LUA_INTFRM_T long long +#include +#include -#else +#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) -#define LUA_INTFRMLEN "l" -#define LUA_INTFRM_T long -#endif -#endif /* } */ +/* +** Number of bits that goes into the first digit. It can be any value +** between 1 and 4; the following definition tries to align the number +** to nibble boundaries by making what is left after that first digit a +** multiple of 4. +*/ +#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) /* -** LUA_FLTFRMLEN is the length modifier for float conversions in -** 'string.format'; LUA_FLTFRM_T is the float type corresponding to -** the previous length +** Add integer part of 'x' to buffer and return new 'x' */ -#if !defined(LUA_FLTFRMLEN) +static lua_Number adddigit (char *buff, int n, lua_Number x) { + lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ + int d = (int)dd; + buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ + return x - dd; /* return what is left */ +} -#define LUA_FLTFRMLEN "" -#define LUA_FLTFRM_T double -#endif +static int num2straux (char *buff, int sz, lua_Number x) { + if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT, x); /* equal to '%g' */ + else if (x == 0) { /* can be -0... */ + /* create "0" or "-0" followed by exponent */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", x); + } + else { + int e; + lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ + int n = 0; /* character count */ + if (m < 0) { /* is number negative? */ + buff[n++] = '-'; /* add signal */ + m = -m; /* make it positive */ + } + buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ + m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ + e -= L_NBFD; /* this digit goes before the radix point */ + if (m > 0) { /* more digits? */ + buff[n++] = lua_getlocaledecpoint(); /* add radix point */ + do { /* add as many digits as needed */ + m = adddigit(buff, n++, m * 16); + } while (m > 0); + } + n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ + lua_assert(n < sz); + return n; + } +} + + +static int lua_number2strx (lua_State *L, char *buff, int sz, + const char *fmt, lua_Number x) { + int n = num2straux(buff, sz, x); + if (fmt[SIZELENMOD] == 'A') { + int i; + for (i = 0; i < n; i++) + buff[i] = toupper(uchar(buff[i])); + } + else if (fmt[SIZELENMOD] != 'a') + luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; +} + +#endif /* } */ + + +/* +** Maximum size of each formatted item. This maximum size is produced +** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', +** and '\0') + number of decimal digits to represent maxfloat (which +** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra +** expenses", such as locale-dependent stuff) +*/ +#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) -/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ -#define MAX_ITEM 512 /* valid flags in a format specification */ #define FLAGS "-+ #0" + /* -** maximum size of each format specification (such as '%-099.99d') -** (+10 accounts for %99.99x plus margin of error) +** maximum size of each format specification (such as "%-099.99d") */ -#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) +#define MAX_FORMAT 32 static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { @@ -842,9 +934,9 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { else if (*s == '\0' || iscntrl(uchar(*s))) { char buff[10]; if (!isdigit(uchar(*(s+1)))) - sprintf(buff, "\\%d", (int)uchar(*s)); + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); else - sprintf(buff, "\\%03d", (int)uchar(*s)); + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); luaL_addstring(b, buff); } else @@ -869,8 +961,8 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; - memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); - form += p - strfrmt + 1; + memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); + form += (p - strfrmt) + 1; *form = '\0'; return p; } @@ -903,7 +995,7 @@ static int str_format (lua_State *L) { else if (*++strfrmt == L_ESC) luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ - char form[MAX_FORMAT]; /* to store the format (`%...') */ + char form[MAX_FORMAT]; /* to store the format ('%...') */ char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ int nb = 0; /* number of bytes in added item */ if (++arg > top) @@ -911,36 +1003,25 @@ static int str_format (lua_State *L) { strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - nb = sprintf(buff, form, luaL_checkint(L, arg)); - break; - } - case 'd': case 'i': { - lua_Number n = luaL_checknumber(L, arg); - LUA_INTFRM_T ni = (LUA_INTFRM_T)n; - lua_Number diff = n - (lua_Number)ni; - luaL_argcheck(L, -1 < diff && diff < 1, arg, - "not a number in proper range"); - addlenmod(form, LUA_INTFRMLEN); - nb = sprintf(buff, form, ni); + nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); break; } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { - lua_Number n = luaL_checknumber(L, arg); - unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; - lua_Number diff = n - (lua_Number)ni; - luaL_argcheck(L, -1 < diff && diff < 1, arg, - "not a non-negative number in proper range"); - addlenmod(form, LUA_INTFRMLEN); - nb = sprintf(buff, form, ni); + lua_Integer n = luaL_checkinteger(L, arg); + addlenmod(form, LUA_INTEGER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, n); break; } - case 'e': case 'E': case 'f': -#if defined(LUA_USE_AFORMAT) case 'a': case 'A': -#endif + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, MAX_ITEM, form, + luaL_checknumber(L, arg)); + break; + case 'e': case 'E': case 'f': case 'g': case 'G': { - addlenmod(form, LUA_FLTFRMLEN); - nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg)); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, luaL_checknumber(L, arg)); break; } case 'q': { @@ -950,23 +1031,27 @@ static int str_format (lua_State *L) { case 's': { size_t l; const char *s = luaL_tolstring(L, arg, &l); - if (!strchr(form, '.') && l >= 100) { - /* no precision and string is too long to be formatted; - keep original string */ - luaL_addvalue(&b); - break; - } + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ else { - nb = sprintf(buff, form, s); - lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ - break; + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + if (!strchr(form, '.') && l >= 100) { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else { /* format the string into 'buff' */ + nb = l_sprintf(buff, MAX_ITEM, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } } + break; } - default: { /* also treat cases `pnLlh' */ - return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " - LUA_QL("format"), *(strfrmt - 1)); + default: { /* also treat cases 'pnLlh' */ + return luaL_error(L, "invalid option '%%%c' to 'format'", + *(strfrmt - 1)); } } + lua_assert(nb < MAX_ITEM); luaL_addsize(&b, nb); } } @@ -977,6 +1062,452 @@ static int str_format (lua_State *L) { /* }====================================================== */ +/* +** {====================================================== +** PACK/UNPACK +** ======================================================= +*/ + + +/* value used for padding */ +#if !defined(LUA_PACKPADBYTE) +#define LUA_PACKPADBYTE 0x00 +#endif + +/* maximum size for the binary representation of an integer */ +#define MAXINTSIZE 16 + +/* number of bits in a character */ +#define NB CHAR_BIT + +/* mask for one character (NB 1's) */ +#define MC ((1 << NB) - 1) + +/* size of a lua_Integer */ +#define SZINT ((int)sizeof(lua_Integer)) + + +/* dummy union to get native endianness */ +static const union { + int dummy; + char little; /* true iff machine is little endian */ +} nativeendian = {1}; + + +/* dummy structure to get native alignment requirements */ +struct cD { + char c; + union { double d; void *p; lua_Integer i; lua_Number n; } u; +}; + +#define MAXALIGN (offsetof(struct cD, u)) + + +/* +** Union for serializing floats +*/ +typedef union Ftypes { + float f; + double d; + lua_Number n; + char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ +} Ftypes; + + +/* +** information to pack/unpack stuff +*/ +typedef struct Header { + lua_State *L; + int islittle; + int maxalign; +} Header; + + +/* +** options for pack/unpack +*/ +typedef enum KOption { + Kint, /* signed integers */ + Kuint, /* unsigned integers */ + Kfloat, /* floating-point numbers */ + Kchar, /* fixed-length strings */ + Kstring, /* strings with prefixed length */ + Kzstr, /* zero-terminated strings */ + Kpadding, /* padding */ + Kpaddalign, /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ +} KOption; + + +/* +** Read an integer numeral from string 'fmt' or return 'df' if +** there is no numeral +*/ +static int digit (int c) { return '0' <= c && c <= '9'; } + +static int getnum (const char **fmt, int df) { + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + (*((*fmt)++) - '0'); + } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); + return a; + } +} + + +/* +** Read an integer numeral and raises an error if it is larger +** than the maximum size for integers. +*/ +static int getnumlimit (Header *h, const char **fmt, int df) { + int sz = getnum(fmt, df); + if (sz > MAXINTSIZE || sz <= 0) + luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; +} + + +/* +** Initialize Header +*/ +static void initheader (lua_State *L, Header *h) { + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; +} + + +/* +** Read and classify next option. 'size' is filled with option's size. +*/ +static KOption getoption (Header *h, const char **fmt, int *size) { + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) { + case 'b': *size = sizeof(char); return Kint; + case 'B': *size = sizeof(char); return Kuint; + case 'h': *size = sizeof(short); return Kint; + case 'H': *size = sizeof(short); return Kuint; + case 'l': *size = sizeof(long); return Kint; + case 'L': *size = sizeof(long); return Kuint; + case 'j': *size = sizeof(lua_Integer); return Kint; + case 'J': *size = sizeof(lua_Integer); return Kuint; + case 'T': *size = sizeof(size_t); return Kuint; + case 'f': *size = sizeof(float); return Kfloat; + case 'd': *size = sizeof(double); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Kfloat; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (*size == -1) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; break; + case '>': h->islittle = 0; break; + case '=': h->islittle = nativeendian.little; break; + case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; +} + + +/* +** Read, classify, and fill other details about the next option. +** 'psize' is filled with option's size, 'notoalign' with its +** alignment requirements. +** Local variable 'size' gets the size to be aligned. (Kpadal option +** always gets its full alignment, other options are limited by +** the maximum alignment ('maxalign'). Kchar option needs no alignment +** despite its size. +*/ +static KOption getdetails (Header *h, size_t totalsize, + const char **fmt, int *psize, int *ntoalign) { + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; +} + + +/* +** Pack integer 'n' with 'size' bytes and 'islittle' endianness. +** The final 'if' handles the case when 'size' is larger than +** the size of a Lua integer, correcting the extra sign-extension +** bytes if necessary (by default they would be zeros). +*/ +static void packint (luaL_Buffer *b, lua_Unsigned n, + int islittle, int size, int neg) { + char *buff = luaL_prepbuffsize(b, size); + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) { /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + luaL_addsize(b, size); /* add result to buffer */ +} + + +/* +** Copy 'size' bytes from 'src' to 'dest', correcting endianness if +** given 'islittle' is different from native endianness. +*/ +static void copywithendian (volatile char *dest, volatile const char *src, + int size, int islittle) { + if (islittle == nativeendian.little) { + while (size-- != 0) + *(dest++) = *(src++); + } + else { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } +} + + +static int str_pack (lua_State *L) { + luaL_Buffer b; + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + int arg = 1; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) { + case Kint: { /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) { /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: { /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(&b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: { /* floating-point options */ + volatile Ftypes u; + char *buff = luaL_prepbuffsize(&b, size); + lua_Number n = luaL_checknumber(L, arg); /* get argument */ + if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ + else if (size == sizeof(u.d)) u.d = (double)n; + else u.n = n; + /* move 'u' to final result, correcting endianness if needed */ + copywithendian(buff, u.buff, size, h.islittle); + luaL_addsize(&b, size); + break; + } + case Kchar: { /* fixed-size string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + if ((size_t)size <= len) /* string larger than (or equal to) needed? */ + luaL_addlstring(&b, s, size); /* truncate string to asked size */ + else { /* string smaller than needed */ + luaL_addlstring(&b, s, len); /* add it all */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUA_PACKPADBYTE); + } + break; + } + case Kstring: { /* strings with length count */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + luaL_addlstring(&b, s, len); + totalsize += len; + break; + } + case Kzstr: { /* zero-terminated string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + luaL_addlstring(&b, s, len); + luaL_addchar(&b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: case Knop: + arg--; /* undo increment */ + break; + } + } + luaL_pushresult(&b); + return 1; +} + + +static int str_packsize (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + switch (opt) { + case Kstring: /* strings with length count */ + case Kzstr: /* zero-terminated string */ + luaL_argerror(L, 1, "variable-length format"); + /* call never return, but to avoid warnings: *//* FALLTHROUGH */ + default: break; + } + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; +} + + +/* +** Unpack an integer with 'size' bytes and 'islittle' endianness. +** If size is smaller than the size of a Lua integer and integer +** is signed, must do sign extension (propagating the sign to the +** higher bits); if size is larger than the size of a Lua integer, +** it must check the unread bytes to see whether they do not cause an +** overflow. +*/ +static lua_Integer unpackint (lua_State *L, const char *str, + int islittle, int size, int issigned) { + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) { /* real size smaller than lua_Integer? */ + if (issigned) { /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) { /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) { + if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; +} + + +static int str_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) + luaL_argerror(L, 2, "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) { + case Kint: + case Kuint: { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: { + volatile Ftypes u; + lua_Number num; + copywithendian(u.buff, data + pos, size, h.islittle); + if (size == sizeof(u.f)) num = (lua_Number)u.f; + else if (size == sizeof(u.d)) num = (lua_Number)u.d; + else num = u.n; + lua_pushnumber(L, num); + break; + } + case Kchar: { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: { + size_t len = (int)strlen(data + pos); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: case Kpadding: case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + +/* }====================================================== */ + + static const luaL_Reg strlib[] = { {"byte", str_byte}, {"char", str_char}, @@ -992,6 +1523,9 @@ static const luaL_Reg strlib[] = { {"reverse", str_reverse}, {"sub", str_sub}, {"upper", str_upper}, + {"pack", str_pack}, + {"packsize", str_packsize}, + {"unpack", str_unpack}, {NULL, NULL} }; diff --git a/deps/lua/ltable.c b/deps/lua/ltable.c index 5d76f97..7e15b71 100644 --- a/deps/lua/ltable.c +++ b/deps/lua/ltable.c @@ -1,27 +1,30 @@ /* -** $Id: ltable.c,v 2.72.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ltable.c,v 2.117 2015/11/19 19:16:22 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ +#define ltable_c +#define LUA_CORE + +#include "lprefix.h" + /* ** Implementation of tables (aka arrays, objects, or hash tables). ** Tables keep its elements in two parts: an array part and a hash part. ** Non-negative integer keys are all candidates to be kept in the array -** part. The actual size of the array is the largest `n' such that at -** least half the slots between 0 and n are in use. +** part. The actual size of the array is the largest 'n' such that +** more than half the slots between 1 and n are in use. ** Hash uses a mix of chained scatter table with Brent's variation. ** A main invariant of these tables is that, if an element is not -** in its main position (i.e. the `original' position that its hash gives +** in its main position (i.e. the 'original' position that its hash gives ** to it), then the colliding element is in its own main position. ** Hence even when the load factor reaches 100%, performance remains good. */ -#include - -#define ltable_c -#define LUA_CORE +#include +#include #include "lua.h" @@ -37,21 +40,26 @@ /* -** max size of array part is 2^MAXBITS +** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is +** the largest integer such that MAXASIZE fits in an unsigned int. */ -#if LUAI_BITSINT >= 32 -#define MAXBITS 30 -#else -#define MAXBITS (LUAI_BITSINT-2) -#endif +#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) +#define MAXASIZE (1u << MAXABITS) -#define MAXASIZE (1 << MAXBITS) +/* +** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest +** integer such that 2^MAXHBITS fits in a signed int. (Note that the +** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still +** fits comfortably in an unsigned int.) +*/ +#define MAXHBITS (MAXABITS - 1) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) -#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#define hashstr(t,str) hashpow2(t, (str)->hash) #define hashboolean(t,p) hashpow2(t, p) +#define hashint(t,i) hashpow2(t, i) /* @@ -61,7 +69,7 @@ #define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) -#define hashpointer(t,p) hashmod(t, IntPoint(p)) +#define hashpointer(t,p) hashmod(t, point2uint(p)) #define dummynode (&dummynode_) @@ -70,44 +78,54 @@ static const Node dummynode_ = { {NILCONSTANT}, /* value */ - {{NILCONSTANT, NULL}} /* key */ + {{NILCONSTANT, 0}} /* key */ }; /* -** hash for lua_Numbers +** Hash for floating-point numbers. +** The main computation should be just +** n = frexp(n, &i); return (n * INT_MAX) + i +** but there are some numerical subtleties. +** In a two-complement representation, INT_MAX does not has an exact +** representation as a float, but INT_MIN does; because the absolute +** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the +** absolute value of the product 'frexp * -INT_MIN' is smaller or equal +** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when +** adding 'i'; the use of '~u' (instead of '-u') avoids problems with +** INT_MIN. */ -static Node *hashnum (const Table *t, lua_Number n) { +#if !defined(l_hashfloat) +static int l_hashfloat (lua_Number n) { int i; - luai_hashnum(i, n); - if (i < 0) { - if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */ - i = 0; /* handle INT_MIN */ - i = -i; /* must be a positive value */ + lua_Integer ni; + n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); + if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ + lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); + return 0; + } + else { /* normal case */ + unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); + return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u); } - return hashmod(t, i); } - +#endif /* -** returns the `main' position of an element in a table (that is, the index +** returns the 'main' position of an element in a table (that is, the index ** of its hash value) */ static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TNUMBER: - return hashnum(t, nvalue(key)); - case LUA_TLNGSTR: { - TString *s = rawtsvalue(key); - if (s->tsv.extra == 0) { /* no hash? */ - s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash); - s->tsv.extra = 1; /* now it has its hash */ - } - return hashstr(t, rawtsvalue(key)); - } + case LUA_TNUMINT: + return hashint(t, ivalue(key)); + case LUA_TNUMFLT: + return hashmod(t, l_hashfloat(fltvalue(key))); case LUA_TSHRSTR: - return hashstr(t, rawtsvalue(key)); + return hashstr(t, tsvalue(key)); + case LUA_TLNGSTR: + return hashpow2(t, luaS_hashlongstr(tsvalue(key))); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: @@ -115,67 +133,68 @@ static Node *mainposition (const Table *t, const TValue *key) { case LUA_TLCF: return hashpointer(t, fvalue(key)); default: + lua_assert(!ttisdeadkey(key)); return hashpointer(t, gcvalue(key)); } } /* -** returns the index for `key' if `key' is an appropriate key to live in -** the array part of the table, -1 otherwise. +** returns the index for 'key' if 'key' is an appropriate key to live in +** the array part of the table, 0 otherwise. */ -static int arrayindex (const TValue *key) { - if (ttisnumber(key)) { - lua_Number n = nvalue(key); - int k; - lua_number2int(k, n); - if (luai_numeq(cast_num(k), n)) - return k; +static unsigned int arrayindex (const TValue *key) { + if (ttisinteger(key)) { + lua_Integer k = ivalue(key); + if (0 < k && (lua_Unsigned)k <= MAXASIZE) + return cast(unsigned int, k); /* 'key' is an appropriate array index */ } - return -1; /* `key' did not match some condition */ + return 0; /* 'key' did not match some condition */ } /* -** returns the index of a `key' for table traversals. First goes all +** returns the index of a 'key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The -** beginning of a traversal is signaled by -1. +** beginning of a traversal is signaled by 0. */ -static int findindex (lua_State *L, Table *t, StkId key) { - int i; - if (ttisnil(key)) return -1; /* first iteration */ +static unsigned int findindex (lua_State *L, Table *t, StkId key) { + unsigned int i; + if (ttisnil(key)) return 0; /* first iteration */ i = arrayindex(key); - if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ - return i-1; /* yes; that's the index (corrected to C) */ + if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ + return i; /* yes; that's the index */ else { + int nx; Node *n = mainposition(t, key); - for (;;) { /* check whether `key' is somewhere in the chain */ - /* key may be dead already, but it is ok to use it in `next' */ + for (;;) { /* check whether 'key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in 'next' */ if (luaV_rawequalobj(gkey(n), key) || (ttisdeadkey(gkey(n)) && iscollectable(key) && deadvalue(gkey(n)) == gcvalue(key))) { i = cast_int(n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ - return i + t->sizearray; + return (i + 1) + t->sizearray; } - else n = gnext(n); - if (n == NULL) - luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ + nx = gnext(n); + if (nx == 0) + luaG_runerror(L, "invalid key to 'next'"); /* key not found */ + else n += nx; } } } int luaH_next (lua_State *L, Table *t, StkId key) { - int i = findindex(L, t, key); /* find original element */ - for (i++; i < t->sizearray; i++) { /* try first array part */ + unsigned int i = findindex(L, t, key); /* find original element */ + for (; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setnvalue(key, cast_num(i+1)); + setivalue(key, i + 1); setobj2s(L, key+1, &t->array[i]); return 1; } } - for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ + for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ setobj2s(L, key, gkey(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); @@ -192,32 +211,38 @@ int luaH_next (lua_State *L, Table *t, StkId key) { ** ============================================================== */ - -static int computesizes (int nums[], int *narray) { +/* +** Compute the optimal size for the array part of table 't'. 'nums' is a +** "count array" where 'nums[i]' is the number of integers in the table +** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of +** integer keys in the table and leaves with the number of keys that +** will go to the array part; return the optimal size. +*/ +static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { int i; - int twotoi; /* 2^i */ - int a = 0; /* number of elements smaller than 2^i */ - int na = 0; /* number of elements to go to array part */ - int n = 0; /* optimal size for array part */ - for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { + unsigned int twotoi; /* 2^i (candidate for optimal size) */ + unsigned int a = 0; /* number of elements smaller than 2^i */ + unsigned int na = 0; /* number of elements to go to array part */ + unsigned int optimal = 0; /* optimal size for array part */ + /* loop while keys can fill more than half of total size */ + for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) { if (nums[i] > 0) { a += nums[i]; if (a > twotoi/2) { /* more than half elements present? */ - n = twotoi; /* optimal size (till now) */ - na = a; /* all elements smaller than n will go to array part */ + optimal = twotoi; /* optimal size (till now) */ + na = a; /* all elements up to 'optimal' will go to array part */ } } - if (a == *narray) break; /* all elements already counted */ } - *narray = n; - lua_assert(*narray/2 <= na && na <= *narray); - return na; + lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); + *pna = na; + return optimal; } -static int countint (const TValue *key, int *nums) { - int k = arrayindex(key); - if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ +static int countint (const TValue *key, unsigned int *nums) { + unsigned int k = arrayindex(key); + if (k != 0) { /* is 'key' an appropriate array index? */ nums[luaO_ceillog2(k)]++; /* count as such */ return 1; } @@ -226,20 +251,26 @@ static int countint (const TValue *key, int *nums) { } -static int numusearray (const Table *t, int *nums) { +/* +** Count keys in array part of table 't': Fill 'nums[i]' with +** number of keys that will go into corresponding slice and return +** total number of non-nil keys. +*/ +static unsigned int numusearray (const Table *t, unsigned int *nums) { int lg; - int ttlg; /* 2^lg */ - int ause = 0; /* summation of `nums' */ - int i = 1; /* count to traverse all array keys */ - for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ - int lc = 0; /* counter */ - int lim = ttlg; + unsigned int ttlg; /* 2^lg */ + unsigned int ause = 0; /* summation of 'nums' */ + unsigned int i = 1; /* count to traverse all array keys */ + /* traverse each slice */ + for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { + unsigned int lc = 0; /* counter */ + unsigned int lim = ttlg; if (lim > t->sizearray) { lim = t->sizearray; /* adjust upper limit */ if (i > lim) break; /* no more elements to count */ } - /* count elements in range (2^(lg-1), 2^lg] */ + /* count elements in range (2^(lg - 1), 2^lg] */ for (; i <= lim; i++) { if (!ttisnil(&t->array[i-1])) lc++; @@ -251,9 +282,9 @@ static int numusearray (const Table *t, int *nums) { } -static int numusehash (const Table *t, int *nums, int *pnasize) { +static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { int totaluse = 0; /* total number of elements */ - int ause = 0; /* summation of `nums' */ + int ause = 0; /* elements added to 'nums' (can go to array part) */ int i = sizenode(t); while (i--) { Node *n = &t->node[i]; @@ -262,13 +293,13 @@ static int numusehash (const Table *t, int *nums, int *pnasize) { totaluse++; } } - *pnasize += ause; + *pna += ause; return totaluse; } -static void setarrayvector (lua_State *L, Table *t, int size) { - int i; +static void setarrayvector (lua_State *L, Table *t, unsigned int size) { + unsigned int i; luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; iarray[i]); @@ -276,23 +307,23 @@ static void setarrayvector (lua_State *L, Table *t, int size) { } -static void setnodevector (lua_State *L, Table *t, int size) { +static void setnodevector (lua_State *L, Table *t, unsigned int size) { int lsize; if (size == 0) { /* no elements to hash part? */ - t->node = cast(Node *, dummynode); /* use common `dummynode' */ + t->node = cast(Node *, dummynode); /* use common 'dummynode' */ lsize = 0; } else { int i; lsize = luaO_ceillog2(size); - if (lsize > MAXBITS) + if (lsize > MAXHBITS) luaG_runerror(L, "table overflow"); size = twoto(lsize); t->node = luaM_newvector(L, size, Node); - for (i=0; isizearray; +void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize) { + unsigned int i; + int j; + unsigned int oldasize = t->sizearray; int oldhsize = t->lsizenode; Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ @@ -321,8 +354,8 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } /* re-insert elements from hash part */ - for (i = twoto(oldhsize) - 1; i >= 0; i--) { - Node *old = nold+i; + for (j = twoto(oldhsize) - 1; j >= 0; j--) { + Node *old = nold + j; if (!ttisnil(gval(old))) { /* doesn't need barrier/invalidate cache, as entry was already present in the table */ @@ -330,32 +363,35 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { } } if (!isdummy(nold)) - luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */ + luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old hash */ } -void luaH_resizearray (lua_State *L, Table *t, int nasize) { +void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { int nsize = isdummy(t->node) ? 0 : sizenode(t); luaH_resize(L, t, nasize, nsize); } - +/* +** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i +*/ static void rehash (lua_State *L, Table *t, const TValue *ek) { - int nasize, na; - int nums[MAXBITS+1]; /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */ + unsigned int asize; /* optimal size for array part */ + unsigned int na; /* number of keys in the array part */ + unsigned int nums[MAXABITS + 1]; int i; int totaluse; - for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ - nasize = numusearray(t, nums); /* count keys in array part */ - totaluse = nasize; /* all those keys are integer keys */ - totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ + for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ + na = numusearray(t, nums); /* count keys in array part */ + totaluse = na; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &na); /* count keys in hash part */ /* count extra key */ - nasize += countint(ek, nums); + na += countint(ek, nums); totaluse++; /* compute new size for array part */ - na = computesizes(nums, &nasize); + asize = computesizes(nums, &na); /* resize the table to new computed sizes */ - luaH_resize(L, t, nasize, totaluse - na); + luaH_resize(L, t, asize, totaluse - na); } @@ -366,7 +402,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) { Table *luaH_new (lua_State *L) { - Table *t = &luaC_newobj(L, LUA_TTABLE, sizeof(Table), NULL, 0)->h; + GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); + Table *t = gco2t(o); t->metatable = NULL; t->flags = cast_byte(~0); t->array = NULL; @@ -404,37 +441,51 @@ static Node *getfreepos (Table *t) { */ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { Node *mp; + TValue aux; if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && luai_numisnan(L, nvalue(key))) - luaG_runerror(L, "table index is NaN"); + else if (ttisfloat(key)) { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) { /* index is int? */ + setivalue(&aux, k); + key = &aux; /* insert it as an integer */ + } + else if (luai_numisnan(fltvalue(key))) + luaG_runerror(L, "table index is NaN"); + } mp = mainposition(t, key); if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ Node *othern; - Node *n = getfreepos(t); /* get a free place */ - if (n == NULL) { /* cannot find a free place? */ + Node *f = getfreepos(t); /* get a free place */ + if (f == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ - /* whatever called 'newkey' take care of TM cache and GC barrier */ + /* whatever called 'newkey' takes care of TM cache */ return luaH_set(L, t, key); /* insert key into grown table */ } - lua_assert(!isdummy(n)); + lua_assert(!isdummy(f)); othern = mainposition(t, gkey(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ - while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ - gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ - *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - gnext(mp) = NULL; /* now `mp' is free */ + while (othern + gnext(othern) != mp) /* find previous */ + othern += gnext(othern); + gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ + *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + if (gnext(mp) != 0) { + gnext(f) += cast_int(mp - f); /* correct 'next' */ + gnext(mp) = 0; /* now 'mp' is free */ + } setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ - gnext(n) = gnext(mp); /* chain new position */ - gnext(mp) = n; - mp = n; + if (gnext(mp) != 0) + gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ + else lua_assert(gnext(f) == 0); + gnext(mp) = cast_int(f - mp); + mp = f; } } - setobj2t(L, gkey(mp), key); - luaC_barrierback(L, obj2gco(t), key); + setnodekey(L, &mp->i_key, key); + luaC_barrierback(L, t, key); lua_assert(ttisnil(gval(mp))); return gval(mp); } @@ -443,18 +494,21 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { /* ** search function for integers */ -const TValue *luaH_getint (Table *t, int key) { +const TValue *luaH_getint (Table *t, lua_Integer key) { /* (1 <= key && key <= t->sizearray) */ - if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) - return &t->array[key-1]; + if (l_castS2U(key) - 1 < t->sizearray) + return &t->array[key - 1]; else { - lua_Number nk = cast_num(key); - Node *n = hashnum(t, nk); - do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) + Node *n = hashint(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) return gval(n); /* that's it */ - else n = gnext(n); - } while (n); + else { + int nx = gnext(n); + if (nx == 0) break; + n += nx; + } + } return luaO_nilobject; } } @@ -463,15 +517,50 @@ const TValue *luaH_getint (Table *t, int key) { /* ** search function for short strings */ -const TValue *luaH_getstr (Table *t, TString *key) { +const TValue *luaH_getshortstr (Table *t, TString *key) { Node *n = hashstr(t, key); - lua_assert(key->tsv.tt == LUA_TSHRSTR); - do { /* check whether `key' is somewhere in the chain */ - if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key)) + lua_assert(key->tt == LUA_TSHRSTR); + for (;;) { /* check whether 'key' is somewhere in the chain */ + const TValue *k = gkey(n); + if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } +} + + +/* +** "Generic" get version. (Not that generic: not valid for integers, +** which may be in array part, nor for floats with integral values.) +*/ +static const TValue *getgeneric (Table *t, const TValue *key) { + Node *n = mainposition(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (luaV_rawequalobj(gkey(n), key)) return gval(n); /* that's it */ - else n = gnext(n); - } while (n); - return luaO_nilobject; + else { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } +} + + +const TValue *luaH_getstr (Table *t, TString *key) { + if (key->tt == LUA_TSHRSTR) + return luaH_getshortstr(t, key); + else { /* for long strings, use generic case */ + TValue ko; + setsvalue(cast(lua_State *, NULL), &ko, key); + return getgeneric(t, &ko); + } } @@ -480,25 +569,17 @@ const TValue *luaH_getstr (Table *t, TString *key) { */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key)); + case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); + case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); case LUA_TNIL: return luaO_nilobject; - case LUA_TNUMBER: { - int k; - lua_Number n = nvalue(key); - lua_number2int(k, n); - if (luai_numeq(cast_num(k), n)) /* index is int? */ + case LUA_TNUMFLT: { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) /* index is int? */ return luaH_getint(t, k); /* use specialized version */ - /* else go through */ - } - default: { - Node *n = mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (luaV_rawequalobj(gkey(n), key)) - return gval(n); /* that's it */ - else n = gnext(n); - } while (n); - return luaO_nilobject; - } + /* else... */ + } /* FALLTHROUGH */ + default: + return getgeneric(t, key); } } @@ -515,14 +596,14 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { } -void luaH_setint (lua_State *L, Table *t, int key, TValue *value) { +void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { const TValue *p = luaH_getint(t, key); TValue *cell; if (p != luaO_nilobject) cell = cast(TValue *, p); else { TValue k; - setnvalue(&k, cast_num(key)); + setivalue(&k, key); cell = luaH_newkey(L, t, &k); } setobj2t(L, cell, value); @@ -532,16 +613,16 @@ void luaH_setint (lua_State *L, Table *t, int key, TValue *value) { static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j++; - /* find `i' and `j' such that i is present and j is not */ + /* find 'i' and 'j' such that i is present and j is not */ while (!ttisnil(luaH_getint(t, j))) { i = j; - j *= 2; - if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ + if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; while (!ttisnil(luaH_getint(t, i))) i++; return i - 1; } + j *= 2; } /* now do a binary search between them */ while (j - i > 1) { @@ -554,7 +635,7 @@ static int unbound_search (Table *t, unsigned int j) { /* -** Try to find a boundary in table `t'. A `boundary' is an integer index +** Try to find a boundary in table 't'. A 'boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ int luaH_getn (Table *t) { diff --git a/deps/lua/ltable.h b/deps/lua/ltable.h index d69449b..213cc13 100644 --- a/deps/lua/ltable.h +++ b/deps/lua/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.16.1.2 2013/08/30 15:49:41 roberto Exp $ +** $Id: ltable.h,v 2.21 2015/11/03 15:47:30 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -11,26 +11,39 @@ #define gnode(t,i) (&(t)->node[i]) -#define gkey(n) (&(n)->i_key.tvk) #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) + +/* 'const' to avoid wrong writings that can mess up field 'next' */ +#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) + +/* +** writable version of 'gkey'; allows updates to individual fields, +** but not to the whole (which has incompatible type) +*/ +#define wgkey(n) (&(n)->i_key.nk) + #define invalidateTMcache(t) ((t)->flags = 0) + /* returns the key, given the value of a table entry */ #define keyfromval(v) \ (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) -LUAI_FUNC const TValue *luaH_getint (Table *t, int key); -LUAI_FUNC void luaH_setint (lua_State *L, Table *t, int key, TValue *value); +LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); +LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, + TValue *value); +LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); LUAI_FUNC Table *luaH_new (lua_State *L); -LUAI_FUNC void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize); -LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); +LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); LUAI_FUNC int luaH_getn (Table *t); diff --git a/deps/lua/ltablib.c b/deps/lua/ltablib.c index 6001224..b3c9a7c 100644 --- a/deps/lua/ltablib.c +++ b/deps/lua/ltablib.c @@ -1,23 +1,61 @@ /* -** $Id: ltablib.c,v 1.65.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ltablib.c,v 1.90 2015/11/25 12:48:57 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ - -#include - #define ltablib_c #define LUA_LIB +#include "lprefix.h" + + +#include +#include +#include + #include "lua.h" #include "lauxlib.h" #include "lualib.h" -#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) +/* +** Operations that an object must define to mimic a table +** (some functions only need some of them) +*/ +#define TAB_R 1 /* read */ +#define TAB_W 2 /* write */ +#define TAB_L 4 /* length */ +#define TAB_RW (TAB_R | TAB_W) /* read/write */ + +#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) + + +static int checkfield (lua_State *L, const char *key, int n) { + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); +} + + +/* +** Check that 'arg' either is a table or can behave like one (that is, +** has a metatable with the required metamethods) +*/ +static void checktab (lua_State *L, int arg, int what) { + if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ + int n = 1; /* number of elements to pop */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { + lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + luaL_argerror(L, arg, "table expected"); /* force an error */ + } +} #if defined(LUA_COMPAT_MAXN) @@ -39,65 +77,102 @@ static int maxn (lua_State *L) { static int tinsert (lua_State *L) { - int e = aux_getn(L, 1) + 1; /* first empty element */ - int pos; /* where to insert new element */ + lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ + lua_Integer pos; /* where to insert new element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ break; } case 3: { - int i; - pos = luaL_checkint(L, 2); /* 2nd argument is the position */ + lua_Integer i; + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); for (i = e; i > pos; i--) { /* move up elements */ - lua_rawgeti(L, 1, i-1); - lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ } break; } default: { - return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); + return luaL_error(L, "wrong number of arguments to 'insert'"); } } - lua_rawseti(L, 1, pos); /* t[pos] = v */ + lua_seti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { - int size = aux_getn(L, 1); - int pos = luaL_optint(L, 2, size); + lua_Integer size = aux_getn(L, 1, TAB_RW); + lua_Integer pos = luaL_optinteger(L, 2, size); if (pos != size) /* validate 'pos' if given */ luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); - lua_rawgeti(L, 1, pos); /* result = t[pos] */ + lua_geti(L, 1, pos); /* result = t[pos] */ for ( ; pos < size; pos++) { - lua_rawgeti(L, 1, pos+1); - lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */ + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ } lua_pushnil(L); - lua_rawseti(L, 1, pos); /* t[pos] = nil */ + lua_seti(L, 1, pos); /* t[pos] = nil */ return 1; } -static void addfield (lua_State *L, luaL_Buffer *b, int i) { - lua_rawgeti(L, 1, i); +/* +** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever +** possible, copy in increasing order, which is better for rehashing. +** "possible" means destination after original range, or smaller +** than origin, or copying to another table. +*/ +static int tmove (lua_State *L) { + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) { /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || tt != 1) { + for (i = 0; i < n; i++) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + else { + for (i = n - 1; i >= 0; i--) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + } + lua_pushvalue(L, tt); /* return "to table" */ + return 1; +} + + +static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { + lua_geti(L, 1, i); if (!lua_isstring(L, -1)) - luaL_error(L, "invalid value (%s) at index %d in table for " - LUA_QL("concat"), luaL_typename(L, -1), i); + luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", + luaL_typename(L, -1), i); luaL_addvalue(b); } static int tconcat (lua_State *L) { luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); size_t lsep; - int i, last; const char *sep = luaL_optlstring(L, 2, "", &lsep); - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 3, 1); - last = luaL_opt(L, luaL_checkint, 4, luaL_len(L, 1)); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_opt(L, luaL_checkinteger, 4, last); luaL_buffinit(L, &b); for (; i < last; i++) { addfield(L, &b, i); @@ -117,35 +192,31 @@ static int tconcat (lua_State *L) { */ static int pack (lua_State *L) { + int i; int n = lua_gettop(L); /* number of elements to pack */ lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ + for (i = n; i >= 1; i--) /* assign elements */ + lua_seti(L, 1, i); lua_pushinteger(L, n); - lua_setfield(L, -2, "n"); /* t.n = number of elements */ - if (n > 0) { /* at least one element? */ - int i; - lua_pushvalue(L, 1); - lua_rawseti(L, -2, 1); /* insert first element */ - lua_replace(L, 1); /* move table into index 1 */ - for (i = n; i >= 2; i--) /* assign other elements */ - lua_rawseti(L, 1, i); - } + lua_setfield(L, 1, "n"); /* t.n = number of elements */ return 1; /* return table */ } static int unpack (lua_State *L) { - int i, e, n; - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 2, 1); - e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1)); + lua_Unsigned n; + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ - n = e - i + 1; /* number of elements */ - if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ + n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ + if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) return luaL_error(L, "too many results to unpack"); - lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ - while (i++ < e) /* push arg[i + 1...e] */ - lua_rawgeti(L, 1, i); - return n; + for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ + return (int)n; } /* }====================================================== */ @@ -155,102 +226,196 @@ static int unpack (lua_State *L) { /* ** {====================================================== ** Quicksort -** (based on `Algorithms in MODULA-3', Robert Sedgewick; +** (based on 'Algorithms in MODULA-3', Robert Sedgewick; ** Addison-Wesley, 1993.) ** ======================================================= */ -static void set2 (lua_State *L, int i, int j) { - lua_rawseti(L, 1, i); - lua_rawseti(L, 1, j); +/* +** Produce a "random" 'unsigned int' to randomize pivot choice. This +** macro is used only when 'sort' detects a big imbalance in the result +** of a partition. (If you don't want/need this "randomness", ~0 is a +** good choice.) +*/ +#if !defined(l_randomizePivot) /* { */ + +#include + +/* size of 'e' measured in number of 'unsigned int's */ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + +/* +** Use 'time' and 'clock' as sources of "randomness". Because we don't +** know the types 'clock_t' and 'time_t', we cannot cast them to +** anything without risking overflows. A safe way to use their values +** is to copy them to an array of a known type and use the array values. +*/ +static unsigned int l_randomizePivot (void) { + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; } +#endif /* } */ + + +/* arrays larger than 'RANLIMIT' may use randomized pivots */ +#define RANLIMIT 100u + + +static void set2 (lua_State *L, unsigned int i, unsigned int j) { + lua_seti(L, 1, i); + lua_seti(L, 1, j); +} + + +/* +** Return true iff value at stack index 'a' is less than the value at +** index 'b' (according to the order of the sort). +*/ static int sort_comp (lua_State *L, int a, int b) { - if (!lua_isnil(L, 2)) { /* function? */ + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else { /* function */ int res; - lua_pushvalue(L, 2); + lua_pushvalue(L, 2); /* push function */ lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ - lua_call(L, 2, 1); - res = lua_toboolean(L, -1); - lua_pop(L, 1); + lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ return res; } - else /* a < b? */ - return lua_compare(L, a, b, LUA_OPLT); } -static void auxsort (lua_State *L, int l, int u) { - while (l < u) { /* for tail recursion */ - int i, j; - /* sort elements a[l], a[(l+u)/2] and a[u] */ - lua_rawgeti(L, 1, l); - lua_rawgeti(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ - set2(L, l, u); /* swap a[l] - a[u] */ + +/* +** Does the partition: Pivot P is at the top of the stack. +** precondition: a[lo] <= P == a[up-1] <= a[up], +** so it only needs to do the partition from lo + 1 to up - 2. +** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] +** returns 'i'. +*/ +static unsigned int partition (lua_State *L, unsigned int lo, + unsigned int up) { + unsigned int i = lo; /* will be incremented before first use */ + unsigned int j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) { + /* next loop: repeat ++i while a[i] < P */ + while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j < i) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) { /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } +} + + +/* +** Choose an element in the middle (2nd-3th quarters) of [lo,up] +** "randomized" by 'rnd' +*/ +static unsigned int choosePivot (unsigned int lo, unsigned int up, + unsigned int rnd) { + unsigned int r4 = (unsigned int)(up - lo) / 4u; /* range/4 */ + unsigned int p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; +} + + +/* +** QuickSort algorithm (recursive function) +*/ +static void auxsort (lua_State *L, unsigned int lo, unsigned int up, + unsigned int rnd) { + while (lo < up) { /* loop for tail recursion */ + unsigned int p; /* Pivot index */ + unsigned int n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ else - lua_pop(L, 2); - if (u-l == 1) break; /* only 2 elements */ - i = (l+u)/2; - lua_rawgeti(L, 1, i); - lua_rawgeti(L, 1, l); - if (sort_comp(L, -2, -1)) /* a[i]= P */ - while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i>=u) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* repeat --j until a[j] <= P */ - while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j<=l) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[j] */ - } - if (j n) /* partition too imbalanced? */ + rnd = l_randomizePivot(); /* try a new randomization */ + } /* tail call auxsort(L, lo, up, rnd) */ } + static int sort (lua_State *L) { - int n = aux_getn(L, 1); - luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ - if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_settop(L, 2); /* make sure there is two arguments */ - auxsort(L, 1, n); + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) { /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (unsigned int)n, 0u); + } return 0; } @@ -266,6 +431,7 @@ static const luaL_Reg tab_funcs[] = { {"pack", pack}, {"unpack", unpack}, {"remove", tremove}, + {"move", tmove}, {"sort", sort}, {NULL, NULL} }; diff --git a/deps/lua/ltm.c b/deps/lua/ltm.c index 69b4ed7..22b4df3 100644 --- a/deps/lua/ltm.c +++ b/deps/lua/ltm.c @@ -1,22 +1,27 @@ /* -** $Id: ltm.c,v 2.14.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ltm.c,v 2.36 2015/11/03 15:47:30 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ - -#include - #define ltm_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" +#include "ldebug.h" +#include "ldo.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" +#include "lvm.h" static const char udatatypename[] = "userdata"; @@ -25,7 +30,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { "no value", "nil", "boolean", udatatypename, "number", "string", "table", "function", udatatypename, "thread", - "proto", "upval" /* these last two cases are used for tests only */ + "proto" /* this last case is used for tests only */ }; @@ -33,14 +38,16 @@ void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", "__gc", "__mode", "__len", "__eq", - "__add", "__sub", "__mul", "__div", "__mod", - "__pow", "__unm", "__lt", "__le", + "__add", "__sub", "__mul", "__mod", "__pow", + "__div", "__idiv", + "__band", "__bor", "__bxor", "__shl", "__shr", + "__unm", "__bnot", "__lt", "__le", "__concat", "__call" }; int i; for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); - luaS_fix(G(L)->tmname[i]); /* never collect these names */ + luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ } } @@ -50,7 +57,7 @@ void luaT_init (lua_State *L) { ** tag methods */ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { - const TValue *tm = luaH_getstr(events, ename); + const TValue *tm = luaH_getshortstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast_byte(1u<metatable; break; @@ -70,8 +77,73 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { mt = uvalue(o)->metatable; break; default: - mt = G(L)->mt[ttypenv(o)]; + mt = G(L)->mt[ttnov(o)]; + } + return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); +} + + +void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, TValue *p3, int hasres) { + ptrdiff_t result = savestack(L, p3); + StkId func = L->top; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + L->top += 3; + if (!hasres) /* no result? 'p3' is third argument */ + setobj2s(L, L->top++, p3); /* 3rd argument */ + /* metamethod may yield only when called from Lua code */ + if (isLua(L->ci)) + luaD_call(L, func, hasres); + else + luaD_callnoyield(L, func, hasres); + if (hasres) { /* if has result, move it to its place */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); } - return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); +} + + +int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (ttisnil(tm)) return 0; + luaT_callTM(L, tm, p1, p2, res, 1); + return 1; +} + + +void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + if (!luaT_callbinTM(L, p1, p2, res, event)) { + switch (event) { + case TM_CONCAT: + luaG_concaterror(L, p1, p2); + /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ + case TM_BAND: case TM_BOR: case TM_BXOR: + case TM_SHL: case TM_SHR: case TM_BNOT: { + lua_Number dummy; + if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) + luaG_tointerror(L, p1, p2); + else + luaG_opinterror(L, p1, p2, "perform bitwise operation on"); + } + /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ + default: + luaG_opinterror(L, p1, p2, "perform arithmetic on"); + } + } +} + + +int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, + TMS event) { + if (!luaT_callbinTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); } diff --git a/deps/lua/ltm.h b/deps/lua/ltm.h index 7f89c84..180179c 100644 --- a/deps/lua/ltm.h +++ b/deps/lua/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.11.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -13,7 +13,7 @@ /* * WARNING: if you change the order of this enumeration, -* grep "ORDER TM" +* grep "ORDER TM" and "ORDER OP" */ typedef enum { TM_INDEX, @@ -21,14 +21,21 @@ typedef enum { TM_GC, TM_MODE, TM_LEN, - TM_EQ, /* last tag method with `fast' access */ + TM_EQ, /* last tag method with fast access */ TM_ADD, TM_SUB, TM_MUL, - TM_DIV, TM_MOD, TM_POW, + TM_DIV, + TM_IDIV, + TM_BAND, + TM_BOR, + TM_BXOR, + TM_SHL, + TM_SHR, TM_UNM, + TM_BNOT, TM_LT, TM_LE, TM_CONCAT, @@ -44,7 +51,7 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) #define ttypename(x) luaT_typenames_[(x) + 1] -#define objtypename(x) ttypename(ttypenv(x)) +#define objtypename(x) ttypename(ttnov(x)) LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; @@ -54,4 +61,15 @@ LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); LUAI_FUNC void luaT_init (lua_State *L); +LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, TValue *p3, int hasres); +LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, + const TValue *p2, TMS event); + + + #endif diff --git a/deps/lua/lua.c b/deps/lua/lua.c index 4345e55..545d23d 100644 --- a/deps/lua/lua.c +++ b/deps/lua/lua.c @@ -1,17 +1,19 @@ /* -** $Id: lua.c,v 1.206.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lua.c,v 1.226 2015/08/14 19:11:20 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ +#define lua_c + +#include "lprefix.h" + #include #include #include #include -#define lua_c - #include "lua.h" #include "lauxlib.h" @@ -31,28 +33,38 @@ #define LUA_MAXINPUT 512 #endif -#if !defined(LUA_INIT) -#define LUA_INIT "LUA_INIT" +#if !defined(LUA_INIT_VAR) +#define LUA_INIT_VAR "LUA_INIT" #endif -#define LUA_INITVERSION \ - LUA_INIT "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR +#define LUA_INITVARVERSION \ + LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR /* ** lua_stdin_is_tty detects whether the standard input is a 'tty' (that ** is, whether we're running lua interactively). */ -#if defined(LUA_USE_ISATTY) +#if !defined(lua_stdin_is_tty) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + #include #define lua_stdin_is_tty() isatty(0) -#elif defined(LUA_WIN) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + #include -#include #define lua_stdin_is_tty() _isatty(_fileno(stdin)) -#else + +#else /* }{ */ + +/* ISO C definition */ #define lua_stdin_is_tty() 1 /* assume stdin is a tty */ -#endif + +#endif /* } */ + +#endif /* } */ /* @@ -61,26 +73,27 @@ ** lua_saveline defines how to "save" a read line in a "history". ** lua_freeline defines how to free a line read by lua_readline. */ -#if defined(LUA_USE_READLINE) +#if !defined(lua_readline) /* { */ + +#if defined(LUA_USE_READLINE) /* { */ -#include #include #include #define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) -#define lua_saveline(L,idx) \ - if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ - add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_saveline(L,line) ((void)L, add_history(line)) #define lua_freeline(L,b) ((void)L, free(b)) -#elif !defined(lua_readline) +#else /* }{ */ #define lua_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_saveline(L,line) { (void)L; (void)line; } #define lua_freeline(L,b) { (void)L; (void)b; } -#endif +#endif /* } */ + +#endif /* } */ @@ -90,33 +103,40 @@ static lua_State *globalL = NULL; static const char *progname = LUA_PROGNAME; - +/* +** Hook set by signal function to stop the interpreter. +*/ static void lstop (lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ - lua_sethook(L, NULL, 0, 0); + lua_sethook(L, NULL, 0, 0); /* reset hook */ luaL_error(L, "interrupted!"); } +/* +** Function to be called at a C signal. Because a C signal cannot +** just change a Lua state (as there is no proper synchronization), +** this function only sets a hook that, when called, will stop the +** interpreter. +*/ static void laction (int i) { - signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ + signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } static void print_usage (const char *badoption) { - luai_writestringerror("%s: ", progname); + lua_writestringerror("%s: ", progname); if (badoption[1] == 'e' || badoption[1] == 'l') - luai_writestringerror("'%s' needs argument\n", badoption); + lua_writestringerror("'%s' needs argument\n", badoption); else - luai_writestringerror("unrecognized option '%s'\n", badoption); - luai_writestringerror( + lua_writestringerror("unrecognized option '%s'\n", badoption); + lua_writestringerror( "usage: %s [options] [script [args]]\n" "Available options are:\n" - " -e stat execute string " LUA_QL("stat") "\n" - " -i enter interactive mode after executing " LUA_QL("script") "\n" - " -l name require library " LUA_QL("name") "\n" + " -e stat execute string 'stat'\n" + " -i enter interactive mode after executing 'script'\n" + " -l name require library 'name'\n" " -v show version information\n" " -E ignore environment variables\n" " -- stop handling options\n" @@ -126,101 +146,114 @@ static void print_usage (const char *badoption) { } +/* +** Prints an error message, adding the program name in front of it +** (if present) +*/ static void l_message (const char *pname, const char *msg) { - if (pname) luai_writestringerror("%s: ", pname); - luai_writestringerror("%s\n", msg); + if (pname) lua_writestringerror("%s: ", pname); + lua_writestringerror("%s\n", msg); } +/* +** Check whether 'status' is not OK and, if so, prints the error +** message on the top of the stack. It assumes that the error object +** is a string, as it was either generated by Lua or by 'msghandler'. +*/ static int report (lua_State *L, int status) { - if (status != LUA_OK && !lua_isnil(L, -1)) { + if (status != LUA_OK) { const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); - lua_pop(L, 1); - /* force a complete garbage collection in case of errors */ - lua_gc(L, LUA_GCCOLLECT, 0); + lua_pop(L, 1); /* remove message */ } return status; } -/* the next function is called unprotected, so it must avoid errors */ -static void finalreport (lua_State *L, int status) { - if (status != LUA_OK) { - const char *msg = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1) - : NULL; - if (msg == NULL) msg = "(error object is not a string)"; - l_message(progname, msg); - lua_pop(L, 1); - } -} - - -static int traceback (lua_State *L) { +/* +** Message handler used to run all chunks +*/ +static int msghandler (lua_State *L) { const char *msg = lua_tostring(L, 1); - if (msg) - luaL_traceback(L, L, msg, 1); - else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */ - if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */ - lua_pushliteral(L, "(no error message)"); + if (msg == NULL) { /* is error object not a string? */ + if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ + lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ + return 1; /* that is the message */ + else + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); } - return 1; + luaL_traceback(L, L, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ } +/* +** Interface to 'lua_pcall', which sets appropriate message function +** and C-signal handler. Used to run all chunks. +*/ static int docall (lua_State *L, int narg, int nres) { int status; int base = lua_gettop(L) - narg; /* function index */ - lua_pushcfunction(L, traceback); /* push traceback function */ - lua_insert(L, base); /* put it under chunk and args */ + lua_pushcfunction(L, msghandler); /* push message handler */ + lua_insert(L, base); /* put it under function and args */ globalL = L; /* to be available to 'laction' */ - signal(SIGINT, laction); + signal(SIGINT, laction); /* set C-signal handler */ status = lua_pcall(L, narg, nres, base); - signal(SIGINT, SIG_DFL); - lua_remove(L, base); /* remove traceback function */ + signal(SIGINT, SIG_DFL); /* reset C-signal handler */ + lua_remove(L, base); /* remove message handler from the stack */ return status; } static void print_version (void) { - luai_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); - luai_writeline(); + lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); + lua_writeline(); } -static int getargs (lua_State *L, char **argv, int n) { - int narg; - int i; - int argc = 0; - while (argv[argc]) argc++; /* count total number of arguments */ - narg = argc - (n + 1); /* number of arguments to the script */ - luaL_checkstack(L, narg + 3, "too many arguments to script"); - for (i=n+1; i < argc; i++) - lua_pushstring(L, argv[i]); - lua_createtable(L, narg, n + 1); - for (i=0; i < argc; i++) { +/* +** Create the 'arg' table, which stores all arguments from the +** command line ('argv'). It should be aligned so that, at index 0, +** it has 'argv[script]', which is the script name. The arguments +** to the script (everything after 'script') go to positive indices; +** other arguments (before the script name) go to negative indices. +** If there is no script name, assume interpreter's name as base. +*/ +static void createargtable (lua_State *L, char **argv, int argc, int script) { + int i, narg; + if (script == argc) script = 0; /* no script name? */ + narg = argc - (script + 1); /* number of positive indices */ + lua_createtable(L, narg, script + 1); + for (i = 0; i < argc; i++) { lua_pushstring(L, argv[i]); - lua_rawseti(L, -2, i - n); + lua_rawseti(L, -2, i - script); } - return narg; + lua_setglobal(L, "arg"); } -static int dofile (lua_State *L, const char *name) { - int status = luaL_loadfile(L, name); +static int dochunk (lua_State *L, int status) { if (status == LUA_OK) status = docall(L, 0, 0); return report(L, status); } +static int dofile (lua_State *L, const char *name) { + return dochunk(L, luaL_loadfile(L, name)); +} + + static int dostring (lua_State *L, const char *s, const char *name) { - int status = luaL_loadbuffer(L, s, strlen(s), name); - if (status == LUA_OK) status = docall(L, 0, 0); - return report(L, status); + return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name)); } +/* +** Calls 'require(name)' and stores the result in a global variable +** with the given name. +*/ static int dolibrary (lua_State *L, const char *name) { int status; lua_getglobal(L, "require"); @@ -232,6 +265,9 @@ static int dolibrary (lua_State *L, const char *name) { } +/* +** Returns the string to be used as a prompt by the interpreter. +*/ static const char *get_prompt (lua_State *L, int firstline) { const char *p; lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); @@ -244,6 +280,12 @@ static const char *get_prompt (lua_State *L, int firstline) { #define EOFMARK "" #define marklen (sizeof(EOFMARK)/sizeof(char) - 1) + +/* +** Check whether 'status' signals a syntax error and the error +** message at the top of the stack ends with the above mark for +** incomplete statements. +*/ static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; @@ -257,163 +299,230 @@ static int incomplete (lua_State *L, int status) { } +/* +** Prompt the user, read a line, and push it into the Lua stack. +*/ static int pushline (lua_State *L, int firstline) { char buffer[LUA_MAXINPUT]; char *b = buffer; size_t l; const char *prmt = get_prompt(L, firstline); int readstatus = lua_readline(L, b, prmt); - lua_pop(L, 1); /* remove result from 'get_prompt' */ if (readstatus == 0) - return 0; /* no input */ + return 0; /* no input (prompt will be popped by caller) */ + lua_pop(L, 1); /* remove prompt */ l = strlen(b); if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ - b[l-1] = '\0'; /* remove it */ - if (firstline && b[0] == '=') /* first line starts with `=' ? */ - lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + b[--l] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */ + lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */ else - lua_pushstring(L, b); + lua_pushlstring(L, b, l); lua_freeline(L, b); return 1; } +/* +** Try to compile line on the stack as 'return ;'; on return, stack +** has either compiled chunk or original line (if compilation failed). +*/ +static int addreturn (lua_State *L) { + const char *line = lua_tostring(L, -1); /* original line */ + const char *retline = lua_pushfstring(L, "return %s;", line); + int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin"); + if (status == LUA_OK) { + lua_remove(L, -2); /* remove modified line */ + if (line[0] != '\0') /* non empty? */ + lua_saveline(L, line); /* keep history */ + } + else + lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */ + return status; +} + + +/* +** Read multiple lines until a complete Lua statement +*/ +static int multiline (lua_State *L) { + for (;;) { /* repeat until gets a complete statement */ + size_t len; + const char *line = lua_tolstring(L, 1, &len); /* get what it has */ + int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ + if (!incomplete(L, status) || !pushline(L, 0)) { + lua_saveline(L, line); /* keep history */ + return status; /* cannot or should not try to add continuation line */ + } + lua_pushliteral(L, "\n"); /* add newline... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } +} + + +/* +** Read a line and try to load (compile) it first as an expression (by +** adding "return " in front of it) and second as a statement. Return +** the final status of load/call with the resulting function (if any) +** in the top of the stack. +*/ static int loadline (lua_State *L) { int status; lua_settop(L, 0); if (!pushline(L, 1)) return -1; /* no input */ - for (;;) { /* repeat until gets a complete line */ - size_t l; - const char *line = lua_tolstring(L, 1, &l); - status = luaL_loadbuffer(L, line, l, "=stdin"); - if (!incomplete(L, status)) break; /* cannot try to add lines? */ - if (!pushline(L, 0)) /* no more input? */ - return -1; - lua_pushliteral(L, "\n"); /* add a new line... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } - lua_saveline(L, 1); - lua_remove(L, 1); /* remove line */ + if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ + status = multiline(L); /* try as command, maybe with continuation lines */ + lua_remove(L, 1); /* remove line from the stack */ + lua_assert(lua_gettop(L) == 1); return status; } -static void dotty (lua_State *L) { +/* +** Prints (calling the Lua 'print' function) any values on the stack +*/ +static void l_print (lua_State *L) { + int n = lua_gettop(L); + if (n > 0) { /* any result to be printed? */ + luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, n, 0, 0) != LUA_OK) + l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)", + lua_tostring(L, -1))); + } +} + + +/* +** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and +** print any results. +*/ +static void doREPL (lua_State *L) { int status; const char *oldprogname = progname; - progname = NULL; + progname = NULL; /* no 'progname' on errors in interactive mode */ while ((status = loadline(L)) != -1) { - if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); - report(L, status); - if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ - luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK) - l_message(progname, lua_pushfstring(L, - "error calling " LUA_QL("print") " (%s)", - lua_tostring(L, -1))); - } + if (status == LUA_OK) + status = docall(L, 0, LUA_MULTRET); + if (status == LUA_OK) l_print(L); + else report(L, status); } lua_settop(L, 0); /* clear stack */ - luai_writeline(); + lua_writeline(); progname = oldprogname; } -static int handle_script (lua_State *L, char **argv, int n) { +/* +** Push on the stack the contents of table 'arg' from 1 to #arg +*/ +static int pushargs (lua_State *L) { + int i, n; + if (lua_getglobal(L, "arg") != LUA_TTABLE) + luaL_error(L, "'arg' is not a table"); + n = (int)luaL_len(L, -1); + luaL_checkstack(L, n + 3, "too many arguments to script"); + for (i = 1; i <= n; i++) + lua_rawgeti(L, -i, i); + lua_remove(L, -i); /* remove table from the stack */ + return n; +} + + +static int handle_script (lua_State *L, char **argv) { int status; - const char *fname; - int narg = getargs(L, argv, n); /* collect arguments */ - lua_setglobal(L, "arg"); - fname = argv[n]; - if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + const char *fname = argv[0]; + if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) fname = NULL; /* stdin */ status = luaL_loadfile(L, fname); - lua_insert(L, -(narg+1)); - if (status == LUA_OK) - status = docall(L, narg, LUA_MULTRET); - else - lua_pop(L, narg); + if (status == LUA_OK) { + int n = pushargs(L); /* push arguments to script */ + status = docall(L, n, LUA_MULTRET); + } return report(L, status); } -/* check that argument has no extra characters at the end */ -#define noextrachars(x) {if ((x)[2] != '\0') return -1;} - - -/* indices of various argument indicators in array args */ -#define has_i 0 /* -i */ -#define has_v 1 /* -v */ -#define has_e 2 /* -e */ -#define has_E 3 /* -E */ - -#define num_has 4 /* number of 'has_*' */ +/* bits of various argument indicators in 'args' */ +#define has_error 1 /* bad option */ +#define has_i 2 /* -i */ +#define has_v 4 /* -v */ +#define has_e 8 /* -e */ +#define has_E 16 /* -E */ -static int collectargs (char **argv, int *args) { +/* +** Traverses all arguments from 'argv', returning a mask with those +** needed before running any Lua code (or an error code if it finds +** any invalid argument). 'first' returns the first not-handled argument +** (either the script name or a bad argument in case of error). +*/ +static int collectargs (char **argv, int *first) { + int args = 0; int i; for (i = 1; argv[i] != NULL; i++) { + *first = i; if (argv[i][0] != '-') /* not an option? */ - return i; - switch (argv[i][1]) { /* option */ - case '-': - noextrachars(argv[i]); - return (argv[i+1] != NULL ? i+1 : 0); - case '\0': - return i; + return args; /* stop handling options */ + switch (argv[i][1]) { /* else check option */ + case '-': /* '--' */ + if (argv[i][2] != '\0') /* extra characters after '--'? */ + return has_error; /* invalid option */ + *first = i + 1; + return args; + case '\0': /* '-' */ + return args; /* script "name" is '-' */ case 'E': - args[has_E] = 1; + if (argv[i][2] != '\0') /* extra characters after 1st? */ + return has_error; /* invalid option */ + args |= has_E; break; case 'i': - noextrachars(argv[i]); - args[has_i] = 1; /* go through */ + args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */ case 'v': - noextrachars(argv[i]); - args[has_v] = 1; + if (argv[i][2] != '\0') /* extra characters after 1st? */ + return has_error; /* invalid option */ + args |= has_v; break; case 'e': - args[has_e] = 1; /* go through */ + args |= has_e; /* FALLTHROUGH */ case 'l': /* both options need an argument */ if (argv[i][2] == '\0') { /* no concatenated argument? */ i++; /* try next 'argv' */ if (argv[i] == NULL || argv[i][0] == '-') - return -(i - 1); /* no next argument or it is another option */ + return has_error; /* no next argument or it is another option */ } break; - default: /* invalid option; return its index... */ - return -i; /* ...as a negative value */ + default: /* invalid option */ + return has_error; } } - return 0; + *first = i; /* no script name */ + return args; } +/* +** Processes options 'e' and 'l', which involve running Lua code. +** Returns 0 if some code raises an error. +*/ static int runargs (lua_State *L, char **argv, int n) { int i; for (i = 1; i < n; i++) { - lua_assert(argv[i][0] == '-'); - switch (argv[i][1]) { /* option */ - case 'e': { - const char *chunk = argv[i] + 2; - if (*chunk == '\0') chunk = argv[++i]; - lua_assert(chunk != NULL); - if (dostring(L, chunk, "=(command line)") != LUA_OK) - return 0; - break; - } - case 'l': { - const char *filename = argv[i] + 2; - if (*filename == '\0') filename = argv[++i]; - lua_assert(filename != NULL); - if (dolibrary(L, filename) != LUA_OK) - return 0; /* stop if file fails */ - break; - } - default: break; + int option = argv[i][1]; + lua_assert(argv[i][0] == '-'); /* already checked */ + if (option == 'e' || option == 'l') { + int status; + const char *extra = argv[i] + 2; /* both options need an argument */ + if (*extra == '\0') extra = argv[++i]; + lua_assert(extra != NULL); + status = (option == 'e') + ? dostring(L, extra, "=(command line)") + : dolibrary(L, extra); + if (status != LUA_OK) return 0; } } return 1; @@ -421,10 +530,10 @@ static int runargs (lua_State *L, char **argv, int n) { static int handle_luainit (lua_State *L) { - const char *name = "=" LUA_INITVERSION; + const char *name = "=" LUA_INITVARVERSION; const char *init = getenv(name + 1); if (init == NULL) { - name = "=" LUA_INIT; + name = "=" LUA_INIT_VAR; init = getenv(name + 1); /* try alternative name */ } if (init == NULL) return LUA_OK; @@ -435,40 +544,44 @@ static int handle_luainit (lua_State *L) { } +/* +** Main body of stand-alone interpreter (to be called in protected mode). +** Reads the options and handles them all. +*/ static int pmain (lua_State *L) { int argc = (int)lua_tointeger(L, 1); char **argv = (char **)lua_touserdata(L, 2); int script; - int args[num_has]; - args[has_i] = args[has_v] = args[has_e] = args[has_E] = 0; + int args = collectargs(argv, &script); + luaL_checkversion(L); /* check that interpreter has correct version */ if (argv[0] && argv[0][0]) progname = argv[0]; - script = collectargs(argv, args); - if (script < 0) { /* invalid arg? */ - print_usage(argv[-script]); + if (args == has_error) { /* bad arg? */ + print_usage(argv[script]); /* 'script' has index of bad arg. */ return 0; } - if (args[has_v]) print_version(); - if (args[has_E]) { /* option '-E'? */ + if (args & has_v) /* option '-v'? */ + print_version(); + if (args & has_E) { /* option '-E'? */ lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); } - /* open standard libraries */ - luaL_checkversion(L); - lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ - luaL_openlibs(L); /* open libraries */ - lua_gc(L, LUA_GCRESTART, 0); - if (!args[has_E] && handle_luainit(L) != LUA_OK) - return 0; /* error running LUA_INIT */ - /* execute arguments -e and -l */ - if (!runargs(L, argv, (script > 0) ? script : argc)) return 0; - /* execute main script (if there is one) */ - if (script && handle_script(L, argv, script) != LUA_OK) return 0; - if (args[has_i]) /* -i option? */ - dotty(L); - else if (script == 0 && !args[has_e] && !args[has_v]) { /* no arguments? */ - if (lua_stdin_is_tty()) { + luaL_openlibs(L); /* open standard libraries */ + createargtable(L, argv, argc, script); /* create table 'arg' */ + if (!(args & has_E)) { /* no option '-E'? */ + if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ + return 0; /* error running LUA_INIT */ + } + if (!runargs(L, argv, script)) /* execute arguments -e and -l */ + return 0; /* something failed */ + if (script < argc && /* execute main script (if there is one) */ + handle_script(L, argv + script) != LUA_OK) + return 0; + if (args & has_i) /* -i option? */ + doREPL(L); /* do read-eval-print loop */ + else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */ + if (lua_stdin_is_tty()) { /* running in interactive mode? */ print_version(); - dotty(L); + doREPL(L); /* do read-eval-print loop */ } else dofile(L, NULL); /* executes stdin as a file */ } @@ -484,13 +597,12 @@ int main (int argc, char **argv) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } - /* call 'pmain' in protected mode */ - lua_pushcfunction(L, &pmain); + lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ lua_pushinteger(L, argc); /* 1st argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */ - status = lua_pcall(L, 2, 1, 0); + status = lua_pcall(L, 2, 1, 0); /* do the call */ result = lua_toboolean(L, -1); /* get result */ - finalreport(L, status); + report(L, status); lua_close(L); return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/deps/lua/lua.h b/deps/lua/lua.h index 2b19294..6c0e339 100644 --- a/deps/lua/lua.h +++ b/deps/lua/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.285.1.2 2013/11/11 12:09:16 roberto Exp $ +** $Id: lua.h,v 1.329 2015/11/13 17:18:42 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -17,27 +17,29 @@ #define LUA_VERSION_MAJOR "5" -#define LUA_VERSION_MINOR "2" -#define LUA_VERSION_NUM 502 -#define LUA_VERSION_RELEASE "3" +#define LUA_VERSION_MINOR "3" +#define LUA_VERSION_NUM 503 +#define LUA_VERSION_RELEASE "2" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" /* mark for precompiled code ('Lua') */ -#define LUA_SIGNATURE "\033Lua" +#define LUA_SIGNATURE "\x1bLua" /* option for multiple returns in 'lua_pcall' and 'lua_call' */ #define LUA_MULTRET (-1) /* -** pseudo-indices +** Pseudo-indices +** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty +** space after that to help overflow detection) */ -#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX +#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) #define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) @@ -53,22 +55,6 @@ typedef struct lua_State lua_State; -typedef int (*lua_CFunction) (lua_State *L); - - -/* -** functions that read/write blocks when loading/dumping Lua chunks -*/ -typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); - -typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); - - -/* -** prototype for memory-allocation functions -*/ -typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); - /* ** basic types @@ -109,6 +95,34 @@ typedef LUA_INTEGER lua_Integer; /* unsigned integer type */ typedef LUA_UNSIGNED lua_Unsigned; +/* type for continuation-function contexts */ +typedef LUA_KCONTEXT lua_KContext; + + +/* +** Type for C functions registered with Lua +*/ +typedef int (*lua_CFunction) (lua_State *L); + +/* +** Type for continuation functions +*/ +typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); + + +/* +** Type for functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); + + +/* +** Type for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + /* @@ -149,11 +163,9 @@ LUA_API int (lua_absindex) (lua_State *L, int idx); LUA_API int (lua_gettop) (lua_State *L); LUA_API void (lua_settop) (lua_State *L, int idx); LUA_API void (lua_pushvalue) (lua_State *L, int idx); -LUA_API void (lua_remove) (lua_State *L, int idx); -LUA_API void (lua_insert) (lua_State *L, int idx); -LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API void (lua_rotate) (lua_State *L, int idx, int n); LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); -LUA_API int (lua_checkstack) (lua_State *L, int sz); +LUA_API int (lua_checkstack) (lua_State *L, int n); LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); @@ -165,13 +177,13 @@ LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); LUA_API int (lua_isnumber) (lua_State *L, int idx); LUA_API int (lua_isstring) (lua_State *L, int idx); LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isinteger) (lua_State *L, int idx); LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); -LUA_API lua_Unsigned (lua_tounsignedx) (lua_State *L, int idx, int *isnum); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_rawlen) (lua_State *L, int idx); @@ -185,13 +197,20 @@ LUA_API const void *(lua_topointer) (lua_State *L, int idx); ** Comparison and arithmetic functions */ -#define LUA_OPADD 0 /* ORDER TM */ +#define LUA_OPADD 0 /* ORDER TM, ORDER OP */ #define LUA_OPSUB 1 #define LUA_OPMUL 2 -#define LUA_OPDIV 3 -#define LUA_OPMOD 4 -#define LUA_OPPOW 5 -#define LUA_OPUNM 6 +#define LUA_OPMOD 3 +#define LUA_OPPOW 4 +#define LUA_OPDIV 5 +#define LUA_OPIDIV 6 +#define LUA_OPBAND 7 +#define LUA_OPBOR 8 +#define LUA_OPBXOR 9 +#define LUA_OPSHL 10 +#define LUA_OPSHR 11 +#define LUA_OPUNM 12 +#define LUA_OPBNOT 13 LUA_API void (lua_arith) (lua_State *L, int op); @@ -209,8 +228,7 @@ LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); -LUA_API void (lua_pushunsigned) (lua_State *L, lua_Unsigned n); -LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); @@ -224,26 +242,29 @@ LUA_API int (lua_pushthread) (lua_State *L); /* ** get functions (Lua -> stack) */ -LUA_API void (lua_getglobal) (lua_State *L, const char *var); -LUA_API void (lua_gettable) (lua_State *L, int idx); -LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); -LUA_API void (lua_rawget) (lua_State *L, int idx); -LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); -LUA_API void (lua_rawgetp) (lua_State *L, int idx, const void *p); +LUA_API int (lua_getglobal) (lua_State *L, const char *name); +LUA_API int (lua_gettable) (lua_State *L, int idx); +LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawget) (lua_State *L, int idx); +LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); + LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API void (lua_getuservalue) (lua_State *L, int idx); +LUA_API int (lua_getuservalue) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ -LUA_API void (lua_setglobal) (lua_State *L, const char *var); +LUA_API void (lua_setglobal) (lua_State *L, const char *name); LUA_API void (lua_settable) (lua_State *L, int idx); LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawset) (lua_State *L, int idx); -LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); LUA_API void (lua_setuservalue) (lua_State *L, int idx); @@ -252,21 +273,18 @@ LUA_API void (lua_setuservalue) (lua_State *L, int idx); /* ** 'load' and 'call' functions (load and run Lua code) */ -LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx, - lua_CFunction k); +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); #define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) -LUA_API int (lua_getctx) (lua_State *L, int *ctx); - LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - int ctx, lua_CFunction k); + lua_KContext ctx, lua_KFunction k); #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, - const char *mode); + const char *chunkname, const char *mode); -LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); /* Added by xdczju@sina.com */ #if defined(LUA_USE_SHARED_PROTO) @@ -285,11 +303,14 @@ LUA_API int (lua_yieldable)(lua_State *L); /* ** coroutine functions */ -LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx, - lua_CFunction k); +LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k); +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); +LUA_API int (lua_status) (lua_State *L); +LUA_API int (lua_isyieldable) (lua_State *L); + #define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) -LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); -LUA_API int (lua_status) (lua_State *L); + /* ** garbage-collection function and options @@ -303,10 +324,7 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 -#define LUA_GCSETMAJORINC 8 #define LUA_GCISRUNNING 9 -#define LUA_GCGEN 10 -#define LUA_GCINC 11 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -322,20 +340,23 @@ LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); LUA_API void (lua_len) (lua_State *L, int idx); +LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); + LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); /* -** =============================================================== +** {============================================================== ** some useful macros ** =============================================================== */ -#define lua_tonumber(L,i) lua_tonumberx(L,i,NULL) -#define lua_tointeger(L,i) lua_tointegerx(L,i,NULL) -#define lua_tounsigned(L,i) lua_tounsignedx(L,i,NULL) +#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) + +#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) #define lua_pop(L,n) lua_settop(L, -(n)-1) @@ -354,8 +375,7 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) #define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) -#define lua_pushliteral(L, s) \ - lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) +#define lua_pushliteral(L, s) lua_pushstring(L, "" s) #define lua_pushglobaltable(L) \ lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) @@ -363,6 +383,28 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) +#define lua_insert(L,idx) lua_rotate(L, (idx), 1) + +#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) + +#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) + +/* }============================================================== */ + + +/* +** {============================================================== +** compatibility macros for unsigned conversions +** =============================================================== +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) +#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) + +#endif +/* }============================================================== */ /* ** {====================================================================== @@ -407,7 +449,7 @@ LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, int fidx2, int n2); -LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); LUA_API lua_Hook (lua_gethook) (lua_State *L); LUA_API int (lua_gethookmask) (lua_State *L); LUA_API int (lua_gethookcount) (lua_State *L); @@ -435,7 +477,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2013 Lua.org, PUC-Rio. +* Copyright (C) 1994-2015 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/deps/lua/lua.vcxproj b/deps/lua/lua.vcxproj index e9e1ccd..9df3549 100644 --- a/deps/lua/lua.vcxproj +++ b/deps/lua/lua.vcxproj @@ -48,7 +48,7 @@ Level3 Disabled true - WIN32;_DEBUG;LUA_COMPAT_MODULE;LUA_BUILD_AS_DLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + WIN32;_DEBUG;LUA_COMPAT_5_2;LUA_COMPAT_5_1;LUA_BUILD_AS_DLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) Default diff --git a/deps/lua/luac.c b/deps/lua/luac.c index 2059404..e9bfc9e 100644 --- a/deps/lua/luac.c +++ b/deps/lua/luac.c @@ -1,17 +1,20 @@ /* -** $Id: luac.c,v 1.69 2011/11/29 17:46:33 lhf Exp $ -** Lua compiler (saves bytecodes to files; also list bytecodes) +** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $ +** Lua compiler (saves bytecodes to files; also lists bytecodes) ** See Copyright Notice in lua.h */ +#define luac_c +#define LUA_CORE + +#include "lprefix.h" + +#include #include #include #include #include -#define luac_c -#define LUA_CORE - #include "lua.h" #include "lauxlib.h" @@ -47,14 +50,14 @@ static void cannot(const char* what) static void usage(const char* message) { if (*message=='-') - fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); + fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message); else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, "usage: %s [options] [filenames]\n" "Available options are:\n" " -l list (use -l -l for full listing)\n" - " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" + " -o name output to file 'name' (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" @@ -89,7 +92,7 @@ static int doargs(int argc, char* argv[]) { output=argv[++i]; if (output==NULL || *output==0 || (*output=='-' && output[1]!=0)) - usage(LUA_QL("-o") " needs argument"); + usage("'-o' needs argument"); if (IS("-")) output=NULL; } else if (IS("-p")) /* parse only */ @@ -203,7 +206,7 @@ int main(int argc, char* argv[]) } /* -** $Id: print.c,v 1.69 2013/07/04 01:03:46 lhf Exp $ +** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -223,7 +226,7 @@ int main(int argc, char* argv[]) static void PrintString(const TString* ts) { const char* s=getstr(ts); - size_t i,n=ts->tsv.len; + size_t i,n=tsslen(ts); printf("%c",'"'); for (i=0; ik[i]; - switch (ttypenv(o)) + switch (ttype(o)) { case LUA_TNIL: printf("nil"); @@ -259,11 +262,19 @@ static void PrintConstant(const Proto* f, int i) case LUA_TBOOLEAN: printf(bvalue(o) ? "true" : "false"); break; - case LUA_TNUMBER: - printf(LUA_NUMBER_FMT,nvalue(o)); + case LUA_TNUMFLT: + { + char buff[100]; + sprintf(buff,LUA_NUMBER_FMT,fltvalue(o)); + printf("%s",buff); + if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0"); + break; + } + case LUA_TNUMINT: + printf(LUA_INTEGER_FMT,ivalue(o)); break; - case LUA_TSTRING: - PrintString(rawtsvalue(o)); + case LUA_TSHRSTR: case LUA_TLNGSTR: + PrintString(tsvalue(o)); break; default: /* cannot happen */ printf("? type=%d",ttype(o)); @@ -338,8 +349,14 @@ static void PrintCode(const Proto* f) case OP_ADD: case OP_SUB: case OP_MUL: - case OP_DIV: case OP_POW: + case OP_DIV: + case OP_IDIV: + case OP_BAND: + case OP_BOR: + case OP_BXOR: + case OP_SHL: + case OP_SHR: case OP_EQ: case OP_LT: case OP_LE: diff --git a/deps/lua/luaconf.h b/deps/lua/luaconf.h index 4a97ef2..5dce53e 100644 --- a/deps/lua/luaconf.h +++ b/deps/lua/luaconf.h @@ -1,89 +1,173 @@ /* -** $Id: luaconf.h,v 1.176.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: luaconf.h,v 1.254 2015/10/21 18:17:40 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ -#ifndef lconfig_h -#define lconfig_h +#ifndef luaconf_h +#define luaconf_h #include #include /* -** ================================================================== +** =================================================================== ** Search for "@@" to find all configurable definitions. ** =================================================================== */ /* -@@ LUA_ANSI controls the use of non-ansi features. -** CHANGE it (define it) if you want Lua to avoid the use of any -** non-ansi feature or library. +** {==================================================================== +** System Configuration: macros to adapt (if needed) Lua to some +** particular platform, for instance compiling it with 32-bit numbers or +** restricting it to C89. +** ===================================================================== */ -#if !defined(LUA_ANSI) && defined(__STRICT_ANSI__) -#define LUA_ANSI -#endif + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You +** can also define LUA_32BITS in the make file, but changing here you +** ensure that all software connected to Lua will be compiled with the +** same configuration. +*/ +/* #define LUA_32BITS */ -#if !defined(LUA_ANSI) && defined(_WIN32) && !defined(_WIN32_WCE) -#define LUA_WIN /* enable goodies for regular Windows platforms */ -#endif +/* +@@ LUA_USE_C89 controls the use of non-ISO-C89 features. +** Define it if you want Lua to avoid the use of a few C99 features +** or Windows-specific features on Windows. +*/ +/* #define LUA_USE_C89 */ -#if defined(LUA_WIN) -#define LUA_DL_DLL -#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ + +/* +** By default, Lua on Windows use (some) specific Windows features +*/ +#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ #endif +#if defined(LUA_USE_WINDOWS) +#define LUA_DL_DLL /* enable support for DLL */ +#define LUA_USE_C89 /* broadly, Windows is C89 */ +#endif + #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_READLINE /* needs some extra libraries */ -#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */ -#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ -#define LUA_USE_LONGLONG /* assume support for long long */ #endif + #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX -#define LUA_USE_DLOPEN /* does not need -ldl */ +#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ #define LUA_USE_READLINE /* needs an extra library: -lreadline */ -#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */ -#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ -#define LUA_USE_LONGLONG /* assume support for long long */ +#endif + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS #endif /* -@@ LUA_USE_POSIX includes all functionality listed as X/Open System -@* Interfaces Extension (XSI). -** CHANGE it (define it) if your system is XSI compatible. +@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. */ -#if defined(LUA_USE_POSIX) -#define LUA_USE_MKSTEMP -#define LUA_USE_ISATTY -#define LUA_USE_POPEN -#define LUA_USE_ULONGJMP -#define LUA_USE_GMTIME_R +/* avoid undefined shifts */ +#if ((INT_MAX >> 15) >> 15) >= 1 +#define LUAI_BITSINT 32 +#else +/* 'int' always must have at least 16 bits */ +#define LUAI_BITSINT 16 #endif +/* +@@ LUA_INT_TYPE defines the type for Lua integers. +@@ LUA_FLOAT_TYPE defines the type for Lua floats. +** Lua should work fine with any mix of these options (if supported +** by your C compiler). The usual configurations are 64-bit integers +** and 'double' (the default), 32-bit integers and 'float' (for +** restricted platforms), and 'long'/'double' (for C compilers not +** compliant with C99, which may not have support for 'long long'). +*/ + +/* predefined options for LUA_INT_TYPE */ +#define LUA_INT_INT 1 +#define LUA_INT_LONG 2 +#define LUA_INT_LONGLONG 3 + +/* predefined options for LUA_FLOAT_TYPE */ +#define LUA_FLOAT_FLOAT 1 +#define LUA_FLOAT_DOUBLE 2 +#define LUA_FLOAT_LONGDOUBLE 3 + +#if defined(LUA_32BITS) /* { */ +/* +** 32-bit integers and 'float' +*/ +#if LUAI_BITSINT >= 32 /* use 'int' if big enough */ +#define LUA_INT_TYPE LUA_INT_INT +#else /* otherwise use 'long' */ +#define LUA_INT_TYPE LUA_INT_LONG +#endif +#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT + +#elif defined(LUA_C89_NUMBERS) /* }{ */ +/* +** largest types available for C89 ('long' and 'double') +*/ +#define LUA_INT_TYPE LUA_INT_LONG +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE + +#endif /* } */ + + +/* +** default configuration for 64-bit Lua ('long long' and 'double') +*/ +#if !defined(LUA_INT_TYPE) +#define LUA_INT_TYPE LUA_INT_LONGLONG +#endif + +#if !defined(LUA_FLOAT_TYPE) +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE +#endif + +/* }================================================================== */ + + + + +/* +** {================================================================== +** Configuration for Paths. +** =================================================================== +*/ /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for -@* Lua libraries. +** Lua libraries. @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for -@* C libraries. +** C libraries. ** CHANGE them if your machine has a non-conventional directory ** hierarchy or if you want to install your libraries in ** non-conventional directories. */ +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #if defined(_WIN32) /* { */ /* ** In Windows, any exclamation mark ('!') in the path is replaced by the @@ -91,21 +175,26 @@ */ #define LUA_LDIR "!\\lua\\" #define LUA_CDIR "!\\" +#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" #define LUA_PATH_DEFAULT \ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" ".\\?.lua" + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ + LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ + ".\\?.lua;" ".\\?\\init.lua" #define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll" + LUA_CDIR"?.dll;" \ + LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ + LUA_CDIR"loadall.dll;" ".\\?.dll" #else /* }{ */ -#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/" #define LUA_ROOT "/usr/local/" -#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR -#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR +#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" #define LUA_PATH_DEFAULT \ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua" + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ + "./?.lua;" "./?/init.lua" #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" #endif /* } */ @@ -122,14 +211,14 @@ #define LUA_DIRSEP "/" #endif +/* }================================================================== */ + /* -@@ LUA_ENV is the name of the variable that holds the current -@@ environment, used to access global names. -** CHANGE it if you do not like this name. +** {================================================================== +** Marks for exported symbols in the C code +** =================================================================== */ -#define LUA_ENV "_ENV" - /* @@ LUA_API is a mark for all core API functions. @@ -162,10 +251,10 @@ /* @@ LUAI_FUNC is a mark for all extern functions that are not to be -@* exported to outside modules. +** exported to outside modules. @@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables -@* that are not to be exported to outside modules (LUAI_DDEF for -@* definitions and LUAI_DDEC for declarations). +** that are not to be exported to outside modules (LUAI_DDEF for +** definitions and LUAI_DDEC for declarations). ** CHANGE them if you need to mark them in some special way. Elf/gcc ** (versions 3.2 and later) mark them as "hidden" to optimize access ** when Lua is compiled as a shared library. Not all elf targets support @@ -177,74 +266,61 @@ #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ defined(__ELF__) /* { */ #define LUAI_FUNC __attribute__((visibility("hidden"))) extern -#define LUAI_DDEC LUAI_FUNC -#define LUAI_DDEF /* empty */ - #else /* }{ */ #define LUAI_FUNC extern -#define LUAI_DDEC extern -#define LUAI_DDEF /* empty */ #endif /* } */ +#define LUAI_DDEC LUAI_FUNC +#define LUAI_DDEF /* empty */ + +/* }================================================================== */ /* -@@ LUA_QL describes how error messages quote program elements. -** CHANGE it if you want a different appearance. +** {================================================================== +** Compatibility with previous versions +** =================================================================== */ -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") - /* -@@ LUA_IDSIZE gives the maximum size for the description of the source -@* of a function in debug information. -** CHANGE it if you want a different size. +@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. +@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. +** You can define it to get all options, or change specific options +** to fit your specific needs. */ -#define LUA_IDSIZE 60 - +#if defined(LUA_COMPAT_5_2) /* { */ /* -@@ luai_writestring/luai_writeline define how 'print' prints its results. -** They are only used in libraries and the stand-alone program. (The #if -** avoids including 'stdio.h' everywhere.) +@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated +** functions in the mathematical library. */ -#if defined(LUA_LIB) || defined(lua_c) -#include -#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) -#define luai_writeline() (luai_writestring("\n", 1), fflush(stdout)) -#endif +#define LUA_COMPAT_MATHLIB /* -@@ luai_writestringerror defines how to print error messages. -** (A format string with one argument is enough for Lua...) +@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. */ -#define luai_writestringerror(s,p) \ - (fprintf(stderr, (s), (p)), fflush(stderr)) +#define LUA_COMPAT_BITLIB +/* +@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. +*/ +#define LUA_COMPAT_IPAIRS /* -@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is, -** strings that are internalized. (Cannot be smaller than reserved words -** or tags for metamethods, as these strings must be internalized; -** #("function") = 8, #("__newindex") = 10.) +@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for +** manipulating other integer types (lua_pushunsigned, lua_tounsigned, +** luaL_checkint, luaL_checklong, etc.) */ -#define LUAI_MAXSHORTLEN 40 +#define LUA_COMPAT_APIINTCASTS +#endif /* } */ -/* -** {================================================================== -** Compatibility with previous versions -** =================================================================== -*/ +#if defined(LUA_COMPAT_5_1) /* { */ -/* -@@ LUA_COMPAT_ALL controls all compatibility options. -** You can define it to get all options, or change specific options -** to fit your specific needs. -*/ -#if defined(LUA_COMPAT_ALL) /* { */ +/* Incompatibilities from 5.2 -> 5.3 */ +#define LUA_COMPAT_MATHLIB +#define LUA_COMPAT_APIINTCASTS /* @@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. @@ -305,237 +381,375 @@ #endif /* } */ + +/* +@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a +@@ a float mark ('.0'). +** This macro is not on by default even in compatibility mode, +** because this is not really an incompatibility. +*/ +/* #define LUA_COMPAT_FLOATSTRING */ + /* }================================================================== */ /* -@@ LUAI_BITSINT defines the number of bits in an int. -** CHANGE here if Lua cannot automatically detect the number of bits of -** your machine. Probably you do not need to change this. +** {================================================================== +** Configuration for Numbers. +** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* +** satisfy your needs. +** =================================================================== +*/ + +/* +@@ LUA_NUMBER is the floating-point type used by Lua. +@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@@ over a floating number. +@@ l_mathlim(x) corrects limit name 'x' to the proper float type +** by prefixing it with one of FLT/DBL/LDBL. +@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. +@@ LUA_NUMBER_FMT is the format for writing floats. +@@ lua_number2str converts a float to a string. +@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. +@@ l_floor takes the floor of a float. +@@ lua_str2number converts a decimal numeric string to a number. */ -/* avoid overflows in comparison */ -#if INT_MAX-20 < 32760 /* { */ -#define LUAI_BITSINT 16 -#elif INT_MAX > 2147483640L /* }{ */ -/* int has at least 32 bits */ -#define LUAI_BITSINT 32 -#else /* }{ */ -#error "you must define LUA_BITSINT with number of bits in an integer" -#endif /* } */ +/* The following definitions are good for most cases here */ + +#define l_floor(x) (l_mathop(floor)(x)) + +#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n)) + /* -@@ LUA_INT32 is an signed integer with exactly 32 bits. -@@ LUAI_UMEM is an unsigned integer big enough to count the total -@* memory used by Lua. -@@ LUAI_MEM is a signed integer big enough to count the total memory -@* used by Lua. -** CHANGE here if for some weird reason the default definitions are not -** good enough for your machine. Probably you do not need to change -** this. +@@ lua_numbertointeger converts a float number to an integer, or +** returns 0 if float is not within the range of a lua_Integer. +** (The range comparisons are tricky because of rounding. The tests +** here assume a two-complement representation, where MININTEGER always +** has an exact representation as a float; MAXINTEGER may not have one, +** and therefore its conversion to float may have an ill-defined value.) */ -#if LUAI_BITSINT >= 32 /* { */ -#define LUA_INT32 int -#define LUAI_UMEM size_t -#define LUAI_MEM ptrdiff_t -#else /* }{ */ -/* 16-bit ints */ -#define LUA_INT32 long -#define LUAI_UMEM unsigned long -#define LUAI_MEM long -#endif /* } */ +#define lua_numbertointeger(n,p) \ + ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ + (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ + (*(p) = (LUA_INTEGER)(n), 1)) + + +/* now the variable definitions */ + +#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ + +#define LUA_NUMBER float + +#define l_mathlim(n) (FLT_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.7g" + +#define l_mathop(op) op##f + +#define lua_str2number(s,p) strtof((s), (p)) + + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ + +#define LUA_NUMBER long double + +#define l_mathlim(n) (LDBL_##n) + +#define LUAI_UACNUMBER long double + +#define LUA_NUMBER_FRMLEN "L" +#define LUA_NUMBER_FMT "%.19Lg" + +#define l_mathop(op) op##l + +#define lua_str2number(s,p) strtold((s), (p)) + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ + +#define LUA_NUMBER double + +#define l_mathlim(n) (DBL_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.14g" + +#define l_mathop(op) op + +#define lua_str2number(s,p) strtod((s), (p)) + +#else /* }{ */ + +#error "numeric float type not defined" + +#endif /* } */ + /* -@@ LUAI_MAXSTACK limits the size of the Lua stack. -** CHANGE it if you need a different limit. This limit is arbitrary; -** its only purpose is to stop Lua to consume unlimited stack -** space (and to reserve some numbers for pseudo-indices). +@@ LUA_INTEGER is the integer type used by Lua. +** +@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. +** +@@ LUAI_UACINT is the result of an 'usual argument conversion' +@@ over a lUA_INTEGER. +@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. +@@ LUA_INTEGER_FMT is the format for writing integers. +@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. +@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. +@@ lua_integer2str converts an integer to a string. */ -#if LUAI_BITSINT >= 32 -#define LUAI_MAXSTACK 1000000 -#else -#define LUAI_MAXSTACK 15000 -#endif -/* reserve some space for error handling */ -#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000) +/* The following definitions are good for most cases here */ +#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" +#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n)) +#define LUAI_UACINT LUA_INTEGER /* -@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. -** CHANGE it if it uses too much C-stack space. +** use LUAI_UACINT here to avoid problems with promotions (which +** can turn a comparison between unsigneds into a signed comparison) */ -#define LUAL_BUFFERSIZE BUFSIZ +#define LUA_UNSIGNED unsigned LUAI_UACINT +/* now the variable definitions */ + +#if LUA_INT_TYPE == LUA_INT_INT /* { int */ + +#define LUA_INTEGER int +#define LUA_INTEGER_FRMLEN "" + +#define LUA_MAXINTEGER INT_MAX +#define LUA_MININTEGER INT_MIN + +#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ + +#define LUA_INTEGER long +#define LUA_INTEGER_FRMLEN "l" + +#define LUA_MAXINTEGER LONG_MAX +#define LUA_MININTEGER LONG_MIN + +#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ + +/* use presence of macro LLONG_MAX as proxy for C99 compliance */ +#if defined(LLONG_MAX) /* { */ +/* use ISO C99 stuff */ + +#define LUA_INTEGER long long +#define LUA_INTEGER_FRMLEN "ll" + +#define LUA_MAXINTEGER LLONG_MAX +#define LUA_MININTEGER LLONG_MIN + +#elif defined(LUA_USE_WINDOWS) /* }{ */ +/* in Windows, can use specific Windows types */ + +#define LUA_INTEGER __int64 +#define LUA_INTEGER_FRMLEN "I64" + +#define LUA_MAXINTEGER _I64_MAX +#define LUA_MININTEGER _I64_MIN + +#else /* }{ */ + +#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ + or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" + +#endif /* } */ + +#else /* }{ */ + +#error "numeric integer type not defined" + +#endif /* } */ + +/* }================================================================== */ /* ** {================================================================== -@@ LUA_NUMBER is the type of numbers in Lua. -** CHANGE the following definitions only if you want to build Lua -** with a number type different from double. You may also need to -** change lua_number2int & lua_number2integer. +** Dependencies with C99 and other C details ** =================================================================== */ -#define LUA_NUMBER_DOUBLE -#define LUA_NUMBER double - /* -@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' -@* over a number. +@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. +** (All uses in Lua have only one format item.) */ -#define LUAI_UACNUMBER double +#if !defined(LUA_USE_C89) +#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) +#else +#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) +#endif /* -@@ LUA_NUMBER_SCAN is the format for reading numbers. -@@ LUA_NUMBER_FMT is the format for writing numbers. -@@ lua_number2str converts a number to a string. -@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. +@@ lua_strx2number converts an hexadecimal numeric string to a number. +** In C99, 'strtod' does that conversion. Otherwise, you can +** leave 'lua_strx2number' undefined and Lua will provide its own +** implementation. */ -#define LUA_NUMBER_SCAN "%lf" -#define LUA_NUMBER_FMT "%.14g" -#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) -#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ +#if !defined(LUA_USE_C89) +#define lua_strx2number(s,p) lua_str2number(s,p) +#endif /* -@@ l_mathop allows the addition of an 'l' or 'f' to all math operations +@@ lua_number2strx converts a float to an hexadecimal numeric string. +** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. +** Otherwise, you can leave 'lua_number2strx' undefined and Lua will +** provide its own implementation. */ -#define l_mathop(x) (x) +#if !defined(LUA_USE_C89) +#define lua_number2strx(L,b,sz,f,n) l_sprintf(b,sz,f,n) +#endif /* -@@ lua_str2number converts a decimal numeric string to a number. -@@ lua_strx2number converts an hexadecimal numeric string to a number. -** In C99, 'strtod' does both conversions. C89, however, has no function -** to convert floating hexadecimal strings to numbers. For these -** systems, you can leave 'lua_strx2number' undefined and Lua will -** provide its own implementation. +** 'strtof' and 'opf' variants for math functions are not valid in +** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the +** availability of these variants. ('math.h' is already included in +** all files that use these macros.) */ -#define lua_str2number(s,p) strtod((s), (p)) - -#if defined(LUA_USE_STRTODHEX) -#define lua_strx2number(s,p) strtod((s), (p)) +#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) +#undef l_mathop /* variants not available */ +#undef lua_str2number +#define l_mathop(op) (lua_Number)op /* no variant */ +#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) #endif /* -@@ The luai_num* macros define the primitive operations over numbers. +@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation +** functions. It must be a numerical type; Lua will use 'intptr_t' if +** available, otherwise it will use 'ptrdiff_t' (the nearest thing to +** 'intptr_t' in C89) */ +#define LUA_KCONTEXT ptrdiff_t -/* the following operations need the math library */ -#if defined(lobject_c) || defined(lvm_c) -#include -#define luai_nummod(L,a,b) ((a) - l_mathop(floor)((a)/(b))*(b)) -#define luai_numpow(L,a,b) (l_mathop(pow)(a,b)) +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include +#if defined(INTPTR_MAX) /* even in C99 this type is optional */ +#undef LUA_KCONTEXT +#define LUA_KCONTEXT intptr_t #endif - -/* these are quite standard operations */ -#if defined(LUA_CORE) -#define luai_numadd(L,a,b) ((a)+(b)) -#define luai_numsub(L,a,b) ((a)-(b)) -#define luai_nummul(L,a,b) ((a)*(b)) -#define luai_numdiv(L,a,b) ((a)/(b)) -#define luai_numunm(L,a) (-(a)) -#define luai_numeq(a,b) ((a)==(b)) -#define luai_numlt(L,a,b) ((a)<(b)) -#define luai_numle(L,a,b) ((a)<=(b)) -#define luai_numisnan(L,a) (!luai_numeq((a), (a))) #endif - /* -@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. -** CHANGE that if ptrdiff_t is not adequate on your machine. (On most -** machines, ptrdiff_t gives a good choice between int or long.) +@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). +** Change that if you do not want to use C locales. (Code using this +** macro must include header 'locale.h'.) */ -#define LUA_INTEGER ptrdiff_t - -/* -@@ LUA_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned. -** It must have at least 32 bits. -*/ -#define LUA_UNSIGNED unsigned LUA_INT32 +#if !defined(lua_getlocaledecpoint) +#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif +/* }================================================================== */ /* -** Some tricks with doubles +** {================================================================== +** Language Variations +** ===================================================================== */ -#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ /* -** The next definitions activate some tricks to speed up the -** conversion from doubles to integer types, mainly to LUA_UNSIGNED. -** -@@ LUA_MSASMTRICK uses Microsoft assembler to avoid clashes with a -** DirectX idiosyncrasy. -** -@@ LUA_IEEE754TRICK uses a trick that should work on any machine -** using IEEE754 with a 32-bit integer type. -** -@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be -** defined when LUA_INTEGER is a 32-bit integer. -** -@@ LUA_IEEEENDIAN is the endianness of doubles in your machine -** (0 for little endian, 1 for big endian); if not defined, Lua will -** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK). -** -@@ LUA_NANTRICK controls the use of a trick to pack all types into -** a single double value, using NaN values to represent non-number -** values. The trick only works on 32-bit machines (ints and pointers -** are 32-bit values) with numbers represented as IEEE 754-2008 doubles -** with conventional endianess (12345678 or 87654321), in CPUs that do -** not produce signaling NaN values (all NaNs are quiet). +@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some +** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from +** numbers to strings. Define LUA_NOCVTS2N to turn off automatic +** coercion from strings to numbers. */ +/* #define LUA_NOCVTN2S */ +/* #define LUA_NOCVTS2N */ -/* Microsoft compiler on a Pentium (32 bit) ? */ -#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ - -#define LUA_MSASMTRICK -#define LUA_IEEEENDIAN 0 -#define LUA_NANTRICK +/* +@@ LUA_USE_APICHECK turns on several consistency checks on the C API. +** Define it as a help when debugging C code. +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(l,e) assert(e) +#endif -/* pentium 32 bits? */ -#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ +/* }================================================================== */ -#define LUA_IEEE754TRICK -#define LUA_IEEELL -#define LUA_IEEEENDIAN 0 -#define LUA_NANTRICK -/* pentium 64 bits? */ -#elif defined(__x86_64) /* }{ */ +/* +** {================================================================== +** Macros that affect the API and must be stable (that is, must be the +** same when you compile Lua and when you compile code that links to +** Lua). You probably do not want/need to change them. +** ===================================================================== +*/ -#define LUA_IEEE754TRICK -#define LUA_IEEEENDIAN 0 +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua from consuming unlimited stack +** space (and to reserve some numbers for pseudo-indices). +*/ +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif -#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */ -#define LUA_IEEE754TRICK -#define LUA_IEEEENDIAN 1 +/* +@@ LUA_EXTRASPACE defines the size of a raw memory area associated with +** a Lua state with very fast access. +** CHANGE it if you need a different size. +*/ +#define LUA_EXTRASPACE (sizeof(void *)) -#else /* }{ */ -/* assume IEEE754 and a 32-bit integer type */ -#define LUA_IEEE754TRICK +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +@@ of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 -#endif /* } */ -#endif /* } */ +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +** CHANGE it if it uses too much C-stack space. (For long double, +** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a +** smaller buffer would force a memory allocation for each call to +** 'string.format'.) +*/ +#if defined(LUA_FLOAT_LONGDOUBLE) +#define LUAL_BUFFERSIZE 8192 +#else +#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) +#endif /* }================================================================== */ +/* +@@ LUA_QL describes how error messages quote program elements. +** Lua does not use these macros anymore; they are here for +** compatibility only. +*/ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") + + /* =================================================================== */ @@ -547,5 +761,7 @@ #define LUA_USE_SHARED_PROTO + + #endif diff --git a/deps/lua/lualib.h b/deps/lua/lualib.h index 4dcc53f..6544e97 100644 --- a/deps/lua/lualib.h +++ b/deps/lua/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.43.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -29,6 +29,9 @@ LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" LUAMOD_API int (luaopen_string) (lua_State *L); +#define LUA_UTF8LIBNAME "utf8" +LUAMOD_API int (luaopen_utf8) (lua_State *L); + #define LUA_BITLIBNAME "bit32" LUAMOD_API int (luaopen_bit32) (lua_State *L); diff --git a/deps/lua/lundump.c b/deps/lua/lundump.c index e47b29b..7cbf311 100644 --- a/deps/lua/lundump.c +++ b/deps/lua/lundump.c @@ -1,14 +1,17 @@ /* -** $Id: lundump.c,v 2.22.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ -#include - #define lundump_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "ldebug.h" @@ -20,244 +23,261 @@ #include "lundump.h" #include "lzio.h" + +#if !defined(luai_verifycode) +#define luai_verifycode(L,b,f) /* empty */ +#endif + + typedef struct { - lua_State* L; - ZIO* Z; - Mbuffer* b; - const char* name; + lua_State *L; + ZIO *Z; + const char *name; } LoadState; -static l_noret error(LoadState* S, const char* why) -{ - luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why); - luaD_throw(S->L,LUA_ERRSYNTAX); + +static l_noret error(LoadState *S, const char *why) { + luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); + luaD_throw(S->L, LUA_ERRSYNTAX); } -#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) -#define LoadByte(S) (lu_byte)LoadChar(S) -#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) -#define LoadVector(S,b,n,size) LoadMem(S,b,n,size) -#if !defined(luai_verifycode) -#define luai_verifycode(L,b,f) /* empty */ -#endif +/* +** All high-level loads go through LoadVector; you can change it to +** adapt to the endianness of the input +*/ +#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) + +static void LoadBlock (LoadState *S, void *b, size_t size) { + if (luaZ_read(S->Z, b, size) != 0) + error(S, "truncated"); +} + -static void LoadBlock(LoadState* S, void* b, size_t size) -{ - if (luaZ_read(S->Z,b,size)!=0) error(S,"truncated"); +#define LoadVar(S,x) LoadVector(S,&x,1) + + +static lu_byte LoadByte (LoadState *S) { + lu_byte x; + LoadVar(S, x); + return x; } -static int LoadChar(LoadState* S) -{ - char x; - LoadVar(S,x); - return x; + +static int LoadInt (LoadState *S) { + int x; + LoadVar(S, x); + return x; } -static int LoadInt(LoadState* S) -{ - int x; - LoadVar(S,x); - if (x<0) error(S,"corrupted"); - return x; + +static lua_Number LoadNumber (LoadState *S) { + lua_Number x; + LoadVar(S, x); + return x; } -static lua_Number LoadNumber(LoadState* S) -{ - lua_Number x; - LoadVar(S,x); - return x; + +static lua_Integer LoadInteger (LoadState *S) { + lua_Integer x; + LoadVar(S, x); + return x; } #if defined(LoadString) #undef LoadString #endif -static TString* LoadString(LoadState* S) -{ - size_t size; - LoadVar(S,size); - if (size==0) - return NULL; - else - { - char* s=luaZ_openspace(S->L,S->b,size); - LoadBlock(S,s,size*sizeof(char)); - return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ - } +static TString *LoadString (LoadState *S) { + size_t size = LoadByte(S); + if (size == 0xFF) + LoadVar(S, size); + if (size == 0) + return NULL; + else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ + char buff[LUAI_MAXSHORTLEN]; + LoadVector(S, buff, size); + return luaS_newlstr(S->L, buff, size); + } + else { /* long string */ + TString *ts = luaS_createlngstrobj(S->L, size); + LoadVector(S, getstr(ts), size); /* load directly in final place */ + return ts; + } +} + + +static void LoadCode (LoadState *S, SharedProto *f) { + int n = LoadInt(S); + f->code = luaM_newvector(S->L, n, Instruction); + f->sizecode = n; + LoadVector(S, f->code, n); } -static void LoadCode(LoadState* S, SharedProto* f) -{ - int n=LoadInt(S); - f->code=luaM_newvector(S->L,n,Instruction); - f->sizecode=n; - LoadVector(S,f->code,n,sizeof(Instruction)); + +static void LoadFunction(LoadState *S, Proto *f, TString *psource); + + +static void LoadConstants (LoadState *S, Proto *f) { + int i; + int n = LoadInt(S); + f->k = luaM_newvector(S->L, n, TValue); + f->sp->sizek = n; + for (i = 0; i < n; i++) + setnilvalue(&f->k[i]); + for (i = 0; i < n; i++) { + TValue *o = &f->k[i]; + int t = LoadByte(S); + switch (t) { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o, LoadByte(S)); + break; + case LUA_TNUMFLT: + setfltvalue(o, LoadNumber(S)); + break; + case LUA_TNUMINT: + setivalue(o, LoadInteger(S)); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + setsvalue2n(S->L, o, LoadString(S)); + break; + default: + lua_assert(0); + } + } } -static void LoadFunction(LoadState* S, Proto* f); - -static void LoadConstants(LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - f->k=luaM_newvector(S->L,n,TValue); - f->sp->sizek=n; - for (i=0; ik[i]); - for (i=0; ik[i]; - int t=LoadChar(S); - switch (t) - { - case LUA_TNIL: - setnilvalue(o); - break; - case LUA_TBOOLEAN: - setbvalue(o,LoadChar(S)); - break; - case LUA_TNUMBER: - setnvalue(o,LoadNumber(S)); - break; - case LUA_TSTRING: - setsvalue2n(S->L,o,LoadString(S)); - break; - default: lua_assert(0); + +static void LoadProtos (LoadState *S, Proto *f) { + int i; + int n = LoadInt(S); + f->p = luaM_newvector(S->L, n, Proto *); + f->sp->sizep = n; + for (i = 0; i < n; i++) + f->p[i] = NULL; + for (i = 0; i < n; i++) { + f->p[i] = luaF_newproto(S->L, NULL); + LoadFunction(S, f->p[i], f->sp->source); } - } - n=LoadInt(S); - f->p=luaM_newvector(S->L,n,Proto*); - f->sp->sizep=n; - for (i=0; ip[i]=NULL; - for (i=0; ip[i]=luaF_newproto(S->L, NULL); - LoadFunction(S,f->p[i]); - } } -static void LoadUpvalues(LoadState* S, SharedProto* f) -{ - int i,n; - n=LoadInt(S); - f->upvalues=luaM_newvector(S->L,n,Upvaldesc); - f->sizeupvalues=n; - for (i=0; iupvalues[i].name=NULL; - for (i=0; iupvalues[i].instack=LoadByte(S); - f->upvalues[i].idx=LoadByte(S); - } + +static void LoadUpvalues (LoadState *S, SharedProto *f) { + int i, n; + n = LoadInt(S); + f->upvalues = luaM_newvector(S->L, n, Upvaldesc); + f->sizeupvalues = n; + for (i = 0; i < n; i++) + f->upvalues[i].name = NULL; + for (i = 0; i < n; i++) { + f->upvalues[i].instack = LoadByte(S); + f->upvalues[i].idx = LoadByte(S); + } } -static void LoadDebug(LoadState* S, SharedProto* f) -{ - int i,n; - f->source=LoadString(S); - n=LoadInt(S); - f->lineinfo=luaM_newvector(S->L,n,int); - f->sizelineinfo=n; - LoadVector(S,f->lineinfo,n,sizeof(int)); - n=LoadInt(S); - f->locvars=luaM_newvector(S->L,n,LocVar); - f->sizelocvars=n; - for (i=0; ilocvars[i].varname=NULL; - for (i=0; ilocvars[i].varname=LoadString(S); - f->locvars[i].startpc=LoadInt(S); - f->locvars[i].endpc=LoadInt(S); - } - n=LoadInt(S); - for (i=0; iupvalues[i].name=LoadString(S); + +static void LoadDebug (LoadState *S, SharedProto *f) { + int i, n; + n = LoadInt(S); + f->lineinfo = luaM_newvector(S->L, n, int); + f->sizelineinfo = n; + LoadVector(S, f->lineinfo, n); + n = LoadInt(S); + f->locvars = luaM_newvector(S->L, n, LocVar); + f->sizelocvars = n; + for (i = 0; i < n; i++) + f->locvars[i].varname = NULL; + for (i = 0; i < n; i++) { + f->locvars[i].varname = LoadString(S); + f->locvars[i].startpc = LoadInt(S); + f->locvars[i].endpc = LoadInt(S); + } + n = LoadInt(S); + for (i = 0; i < n; i++) + f->upvalues[i].name = LoadString(S); } -static void LoadFunction(LoadState* S, Proto* f) -{ - SharedProto *sp = f->sp; - sp->linedefined=LoadInt(S); - sp->lastlinedefined=LoadInt(S); - sp->numparams=LoadByte(S); - sp->is_vararg=LoadByte(S); - sp->maxstacksize=LoadByte(S); - LoadCode(S,sp); - LoadConstants(S,f); - LoadUpvalues(S,sp); - LoadDebug(S,sp); + +static void LoadFunction (LoadState *S, Proto *fp, TString *psource) { + SharedProto *f = fp->sp; + f->source = LoadString(S); + if (f->source == NULL) /* no source in dump? */ + f->source = psource; /* reuse parent's source */ + f->linedefined = LoadInt(S); + f->lastlinedefined = LoadInt(S); + f->numparams = LoadByte(S); + f->is_vararg = LoadByte(S); + f->maxstacksize = LoadByte(S); + LoadCode(S, f); + LoadConstants(S, fp); + LoadUpvalues(S, f); + LoadProtos(S, fp); + LoadDebug(S, f); } -/* the code below must be consistent with the code in luaU_header */ -#define N0 LUAC_HEADERSIZE -#define N1 (sizeof(LUA_SIGNATURE)-sizeof(char)) -#define N2 N1+2 -#define N3 N2+6 - -static void LoadHeader(LoadState* S) -{ - lu_byte h[LUAC_HEADERSIZE]; - lu_byte s[LUAC_HEADERSIZE]; - luaU_header(h); - memcpy(s,h,sizeof(char)); /* first char already read */ - LoadBlock(S,s+sizeof(char),LUAC_HEADERSIZE-sizeof(char)); - if (memcmp(h,s,N0)==0) return; - if (memcmp(h,s,N1)!=0) error(S,"not a"); - if (memcmp(h,s,N2)!=0) error(S,"version mismatch in"); - if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted"); + +static void checkliteral (LoadState *S, const char *s, const char *msg) { + char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ + size_t len = strlen(s); + LoadVector(S, buff, len); + if (memcmp(s, buff, len) != 0) + error(S, msg); } -/* -** load precompiled chunk -*/ -Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) -{ - LoadState S; - Closure* cl; - if (*name=='@' || *name=='=') - S.name=name+1; - else if (*name==LUA_SIGNATURE[0]) - S.name="binary string"; - else - S.name=name; - S.L=L; - S.Z=Z; - S.b=buff; - LoadHeader(&S); - cl=luaF_newLclosure(L,1); - setclLvalue(L,L->top,cl); incr_top(L); - cl->l.p=luaF_newproto(L, NULL); - LoadFunction(&S,cl->l.p); - if (cl->l.p->sp->sizeupvalues != 1) - { - Proto* p=cl->l.p; - cl=luaF_newLclosure(L,cl->l.p->sp->sizeupvalues); - cl->l.p=p; - setclLvalue(L,L->top-1,cl); - } - luai_verifycode(L,buff,cl->l.p); - return cl; + +static void fchecksize (LoadState *S, size_t size, const char *tname) { + if (LoadByte(S) != size) + error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); +} + + +#define checksize(S,t) fchecksize(S,sizeof(t),#t) + +static void checkHeader (LoadState *S) { + checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ + if (LoadByte(S) != LUAC_VERSION) + error(S, "version mismatch in"); + if (LoadByte(S) != LUAC_FORMAT) + error(S, "format mismatch in"); + checkliteral(S, LUAC_DATA, "corrupted"); + checksize(S, int); + checksize(S, size_t); + checksize(S, Instruction); + checksize(S, lua_Integer); + checksize(S, lua_Number); + if (LoadInteger(S) != LUAC_INT) + error(S, "endianness mismatch in"); + if (LoadNumber(S) != LUAC_NUM) + error(S, "float format mismatch in"); } -#define MYINT(s) (s[0]-'0') -#define VERSION MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR) -#define FORMAT 0 /* this is the official format */ /* -* make header for precompiled chunks -* if you change the code below be sure to update LoadHeader and FORMAT above -* and LUAC_HEADERSIZE in lundump.h +** load precompiled chunk */ -void luaU_header (lu_byte* h) -{ - int x=1; - memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-sizeof(char)); - h+=sizeof(LUA_SIGNATURE)-sizeof(char); - *h++=cast_byte(VERSION); - *h++=cast_byte(FORMAT); - *h++=cast_byte(*(char*)&x); /* endianness */ - *h++=cast_byte(sizeof(int)); - *h++=cast_byte(sizeof(size_t)); - *h++=cast_byte(sizeof(Instruction)); - *h++=cast_byte(sizeof(lua_Number)); - *h++=cast_byte(((lua_Number)0.5)==0); /* is lua_Number integral? */ - memcpy(h,LUAC_TAIL,sizeof(LUAC_TAIL)-sizeof(char)); +LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { + LoadState S; + LClosure *cl; + if (*name == '@' || *name == '=') + S.name = name + 1; + else if (*name == LUA_SIGNATURE[0]) + S.name = "binary string"; + else + S.name = name; + S.L = L; + S.Z = Z; + checkHeader(&S); + cl = luaF_newLclosure(L, LoadByte(&S)); + setclLvalue(L, L->top, cl); + luaD_inctop(L); + cl->p = luaF_newproto(L, NULL); + LoadFunction(&S, cl->p, NULL); + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luai_verifycode(L, buff, cl->p); + return cl; } + diff --git a/deps/lua/lundump.h b/deps/lua/lundump.h index 5255db2..aa5cc82 100644 --- a/deps/lua/lundump.h +++ b/deps/lua/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.39.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -7,22 +7,26 @@ #ifndef lundump_h #define lundump_h +#include "llimits.h" #include "lobject.h" #include "lzio.h" -/* load one chunk; from lundump.c */ -LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); -/* make header; from lundump.c */ -LUAI_FUNC void luaU_header (lu_byte* h); +/* data to catch conversion errors */ +#define LUAC_DATA "\x19\x93\r\n\x1a\n" -/* dump one chunk; from ldump.c */ -LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); +#define LUAC_INT 0x5678 +#define LUAC_NUM cast_num(370.5) -/* data to catch conversion errors */ -#define LUAC_TAIL "\x19\x93\r\n\x1a\n" +#define MYINT(s) (s[0]-'0') +#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) +#define LUAC_FORMAT 0 /* this is the official format */ -/* size in bytes of header of binary files */ -#define LUAC_HEADERSIZE (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char)) +/* load one chunk; from lundump.c */ +LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, + void* data, int strip); #endif diff --git a/deps/lua/lutf8lib.c b/deps/lua/lutf8lib.c new file mode 100644 index 0000000..9042582 --- /dev/null +++ b/deps/lua/lutf8lib.c @@ -0,0 +1,256 @@ +/* +** $Id: lutf8lib.c,v 1.15 2015/03/28 19:16:55 roberto Exp $ +** Standard library for UTF-8 manipulation +** See Copyright Notice in lua.h +*/ + +#define lutf8lib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +#define MAXUNICODE 0x10FFFF + +#define iscont(p) ((*(p) & 0xC0) == 0x80) + + +/* from strlib */ +/* translate a relative string position: negative means back from end */ +static lua_Integer u_posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +/* +** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. +*/ +static const char *utf8_decode (const char *o, int *val) { + static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; + const unsigned char *s = (const unsigned char *)o; + unsigned int c = s[0]; + unsigned int res = 0; /* final result */ + if (c < 0x80) /* ascii? */ + res = c; + else { + int count = 0; /* to count number of continuation bytes */ + while (c & 0x40) { /* still have continuation bytes? */ + int cc = s[++count]; /* read next byte */ + if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ + return NULL; /* invalid byte sequence */ + res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ + c <<= 1; /* to test next bit */ + } + res |= ((c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 3 || res > MAXUNICODE || res <= limits[count]) + return NULL; /* invalid byte sequence */ + s += count; /* skip continuation bytes read */ + } + if (val) *val = res; + return (const char *)s + 1; /* +1 to include first byte */ +} + + +/* +** utf8len(s [, i [, j]]) --> number of characters that start in the +** range [i,j], or nil + current position if 's' is not well formed in +** that interval +*/ +static int utflen (lua_State *L) { + int n = 0; + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, + "initial position out of string"); + luaL_argcheck(L, --posj < (lua_Integer)len, 3, + "final position out of string"); + while (posi <= posj) { + const char *s1 = utf8_decode(s + posi, NULL); + if (s1 == NULL) { /* conversion error? */ + lua_pushnil(L); /* return nil ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s1 - s; + n++; + } + lua_pushinteger(L, n); + return 1; +} + + +/* +** codepoint(s, [i, [j]]) -> returns codepoints for all characters +** that start in the range [i,j] +*/ +static int codepoint (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int n; + const char *se; + luaL_argcheck(L, posi >= 1, 2, "out of range"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + n = 0; + se = s + pose; + for (s += posi - 1; s < se;) { + int code; + s = utf8_decode(s, &code); + if (s == NULL) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, code); + n++; + } + return n; +} + + +static void pushutfchar (lua_State *L, int arg) { + lua_Integer code = luaL_checkinteger(L, arg); + luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); + lua_pushfstring(L, "%U", (long)code); +} + + +/* +** utfchar(n1, n2, ...) -> char(n1)..char(n2)... +*/ +static int utfchar (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + if (n == 1) /* optimize common case of single char */ + pushutfchar(L, 1); + else { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i = 1; i <= n; i++) { + pushutfchar(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + } + return 1; +} + + +/* +** offset(s, n, [i]) -> index where n-th character counting from +** position 'i' starts; 0 means character at 'i'. +*/ +static int byteoffset (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = luaL_checkinteger(L, 2); + lua_Integer posi = (n >= 0) ? 1 : len + 1; + posi = u_posrelat(luaL_optinteger(L, 3, posi), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, + "position out of range"); + if (n == 0) { + /* find beginning of current byte sequence */ + while (posi > 0 && iscont(s + posi)) posi--; + } + else { + if (iscont(s + posi)) + luaL_error(L, "initial position is a continuation byte"); + if (n < 0) { + while (n < 0 && posi > 0) { /* move back */ + do { /* find beginning of previous character */ + posi--; + } while (posi > 0 && iscont(s + posi)); + n++; + } + } + else { + n--; /* do not move for 1st character */ + while (n > 0 && posi < (lua_Integer)len) { + do { /* find beginning of next character */ + posi++; + } while (iscont(s + posi)); /* (cannot pass final '\0') */ + n--; + } + } + } + if (n == 0) /* did it find given character? */ + lua_pushinteger(L, posi + 1); + else /* no such character */ + lua_pushnil(L); + return 1; +} + + +static int iter_aux (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = lua_tointeger(L, 2) - 1; + if (n < 0) /* first iteration? */ + n = 0; /* start from here */ + else if (n < (lua_Integer)len) { + n++; /* skip current byte */ + while (iscont(s + n)) n++; /* and its continuations */ + } + if (n >= (lua_Integer)len) + return 0; /* no more codepoints */ + else { + int code; + const char *next = utf8_decode(s + n, &code); + if (next == NULL || iscont(next)) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, code); + return 2; + } +} + + +static int iter_codes (lua_State *L) { + luaL_checkstring(L, 1); + lua_pushcfunction(L, iter_aux); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; +} + + +/* pattern to match a single UTF-8 character */ +#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" + + +static const luaL_Reg funcs[] = { + {"offset", byteoffset}, + {"codepoint", codepoint}, + {"char", utfchar}, + {"len", utflen}, + {"codes", iter_codes}, + /* placeholders */ + {"charpattern", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_utf8 (lua_State *L) { + luaL_newlib(L, funcs); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); + lua_setfield(L, -2, "charpattern"); + return 1; +} + diff --git a/deps/lua/lvm.c b/deps/lua/lvm.c index 43019d4..34293ee 100644 --- a/deps/lua/lvm.c +++ b/deps/lua/lvm.c @@ -1,17 +1,21 @@ /* -** $Id: lvm.c,v 2.155.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lvm.c,v 2.265 2015/11/23 11:30:45 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ +#define lvm_c +#define LUA_CORE + +#include "lprefix.h" +#include +#include +#include #include #include #include -#define lvm_c -#define LUA_CORE - #include "lua.h" #include "ldebug.h" @@ -27,304 +31,465 @@ #include "lvm.h" - /* limit for table tag-method chains (to avoid loops) */ -#define MAXTAGLOOP 100 +#define MAXTAGLOOP 2000 -const TValue *luaV_tonumber (const TValue *obj, TValue *n) { - lua_Number num; - if (ttisnumber(obj)) return obj; - if (ttisstring(obj) && luaO_str2d(svalue(obj), tsvalue(obj)->len, &num)) { - setnvalue(n, num); - return n; - } - else - return NULL; -} +/* +** 'l_intfitsf' checks whether a given integer can be converted to a +** float without rounding. Used in comparisons. Left undefined if +** all integers fit in a float precisely. +*/ +#if !defined(l_intfitsf) -int luaV_tostring (lua_State *L, StkId obj) { - if (!ttisnumber(obj)) - return 0; - else { - char s[LUAI_MAXNUMBER2STR]; - lua_Number n = nvalue(obj); - int l = lua_number2str(s, n); - setsvalue2s(L, obj, luaS_newlstr(L, s, l)); +/* number of bits in the mantissa of a float */ +#define NBM (l_mathlim(MANT_DIG)) + +/* +** Check whether some integers may not fit in a float, that is, whether +** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger). +** (The shifts are done in parts to avoid shifting by more than the size +** of an integer. In a worst case, NBM == 113 for long double and +** sizeof(integer) == 32.) +*/ +#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \ + >> (NBM - (3 * (NBM / 4)))) > 0 + +#define l_intfitsf(i) \ + (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM)) + +#endif + +#endif + + + +/* +** Try to convert a value to a float. The float case is already handled +** by the macro 'tonumber'. +*/ +int luaV_tonumber_ (const TValue *obj, lua_Number *n) { + TValue v; + if (ttisinteger(obj)) { + *n = cast_num(ivalue(obj)); + return 1; + } + else if (cvt2num(obj) && /* string convertible to number? */ + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { + *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ return 1; } + else + return 0; /* conversion failed */ } -static void traceexec (lua_State *L) { - CallInfo *ci = L->ci; - lu_byte mask = L->hookmask; - int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); - if (counthook) - resethookcount(L); /* reset count */ - if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ - ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ - return; /* do not call hook again (VM yielded, so it did not move) */ +/* +** try to convert a value to an integer, rounding according to 'mode': +** mode == 0: accepts only integral values +** mode == 1: takes the floor of the number +** mode == 2: takes the ceil of the number +*/ +int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { + TValue v; + again: + if (ttisfloat(obj)) { + lua_Number n = fltvalue(obj); + lua_Number f = l_floor(n); + if (n != f) { /* not an integral value? */ + if (mode == 0) return 0; /* fails if mode demands integral value */ + else if (mode > 1) /* needs ceil? */ + f += 1; /* convert floor to ceil (remember: n != f) */ + } + return lua_numbertointeger(f, p); } - if (counthook) - luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ - if (mask & LUA_MASKLINE) { - Proto *p = ci_func(ci)->p; - int npc = pcRel(ci->u.l.savedpc, p); - int newline = getfuncline(p, npc); - if (npc == 0 || /* call linehook when enter a new function, */ - ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ - newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ - luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ + else if (ttisinteger(obj)) { + *p = ivalue(obj); + return 1; } - L->oldpc = ci->u.l.savedpc; - if (L->status == LUA_YIELD) { /* did hook yield? */ - if (counthook) - L->hookcount = 1; /* undo decrement to zero */ - ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ - ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ - ci->func = L->top - 1; /* protect stack below results */ - luaD_throw(L, LUA_YIELD); + else if (cvt2num(obj) && + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { + obj = &v; + goto again; /* convert result from 'luaO_str2num' to an integer */ } + return 0; /* conversion failed */ } -static void callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, TValue *p3, int hasres) { - ptrdiff_t result = savestack(L, p3); - setobj2s(L, L->top++, f); /* push function */ - setobj2s(L, L->top++, p1); /* 1st argument */ - setobj2s(L, L->top++, p2); /* 2nd argument */ - if (!hasres) /* no result? 'p3' is third argument */ - setobj2s(L, L->top++, p3); /* 3rd argument */ - /* metamethod may yield only when called from Lua code */ - luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); - if (hasres) { /* if has result, move it to its place */ - p3 = restorestack(L, result); - setobjs2s(L, p3, --L->top); +/* +** Try to convert a 'for' limit to an integer, preserving the +** semantics of the loop. +** (The following explanation assumes a non-negative step; it is valid +** for negative steps mutatis mutandis.) +** If the limit can be converted to an integer, rounding down, that is +** it. +** Otherwise, check whether the limit can be converted to a number. If +** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, +** which means no limit. If the number is too negative, the loop +** should not run, because any initial integer value is larger than the +** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects +** the extreme case when the initial value is LUA_MININTEGER, in which +** case the LUA_MININTEGER limit would still run the loop once. +*/ +static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, + int *stopnow) { + *stopnow = 0; /* usually, let loops run */ + if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ + lua_Number n; /* try to convert to float */ + if (!tonumber(obj, &n)) /* cannot convert to float? */ + return 0; /* not a number */ + if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ + *p = LUA_MAXINTEGER; + if (step < 0) *stopnow = 1; + } + else { /* float is smaller than min integer */ + *p = LUA_MININTEGER; + if (step >= 0) *stopnow = 1; + } } + return 1; } -void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { - int loop; +/* +** Complete a table access: if 't' is a table, 'tm' has its metamethod; +** otherwise, 'tm' is NULL. +*/ +void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, + const TValue *tm) { + int loop; /* counter to avoid infinite loops */ + lua_assert(tm != NULL || !ttistable(t)); for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - const TValue *res = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(res) || /* result is not nil? */ - (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ - setobj2s(L, val, res); - return; - } - /* else will try the tag method */ + if (tm == NULL) { /* no metamethod (from a table)? */ + if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + luaG_typeerror(L, t, "index"); /* no metamethod */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTM(L, tm, t, key, val, 1); + if (ttisfunction(tm)) { /* metamethod is a function */ + luaT_callTM(L, tm, t, key, val, 1); /* call it */ + return; + } + t = tm; /* else repeat access over 'tm' */ + if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ + setobj2s(L, val, tm); /* done */ return; } - t = tm; /* else repeat with 'tm' */ + /* else repeat */ } - luaG_runerror(L, "loop in gettable"); + luaG_runerror(L, "gettable chain too long; possible loop"); } -void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { - int loop; +/* +** Main function for table assignment (invoking metamethods if needed). +** Compute 't[key] = val' +*/ +void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *oldval) { + int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - TValue *oldval = cast(TValue *, luaH_get(h, key)); - /* if previous value is not nil, there must be a previous entry - in the table; moreover, a metamethod has no relevance */ - if (!ttisnil(oldval) || - /* previous value is nil; must check the metamethod */ - ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && + if (oldval != NULL) { + lua_assert(ttistable(t) && ttisnil(oldval)); + /* must check the metamethod */ + if ((tm = fasttm(L, hvalue(t)->metatable, TM_NEWINDEX)) == NULL && /* no metamethod; is there a previous entry in the table? */ (oldval != luaO_nilobject || /* no previous entry; must create one. (The next test is always true; we only need the assignment.) */ - (oldval = luaH_newkey(L, h, key), 1)))) { + (oldval = luaH_newkey(L, hvalue(t), key), 1))) { /* no metamethod and (now) there is an entry with given key */ - setobj2t(L, oldval, val); /* assign new value to that entry */ - invalidateTMcache(h); - luaC_barrierback(L, obj2gco(h), val); + setobj2t(L, cast(TValue *, oldval), val); + invalidateTMcache(hvalue(t)); + luaC_barrierback(L, hvalue(t), val); return; } /* else will try the metamethod */ } - else /* not a table; check metamethod */ + else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); - /* there is a metamethod */ + } + /* try the metamethod */ if (ttisfunction(tm)) { - callTM(L, tm, t, key, val, 0); + luaT_callTM(L, tm, t, key, val, 0); return; } - t = tm; /* else repeat with 'tm' */ + t = tm; /* else repeat assignment over 'tm' */ + if (luaV_fastset(L, t, key, oldval, luaH_get, val)) + return; /* done */ + /* else loop */ } - luaG_runerror(L, "loop in settable"); + luaG_runerror(L, "settable chain too long; possible loop"); } -static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event) { - const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ - if (ttisnil(tm)) - tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ - if (ttisnil(tm)) return 0; - callTM(L, tm, p1, p2, res, 1); - return 1; +/* +** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- +** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. +** The code is a little tricky because it allows '\0' in the strings +** and it uses 'strcoll' (to respect locales) for each segments +** of the strings. +*/ +static int l_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = tsslen(ls); + const char *r = getstr(rs); + size_t lr = tsslen(rs); + for (;;) { /* for each segment */ + int temp = strcoll(l, r); + if (temp != 0) /* not equal? */ + return temp; /* done */ + else { /* strings are equal up to a '\0' */ + size_t len = strlen(l); /* index of first '\0' in both strings */ + if (len == lr) /* 'rs' is finished? */ + return (len == ll) ? 0 : 1; /* check 'ls' */ + else if (len == ll) /* 'ls' is finished? */ + return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ + /* both strings longer than 'len'; go on comparing after the '\0' */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } } -static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2, - TMS event) { - const TValue *tm1 = fasttm(L, mt1, event); - const TValue *tm2; - if (tm1 == NULL) return NULL; /* no metamethod */ - if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ - tm2 = fasttm(L, mt2, event); - if (tm2 == NULL) return NULL; /* no metamethod */ - if (luaV_rawequalobj(tm1, tm2)) /* same metamethods? */ - return tm1; - return NULL; +/* +** Check whether integer 'i' is less than float 'f'. If 'i' has an +** exact representation as a float ('l_intfitsf'), compare numbers as +** floats. Otherwise, if 'f' is outside the range for integers, result +** is trivial. Otherwise, compare them as integers. (When 'i' has no +** float representation, either 'f' is "far away" from 'i' or 'f' has +** no precision left for a fractional part; either way, how 'f' is +** truncated is irrelevant.) When 'f' is NaN, comparisons must result +** in false. +*/ +static int LTintfloat (lua_Integer i, lua_Number f) { +#if defined(l_intfitsf) + if (!l_intfitsf(i)) { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ + return (i < cast(lua_Integer, f)); /* compare them as integers */ + else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ + return 0; + } +#endif + return luai_numlt(cast_num(i), f); /* compare them as floats */ } -static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, - TMS event) { - if (!call_binTM(L, p1, p2, L->top, event)) - return -1; /* no metamethod */ - else - return !l_isfalse(L->top); +/* +** Check whether integer 'i' is less than or equal to float 'f'. +** See comments on previous function. +*/ +static int LEintfloat (lua_Integer i, lua_Number f) { +#if defined(l_intfitsf) + if (!l_intfitsf(i)) { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ + return (i <= cast(lua_Integer, f)); /* compare them as integers */ + else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ + return 0; + } +#endif + return luai_numle(cast_num(i), f); /* compare them as floats */ } -static int l_strcmp (const TString *ls, const TString *rs) { - const char *l = getstr(ls); - size_t ll = ls->tsv.len; - const char *r = getstr(rs); - size_t lr = rs->tsv.len; - for (;;) { - int temp = strcoll(l, r); - if (temp != 0) return temp; - else { /* strings are equal up to a `\0' */ - size_t len = strlen(l); /* index of first `\0' in both strings */ - if (len == lr) /* r is finished? */ - return (len == ll) ? 0 : 1; - else if (len == ll) /* l is finished? */ - return -1; /* l is smaller than r (because r is not finished) */ - /* both strings longer than `len'; go on comparing (after the `\0') */ - len++; - l += len; ll -= len; r += len; lr -= len; - } +/* +** Return 'l < r', for numbers. +*/ +static int LTnum (const TValue *l, const TValue *r) { + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li < ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LTintfloat(li, fltvalue(r)); /* l < r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numlt(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN < i is always false */ + else /* without NaN, (l < r) <--> not(r <= l) */ + return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ } } +/* +** Return 'l <= r', for numbers. +*/ +static int LEnum (const TValue *l, const TValue *r) { + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li <= ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LEintfloat(li, fltvalue(r)); /* l <= r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numle(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN <= i is always false */ + else /* without NaN, (l <= r) <--> not(r < l) */ + return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ + } +} + + +/* +** Main operation less than; return 'l < r'. +*/ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; - if (ttisnumber(l) && ttisnumber(r)) - return luai_numlt(L, nvalue(l), nvalue(r)); - else if (ttisstring(l) && ttisstring(r)) - return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; - else if ((res = call_orderTM(L, l, r, TM_LT)) < 0) - luaG_ordererror(L, l, r); + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LTnum(l, r); + else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) < 0; + else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ + luaG_ordererror(L, l, r); /* error */ return res; } +/* +** Main operation less than or equal to; return 'l <= r'. If it needs +** a metamethod and there is no '__le', try '__lt', based on +** l <= r iff !(r < l) (assuming a total order). If the metamethod +** yields during this substitution, the continuation has to know +** about it (to negate the result of r= 0) /* first try `le' */ + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LEnum(l, r); + else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; + else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */ return res; - else if ((res = call_orderTM(L, r, l, TM_LT)) < 0) /* else try `lt' */ - luaG_ordererror(L, l, r); - return !res; + else { /* try 'lt': */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + res = luaT_callorderTM(L, r, l, TM_LT); + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + if (res < 0) + luaG_ordererror(L, l, r); + return !res; /* result is negated */ + } } /* -** equality of Lua values. L == NULL means raw equality (no metamethods) +** Main operation for equality of Lua values; return 't1 == t2'. +** L == NULL means raw equality (no metamethods) */ -int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) { +int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; - lua_assert(ttisequal(t1, t2)); + if (ttype(t1) != ttype(t2)) { /* not the same variant? */ + if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) + return 0; /* only numbers can be equal with different variants */ + else { /* two numbers with different variants */ + lua_Integer i1, i2; /* compare them as integers */ + return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); + } + } + /* values have same type and same variant */ switch (ttype(t1)) { case LUA_TNIL: return 1; - case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); + case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); + case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TLCF: return fvalue(t1) == fvalue(t2); - case LUA_TSHRSTR: return eqshrstr(rawtsvalue(t1), rawtsvalue(t2)); - case LUA_TLNGSTR: return luaS_eqlngstr(rawtsvalue(t1), rawtsvalue(t2)); + case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); + case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; else if (L == NULL) return 0; - tm = get_equalTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); + tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; else if (L == NULL) return 0; - tm = get_equalTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: - lua_assert(iscollectable(t1)); return gcvalue(t1) == gcvalue(t2); } - if (tm == NULL) return 0; /* no TM? */ - callTM(L, tm, t1, t2, L->top, 1); /* call TM */ + if (tm == NULL) /* no TM? */ + return 0; /* objects are different */ + luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ return !l_isfalse(L->top); } +/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ +#define tostring(L,o) \ + (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) + +#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) + +/* copy strings in stack from top - n up to top - 1 to buffer */ +static void copy2buff (StkId top, int n, char *buff) { + size_t tl = 0; /* size already copied */ + do { + size_t l = vslen(top - n); /* length of string being copied */ + memcpy(buff + tl, svalue(top - n), l * sizeof(char)); + tl += l; + } while (--n > 0); +} + + +/* +** Main operation for concatenation: concat 'total' values in the stack, +** from 'L->top - total' up to 'L->top - 1'. +*/ void luaV_concat (lua_State *L, int total) { lua_assert(total >= 2); do { StkId top = L->top; int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { - if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) - luaG_concaterror(L, top-2, top-1); - } - else if (tsvalue(top-1)->len == 0) /* second operand is empty? */ - (void)tostring(L, top - 2); /* result is first operand */ - else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { + if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) + luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); + else if (isemptystr(top - 1)) /* second operand is empty? */ + cast_void(tostring(L, top - 2)); /* result is first operand */ + else if (isemptystr(top - 2)) { /* first operand is an empty string? */ setobjs2s(L, top - 2, top - 1); /* result is second op. */ } else { /* at least two non-empty string values; get as many as possible */ - size_t tl = tsvalue(top-1)->len; - char *buffer; - int i; - /* collect total length */ - for (i = 1; i < total && tostring(L, top-i-1); i++) { - size_t l = tsvalue(top-i-1)->len; - if (l >= (MAX_SIZET/sizeof(char)) - tl) + size_t tl = vslen(top - 1); + TString *ts; + /* collect total length and number of strings */ + for (n = 1; n < total && tostring(L, top - n - 1); n++) { + size_t l = vslen(top - n - 1); + if (l >= (MAX_SIZE/sizeof(char)) - tl) luaG_runerror(L, "string length overflow"); tl += l; } - buffer = luaZ_openspace(L, &G(L)->buff, tl); - tl = 0; - n = i; - do { /* concat all strings */ - size_t l = tsvalue(top-i)->len; - memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); - tl += l; - } while (--i > 0); - setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); + if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ + char buff[LUAI_MAXSHORTLEN]; + copy2buff(top, n, buff); /* copy strings to buffer */ + ts = luaS_newlstr(L, buff, tl); + } + else { /* long string; copy strings directly to final result */ + ts = luaS_createlngstrobj(L, tl); + copy2buff(top, n, getstr(ts)); + } + setsvalue2s(L, top - n, ts); /* create result */ } total -= n-1; /* got 'n' strings to create 1 new */ L->top -= n-1; /* popped 'n' strings and pushed one */ @@ -332,18 +497,25 @@ void luaV_concat (lua_State *L, int total) { } +/* +** Main operation 'ra' = #rb'. +*/ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { const TValue *tm; - switch (ttypenv(rb)) { + switch (ttype(rb)) { case LUA_TTABLE: { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); if (tm) break; /* metamethod? break switch to call it */ - setnvalue(ra, cast_num(luaH_getn(h))); /* else primitive len */ + setivalue(ra, luaH_getn(h)); /* else primitive len */ return; } - case LUA_TSTRING: { - setnvalue(ra, cast_num(tsvalue(rb)->len)); + case LUA_TSHRSTR: { + setivalue(ra, tsvalue(rb)->shrlen); + return; + } + case LUA_TLNGSTR: { + setivalue(ra, tsvalue(rb)->u.lnglen); return; } default: { /* try metamethod */ @@ -353,21 +525,66 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { break; } } - callTM(L, tm, rb, rb, ra, 1); + luaT_callTM(L, tm, rb, rb, ra, 1); +} + + +/* +** Integer division; return 'm // n', that is, floor(m/n). +** C division truncates its result (rounds towards zero). +** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, +** otherwise 'floor(q) == trunc(q) - 1'. +*/ +lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to divide by zero"); + return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ + } + else { + lua_Integer q = m / n; /* perform C division */ + if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ + q -= 1; /* correct result for different rounding */ + return q; + } +} + + +/* +** Integer modulus; return 'm % n'. (Assume that C '%' with +** negative operands follows C99 behavior. See previous comment +** about luaV_div.) +*/ +lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to perform 'n%%0'"); + return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ + } + else { + lua_Integer r = m % n; + if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ + r += n; /* correct result for different rounding */ + return r; + } } -void luaV_arith (lua_State *L, StkId ra, const TValue *rb, - const TValue *rc, TMS op) { - TValue tempb, tempc; - const TValue *b, *c; - if ((b = luaV_tonumber(rb, &tempb)) != NULL && - (c = luaV_tonumber(rc, &tempc)) != NULL) { - lua_Number res = luaO_arith(op - TM_ADD + LUA_OPADD, nvalue(b), nvalue(c)); - setnvalue(ra, res); +/* number of bits in an integer */ +#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) + +/* +** Shift left operation. (Shift right just negates 'y'.) +*/ +lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { + if (y < 0) { /* shift right? */ + if (y <= -NBITS) return 0; + else return intop(>>, x, -y); + } + else { /* shift left */ + if (y >= NBITS) return 0; + else return intop(<<, x, y); } - else if (!call_binTM(L, rb, rc, ra, op)) - luaG_aritherror(L, rb, rc); } @@ -376,15 +593,15 @@ void luaV_arith (lua_State *L, StkId ra, const TValue *rb, ** whether there is a cached closure with the same upvalues needed by ** new closure to be created. */ -static Closure *getcached (Proto *p, UpVal **encup, StkId base) { - Closure *c = p->cache; +static LClosure *getcached (Proto *p, UpVal **encup, StkId base) { + LClosure *c = p->cache; if (c != NULL) { /* is there a cached closure? */ int nup = p->sp->sizeupvalues; Upvaldesc *uv = p->sp->upvalues; int i; for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; - if (c->l.upvals[i]->v != v) + if (c->upvals[i]->v != v) return NULL; /* wrong upvalue; cannot reuse closure */ } } @@ -394,26 +611,28 @@ static Closure *getcached (Proto *p, UpVal **encup, StkId base) { /* ** create a new Lua closure, push it in the stack, and initialize -** its upvalues. Note that the call to 'luaC_barrierproto' must come -** before the assignment to 'p->cache', as the function needs the -** original value of that field. +** its upvalues. Note that the closure is not cached if prototype is +** already black (which means that 'cache' was already cleared by the +** GC). */ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, StkId ra) { int nup = p->sp->sizeupvalues; Upvaldesc *uv = p->sp->upvalues; int i; - Closure *ncl = luaF_newLclosure(L, nup); - ncl->l.p = p; + LClosure *ncl = luaF_newLclosure(L, nup); + ncl->p = p; setclLvalue(L, ra, ncl); /* anchor new closure in stack */ for (i = 0; i < nup; i++) { /* fill in its upvalues */ if (uv[i].instack) /* upvalue refers to local variable? */ - ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx); + ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); else /* get upvalue from enclosing function */ - ncl->l.upvals[i] = encup[uv[i].idx]; + ncl->upvals[i] = encup[uv[i].idx]; + ncl->upvals[i]->refcount++; + /* new closure is white, so we do not need a barrier here */ } - luaC_barrierproto(L, p, ncl); - p->cache = ncl; /* save it on cache for reuse */ + if (!isblack(p)) /* cache will not break GC invariant? */ + p->cache = ncl; /* save it on cache for reuse */ } @@ -426,8 +645,10 @@ void luaV_finishOp (lua_State *L) { Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ OpCode op = GET_OPCODE(inst); switch (op) { /* finish its execution */ - case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: - case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: + case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: + case OP_MOD: case OP_POW: + case OP_UNM: case OP_BNOT: case OP_LEN: case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { setobjs2s(L, base + GETARG_A(inst), --L->top); break; @@ -435,18 +656,18 @@ void luaV_finishOp (lua_State *L) { case OP_LE: case OP_LT: case OP_EQ: { int res = !l_isfalse(L->top - 1); L->top--; - /* metamethod should not be called when operand is K */ - lua_assert(!ISK(GETARG_B(inst))); - if (op == OP_LE && /* "<=" using "<" instead? */ - ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) - res = !res; /* invert result */ + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ + lua_assert(op == OP_LE); + ci->callstatus ^= CIST_LEQ; /* clear mark */ + res = !res; /* negate result */ + } lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); if (res != GETARG_A(inst)) /* condition failed? */ ci->u.l.savedpc++; /* skip jump instruction */ break; } case OP_CONCAT: { - StkId top = L->top - 1; /* top when 'call_binTM' was called */ + StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ int b = GETARG_B(inst); /* first element to concatenate */ int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ setobj2s(L, top - 2, top); /* put TM result in proper position */ @@ -477,31 +698,32 @@ void luaV_finishOp (lua_State *L) { + /* -** some macros for common tasks in `luaV_execute' +** {================================================================== +** Function 'luaV_execute': main interpreter loop +** =================================================================== */ -#if !defined luai_runtimecheck -#define luai_runtimecheck(L, c) /* void */ -#endif + +/* +** some macros for common tasks in 'luaV_execute' +*/ #define RA(i) (base+GETARG_A(i)) -/* to be used after possible stack reallocation */ #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) -#define KBx(i) \ - (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) /* execute a jump instruction */ #define dojump(ci,i,e) \ { int a = GETARG_A(i); \ - if (a > 0) luaF_close(L, ci->u.l.base + a - 1); \ + if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \ ci->u.l.savedpc += GETARG_sBx(i) + e; } /* for test instructions, execute the jump instruction that follows it */ @@ -511,96 +733,119 @@ void luaV_finishOp (lua_State *L) { #define Protect(x) { {x;}; base = ci->u.l.base; } #define checkGC(L,c) \ - Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \ - luaC_step(L); \ - L->top = ci->top;}) /* restore top */ \ - luai_threadyield(L); ) + { luaC_condGC(L, L->top = (c), /* limit of live values */ \ + Protect(L->top = ci->top)); /* restore top */ \ + luai_threadyield(L); } -#define arith_op(op,tm) { \ - TValue *rb = RKB(i); \ - TValue *rc = RKC(i); \ - if (ttisnumber(rb) && ttisnumber(rc)) { \ - lua_Number nb = nvalue(rb), nc = nvalue(rc); \ - setnvalue(ra, op(L, nb, nc)); \ - } \ - else { Protect(luaV_arith(L, ra, rb, rc, tm)); } } +#define vmdispatch(o) switch(o) +#define vmcase(l) case l: +#define vmbreak break + + +/* +** copy of 'luaV_gettable', but protecting call to potential metamethod +** (which can reallocate the stack) +*/ +#define gettableProtected(L,t,k,v) { const TValue *aux; \ + if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ + else Protect(luaV_finishget(L,t,k,v,aux)); } + + +/* same for 'luaV_settable' */ +#define settableProtected(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ + Protect(luaV_finishset(L,t,k,v,slot)); } -#define vmdispatch(o) switch(o) -#define vmcase(l,b) case l: {b} break; -#define vmcasenb(l,b) case l: {b} /* nb = no break */ void luaV_execute (lua_State *L) { CallInfo *ci = L->ci; LClosure *cl; TValue *k; StkId base; + ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ newframe: /* reentry point when frame changes (call/return) */ lua_assert(ci == L->ci); - cl = clLvalue(ci->func); - k = cl->p->k; - base = ci->u.l.base; + cl = clLvalue(ci->func); /* local reference to function's closure */ + k = cl->p->k; /* local reference to function's constant table */ + base = ci->u.l.base; /* local copy of function's base */ /* main loop of interpreter */ for (;;) { Instruction i = *(ci->u.l.savedpc++); StkId ra; - if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && - (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - Protect(traceexec(L)); - } - /* WARNING: several calls may realloc the stack and invalidate `ra' */ + if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) + Protect(luaG_traceexec(L)); + /* WARNING: several calls may realloc the stack and invalidate 'ra' */ ra = RA(i); lua_assert(base == ci->u.l.base); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); vmdispatch (GET_OPCODE(i)) { - vmcase(OP_MOVE, + vmcase(OP_MOVE) { setobjs2s(L, ra, RB(i)); - ) - vmcase(OP_LOADK, + vmbreak; + } + vmcase(OP_LOADK) { TValue *rb = k + GETARG_Bx(i); setobj2s(L, ra, rb); - ) - vmcase(OP_LOADKX, + vmbreak; + } + vmcase(OP_LOADKX) { TValue *rb; lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); rb = k + GETARG_Ax(*ci->u.l.savedpc++); setobj2s(L, ra, rb); - ) - vmcase(OP_LOADBOOL, + vmbreak; + } + vmcase(OP_LOADBOOL) { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - ) - vmcase(OP_LOADNIL, + vmbreak; + } + vmcase(OP_LOADNIL) { int b = GETARG_B(i); do { setnilvalue(ra++); } while (b--); - ) - vmcase(OP_GETUPVAL, + vmbreak; + } + vmcase(OP_GETUPVAL) { int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); - ) - vmcase(OP_GETTABUP, - int b = GETARG_B(i); - Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra)); - ) - vmcase(OP_GETTABLE, - Protect(luaV_gettable(L, RB(i), RKC(i), ra)); - ) - vmcase(OP_SETTABUP, - int a = GETARG_A(i); - Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i))); - ) - vmcase(OP_SETUPVAL, + vmbreak; + } + vmcase(OP_GETTABUP) { + TValue *upval = cl->upvals[GETARG_B(i)]->v; + TValue *rc = RKC(i); + gettableProtected(L, upval, rc, ra); + vmbreak; + } + vmcase(OP_GETTABLE) { + StkId rb = RB(i); + TValue *rc = RKC(i); + gettableProtected(L, rb, rc, ra); + vmbreak; + } + vmcase(OP_SETTABUP) { + TValue *upval = cl->upvals[GETARG_A(i)]->v; + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, upval, rb, rc); + vmbreak; + } + vmcase(OP_SETUPVAL) { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); - luaC_barrier(L, uv, ra); - ) - vmcase(OP_SETTABLE, - Protect(luaV_settable(L, ra, RKB(i), RKC(i))); - ) - vmcase(OP_NEWTABLE, + luaC_upvalbarrier(L, uv); + vmbreak; + } + vmcase(OP_SETTABLE) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, ra, rb, rc); + vmbreak; + } + vmcase(OP_NEWTABLE) { int b = GETARG_B(i); int c = GETARG_C(i); Table *t = luaH_new(L); @@ -608,96 +853,252 @@ void luaV_execute (lua_State *L) { if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); checkGC(L, ra + 1); - ) - vmcase(OP_SELF, + vmbreak; + } + vmcase(OP_SELF) { + const TValue *aux; StkId rb = RB(i); - setobjs2s(L, ra+1, rb); - Protect(luaV_gettable(L, rb, RKC(i), ra)); - ) - vmcase(OP_ADD, - arith_op(luai_numadd, TM_ADD); - ) - vmcase(OP_SUB, - arith_op(luai_numsub, TM_SUB); - ) - vmcase(OP_MUL, - arith_op(luai_nummul, TM_MUL); - ) - vmcase(OP_DIV, - arith_op(luai_numdiv, TM_DIV); - ) - vmcase(OP_MOD, - arith_op(luai_nummod, TM_MOD); - ) - vmcase(OP_POW, - arith_op(luai_numpow, TM_POW); - ) - vmcase(OP_UNM, + TValue *rc = RKC(i); + TString *key = tsvalue(rc); /* key must be a string */ + setobjs2s(L, ra + 1, rb); + if (luaV_fastget(L, rb, key, aux, luaH_getstr)) { + setobj2s(L, ra, aux); + } + else Protect(luaV_finishget(L, rb, rc, ra, aux)); + vmbreak; + } + vmcase(OP_ADD) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(+, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numadd(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } + vmbreak; + } + vmcase(OP_SUB) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(-, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numsub(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } + vmbreak; + } + vmcase(OP_MUL) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(*, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_nummul(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } + vmbreak; + } + vmcase(OP_DIV) { /* float division (always with floats) */ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numdiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } + vmbreak; + } + vmcase(OP_BAND) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(&, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } + vmbreak; + } + vmcase(OP_BOR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(|, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } + vmbreak; + } + vmcase(OP_BXOR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(^, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } + vmbreak; + } + vmcase(OP_SHL) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, luaV_shiftl(ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } + vmbreak; + } + vmcase(OP_SHR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, luaV_shiftl(ib, -ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } + vmbreak; + } + vmcase(OP_MOD) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_mod(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + lua_Number m; + luai_nummod(L, nb, nc, m); + setfltvalue(ra, m); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } + vmbreak; + } + vmcase(OP_IDIV) { /* floor division */ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_div(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numidiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } + vmbreak; + } + vmcase(OP_POW) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numpow(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } + vmbreak; + } + vmcase(OP_UNM) { TValue *rb = RB(i); - if (ttisnumber(rb)) { - lua_Number nb = nvalue(rb); - setnvalue(ra, luai_numunm(L, nb)); + lua_Number nb; + if (ttisinteger(rb)) { + lua_Integer ib = ivalue(rb); + setivalue(ra, intop(-, 0, ib)); + } + else if (tonumber(rb, &nb)) { + setfltvalue(ra, luai_numunm(L, nb)); } else { - Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); + Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); } - ) - vmcase(OP_NOT, + vmbreak; + } + vmcase(OP_BNOT) { + TValue *rb = RB(i); + lua_Integer ib; + if (tointeger(rb, &ib)) { + setivalue(ra, intop(^, ~l_castS2U(0), ib)); + } + else { + Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); + } + vmbreak; + } + vmcase(OP_NOT) { TValue *rb = RB(i); int res = l_isfalse(rb); /* next assignment may change this value */ setbvalue(ra, res); - ) - vmcase(OP_LEN, + vmbreak; + } + vmcase(OP_LEN) { Protect(luaV_objlen(L, ra, RB(i))); - ) - vmcase(OP_CONCAT, + vmbreak; + } + vmcase(OP_CONCAT) { int b = GETARG_B(i); int c = GETARG_C(i); StkId rb; L->top = base + c + 1; /* mark the end of concat operands */ Protect(luaV_concat(L, c - b + 1)); - ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */ - rb = b + base; + ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */ + rb = base + b; setobjs2s(L, ra, rb); checkGC(L, (ra >= rb ? ra + 1 : rb)); L->top = ci->top; /* restore top */ - ) - vmcase(OP_JMP, + vmbreak; + } + vmcase(OP_JMP) { dojump(ci, i, 0); - ) - vmcase(OP_EQ, + vmbreak; + } + vmcase(OP_EQ) { TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( - if (cast_int(equalobj(L, rb, rc)) != GETARG_A(i)) + if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) - ) - vmcase(OP_LT, + vmbreak; + } + vmcase(OP_LT) { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) - ) - vmcase(OP_LE, + vmbreak; + } + vmcase(OP_LE) { Protect( if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) - ) - vmcase(OP_TEST, + vmbreak; + } + vmcase(OP_TEST) { if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) ci->u.l.savedpc++; else donextjump(ci); - ) - vmcase(OP_TESTSET, + vmbreak; + } + vmcase(OP_TESTSET) { TValue *rb = RB(i); if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) ci->u.l.savedpc++; @@ -705,27 +1106,30 @@ void luaV_execute (lua_State *L) { setobjs2s(L, ra, rb); donextjump(ci); } - ) - vmcase(OP_CALL, + vmbreak; + } + vmcase(OP_CALL) { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ if (luaD_precall(L, ra, nresults)) { /* C function? */ - if (nresults >= 0) L->top = ci->top; /* adjust results */ - base = ci->u.l.base; + if (nresults >= 0) + L->top = ci->top; /* adjust results */ + Protect((void)0); /* update 'base' */ } else { /* Lua function */ ci = L->ci; - ci->callstatus |= CIST_REENTRY; goto newframe; /* restart luaV_execute over new Lua function */ } - ) - vmcase(OP_TAILCALL, + vmbreak; + } + vmcase(OP_TAILCALL) { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */ - base = ci->u.l.base; + if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + Protect((void)0); /* update 'base' */ + } else { /* tail call: put called frame (n) in place of caller one (o) */ CallInfo *nci = L->ci; /* called frame */ @@ -748,13 +1152,13 @@ void luaV_execute (lua_State *L) { lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); goto newframe; /* restart luaV_execute over new Lua function */ } - ) - vmcasenb(OP_RETURN, + vmbreak; + } + vmcase(OP_RETURN) { int b = GETARG_B(i); - if (b != 0) L->top = ra+b-1; if (cl->p->sp->sizep > 0) luaF_close(L, base); - b = luaD_poscall(L, ra); - if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */ + b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); + if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ return; /* external invocation: return */ else { /* invocation via reentry: continue execution */ ci = L->ci; @@ -763,105 +1167,137 @@ void luaV_execute (lua_State *L) { lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); goto newframe; /* restart luaV_execute over new Lua function */ } - ) - vmcase(OP_FORLOOP, - lua_Number step = nvalue(ra+2); - lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ - lua_Number limit = nvalue(ra+1); - if (luai_numlt(L, 0, step) ? luai_numle(L, idx, limit) - : luai_numle(L, limit, idx)) { - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - setnvalue(ra, idx); /* update internal index... */ - setnvalue(ra+3, idx); /* ...and external index */ - } - ) - vmcase(OP_FORPREP, - const TValue *init = ra; - const TValue *plimit = ra+1; - const TValue *pstep = ra+2; - if (!tonumber(init, ra)) - luaG_runerror(L, LUA_QL("for") " initial value must be a number"); - else if (!tonumber(plimit, ra+1)) - luaG_runerror(L, LUA_QL("for") " limit must be a number"); - else if (!tonumber(pstep, ra+2)) - luaG_runerror(L, LUA_QL("for") " step must be a number"); - setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); + } + vmcase(OP_FORLOOP) { + if (ttisinteger(ra)) { /* integer loop? */ + lua_Integer step = ivalue(ra + 2); + lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */ + lua_Integer limit = ivalue(ra + 1); + if ((0 < step) ? (idx <= limit) : (limit <= idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgivalue(ra, idx); /* update internal index... */ + setivalue(ra + 3, idx); /* ...and external index */ + } + } + else { /* floating loop */ + lua_Number step = fltvalue(ra + 2); + lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ + lua_Number limit = fltvalue(ra + 1); + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgfltvalue(ra, idx); /* update internal index... */ + setfltvalue(ra + 3, idx); /* ...and external index */ + } + } + vmbreak; + } + vmcase(OP_FORPREP) { + TValue *init = ra; + TValue *plimit = ra + 1; + TValue *pstep = ra + 2; + lua_Integer ilimit; + int stopnow; + if (ttisinteger(init) && ttisinteger(pstep) && + forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { + /* all values are integer */ + lua_Integer initv = (stopnow ? 0 : ivalue(init)); + setivalue(plimit, ilimit); + setivalue(init, intop(-, initv, ivalue(pstep))); + } + else { /* try making all values floats */ + lua_Number ninit; lua_Number nlimit; lua_Number nstep; + if (!tonumber(plimit, &nlimit)) + luaG_runerror(L, "'for' limit must be a number"); + setfltvalue(plimit, nlimit); + if (!tonumber(pstep, &nstep)) + luaG_runerror(L, "'for' step must be a number"); + setfltvalue(pstep, nstep); + if (!tonumber(init, &ninit)) + luaG_runerror(L, "'for' initial value must be a number"); + setfltvalue(init, luai_numsub(L, ninit, nstep)); + } ci->u.l.savedpc += GETARG_sBx(i); - ) - vmcasenb(OP_TFORCALL, + vmbreak; + } + vmcase(OP_TFORCALL) { StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); L->top = cb + 3; /* func. + 2 args (state and index) */ - Protect(luaD_call(L, cb, GETARG_C(i), 1)); + Protect(luaD_call(L, cb, GETARG_C(i))); L->top = ci->top; i = *(ci->u.l.savedpc++); /* go to next instruction */ ra = RA(i); lua_assert(GET_OPCODE(i) == OP_TFORLOOP); goto l_tforloop; - ) - vmcase(OP_TFORLOOP, + } + vmcase(OP_TFORLOOP) { l_tforloop: if (!ttisnil(ra + 1)) { /* continue loop? */ setobjs2s(L, ra, ra + 1); /* save control variable */ ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ } - ) - vmcase(OP_SETLIST, + vmbreak; + } + vmcase(OP_SETLIST) { int n = GETARG_B(i); int c = GETARG_C(i); - int last; + unsigned int last; Table *h; if (n == 0) n = cast_int(L->top - ra) - 1; if (c == 0) { lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); c = GETARG_Ax(*ci->u.l.savedpc++); } - luai_runtimecheck(L, ttistable(ra)); h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ - luaH_resizearray(L, h, last); /* pre-allocate it at once */ + luaH_resizearray(L, h, last); /* preallocate it at once */ for (; n > 0; n--) { TValue *val = ra+n; luaH_setint(L, h, last--, val); - luaC_barrierback(L, obj2gco(h), val); + luaC_barrierback(L, h, val); } L->top = ci->top; /* correct top (in case of previous open call) */ - ) - vmcase(OP_CLOSURE, + vmbreak; + } + vmcase(OP_CLOSURE) { Proto *p = cl->p->p[GETARG_Bx(i)]; - Closure *ncl = getcached(p, cl->upvals, base); /* cached closure */ + LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ if (ncl == NULL) /* no match? */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ else setclLvalue(L, ra, ncl); /* push cashed closure */ checkGC(L, ra + 1); - ) - vmcase(OP_VARARG, - int b = GETARG_B(i) - 1; + vmbreak; + } + vmcase(OP_VARARG) { + int b = GETARG_B(i) - 1; /* required results */ int j; int n = cast_int(base - ci->func) - cl->p->sp->numparams - 1; + if (n < 0) /* less arguments than parameters? */ + n = 0; /* no vararg arguments */ if (b < 0) { /* B == 0? */ b = n; /* get all var. arguments */ Protect(luaD_checkstack(L, n)); ra = RA(i); /* previous call may change the stack */ L->top = ra + n; } - for (j = 0; j < b; j++) { - if (j < n) { - setobjs2s(L, ra + j, base - n + j); - } - else { - setnilvalue(ra + j); - } - } - ) - vmcase(OP_EXTRAARG, + for (j = 0; j < b && j < n; j++) + setobjs2s(L, ra + j, base - n + j); + for (; j < b; j++) /* complete required results with nil */ + setnilvalue(ra + j); + vmbreak; + } + vmcase(OP_EXTRAARG) { lua_assert(0); - ) + vmbreak; + } } } } +/* }================================================================== */ + diff --git a/deps/lua/lvm.h b/deps/lua/lvm.h index 5380270..fd0e748 100644 --- a/deps/lua/lvm.h +++ b/deps/lua/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.18.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lvm.h,v 2.39 2015/09/09 13:44:07 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -13,32 +13,102 @@ #include "ltm.h" -#define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o))) +#if !defined(LUA_NOCVTN2S) +#define cvt2str(o) ttisnumber(o) +#else +#define cvt2str(o) 0 /* no conversion from numbers to strings */ +#endif + + +#if !defined(LUA_NOCVTS2N) +#define cvt2num(o) ttisstring(o) +#else +#define cvt2num(o) 0 /* no conversion from strings to numbers */ +#endif + + +/* +** You can define LUA_FLOORN2I if you want to convert floats to integers +** by flooring them (instead of raising an error if they are not +** integral values) +*/ +#if !defined(LUA_FLOORN2I) +#define LUA_FLOORN2I 0 +#endif + + +#define tonumber(o,n) \ + (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) -#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL)) +#define tointeger(o,i) \ + (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) -#define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2)) +#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) -#define luaV_rawequalobj(o1,o2) equalobj(NULL,o1,o2) +#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) + + +/* +** fast track for 'gettable': 1 means 'aux' points to resulted value; +** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is +** the raw get function to use. +*/ +#define luaV_fastget(L,t,k,aux,f) \ + (!ttistable(t) \ + ? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \ + : (aux = f(hvalue(t), k), /* else, do raw access */ \ + !ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \ + : (aux = fasttm(L, hvalue(t)->metatable, TM_INDEX), /* get metamethod */\ + aux != NULL ? 0 /* has metamethod? must call it */ \ + : (aux = luaO_nilobject, 1)))) /* else, final result is nil */ + +/* +** standard implementation for 'gettable' +*/ +#define luaV_gettable(L,t,k,v) { const TValue *aux; \ + if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ + else luaV_finishget(L,t,k,v,aux); } + + +/* +** Fast track for set table. If 't' is a table and 't[k]' is not nil, +** call GC barrier, do a raw 't[k]=v', and return true; otherwise, +** return false with 'slot' equal to NULL (if 't' is not a table) or +** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro +** returns true, there is no need to 'invalidateTMcache', because the +** call is not creating a new entry. +*/ +#define luaV_fastset(L,t,k,slot,f,v) \ + (!ttistable(t) \ + ? (slot = NULL, 0) \ + : (slot = f(hvalue(t), k), \ + ttisnil(slot) ? 0 \ + : (luaC_barrierback(L, hvalue(t), v), \ + setobj2t(L, cast(TValue *,slot), v), \ + 1))) -/* not to called directly */ -LUAI_FUNC int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2); +#define luaV_settable(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ + luaV_finishset(L,t,k,v,slot); } + +LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); -LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); -LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); -LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, - StkId val); -LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, - StkId val); +LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); +LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); +LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *tm); +LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *oldval); LUAI_FUNC void luaV_finishOp (lua_State *L); LUAI_FUNC void luaV_execute (lua_State *L); LUAI_FUNC void luaV_concat (lua_State *L, int total); -LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb, - const TValue *rc, TMS op); +LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); #endif diff --git a/deps/lua/lzio.c b/deps/lua/lzio.c index 20efea9..c9e1f49 100644 --- a/deps/lua/lzio.c +++ b/deps/lua/lzio.c @@ -1,15 +1,17 @@ /* -** $Id: lzio.c,v 1.35.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ - -#include - #define lzio_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "llimits.h" @@ -64,13 +66,3 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) { return 0; } -/* ------------------------------------------------------------------------ */ -char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { - if (n > buff->buffsize) { - if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - luaZ_resizebuffer(L, buff, n); - } - return buff->buffer; -} - - diff --git a/deps/lua/lzio.h b/deps/lua/lzio.h index 441f747..e7b6f34 100644 --- a/deps/lua/lzio.h +++ b/deps/lua/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.26.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -32,20 +32,21 @@ typedef struct Mbuffer { #define luaZ_sizebuffer(buff) ((buff)->buffsize) #define luaZ_bufflen(buff) ((buff)->n) +#define luaZ_buffremove(buff,i) ((buff)->n -= (i)) #define luaZ_resetbuffer(buff) ((buff)->n = 0) #define luaZ_resizebuffer(L, buff, size) \ - (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ + ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ + (buff)->buffsize, size), \ (buff)->buffsize = size) #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) -LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data); -LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ +LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ @@ -55,7 +56,7 @@ struct Zio { size_t n; /* bytes still unread */ const char *p; /* current position in buffer */ lua_Reader reader; /* reader function */ - void* data; /* additional data */ + void *data; /* additional data */ lua_State *L; /* Lua state (for reader) */ }; diff --git a/node-lua.vcxproj b/node-lua.vcxproj index 29bbfc4..3fb9615 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -54,7 +54,7 @@ Disabled deps\lua;deps\uv\include;deps\uv\include\uv-private;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CONSOLE;LUA_COMPAT_ALL;%(PreprocessorDefinitions) + WIN32;_DEBUG;_CONSOLE;LUA_COMPAT_5_2;LUA_COMPAT_5_1;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL From 837cb5491560e995720baccfcc1abe25fe5c757e Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 25 Mar 2016 00:42:11 +0800 Subject: [PATCH 002/173] =?UTF-8?q?=E5=8D=87=E7=BA=A7lua5.2.3->5.3.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deps/lua/README | 2 +- deps/lua/lapi.c | 5 ++--- deps/lua/lua.vcxproj | 2 ++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/deps/lua/README b/deps/lua/README index 9e1aea2..11c03d2 100644 --- a/deps/lua/README +++ b/deps/lua/README @@ -1,3 +1,3 @@ -This is a modify version of lua 5.2.3 (http://www.lua.org/ftp/lua-5.2.3.tar.gz) . +This is a modify version of lua 5.3.2. For detail : http://lua-users.org/lists/lua-l/2014-03/msg00489.html diff --git a/deps/lua/lapi.c b/deps/lua/lapi.c index 38c7ec8..4b1d3db 100644 --- a/deps/lua/lapi.c +++ b/deps/lua/lapi.c @@ -1025,7 +1025,7 @@ cloneproto (lua_State *L, const Proto *src) { const TValue *s=&src->k[i]; TValue *o=&f->k[i]; if (ttisstring(s)) { - TString * str = luaS_newlstr(L,svalue(s),tsvalue(s)->len); + TString * str = luaS_newlstr(L,svalue(s),vslen(s)); setsvalue2n(L,o,str); } else { setobj(L,o,s); @@ -1071,7 +1071,6 @@ static void lua_initsharedproto(lua_State *L, Proto *p, const TValue *val, const TValue *gt) { int i; TValue cl; - UpVal *up; LClosure *pcl = luaF_newLclosure(L, 1); pcl->p = p; p->sp->refnum = 2; //initial as 2 @@ -1109,7 +1108,7 @@ LUA_API void* lua_initsharedclosure(lua_State *L) { reg = hvalue(&G(L)->l_registry); gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - setnvalue(&val, cast_num(1)); + setivalue(&val, cast_int(1)); setobj2t(L, luaH_set(L, hvalue(gt), cl), &val); invalidateTMcache(hvalue(gt)); --L->top; diff --git a/deps/lua/lua.vcxproj b/deps/lua/lua.vcxproj index 9df3549..91eadc7 100644 --- a/deps/lua/lua.vcxproj +++ b/deps/lua/lua.vcxproj @@ -103,6 +103,7 @@ + @@ -122,6 +123,7 @@ + From d544645b56999b7687e010d89f22c7560440ea8d Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 25 Mar 2016 01:41:53 +0800 Subject: [PATCH 003/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dlua5.3.2=E4=B8=8BluaK?= =?UTF-8?q?function=E7=9A=84=E5=8D=87=E7=BA=A7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deps/lua/lua.vcxproj.filters | 6 ++++++ node-lua.v12.suo | Bin 158720 -> 158720 bytes src/context_lua.cpp | 15 +++++++-------- src/context_lua.h | 12 ++++++------ src/lcororep.cpp | 9 ++++++--- src/lua_tcp_handle.cpp | 6 +++--- src/lua_tcp_handle.h | 6 +++--- src/lua_timer_handle.cpp | 2 +- src/lua_timer_handle.h | 2 +- 9 files changed, 33 insertions(+), 25 deletions(-) diff --git a/deps/lua/lua.vcxproj.filters b/deps/lua/lua.vcxproj.filters index 912d92d..ae742ed 100644 --- a/deps/lua/lua.vcxproj.filters +++ b/deps/lua/lua.vcxproj.filters @@ -97,6 +97,9 @@ src + + src + @@ -177,6 +180,9 @@ src + + src + diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 82dc3a7d878b2cc552a0f8c3997c547a519e2193..096f9a09c9e67270389869d2a7fd7bef482b185b 100644 GIT binary patch delta 3129 zcmds1dr(wm6u;+ocey;f!17*XL408#1c-*oLlANp1MD#>CQm_x-31ntLV2iYj8m{* za{pn*q#`2~(@0@JZ<1PkbVm%DHc#o~hY_=UIpqh=qvl2$HT!@_Z2)Jt7qmicXaxO+vUbeOJxF(3g6bXo_ky%Rgm02%YdR#Amk&1FlelZqnG8?Kr|Su9H*WxNA!TG6sr*VO>5^G@m``?V zyh*fYn5qOH$Q8SNVUF1A3tBPG7YZp zQ;a)YfDRRoJKW?(@55AjJSrl?(X)x4W?bWYl}@`x1M44G@ZHBEPi?t^H!$FFGS0R@9M40)!GiNJ8*1=j)h)mzX+UIydMI{?Ea_u zCGpH-nD+#+DjGt`uH%A`Q+V8`_N8Z{d}`nJc{Bg$0umzm)Em`&;$+E&gWw=s9v+EI z8$O%OawB#IA8QediG}%2SmEz0+O**@dGbSOdh_IiDAkw%N=l!mQ-hB4wVk@qaA=P-H)$bM93|@M$Ykg zOVbYW;+ZIFw+3BkeM#R3?)+klYE>l65~I(6t8g~Ed+sOkCw7KiI^7yo_Gqcx z3+8grOf*;bR)`RjzX0ATkNL*f?ARL{@w(m0lnVzwyE!b2SDV3!PqMsi5qA(A(`!q2 ze?2CCxhpW~;TA!Xg|!i^!#@~!Y=HX?d}5eN9(Ym~j@jm52#8k0lO`ZpUN<`C4ilB23*iBbxeF779Ts^a)1fqS;58TbyR=HzuQp{FSLbEu zvqcyL7aUbFL(6)I#&}i`M$1yiM*Ba{x)N2`ICu1YgIE{O8k>IQ{#WscfdddC{C?rm Z(T}><=>Ioj9~%I-KPzO77Mite@^25a_BsFn delta 1680 zcmchXUrbw79LM{+oR(W?S!s(M;gXe0B`{f_&H)bAG3gx16fk3xEgC_2mdrfM>FFyDs-kG`(U{U>8}*HC z{^}SXR0e6ExuE0{on#U|dp35;lc%^u_{1VKZV(#1!Fxq18GK9>3D{CRApTrKCm`wGQ^umSe)@2!{)1DA@ zs`M*`uc=`nBjtd#+$*nG3L^wPy?sR(^3)J-%kw1M`^hRRn&Ovoi=y2O*knJBmiB|BNv;%{CSs16<)_xgd9qvM3xzdi#5-bl$}66c=|INh z&5bH%qu>GXL}o>dr5@MbMv{IR^!3*WDj4k6Y?@|`{;Q?4IzeCu12%(xr#_vpVR%ZocN52 zTz$1e#YaD^|H5}Q^3(Sl`uaIoQBd$K{MEpBEeJz@6k`*2^a3%HAqOnj(DeD4qY3JL%3ZC?7X6V<8bY76Aur}X86XxOh7UG$# zpkpoa6`8EZb11C-f{72vPE1E~XoUC?Gu`h>r0p^WwkS4Zk4o#s_9q{2H(o1N8dmA} z=_WfB!poYBCo^(-gm%lnOhH@%NIg3m_yielding_status; } -int32_t context_lua_t::common_yield_continue(lua_State* L) +int32_t context_lua_t::common_yield_continue(lua_State* L, int status, lua_KContext ctx) { if (!lua_toboolean(L, -4) && context_lua_t::lua_get_context(L)->get_yielding_status() != UV_OK) { context_lua_t::lua_throw(L, -3); @@ -340,7 +340,7 @@ int32_t context_lua_t::common_yield_continue(lua_State* L) return 2; } -int32_t context_lua_t::lua_yield_send(lua_State *L, uint32_t destination, yiled_finalize_t fnz, void* fnz_ud, lua_CFunction yieldk, int64_t timeout) +int32_t context_lua_t::lua_yield_send(lua_State *L, uint32_t destination, yiled_finalize_t fnz, void* fnz_ud, lua_KFunction yieldk, int64_t timeout) { int stacks; context_lua_t* lctx = context_lua_t::lua_get_context(L); @@ -359,7 +359,7 @@ int32_t context_lua_t::lua_yield_send(lua_State *L, uint32_t destination, yiled_ lua_pushinteger(L, NL_EYIELD); lua_pushnil(L); lua_pushnil(L); - return (yieldk == NULL) ? 4 : yieldk(L); + return (yieldk == NULL) ? 4 : yieldk(L, LUA_YIELD, 0); } else { /* error jump directly */ lctx->yielding_finalize(NULL, NL_ESTACKLESS); return luaL_error(L, "attempt to yield across a stack-less coroutine"); @@ -384,9 +384,8 @@ int32_t context_lua_t::lua_ref_callback_entry_finish(lua_State *L, int32_t statu return 0; //return none result out!!! } -int32_t context_lua_t::lua_ref_callback_entry_continue(lua_State *L) +int32_t context_lua_t::lua_ref_callback_entry_continue(lua_State *L, int status, lua_KContext ctx) { - int status = lua_getctx(L, NULL); return lua_ref_callback_entry_finish(L, (status == LUA_YIELD)); } @@ -942,7 +941,7 @@ int32_t context_lua_t::context_query_yield_finalize(lua_State *root_coro, lua_St return UV_OK; } -int32_t context_lua_t::context_query_yield_continue(lua_State* L) +int32_t context_lua_t::context_query_yield_continue(lua_State* L, int status, lua_KContext ctx) { if (!lua_toboolean(L, -4)) { int32_t ret = context_lua_t::lua_get_context(L)->get_yielding_status(); @@ -1037,7 +1036,7 @@ int32_t context_lua_t::context_recv_yield_finalize(lua_State *root_coro, lua_Sta return UV_OK; } -int32_t context_lua_t::context_recv_yield_continue(lua_State* L) +int32_t context_lua_t::context_recv_yield_continue(lua_State* L, int status, lua_KContext ctx) { if (!lua_toboolean(L, -4) && context_lua_t::lua_get_context(L)->get_yielding_status() != UV_OK) { context_lua_t::lua_throw(L, -3); @@ -1090,7 +1089,7 @@ int32_t context_lua_t::context_wait_yield_finalize(lua_State *root_coro, lua_Sta } return UV_OK; } -int32_t context_lua_t::context_wait_yield_continue(lua_State* L) +int32_t context_lua_t::context_wait_yield_continue(lua_State* L, int status, lua_KContext ctx) { if (!lua_toboolean(L, -4)) { int32_t ret = context_lua_t::lua_get_context(L)->get_yielding_status(); diff --git a/src/context_lua.h b/src/context_lua.h index f22b41c..d0213b2 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -105,7 +105,7 @@ class context_lua_t : public context_t { public: static int32_t lua_ref_callback_entry(lua_State *L); /* for lua_ref_callback */ - static int32_t lua_ref_callback_entry_continue(lua_State *L); /* for lua_ref_callback */ + static int32_t lua_ref_callback_entry_continue(lua_State *L, int status, lua_KContext ctx); /* for lua_ref_callback */ static int32_t lua_ref_callback_entry_finish(lua_State *L, int32_t status); public: @@ -115,8 +115,8 @@ class context_lua_t : public context_t { static void lua_throw(lua_State *L, int32_t idx); /******** the following are yielding facilities ********/ - static int32_t common_yield_continue(lua_State* L); - static int32_t lua_yield_send(lua_State *L, uint32_t destination, yiled_finalize_t fnz, void* fnz_ud = NULL, lua_CFunction yieldk = NULL, int64_t timeout = 0); + static int32_t common_yield_continue(lua_State* L, int status, lua_KContext ctx); + static int32_t lua_yield_send(lua_State *L, uint32_t destination, yiled_finalize_t fnz, void* fnz_ud = NULL, lua_KFunction yieldk = NULL, int64_t timeout = 0); static int32_t common_callback_adjust(lua_State* L); static int32_t lua_ref_session(lua_State *L, int32_t idx); static void lua_unref_session(lua_State *L, int32_t idx, int32_t session); @@ -135,12 +135,12 @@ class context_lua_t : public context_t { static int32_t context_check_message(lua_State *L, int32_t idx, uint32_t msg_type, message_t& message); static int32_t context_send(lua_State *L, int32_t idx, uint32_t handle, int32_t session, uint32_t msg_type); static int32_t context_query_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); - static int32_t context_query_yield_continue(lua_State* L); + static int32_t context_query_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t context_recv_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); - static int32_t context_recv_yield_continue(lua_State* L); + static int32_t context_recv_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t context_recv_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat); static int32_t context_wait_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); - static int32_t context_wait_yield_continue(lua_State* L); + static int32_t context_wait_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t context_wait_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat); static int32_t context_strerror(lua_State *L); static int32_t context_self(lua_State *L); diff --git a/src/lcororep.cpp b/src/lcororep.cpp index 2ce88d2..e2504f2 100644 --- a/src/lcororep.cpp +++ b/src/lcororep.cpp @@ -1,7 +1,7 @@ #include "common.h" #include "context_lua.h" -static int lua_coresume (lua_State *L); +static int32_t coresume_continue(lua_State *L, int status, lua_KContext ctx); static int auxresume (lua_State *L, lua_State *co, int narg) { int status, stacks; @@ -23,7 +23,7 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { context_lua_t *lctx = context_lua_t::lua_get_context(L); while (((status = lua_resume(co, L, narg)) == LUA_YIELD) && lctx->yielding_up()) { /* can happen only when status == LUA_YIELD */ if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_yieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */ - return lua_yieldk(L, 0, 0, lua_coresume); /* yield again! n(0) result to yield and ctx(0) is not allowed */ + return lua_yieldk(L, 0, 0, coresume_continue); /* yield again! n(0) result to yield and ctx(0) is not allowed */ } else { /* lua_gettop(co) must be 0 since context_lua_t::lua_yield_send yield 0 result */ int yieldup_status = stacks ? NL_EYIELD : NL_ESTACKLESS; lctx->yielding_finalize(NULL, yieldup_status); @@ -49,7 +49,6 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { } } - static int lua_coresume (lua_State *L) { lua_State *co = lua_tothread(L, 1); int r; @@ -67,6 +66,10 @@ static int lua_coresume (lua_State *L) { } } +static int32_t coresume_continue(lua_State *L, int status, lua_KContext ctx) +{ + return lua_coresume(L); +} static int lua_auxwrap (lua_State *L) { lua_State *co = lua_tothread(L, lua_upvalueindex(1)); diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 7090821..0c3d46d 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -143,7 +143,7 @@ int32_t lua_tcp_listen_handle_t::listen_yield_finalize(lua_State *root_coro, lua return UV_OK; } -int32_t lua_tcp_listen_handle_t::listen_yield_continue(lua_State* L) +int32_t lua_tcp_listen_handle_t::listen_yield_continue(lua_State* L, int status, lua_KContext ctx) { uv_tcp_listen_handle_t* listen_handle = (uv_tcp_listen_handle_t*)lua_touserdata(L, -3); if (listen_handle) { @@ -226,7 +226,7 @@ int32_t lua_tcp_listen_handle_t::accept_yield_finalize(lua_State *root_coro, lua return UV_OK; } -int32_t lua_tcp_listen_handle_t::accept_yield_continue(lua_State* L) +int32_t lua_tcp_listen_handle_t::accept_yield_continue(lua_State* L, int status, lua_KContext ctx) { uv_tcp_socket_handle_t* accept_handle = (uv_tcp_socket_handle_t*)lua_touserdata(L, -3); if (accept_handle) { @@ -487,7 +487,7 @@ int32_t lua_tcp_socket_handle_t::connect_callback_adjust(lua_State* L) return 2; } -int32_t lua_tcp_socket_handle_t::connect_yield_continue(lua_State* L) +int32_t lua_tcp_socket_handle_t::connect_yield_continue(lua_State* L, int status, lua_KContext ctx) { uv_tcp_socket_handle_t* connect_handle = (uv_tcp_socket_handle_t*)lua_touserdata(L, -3); if (connect_handle) { diff --git a/src/lua_tcp_handle.h b/src/lua_tcp_handle.h index 3852e4b..0b8a010 100644 --- a/src/lua_tcp_handle.h +++ b/src/lua_tcp_handle.h @@ -30,8 +30,8 @@ class lua_tcp_listen_handle_t : public lua_handle_base_t static int32_t accept_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t listen_callback_adjust(lua_State* L); static int32_t accept_callback_adjust(lua_State* L); - static int32_t listen_yield_continue(lua_State* L); - static int32_t accept_yield_continue(lua_State* L); + static int32_t listen_yield_continue(lua_State* L, int status, lua_KContext ctx); + static int32_t accept_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t accept_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat); private: @@ -66,7 +66,7 @@ class lua_tcp_socket_handle_t : public lua_handle_base_t static int32_t write_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t read_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t connect_callback_adjust(lua_State* L); - static int32_t connect_yield_continue(lua_State* L); + static int32_t connect_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t read_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat); public: diff --git a/src/lua_timer_handle.cpp b/src/lua_timer_handle.cpp index df1335c..66146a2 100644 --- a/src/lua_timer_handle.cpp +++ b/src/lua_timer_handle.cpp @@ -26,7 +26,7 @@ int32_t lua_timer_handle_t::sleep_yield_finalize(lua_State *root_coro, lua_State return UV_OK; } -int32_t lua_timer_handle_t::sleep_yield_continue(lua_State* L) +int32_t lua_timer_handle_t::sleep_yield_continue(lua_State* L, int status, lua_KContext ctx) { return 0; } diff --git a/src/lua_timer_handle.h b/src/lua_timer_handle.h index 716b87f..cbff549 100644 --- a/src/lua_timer_handle.h +++ b/src/lua_timer_handle.h @@ -38,7 +38,7 @@ class lua_timer_handle_t : public lua_handle_base_t private: static int32_t sleep_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); - static int32_t sleep_yield_continue(lua_State* L); + static int32_t sleep_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t timer_callback_adjust(lua_State* L); public: From 93d0a15c8f78ea6c3cf002da16dd1dc0a73e989d Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 25 Mar 2016 01:50:31 +0800 Subject: [PATCH 004/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0lua52=20lua51?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E5=AE=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clib/mime/Makefile | 2 +- src/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clib/mime/Makefile b/clib/mime/Makefile index 5614969..34fc0eb 100644 --- a/clib/mime/Makefile +++ b/clib/mime/Makefile @@ -19,7 +19,7 @@ LIBRARY_PATH := ../../deps/lua LIBS := nlua ## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_ALL +CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) CFLAGS += -D RELEASE endif diff --git a/src/Makefile b/src/Makefile index 1cb96f7..92bfbe2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,7 @@ LIBRARY_PATH := ../deps/lua ../deps/uv LIBS := nlua uv m ## define CFLAGS -CFLAGS += -g -pedantic -O3 -Wall -Wextra -Wno-unused-parameter -D LUA_COMPAT_ALL +CFLAGS += -g -pedantic -O3 -Wall -Wextra -Wno-unused-parameter -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) CFLAGS += -D RELEASE endif From 289ab5dc2223958c6fa4123567bbd2de1f7a1d90 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 28 Mar 2016 00:46:39 +0800 Subject: [PATCH 005/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96soc?= =?UTF-8?q?ket=20local=20fd(=E6=9C=8D=E5=8A=A1=E5=86=85=E5=94=AF=E4=B8=80)?= =?UTF-8?q?=E5=92=8Cremote=20fd(=E6=9C=8D=E5=8A=A1=E9=97=B4=E5=94=AF?= =?UTF-8?q?=E4=B8=80)=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lua_handle_base.cpp | 2 ++ src/lua_handle_base.h | 6 ++--- src/lua_tcp_handle.cpp | 49 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/lua_handle_base.cpp b/src/lua_handle_base.cpp index 9bae4a7..3414d03 100644 --- a/src/lua_handle_base.cpp +++ b/src/lua_handle_base.cpp @@ -2,6 +2,7 @@ #include "network.h" #include "uv_handle_base.h" #include "lua_handle_base.h" +#include "context_lua.h" char lua_handle_base_t::m_lua_ref_table_key = 0; @@ -155,3 +156,4 @@ int32_t lua_handle_base_t::is_closed(lua_State* L) lua_pushboolean(L, handle == NULL || handle->is_closed()); return 1; } + diff --git a/src/lua_handle_base.h b/src/lua_handle_base.h index 8dfa02a..64caf5e 100644 --- a/src/lua_handle_base.h +++ b/src/lua_handle_base.h @@ -12,9 +12,9 @@ class lua_handle_base_t virtual ~lua_handle_base_t() {}; public: - int32_t get_handle_ref() const { return m_lua_ref; }; - bool is_closed() const { return m_uv_handle == NULL; }; - handle_set get_handle_set() const { return m_handle_set; }; + FORCE_INLINE int32_t get_handle_ref() const { return m_lua_ref; }; + FORCE_INLINE bool is_closed() const { return m_uv_handle == NULL; }; + FORCE_INLINE handle_set get_handle_set() const { return m_handle_set; }; uv_handle_type get_uv_handle_type() const; virtual bool set_option(uint8_t type, const char* option, uint8_t option_len); static int32_t close(lua_State* L); diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 0c3d46d..da7bf35 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -20,15 +20,23 @@ static int32_t lua_tcp_close(lua_State* L) } } -static int32_t lua_tcp_is_closed(lua_State* L) +static lua_handle_base_t* lua_check_tcp_handle(lua_State* L, int32_t idx) { lua_handle_base_t* handle; - handle = (lua_handle_base_t*)luaL_testudata(L, 1, TCP_LISTEN_SOCKET_METATABLE); + handle = (lua_handle_base_t*)luaL_testudata(L, idx, TCP_LISTEN_SOCKET_METATABLE); if (handle != NULL) { - lua_pushboolean(L, handle->is_closed()); - return 1; + return handle; } - handle = (lua_handle_base_t*)luaL_testudata(L, 1, TCP_SOCKET_METATABLE); + handle = (lua_handle_base_t*)luaL_testudata(L, idx, TCP_SOCKET_METATABLE); + if (handle != NULL) { + return handle; + } + return NULL; +} + +static int32_t lua_tcp_is_closed(lua_State* L) +{ + lua_handle_base_t* handle = lua_check_tcp_handle(L, 1); if (handle != NULL) { lua_pushboolean(L, handle->is_closed()); return 1; @@ -37,6 +45,27 @@ static int32_t lua_tcp_is_closed(lua_State* L) return 1; } +static int32_t get_local_fd(lua_State* L) +{ + lua_handle_base_t* handle = lua_check_tcp_handle(L, 1); + if (handle != NULL) { + lua_pushinteger(L, handle->get_handle_ref()); + return 1; + } + return 0; +} + +static int32_t get_remote_fd(lua_State* L) +{ + lua_handle_base_t* handle = lua_check_tcp_handle(L, 1); + if (handle != NULL) { + int64_t fd = ((int64_t)handle->get_handle_ref() % 1000000) + 1000000 * (int64_t)context_lua_t::lua_get_context_handle(L); + lua_pushinteger(L, fd); + return 1; + } + return 0; +} + ///////////////////////////////////////////////////////////////////////////////////////////////////////// lua_tcp_listen_handle_t* lua_tcp_listen_handle_t::create_tcp_listen_socket(uv_tcp_listen_handle_t* handle, lua_State* L) @@ -53,6 +82,10 @@ lua_tcp_listen_handle_t* lua_tcp_listen_handle_t::create_tcp_listen_socket(uv_tc lua_setfield(L, -2, "close"); lua_pushcfunction(L, lua_tcp_is_closed); lua_setfield(L, -2, "is_closed"); + lua_pushcfunction(L, get_local_fd); + lua_setfield(L, -2, "local_fd"); + lua_pushcfunction(L, get_remote_fd); + lua_setfield(L, -2, "remote_fd"); } lua_setmetatable(L, -2); return socket; @@ -352,6 +385,10 @@ lua_tcp_socket_handle_t* lua_tcp_socket_handle_t::create_tcp_socket(uv_tcp_socke lua_setfield(L, -2, "set_nodelay"); lua_pushcfunction(L, lua_tcp_is_closed); lua_setfield(L, -2, "is_closed"); + lua_pushcfunction(L, get_local_fd); + lua_setfield(L, -2, "local_fd"); + lua_pushcfunction(L, get_remote_fd); + lua_setfield(L, -2, "remote_fd"); } lua_setmetatable(L, -2); return socket; @@ -893,6 +930,8 @@ int luaopen_tcp(lua_State *L) { "set_nodelay", lua_tcp_socket_handle_t::set_nodelay }, { "close", lua_tcp_close }, { "is_closed", lua_tcp_is_closed }, + { "local_fd", get_local_fd }, + { "remote_fd", get_remote_fd }, { NULL, NULL }, }; luaL_newlib(L, l); From e58eed40c576a9c91a90559fdd9c1507ced77f13 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 28 Mar 2016 01:17:11 +0800 Subject: [PATCH 006/173] =?UTF-8?q?=E4=BC=98=E5=8C=96fd=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lua_tcp_handle.cpp | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index da7bf35..1993987 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -45,17 +45,7 @@ static int32_t lua_tcp_is_closed(lua_State* L) return 1; } -static int32_t get_local_fd(lua_State* L) -{ - lua_handle_base_t* handle = lua_check_tcp_handle(L, 1); - if (handle != NULL) { - lua_pushinteger(L, handle->get_handle_ref()); - return 1; - } - return 0; -} - -static int32_t get_remote_fd(lua_State* L) +static int32_t get_fd(lua_State* L) { lua_handle_base_t* handle = lua_check_tcp_handle(L, 1); if (handle != NULL) { @@ -82,10 +72,8 @@ lua_tcp_listen_handle_t* lua_tcp_listen_handle_t::create_tcp_listen_socket(uv_tc lua_setfield(L, -2, "close"); lua_pushcfunction(L, lua_tcp_is_closed); lua_setfield(L, -2, "is_closed"); - lua_pushcfunction(L, get_local_fd); - lua_setfield(L, -2, "local_fd"); - lua_pushcfunction(L, get_remote_fd); - lua_setfield(L, -2, "remote_fd"); + lua_pushcfunction(L, get_fd); + lua_setfield(L, -2, "fd"); } lua_setmetatable(L, -2); return socket; @@ -385,10 +373,8 @@ lua_tcp_socket_handle_t* lua_tcp_socket_handle_t::create_tcp_socket(uv_tcp_socke lua_setfield(L, -2, "set_nodelay"); lua_pushcfunction(L, lua_tcp_is_closed); lua_setfield(L, -2, "is_closed"); - lua_pushcfunction(L, get_local_fd); - lua_setfield(L, -2, "local_fd"); - lua_pushcfunction(L, get_remote_fd); - lua_setfield(L, -2, "remote_fd"); + lua_pushcfunction(L, get_fd); + lua_setfield(L, -2, "fd"); } lua_setmetatable(L, -2); return socket; @@ -930,8 +916,7 @@ int luaopen_tcp(lua_State *L) { "set_nodelay", lua_tcp_socket_handle_t::set_nodelay }, { "close", lua_tcp_close }, { "is_closed", lua_tcp_is_closed }, - { "local_fd", get_local_fd }, - { "remote_fd", get_remote_fd }, + { "fd", get_fd }, { NULL, NULL }, }; luaL_newlib(L, l); From 8ca6a8fb5b3465b63ee60bfdeb6b5ecea6d075c9 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 28 Mar 2016 15:17:12 +0800 Subject: [PATCH 007/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0int64=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E4=BC=A0=E8=BE=93=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 30 +++++++++++++++++++++--------- src/lua_tcp_handle.cpp | 13 +++++++++---- src/lua_tcp_handle.h | 1 + src/message.h | 14 +++++++++++--- src/request.h | 12 ++++++++++++ src/uv_handle_base.cpp | 4 ++-- 6 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 5cd523c..e60fb2d 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -71,7 +71,7 @@ bool context_lua_t::init(int32_t argc, char* argv[], char* env[]) } printf("[alert] context:0x%08x init: %s\n", m_handle, args); /* to be implemented : put reason to another context and output it */ nl_free(args); - return singleton_ref(node_lua_t).context_send(this, m_handle, 0, LUA_CTX_INIT, (double)argc); + return singleton_ref(node_lua_t).context_send(this, m_handle, 0, LUA_CTX_INIT, (int64_t)argc); } bool context_lua_t::deinit(const char *arg) @@ -537,6 +537,9 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) case NUMBER: lua_pushnumber(L, message_number(message)); return; + case INTEGER: + lua_pushinteger(L, message_integer(message)); + return; case BUFFER: create_buffer(L, message_buffer(message)); return; @@ -675,7 +678,7 @@ void context_lua_t::on_dropped(message_t& message) } return; case LUA_CTX_WAIT: - singleton_ref(node_lua_t).context_send(message.m_source, (uint32_t)message_number(message), LUA_REFNIL, LUA_CTX_WAKEUP, UV_OK); + singleton_ref(node_lua_t).context_send(message.m_source, (uint32_t)message_integer(message), LUA_REFNIL, LUA_CTX_WAKEUP, UV_OK); return; default: break; @@ -684,7 +687,7 @@ void context_lua_t::on_dropped(message_t& message) void context_lua_t::lua_ctx_init(message_t& message) { - int32_t argc = (int32_t)message_number(message); + int32_t argc = (int32_t)message_integer(message); int32_t envc = lua_gettop(m_lstate) - argc; const char *file = lua_tostring(m_lstate, 1); if (luaL_loadfile(m_lstate, file) == LUA_OK) { @@ -759,7 +762,7 @@ void context_lua_t::response_tcp_read(message_t& response) void context_lua_t::response_handle_close(message_t& response) { - lua_handle_base_t::release_ref(m_lstate, response.m_session, (handle_set)(int32_t)message_number(response)); + lua_handle_base_t::release_ref(m_lstate, response.m_session, (handle_set)(int32_t)message_integer(response)); } void context_lua_t::response_tcp_closing(message_t& response) @@ -827,8 +830,13 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t buffer_t* buffer; switch (lua_type(L, idx)) { case LUA_TNUMBER: - message.m_type = MAKE_MESSAGE_TYPE(msg_type, NUMBER); - message.m_data.m_number = (double)lua_tonumber(L, idx); + if (lua_isinteger(L, idx)) { + message.m_type = MAKE_MESSAGE_TYPE(msg_type, INTEGER); + message.m_data.m_integer = (int64_t)lua_tointeger(L, idx); + } else { + message.m_type = MAKE_MESSAGE_TYPE(msg_type, NUMBER); + message.m_data.m_number = (double)lua_tonumber(L, idx); + } message.m_source = lua_get_context_handle(L); return UV_OK; case LUA_TSTRING: @@ -870,7 +878,11 @@ int32_t context_lua_t::context_send(lua_State *L, int32_t idx, uint32_t handle, context_t* ctx = lua_get_context(L); switch (lua_type(L, idx)) { case LUA_TNUMBER: - ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (double)lua_tonumber(L, idx)); + if (lua_isinteger(L, idx)) { + ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (int64_t)lua_tointeger(L, idx)); + } else { + ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (double)lua_tonumber(L, idx)); + } break; case LUA_TSTRING: ret = singleton_ref(node_lua_t).context_send_string_safe(handle, ctx->get_handle(), session, msg_type, lua_tostring(L, idx)); @@ -1076,7 +1088,7 @@ int32_t context_lua_t::context_wait_yield_finalize(lua_State *root_coro, lua_Sta { if (root_coro != NULL) { context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); - if (singleton_ref(node_lua_t).context_send(destination, lctx->get_handle(), LUA_REFNIL, LUA_CTX_WAIT, (double)destination)) { + if (singleton_ref(node_lua_t).context_send(destination, lctx->get_handle(), LUA_REFNIL, LUA_CTX_WAIT, (int64_t)destination)) { int32_t session = lctx->m_context_wait_sessions.push_blocking(destination, root_coro); int64_t timeout = lctx->get_yielding_timeout(); if (timeout > 0) { @@ -1141,7 +1153,7 @@ int32_t context_lua_t::context_wait(lua_State *L) } if (callback > 0) { //nonblocking lua_settop(L, callback); - if (singleton_ref(node_lua_t).context_send(handle, lctx->get_handle(), LUA_REFNIL, LUA_CTX_WAIT, (double)handle)) { + if (singleton_ref(node_lua_t).context_send(handle, lctx->get_handle(), LUA_REFNIL, LUA_CTX_WAIT, (int64_t)handle)) { lctx->m_context_wait_sessions.make_nonblocking_callback(handle, L, callback - 1, common_callback_adjust, &session); if (timeout > 0) { context_lua_t::lua_ref_timer(L, session, timeout, 0, false, (void*)handle, context_wait_timeout); diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 1993987..a273351 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -45,7 +45,7 @@ static int32_t lua_tcp_is_closed(lua_State* L) return 1; } -static int32_t get_fd(lua_State* L) +static int32_t lua_tcp_get_fd(lua_State* L) { lua_handle_base_t* handle = lua_check_tcp_handle(L, 1); if (handle != NULL) { @@ -72,7 +72,7 @@ lua_tcp_listen_handle_t* lua_tcp_listen_handle_t::create_tcp_listen_socket(uv_tc lua_setfield(L, -2, "close"); lua_pushcfunction(L, lua_tcp_is_closed); lua_setfield(L, -2, "is_closed"); - lua_pushcfunction(L, get_fd); + lua_pushcfunction(L, lua_tcp_get_fd); lua_setfield(L, -2, "fd"); } lua_setmetatable(L, -2); @@ -373,7 +373,7 @@ lua_tcp_socket_handle_t* lua_tcp_socket_handle_t::create_tcp_socket(uv_tcp_socke lua_setfield(L, -2, "set_nodelay"); lua_pushcfunction(L, lua_tcp_is_closed); lua_setfield(L, -2, "is_closed"); - lua_pushcfunction(L, get_fd); + lua_pushcfunction(L, lua_tcp_get_fd); lua_setfield(L, -2, "fd"); } lua_setmetatable(L, -2); @@ -525,6 +525,11 @@ int32_t lua_tcp_socket_handle_t::connect_yield_continue(lua_State* L, int status return 2; } +int32_t lua_tcp_socket_handle_t::write2(lua_State* L) +{ + return 0; +} + int32_t lua_tcp_socket_handle_t::write(lua_State* L) { lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)luaL_checkudata(L, 1, TCP_SOCKET_METATABLE); @@ -916,7 +921,7 @@ int luaopen_tcp(lua_State *L) { "set_nodelay", lua_tcp_socket_handle_t::set_nodelay }, { "close", lua_tcp_close }, { "is_closed", lua_tcp_is_closed }, - { "fd", get_fd }, + { "fd", lua_tcp_get_fd }, { NULL, NULL }, }; luaL_newlib(L, l); diff --git a/src/lua_tcp_handle.h b/src/lua_tcp_handle.h index 0b8a010..3e53ef2 100644 --- a/src/lua_tcp_handle.h +++ b/src/lua_tcp_handle.h @@ -55,6 +55,7 @@ class lua_tcp_socket_handle_t : public lua_handle_base_t static int32_t connect6(lua_State* L); static int32_t connects(lua_State* L); static int32_t write(lua_State* L); + static int32_t write2(lua_State* L); static int32_t read(lua_State* L); static int32_t set_rwopt(lua_State* L); static int32_t get_rwopt(lua_State* L); diff --git a/src/message.h b/src/message.h index 953b94e..956e4da 100644 --- a/src/message.h +++ b/src/message.h @@ -14,15 +14,17 @@ enum data_type { TBOOLEAN = 1, USERDATA = 2, //light userdata NUMBER = 3, - BUFFER = 4, //need to be freed - STRING = 5, //need to be freed - TERROR = 6 // + INTEGER = 4, //support after lua53 + BUFFER = 5, //need to be freed + STRING = 6, //need to be freed + TERROR = 7 // }; typedef union data_t { bool m_bool; void *m_userdata; double m_number; + int64_t m_integer; buffer_t m_buffer; char *m_string; int32_t m_error; @@ -54,6 +56,7 @@ enum message_type { #define message_bool(msg) ((msg).m_data.m_bool) #define message_userdata(msg) ((msg).m_data.m_userdata) #define message_number(msg) ((msg).m_data.m_number) +#define message_integer(msg) ((msg).m_data.m_integer) #define message_buffer(msg) ((msg).m_data.m_buffer) #define message_string(msg) ((msg).m_data.m_string) #define message_error(msg) ((msg).m_data.m_error) @@ -63,6 +66,7 @@ enum message_type { #define message_is_bool(msg) (TBOOLEAN == message_data_type(msg)) #define message_is_userdata(msg) (USERDATA == message_data_type(msg)) #define message_is_number(msg) (NUMBER == message_data_type(msg)) +#define message_is_integer(msg) (INTEGER == message_data_type(msg)) #define message_is_buffer(msg) (BUFFER == message_data_type(msg)) #define message_is_string(msg) (STRING == message_data_type(msg)) #define message_is_error(msg) (TERROR == message_data_type(msg)) @@ -105,6 +109,10 @@ class message_t { message_t(uint32_t source, int32_t session, uint32_t msg_type, double number) : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, NUMBER)) { m_data.m_number = number; } + + message_t(uint32_t source, int32_t session, uint32_t msg_type, int64_t integer) + : m_source(source), m_session(session), + m_type(MAKE_MESSAGE_TYPE(msg_type, INTEGER)) { m_data.m_integer = integer; } message_t(uint32_t source, int32_t session, uint32_t msg_type, char *string) : m_source(source), m_session(session), diff --git a/src/request.h b/src/request.h index d18c7ea..ba39fe6 100644 --- a/src/request.h +++ b/src/request.h @@ -91,6 +91,17 @@ struct request_tcp_write_t { REQUEST_SPARE_REGION }; +/* write by shared fd */ +struct request_tcp_write2_t { + uint64_t m_fd; + uint32_t m_length; + union { + const char* m_string; + buffer_t m_buffer; + }; + REQUEST_SPARE_REGION +}; + struct request_handle_option_t { uv_handle_base_t *m_handle; uint8_t m_option_type; @@ -123,6 +134,7 @@ struct request_t { request_tcp_connects_t m_tcp_connects; request_tcp_read_t m_tcp_read; request_tcp_write_t m_tcp_write; + request_tcp_write2_t m_tcp_write2; request_handle_option_t m_handle_option; request_handle_close_t m_handle_close; request_timer_start_t m_timer_start; diff --git a/src/uv_handle_base.cpp b/src/uv_handle_base.cpp index b133881..70879b5 100644 --- a/src/uv_handle_base.cpp +++ b/src/uv_handle_base.cpp @@ -70,7 +70,7 @@ void uv_handle_base_t::close() if (m_handle) { uv_close(m_handle, on_closed); } else if (m_lua_ref != LUA_REFNIL) { - singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_HANDLE_CLOSE, (double)get_handle_set()); + singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_HANDLE_CLOSE, (int64_t)get_handle_set()); delete this; } } @@ -79,7 +79,7 @@ void uv_handle_base_t::on_closed(uv_handle_t* handle) { uv_handle_base_t* tcp_handle = (uv_handle_base_t*)handle->data; if (tcp_handle->m_lua_ref != LUA_REFNIL) { - singleton_ref(node_lua_t).context_send(tcp_handle->m_source, 0, tcp_handle->m_lua_ref, RESPONSE_HANDLE_CLOSE, (double)(tcp_handle->get_handle_set())); + singleton_ref(node_lua_t).context_send(tcp_handle->m_source, 0, tcp_handle->m_lua_ref, RESPONSE_HANDLE_CLOSE, (int64_t)(tcp_handle->get_handle_set())); } delete tcp_handle; } From bee7b860914491ec4d29a4015140ca28cb06119c Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 28 Mar 2016 21:09:04 +0800 Subject: [PATCH 008/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0tcp=20fd=E7=9A=84?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E5=86=99=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lua_tcp_handle.cpp | 32 ++++++++++++++++++++++++++++++++ src/network.cpp | 5 +++++ src/network.h | 1 + src/request.h | 1 + 4 files changed, 39 insertions(+) diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index a273351..585f662 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -527,6 +527,37 @@ int32_t lua_tcp_socket_handle_t::connect_yield_continue(lua_State* L, int status int32_t lua_tcp_socket_handle_t::write2(lua_State* L) { + int64_t fd = luaL_checkinteger(L, 1); + if (fd <= 0) { + return 0; + } + const char *s = NULL; + uint32_t length; + buffer_t* buffer = NULL; + if (((s = lua_tolstring(L, 2, (size_t*)&length)) == NULL) && ((buffer = (buffer_t*)luaL_testudata(L, 2, BUFFER_METATABLE)) == NULL)) { + luaL_argerror(L, 2, "string expected"); + } + if (buffer) { + length = (uint32_t)buffer_data_length(*buffer); + } + if (length == 0) { + return 0; + } + request_t request; + request.m_type = REQUEST_TCP_WRITE2; + request.m_length = REQUEST_SIZE(request_tcp_write2_t, 0); + request.m_tcp_write2.m_fd = fd; + if (s) { + request.m_tcp_write2.m_length = length; /* length > 0 */ + request.m_tcp_write2.m_string = (const char*)nl_memdup(s, length); + if (!request.m_tcp_write2.m_string) { + return luaL_error(L, "attempt to send data(length %lu) failed: memory not enough", length); + } + } else { + request.m_tcp_write2.m_length = 0; + request.m_tcp_write2.m_buffer = buffer_grab(*buffer); + } + singleton_ref(network_t).send_request(request); return 0; } @@ -915,6 +946,7 @@ int luaopen_tcp(lua_State *L) { "connect6", lua_tcp_socket_handle_t::connect6 }, { "connects", lua_tcp_socket_handle_t::connects }, { "write", lua_tcp_socket_handle_t::write }, + { "write2", lua_tcp_socket_handle_t::write2 }, { "read", lua_tcp_socket_handle_t::read }, { "set_rwopt", lua_tcp_socket_handle_t::set_rwopt }, { "get_rwopt", lua_tcp_socket_handle_t::get_rwopt }, diff --git a/src/network.cpp b/src/network.cpp index 4c76e6c..f67dacb 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -135,6 +135,11 @@ void network_t::request_tcp_write(request_tcp_write_t& request) request.m_socket_handle->write(request); } +void network_t::request_tcp_write2(request_tcp_write2_t& request) +{ + +} + void network_t::request_handle_option(request_handle_option_t& request) { request.m_handle->set_option(request.m_option_type, REQUEST_SPARE_PTR(request)); diff --git a/src/network.h b/src/network.h index 5b97423..c3a4aa9 100644 --- a/src/network.h +++ b/src/network.h @@ -43,6 +43,7 @@ class network_t : public singleton_t { void request_tcp_connect(request_tcp_connect_t& request); void request_tcp_connects(request_tcp_connects_t& request); void request_tcp_write(request_tcp_write_t& request); + void request_tcp_write2(request_tcp_write2_t& request); void request_tcp_read(request_tcp_read_t& request); void request_handle_option(request_handle_option_t& request); void request_handle_close(request_handle_close_t& request); diff --git a/src/request.h b/src/request.h index ba39fe6..464632f 100644 --- a/src/request.h +++ b/src/request.h @@ -25,6 +25,7 @@ enum request_type { REQUEST_TCP_CONNECTS, REQUEST_TCP_READ, REQUEST_TCP_WRITE, + REQUEST_TCP_WRITE2, REQUEST_HANDLE_OPTION, REQUEST_HANDLE_CLOSE, REQUEST_TIMER_START From 4ee9f0384630400d708e09320097daca2ba46d88 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 29 Mar 2016 22:16:02 +0800 Subject: [PATCH 009/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0tcp=20socket=E7=9A=84?= =?UTF-8?q?=E5=85=B1=E4=BA=AB=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lua_handle_base.cpp | 4 ++- src/lua_tcp_handle.cpp | 17 ++++++++++--- src/lua_tcp_handle.h | 3 +++ src/network.cpp | 5 +++- src/request.h | 4 +-- src/uv_tcp_handle.cpp | 55 +++++++++++++++++++++++++++++++++++++++++ src/uv_tcp_handle.h | 19 ++++++++++---- 7 files changed, 95 insertions(+), 12 deletions(-) diff --git a/src/lua_handle_base.cpp b/src/lua_handle_base.cpp index 3414d03..70a309e 100644 --- a/src/lua_handle_base.cpp +++ b/src/lua_handle_base.cpp @@ -112,7 +112,9 @@ bool lua_handle_base_t::set_option(uint8_t type, const char *option, uint8_t opt request.m_length = REQUEST_SIZE(request_handle_option_t, option_len); request.m_handle_option.m_handle = m_uv_handle; request.m_handle_option.m_option_type = type; - memcpy(REQUEST_SPARE_PTR(request.m_handle_option), option, option_len); + if (option_len > 0) { + memcpy(REQUEST_SPARE_PTR(request.m_handle_option), option, option_len); + } singleton_ref(network_t).send_request(request); return true; } diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 585f662..49ab519 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -49,7 +49,7 @@ static int32_t lua_tcp_get_fd(lua_State* L) { lua_handle_base_t* handle = lua_check_tcp_handle(L, 1); if (handle != NULL) { - int64_t fd = ((int64_t)handle->get_handle_ref() % 1000000) + 1000000 * (int64_t)context_lua_t::lua_get_context_handle(L); + int64_t fd = TCP_SOCKET_MAKE_FD(handle->get_handle_ref(), context_lua_t::lua_get_context_handle(L)); lua_pushinteger(L, fd); return 1; } @@ -865,9 +865,20 @@ int32_t lua_tcp_socket_handle_t::get_rwopt(lua_State* L) int32_t lua_tcp_socket_handle_t::set_nodelay(lua_State* L) { - lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)luaL_testudata(L, 1, TCP_SOCKET_METATABLE); + lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)luaL_checkudata(L, 1, TCP_SOCKET_METATABLE); if (!socket->is_closed() && socket->get_uv_handle_type() == UV_TCP) { - socket->set_option(OPT_TCP_NODELAY, lua_toboolean(L, 2) ? "\x01\0" : "\0\0", 2); + socket->set_option(OPT_TCP_NODELAY, lua_toboolean(L, 2) ? "\x01\0" : "\x00\0", 2); + } + return 0; +} + +int32_t lua_tcp_socket_handle_t::set_wshared(lua_State* L) +{ + lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)luaL_checkudata(L, 1, TCP_SOCKET_METATABLE); + if (!socket->is_closed()) { + socket->set_option(OPT_TCP_WSHARED, lua_toboolean(L, 2) ? "\x01\0" : "\x00\0", 2); + uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)socket->m_uv_handle; + froze_head_option(handle->m_write_head_option); } return 0; } diff --git a/src/lua_tcp_handle.h b/src/lua_tcp_handle.h index 3e53ef2..fbbe0fc 100644 --- a/src/lua_tcp_handle.h +++ b/src/lua_tcp_handle.h @@ -6,6 +6,8 @@ #include "context_lua.h" #include +#define TCP_SOCKET_MAKE_FD(lua_ref, context_id) ((int64_t)(lua_ref)/1000000 + 1000000*(int64_t)(context_id)) + class context_lua_t; class uv_handle_base_t; class uv_tcp_listen_handle_t; @@ -60,6 +62,7 @@ class lua_tcp_socket_handle_t : public lua_handle_base_t static int32_t set_rwopt(lua_State* L); static int32_t get_rwopt(lua_State* L); static int32_t set_nodelay(lua_State* L); + static int32_t set_wshared(lua_State* L); static int32_t close(lua_State* L); private: static int32_t _connect(lua_State* L, bool ipv6); diff --git a/src/network.cpp b/src/network.cpp index f67dacb..35992ff 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -137,7 +137,7 @@ void network_t::request_tcp_write(request_tcp_write_t& request) void network_t::request_tcp_write2(request_tcp_write2_t& request) { - + uv_tcp_socket_handle_t::write2(request); } void network_t::request_handle_option(request_handle_option_t& request) @@ -217,6 +217,9 @@ void network_t::process_request(request_t& request) case REQUEST_TCP_WRITE: request_tcp_write(request.m_tcp_write); break; + case REQUEST_TCP_WRITE2: + request_tcp_write2(request.m_tcp_write2); + break; case REQUEST_TCP_READ: request_tcp_read(request.m_tcp_read); break; diff --git a/src/request.h b/src/request.h index 464632f..722b265 100644 --- a/src/request.h +++ b/src/request.h @@ -84,7 +84,7 @@ struct request_tcp_read_t { struct request_tcp_write_t { uv_tcp_socket_handle_t *m_socket_handle; uint32_t m_session; - uint32_t m_length; + uint32_t m_length; /* judge it's string or buffer */ union { const char* m_string; buffer_t m_buffer; @@ -95,7 +95,7 @@ struct request_tcp_write_t { /* write by shared fd */ struct request_tcp_write2_t { uint64_t m_fd; - uint32_t m_length; + uint32_t m_length; /* judge it's string or buffer */ union { const char* m_string; buffer_t m_buffer; diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index d5a8a31..f339874 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -2,6 +2,7 @@ #include "network.h" #include "node_lua.h" #include "uv_tcp_handle.h" +#include "lua_tcp_handle.h" void uv_tcp_listen_handle_t::on_accept(uv_stream_t* server, int status) { @@ -84,6 +85,7 @@ void uv_tcp_listen_handle_t::accept(request_tcp_accept_t& request) #define LARGE_UNCOMPLETE_LIMIT (1 * 1024) #define SHARED_READ_BUFFER_SIZE (64 * 1024) uv_buf_t uv_tcp_socket_handle_t::m_shared_read_buffer = { 0, NULL, }; +write_shared_map_t uv_tcp_socket_handle_t::m_write_shared_sockets; void uv_tcp_socket_handle_t::make_shared_read_buffer() { @@ -103,6 +105,13 @@ void uv_tcp_socket_handle_t::free_shared_read_buffer() } } +uv_tcp_socket_handle_t::~uv_tcp_socket_handle_t() +{ + clear_read_cached_buffers(); + clear_write_cached_requests(); + m_write_shared_sockets.erase(TCP_SOCKET_MAKE_FD(m_lua_ref, m_source)); +} + void uv_tcp_socket_handle_t::on_connect(uv_connect_t* req, int status) { uv_handle_t *client = (uv_handle_t*)req->handle; @@ -167,6 +176,38 @@ void uv_tcp_socket_handle_t::on_write(uv_write_t* req, int status) socket_handle->put_write_cached_request(uv_request); } +void uv_tcp_socket_handle_t::write2(request_tcp_write2_t& request) +{ + write_shared_map_t::iterator it = m_write_shared_sockets.find(request.m_fd); + if (it != m_write_shared_sockets.end()) { + uv_tcp_socket_handle_t* handle = it->second; + if (!uv_is_closing((uv_handle_t*)handle)) { + request_tcp_write_t req; + uint32_t length; + req.m_session = LUA_REFNIL; + req.m_length = request.m_length; + if (request.m_length > 0) { /* is raw string */ + req.m_string = request.m_string; + length = request.m_length; + } else { /* is buffer */ + req.m_buffer = request.m_buffer; + length = (uint32_t)buffer_data_length(request.m_buffer); + } + if (check_head_option_max(handle->m_write_head_option, length)) { + handle->write(req); + return; + } + /* to be fix : put error message "attempt to send data(length %lu) too long(max %lu)" */ + } + } + /* write error had been occurred */ + if (request.m_length > 0) { + nl_free((void*)request.m_string); + } else { + buffer_release(request.m_buffer); + } +} + /* We must response something to lua-service even error occurred. */ void uv_tcp_socket_handle_t::write(request_tcp_write_t& request) { @@ -375,6 +416,9 @@ void uv_tcp_socket_handle_t::set_option(uint8_t type, const char *option) case OPT_TCP_NODELAY: set_tcp_nodelay(*option); break; + case OPT_TCP_WSHARED: + set_tcp_wshared(*option); + break; default: break; } @@ -387,3 +431,14 @@ void uv_tcp_socket_handle_t::set_tcp_nodelay(bool enable) } } +void uv_tcp_socket_handle_t::set_tcp_wshared(bool enable) +{ + if (!uv_is_closing((uv_handle_t*)(m_handle))) { + int64_t fd = TCP_SOCKET_MAKE_FD(m_lua_ref, m_source); + if (enable) { + m_write_shared_sockets[fd] = this; + } else { + m_write_shared_sockets.erase(fd); + } + } +} diff --git a/src/uv_tcp_handle.h b/src/uv_tcp_handle.h index 1517886..ea0ecb9 100644 --- a/src/uv_tcp_handle.h +++ b/src/uv_tcp_handle.h @@ -6,6 +6,7 @@ #include "uv_handle_base.h" #include #include +#include #define TCP_TRANSPORT_DEFAULT_ENDIAN LITTLE_ENDIAN_VAL #define TCP_WRITE_UV_REQUEST_CACHE_MAX 32 @@ -28,6 +29,7 @@ typedef struct { enum tcp_option_type { OPT_TCP_NODELAY, + OPT_TCP_WSHARED, }; class uv_tcp_listen_handle_t : public uv_handle_base_t @@ -54,6 +56,8 @@ class uv_tcp_listen_handle_t : public uv_handle_base_t since nonblocking may be treated as blocking in context thread. */ }; +typedef std::map write_shared_map_t; + class uv_tcp_socket_handle_t : public uv_handle_base_t { public: @@ -70,6 +74,7 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t init_head_option(m_write_head_option); buffer_make_invalid(m_read_buffer); } + ~uv_tcp_socket_handle_t(); friend class uv_tcp_listen_handle_t; friend class lua_tcp_socket_handle_t; @@ -87,18 +92,15 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t void connect_sock(request_tcp_connects_t& request); void write(request_tcp_write_t& request); void read(request_tcp_read_t& request); + static void write2(request_tcp_write2_t& request); public: - ~uv_tcp_socket_handle_t() - { - clear_read_cached_buffers(); - clear_write_cached_requests(); - } bool read_start_state() const { return m_has_noblocking_read || m_blocking_read_count > 0; } void set_option(uint8_t type, const char *option); void set_tcp_nodelay(bool enable); + void set_tcp_wshared(bool enable); uv_err_code get_read_error() const { return m_read_error; } uv_err_code get_write_error() const { return m_write_error; } static void free_shared_read_buffer(); @@ -166,6 +168,13 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t } m_write_cached_reqs.clear(); } + +private: + static write_shared_map_t m_write_shared_sockets; + //static uv_tcp_socket_handle_t* get_write_shared_socket(int64_t fd) { + // write_shared_map_t::iterator it = m_write_shared_sockets.find(fd); + // return it != m_write_shared_sockets.end() ? it->second : NULL; + //} }; #endif From 5c6d76bb6b562214e6962f8bdc1739ade0f232c9 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 29 Mar 2016 22:18:14 +0800 Subject: [PATCH 010/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0tcp=20socket=E7=9A=84?= =?UTF-8?q?=E5=85=B1=E4=BA=AB=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/uv_tcp_handle.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/uv_tcp_handle.h b/src/uv_tcp_handle.h index ea0ecb9..95dcfed 100644 --- a/src/uv_tcp_handle.h +++ b/src/uv_tcp_handle.h @@ -171,10 +171,6 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t private: static write_shared_map_t m_write_shared_sockets; - //static uv_tcp_socket_handle_t* get_write_shared_socket(int64_t fd) { - // write_shared_map_t::iterator it = m_write_shared_sockets.find(fd); - // return it != m_write_shared_sockets.end() ? it->second : NULL; - //} }; #endif From f2713509668d39a4f501e8850a8bfa0f8adfca88 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 29 Mar 2016 23:40:00 +0800 Subject: [PATCH 011/173] =?UTF-8?q?=E4=BC=98=E5=8C=96tcp=20socket=E5=86=99?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/main.lua | 31 ++++++++++++++++++++++++++----- src/lua_tcp_handle.cpp | 3 +++ src/lua_tcp_handle.h | 2 +- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/sample/main.lua b/sample/main.lua index dba28e2..b830f7e 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -70,6 +70,7 @@ print("value", value1, value2)]] -- # define TEST_PIPENAME_2 "/tmp/uv-test-sock2" -- #endif + if context.winos then package.cpath = package.cpath ..";".."..\\clib\\?.dll" package.path = package.path ..";".."..\\lualib\\?.lua" @@ -78,20 +79,40 @@ else package.path = package.path ..";".."../lualib/?.lua" end -for i = 1, 32 do - context.create("test.lua", 1, 2, 3) -end -do return end +-- for i = 1, 32 do + -- context.create("test.lua", 1, 2, 3) +-- end +-- do return end local ret, sock = tcp.listen("0.0.0.0", 8801) if not ret then print("tcp.listens failed: ", context.strerror(sock)) else print("tcp.listens success: ", sock) - sock:accept(function(result, accept_sock) print("sock:accept", result, accept_sock) sock:close() accept_sock:set_nodelay(false) accept_sock:write("hello world!") end) + sock:accept(function(result, accept_sock) + print("sock:accept", result, accept_sock) + sock:close() + --accept_sock:set_nodelay(false) + accept_sock:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535,}) + accept_sock:set_wshared(true) + print("accept_sock:fd", accept_sock:fd()) + tcp.write2(accept_sock:fd(), "hello world!") + accept_sock:write("hello world!") + tcp.write2(accept_sock:fd(), "hello world!") + tcp.write2(accept_sock:fd(), "hello world!") + accept_sock:write("hello world!") + end) local ret, con_sock = tcp.connect("127.0.0.1", 8801) if ret then print("tcp.connect", ret, con_sock) + con_sock:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535,}) + con_sock:set_wshared(true) + local ret, buffer = con_sock:read() + print("tcp read", ret, ret and buffer:tostring()) + local ret, buffer = con_sock:read() + print("tcp read", ret, ret and buffer:tostring()) + local ret, buffer = con_sock:read() + print("tcp read", ret, ret and buffer:tostring()) local ret, buffer = con_sock:read() print("tcp read", ret, ret and buffer:tostring()) else diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 49ab519..993e23b 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -371,6 +371,8 @@ lua_tcp_socket_handle_t* lua_tcp_socket_handle_t::create_tcp_socket(uv_tcp_socke lua_setfield(L, -2, "get_rwopt"); lua_pushcfunction(L, lua_tcp_socket_handle_t::set_nodelay); lua_setfield(L, -2, "set_nodelay"); + lua_pushcfunction(L, lua_tcp_socket_handle_t::set_wshared); + lua_setfield(L, -2, "set_wshared"); lua_pushcfunction(L, lua_tcp_is_closed); lua_setfield(L, -2, "is_closed"); lua_pushcfunction(L, lua_tcp_get_fd); @@ -962,6 +964,7 @@ int luaopen_tcp(lua_State *L) { "set_rwopt", lua_tcp_socket_handle_t::set_rwopt }, { "get_rwopt", lua_tcp_socket_handle_t::get_rwopt }, { "set_nodelay", lua_tcp_socket_handle_t::set_nodelay }, + { "set_wshared", lua_tcp_socket_handle_t::set_wshared }, { "close", lua_tcp_close }, { "is_closed", lua_tcp_is_closed }, { "fd", lua_tcp_get_fd }, diff --git a/src/lua_tcp_handle.h b/src/lua_tcp_handle.h index fbbe0fc..e70babb 100644 --- a/src/lua_tcp_handle.h +++ b/src/lua_tcp_handle.h @@ -6,7 +6,7 @@ #include "context_lua.h" #include -#define TCP_SOCKET_MAKE_FD(lua_ref, context_id) ((int64_t)(lua_ref)/1000000 + 1000000*(int64_t)(context_id)) +#define TCP_SOCKET_MAKE_FD(lua_ref, context_id) ((int64_t)(lua_ref)%1000000 + 1000000*(int64_t)(context_id)) class context_lua_t; class uv_handle_base_t; From fb14faa8532c91fb34629158af7592d4679328ac Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 30 Mar 2016 00:18:28 +0800 Subject: [PATCH 012/173] =?UTF-8?q?=E4=BC=98=E5=8C=96tcp=20socket=E5=86=99?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lua_tcp_handle.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 993e23b..a7de128 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -878,9 +878,12 @@ int32_t lua_tcp_socket_handle_t::set_wshared(lua_State* L) { lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)luaL_checkudata(L, 1, TCP_SOCKET_METATABLE); if (!socket->is_closed()) { - socket->set_option(OPT_TCP_WSHARED, lua_toboolean(L, 2) ? "\x01\0" : "\x00\0", 2); - uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)socket->m_uv_handle; - froze_head_option(handle->m_write_head_option); + bool enable = lua_toboolean(L, 2); + socket->set_option(OPT_TCP_WSHARED, enable ? "\x01\0" : "\x00\0", 2); + if (enable) { + uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)socket->m_uv_handle; + froze_head_option(handle->m_write_head_option); + } } return 0; } From bd683e5ac517c15a878e3bdc411ed5daa610afe6 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 31 Mar 2016 17:27:14 +0800 Subject: [PATCH 013/173] a little thing --- src/lua_handle_base.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/lua_handle_base.cpp b/src/lua_handle_base.cpp index 70a309e..e32e555 100644 --- a/src/lua_handle_base.cpp +++ b/src/lua_handle_base.cpp @@ -7,7 +7,7 @@ char lua_handle_base_t::m_lua_ref_table_key = 0; lua_handle_base_t::lua_handle_base_t(uv_handle_base_t* handle, lua_State* L) - : m_handle_set(handle->get_handle_set()), m_lua_ref(handle->m_lua_ref), m_uv_handle(handle) + : m_handle_set(handle->get_handle_set()), m_lua_ref(LUA_REFNIL), m_uv_handle(handle) { grab_ref(L, this, m_handle_set); } @@ -46,19 +46,13 @@ int32_t lua_handle_base_t::grab_ref(lua_State* L, lua_handle_base_t* handle, han { push_ref_table(L, type); lua_pushlightuserdata(L, handle); - if (handle != NULL) { - ASSERT(type == handle->m_handle_set); - if (handle->m_lua_ref == LUA_REFNIL) { - handle->m_uv_handle->m_lua_ref = handle->m_lua_ref = luaL_ref(L, -2); - } else { - lua_rawseti(L, -2, handle->m_lua_ref); - } - lua_pop(L, 1); - return handle->m_lua_ref; - } - int32_t ref = luaL_ref(L, -2); - lua_pop(L, 1); - return ref; + ASSERT(handle != NULL); + ASSERT(handle->m_handle_set == type); + ASSERT(handle->m_uv_handle->m_lua_ref == LUA_REFNIL); + ASSERT(handle->m_lua_ref == LUA_REFNIL); + handle->m_uv_handle->m_lua_ref = handle->m_lua_ref = luaL_ref(L, -2); + lua_pop(L, 1); //pop lua_ref_table + return handle->m_lua_ref; } /* From 97585c9d0397d0490204aa4cef79f1763780e47c Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 31 Mar 2016 17:50:19 +0800 Subject: [PATCH 014/173] revert a little thing --- src/lua_handle_base.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lua_handle_base.cpp b/src/lua_handle_base.cpp index 70a309e..aa226d7 100644 --- a/src/lua_handle_base.cpp +++ b/src/lua_handle_base.cpp @@ -158,4 +158,3 @@ int32_t lua_handle_base_t::is_closed(lua_State* L) lua_pushboolean(L, handle == NULL || handle->is_closed()); return 1; } - From 5e81c2554e6e84f420e1f579ce5f133a072417fc Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 31 Mar 2016 17:52:13 +0800 Subject: [PATCH 015/173] revert a little thing --- src/lua_handle_base.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/lua_handle_base.cpp b/src/lua_handle_base.cpp index 7aa459f..70a309e 100644 --- a/src/lua_handle_base.cpp +++ b/src/lua_handle_base.cpp @@ -7,7 +7,7 @@ char lua_handle_base_t::m_lua_ref_table_key = 0; lua_handle_base_t::lua_handle_base_t(uv_handle_base_t* handle, lua_State* L) - : m_handle_set(handle->get_handle_set()), m_lua_ref(LUA_REFNIL), m_uv_handle(handle) + : m_handle_set(handle->get_handle_set()), m_lua_ref(handle->m_lua_ref), m_uv_handle(handle) { grab_ref(L, this, m_handle_set); } @@ -46,13 +46,19 @@ int32_t lua_handle_base_t::grab_ref(lua_State* L, lua_handle_base_t* handle, han { push_ref_table(L, type); lua_pushlightuserdata(L, handle); - ASSERT(handle != NULL); - ASSERT(handle->m_handle_set == type); - ASSERT(handle->m_uv_handle->m_lua_ref == LUA_REFNIL); - ASSERT(handle->m_lua_ref == LUA_REFNIL); - handle->m_uv_handle->m_lua_ref = handle->m_lua_ref = luaL_ref(L, -2); - lua_pop(L, 1); //pop lua_ref_table - return handle->m_lua_ref; + if (handle != NULL) { + ASSERT(type == handle->m_handle_set); + if (handle->m_lua_ref == LUA_REFNIL) { + handle->m_uv_handle->m_lua_ref = handle->m_lua_ref = luaL_ref(L, -2); + } else { + lua_rawseti(L, -2, handle->m_lua_ref); + } + lua_pop(L, 1); + return handle->m_lua_ref; + } + int32_t ref = luaL_ref(L, -2); + lua_pop(L, 1); + return ref; } /* @@ -152,3 +158,4 @@ int32_t lua_handle_base_t::is_closed(lua_State* L) lua_pushboolean(L, handle == NULL || handle->is_closed()); return 1; } + From 72ab9feb4d51be97f4af752857ea5b5c1f9509ce Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 31 Mar 2016 20:35:12 +0800 Subject: [PATCH 016/173] =?UTF-8?q?=E4=BC=98=E5=8C=96tcp=20socket=E7=9A=84?= =?UTF-8?q?=E5=85=B1=E4=BA=AB=E5=86=99=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.v12.suo | Bin 158720 -> 158720 bytes sample/main.lua | 12 ++++--- src/errors.h | 4 ++- src/lua_tcp_handle.cpp | 80 ++++++++++++++++++++++++++++++----------- src/lua_tcp_handle.h | 3 +- src/network.cpp | 10 +----- src/network.h | 1 - src/request.h | 20 ++++------- src/uv_tcp_handle.cpp | 68 ++++++++++++++++------------------- src/uv_tcp_handle.h | 9 ++--- 10 files changed, 115 insertions(+), 92 deletions(-) diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 096f9a09c9e67270389869d2a7fd7bef482b185b..7d79b2602c7dbb62eb6c0869c1f18181ba71be8c 100644 GIT binary patch delta 1449 zcmcJNYfKbZ6vyWbGce08IE5uhShK@Av8Y9NmPZPjb%n(~qOCRr25Ng@&wO#poV%5{eXTy``?Y6AXW|fK@1hCJ8xF?S+Ssbo`UO!J+lPx(rVb2e z&}2;c>l-kKwQQkc1+va- zT;ZnOpRK4ndm(sW&6DCXz5qLpq~WF0GvPxFMHd@YA3*Yq?^gSq;<|GWzCPdg<+yIe z$RBAbJvRX1bw%Aj;6qyKI4pI2e+PEz-{2F==bQ`w`Pw8e+%qy zQhpzin+MI$(V3fHn3GqUr{xqD7r1kBKk2JxyV^X}*SdciEngdmV=G5G;B}~+gs|O( Q>KsRd*8yE#2Y>eCXD?~z761SM delta 1066 zcmaKqTSydP6vyX`GrHrhHsywj6FY62X<<25QdF*Cx0g_(dXmCYyO~<<3ev^xP7<;1 z$>t>pM3)N6@{9H%A0(xMwnBO_vU`w~4_y$t;B4pHE-zg^_;b#8&iT&y%{O0QNC^xn z!F&+fj4T-hL0EOAJWEU|`*`8xrz3-)Q$)aKaSt@HF>w}1Nqp~-&SBK%gai0oN(UQ$ zk!DEau~-Z}vaXPgZKJBgxLTejpC+#w{jw{QW(XSX){=5aUXq)%2QSJlu<)+pat3J6 z&+i~RPHH8E#M+c#H09ujKXB|2vZ*PYsDanhISZ%Qx-lv_l)V($O8S8)#SwYuIO1GN z`~^|_7h?S2Wm%Ig@>+0E&T{flIkhPyanfU?p6C#ul&mTHML}pGS!~>%AWrAC6_n@J zN4A~BY58g-UnT{yGBt}8r}hCJdb)(^$^G!Fo#S^qs_${?Yf-P8hW(-;H`0tPII(69 z>NOf0*t$Vx?xCrmz&q+VNaiWe>>NOEcKoOo(`~`{kHGK(C$}#M_2&0~&w9JXcu+S_T00&zZ9!^93tH;Kh z4pNREV!p2@prcp43T~0P?>)&(cTk4EJHGO2{goAsyEj+(o6NQ(F;{(GqQnzR3kvp4 z@HcIYlx4sbFn3>qndYoiSck=(i`vhEs#foex>}E~_qtloySldDT#N>DwKXJ$CjgjB zSAxNe(fjt0)5AO?X94>YjO6VE&7T=@S!vnm8PTPeeDkbV$9&Pjd?TgtLOEW@zI;oP zPA5VDR^WlI*=Er&WT=m;1`BU3f6zYf^`mZYbAca?+{uyAL~sIKms^aub07?O8yAG? z0+>;g^Ybq)0i4g$B2F8OLg@1{+iMz|&PT`Z=ko~&J3#8`41j7iuZdZ&?reVJ-Fc?a zx?XPvmx~SIN&m~5d2hi`)jIkiRYJ9pC)5glq0;Po3tkqm0?^Z04yO7J63t3Y%*2K+ W_3u+cPB(h8wPQsZM2a-=M(KB5)MrBg diff --git a/sample/main.lua b/sample/main.lua index b830f7e..d0816b7 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -96,11 +96,13 @@ else accept_sock:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535,}) accept_sock:set_wshared(true) print("accept_sock:fd", accept_sock:fd()) - tcp.write2(accept_sock:fd(), "hello world!") - accept_sock:write("hello world!") - tcp.write2(accept_sock:fd(), "hello world!") - tcp.write2(accept_sock:fd(), "hello world!") - accept_sock:write("hello world!") + tcp.write(accept_sock:fd(), "hello world!", true) + accept_sock:write("hello world!", function(result, error) print("tcp.write1", result, error) end) + tcp.write(accept_sock:fd(), "hello world!", function(result, error) print("tcp.write2", result, error) end) + accept_sock:close() + --timer.sleep(1) + tcp.write(accept_sock:fd(), "hello world!", function(result, error) print("tcp.write3", result, error) end) + --accept_sock:write("hello world!", function(result, error) print("tcp.write4", result, error) end) end) local ret, con_sock = tcp.connect("127.0.0.1", 8801) if ret then diff --git a/src/errors.h b/src/errors.h index 342d0a2..7e16cf2 100644 --- a/src/errors.h +++ b/src/errors.h @@ -5,7 +5,7 @@ /* Expand this list if necessary. */ #define NL_ERRNO_MAP(XX) \ - XX( 200, EYIELD, "attempt to yield across a C-call boundary") \ + XX( 200, EYIELD, "attempt to yield across a C-call boundary") \ XX( 201, EYIELDFNZ, "yielding up finalize error") \ XX( 202, ESTACKLESS, "attempt to yield across a stack-less coroutine") \ XX( 203, ETCPSCLOSED, "tcp socket has been closed") \ @@ -14,6 +14,8 @@ XX( 206, ETRANSTYPE, "transfer data type not supported") \ XX( 207, ENOREPLY, "no reply") \ XX( 208, ETIMEOUT, "timeout") \ + XX( 209, ETCPNOWSHARED, "tcp socket not set write shared") \ + XX( 210, ETCPWRITELONG, "attempt to send data too long") \ #define NL_ERRNO_GEN(val, name, s) NL_##name = val, typedef enum { diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index a7de128..2edb52a 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -527,43 +527,80 @@ int32_t lua_tcp_socket_handle_t::connect_yield_continue(lua_State* L, int status return 2; } -int32_t lua_tcp_socket_handle_t::write2(lua_State* L) +int32_t lua_tcp_socket_handle_t::write(lua_State* L) +{ + return !lua_isinteger(L, 1) ? write_handle(L) : write_fd(L); +} + +int32_t lua_tcp_socket_handle_t::write_fd(lua_State* L) { int64_t fd = luaL_checkinteger(L, 1); - if (fd <= 0) { - return 0; - } const char *s = NULL; uint32_t length; buffer_t* buffer = NULL; + if (fd <= 0) { + return luaL_error(L, "invalid shared socket fd"); + } if (((s = lua_tolstring(L, 2, (size_t*)&length)) == NULL) && ((buffer = (buffer_t*)luaL_testudata(L, 2, BUFFER_METATABLE)) == NULL)) { luaL_argerror(L, 2, "string expected"); } if (buffer) { length = (uint32_t)buffer_data_length(*buffer); } - if (length == 0) { + bool safety = false; + bool nonblocking = false; + if (lua_gettop(L) >= 3) { + if (lua_isfunction(L, 3)) { + nonblocking = true; + lua_settop(L, 3); + } else { + safety = lua_toboolean(L, 3); + } + } + context_lua_t* lctx = context_lua_t::lua_get_context(L); + if (length == 0) { /* empty string or buffer */ + if (nonblocking) { + int32_t session = context_lua_t::lua_ref_callback(L, 2, LUA_REFNIL, context_lua_t::common_callback_adjust); + singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), session, RESPONSE_TCP_WRITE, UV_OK); + } else if (safety) { /* real blocking mode */ + lua_pushboolean(L, true); + lua_pushinteger(L, UV_OK); + return 2; + } return 0; } - request_t request; - request.m_type = REQUEST_TCP_WRITE2; - request.m_length = REQUEST_SIZE(request_tcp_write2_t, 0); - request.m_tcp_write2.m_fd = fd; + request_t& request = lctx->get_yielding_request(); + request.m_type = REQUEST_TCP_WRITE; + request.m_length = REQUEST_SIZE(request_tcp_write_t, 0); + request.m_tcp_write.m_socket_fd = fd; + request.m_tcp_write.m_source = lctx->get_handle(); + request.m_tcp_write.m_shared_write = true; if (s) { - request.m_tcp_write2.m_length = length; /* length > 0 */ - request.m_tcp_write2.m_string = (const char*)nl_memdup(s, length); - if (!request.m_tcp_write2.m_string) { + request.m_tcp_write.m_length = length; /* length > 0 */ + request.m_tcp_write.m_string = (const char*)nl_memdup(s, length); + if (!request.m_tcp_write.m_string) { return luaL_error(L, "attempt to send data(length %lu) failed: memory not enough", length); } } else { - request.m_tcp_write2.m_length = 0; - request.m_tcp_write2.m_buffer = buffer_grab(*buffer); + request.m_tcp_write.m_length = 0; + request.m_tcp_write.m_buffer = buffer_grab(*buffer); + } + if (nonblocking) { /*nonblocking callback mode*/ + request.m_tcp_write.m_session = context_lua_t::lua_ref_callback(L, 2, LUA_REFNIL, context_lua_t::common_callback_adjust); + singleton_ref(network_t).send_request(request); + return 0; + } else { /* blocking mode */ + if (!safety) { /* wait for nothing */ + request.m_tcp_write.m_session = LUA_REFNIL; + singleton_ref(network_t).send_request(request); + return 0; + } else { /* real blocking mode */ + return lctx->lua_yield_send(L, 0, write_yield_finalize, NULL, context_lua_t::common_yield_continue); + } } - singleton_ref(network_t).send_request(request); - return 0; } -int32_t lua_tcp_socket_handle_t::write(lua_State* L) +int32_t lua_tcp_socket_handle_t::write_handle(lua_State* L) { lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)luaL_checkudata(L, 1, TCP_SOCKET_METATABLE); if (socket->is_closed()) { @@ -610,6 +647,8 @@ int32_t lua_tcp_socket_handle_t::write(lua_State* L) request.m_type = REQUEST_TCP_WRITE; request.m_length = REQUEST_SIZE(request_tcp_write_t, 0); request.m_tcp_write.m_socket_handle = (uv_tcp_socket_handle_t*)socket->m_uv_handle; + request.m_tcp_write.m_source = lctx->get_handle(); + request.m_tcp_write.m_shared_write = false; if (s) { request.m_tcp_write.m_length = length; /* length > 0 */ request.m_tcp_write.m_string = (const char*)nl_memdup(s, length); @@ -643,8 +682,10 @@ int32_t lua_tcp_socket_handle_t::write_yield_finalize(lua_State *root_coro, lua_ context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); request_t& request = lctx->get_yielding_request(); request.m_tcp_write.m_session = context_lua_t::lua_ref_yield_coroutine(root_coro); - uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)((lua_tcp_socket_handle_t*)userdata)->m_uv_handle; - froze_head_option(handle->m_write_head_option); + if (userdata != NULL) { + uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)((lua_tcp_socket_handle_t*)userdata)->m_uv_handle; + froze_head_option(handle->m_write_head_option); + } singleton_ref(network_t).send_request(request); } else { //yield failed, clear your data in case of memory leak. context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); @@ -962,7 +1003,6 @@ int luaopen_tcp(lua_State *L) { "connect6", lua_tcp_socket_handle_t::connect6 }, { "connects", lua_tcp_socket_handle_t::connects }, { "write", lua_tcp_socket_handle_t::write }, - { "write2", lua_tcp_socket_handle_t::write2 }, { "read", lua_tcp_socket_handle_t::read }, { "set_rwopt", lua_tcp_socket_handle_t::set_rwopt }, { "get_rwopt", lua_tcp_socket_handle_t::get_rwopt }, diff --git a/src/lua_tcp_handle.h b/src/lua_tcp_handle.h index e70babb..ea50e50 100644 --- a/src/lua_tcp_handle.h +++ b/src/lua_tcp_handle.h @@ -57,7 +57,6 @@ class lua_tcp_socket_handle_t : public lua_handle_base_t static int32_t connect6(lua_State* L); static int32_t connects(lua_State* L); static int32_t write(lua_State* L); - static int32_t write2(lua_State* L); static int32_t read(lua_State* L); static int32_t set_rwopt(lua_State* L); static int32_t get_rwopt(lua_State* L); @@ -67,6 +66,8 @@ class lua_tcp_socket_handle_t : public lua_handle_base_t private: static int32_t _connect(lua_State* L, bool ipv6); static int32_t connect_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); + static int32_t write_handle(lua_State* L); + static int32_t write_fd(lua_State* L); static int32_t write_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t read_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t connect_callback_adjust(lua_State* L); diff --git a/src/network.cpp b/src/network.cpp index 35992ff..bcb5c0a 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -132,12 +132,7 @@ void network_t::request_tcp_read(request_tcp_read_t& request) void network_t::request_tcp_write(request_tcp_write_t& request) { - request.m_socket_handle->write(request); -} - -void network_t::request_tcp_write2(request_tcp_write2_t& request) -{ - uv_tcp_socket_handle_t::write2(request); + uv_tcp_socket_handle_t::write(request); } void network_t::request_handle_option(request_handle_option_t& request) @@ -217,9 +212,6 @@ void network_t::process_request(request_t& request) case REQUEST_TCP_WRITE: request_tcp_write(request.m_tcp_write); break; - case REQUEST_TCP_WRITE2: - request_tcp_write2(request.m_tcp_write2); - break; case REQUEST_TCP_READ: request_tcp_read(request.m_tcp_read); break; diff --git a/src/network.h b/src/network.h index c3a4aa9..5b97423 100644 --- a/src/network.h +++ b/src/network.h @@ -43,7 +43,6 @@ class network_t : public singleton_t { void request_tcp_connect(request_tcp_connect_t& request); void request_tcp_connects(request_tcp_connects_t& request); void request_tcp_write(request_tcp_write_t& request); - void request_tcp_write2(request_tcp_write2_t& request); void request_tcp_read(request_tcp_read_t& request); void request_handle_option(request_handle_option_t& request); void request_handle_close(request_handle_close_t& request); diff --git a/src/request.h b/src/request.h index 722b265..7d98d5a 100644 --- a/src/request.h +++ b/src/request.h @@ -25,7 +25,6 @@ enum request_type { REQUEST_TCP_CONNECTS, REQUEST_TCP_READ, REQUEST_TCP_WRITE, - REQUEST_TCP_WRITE2, REQUEST_HANDLE_OPTION, REQUEST_HANDLE_CLOSE, REQUEST_TIMER_START @@ -82,24 +81,18 @@ struct request_tcp_read_t { }; struct request_tcp_write_t { - uv_tcp_socket_handle_t *m_socket_handle; - uint32_t m_session; - uint32_t m_length; /* judge it's string or buffer */ union { - const char* m_string; - buffer_t m_buffer; + uv_tcp_socket_handle_t *m_socket_handle; + uint64_t m_socket_fd; }; - REQUEST_SPARE_REGION -}; - -/* write by shared fd */ -struct request_tcp_write2_t { - uint64_t m_fd; - uint32_t m_length; /* judge it's string or buffer */ union { const char* m_string; buffer_t m_buffer; }; + uint32_t m_length; /* judge it's string or buffer */ + uint32_t m_source; /* redundant if m_shared_write is true */ + uint32_t m_session; + bool m_shared_write; /* whether m_socket_fd is valid */ REQUEST_SPARE_REGION }; @@ -135,7 +128,6 @@ struct request_t { request_tcp_connects_t m_tcp_connects; request_tcp_read_t m_tcp_read; request_tcp_write_t m_tcp_write; - request_tcp_write2_t m_tcp_write2; request_handle_option_t m_handle_option; request_handle_close_t m_handle_close; request_timer_start_t m_timer_start; diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index f339874..9ef2c34 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -171,50 +171,52 @@ void uv_tcp_socket_handle_t::on_write(uv_write_t* req, int status) buffer_release(uv_request->m_buffer); } if (uv_request->m_session != LUA_REFNIL) { - singleton_ref(node_lua_t).context_send(socket_handle->m_source, 0, uv_request->m_session, RESPONSE_TCP_WRITE, status == 0 ? UV_OK : socket_handle->m_write_error); + singleton_ref(node_lua_t).context_send(uv_request->m_source, 0, uv_request->m_session, RESPONSE_TCP_WRITE, status == 0 ? UV_OK : socket_handle->m_write_error); } socket_handle->put_write_cached_request(uv_request); } -void uv_tcp_socket_handle_t::write2(request_tcp_write2_t& request) +void uv_tcp_socket_handle_t::write(request_tcp_write_t& request) { - write_shared_map_t::iterator it = m_write_shared_sockets.find(request.m_fd); - if (it != m_write_shared_sockets.end()) { - uv_tcp_socket_handle_t* handle = it->second; - if (!uv_is_closing((uv_handle_t*)handle)) { - request_tcp_write_t req; - uint32_t length; - req.m_session = LUA_REFNIL; - req.m_length = request.m_length; - if (request.m_length > 0) { /* is raw string */ - req.m_string = request.m_string; - length = request.m_length; - } else { /* is buffer */ - req.m_buffer = request.m_buffer; - length = (uint32_t)buffer_data_length(request.m_buffer); - } - if (check_head_option_max(handle->m_write_head_option, length)) { - handle->write(req); - return; + int32_t err = UV_UNKNOWN; + if (request.m_shared_write) { + write_shared_map_t::iterator it = m_write_shared_sockets.find(request.m_socket_fd); + if (it != m_write_shared_sockets.end()) { + uv_tcp_socket_handle_t* handle = it->second; + uint32_t length = request.m_length > 0 ? request.m_length : (uint32_t)buffer_data_length(request.m_buffer); + if (uv_is_closing((uv_handle_t*)handle)) { + err = NL_ETCPSCLOSED; + } else if (!check_head_option_max(handle->m_write_head_option, length)) { + err = NL_ETCPWRITELONG; + } else { + err = handle->write_handle(request); } - /* to be fix : put error message "attempt to send data(length %lu) too long(max %lu)" */ + } else { + err = NL_ETCPNOWSHARED; } - } - /* write error had been occurred */ - if (request.m_length > 0) { - nl_free((void*)request.m_string); } else { - buffer_release(request.m_buffer); + err = request.m_socket_handle->write_handle(request); + } + if (err != UV_OK) { /* write error had been occurred */ + if (request.m_length > 0) { + nl_free((void*)request.m_string); + } else { + buffer_release(request.m_buffer); + } + if (request.m_session != LUA_REFNIL) { + singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_WRITE, (nl_err_code)err); + } } } /* We must response something to lua-service even error occurred. */ -void uv_tcp_socket_handle_t::write(request_tcp_write_t& request) +int32_t uv_tcp_socket_handle_t::write_handle(request_tcp_write_t& request) { int result; if (m_write_error == UV_OK) { uv_buf_t uv_buf[] = { { 0, NULL }, { 0, NULL } }; write_uv_request_t* uv_request = get_write_cached_request(); + uv_request->m_source = request.m_source; uv_request->m_session = request.m_session; uv_request->m_length = request.m_length; if (request.m_length > 0) { @@ -234,19 +236,11 @@ void uv_tcp_socket_handle_t::write(request_tcp_write_t& request) } else { result = uv_write(&uv_request->m_write_req, (uv_stream_t*)(m_handle), uv_buf + 1, 1, on_write); } - if (result == 0) return; + if (result == 0) return UV_OK; m_write_error = singleton_ref(network_t).last_error(); /* write error occurs */ put_write_cached_request(uv_request); } - /* write error had been occurred */ - if (request.m_length > 0) { - nl_free((void*)request.m_string); - } else { - buffer_release(request.m_buffer); - } - if (request.m_session != LUA_REFNIL) { - singleton_ref(node_lua_t).context_send(m_source, 0, request.m_session, RESPONSE_TCP_WRITE, m_write_error); - } + return m_write_error; } uv_buf_t uv_tcp_socket_handle_t::on_read_alloc(uv_handle_t* handle, size_t suggested_size) diff --git a/src/uv_tcp_handle.h b/src/uv_tcp_handle.h index 95dcfed..83991dd 100644 --- a/src/uv_tcp_handle.h +++ b/src/uv_tcp_handle.h @@ -84,15 +84,15 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t static void on_read(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); static uv_buf_t on_read_alloc(uv_handle_t* handle, size_t suggested_size); /* return tcp shared read buffer */ + int32_t write_handle(request_tcp_write_t& request); void write_read_buffer(ssize_t nread, uv_buf_t buf); void write_read_buffer_finish(uv_err_code err_code); void clear_read_cached_buffers(); public: void connect_tcp(request_tcp_connect_t& request); void connect_sock(request_tcp_connects_t& request); - void write(request_tcp_write_t& request); void read(request_tcp_read_t& request); - static void write2(request_tcp_write2_t& request); + static void write(request_tcp_write_t& request); public: bool read_start_state() const { @@ -125,12 +125,13 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t private: typedef struct { uv_write_t m_write_req; - uint32_t m_session; - uint32_t m_length; union { const char* m_string; buffer_t m_buffer; }; + uint32_t m_length; /* judge it's string or buffer */ + uint32_t m_source; + uint32_t m_session; int8_t m_head_buffer[4]; } write_uv_request_t; From 4150a2180815219f5865752fa56b343bedacf539 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 1 Apr 2016 10:48:33 +0800 Subject: [PATCH 017/173] =?UTF-8?q?context=E5=AF=B9=E8=B1=A1=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=88=B6=E4=BA=B2=E6=9C=8D=E5=8A=A1id=E6=88=90?= =?UTF-8?q?=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/main.lua | 5 +++++ sample/test.lua | 1 + src/context.cpp | 6 ++++-- src/context.h | 4 +++- src/context_lua.cpp | 9 +++++++-- src/context_mgr.cpp | 4 ++-- src/context_mgr.h | 2 +- src/node_lua.cpp | 2 +- src/node_lua.h | 4 ++-- 9 files changed, 26 insertions(+), 11 deletions(-) diff --git a/sample/main.lua b/sample/main.lua index d0816b7..9326593 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -71,6 +71,11 @@ print("value", value1, value2)]] -- #endif + +local handle = context.create("test.lua") + +print(context.self, context.parent, handle) + if context.winos then package.cpath = package.cpath ..";".."..\\clib\\?.dll" package.path = package.path ..";".."..\\lualib\\?.lua" diff --git a/sample/test.lua b/sample/test.lua index e8981a8..ff6bdb9 100644 --- a/sample/test.lua +++ b/sample/test.lua @@ -1,4 +1,5 @@ --print(package.path) +print(context.parent) package.path = package.path .. ";..\\lualib\\?.lua" package.cpath = package.cpath .. ";..\\clib\\?.dll" diff --git a/src/context.cpp b/src/context.cpp index 9c93054..5f456de 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -5,7 +5,8 @@ #include "node_lua.h" context_t::context_t() - : m_handle(0), + : m_parent(0), + m_handle(0), m_worker(NULL), m_inited(false), m_ref(1), @@ -20,9 +21,10 @@ context_t::~context_t() } -void context_t::on_registered( uint32_t handle ) +void context_t::on_registered(uint32_t parent, uint32_t handle) { if (m_handle == 0) { + m_parent = parent; m_handle = handle; grab(); } diff --git a/src/context.h b/src/context.h index 1d1c267..bf9cd5c 100644 --- a/src/context.h +++ b/src/context.h @@ -8,6 +8,7 @@ class worker_t; class context_t { public: context_t(); + FORCE_INLINE uint32_t get_parent() const { return m_parent; } FORCE_INLINE uint32_t get_handle() const { return m_handle; } FORCE_INLINE void grab() { atomic_inc(m_ref); } FORCE_INLINE void release() { if (atomic_dec(m_ref) == 1) delete this; } @@ -22,7 +23,7 @@ class context_t { void attach_worker(worker_t* worker); void detach_worker(); - void on_registered(uint32_t handle); /* thread safe */ + void on_registered(uint32_t parent, uint32_t handle); /* thread safe */ void on_retired(); /* thread safe */ bool push_message(message_t& message, bool& processing); bool pop_message(message_t& message); @@ -39,6 +40,7 @@ class context_t { context_t(const context_t& ctx); context_t& operator=(const context_t& ctx); + uint32_t m_parent; /* parent handle */ uint32_t m_handle; /* allocated handle */ worker_t* m_worker; /* attached worker */ private: diff --git a/src/context_lua.cpp b/src/context_lua.cpp index e60fb2d..71d02d6 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -801,7 +801,8 @@ int32_t context_lua_t::context_create(lua_State *L) for (int32_t i = 0; i < argc; ++i) { argv[i] = (char*)luaL_checkstring(L, i + 1); } - uint32_t handle = singleton_ref(node_lua_t).context_create(argc, argv, env); + uint32_t parent = lua_get_context_handle(L); + uint32_t handle = singleton_ref(node_lua_t).context_create(parent, argc, argv, env); lua_free_env(L, env); if (handle > 0) { lua_pushinteger(L, handle); @@ -1185,7 +1186,6 @@ int luaopen_context(lua_State *L) { "strerror", context_lua_t::context_strerror }, { "create", context_lua_t::context_create }, { "destroy", context_lua_t::context_destroy }, - { "self", context_lua_t::context_self }, { "thread", context_lua_t::context_thread }, { "send", context_lua_t::context_send }, { "query", context_lua_t::context_query }, @@ -1201,6 +1201,11 @@ int luaopen_context(lua_State *L) lua_pushboolean(L, 0); #endif lua_setfield(L, -2, "winos"); + context_lua_t* lctx = context_lua_t::lua_get_context(L); + lua_pushinteger(L, lctx->get_handle()); + lua_setfield(L, -2, "self"); + lua_pushinteger(L, lctx->get_parent()); + lua_setfield(L, -2, "parent"); return 1; } diff --git a/src/context_mgr.cpp b/src/context_mgr.cpp index eb65feb..5e50752 100644 --- a/src/context_mgr.cpp +++ b/src/context_mgr.cpp @@ -35,7 +35,7 @@ void context_mgr_t::expand_slot() m_slot_cap = new_cap; } -bool context_mgr_t::register_context( context_t* ctx ) +bool context_mgr_t::register_context(context_t* ctx, int32_t parent) { uv_rwlock_wrlock(&m_lock); if (m_ctx_size == MAX_CTX_SIZE || ctx->get_handle() != 0) { @@ -54,7 +54,7 @@ bool context_mgr_t::register_context( context_t* ctx ) m_ctx_slot[hash] = ctx; m_handle_index = handle + 1; ++m_ctx_size; - ctx->on_registered(handle); + ctx->on_registered(parent, handle); uv_rwlock_wrunlock(&m_lock); return true; } diff --git a/src/context_mgr.h b/src/context_mgr.h index 5cb3296..769b11d 100644 --- a/src/context_mgr.h +++ b/src/context_mgr.h @@ -7,7 +7,7 @@ class context_mgr_t { public: context_mgr_t(); ~context_mgr_t(); - bool register_context(context_t* ctx); + bool register_context(context_t* ctx, int32_t parent); void retire_context(context_t* ctx); context_t* grab_context(uint32_t handle); uint32_t get_context_count() const { return m_ctx_size; } diff --git a/src/node_lua.cpp b/src/node_lua.cpp index e817bcf..badc4e6 100644 --- a/src/node_lua.cpp +++ b/src/node_lua.cpp @@ -36,7 +36,7 @@ node_lua_t::node_lua_t(int argc, char* argv[], char* env[]) m_worker_mgr = new worker_mgr_t(); m_network->start(); m_worker_mgr->start(); - context_create(argc, argv, env); + context_create(0, argc, argv, env); m_worker_mgr->wait(); m_network->stop(); m_network->wait(); diff --git a/src/node_lua.h b/src/node_lua.h index 17a2764..8e00765 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -70,10 +70,10 @@ class node_lua_t : public singleton_t { } template < class type > - uint32_t context_create(int32_t argc, char* argv[], char* env[]) { + uint32_t context_create(uint32_t parent, int32_t argc, char* argv[], char* env[]) { uint32_t handle = 0; type *ctx = new type(); - if (m_ctx_mgr->register_context(ctx)) { + if (m_ctx_mgr->register_context(ctx, parent)) { if (ctx->init(argc, argv, env)) { ctx->set_inited(true); handle = ctx->get_handle(); From 337b2737f7af2643011da65dac7c599d2a41b6f3 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 1 Apr 2016 14:33:22 +0800 Subject: [PATCH 018/173] fix a little thing for safety --- src/lua_handle_base.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lua_handle_base.cpp b/src/lua_handle_base.cpp index 70a309e..428a482 100644 --- a/src/lua_handle_base.cpp +++ b/src/lua_handle_base.cpp @@ -74,9 +74,11 @@ void lua_handle_base_t::release_ref(lua_State* L, int32_t ref, handle_set type) lua_pushlightuserdata(L, NULL); lua_rawseti(L, -3, ref); lua_pop(L, 2); - } else { + } else if (!lua_isinteger(L, -1)) { luaL_unref(L, -2, ref); lua_pop(L, 2); + } else { + lua_pop(L, 2); } } } From b41130d363ff11a97464791ba9880523070f15c4 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 1 Apr 2016 19:51:32 +0800 Subject: [PATCH 019/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E8=8E=B7=E5=8F=96socket=20fd=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/uv_tcp_handle.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 9ef2c34..4b62eda 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -4,6 +4,16 @@ #include "uv_tcp_handle.h" #include "lua_tcp_handle.h" +#if defined (CC_MSVC) +#define uv_tcp_fd(handle) ((handle)->socket) +#elif defined(__APPLE__) +int uv___stream_fd(uv_stream_t* handle); +#define uv_tcp_fd(handle) (uv___stream_fd((uv_stream_t*) (handle))) +#else +#define uv_tcp_fd(handle) ((handle)->io_watcher.fd) +#endif /* defined(__APPLE__) */ + + void uv_tcp_listen_handle_t::on_accept(uv_stream_t* server, int status) { uv_tcp_listen_handle_t *listen_handle = (uv_tcp_listen_handle_t*)(server->data); From c7c0d3c985230c6fdd86bbf10352be62062b7b0b Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 3 Apr 2016 01:46:15 +0800 Subject: [PATCH 020/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96tcp?= =?UTF-8?q?=20socket=20=E8=87=AA=E7=AB=AF=E5=92=8C=E8=BF=9C=E7=AB=AFaddres?= =?UTF-8?q?s=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/main.lua | 76 +++++++++++++++++++++++---------------- src/lua_tcp_handle.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++ src/lua_tcp_handle.h | 4 +++ src/utils.cpp | 32 +++++++++++++++++ src/utils.h | 1 + src/uv_tcp_handle.cpp | 6 ++++ src/uv_tcp_handle.h | 2 ++ 7 files changed, 171 insertions(+), 30 deletions(-) diff --git a/sample/main.lua b/sample/main.lua index 9326593..6bfeed7 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -72,9 +72,9 @@ print("value", value1, value2)]] -local handle = context.create("test.lua") +-- local handle = context.create("test.lua") -print(context.self, context.parent, handle) +-- print(context.self, context.parent, handle) if context.winos then package.cpath = package.cpath ..";".."..\\clib\\?.dll" @@ -89,42 +89,58 @@ end -- end -- do return end +acceptSockets = {} +connecSockets = {} + local ret, sock = tcp.listen("0.0.0.0", 8801) if not ret then print("tcp.listens failed: ", context.strerror(sock)) else print("tcp.listens success: ", sock) - sock:accept(function(result, accept_sock) - print("sock:accept", result, accept_sock) - sock:close() + sock:accept(function(result, accept_sock) + if result then + acceptSockets[#acceptSockets+1] = accept_sock + print("sock:accept success", #acceptSockets, accept_sock:fd(), accept_sock:local_port()) + else + print("sock:accept fail", ret, context.strerror(accept_sock)) + end + --sock:close() --accept_sock:set_nodelay(false) - accept_sock:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535,}) - accept_sock:set_wshared(true) - print("accept_sock:fd", accept_sock:fd()) - tcp.write(accept_sock:fd(), "hello world!", true) - accept_sock:write("hello world!", function(result, error) print("tcp.write1", result, error) end) - tcp.write(accept_sock:fd(), "hello world!", function(result, error) print("tcp.write2", result, error) end) - accept_sock:close() - --timer.sleep(1) - tcp.write(accept_sock:fd(), "hello world!", function(result, error) print("tcp.write3", result, error) end) - --accept_sock:write("hello world!", function(result, error) print("tcp.write4", result, error) end) + -- print("accept_sock local addr:", accept_sock:local_addr(), accept_sock:local_port()) + -- print("accept_sock remote addr:", accept_sock:remote_addr(), accept_sock:remote_port()) + -- accept_sock:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535,}) + -- accept_sock:set_wshared(true) + -- print("accept_sock:fd", accept_sock:fd()) + -- tcp.write(accept_sock:fd(), "hello world!", true) + -- accept_sock:write("hello world!", function(result, error) print("tcp.write1", result, error) end) + -- tcp.write(accept_sock:fd(), "hello world!", function(result, error) print("tcp.write2", result, error) end) + -- accept_sock:close() + -- tcp.write(accept_sock:fd(), "hello world!", function(result, error) print("tcp.write3", result, error) end) end) - local ret, con_sock = tcp.connect("127.0.0.1", 8801) - if ret then - print("tcp.connect", ret, con_sock) - con_sock:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535,}) - con_sock:set_wshared(true) - local ret, buffer = con_sock:read() - print("tcp read", ret, ret and buffer:tostring()) - local ret, buffer = con_sock:read() - print("tcp read", ret, ret and buffer:tostring()) - local ret, buffer = con_sock:read() - print("tcp read", ret, ret and buffer:tostring()) - local ret, buffer = con_sock:read() - print("tcp read", ret, ret and buffer:tostring()) - else - print("tcp.connect", ret, context.strerror(sock)) + for i = 1, 70000 do + local ret, con_sock = tcp.connect("127.0.0.1", 8801) + if ret then + connecSockets[#connecSockets+1] = con_sock + print("tcp.connect success", #connecSockets, con_sock:fd(), con_sock:remote_port(), con_sock:local_port()) + -- print("tcp.connect", ret, con_sock) + -- print("con_sock local addr:", con_sock:local_addr(), con_sock:local_port()) + -- print("con_sock remote addr:", con_sock:remote_addr(), con_sock:remote_port()) + -- con_sock:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535,}) + -- con_sock:set_wshared(true) + -- local ret, buffer = con_sock:read() + -- print("tcp read", ret, ret and buffer:tostring()) + -- local ret, buffer = con_sock:read() + -- print("tcp read", ret, ret and buffer:tostring()) + -- local ret, buffer = con_sock:read() + -- print("tcp read", ret, ret and buffer:tostring()) + -- local ret, buffer = con_sock:read() + -- print("tcp read", ret, ret and buffer:tostring()) + else + print("tcp.connect fail", ret, context.strerror(con_sock), #connecSockets) + break + end end + sock:close() end diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 2edb52a..b5595a8 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -373,6 +373,14 @@ lua_tcp_socket_handle_t* lua_tcp_socket_handle_t::create_tcp_socket(uv_tcp_socke lua_setfield(L, -2, "set_nodelay"); lua_pushcfunction(L, lua_tcp_socket_handle_t::set_wshared); lua_setfield(L, -2, "set_wshared"); + lua_pushcfunction(L, lua_tcp_socket_handle_t::get_local_addr); + lua_setfield(L, -2, "local_addr"); + lua_pushcfunction(L, lua_tcp_socket_handle_t::get_remote_addr); + lua_setfield(L, -2, "remote_addr"); + lua_pushcfunction(L, lua_tcp_socket_handle_t::get_local_port); + lua_setfield(L, -2, "local_port"); + lua_pushcfunction(L, lua_tcp_socket_handle_t::get_remote_port); + lua_setfield(L, -2, "remote_port"); lua_pushcfunction(L, lua_tcp_is_closed); lua_setfield(L, -2, "is_closed"); lua_pushcfunction(L, lua_tcp_get_fd); @@ -929,6 +937,74 @@ int32_t lua_tcp_socket_handle_t::set_wshared(lua_State* L) return 0; } +static lua_tcp_socket_handle_t* check_socket_addr(lua_State* L, int32_t idx) +{ + lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)luaL_checkudata(L, idx, TCP_SOCKET_METATABLE); + if (socket->is_closed()) { + luaL_error(L, "attempt to perform on a invalid or closed socket"); + } + if (socket->get_uv_handle_type() == UV_NAMED_PIPE) { +#if defined CC_MSVC + luaL_error(L, "attempt to perform on a named pipe"); +#else + luaL_error(L, "attempt to perform on a unix domain socket"); +#endif + } + return socket; +} + +int32_t lua_tcp_socket_handle_t::get_local_addr(lua_State* L) +{ + lua_tcp_socket_handle_t* socket = check_socket_addr(L, 1); + uv_os_sock_t sock = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->m_tcp_sock; + char host[512]; + if (socket_host(sock, true, host, sizeof(host), NULL)) { + lua_pushstring(L, host); + } else { + lua_pushstring(L, "unknown address"); + } + return 1; +} + +int32_t lua_tcp_socket_handle_t::get_remote_addr(lua_State* L) +{ + lua_tcp_socket_handle_t* socket = check_socket_addr(L, 1); + uv_os_sock_t sock = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->m_tcp_sock; + char host[512]; + if (socket_host(sock, false, host, sizeof(host), NULL)) { + lua_pushstring(L, host); + } else { + lua_pushstring(L, "unknown address"); + } + return 1; +} + +int32_t lua_tcp_socket_handle_t::get_local_port(lua_State* L) +{ + lua_tcp_socket_handle_t* socket = check_socket_addr(L, 1); + uv_os_sock_t sock = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->m_tcp_sock; + uint16_t port; + if (socket_host(sock, true, NULL, 0, &port)) { + lua_pushinteger(L, port); + } else { + lua_pushinteger(L, -1); + } + return 1; +} + +int32_t lua_tcp_socket_handle_t::get_remote_port(lua_State* L) +{ + lua_tcp_socket_handle_t* socket = check_socket_addr(L, 1); + uv_os_sock_t sock = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->m_tcp_sock; + uint16_t port; + if (socket_host(sock, false, NULL, 0, &port)) { + lua_pushinteger(L, port); + } else { + lua_pushinteger(L, -1); + } + return 1; +} + int32_t lua_tcp_socket_handle_t::wakeup_connect(lua_State* L, message_t& message) { context_lua_t* lctx = context_lua_t::lua_get_context(L); @@ -1008,6 +1084,10 @@ int luaopen_tcp(lua_State *L) { "get_rwopt", lua_tcp_socket_handle_t::get_rwopt }, { "set_nodelay", lua_tcp_socket_handle_t::set_nodelay }, { "set_wshared", lua_tcp_socket_handle_t::set_wshared }, + { "local_addr", lua_tcp_socket_handle_t::get_local_addr }, + { "remote_addr", lua_tcp_socket_handle_t::get_remote_addr }, + { "local_port", lua_tcp_socket_handle_t::get_local_port }, + { "remote_port", lua_tcp_socket_handle_t::get_remote_port }, { "close", lua_tcp_close }, { "is_closed", lua_tcp_is_closed }, { "fd", lua_tcp_get_fd }, diff --git a/src/lua_tcp_handle.h b/src/lua_tcp_handle.h index ea50e50..e46138b 100644 --- a/src/lua_tcp_handle.h +++ b/src/lua_tcp_handle.h @@ -62,6 +62,10 @@ class lua_tcp_socket_handle_t : public lua_handle_base_t static int32_t get_rwopt(lua_State* L); static int32_t set_nodelay(lua_State* L); static int32_t set_wshared(lua_State* L); + static int32_t get_local_addr(lua_State* L); + static int32_t get_remote_addr(lua_State* L); + static int32_t get_local_port(lua_State* L); + static int32_t get_remote_port(lua_State* L); static int32_t close(lua_State* L); private: static int32_t _connect(lua_State* L, bool ipv6); diff --git a/src/utils.cpp b/src/utils.cpp index 7b3a171..1f7a3a4 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -43,3 +43,35 @@ extern void* nl_memdup(const void* src, uint32_t len) } return NULL; } + +extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, uint16_t* port) +{ + union sock_name_u { + sockaddr_in sock4; + sockaddr_in6 sock6; + } sock_name; + int sock_len = sizeof(sock_name); + int result = local ? getsockname(sock, (sockaddr*)&sock_name, &sock_len) : getpeername(sock, (sockaddr*)&sock_name, &sock_len); + if (result != 0) + return false; + uint16_t family = ((sockaddr*)&sock_name)->sa_family; + if (family == AF_INET) { + if (host != NULL) { + uv_ip4_name(&sock_name.sock4, host, host_len); + } + if (port != NULL) { + *port = sock_name.sock4.sin_port; + } + return true; + } + if (family == AF_INET6) { + if (host != NULL) { + uv_ip6_name(&sock_name.sock6, host, host_len); + } + if (port != NULL) { + *port = sock_name.sock6.sin6_port; + } + return true; + } + return false; +} diff --git a/src/utils.h b/src/utils.h index dc9e3ea..b5643be 100644 --- a/src/utils.h +++ b/src/utils.h @@ -4,5 +4,6 @@ extern char* filter_arg(char **param, int32_t *len); extern void* nl_memdup(const void* src, uint32_t len); +extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, uint16_t* port); #endif diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 4b62eda..14e1c48 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -70,6 +70,9 @@ void uv_tcp_listen_handle_t::try_accept() uv_tcp_socket_handle_t *client_handle = new uv_tcp_socket_handle_t(m_handle->loop, m_source, (m_handle->type == UV_NAMED_PIPE)); uv_handle_t *client = (uv_handle_t*)client_handle->m_handle; if (uv_accept((uv_stream_t*)(m_handle), (uv_stream_t*)client) == 0) { + if (m_handle->type == UV_TCP) { + client_handle->m_tcp_sock = uv_tcp_fd((uv_tcp_t*)client); + } if (!singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_TCP_ACCEPT, (void*)client_handle)) { uv_close((uv_handle_t*)client, on_closed); } else if (m_blocking_accept_count > 0) { @@ -128,6 +131,9 @@ void uv_tcp_socket_handle_t::on_connect(uv_connect_t* req, int status) uv_tcp_socket_handle_t *client_handle = (uv_tcp_socket_handle_t*)client->data; uint32_t session = (uint64_t)req->data; if (status == 0) { //connect success + if (client->type == UV_TCP) { + client_handle->m_tcp_sock = uv_tcp_fd((uv_tcp_t*)client); + } if (!singleton_ref(node_lua_t).context_send(client_handle->m_source, 0, session, RESPONSE_TCP_CONNECT, (void*)client_handle)) { uv_close((uv_handle_t*)client, on_closed); } diff --git a/src/uv_tcp_handle.h b/src/uv_tcp_handle.h index 83991dd..f353ab3 100644 --- a/src/uv_tcp_handle.h +++ b/src/uv_tcp_handle.h @@ -63,6 +63,7 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t public: uv_tcp_socket_handle_t(uv_loop_t* loop, uint32_t source, bool sock) : uv_handle_base_t(loop, (sock ? UV_NAMED_PIPE : UV_TCP), source), + m_tcp_sock(-1), m_has_noblocking_read(false), m_blocking_read_count(0), m_read_error(UV_OK), @@ -106,6 +107,7 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t static void free_shared_read_buffer(); static void make_shared_read_buffer(); private: + uv_os_sock_t m_tcp_sock; /* read parameters */ bool m_has_noblocking_read; /* can't change to false if set to be true */ uint32_t m_blocking_read_count; /* maybe not so precise only if m_has_noblocking_accept has been set true, From 202c771fe822a04705a7b904c43b832b9ceaca4c Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 6 Apr 2016 19:54:07 +0800 Subject: [PATCH 021/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0bson=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.v12.suo | Bin 158720 -> 159744 bytes node-lua.vcxproj | 3 + node-lua.vcxproj.filters | 9 + src/context_lua.cpp | 3 + src/lbson.cpp | 1234 ++++++++++++++++++++++++++++++++++++++ src/lbson.h | 18 + src/message.cpp | 10 + src/message.h | 59 +- 8 files changed, 1324 insertions(+), 12 deletions(-) create mode 100644 src/lbson.cpp create mode 100644 src/lbson.h create mode 100644 src/message.cpp diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 7d79b2602c7dbb62eb6c0869c1f18181ba71be8c..7e630ce29613f2a3eabde2226b28104dc1e48a6e 100644 GIT binary patch delta 8146 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 P3UOGsfURn_vhaTa&%Lsa diff --git a/node-lua.vcxproj b/node-lua.vcxproj index 3fb9615..da97e90 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -102,6 +102,7 @@ + @@ -130,11 +131,13 @@ + + diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index 0a3ae1e..a49f5ca 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -96,6 +96,9 @@ include + + include + @@ -167,5 +170,11 @@ src + + src + + + src + \ No newline at end of file diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 71d02d6..467c6e0 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -114,6 +114,8 @@ LUAMOD_API int (luaopen_buffer)(lua_State *L); LUAMOD_API int (luaopen_context)(lua_State *L); #define LUA_TIMERLIBNAME "timer" LUAMOD_API int (luaopen_timer)(lua_State *L); +#define LUA_BSONLIBNAME "bson" +LUAMOD_API int (luaopen_bson)(lua_State *L); void context_lua_t::lua_open_libs(lua_State *L) { @@ -135,6 +137,7 @@ void context_lua_t::lua_open_libs(lua_State *L) {LUA_BUFFERLIBNAME, luaopen_buffer}, {LUA_CONTEXTLIBNAME, luaopen_context}, {LUA_TIMERLIBNAME, luaopen_timer}, + {LUA_BSONLIBNAME, luaopen_bson}, {NULL, NULL} }; static const luaL_Reg preloadedlibs[] = { diff --git a/src/lbson.cpp b/src/lbson.cpp new file mode 100644 index 0000000..ed98b56 --- /dev/null +++ b/src/lbson.cpp @@ -0,0 +1,1234 @@ +#include +#include "lbson.h" + +#define MAX_NUMBER 1024 +// avoid circular reference while encodeing +#define MAX_DEPTH 128 + +#define BSON_REAL 1 +#define BSON_STRING 2 +#define BSON_DOCUMENT 3 +#define BSON_ARRAY 4 +#define BSON_BINARY 5 +#define BSON_UNDEFINED 6 +#define BSON_OBJECTID 7 +#define BSON_BOOLEAN 8 +#define BSON_DATE 9 +#define BSON_NULL 10 +#define BSON_REGEX 11 +#define BSON_DBPOINTER 12 +#define BSON_JSCODE 13 +#define BSON_SYMBOL 14 +#define BSON_CODEWS 15 +#define BSON_INT32 16 +#define BSON_TIMESTAMP 17 +#define BSON_INT64 18 +#define BSON_MINKEY 255 +#define BSON_MAXKEY 127 + +#define BSON_TYPE_SHIFT 5 + +static char bson_numstrs[MAX_NUMBER][4]; +static int bson_numstr_len[MAX_NUMBER]; + +struct bson_reader { + const uint8_t * ptr; + int size; +}; + +static inline int32_t +get_length(const uint8_t * data) { + const uint8_t * b = (const uint8_t *)data; + int32_t len = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; + return len; +} + +static inline void +bson_destroy(struct bson *b) { + if (b->ptr != b->buffer) { + nl_free(b->ptr); + } +} + +static inline void +bson_create(struct bson *b) { + b->size = 0; + b->cap = DEFAULT_CAP; + b->ptr = b->buffer; +} + +static inline void +bson_reserve(struct bson *b, int sz) { + if (b->size + sz <= b->cap) + return; + do { + b->cap *= 2; + } while (b->cap <= b->size + sz); + + if (b->ptr == b->buffer) { + b->ptr = (uint8_t *)nl_malloc(b->cap); + memcpy(b->ptr, b->buffer, b->size); + } else { + b->ptr = (uint8_t *)nl_realloc(b->ptr, b->cap); + } +} + +static inline void +check_reader(lua_State *L, struct bson_reader *br, int sz) { + if (br->size < sz) { + luaL_error(L, "Invalid bson block (%d:%d)", br->size, sz); + } +} + +static inline int +read_byte(lua_State *L, struct bson_reader *br) { + check_reader(L, br, 1); + const uint8_t * b = br->ptr; + int r = b[0]; + ++br->ptr; + --br->size; + + return r; +} + +static inline int32_t +read_int32(lua_State *L, struct bson_reader *br) { + check_reader(L, br, 4); + const uint8_t * b = br->ptr; + uint32_t v = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; + br->ptr+=4; + br->size-=4; + return (int32_t)v; +} + +static inline int64_t +read_int64(lua_State *L, struct bson_reader *br) { + check_reader(L, br, 8); + const uint8_t * b = br->ptr; + uint32_t lo = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; + uint32_t hi = b[4] | b[5]<<8 | b[6]<<16 | b[7]<<24; + uint64_t v = (uint64_t)lo | (uint64_t)hi<<32; + br->ptr+=8; + br->size-=8; + return (int64_t)v; +} + +static inline lua_Number +read_double(lua_State *L, struct bson_reader *br) { + check_reader(L, br, 8); + union { + uint64_t i; + double d; + } v; + const uint8_t * b = br->ptr; + uint32_t lo = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; + uint32_t hi = b[4] | b[5]<<8 | b[6]<<16 | b[7]<<24; + v.i = (uint64_t)lo | (uint64_t)hi<<32; + br->ptr+=8; + br->size-=8; + return v.d; +} + +static inline const void * +read_bytes(lua_State *L, struct bson_reader *br, int sz) { + const void * r = br->ptr; + check_reader(L, br, sz); + br->ptr+=sz; + br->size-=sz; + return r; +} + +static inline const char * +read_cstring(lua_State *L, struct bson_reader *br, size_t *sz) { + int i; + for (i=0;;i++) { + if (i==br->size) { + luaL_error(L, "Invalid bson block : cstring"); + } + if (br->ptr[i] == '\0') { + break; + } + } + *sz = i; + const char * r = (const char *)br->ptr; + br->ptr += i+1; + br->size -= i+1; + return r; +} + +static inline void +write_byte(struct bson *b, uint8_t v) { + bson_reserve(b,1); + b->ptr[b->size++] = v; +} + +static inline void +write_int32(struct bson *b, int32_t v) { + uint32_t uv = (uint32_t)v; + bson_reserve(b,4); + b->ptr[b->size++] = uv & 0xff; + b->ptr[b->size++] = (uv >> 8)&0xff; + b->ptr[b->size++] = (uv >> 16)&0xff; + b->ptr[b->size++] = (uv >> 24)&0xff; +} + +static inline void +write_length(struct bson *b, int32_t v, int off) { + uint32_t uv = (uint32_t)v; + b->ptr[off++] = uv & 0xff; + b->ptr[off++] = (uv >> 8)&0xff; + b->ptr[off++] = (uv >> 16)&0xff; + b->ptr[off++] = (uv >> 24)&0xff; +} + +static void +write_string(struct bson *b, const char *key, size_t sz) { + bson_reserve(b,sz+1); + memcpy(b->ptr + b->size, key, sz); + b->ptr[b->size+sz] = '\0'; + b->size+=sz+1; +} + +static inline int +reserve_length(struct bson *b) { + int sz = b->size; + bson_reserve(b,4); + b->size +=4; + return sz; +} + +static inline void +write_int64(struct bson *b, int64_t v) { + uint64_t uv = (uint64_t)v; + int i; + bson_reserve(b,8); + for (i=0;i<64;i+=8) { + b->ptr[b->size++] = (uv>>i) & 0xff; + } +} + +static inline void +write_double(struct bson *b, lua_Number d) { + union { + double d; + uint64_t i; + } v; + v.d = d; + int i; + bson_reserve(b,8); + for (i=0;i<64;i+=8) { + b->ptr[b->size++] = (v.i>>i) & 0xff; + } +} + +static void pack_dict(lua_State *L, struct bson *b, bool array, int depth); + +static inline void +append_key(struct bson *bs, int type, const char *key, size_t sz) { + write_byte(bs, type); + write_string(bs, key, sz); +} + +static inline int +is_32bit(int64_t v) { + return v >= INT32_MIN && v <= INT32_MAX; +} + +static void +append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) { + if (lua_isinteger(L, -1)) { + int64_t i = lua_tointeger(L, -1); + if (is_32bit(i)) { + append_key(bs, BSON_INT32, key, sz); + write_int32(bs, i); + } else { + append_key(bs, BSON_INT64, key, sz); + write_int64(bs, i); + } + } else { + lua_Number d = lua_tonumber(L,-1); + append_key(bs, BSON_REAL, key, sz); + write_double(bs, d); + } +} + +static void +append_table(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) { + size_t len = lua_rawlen(L, -1); + bool isarray = false; + if (len > 0) { + lua_pushinteger(L, len); + if (lua_next(L,-2) == 0) { + isarray = true; + } else { + lua_pop(L,2); + } + } + if (isarray) { + append_key(bs, BSON_ARRAY, key, sz); + } else { + append_key(bs, BSON_DOCUMENT, key, sz); + } + pack_dict(L, bs, isarray, depth); +} + +static void +write_binary(struct bson *b, const void * buffer, size_t sz) { + int length = reserve_length(b); + bson_reserve(b,sz); + memcpy(b->ptr + b->size, buffer, sz); // include sub type + b->size+=sz; + write_length(b, sz-1, length); // not include sub type +} + +static void +append_one(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) { + int vt = lua_type(L,-1); + switch(vt) { + case LUA_TNUMBER: + append_number(bs, L, key, sz); + break; + case LUA_TUSERDATA: { + append_key(bs, BSON_DOCUMENT, key, sz); + int32_t * doc = (int32_t*)lua_touserdata(L, -1); + int32_t sz = *doc; + bson_reserve(bs,sz); + memcpy(bs->ptr + bs->size, doc, sz); + bs->size += sz; + break; + } + case LUA_TSTRING: { + size_t len; + const char * str = lua_tolstring(L,-1,&len); + if (len > 1 && str[0]==0) { + int subt = (uint8_t)str[1]; + append_key(bs, subt, key, sz); + switch(subt) { + case BSON_BINARY: + write_binary(bs, str+2, len-2); + break; + case BSON_OBJECTID: + if (len != 2+12) { + luaL_error(L, "Invalid object id %s", str+2); + } + // go though + case BSON_JSCODE: + case BSON_DBPOINTER: + case BSON_SYMBOL: + case BSON_CODEWS: + bson_reserve(bs,len-2); + memcpy(bs->ptr + bs->size, str+2, len-2); + bs->size += len-2; + break; + case BSON_DATE: { + if (len != 2+4) { + luaL_error(L, "Invalid date"); + } + const uint32_t * ts = (const uint32_t *)(str + 2); + int64_t v = (int64_t)*ts * 1000; + write_int64(bs, v); + break; + } + case BSON_TIMESTAMP: { + if (len != 2+8) { + luaL_error(L, "Invalid timestamp"); + } + const uint32_t * inc = (const uint32_t *)(str + 2); + const uint32_t * ts = (const uint32_t *)(str + 6); + write_int32(bs, *inc); + write_int32(bs, *ts); + break; + } + case BSON_REGEX: { + str+=2; + len-=3; + size_t i; + for (i=0;i MAX_DEPTH) { + luaL_error(L, "Too depth while encoding bson"); + } + luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table + int length = reserve_length(b); + lua_pushnil(L); + while(lua_next(L,-2) != 0) { + int kt = lua_type(L, -2); + char numberkey[32]; + const char * key = NULL; + size_t sz; + if (isarray) { + if (kt != LUA_TNUMBER) { + luaL_error(L, "Invalid array key type : %s", lua_typename(L, kt)); + return; + } + sz = bson_numstr(numberkey, (unsigned int)lua_tointeger(L,-2)-1); + key = numberkey; + + append_one(b, L, key, sz, depth); + lua_pop(L,1); + } else { + switch(kt) { + case LUA_TNUMBER: + // copy key, don't change key type + lua_pushvalue(L,-2); + lua_insert(L,-2); + key = lua_tolstring(L,-2,&sz); + append_one(b, L, key, sz, depth); + lua_pop(L,2); + break; + case LUA_TSTRING: + key = lua_tolstring(L,-2,&sz); + append_one(b, L, key, sz, depth); + lua_pop(L,1); + break; + default: + luaL_error(L, "Invalid key type : %s", lua_typename(L, kt)); + return; + } + } + } + write_byte(b,0); + write_length(b, b->size - length, length); +} + +static void +pack_ordered_dict(lua_State *L, struct bson *b, int n, int depth) { + int length = reserve_length(b); + int i; + for (i=0;isize - length, length); +} + +static int +ltostring(lua_State *L) { + size_t sz = lua_rawlen(L, 1); + void * ud = lua_touserdata(L,1); + lua_pushlstring(L, (const char*)ud, sz); + return 1; +} + +static int +llen(lua_State *L) { + size_t sz = lua_rawlen(L, 1); + lua_pushinteger(L, sz); + return 1; +} + +static void +make_object(lua_State *L, int type, const void * ptr, size_t len) { + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, type); + luaL_addlstring(&b, (const char*)ptr, len); + luaL_pushresult(&b); +} + +static void +unpack_dict(lua_State *L, struct bson_reader *br, bool array) { + luaL_checkstack(L, 16, NULL); // reserve enough stack space to unpack table + int sz = read_int32(L, br); + const void * bytes = read_bytes(L, br, sz-5); + struct bson_reader t = { (const uint8_t *)bytes, sz - 5 }; + int end = read_byte(L, br); + if (end != '\0') { + luaL_error(L, "Invalid document end"); + } + + lua_newtable(L); + + for (;;) { + if (t.size == 0) + break; + int bt = read_byte(L, &t); + size_t klen = 0; + const char * key = read_cstring(L, &t, &klen); + if (array) { + int id = strtol(key, NULL, 10) + 1; + lua_pushinteger(L,id); + } else { + lua_pushlstring(L, key, klen); + } + switch (bt) { + case BSON_REAL: + lua_pushnumber(L, read_double(L, &t)); + break; + case BSON_BOOLEAN: + lua_pushboolean(L, read_byte(L, &t)); + break; + case BSON_STRING: { + int sz = read_int32(L, &t); + if (sz <= 0) { + luaL_error(L, "Invalid bson string , length = %d", sz); + } + lua_pushlstring(L, (const char*)read_bytes(L, &t, sz), sz-1); + break; + } + case BSON_DOCUMENT: + unpack_dict(L, &t, false); + break; + case BSON_ARRAY: + unpack_dict(L, &t, true); + break; + case BSON_BINARY: { + int sz = read_int32(L, &t); + int subtype = read_byte(L, &t); + + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_BINARY); + luaL_addchar(&b, subtype); + luaL_addlstring(&b, (const char*)read_bytes(L, &t, sz), sz); + luaL_pushresult(&b); + break; + } + case BSON_OBJECTID: + make_object(L, BSON_OBJECTID, read_bytes(L, &t, 12), 12); + break; + case BSON_DATE: { + int64_t date = read_int64(L, &t); + uint32_t v = date / 1000; + make_object(L, BSON_DATE, &v, 4); + break; + } + case BSON_MINKEY: + case BSON_MAXKEY: + case BSON_NULL: { + char key[] = { 0, bt }; + lua_pushlstring(L, key, sizeof(key)); + break; + } + case BSON_REGEX: { + size_t rlen1=0; + size_t rlen2=0; + const char * r1 = read_cstring(L, &t, &rlen1); + const char * r2 = read_cstring(L, &t, &rlen2); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_REGEX); + luaL_addlstring(&b, r1, rlen1); + luaL_addchar(&b,0); + luaL_addlstring(&b, r2, rlen2); + luaL_addchar(&b,0); + luaL_pushresult(&b); + break; + } + case BSON_INT32: + lua_pushinteger(L, read_int32(L, &t)); + break; + case BSON_TIMESTAMP: { + int32_t inc = read_int32(L, &t); + int32_t ts = read_int32(L, &t); + + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_TIMESTAMP); + luaL_addlstring(&b, (const char *)&inc, 4); + luaL_addlstring(&b, (const char *)&ts, 4); + luaL_pushresult(&b); + break; + } + case BSON_INT64: + lua_pushinteger(L, read_int64(L, &t)); + break; + case BSON_DBPOINTER: { + const void * ptr = t.ptr; + int sz = read_int32(L, &t); + read_bytes(L, &t, sz+12); + make_object(L, BSON_DBPOINTER, ptr, sz + 16); + break; + } + case BSON_JSCODE: + case BSON_SYMBOL: { + const void * ptr = t.ptr; + int sz = read_int32(L, &t); + read_bytes(L, &t, sz); + make_object(L, bt, ptr, sz + 4); + break; + } + case BSON_CODEWS: { + const void * ptr = t.ptr; + int sz = read_int32(L, &t); + read_bytes(L, &t, sz-4); + make_object(L, bt, ptr, sz); + break; + } + default: + // unsupported + luaL_error(L, "Invalid bson type : %d", bt); + lua_pop(L,1); + continue; + } + lua_rawset(L,-3); + } +} + +static int +lmakeindex(lua_State *L) { + int32_t *bson = (int32_t *)luaL_checkudata(L, 1, "bson"); + const uint8_t * start = (const uint8_t *)bson; + struct bson_reader br = { start+4, get_length(start) - 5 }; + lua_newtable(L); + + for (;;) { + if (br.size == 0) + break; + int bt = read_byte(L, &br); + size_t klen = 0; + const char * key = read_cstring(L, &br, &klen); + int field_size = 0; + switch (bt) { + case BSON_INT64: + case BSON_TIMESTAMP: + case BSON_DATE: + case BSON_REAL: + field_size = 8; + break; + case BSON_BOOLEAN: + field_size = 1; + break; + case BSON_JSCODE: + case BSON_SYMBOL: + case BSON_STRING: { + int sz = read_int32(L, &br); + read_bytes(L, &br, sz); + break; + } + case BSON_CODEWS: + case BSON_ARRAY: + case BSON_DOCUMENT: { + int sz = read_int32(L, &br); + read_bytes(L, &br, sz-4); + break; + } + case BSON_BINARY: { + int sz = read_int32(L, &br); + read_bytes(L, &br, sz+1); + break; + } + case BSON_OBJECTID: + field_size = 12; + break; + case BSON_MINKEY: + case BSON_MAXKEY: + case BSON_NULL: + break; + case BSON_REGEX: { + size_t rlen1=0; + size_t rlen2=0; + read_cstring(L, &br, &rlen1); + read_cstring(L, &br, &rlen2); + break; + } + case BSON_INT32: + field_size = 4; + break; + case BSON_DBPOINTER: { + int sz = read_int32(L, &br); + read_bytes(L, &br, sz+12); + break; + } + default: + // unsupported + luaL_error(L, "Invalid bson type : %d", bt); + lua_pop(L,1); + continue; + } + if (field_size > 0) { + int id = bt | (int)(br.ptr - start) << BSON_TYPE_SHIFT; + read_bytes(L, &br, field_size); + lua_pushlstring(L, key, klen); + lua_pushinteger(L,id); + lua_rawset(L,-3); + } + } + lua_setuservalue(L,1); + lua_settop(L,1); + + return 1; +} + +static void +replace_object(lua_State *L, int type, struct bson * bs) { + size_t len = 0; + const char * data = luaL_checklstring(L,3, &len); + if (len < 6 || data[0] != 0 || data[1] != type) { + luaL_error(L, "Type mismatch, need bson type %d", type); + } + switch (type) { + case BSON_OBJECTID: + if (len != 2+12) { + luaL_error(L, "Invalid object id"); + } + memcpy(bs->ptr, data+2, 12); + break; + case BSON_DATE: { + if (len != 2+4) { + luaL_error(L, "Invalid date"); + } + const uint32_t * ts = (const uint32_t *)(data + 2); + int64_t v = (int64_t)*ts * 1000; + write_int64(bs, v); + break; + } + case BSON_TIMESTAMP: { + if (len != 2+8) { + luaL_error(L, "Invalid timestamp"); + } + const uint32_t * inc = (const uint32_t *)(data + 2); + const uint32_t * ts = (const uint32_t *)(data + 6); + write_int32(bs, *inc); + write_int32(bs, *ts); + break; + } + } +} + +static int +lreplace(lua_State *L) { + lua_getuservalue(L,1); + if (!lua_istable(L,-1)) { + return luaL_error(L, "call makeindex first"); + } + lua_pushvalue(L,2); + if (lua_rawget(L, -2) != LUA_TNUMBER) { + return luaL_error(L, "Can't replace key : %s", lua_tostring(L,2)); + } + int id = lua_tointeger(L, -1); + int type = id & ((1<<(BSON_TYPE_SHIFT)) - 1); + int offset = id >> BSON_TYPE_SHIFT; + uint8_t * start = (uint8_t *)lua_touserdata(L, 1); + struct bson b = { 0,16, start + offset }; + switch (type) { + case BSON_REAL: + write_double(&b, luaL_checknumber(L, 3)); + break; + case BSON_BOOLEAN: + write_byte(&b, lua_toboolean(L,3)); + break; + case BSON_OBJECTID: + case BSON_DATE: + case BSON_TIMESTAMP: + replace_object(L, type, &b); + break; + case BSON_INT32: { + if (!lua_isinteger(L, 3)) { + luaL_error(L, "%f must be a 32bit integer ", lua_tonumber(L, 3)); + } + int32_t i = lua_tointeger(L,3); + write_int32(&b, i); + break; + } + case BSON_INT64: { + if (!lua_isinteger(L, 3)) { + luaL_error(L, "%f must be a 64bit integer ", lua_tonumber(L, 3)); + } + int64_t i = lua_tointeger(L,3); + write_int64(&b, i); + break; + } + default: + luaL_error(L, "Can't replace type %d", type); + break; + } + return 0; +} + +static int +ldecode(lua_State *L) { + const int32_t * data = (int32_t *)lua_touserdata(L, 1); + if (data == NULL) { + return 0; + } + const uint8_t * b = (const uint8_t *)data; + int32_t len = get_length(b); + struct bson_reader br = { b , len }; + + unpack_dict(L, &br, false); + + return 1; +} + +static void +bson_meta(lua_State *L) { + if (luaL_newmetatable(L, "bson")) { + luaL_Reg l[] = { + { "decode", ldecode }, + { "makeindex", lmakeindex }, + { NULL, NULL }, + }; + luaL_newlib(L,l); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, ltostring); + lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, llen); + lua_setfield(L, -2, "__len"); + lua_pushcfunction(L, lreplace); + lua_setfield(L, -2, "__newindex"); + } + lua_setmetatable(L, -2); +} + +static int +lencode(lua_State *L) { + struct bson b; + bson_create(&b); + lua_settop(L,1); + luaL_checktype(L, 1, LUA_TTABLE); + pack_dict(L, &b, false, 0); + void * ud = lua_newuserdata(L, b.size); + memcpy(ud, b.ptr, b.size); + bson_destroy(&b); + bson_meta(L); + return 1; +} + +static int +lencode_order(lua_State *L) { + struct bson b; + bson_create(&b); + int n = lua_gettop(L); + if (n%2 != 0) { + return luaL_error(L, "Invalid ordered dict"); + } + pack_ordered_dict(L, &b, n, 0); + lua_settop(L,1); + void * ud = lua_newuserdata(L, b.size); + memcpy(ud, b.ptr, b.size); + bson_destroy(&b); + bson_meta(L); + return 1; +} + +static int +ldate(lua_State *L) { + int d = luaL_checkinteger(L,1); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_DATE); + luaL_addlstring(&b, (const char *)&d, sizeof(d)); + luaL_pushresult(&b); + + return 1; +} + +static int +ltimestamp(lua_State *L) { + int d = luaL_checkinteger(L,1); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_TIMESTAMP); + if (lua_isnoneornil(L,2)) { + static uint32_t inc = 0; + luaL_addlstring(&b, (const char *)&inc, sizeof(inc)); + ++inc; + } else { + uint32_t i = (uint32_t)lua_tointeger(L,2); + luaL_addlstring(&b, (const char *)&i, sizeof(i)); + } + luaL_addlstring(&b, (const char *)&d, sizeof(d)); + luaL_pushresult(&b); + + return 1; +} + +static int +lregex(lua_State *L) { + luaL_checkstring(L,1); + if (lua_gettop(L) < 2) { + lua_pushliteral(L,""); + } + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_REGEX); + lua_pushvalue(L,1); + luaL_addvalue(&b); + luaL_addchar(&b,0); + lua_pushvalue(L,2); + luaL_addvalue(&b); + luaL_addchar(&b,0); + luaL_pushresult(&b); + + return 1; +} + +static int +lbinary(lua_State *L) { + lua_settop(L,1); + luaL_Buffer b; + luaL_buffinit(L, &b); + luaL_addchar(&b, 0); + luaL_addchar(&b, BSON_BINARY); + luaL_addchar(&b, 0); // sub type + luaL_addvalue(&b); + luaL_pushresult(&b); + + return 1; +} + +static int +lsubtype(lua_State *L, int subtype, const uint8_t * buf, size_t sz) { + switch(subtype) { + case BSON_BINARY: + lua_pushvalue(L, lua_upvalueindex(6)); + lua_pushlstring(L, (const char *)buf+1, sz-1); + lua_pushinteger(L, buf[0]); + return 3; + case BSON_OBJECTID: { + if (sz != 12) { + return luaL_error(L, "Invalid object id"); + } + char oid[24]; + int i; + const uint8_t * id = buf; + static char *hex = "0123456789abcdef"; + for (i=0;i<12;i++) { + oid[i*2] = hex[id[i] >> 4]; + oid[i*2+1] = hex[id[i] & 0xf]; + } + lua_pushvalue(L, lua_upvalueindex(7)); + lua_pushlstring(L, oid, 24); + + return 2; + } + case BSON_DATE: { + if (sz != 4) { + return luaL_error(L, "Invalid date"); + } + int d = *(const int *)buf; + lua_pushvalue(L, lua_upvalueindex(9)); + lua_pushinteger(L, d); + return 2; + } + case BSON_TIMESTAMP: { + if (sz != 8) { + return luaL_error(L, "Invalid timestamp"); + } + const uint32_t * ts = (const uint32_t *)buf; + lua_pushvalue(L, lua_upvalueindex(8)); + lua_pushinteger(L, (lua_Integer)ts[1]); + lua_pushinteger(L, (lua_Integer)ts[0]); + return 3; + } + case BSON_REGEX: { + --sz; + size_t i; + const uint8_t *str = buf; + for (i=0;i= 2) { + return lsubtype(L, (uint8_t)str[1], (const uint8_t *)str+2, len-2); + } else { + type = 5; + break; + } + } + default: + return luaL_error(L, "Invalid type %s",lua_typename(L,t)); + } + lua_pushvalue(L, lua_upvalueindex(type)); + lua_pushvalue(L,1); + return 2; +} + +static void +typeclosure(lua_State *L) { + static const char * typename_array[] = { + "number", // 1 + "boolean", // 2 + "table", // 3 + "nil", // 4 + "string", // 5 + "binary", // 6 + "objectid", // 7 + "timestamp", // 8 + "date", // 9 + "regex", // 10 + "minkey", // 11 + "maxkey", // 12 + "unsupported", // 13 + }; + int i; + int n = sizeof(typename_array) / sizeof(typename_array[0]); + for (i=0;i>2)+hostname[i]); + } + h ^= i; + } + oid_header[0] = h & 0xff; + oid_header[1] = (h>>8) & 0xff; + oid_header[2] = (h>>16) & 0xff; + oid_header[3] = pid & 0xff; + oid_header[4] = (pid >> 8) & 0xff; + + uint32_t c = h ^ time(NULL) ^ (uintptr_t)&h; + if (c == 0) { + c = 1; + } + oid_counter = c; +} + +static inline int +hextoint(char c) { + if (c>='0' && c<='9') + return c-'0'; + if (c>='a' && c<='z') + return c-'a'+10; + if (c>='A' && c<='Z') + return c-'A'+10; + return 0; +} + +static int +lobjectid(lua_State *L) { + uint8_t oid[14] = { 0, BSON_OBJECTID }; + if (lua_isstring(L,1)) { + size_t len; + const char * str = lua_tolstring(L,1,&len); + if (len != 24) { + return luaL_error(L, "Invalid objectid %s", str); + } + int i; + for (i=0;i<12;i++) { + oid[i+2] = hextoint(str[i*2]) << 4 | hextoint(str[i*2+1]); + } + } else { + time_t ti = time(NULL); + // old_counter is a static var, use atom inc. + uint32_t id = atomic_inc(oid_counter); + + oid[2] = (ti>>24) & 0xff; + oid[3] = (ti>>16) & 0xff; + oid[4] = (ti>>8) & 0xff; + oid[5] = ti & 0xff; + memcpy(oid+6 , oid_header, 5); + oid[11] = (id>>16) & 0xff; + oid[12] = (id>>8) & 0xff; + oid[13] = id & 0xff; + } + lua_pushlstring( L, (const char *)oid, 14); + + return 1; +} + +static void init_bson_numstr() { + int i; + for (i = 0; i < MAX_NUMBER; i++) { + char tmp[8]; + bson_numstr_len[i] = sprintf(tmp, "%d", i); + memcpy(bson_numstrs[i], tmp, bson_numstr_len[i]); + } +} + +static atomic_t g_inited = 0; + +static void init_once() { + if (g_inited == 0 && atomic_cas(g_inited, 0, 1)) { + init_oid_header(); + init_bson_numstr(); + } +} + +LUAMOD_API int luaopen_bson(lua_State *L) { + luaL_checkversion(L); + init_once(); + luaL_Reg l[] = { + { "encode", lencode }, + { "encode_order", lencode_order }, + { "date", ldate }, + { "timestamp", ltimestamp }, + { "regex", lregex }, + { "binary", lbinary }, + { "objectid", lobjectid }, + { "decode", ldecode }, + { NULL, NULL }, + }; + + luaL_newlib(L,l); + + typeclosure(L); + lua_setfield(L,-2,"type"); + char null[] = { 0, BSON_NULL }; + lua_pushlstring(L, null, sizeof(null)); + lua_setfield(L,-2,"null"); + char minkey[] = { 0, BSON_MINKEY }; + lua_pushlstring(L, minkey, sizeof(minkey)); + lua_setfield(L,-2,"minkey"); + char maxkey[] = { 0, BSON_MAXKEY }; + lua_pushlstring(L, maxkey, sizeof(maxkey)); + lua_setfield(L,-2,"maxkey"); + + return 1; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bson_t* bson_new() { + bson_t* ptr = (bson_t*)nl_malloc(sizeof(*ptr)); + bson_create(ptr); + return ptr; +} + +void bson_free(bson_t* ptr) { + bson_destroy(ptr); + nl_free(ptr); +} + +static int bson_encode_safe(lua_State *L) { + bson_t* b = (bson_t*)lua_touserdata(L, 2); //arg1: table, arg2: bson_t ptr. + lua_settop(L, 1); + pack_dict(L, b, false, 0); + return 0; +} + +bool bson_encode(bson_t* b, lua_State *L, int idx) { + if (lua_istable(L, idx)) { + int status; + lua_checkstack(L, 3); + lua_pushcfunction(L, bson_encode_safe); + lua_pushvalue(L, idx); + lua_pushlightuserdata(L, b); + return lua_pcall(L, 2, 0, NULL) == LUA_OK; + } + lua_checkstack(L, 1); + lua_pushstring(L, "table expected"); + return false; +} + diff --git a/src/lbson.h b/src/lbson.h new file mode 100644 index 0000000..605a20c --- /dev/null +++ b/src/lbson.h @@ -0,0 +1,18 @@ +#ifndef LBSON_H_ +#define LBSON_H_ +#include "common.h" + +#define DEFAULT_CAP 64 + +typedef struct bson { + int size; + int cap; + uint8_t *ptr; + uint8_t buffer[DEFAULT_CAP]; +} bson_t; + +extern bson_t* bson_new(); +extern void bson_free(bson_t* b); +extern bool bson_encode(bson_t* b, lua_State *L, int idx); + +#endif \ No newline at end of file diff --git a/src/message.cpp b/src/message.cpp new file mode 100644 index 0000000..d6e2a4a --- /dev/null +++ b/src/message.cpp @@ -0,0 +1,10 @@ +#include "message.h" + +message_array_t* message_array_create(message_t* messages, uint32_t count) { + return NULL; +} + +void message_array_release(message_array_t* array) { + //to be fix + return; +} diff --git a/src/message.h b/src/message.h index 956e4da..603b4a1 100644 --- a/src/message.h +++ b/src/message.h @@ -1,6 +1,7 @@ #ifndef MESSAGE_H_ #define MESSAGE_H_ #include "buffer.h" +#include "lbson.h" #define MESSAGE_TYPE_BIT 24 #define MAKE_MESSAGE_TYPE(mtype, dtype) (((uint32_t)(dtype) << MESSAGE_TYPE_BIT) | ((mtype) & (((uint32_t)1 << MESSAGE_TYPE_BIT) - 1))) @@ -8,6 +9,7 @@ #define MESSAGE_TYPE(type) (type & ((((uint32_t)1 << MESSAGE_TYPE_BIT) - 1))) typedef struct { uint8_t m_nil; } nil_t; +typedef struct message_array_t message_array_t; enum data_type { NIL = 0, @@ -17,17 +19,21 @@ enum data_type { INTEGER = 4, //support after lua53 BUFFER = 5, //need to be freed STRING = 6, //need to be freed - TERROR = 7 // + BSON = 7, //need to be freed + ARRAY = 8, //need to be freed[warning] + TERROR = 9 // }; typedef union data_t { - bool m_bool; - void *m_userdata; - double m_number; - int64_t m_integer; - buffer_t m_buffer; - char *m_string; - int32_t m_error; + bool m_bool; + void *m_userdata; + double m_number; + int64_t m_integer; + buffer_t m_buffer; + char *m_string; + bson_t *m_bson; + message_array_t *m_array; + int32_t m_error; } data_t; enum message_type { @@ -59,6 +65,8 @@ enum message_type { #define message_integer(msg) ((msg).m_data.m_integer) #define message_buffer(msg) ((msg).m_data.m_buffer) #define message_string(msg) ((msg).m_data.m_string) +#define message_bson(msg) ((msg).m_data.m_bson) +#define message_array(msg) ((msg).m_data.m_array) #define message_error(msg) ((msg).m_data.m_error) #define message_data_type(msg) (DATA_TYPE((msg).m_type)) @@ -69,6 +77,8 @@ enum message_type { #define message_is_integer(msg) (INTEGER == message_data_type(msg)) #define message_is_buffer(msg) (BUFFER == message_data_type(msg)) #define message_is_string(msg) (STRING == message_data_type(msg)) +#define message_is_bson(msg) (BSON == message_data_type(msg)) +#define message_is_array(msg) (ARRAY == message_data_type(msg)) #define message_is_error(msg) (TERROR == message_data_type(msg)) #define message_is_pure_error(msg) (TERROR == message_data_type(msg) && message_error(msg) != 0) @@ -77,13 +87,24 @@ enum message_type { #define message_clean(msg) do { \ if (message_is_buffer(msg)) { \ buffer_release(msg.m_data.m_buffer); \ - } else if (message_is_string(msg)&&(msg).m_data.m_string) { \ - nl_free((msg).m_data.m_string); \ - msg.m_data.m_string = NULL; \ + } else if (message_is_string(msg)) { \ + if ((msg).m_data.m_string) { \ + nl_free((msg).m_data.m_string); \ + (msg).m_data.m_string = NULL; \ + } \ + } else if (message_is_bson(msg)) { \ + if ((msg).m_data.m_bson) { \ + bson_free((msg).m_data.m_bson); \ + (msg).m_data.m_bson = NULL; \ + } \ + } else if (message_is_array(msg)) { \ + if ((msg).m_data.m_array) { \ + message_array_release((msg).m_data.m_array); \ + (msg).m_data.m_array = NULL; \ + } \ } \ } while (0) - class message_t { public: message_t() @@ -125,6 +146,10 @@ class message_t { message_t(uint32_t source, int32_t session, uint32_t msg_type, nl_err_code err) : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, TERROR)) { m_data.m_error = err; } + + message_t(uint32_t source, int32_t session, uint32_t msg_type, bson_t* bson) + : m_source(source), m_session(session), + m_type(MAKE_MESSAGE_TYPE(msg_type, BSON)) { m_data.m_bson = bson; } public: uint32_t m_source; int32_t m_session; @@ -132,4 +157,14 @@ class message_t { data_t m_data; }; +///////////////////////////////////////////////////////////////////////////////////////////////////////// +//message array api +struct message_array_t { + uint32_t m_count; + message_t m_array[0]; +}; + +extern message_array_t* message_array_create(message_t* messages, uint32_t count); +extern void message_array_release(message_array_t* array); + #endif From a2afce75c9196e41cbc701dfcd459a31dc1f2dbe Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 7 Apr 2016 09:23:04 +0800 Subject: [PATCH 022/173] =?UTF-8?q?=E4=BC=98=E5=8C=96bson=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 45 ++++++++++++++++++++++++++----- src/lbson.cpp | 64 ++++++++++++++++++++++++++++++++------------- src/lbson.h | 12 ++++++--- src/message.cpp | 6 +++-- src/message.h | 2 +- 5 files changed, 98 insertions(+), 31 deletions(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 467c6e0..3755a17 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -549,9 +549,26 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) case STRING: lua_pushstring(L, message_string(message)); return; + case BSON: + if (message_bson(message)->extract) { + bson_decode(message_bson(message), L); + } else { + create_bson(message_bson(message), L); + } + return; case TERROR: lua_pushinteger(L, message_error(message)); return; + case ARRAY: + message_array_t *array = message_array(message); + if (array->m_count > 0) { + for (int32_t i = 0; i < array->m_count; ++i) { //extract them + lua_pushmessage(L, array->m_array[i]); + } + } else { + lua_pushnil(L); + } + return; default: lua_pushnil(L); return; @@ -600,11 +617,13 @@ int32_t context_lua_t::wakeup_ref_session(int32_t ref, message_t& message, bool if (blocking || free_callback) { lua_free_ref_session(m_lstate, ref); } + int32_t oldTop = lua_gettop(m_lstate); lua_pushboolean(co, !message_is_pure_error(message)); lua_pushmessage(co, message); lua_pushnumber(co, message.m_source); lua_pushinteger(co, message.m_session); - resume_coroutine(co, 4); + int32_t newTop = lua_gettop(m_lstate); + resume_coroutine(co, newTop - oldTop); return 1; } return 0; @@ -832,6 +851,7 @@ int32_t context_lua_t::context_destroy(lua_State *L) int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t msg_type, message_t& message) { buffer_t* buffer; + int32_t* bson; switch (lua_type(L, idx)) { case LUA_TNUMBER: if (lua_isinteger(L, idx)) { @@ -859,11 +879,21 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t return UV_OK; case LUA_TUSERDATA: buffer = (buffer_t*)luaL_testudata(L, idx, BUFFER_METATABLE); - if (!buffer) return NL_ETRANSTYPE; - message.m_type = MAKE_MESSAGE_TYPE(msg_type, USERDATA); - message.m_data.m_buffer = *buffer; - message.m_source = lua_get_context_handle(L); - return UV_OK; + if (buffer) { + message.m_type = MAKE_MESSAGE_TYPE(msg_type, BUFFER); + message.m_data.m_buffer = *buffer; + message.m_source = lua_get_context_handle(L); + return UV_OK; + } + //to be fix : bson, array + //bson = (int32_t*)luaL_testudata(L, idx, BSON_METATABLE); + //if (bson) { + // message.m_type = MAKE_MESSAGE_TYPE(msg_type, BSON); + // message.m_data.m_bson = (bson_t*)bson; //temporary store the pointer here, which is not illegal. + // message.m_source = lua_get_context_handle(L); + // return UV_OK; + //} + return NL_ETRANSTYPE; case LUA_TLIGHTUSERDATA: message.m_type = MAKE_MESSAGE_TYPE(msg_type, USERDATA); message.m_data.m_userdata = (void*)lua_touserdata(L, idx); @@ -905,6 +935,7 @@ int32_t context_lua_t::context_send(lua_State *L, int32_t idx, uint32_t handle, } else { return NL_ETRANSTYPE; } + //to be fix : bson, array case LUA_TLIGHTUSERDATA: ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (void*)lua_touserdata(L, idx)); break; @@ -940,6 +971,8 @@ int32_t context_lua_t::context_query_yield_finalize(lua_State *root_coro, lua_St bool ret; if (message_is_string(message)) { ret = singleton_ref(node_lua_t).context_send_string_safe(destination, lctx->get_handle(), message.m_session, CONTEXT_QUERY, message_string(message)); + } else if (message_is_bson(message)) { + } else { ret = singleton_ref(node_lua_t).context_send(destination, message); } diff --git a/src/lbson.cpp b/src/lbson.cpp index ed98b56..b029185 100644 --- a/src/lbson.cpp +++ b/src/lbson.cpp @@ -51,7 +51,8 @@ bson_destroy(struct bson *b) { } static inline void -bson_create(struct bson *b) { +bson_create(struct bson *b, bool extract) { + b->extract = extract; b->size = 0; b->cap = DEFAULT_CAP; b->ptr = b->buffer; @@ -626,7 +627,7 @@ unpack_dict(lua_State *L, struct bson_reader *br, bool array) { static int lmakeindex(lua_State *L) { - int32_t *bson = (int32_t *)luaL_checkudata(L, 1, "bson"); + int32_t *bson = (int32_t *)luaL_checkudata(L, 1, BSON_METATABLE); const uint8_t * start = (const uint8_t *)bson; struct bson_reader br = { start+4, get_length(start) - 5 }; lua_newtable(L); @@ -812,7 +813,7 @@ ldecode(lua_State *L) { static void bson_meta(lua_State *L) { - if (luaL_newmetatable(L, "bson")) { + if (luaL_newmetatable(L, BSON_METATABLE)) { luaL_Reg l[] = { { "decode", ldecode }, { "makeindex", lmakeindex }, @@ -833,7 +834,7 @@ bson_meta(lua_State *L) { static int lencode(lua_State *L) { struct bson b; - bson_create(&b); + bson_create(&b, false); lua_settop(L,1); luaL_checktype(L, 1, LUA_TTABLE); pack_dict(L, &b, false, 0); @@ -847,7 +848,7 @@ lencode(lua_State *L) { static int lencode_order(lua_State *L) { struct bson b; - bson_create(&b); + bson_create(&b, false); int n = lua_gettop(L); if (n%2 != 0) { return luaL_error(L, "Invalid ordered dict"); @@ -1200,35 +1201,62 @@ LUAMOD_API int luaopen_bson(lua_State *L) { //////////////////////////////////////////////////////////////////////////////////////////////////// -bson_t* bson_new() { - bson_t* ptr = (bson_t*)nl_malloc(sizeof(*ptr)); - bson_create(ptr); - return ptr; +bson_t* create_bson(bson_t* bson_ptr, lua_State* L) { + void * ud = lua_newuserdata(L, bson_ptr->size); + memcpy(ud, bson_ptr->ptr, bson_ptr->size); + bson_meta(L); +} + +bson_t* bson_new(bool extract) { + bson_t* bson_ptr = (bson_t*)nl_malloc(sizeof(*bson_ptr)); + bson_create(bson_ptr, extract); + return bson_ptr; } -void bson_free(bson_t* ptr) { - bson_destroy(ptr); - nl_free(ptr); +void bson_release(bson_t* bson_ptr) { + bson_destroy(bson_ptr); + nl_free(bson_ptr); } static int bson_encode_safe(lua_State *L) { - bson_t* b = (bson_t*)lua_touserdata(L, 2); //arg1: table, arg2: bson_t ptr. + bson_t* bson_ptr = (bson_t*)lua_touserdata(L, 2); //arg1: table, arg2: bson_t ptr. lua_settop(L, 1); - pack_dict(L, b, false, 0); - return 0; + pack_dict(L, bson_ptr, false, 0); + lua_pushlightuserdata(L, bson_ptr); + return 1; } -bool bson_encode(bson_t* b, lua_State *L, int idx) { +bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx) { if (lua_istable(L, idx)) { int status; lua_checkstack(L, 3); lua_pushcfunction(L, bson_encode_safe); lua_pushvalue(L, idx); - lua_pushlightuserdata(L, b); - return lua_pcall(L, 2, 0, NULL) == LUA_OK; + lua_pushlightuserdata(L, bson_ptr); + if (lua_pcall(L, 2, 1, NULL) == LUA_OK) { + return true; + } + return false; } lua_checkstack(L, 1); lua_pushstring(L, "table expected"); return false; } +static int bson_decode_safe(lua_State *L) { + bson_t* bson_ptr = (bson_t*)lua_touserdata(L, 1); //arg1: bson_t ptr. + lua_settop(L, 1); + const uint8_t * b = (const uint8_t *)bson_ptr->ptr; + int32_t len = get_length(b); + struct bson_reader br = { b, len }; + unpack_dict(L, &br, false); + return 1; +} + +bool bson_decode(bson_t* bson_ptr, lua_State *L) { + lua_checkstack(L, 3); + lua_pushcfunction(L, bson_decode_safe); + lua_pushlightuserdata(L, bson_ptr); + return lua_pcall(L, 1, 1, NULL) == LUA_OK; +} + diff --git a/src/lbson.h b/src/lbson.h index 605a20c..81ff0b7 100644 --- a/src/lbson.h +++ b/src/lbson.h @@ -2,17 +2,21 @@ #define LBSON_H_ #include "common.h" -#define DEFAULT_CAP 64 +#define DEFAULT_CAP 64 +#define BSON_METATABLE "bson" typedef struct bson { + bool extract; int size; int cap; uint8_t *ptr; uint8_t buffer[DEFAULT_CAP]; } bson_t; -extern bson_t* bson_new(); -extern void bson_free(bson_t* b); -extern bool bson_encode(bson_t* b, lua_State *L, int idx); +extern bson_t* create_bson(bson_t* bson_ptr, lua_State* L); +extern bson_t* bson_new(bool extract); +extern void bson_release(bson_t* bson_ptr); +extern bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx); +extern bool bson_decode(bson_t* bson_ptr, lua_State *L); #endif \ No newline at end of file diff --git a/src/message.cpp b/src/message.cpp index d6e2a4a..cadf796 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -5,6 +5,8 @@ message_array_t* message_array_create(message_t* messages, uint32_t count) { } void message_array_release(message_array_t* array) { - //to be fix - return; + for (int32_t i = 0; i < array->m_count; ++i) { + message_clean(array->m_array[i]); + } + nl_free(array); } diff --git a/src/message.h b/src/message.h index 603b4a1..31e6457 100644 --- a/src/message.h +++ b/src/message.h @@ -94,7 +94,7 @@ enum message_type { } \ } else if (message_is_bson(msg)) { \ if ((msg).m_data.m_bson) { \ - bson_free((msg).m_data.m_bson); \ + bson_release((msg).m_data.m_bson); \ (msg).m_data.m_bson = NULL; \ } \ } else if (message_is_array(msg)) { \ From ede3b3432e5bc9881052a71784a08889cf284452 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 7 Apr 2016 10:42:01 +0800 Subject: [PATCH 023/173] =?UTF-8?q?=E4=BC=98=E5=8C=96bson?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 5 +++-- src/lbson.cpp | 5 +++-- src/lbson.h | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 3755a17..64280a1 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -527,6 +527,7 @@ void context_lua_t::lua_free_ref_session(lua_State *L, int32_t ref) void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) { + message_array_t *array = NULL; switch (message_data_type(message)) { case NIL: lua_pushnil(L); @@ -560,8 +561,8 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) lua_pushinteger(L, message_error(message)); return; case ARRAY: - message_array_t *array = message_array(message); - if (array->m_count > 0) { + array = message_array(message); + if (array != NULL && array->m_count > 0) { for (int32_t i = 0; i < array->m_count; ++i) { //extract them lua_pushmessage(L, array->m_array[i]); } diff --git a/src/lbson.cpp b/src/lbson.cpp index b029185..a24ba7a 100644 --- a/src/lbson.cpp +++ b/src/lbson.cpp @@ -760,7 +760,7 @@ lreplace(lua_State *L) { int type = id & ((1<<(BSON_TYPE_SHIFT)) - 1); int offset = id >> BSON_TYPE_SHIFT; uint8_t * start = (uint8_t *)lua_touserdata(L, 1); - struct bson b = { 0,16, start + offset }; + struct bson b = { false, 0, 16, start + offset }; switch (type) { case BSON_REAL: write_double(&b, luaL_checknumber(L, 3)); @@ -1201,10 +1201,11 @@ LUAMOD_API int luaopen_bson(lua_State *L) { //////////////////////////////////////////////////////////////////////////////////////////////////// -bson_t* create_bson(bson_t* bson_ptr, lua_State* L) { +void* create_bson(bson_t* bson_ptr, lua_State* L) { void * ud = lua_newuserdata(L, bson_ptr->size); memcpy(ud, bson_ptr->ptr, bson_ptr->size); bson_meta(L); + return ud; } bson_t* bson_new(bool extract) { diff --git a/src/lbson.h b/src/lbson.h index 81ff0b7..8b3592f 100644 --- a/src/lbson.h +++ b/src/lbson.h @@ -13,7 +13,7 @@ typedef struct bson { uint8_t buffer[DEFAULT_CAP]; } bson_t; -extern bson_t* create_bson(bson_t* bson_ptr, lua_State* L); +extern void* create_bson(bson_t* bson_ptr, lua_State* L); extern bson_t* bson_new(bool extract); extern void bson_release(bson_t* bson_ptr); extern bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx); From d1a4144d9581196206bb6883dc07cddac26a34c8 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sat, 9 Apr 2016 19:21:48 +0800 Subject: [PATCH 024/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E4=B9=8B=E9=97=B4=E6=B6=88=E6=81=AF=E5=8F=91=E9=80=81?= =?UTF-8?q?=E5=92=8C=E8=AF=BB=E5=8F=96,=E4=BC=98=E5=8C=96bson=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.lua | 25 +++-- src/context_lua.cpp | 231 +++++++++++++++++++++++------------------ src/context_lua.h | 6 +- src/lbson.cpp | 25 +++-- src/lbson.h | 4 +- src/lua_tcp_handle.cpp | 3 +- src/message.cpp | 15 ++- src/message.h | 6 +- src/node_lua.cpp | 2 - src/node_lua.h | 30 +++++- src/uv_tcp_handle.cpp | 6 +- 11 files changed, 217 insertions(+), 136 deletions(-) diff --git a/node-lua.lua b/node-lua.lua index f5891ef..c0490f1 100644 --- a/node-lua.lua +++ b/node-lua.lua @@ -27,23 +27,30 @@ 14. tcp.set_nodelay(socket, enable) -15. result, error = context.send(handle, data) --QUERY +15. result, error = context.send(handle, data1, data2, ...) --QUERY -16. result, query_data = context.query(handle, data[, timeout [, query_callback(result, query_data, handle, data[, timeout])]]) --QUERY(real query) +16. result, query_data1, query_data2, ... = context.query(handle, data1, data2, ... [, query_callback(result, query_data1, query_data2, ...)]]) --QUERY(real query) --query_callback is a once callback, blocking if callback is nil. -17. result, error = context.reply(handle, session, data) --REPLY -18. result, data, recv_handle, session = context.recv(handle[, timeout]) +17. result, query_data1, query_data2, ... = context.timed_query(handle, timeout, data1, data2, ... [, query_callback(result, query_data1, query_data2, ...)]]) --QUERY(real query) + --query_callback is a once callback, blocking if callback is nil. + +18. result, error = context.reply(handle, session, data1, data2, ...) --REPLY + +19. result, recv_handle, session, data1, data2, ... = context.recv(handle[, timeout]) --recv_callback is a continues callback, blocking if callback is nil. -19. result, data, recv_handle, session = context.recv(handle[, recv_callback(result, data, recv_handle, session, handle)]) + +20. result, recv_handle, session, data1, data2, ... = context.recv(handle[, recv_callback(result, recv_handle, session, data1, data2, ... )]) --recv_callback is a continues callback, blocking if callback is nil. -20. result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]]) + +21. result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]]) --connect_callback is a once callback, blocking if callback is nil. -21. timer.sleep(seconds) -22. timer.timeout(seconds, ..., void (*callback)(...)) +22. timer.sleep(seconds) + +23. timer.timeout(seconds, ..., void (*callback)(...)) -23. timer.loop(interval, repeat_time, ..., void (*callback)(...)) +24. timer.loop(interval, repeat_time, ..., void (*callback)(...)) ---------------------------------------------------------------------------------------------------------------------------- diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 64280a1..a5ca140 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -336,11 +336,12 @@ int32_t context_lua_t::yielding_finalize(lua_State *root_coro, int32_t status) int32_t context_lua_t::common_yield_continue(lua_State* L, int status, lua_KContext ctx) { - if (!lua_toboolean(L, -4) && context_lua_t::lua_get_context(L)->get_yielding_status() != UV_OK) { - context_lua_t::lua_throw(L, -3); + int32_t old_top = (int32_t)ctx; + if (!lua_toboolean(L, old_top + 1) && context_lua_t::lua_get_context(L)->get_yielding_status() != UV_OK) { + context_lua_t::lua_throw(L, old_top + 2); } lua_pop(L, 2); //pop out two useless arguments - return 2; + return lua_gettop(L) - old_top; } int32_t context_lua_t::lua_yield_send(lua_State *L, uint32_t destination, yiled_finalize_t fnz, void* fnz_ud, lua_KFunction yieldk, int64_t timeout) @@ -354,15 +355,16 @@ int32_t context_lua_t::lua_yield_send(lua_State *L, uint32_t destination, yiled_ lctx->m_shared->m_yielding_status = UV_OK; lctx->m_shared->m_yielding_timeout = timeout; if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_yieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */ - return lua_yieldk(L, 0, 0, yieldk); /* n(0) result to yield and ctx(0) is not allowed */ + return lua_yieldk(L, 0, (lua_KContext)lua_gettop(L), yieldk); } else { if (stacks) { /* stack enough, but not yield-able */ lctx->yielding_finalize(NULL, NL_EYIELD); + int32_t top = lua_gettop(L); lua_pushboolean(L, 0); lua_pushinteger(L, NL_EYIELD); lua_pushnil(L); lua_pushnil(L); - return (yieldk == NULL) ? 4 : yieldk(L, LUA_YIELD, 0); + return (yieldk == NULL) ? 4 : yieldk(L, LUA_YIELD, (lua_KContext)top); } else { /* error jump directly */ lctx->yielding_finalize(NULL, NL_ESTACKLESS); return luaL_error(L, "attempt to yield across a stack-less coroutine"); @@ -563,6 +565,7 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) case ARRAY: array = message_array(message); if (array != NULL && array->m_count > 0) { + lua_checkstack(L, array->m_count); for (int32_t i = 0; i < array->m_count; ++i) { //extract them lua_pushmessage(L, array->m_array[i]); } @@ -619,8 +622,10 @@ int32_t context_lua_t::wakeup_ref_session(int32_t ref, message_t& message, bool lua_free_ref_session(m_lstate, ref); } int32_t oldTop = lua_gettop(m_lstate); + lua_checkstack(co, 2); lua_pushboolean(co, !message_is_pure_error(message)); lua_pushmessage(co, message); + lua_checkstack(co, 2); lua_pushnumber(co, message.m_source); lua_pushinteger(co, message.m_session); int32_t newTop = lua_gettop(m_lstate); @@ -852,7 +857,8 @@ int32_t context_lua_t::context_destroy(lua_State *L) int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t msg_type, message_t& message) { buffer_t* buffer; - int32_t* bson; + bson_t* bson_ptr; + int32_t* bson_data; switch (lua_type(L, idx)) { case LUA_TNUMBER: if (lua_isinteger(L, idx)) { @@ -863,99 +869,98 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t message.m_data.m_number = (double)lua_tonumber(L, idx); } message.m_source = lua_get_context_handle(L); - return UV_OK; + return 1; case LUA_TSTRING: message.m_type = MAKE_MESSAGE_TYPE(msg_type, STRING); - message.m_data.m_string = (char*)lua_tostring(L, idx); + message.m_data.m_string = nl_strdup(lua_tostring(L, idx)); message.m_source = lua_get_context_handle(L); - return UV_OK; + return 1; case LUA_TBOOLEAN: message.m_type = MAKE_MESSAGE_TYPE(msg_type, TBOOLEAN); message.m_data.m_bool = (bool)lua_toboolean(L, idx); message.m_source = lua_get_context_handle(L); - return UV_OK; + return 1; case LUA_TNIL: message.m_type = MAKE_MESSAGE_TYPE(msg_type, NIL); message.m_source = lua_get_context_handle(L); - return UV_OK; + return 1; case LUA_TUSERDATA: buffer = (buffer_t*)luaL_testudata(L, idx, BUFFER_METATABLE); if (buffer) { message.m_type = MAKE_MESSAGE_TYPE(msg_type, BUFFER); - message.m_data.m_buffer = *buffer; + message.m_data.m_buffer = buffer_grab(*buffer); message.m_source = lua_get_context_handle(L); - return UV_OK; + return 1; } - //to be fix : bson, array - //bson = (int32_t*)luaL_testudata(L, idx, BSON_METATABLE); - //if (bson) { - // message.m_type = MAKE_MESSAGE_TYPE(msg_type, BSON); - // message.m_data.m_bson = (bson_t*)bson; //temporary store the pointer here, which is not illegal. - // message.m_source = lua_get_context_handle(L); - // return UV_OK; - //} - return NL_ETRANSTYPE; + bson_data = (int32_t*)luaL_testudata(L, idx, BSON_METATABLE); + if (bson_data) { + message.m_type = MAKE_MESSAGE_TYPE(msg_type, BSON); + message.m_data.m_bson = bson_new(bson_data, false); + message.m_source = lua_get_context_handle(L); + return 1; + } + lua_pushstring(L, "transfer data type not supported"); + return 0; case LUA_TLIGHTUSERDATA: message.m_type = MAKE_MESSAGE_TYPE(msg_type, USERDATA); message.m_data.m_userdata = (void*)lua_touserdata(L, idx); message.m_source = lua_get_context_handle(L); - return UV_OK; + return 1; + case LUA_TTABLE: + message.m_type = MAKE_MESSAGE_TYPE(msg_type, BSON); + message.m_data.m_bson = bson_new(NULL, true); + message.m_source = lua_get_context_handle(L); + return bson_encode(message.m_data.m_bson, L, idx) ? 1 : 0; default: - return NL_ETRANSTYPE; + lua_pushstring(L, "transfer data type not supported"); + return 0; } } -int32_t context_lua_t::context_send(lua_State *L, int32_t idx, uint32_t handle, int32_t session, uint32_t msg_type) +int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t count, uint32_t msg_type, message_t& message) { - bool ret = false; - nil_t nil; - buffer_t* buffer; - context_t* ctx = lua_get_context(L); - switch (lua_type(L, idx)) { - case LUA_TNUMBER: - if (lua_isinteger(L, idx)) { - ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (int64_t)lua_tointeger(L, idx)); - } else { - ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (double)lua_tonumber(L, idx)); - } - break; - case LUA_TSTRING: - ret = singleton_ref(node_lua_t).context_send_string_safe(handle, ctx->get_handle(), session, msg_type, lua_tostring(L, idx)); - break; - case LUA_TBOOLEAN: - ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (bool)lua_toboolean(L, idx)); - break; - case LUA_TNIL: - ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, nil); - break; - case LUA_TUSERDATA: - buffer = (buffer_t*)luaL_testudata(L, idx, BUFFER_METATABLE); - if (buffer) { - ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, *buffer); - break; - } else { - return NL_ETRANSTYPE; + if (count <= 1) { + return context_check_message(L, idx, msg_type, message); + } + message_array_t* array = message_array_create(count); + message.m_type = MAKE_MESSAGE_TYPE(msg_type, ARRAY); + message.m_data.m_array = array; + message.m_source = lua_get_context_handle(L); + for (int32_t i = 0; i < count; ++i) { + if (context_check_message(L, idx + i, msg_type, array->m_array[i]) == 0) { + return 0; } - //to be fix : bson, array - case LUA_TLIGHTUSERDATA: - ret = singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, msg_type, (void*)lua_touserdata(L, idx)); - break; - default: + } + return 1; +} + +int32_t context_lua_t::context_send(lua_State *L, int32_t idx, uint32_t count, uint32_t handle, int32_t session, uint32_t msg_type) +{ + message_t message; + int32_t status = context_check_message(L, idx, count, msg_type, message); + if (status == 0) { + message_clean(message); return NL_ETRANSTYPE; } - return ret ? UV_OK : NL_ENOCONTEXT; + if (singleton_ref(node_lua_t).context_send(handle, message)) { + return UV_OK; + } + message_clean(message); + return NL_ENOCONTEXT; } int32_t context_lua_t::context_send(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); - int32_t ret = context_send(L, 2, handle, LUA_REFNIL, CONTEXT_QUERY); + int32_t top = lua_gettop(L); + luaL_checkany(L, 2); + int32_t ret = context_send(L, 2, top - 1, handle, LUA_REFNIL, CONTEXT_QUERY); if (ret == UV_OK) { lua_pushboolean(L, 1); return 1; } if (ret == NL_ETRANSTYPE) { - luaL_argerror(L, 2, common_strerror(NL_ETRANSTYPE)); + lua_error(L); return 0; } lua_pushboolean(L, 0); @@ -969,14 +974,7 @@ int32_t context_lua_t::context_query_yield_finalize(lua_State *root_coro, lua_St context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); message_t& message = lctx->get_yielding_message(); message.m_session = context_lua_t::lua_ref_yield_coroutine(root_coro); - bool ret; - if (message_is_string(message)) { - ret = singleton_ref(node_lua_t).context_send_string_safe(destination, lctx->get_handle(), message.m_session, CONTEXT_QUERY, message_string(message)); - } else if (message_is_bson(message)) { - - } else { - ret = singleton_ref(node_lua_t).context_send(destination, message); - } + bool ret = singleton_ref(node_lua_t).context_send(destination, message); if (ret) { int64_t timeout = lctx->get_yielding_timeout(); if (timeout > 0) { @@ -985,47 +983,50 @@ int32_t context_lua_t::context_query_yield_finalize(lua_State *root_coro, lua_St return UV_OK; } else { lua_free_ref_session(main_coro, message.m_session); + message_clean(message); return NL_ENOCONTEXT; } + } else { + context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); + message_t& message = lctx->get_yielding_message(); + message_clean(message); } return UV_OK; } int32_t context_lua_t::context_query_yield_continue(lua_State* L, int status, lua_KContext ctx) { - if (!lua_toboolean(L, -4)) { + int32_t old_top = (int32_t)ctx; + if (!lua_toboolean(L, old_top + 1)) { int32_t ret = context_lua_t::lua_get_context(L)->get_yielding_status(); if (ret != UV_OK && ret != NL_ENOCONTEXT) { - context_lua_t::lua_throw(L, -3); + context_lua_t::lua_throw(L, old_top + 2); } } lua_pop(L, 2); //pop two useless arguments - return 2; + return lua_gettop(L) - old_top; } -int32_t context_lua_t::context_query(lua_State *L) +int32_t context_lua_t::context_query(lua_State *L, bool timed_query) { uint32_t handle = luaL_checkunsigned(L, 1); int32_t top = lua_gettop(L); uint64_t timeout = 0; - int32_t callback = 0; - if (top >= 3) { //nonblocking - if (lua_isfunction(L, 3)) { - callback = 3; - } else { - timeout = 1000 * luaL_checknumber(L, 3); - if (top >= 4) { - luaL_checktype(L, 4, LUA_TFUNCTION); - callback = 4; - } - } + if (timed_query) { + timeout = 1000 * luaL_checknumber(L, 2); + luaL_checkany(L, 3); + } else { + luaL_checkany(L, 2); } - if (callback > 0) { - lua_settop(L, callback); - lua_pushvalue(L, 2); - lua_insert(L, 1); - int32_t session = context_lua_t::lua_ref_callback(L, callback - 1, LUA_REFNIL, common_callback_adjust); - int32_t ret = context_send(L, 1, handle, session, CONTEXT_QUERY); + bool callback = lua_isfunction(L, -1); + int32_t idx = timed_query ? 3 : 2; + int32_t count = top - 1 - (timed_query ? 1 : 0) - (callback ? 1 : 0); + if (count <= 0) { + luaL_error(L, "no data to be sent"); + } + if (callback) { + int32_t session = context_lua_t::lua_ref_callback(L, 0, LUA_REFNIL, common_callback_adjust); + int32_t ret = context_send(L, idx, count, handle, session, CONTEXT_QUERY); if (ret == UV_OK) { if (timeout > 0) { context_lua_t::lua_ref_timer(L, session, timeout, 0, false); @@ -1036,7 +1037,7 @@ int32_t context_lua_t::context_query(lua_State *L) } context_lua_t::lua_free_ref_session(L, session); if (ret == NL_ETRANSTYPE) { - luaL_argerror(L, 2, common_strerror(NL_ETRANSTYPE)); + lua_error(L); return 0; } lua_pushboolean(L, 0); @@ -1045,27 +1046,38 @@ int32_t context_lua_t::context_query(lua_State *L) } context_lua_t* lctx = context_lua_t::lua_get_context(L); message_t& message = lctx->get_yielding_message(); - int ret = context_check_message(L, 2, CONTEXT_QUERY, message); - if (ret != UV_OK) { - luaL_argerror(L, 2, common_strerror(ret)); + int ret = context_check_message(L, idx, count, CONTEXT_QUERY, message); + if (ret == 0) { + message_clean(message); + lua_error(L); return 0; } return lctx->lua_yield_send(L, handle, context_query_yield_finalize, NULL, context_lua_t::context_query_yield_continue, timeout); } +int32_t context_lua_t::context_query(lua_State *L) +{ + return context_query(L, false); +} + +int32_t context_lua_t::context_timed_query(lua_State *L) +{ + return context_query(L, true); +} + int32_t context_lua_t::context_reply(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); int32_t session = luaL_checkinteger(L, 2); - int32_t ret = context_send(L, 3, handle, session, CONTEXT_REPLY); + luaL_checkany(L, 3); + int32_t ret = context_send(L, 3, lua_gettop(L) - 2, handle, session, CONTEXT_REPLY); if (ret == UV_OK) { lua_pushboolean(L, 1); return 1; } if (ret == NL_ETRANSTYPE) { - context_t* ctx = lua_get_context(L); - singleton_ref(node_lua_t).context_send(handle, ctx->get_handle(), session, CONTEXT_REPLY, NL_ETRANSTYPE); - luaL_argerror(L, 3, common_strerror(NL_ETRANSTYPE)); + singleton_ref(node_lua_t).context_send(handle, lua_get_context_handle(L), session, CONTEXT_REPLY, NL_ETRANSTYPE); + lua_error(L); return 0; } lua_pushboolean(L, 0); @@ -1088,10 +1100,24 @@ int32_t context_lua_t::context_recv_yield_finalize(lua_State *root_coro, lua_Sta int32_t context_lua_t::context_recv_yield_continue(lua_State* L, int status, lua_KContext ctx) { - if (!lua_toboolean(L, -4) && context_lua_t::lua_get_context(L)->get_yielding_status() != UV_OK) { - context_lua_t::lua_throw(L, -3); + int32_t old_top = (int32_t)ctx; + bool result = lua_toboolean(L, old_top + 1); + if (!result && context_lua_t::lua_get_context(L)->get_yielding_status() != UV_OK) { + context_lua_t::lua_throw(L, old_top + 2); + } + if (result) { + lua_rotate(L, old_top + 2, 2); + } + return lua_gettop(L) - old_top; +} + +int32_t context_lua_t::context_recv_callback_adjust(lua_State* L) +{ + bool result = lua_toboolean(L, 1); //old_top is 0 + if (result) { + lua_rotate(L, 2, 2); //push source handle and session before recved data. } - return 4; + return lua_gettop(L); } int32_t context_lua_t::context_recv_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat) @@ -1110,7 +1136,7 @@ int32_t context_lua_t::context_recv(lua_State *L) if (top >= 2) { //nonblocking if (lua_isfunction(L, 2)) { lua_settop(L, 2); - lctx->m_context_recv_sessions.make_nonblocking_callback(handle, L, 1); + lctx->m_context_recv_sessions.make_nonblocking_callback(handle, L, 0, context_recv_callback_adjust); return 0; } if (lua_isnil(L, 2)) { @@ -1226,6 +1252,7 @@ int luaopen_context(lua_State *L) { "thread", context_lua_t::context_thread }, { "send", context_lua_t::context_send }, { "query", context_lua_t::context_query }, + { "timed_query", context_lua_t::context_timed_query }, { "reply", context_lua_t::context_reply }, { "recv", context_lua_t::context_recv }, { "wait", context_lua_t::context_wait }, diff --git a/src/context_lua.h b/src/context_lua.h index d0213b2..e3a17f0 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -133,11 +133,14 @@ class context_lua_t : public context_t { /********** the following are context lua api **********/ static int32_t context_check_message(lua_State *L, int32_t idx, uint32_t msg_type, message_t& message); - static int32_t context_send(lua_State *L, int32_t idx, uint32_t handle, int32_t session, uint32_t msg_type); + static int32_t context_check_message(lua_State *L, int32_t idx, uint32_t count, uint32_t msg_type, message_t& message); + static int32_t context_send(lua_State *L, int32_t idx, uint32_t count, uint32_t handle, int32_t session, uint32_t msg_type); + static int32_t context_query(lua_State *L, bool timed_query); static int32_t context_query_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t context_query_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t context_recv_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t context_recv_yield_continue(lua_State* L, int status, lua_KContext ctx); + static int32_t context_recv_callback_adjust(lua_State* L); static int32_t context_recv_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat); static int32_t context_wait_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t context_wait_yield_continue(lua_State* L, int status, lua_KContext ctx); @@ -149,6 +152,7 @@ class context_lua_t : public context_t { static int32_t context_destroy(lua_State *L); static int32_t context_send(lua_State *L); static int32_t context_query(lua_State *L); + static int32_t context_timed_query(lua_State *L); static int32_t context_reply(lua_State *L); static int32_t context_recv(lua_State *L); static int32_t context_wait(lua_State *L); diff --git a/src/lbson.cpp b/src/lbson.cpp index a24ba7a..8199801 100644 --- a/src/lbson.cpp +++ b/src/lbson.cpp @@ -1198,7 +1198,6 @@ LUAMOD_API int luaopen_bson(lua_State *L) { return 1; } - //////////////////////////////////////////////////////////////////////////////////////////////////// void* create_bson(bson_t* bson_ptr, lua_State* L) { @@ -1208,9 +1207,22 @@ void* create_bson(bson_t* bson_ptr, lua_State* L) { return ud; } -bson_t* bson_new(bool extract) { +bson_t* bson_new(void* ud, bool extract) { bson_t* bson_ptr = (bson_t*)nl_malloc(sizeof(*bson_ptr)); bson_create(bson_ptr, extract); + if (ud != NULL) { + const uint8_t * b = (const uint8_t *)ud; + int len = get_length(b); + bson_ptr->size = len; + if (len <= DEFAULT_CAP) { + bson_ptr->ptr = bson_ptr->buffer; + bson_ptr->cap = DEFAULT_CAP; + } else { + bson_ptr->ptr = (uint8_t*)nl_malloc(len); + bson_ptr->cap = len; + } + memcpy(bson_ptr->ptr, b, len); + } return bson_ptr; } @@ -1223,8 +1235,7 @@ static int bson_encode_safe(lua_State *L) { bson_t* bson_ptr = (bson_t*)lua_touserdata(L, 2); //arg1: table, arg2: bson_t ptr. lua_settop(L, 1); pack_dict(L, bson_ptr, false, 0); - lua_pushlightuserdata(L, bson_ptr); - return 1; + return 0; } bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx) { @@ -1234,7 +1245,7 @@ bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx) { lua_pushcfunction(L, bson_encode_safe); lua_pushvalue(L, idx); lua_pushlightuserdata(L, bson_ptr); - if (lua_pcall(L, 2, 1, NULL) == LUA_OK) { + if (lua_pcall(L, 2, LUA_MULTRET, NULL) == LUA_OK) { return true; } return false; @@ -1247,7 +1258,7 @@ bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx) { static int bson_decode_safe(lua_State *L) { bson_t* bson_ptr = (bson_t*)lua_touserdata(L, 1); //arg1: bson_t ptr. lua_settop(L, 1); - const uint8_t * b = (const uint8_t *)bson_ptr->ptr; + const uint8_t * b = (const uint8_t*)bson_ptr->ptr; int32_t len = get_length(b); struct bson_reader br = { b, len }; unpack_dict(L, &br, false); @@ -1258,6 +1269,6 @@ bool bson_decode(bson_t* bson_ptr, lua_State *L) { lua_checkstack(L, 3); lua_pushcfunction(L, bson_decode_safe); lua_pushlightuserdata(L, bson_ptr); - return lua_pcall(L, 1, 1, NULL) == LUA_OK; + return lua_pcall(L, 1, LUA_MULTRET, NULL) == LUA_OK; } diff --git a/src/lbson.h b/src/lbson.h index 8b3592f..1855b9f 100644 --- a/src/lbson.h +++ b/src/lbson.h @@ -6,7 +6,7 @@ #define BSON_METATABLE "bson" typedef struct bson { - bool extract; + bool extract; //whether extract to lua table int size; int cap; uint8_t *ptr; @@ -14,7 +14,7 @@ typedef struct bson { } bson_t; extern void* create_bson(bson_t* bson_ptr, lua_State* L); -extern bson_t* bson_new(bool extract); +extern bson_t* bson_new(void* ud, bool extract); extern void bson_release(bson_t* bson_ptr); extern bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx); extern bool bson_decode(bson_t* bson_ptr, lua_State *L); diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index b5595a8..b9588eb 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -1062,7 +1062,8 @@ int32_t lua_tcp_socket_handle_t::close(lua_State* L) void lua_tcp_socket_handle_t::release_read_overflow_buffers() { - for (int32_t i = 0; i < m_read_overflow_buffers.size(); ++i) { + int32_t size = m_read_overflow_buffers.size(); + for (int32_t i = 0; i < size; ++i) { buffer_release(m_read_overflow_buffers.front()); m_read_overflow_buffers.pop(); } diff --git a/src/message.cpp b/src/message.cpp index cadf796..b16de82 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -1,12 +1,17 @@ #include "message.h" -message_array_t* message_array_create(message_t* messages, uint32_t count) { - return NULL; +message_array_t* message_array_create(uint32_t count) { + message_array_t* array = (message_array_t*)nl_calloc(1, sizeof(message_array_t) + (count - 1)*sizeof(message_t)); + array->m_count = count; + return array; } void message_array_release(message_array_t* array) { - for (int32_t i = 0; i < array->m_count; ++i) { - message_clean(array->m_array[i]); + if (array != NULL) { + for (int32_t i = 0; i < array->m_count; ++i) { + message_clean(array->m_array[i]); + } + nl_free(array); } - nl_free(array); } + diff --git a/src/message.h b/src/message.h index 31e6457..b1bfee8 100644 --- a/src/message.h +++ b/src/message.h @@ -20,7 +20,7 @@ enum data_type { BUFFER = 5, //need to be freed STRING = 6, //need to be freed BSON = 7, //need to be freed - ARRAY = 8, //need to be freed[warning] + ARRAY = 8, //need to be freed TERROR = 9 // }; @@ -161,10 +161,10 @@ class message_t { //message array api struct message_array_t { uint32_t m_count; - message_t m_array[0]; + message_t m_array[1]; }; -extern message_array_t* message_array_create(message_t* messages, uint32_t count); +extern message_array_t* message_array_create(uint32_t count); extern void message_array_release(message_array_t* array); #endif diff --git a/src/node_lua.cpp b/src/node_lua.cpp index badc4e6..82af902 100644 --- a/src/node_lua.cpp +++ b/src/node_lua.cpp @@ -53,14 +53,12 @@ bool node_lua_t::context_send(context_t* ctx, message_t& msg) { if (ctx->get_handle() != 0 && (ctx->is_inited() || ctx->get_handle() == msg.m_source)) { bool processing; - message_buffer_grab(msg); if (ctx->push_message(msg, processing)) { if (!processing) { m_worker_mgr->push_context(ctx); } return true; } - message_buffer_release(msg); } return false; } diff --git a/src/node_lua.h b/src/node_lua.h index 8e00765..c07b98f 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -53,11 +53,35 @@ class node_lua_t : public singleton_t { return false; } + FORCE_INLINE bool context_send_buffer_safe(uint32_t handle, uint32_t source, int session, int msg_type, buffer_t& buffer) + { + buffer_grab(buffer); + message_t msg(source, session, msg_type, buffer); + bool ret = context_send(handle, msg); + if (!ret) { + buffer_release(buffer); + } + return ret; + } + + FORCE_INLINE bool context_send_buffer_safe(context_t* ctx, uint32_t source, int session, int msg_type, buffer_t& buffer) + { + buffer_grab(buffer); + message_t msg(source, session, msg_type, buffer); + bool ret = context_send(ctx, msg); + if (!ret) { + buffer_release(buffer); + } + return ret; + } + FORCE_INLINE bool context_send_buffer_release(uint32_t handle, uint32_t source, int session, int msg_type, buffer_t& buffer) { message_t msg(source, session, msg_type, buffer); bool ret = context_send(handle, msg); - buffer_release(buffer); + if (!ret) { + buffer_release(buffer); + } return ret; } @@ -65,7 +89,9 @@ class node_lua_t : public singleton_t { { message_t msg(source, session, msg_type, buffer); bool ret = context_send(ctx, msg); - buffer_release(buffer); + if (!ret) { + buffer_release(buffer); + } return ret; } diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 14e1c48..6e196cf 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -345,7 +345,8 @@ void uv_tcp_socket_handle_t::write_read_buffer(ssize_t nread, uv_buf_t buf) void uv_tcp_socket_handle_t::clear_read_cached_buffers() { buffer_release(m_read_buffer); - for (int i = 0; i < m_read_cached_buffers.size(); ++i) { + int size = m_read_cached_buffers.size(); + for (int i = 0; i < size; ++i) { buffer_release(m_read_cached_buffers.front()); m_read_cached_buffers.pop(); } @@ -399,7 +400,8 @@ void uv_tcp_socket_handle_t::read(request_tcp_read_t& request) } else { //non-blocking has started m_has_noblocking_read = true; } - for (int i = 0; i < m_read_cached_buffers.size(); ++i) { + int size = m_read_cached_buffers.size(); + for (int i = 0; i < size; ++i) { singleton_ref(node_lua_t).context_send_buffer_release(m_source, 0, m_lua_ref, RESPONSE_TCP_READ, m_read_cached_buffers.front()); m_read_cached_buffers.pop(); if (m_blocking_read_count > 0) { From 9cd48ede235db7b2c86594d97f3908ff8415a279 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sat, 9 Apr 2016 20:35:24 +0800 Subject: [PATCH 025/173] fix a small thing --- sample/main.lua | 4 +++- src/context_lua.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sample/main.lua b/sample/main.lua index 6bfeed7..73d6460 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -117,7 +117,7 @@ else -- accept_sock:close() -- tcp.write(accept_sock:fd(), "hello world!", function(result, error) print("tcp.write3", result, error) end) end) - for i = 1, 70000 do + for i = 1, 100 do local ret, con_sock = tcp.connect("127.0.0.1", 8801) if ret then connecSockets[#connecSockets+1] = con_sock @@ -143,6 +143,8 @@ else sock:close() end +timer.sleep(100) + do return end diff --git a/src/context_lua.cpp b/src/context_lua.cpp index a5ca140..ff02c92 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -621,14 +621,14 @@ int32_t context_lua_t::wakeup_ref_session(int32_t ref, message_t& message, bool if (blocking || free_callback) { lua_free_ref_session(m_lstate, ref); } - int32_t oldTop = lua_gettop(m_lstate); + int32_t oldTop = lua_gettop(co); lua_checkstack(co, 2); lua_pushboolean(co, !message_is_pure_error(message)); lua_pushmessage(co, message); lua_checkstack(co, 2); lua_pushnumber(co, message.m_source); lua_pushinteger(co, message.m_session); - int32_t newTop = lua_gettop(m_lstate); + int32_t newTop = lua_gettop(co); resume_coroutine(co, newTop - oldTop); return 1; } From a34348f377b88f203e58384aff3bf72fee7773b2 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 10 Apr 2016 00:15:00 +0800 Subject: [PATCH 026/173] fix a little thing --- src/context_lua.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index ff02c92..33d01b5 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -626,7 +626,7 @@ int32_t context_lua_t::wakeup_ref_session(int32_t ref, message_t& message, bool lua_pushboolean(co, !message_is_pure_error(message)); lua_pushmessage(co, message); lua_checkstack(co, 2); - lua_pushnumber(co, message.m_source); + lua_pushinteger(co, message.m_source); lua_pushinteger(co, message.m_session); int32_t newTop = lua_gettop(co); resume_coroutine(co, newTop - oldTop); From d705b166543113ad9b3c03218f3dadcaef8edd73 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 10 Apr 2016 00:50:48 +0800 Subject: [PATCH 027/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dcontext.reply?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 33d01b5..df09700 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -942,6 +942,7 @@ int32_t context_lua_t::context_send(lua_State *L, int32_t idx, uint32_t count, u message_clean(message); return NL_ETRANSTYPE; } + message.m_session = session; if (singleton_ref(node_lua_t).context_send(handle, message)) { return UV_OK; } From 0685ae7d3ad24cee93b63227ee179d19695d5350 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 10 Apr 2016 11:44:38 +0800 Subject: [PATCH 028/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dunix=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E4=B8=8B=E7=9A=84=E7=BC=96=E8=AF=91=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lbson.cpp | 5 +++++ src/utils.cpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/lbson.cpp b/src/lbson.cpp index 8199801..a46bda1 100644 --- a/src/lbson.cpp +++ b/src/lbson.cpp @@ -1,5 +1,10 @@ #include +#define __STDC_LIMIT_MACROS #include "lbson.h" +#ifndef _WIN32 +# include +#endif + #define MAX_NUMBER 1024 // avoid circular reference while encodeing diff --git a/src/utils.cpp b/src/utils.cpp index 1f7a3a4..885cec2 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -51,7 +51,11 @@ extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host sockaddr_in6 sock6; } sock_name; int sock_len = sizeof(sock_name); +#ifdef _WIN32 int result = local ? getsockname(sock, (sockaddr*)&sock_name, &sock_len) : getpeername(sock, (sockaddr*)&sock_name, &sock_len); +#else + int result = local ? getsockname(sock, (sockaddr*)&sock_name, (socklen_t*)&sock_len) : getpeername(sock, (sockaddr*)&sock_name, (socklen_t*)&sock_len); +#endif if (result != 0) return false; uint16_t family = ((sockaddr*)&sock_name)->sa_family; From 0d34e8baae9bd6a447c56dde917d27f9c4842e17 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 10 Apr 2016 17:38:05 +0800 Subject: [PATCH 029/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dmax=20os=E4=B8=8Buv?= =?UTF-8?q?=5F=5F=5Fstream=5Ffd=E7=AC=A6=E5=8F=B7=E9=93=BE=E6=8E=A5?= =?UTF-8?q?=E9=97=AE=E9=A2=98(c=E7=AC=A6=E5=8F=B7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/uv_tcp_handle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 6e196cf..557ad18 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -7,7 +7,7 @@ #if defined (CC_MSVC) #define uv_tcp_fd(handle) ((handle)->socket) #elif defined(__APPLE__) -int uv___stream_fd(uv_stream_t* handle); +extern "C" int uv___stream_fd(uv_stream_t* handle); #define uv_tcp_fd(handle) (uv___stream_fd((uv_stream_t*) (handle))) #else #define uv_tcp_fd(handle) ((handle)->io_watcher.fd) From b8a618fc9eea4dd35570a4ce96de697b1a2d407a Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 10 Apr 2016 17:41:56 +0800 Subject: [PATCH 030/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E4=B9=8B=E9=97=B4=E9=80=9A=E4=BF=A1=E6=B5=8B=E8=AF=95=E4=BE=8B?= =?UTF-8?q?=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/main.lua | 12 ++++++++++-- sample/test.lua | 51 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/sample/main.lua b/sample/main.lua index 73d6460..35529f0 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -72,7 +72,15 @@ print("value", value1, value2)]] --- local handle = context.create("test.lua") +local handle = context.create("sample/test.lua") + +print("main service create sub service:", handle) + +context.send(handle, 1, 2, 3, 4, nil, true, false, "hello", { 1, 2, 3, 4, nil, true, false, ["main"] = 1, }) +context.send(handle, 1, 2, 3, 4, nil, true, false, "hello", { 1, 2, 3, 4, nil, true, false, ["main"] = 1, }) +print("context.query", context.timed_query(handle, 0.5, "hello world")) + +do return end -- print(context.self, context.parent, handle) @@ -143,7 +151,7 @@ else sock:close() end -timer.sleep(100) +--timer.sleep(1) do return end diff --git a/sample/test.lua b/sample/test.lua index ff6bdb9..2f2b1c8 100644 --- a/sample/test.lua +++ b/sample/test.lua @@ -1,22 +1,39 @@ --print(package.path) -print(context.parent) -package.path = package.path .. ";..\\lualib\\?.lua" -package.cpath = package.cpath .. ";..\\clib\\?.dll" +-- print(context.parent) +-- package.path = package.path .. ";..\\lualib\\?.lua" +-- package.cpath = package.cpath .. ";..\\clib\\?.dll" -local redis = require 'redis' -local client = redis.connect("10.4.0.32", 6379, 2) -client:set('usr:nrk', "hello world") -client:set('usr:nobody', 5) -local value1 = client:get('usr:nrk') -local value2 = client:get('usr:nobody') -print("value", value1, value2) +-- local redis = require 'redis' +-- local client = redis.connect("10.4.0.32", 6379, 2) +-- client:set('usr:nrk', "hello world") +-- client:set('usr:nobody', 5) +-- local value1 = client:get('usr:nrk') +-- local value2 = client:get('usr:nobody') +-- print("value", value1, value2) -local http = require 'http' -print(http.request("www.baidu.com")) +-- local http = require 'http' +-- print(http.request("www.baidu.com")) -function gethttpsize(u) - local r, c, h = http.request {method = "HEAD", url = u} - return r, c, h -end +-- function gethttpsize(u) + -- local r, c, h = http.request {method = "HEAD", url = u} + -- return r, c, h +-- end + +-- print(gethttpsize("www.baidu.com")) + +--------------------------------- +print("this is the child service : ", context.self, context.parent) +print("context.recv blocking1: ", context.recv(0)) +print("context.recv blocking2: ", context.recv(0)) +local result = { context.recv(0) } +print("context.recv blocking3: ", unpack(result)) +print("context.reply: ", result[2], result[3]) +--timer.sleep(5) +context.reply(result[2], result[3], 1, 2, 3, "aaaa", { ["hello"] = true, }) + +print("context.recv blocking3: ", context.recv(0)) +context.recv(0, function(result, recv_handle, session, ... ) + print("context.recv noblocking: ", result, recv_handle, session, ...) + end +) -print(gethttpsize("www.baidu.com")) From 45467a709bf58274f2d60fc71202381655324635 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 10 Apr 2016 17:43:28 +0800 Subject: [PATCH 031/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E4=B9=8B=E9=97=B4=E9=80=9A=E4=BF=A1=E6=B5=8B=E8=AF=95=E4=BE=8B?= =?UTF-8?q?=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/main.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/sample/main.lua b/sample/main.lua index 35529f0..35d36d1 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -79,6 +79,7 @@ print("main service create sub service:", handle) context.send(handle, 1, 2, 3, 4, nil, true, false, "hello", { 1, 2, 3, 4, nil, true, false, ["main"] = 1, }) context.send(handle, 1, 2, 3, 4, nil, true, false, "hello", { 1, 2, 3, 4, nil, true, false, ["main"] = 1, }) print("context.query", context.timed_query(handle, 0.5, "hello world")) +context.destroy(handle) do return end From 136184d5fcb4edb947c06f82e2ee7c0abf7ee535 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 11 Apr 2016 14:06:01 +0800 Subject: [PATCH 032/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=85=B1=E4=BA=ABproto(sharedproto)=E7=8E=AF=E5=A2=83=E4=B8=8B?= =?UTF-8?q?,lua=E5=85=B1=E4=BA=AB=E5=86=85=E5=AD=98=E5=9C=A8=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E7=BB=93=E6=9D=9F=E6=97=B6=E6=B2=A1=E6=9C=89=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deps/lua/lauxlib.c | 5 ++--- src/context_lua.cpp | 7 +++++++ src/context_lua.h | 1 + src/node_lua.cpp | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/deps/lua/lauxlib.c b/deps/lua/lauxlib.c index 0915e33..f305417 100644 --- a/deps/lua/lauxlib.c +++ b/deps/lua/lauxlib.c @@ -1190,7 +1190,7 @@ static int luaL_loadfilex_clone (lua_State *L, const char *filename, const char return LUA_OK; } -/* need to wait for all threads to be terminated */ +/* warning: need to wait for all threads to be terminated in muti-thread situation */ LUALIB_API int luaL_closesharedclosure() { int i; shared_lstate_t* sl; @@ -1202,8 +1202,7 @@ LUALIB_API int luaL_closesharedclosure() { lua_close(sl->L); } } - //TO BE FIXED!!! MUTI-THREAD PROBLEM! - printf("shared_lstate_count %ld\n", shared_lstate_count); + //printf("shared_lstate_count %ld\n", shared_lstate_count); return 0; } diff --git a/src/context_lua.cpp b/src/context_lua.cpp index df09700..e6d3dee 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -158,6 +158,13 @@ void context_lua_t::lua_open_libs(lua_State *L) lua_pop(L, 1); /* remove _PRELOAD table */ } +void context_lua_t::unload() +{ +#if defined(LUA_CACHELIB) + luaL_closesharedclosure(); +#endif +} + void context_lua_t::lua_load_env(lua_State *L, char* env[]) { lua_checkstack(L, 3); diff --git a/src/context_lua.h b/src/context_lua.h index e3a17f0..02ec2a7 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -104,6 +104,7 @@ class context_lua_t : public context_t { void response_timeout(message_t& response); public: + static void unload(); static int32_t lua_ref_callback_entry(lua_State *L); /* for lua_ref_callback */ static int32_t lua_ref_callback_entry_continue(lua_State *L, int status, lua_KContext ctx); /* for lua_ref_callback */ static int32_t lua_ref_callback_entry_finish(lua_State *L, int32_t status); diff --git a/src/node_lua.cpp b/src/node_lua.cpp index 82af902..130d40b 100644 --- a/src/node_lua.cpp +++ b/src/node_lua.cpp @@ -40,6 +40,7 @@ node_lua_t::node_lua_t(int argc, char* argv[], char* env[]) m_worker_mgr->wait(); m_network->stop(); m_network->wait(); + context_lua_t::unload(); } node_lua_t::~node_lua_t() From 1231503f10cdc7fdf1f479e862189248dfc37a36 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 11 Apr 2016 15:52:00 +0800 Subject: [PATCH 033/173] nothing --- node-lua.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/node-lua.lua b/node-lua.lua index c0490f1..5ba0f4f 100644 --- a/node-lua.lua +++ b/node-lua.lua @@ -68,6 +68,8 @@ io 阻塞非阻塞? setvbuf {"__tostring", f_tostring}, 热更新 +优化lua shared proto 锁,不使用原子锁? +udp tty 在线调试 warning 编译lua的共享dll库,需要在编译时开启 LUA_BUILD_AS_DLL 这个宏(以便在vc下边下编译时导出符号) (外部模块库需要同时开启 LUA_CORE 这个宏,以便使用 LUAMOD_API 这个宏来导出luaopen接口) warning 使用lua的dll扩展库,需要把lua整个打成dll动态库,主进程和其它扩展库都需要使用动态链接lua库的方式来编译或生成,不然lua的版本校验将不会通过(动态库实际使用lua.dll,编译和链接时使用lua.lib) From 0cc809c568fc75f45e9d0007418484a353311aaf Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 11 Apr 2016 23:22:51 +0800 Subject: [PATCH 034/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/agent.lua | 14 +++++++++++++ sample/client.lua | 18 +++++++++++++++++ sample/gate.lua | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 sample/agent.lua create mode 100644 sample/client.lua create mode 100644 sample/gate.lua diff --git a/sample/agent.lua b/sample/agent.lua new file mode 100644 index 0000000..aeb4db7 --- /dev/null +++ b/sample/agent.lua @@ -0,0 +1,14 @@ + +local fd, write_count = ... +fd = tonumber(fd) +write_count = tonumber(write_count) + +local counter = 0 +context.recv(0, function(result, recv_handle, session, type, data, data2) + counter = counter + 1 + --print("agent["..(context.self).."] recved: ", result, recv_handle, session, type, data, data2) + tcp.write(fd, data) + if counter >= write_count then + context.recv(0, nil) + end +end) diff --git a/sample/client.lua b/sample/client.lua new file mode 100644 index 0000000..55aac93 --- /dev/null +++ b/sample/client.lua @@ -0,0 +1,18 @@ + +local host, port, write_count = ... +write_count = tonumber(write_count) +local result, socket = tcp.connect(host, tonumber(port)) +if result then + socket:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535, }) + for i = 1, write_count do + socket:write("client wrote: "..(context.self).."_"..i) + end + for i = 1, write_count do + local result, data = socket:read() + if result then + --print("client readed "..(context.self).."_"..i .." :", data) + end + end +else + print("tcp.connect connect failed: ", context.strerror(socket)) +end \ No newline at end of file diff --git a/sample/gate.lua b/sample/gate.lua new file mode 100644 index 0000000..a5087cc --- /dev/null +++ b/sample/gate.lua @@ -0,0 +1,51 @@ + +local client_count = 100 +local write_count = 100 +local fd_clents = {} +local agent_clents = {} + +local function socket_read_func(result, buffer, socket) + local fd = socket:fd() + local client = fd_clents[fd] + if not result then + if client then + fd_clents[fd] = nil + agent_clents[client.agent] = nil + context.destroy(client.agent, "socket closed: " .. context.strerror(buffer)) + end + socket:close() + return + end + --print("socket_read_func(result, buffer, socket)", result, buffer, socket) + context.send(client.agent, 1, buffer) +end + +local result, listen_socket = tcp.listen("127.0.0.1", 9901) +if result then + listen_socket:accept(function(result, accept_socket) + if result then + local fd = accept_socket:fd() + accept_socket:set_rwopt({ read_head_endian = "L", read_head_bytes = 2, read_head_max = 65535, write_head_endian = "L", write_head_bytes = 2, write_head_max = 65535, }) + accept_socket:set_wshared(true) + local agent = context.create("sample/agent.lua", fd, write_count) + local client = { fd = fd, agent = agent, addr = accept_socket:remote_addr(), } + fd_clents[fd] = client + agent_clents[agent] = client + accept_socket:read(socket_read_func) + else + print("server accept error: ", context.strerror(accept_socket)) + end + end) + local clients = {} + for i = 1, client_count do --n clients will create n agent + clients[i] = context.create("sample/client.lua", "127.0.0.1", 9901, write_count) + end + for i = 1, #clients do + context.wait(clients[i]) + --print("client "..i .. "waited back!") + end + listen_socket:close() +else + print("server listen error: ", context.strerror(listen_socket)) +end + From d4e70c29d261df683741de0cedc03b63afbcd031 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 12 Apr 2016 00:19:06 +0800 Subject: [PATCH 035/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dfreebsd=E4=B8=8Bdtrac?= =?UTF-8?q?e=E5=8C=85=E5=90=AB=E5=A4=B4=E6=96=87=E4=BB=B6=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 92bfbe2..f2e6bad 100644 --- a/src/Makefile +++ b/src/Makefile @@ -69,10 +69,10 @@ ifeq (openbsd,$(PLATFORM)) LIBS += kvm endif -## here we must include ../deps/uv/unix (include dtrace header file) and declare HAVE_DTRACE macro. +## here we must include ../deps/src/uv/unix (include dtrace header file) and declare HAVE_DTRACE macro. ## otherwise dtrace method will be undefined reference linkage. ifeq ($(HAVE_DTRACE), 1) -INCLUDE_PATH += ../deps/uv/unix +INCLUDE_PATH += ../deps/src/uv/unix CFLAGS += -DHAVE_DTRACE endif From efad8c708662dc4a704a05dc96cabc8c87dbf038 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 12 Apr 2016 00:20:38 +0800 Subject: [PATCH 036/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dfreebsd=E4=B8=8Bdtrac?= =?UTF-8?q?e=E5=8C=85=E5=90=AB=E5=A4=B4=E6=96=87=E4=BB=B6=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index f2e6bad..e38e5b3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -69,10 +69,10 @@ ifeq (openbsd,$(PLATFORM)) LIBS += kvm endif -## here we must include ../deps/src/uv/unix (include dtrace header file) and declare HAVE_DTRACE macro. +## here we must include ../deps/uv/src/unix (include dtrace header file) and declare HAVE_DTRACE macro. ## otherwise dtrace method will be undefined reference linkage. ifeq ($(HAVE_DTRACE), 1) -INCLUDE_PATH += ../deps/src/uv/unix +INCLUDE_PATH += ../deps/uv/src/unix CFLAGS += -DHAVE_DTRACE endif From 0e960a989fc601f8a73e3d151b5db5abcc84f1af Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 13 Apr 2016 00:53:19 +0800 Subject: [PATCH 037/173] =?UTF-8?q?=E5=8F=96=E6=B6=88=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E6=97=B6dtrace=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deps/uv/config-unix.mk | 3 ++- src/Makefile | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deps/uv/config-unix.mk b/deps/uv/config-unix.mk index d230bb2..5b66efb 100644 --- a/deps/uv/config-unix.mk +++ b/deps/uv/config-unix.mk @@ -107,7 +107,8 @@ OBJS += src/unix/linux-core.o \ endif ifeq (freebsd,$(PLATFORM)) -ifeq ($(shell dtrace -l 1>&2 2>/dev/null; echo $$?),0) +# ifeq ($(shell dtrace -l 1>&2 2>/dev/null; echo $$?),0) +ifeq ($(shell dtrace -l >/dev/null; echo $$?),0) #modified by xdczju@sina.com HAVE_DTRACE ?= 1 endif LDFLAGS+=-lkvm diff --git a/src/Makefile b/src/Makefile index e38e5b3..1ff1e43 100644 --- a/src/Makefile +++ b/src/Makefile @@ -51,7 +51,7 @@ LIBS += dl rt endif ifeq (freebsd,$(PLATFORM)) -ifeq ($(shell dtrace -l 1>&2 2>/dev/null; echo $$?),0) +ifeq ($(shell dtrace -l >/dev/null; echo $$?),0) HAVE_DTRACE ?= 1 endif LIBS += kvm pthread From e857e9623959a4f968f2d1f04177a0c735e98963 Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 13 Apr 2016 01:11:12 +0800 Subject: [PATCH 038/173] fix a little thing --- src/request.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/request.h b/src/request.h index 7d98d5a..fee2c8e 100644 --- a/src/request.h +++ b/src/request.h @@ -1,8 +1,7 @@ #ifndef REQUEST_H_ #define REQUEST_H_ -#include "uv.h" -#include "lua.hpp" +#include "common.h" #include "buffer.h" class uv_handle_base_t; From 2e1cccdd3abac8766de16afe7d9fe266a0dd5d7e Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 13 Apr 2016 20:34:01 +0800 Subject: [PATCH 039/173] fix a little thing --- src/request.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/request.h b/src/request.h index 7d98d5a..fee2c8e 100644 --- a/src/request.h +++ b/src/request.h @@ -1,8 +1,7 @@ #ifndef REQUEST_H_ #define REQUEST_H_ -#include "uv.h" -#include "lua.hpp" +#include "common.h" #include "buffer.h" class uv_handle_base_t; From 84ff85d31a4037b7313c60b97f16b85a60ecdcf2 Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 13 Apr 2016 20:40:25 +0800 Subject: [PATCH 040/173] add something --- node-lua.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/node-lua.lua b/node-lua.lua index 5ba0f4f..3ddf31c 100644 --- a/node-lua.lua +++ b/node-lua.lua @@ -71,6 +71,11 @@ io 阻塞非阻塞? setvbuf 优化lua shared proto 锁,不使用原子锁? udp tty 在线调试 +freebsd: +1. pkg 命令安装软件 pkg安装pkg自身 pkg install +2. sshd 服务器配置 /etc/ssh/sshd_config : PermitRootLogin yes +3. make 和 其它操作系统不一样,需要安装gmake + warning 编译lua的共享dll库,需要在编译时开启 LUA_BUILD_AS_DLL 这个宏(以便在vc下边下编译时导出符号) (外部模块库需要同时开启 LUA_CORE 这个宏,以便使用 LUAMOD_API 这个宏来导出luaopen接口) warning 使用lua的dll扩展库,需要把lua整个打成dll动态库,主进程和其它扩展库都需要使用动态链接lua库的方式来编译或生成,不然lua的版本校验将不会通过(动态库实际使用lua.dll,编译和链接时使用lua.lib) 如果是静态库,那么每个模块加载该静态库后,每个模块都分别有一个拷贝。如果是动态库,每个模块加载该动态库后,都只有一个拷贝。 From 67657b14988c8deb9ee072f589a16f24d0ca24ce Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 00:44:45 +0800 Subject: [PATCH 041/173] =?UTF-8?q?=E7=A6=81=E7=94=A8dtrace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 4 ++-- src/Makefile | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f27fc49..929dac5 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ ROOT_PATH = $(shell pwd) define MAKE_PLATFORM ##main essential builds cd deps/lua && make $(2); cd $(ROOT_PATH) - cd deps/uv && make PLATFORM=$(1); rm -f libuv.so libuv.dylib; cd $(ROOT_PATH) - cd src && make PLATFORM=$(1) RELEASE=$(3); cd $(ROOT_PATH) + cd deps/uv && make PLATFORM=$(1) HAVE_DTRACE=0; rm -f libuv.so libuv.dylib; cd $(ROOT_PATH) + cd src && make PLATFORM=$(1) HAVE_DTRACE=0 RELEASE=$(3); cd $(ROOT_PATH) ##not essential builds cd clib/mime && make PLATFORM=$(1) RELEASE=$(3); cd $(ROOT_PATH) endef diff --git a/src/Makefile b/src/Makefile index 1ff1e43..0b8120d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -69,8 +69,7 @@ ifeq (openbsd,$(PLATFORM)) LIBS += kvm endif -## here we must include ../deps/uv/src/unix (include dtrace header file) and declare HAVE_DTRACE macro. -## otherwise dtrace method will be undefined reference linkage. +## !!! HAVE_DTRACE not supported(undefined reference to `__dtrace_uv___tick__start' & undefined reference to `__dtrace_uv___tick__stop') ifeq ($(HAVE_DTRACE), 1) INCLUDE_PATH += ../deps/uv/src/unix CFLAGS += -DHAVE_DTRACE From 32e2a412e23fdab8e219321eedc2c364a577a839 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 00:55:16 +0800 Subject: [PATCH 042/173] =?UTF-8?q?=E7=A6=81=E7=94=A8dtrace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 929dac5..c03fa24 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ ROOT_PATH = $(shell pwd) define MAKE_PLATFORM ##main essential builds + ##disable dtrace cd deps/lua && make $(2); cd $(ROOT_PATH) cd deps/uv && make PLATFORM=$(1) HAVE_DTRACE=0; rm -f libuv.so libuv.dylib; cd $(ROOT_PATH) cd src && make PLATFORM=$(1) HAVE_DTRACE=0 RELEASE=$(3); cd $(ROOT_PATH) From 7fda596f6521e662e6ec80ef5f7c5092697f909a Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 18:54:08 +0800 Subject: [PATCH 043/173] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 94 +++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index d8ec25b..929c005 100644 --- a/README.md +++ b/README.md @@ -8,82 +8,82 @@ 5. A context starts with a lua file as the entry. The process will exit automaticly when all contexts ends or terminates and a context will exit automaticly when all its running and suspending sync and async remote procedure call ends or terminates. 6. A optimized task scheduling is used with a thread based context queue which reduces the thread race condition and work-stealing algorithm is used in the task scheduling. 7. A more friendly tcp api is embeded in this engine with sync and async implementation which is much more convenient to build a tcp server. +8. A shared buffer api is much more efficient for sending a broadcast packet. ## build & install -For windows, just open node-lua.sln and build the whole solution. For linux or other unix-like system -``` -git clone https://github.com/socoding/node-lua.git -cd node-lua -make && make install -make release && make install -``` +For windows, just open node-lua.sln and build the whole solution. For linux or other unix-like system where centos, macos, freebsd and ubuntu has been successfully supported and tested, run the flowing shell scripts: + + git clone https://github.com/socoding/node-lua.git + cd node-lua + make [release] #add release to build for release versions + make install ## usefull api ### tcp api -1. result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) - --listen_callback is a once callback, blocking if callback is nil. +1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` + *`--listen_callback is a once callback, blocking if callback is nil.`* -2. result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)]) - --listen_callback is a once callback, blocking if callback is nil. +2. `result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)])` + *`--listen_callback is a once callback, blocking if callback is nil.`* -3. result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) - --listen_callback is a once callback, blocking if callback is nil. +3. `result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` + *`--listen_callback is a once callback, blocking if callback is nil.`* -4. result, accept_socket = tcp.accept(listen_socket[, timeout]) - --accept_callback is a continues callback, blocking if callback is nil. +4. `result, accept_socket = tcp.accept(listen_socket[, timeout])` + *`--accept_callback is a continues callback, blocking if callback is nil.`* -5. result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)]) - --accept_callback is a continues callback, blocking if callback is nil. +5. `result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)])` + *`--accept_callback is a continues callback, blocking if callback is nil.`* -6. result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]]) - --connect_callback is a once callback, blocking if callback is nil. +6. `result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` + *`--connect_callback is a once callback, blocking if callback is nil.`* -7. result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]]) - --connect_callback is a once callback, blocking if callback is nil. +7. `result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` + *`--connect_callback is a once callback, blocking if callback is nil.`* -8. result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]]) - --connect_callback is a once callback, blocking if callback is nil. +8. `result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` + *`--connect_callback is a once callback, blocking if callback is nil.`* -9. result, buffer = tcp.read(socket[, timeout]) - --recv_callback is a continues callback, blocking if callback is nil. +9. `result, buffer = tcp.read(socket[, timeout])` + *`--recv_callback is a continues callback, blocking if callback is nil.`* -10. result, buffer = tcp.read(socket[, recv_callback(result, buffer, socket)]) - --recv_callback is a continues callback, blocking if callback is nil. +10. `result, buffer = tcp.read(socket[, recv_callback(result, buffer, socket)])` + *`--recv_callback is a continues callback, blocking if callback is nil.`* -11. result, error = tcp.write(socket, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety]) - --send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true. +11. `result, error = tcp.write(socket, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` + *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* -12. tcp.set_rwopt(socket, option_table) - --set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, } +12. `tcp.set_rwopt(socket, option_table)` + *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* -13. option_table = tcp.get_rwopt(socket) - --get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, } +13. `option_table = tcp.get_rwopt(socket)` + *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* -14. tcp.set_nodelay(socket, enable) +14. `tcp.set_nodelay(socket, enable)` ### context api -1. result, error = context.send(handle, data) --QUERY +1. `result, error = context.send(handle, data) --QUERY` -2. result, query_data = context.query(handle, data[, timeout [, query_callback(result, query_data, handle, data[, timeout])]]) --QUERY(real query) - --query_callback is a once callback, blocking if callback is nil. +2. `result, query_data = context.query(handle, data[, timeout [, query_callback(result, query_data, handle, data[, timeout])]]) --QUERY(real query)` + *`--query_callback is a once callback, blocking if callback is nil.`* -3. result, error = context.reply(handle, session, data) --REPLY +3. `result, error = context.reply(handle, session, data) --REPLY` -4. result, data, recv_handle, session = context.recv(handle[, timeout]) - --recv_callback is a continues callback, blocking if callback is nil. +4. `result, data, recv_handle, session = context.recv(handle[, timeout])` + *`--recv_callback is a continues callback, blocking if callback is nil.`* -5. result, data, recv_handle, session = context.recv(handle[, recv_callback(result, data, recv_handle, session, handle)]) - --recv_callback is a continues callback, blocking if callback is nil. +5. `result, data, recv_handle, session = context.recv(handle[, recv_callback(result, data, recv_handle, session, handle)])` + *`--recv_callback is a continues callback, blocking if callback is nil.`* -6. result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]]) - --connect_callback is a once callback, blocking if callback is nil. +6. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` + *`--connect_callback is a once callback, blocking if callback is nil.`* ### timer api -1. timer.sleep(seconds) +1. `timer.sleep(seconds)` -2. timer.timeout(seconds, ..., callback(...)) +2. `timer.timeout(seconds, ..., callback(...))` -3. timer.loop(interval, repeat_time, ..., callback(...)) +3. `timer.loop(interval, repeat_time, ..., callback(...))` ### buffer api From 9b73732cbc2cb37d8deda1d78a0286569029e8cb Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 18:57:01 +0800 Subject: [PATCH 044/173] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 929c005..cb0617a 100644 --- a/README.md +++ b/README.md @@ -22,43 +22,43 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o ## usefull api ### tcp api 1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` - *`--listen_callback is a once callback, blocking if callback is nil.`* + *`--listen_callback is a once callback, blocking if callback is nil.`* 2. `result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)])` - *`--listen_callback is a once callback, blocking if callback is nil.`* + *`--listen_callback is a once callback, blocking if callback is nil.`* 3. `result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` - *`--listen_callback is a once callback, blocking if callback is nil.`* + *`--listen_callback is a once callback, blocking if callback is nil.`* 4. `result, accept_socket = tcp.accept(listen_socket[, timeout])` - *`--accept_callback is a continues callback, blocking if callback is nil.`* + *`--accept_callback is a continues callback, blocking if callback is nil.`* 5. `result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)])` - *`--accept_callback is a continues callback, blocking if callback is nil.`* + *`--accept_callback is a continues callback, blocking if callback is nil.`* 6. `result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` - *`--connect_callback is a once callback, blocking if callback is nil.`* + *`--connect_callback is a once callback, blocking if callback is nil.`* 7. `result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` - *`--connect_callback is a once callback, blocking if callback is nil.`* + *`--connect_callback is a once callback, blocking if callback is nil.`* 8. `result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` - *`--connect_callback is a once callback, blocking if callback is nil.`* + *`--connect_callback is a once callback, blocking if callback is nil.`* 9. `result, buffer = tcp.read(socket[, timeout])` - *`--recv_callback is a continues callback, blocking if callback is nil.`* + *`--recv_callback is a continues callback, blocking if callback is nil.`* 10. `result, buffer = tcp.read(socket[, recv_callback(result, buffer, socket)])` - *`--recv_callback is a continues callback, blocking if callback is nil.`* + *`--recv_callback is a continues callback, blocking if callback is nil.`* 11. `result, error = tcp.write(socket, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` - *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* + *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* 12. `tcp.set_rwopt(socket, option_table)` - *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* + *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* 13. `option_table = tcp.get_rwopt(socket)` - *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* + *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* 14. `tcp.set_nodelay(socket, enable)` @@ -66,18 +66,18 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 1. `result, error = context.send(handle, data) --QUERY` 2. `result, query_data = context.query(handle, data[, timeout [, query_callback(result, query_data, handle, data[, timeout])]]) --QUERY(real query)` - *`--query_callback is a once callback, blocking if callback is nil.`* + *`--query_callback is a once callback, blocking if callback is nil.`* 3. `result, error = context.reply(handle, session, data) --REPLY` 4. `result, data, recv_handle, session = context.recv(handle[, timeout])` - *`--recv_callback is a continues callback, blocking if callback is nil.`* + *`--recv_callback is a continues callback, blocking if callback is nil.`* 5. `result, data, recv_handle, session = context.recv(handle[, recv_callback(result, data, recv_handle, session, handle)])` - *`--recv_callback is a continues callback, blocking if callback is nil.`* + *`--recv_callback is a continues callback, blocking if callback is nil.`* 6. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` - *`--connect_callback is a once callback, blocking if callback is nil.`* + *`--connect_callback is a once callback, blocking if callback is nil.`* ### timer api 1. `timer.sleep(seconds)` From 12eb878aec194c96a8b5887e2b627dcecf5d7315 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 20:27:04 +0800 Subject: [PATCH 045/173] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index cb0617a..7f30ca3 100644 --- a/README.md +++ b/README.md @@ -21,69 +21,69 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o ## usefull api ### tcp api -1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` +1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` *`--listen_callback is a once callback, blocking if callback is nil.`* -2. `result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)])` +2. `result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)])` *`--listen_callback is a once callback, blocking if callback is nil.`* -3. `result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` +3. `result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` *`--listen_callback is a once callback, blocking if callback is nil.`* -4. `result, accept_socket = tcp.accept(listen_socket[, timeout])` +4. `result, accept_socket = tcp.accept(listen_socket[, timeout])` *`--accept_callback is a continues callback, blocking if callback is nil.`* -5. `result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)])` +5. `result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)])` *`--accept_callback is a continues callback, blocking if callback is nil.`* -6. `result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` +6. `result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` *`--connect_callback is a once callback, blocking if callback is nil.`* -7. `result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` +7. `result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` *`--connect_callback is a once callback, blocking if callback is nil.`* -8. `result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` +8. `result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` *`--connect_callback is a once callback, blocking if callback is nil.`* -9. `result, buffer = tcp.read(socket[, timeout])` +9. `result, buffer = tcp.read(socket[, timeout])` *`--recv_callback is a continues callback, blocking if callback is nil.`* -10. `result, buffer = tcp.read(socket[, recv_callback(result, buffer, socket)])` +10. `result, buffer = tcp.read(socket[, recv_callback(result, buffer, socket)])` *`--recv_callback is a continues callback, blocking if callback is nil.`* -11. `result, error = tcp.write(socket, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` +11. `result, error = tcp.write(socket, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* -12. `tcp.set_rwopt(socket, option_table)` +12. `tcp.set_rwopt(socket, option_table)` *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* -13. `option_table = tcp.get_rwopt(socket)` +13. `option_table = tcp.get_rwopt(socket)` *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* -14. `tcp.set_nodelay(socket, enable)` +14. `tcp.set_nodelay(socket, enable)` ### context api -1. `result, error = context.send(handle, data) --QUERY` +1. `result, error = context.send(handle, data) --QUERY` -2. `result, query_data = context.query(handle, data[, timeout [, query_callback(result, query_data, handle, data[, timeout])]]) --QUERY(real query)` +2. `result, query_data = context.query(handle, data[, timeout [, query_callback(result, query_data, handle, data[, timeout])]]) --QUERY(real query)` *`--query_callback is a once callback, blocking if callback is nil.`* -3. `result, error = context.reply(handle, session, data) --REPLY` +3. `result, error = context.reply(handle, session, data) --REPLY` -4. `result, data, recv_handle, session = context.recv(handle[, timeout])` +4. `result, data, recv_handle, session = context.recv(handle[, timeout])` *`--recv_callback is a continues callback, blocking if callback is nil.`* -5. `result, data, recv_handle, session = context.recv(handle[, recv_callback(result, data, recv_handle, session, handle)])` +5. `result, data, recv_handle, session = context.recv(handle[, recv_callback(result, data, recv_handle, session, handle)])` *`--recv_callback is a continues callback, blocking if callback is nil.`* -6. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` +6. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` *`--connect_callback is a once callback, blocking if callback is nil.`* ### timer api -1. `timer.sleep(seconds)` +1. `timer.sleep(seconds)` -2. `timer.timeout(seconds, ..., callback(...))` +2. `timer.timeout(seconds, ..., callback(...))` -3. `timer.loop(interval, repeat_time, ..., callback(...))` +3. `timer.loop(interval, repeat_time, ..., callback(...))` ### buffer api From 4ec0fe5e3fbae48e08fe89f1ab5a71140faaf74a Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 21:11:20 +0800 Subject: [PATCH 046/173] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7f30ca3..f356f3b 100644 --- a/README.md +++ b/README.md @@ -21,17 +21,20 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o ## usefull api ### tcp api -1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` +1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` + *`--listen on a ipv4 address.`* *`--listen_callback is a once callback, blocking if callback is nil.`* 2. `result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)])` + *`--listen on a windows named pipe or unix domain socket.`* *`--listen_callback is a once callback, blocking if callback is nil.`* 3. `result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` + *`--listen on a ipv6 address.`* *`--listen_callback is a once callback, blocking if callback is nil.`* 4. `result, accept_socket = tcp.accept(listen_socket[, timeout])` - *`--accept_callback is a continues callback, blocking if callback is nil.`* + *`--accept on a listen socket in blocking mode, timeout is activated if timeout is set.`* 5. `result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)])` *`--accept_callback is a continues callback, blocking if callback is nil.`* @@ -40,6 +43,7 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--connect_callback is a once callback, blocking if callback is nil.`* 7. `result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` + *`--connects to a windows named pipe or unix domain socket.`* *`--connect_callback is a once callback, blocking if callback is nil.`* 8. `result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` @@ -51,19 +55,45 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 10. `result, buffer = tcp.read(socket[, recv_callback(result, buffer, socket)])` *`--recv_callback is a continues callback, blocking if callback is nil.`* -11. `result, error = tcp.write(socket, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` +11. `result, error = tcp.write(socket/fd, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` + *`--write a tcp socket or directly on a tcp fd(tcp.fd()) where the socket must enable shared write in advance.`* *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* 12. `tcp.set_rwopt(socket, option_table)` - *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* + *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* 13. `option_table = tcp.get_rwopt(socket)` - *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, }`* + *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* 14. `tcp.set_nodelay(socket, enable)` + *`--change tcp socket write 'nodelay' option. Enable nodelay if 'enable' is true or disable it if 'enable' is false.`* + +15. `tcp.set_wshared(socket, enable)` + *`--change tcp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false. tcp.set_rwopt will be choked or invalid if write shared is enabled. So if you want to call both tcp.set_wshared and tcp.set_rwopt, call tcp.set_rwopt first!`* + +16. `tcp.local_addr(socket)` + *`socket can't be a listen socket`* + +17. `tcp.remote_addr(socket)` + *`socket can't be a listen socket`* + +18. `tcp.local_port(socket)` + *`socket can't be a listen socket`* + +19. `tcp.remote_port(socket)` + *`socket can't be a listen socket`* + +20. `tcp.close(socket)` + *`close the tcp socket directly`* + +21. `tcp.is_closed(socket)` + *`check whether the tcp socket is closed`* + +22. `tcp.fd(socket)` + *`get tcp socket lua fd`* ### context api -1. `result, error = context.send(handle, data) --QUERY` +1. `result, error = context.send(handle, data1[,data2[, ...]])` 2. `result, query_data = context.query(handle, data[, timeout [, query_callback(result, query_data, handle, data[, timeout])]]) --QUERY(real query)` *`--query_callback is a once callback, blocking if callback is nil.`* From 291ebc6df440419042fb90eaa8846b96c1c99295 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 21:14:37 +0800 Subject: [PATCH 047/173] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f356f3b..6e11608 100644 --- a/README.md +++ b/README.md @@ -72,25 +72,25 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--change tcp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false. tcp.set_rwopt will be choked or invalid if write shared is enabled. So if you want to call both tcp.set_wshared and tcp.set_rwopt, call tcp.set_rwopt first!`* 16. `tcp.local_addr(socket)` - *`socket can't be a listen socket`* + *`--socket can't be a listen socket`* 17. `tcp.remote_addr(socket)` - *`socket can't be a listen socket`* + *`--socket can't be a listen socket`* 18. `tcp.local_port(socket)` - *`socket can't be a listen socket`* + *`--socket can't be a listen socket`* 19. `tcp.remote_port(socket)` - *`socket can't be a listen socket`* + *`--socket can't be a listen socket`* 20. `tcp.close(socket)` - *`close the tcp socket directly`* + *`--close the tcp socket directly`* 21. `tcp.is_closed(socket)` - *`check whether the tcp socket is closed`* + *`--check whether the tcp socket is closed`* 22. `tcp.fd(socket)` - *`get tcp socket lua fd`* + *`--get tcp socket lua fd`* ### context api 1. `result, error = context.send(handle, data1[,data2[, ...]])` From d3cb832e6d781d38d655109902244a155a80a516 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 23:51:27 +0800 Subject: [PATCH 048/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 98 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 6e11608..6874395 100644 --- a/README.md +++ b/README.md @@ -23,47 +23,46 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o ### tcp api 1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` *`--listen on a ipv4 address.`* - *`--listen_callback is a once callback, blocking if callback is nil.`* + *`--listen_callback is a once callback, blocking if listen_callback is nil.`* 2. `result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)])` *`--listen on a windows named pipe or unix domain socket.`* - *`--listen_callback is a once callback, blocking if callback is nil.`* + *`--listen_callback is a once callback, blocking if listen_callback is nil.`* 3. `result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` *`--listen on a ipv6 address.`* - *`--listen_callback is a once callback, blocking if callback is nil.`* + *`--listen_callback is a once callback, blocking if listen_callback is nil.`* 4. `result, accept_socket = tcp.accept(listen_socket[, timeout])` *`--accept on a listen socket in blocking mode, timeout is activated if timeout is set.`* 5. `result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)])` - *`--accept_callback is a continues callback, blocking if callback is nil.`* + *`--accept_callback is a continues callback, blocking if accept_callback is nil.`* 6. `result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` - *`--connect_callback is a once callback, blocking if callback is nil.`* + *`--connect_callback is a once callback, blocking if connect_callback is nil.`* 7. `result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` *`--connects to a windows named pipe or unix domain socket.`* - *`--connect_callback is a once callback, blocking if callback is nil.`* + *`--connect_callback is a once callback, blocking if connect_callback is nil.`* 8. `result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` - *`--connect_callback is a once callback, blocking if callback is nil.`* + *`--connect_callback is a once callback, blocking if connect_callback is nil.`* 9. `result, buffer = tcp.read(socket[, timeout])` - *`--recv_callback is a continues callback, blocking if callback is nil.`* -10. `result, buffer = tcp.read(socket[, recv_callback(result, buffer, socket)])` - *`--recv_callback is a continues callback, blocking if callback is nil.`* +10. `result, buffer = tcp.read(socket[, read_callback(result, buffer, socket)])` + *`--read_callback is a continues callback, blocking if read_callback is nil.`* 11. `result, error = tcp.write(socket/fd, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` *`--write a tcp socket or directly on a tcp fd(tcp.fd()) where the socket must enable shared write in advance.`* *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* 12. `tcp.set_rwopt(socket, option_table)` - *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* + *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* 13. `option_table = tcp.get_rwopt(socket)` - *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* + *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* 14. `tcp.set_nodelay(socket, enable)` *`--change tcp socket write 'nodelay' option. Enable nodelay if 'enable' is true or disable it if 'enable' is false.`* @@ -71,49 +70,84 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 15. `tcp.set_wshared(socket, enable)` *`--change tcp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false. tcp.set_rwopt will be choked or invalid if write shared is enabled. So if you want to call both tcp.set_wshared and tcp.set_rwopt, call tcp.set_rwopt first!`* -16. `tcp.local_addr(socket)` - *`--socket can't be a listen socket`* +16. `local_addr = tcp.local_addr(socket)` + *`--socket can't be a listen socket.`* -17. `tcp.remote_addr(socket)` - *`--socket can't be a listen socket`* +17. `remote_addr = tcp.remote_addr(socket)` + *`--socket can't be a listen socket.`* -18. `tcp.local_port(socket)` +18. `local_port = tcp.local_port(socket)` *`--socket can't be a listen socket`* -19. `tcp.remote_port(socket)` - *`--socket can't be a listen socket`* +19. `remote_port = tcp.remote_port(socket)` + *`--socket can't be a listen socket.`* 20. `tcp.close(socket)` - *`--close the tcp socket directly`* + *`--close the tcp socket directly.`* -21. `tcp.is_closed(socket)` - *`--check whether the tcp socket is closed`* +21. `is_closed = tcp.is_closed(socket)` + *`--check whether the tcp socket is closed.`* -22. `tcp.fd(socket)` +22. `fd = tcp.fd(socket)` *`--get tcp socket lua fd`* ### context api -1. `result, error = context.send(handle, data1[,data2[, ...]])` +1. `result, error = context.send(handle, data1[, ...])` + *`--send data1, data2, ... directy to context specified by handle noblocking.`* -2. `result, query_data = context.query(handle, data[, timeout [, query_callback(result, query_data, handle, data[, timeout])]]) --QUERY(real query)` - *`--query_callback is a once callback, blocking if callback is nil.`* +2. `result, query_data1, ... = context.query(handle, data1[, ... [, query_callback(result, query_data1[, ...])]])` + *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* + *`--query_callback is a once callback, blocking if query_callback is nil.`* + +3. `result, query_data1, ... = context.timed_query(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]])` + *`--query context specified by handle with data1, data2, ... in timeout seconds`* + *`--query_callback is a once callback, blocking if query_callback is nil.`* -3. `result, error = context.reply(handle, session, data) --REPLY` +4. `result, error = context.reply(handle, session, data1[, ...])` + *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* -4. `result, data, recv_handle, session = context.recv(handle[, timeout])` - *`--recv_callback is a continues callback, blocking if callback is nil.`* +5. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, timeout])` + *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* + *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* -5. `result, data, recv_handle, session = context.recv(handle[, recv_callback(result, data, recv_handle, session, handle)])` - *`--recv_callback is a continues callback, blocking if callback is nil.`* +5. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)])` + *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* + *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* + *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* 6. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` - *`--connect_callback is a once callback, blocking if callback is nil.`* + *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* + *`--callback is a once callback, blocking if callback is nil.`* + +7. `error = context.strerror(errno)` + *`--convert error number to error string. Error number is always the next argument after **result** in most apis.`* + +8. `handle = context.create(file_name[, arg1[, ...]])` + *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* + +9. `handle = context.destroy([handle[, message]])` + *`--destroy a context specified by handle with a string message. You'll kill the context itself if handle is nil and message is a optional argument.`* + +10. `thread = context.thread()` + *`--return the running thread index.`* + +11. `context.winos` + *`--whether the running system is windows.`* + +12. `context.self` + *`--the running context id.`* + +13. `context.parent` + *`--the running context parent id.`* ### timer api 1. `timer.sleep(seconds)` + *`--blocking for seconds.`* 2. `timer.timeout(seconds, ..., callback(...))` + *`--make a tiimeout callback in seconds.`* 3. `timer.loop(interval, repeat_time, ..., callback(...))` + *`--make a repeated callback. The first time callback will be triggered in interval seconds and then repeated in repeat_time`* ### buffer api From 4ca5f03f969001bbf11c395373dfcb63f4d8abd4 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 23:53:12 +0800 Subject: [PATCH 049/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6874395..0d96f96 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--callback is a once callback, blocking if callback is nil.`* 7. `error = context.strerror(errno)` - *`--convert error number to error string. Error number is always the next argument after **result** in most apis.`* + *`--convert error number to error string. Error number is always the next argument after result in most apis.`* 8. `handle = context.create(file_name[, arg1[, ...]])` *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* From a4f589bfab9c62f0773f64ffe26c14e98b4c6479 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 23:54:48 +0800 Subject: [PATCH 050/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0d96f96..a0dc294 100644 --- a/README.md +++ b/README.md @@ -107,16 +107,16 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* 5. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, timeout])` - *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* + *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* 5. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)])` - *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* - *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* - *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* + *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* + *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* + *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* 6. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` - *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* + *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* *`--callback is a once callback, blocking if callback is nil.`* 7. `error = context.strerror(errno)` From 492e5b2d0b39ac0eaf37ee3764be1e6ae1dd0419 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 14 Apr 2016 23:56:05 +0800 Subject: [PATCH 051/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a0dc294..836187b 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--read_callback is a continues callback, blocking if read_callback is nil.`* 11. `result, error = tcp.write(socket/fd, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` - *`--write a tcp socket or directly on a tcp fd(tcp.fd()) where the socket must enable shared write in advance.`* + *`--write a tcp socket or directly on a tcp fd(tcp.fd()) where the socket must enable shared write in advance.`* *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* 12. `tcp.set_rwopt(socket, option_table)` @@ -96,7 +96,7 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--send data1, data2, ... directy to context specified by handle noblocking.`* 2. `result, query_data1, ... = context.query(handle, data1[, ... [, query_callback(result, query_data1[, ...])]])` - *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* + *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* *`--query_callback is a once callback, blocking if query_callback is nil.`* 3. `result, query_data1, ... = context.timed_query(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]])` From e994b702e890775c0cfc21610b1fc3e9e993ebb5 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 15 Apr 2016 00:00:23 +0800 Subject: [PATCH 052/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 104 +++++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 836187b..0a2e7ca 100644 --- a/README.md +++ b/README.md @@ -21,133 +21,133 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o ## usefull api ### tcp api -1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` - *`--listen on a ipv4 address.`* - *`--listen_callback is a once callback, blocking if listen_callback is nil.`* +1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` + *`--listen on a ipv4 address.`* + *`--listen_callback is a once callback, blocking if listen_callback is nil.`* 2. `result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)])` - *`--listen on a windows named pipe or unix domain socket.`* - *`--listen_callback is a once callback, blocking if listen_callback is nil.`* + *`--listen on a windows named pipe or unix domain socket.`* + *`--listen_callback is a once callback, blocking if listen_callback is nil.`* 3. `result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` - *`--listen on a ipv6 address.`* - *`--listen_callback is a once callback, blocking if listen_callback is nil.`* + *`--listen on a ipv6 address.`* + *`--listen_callback is a once callback, blocking if listen_callback is nil.`* 4. `result, accept_socket = tcp.accept(listen_socket[, timeout])` - *`--accept on a listen socket in blocking mode, timeout is activated if timeout is set.`* + *`--accept on a listen socket in blocking mode, timeout is activated if timeout is set.`* 5. `result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)])` - *`--accept_callback is a continues callback, blocking if accept_callback is nil.`* + *`--accept_callback is a continues callback, blocking if accept_callback is nil.`* 6. `result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` - *`--connect_callback is a once callback, blocking if connect_callback is nil.`* + *`--connect_callback is a once callback, blocking if connect_callback is nil.`* 7. `result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` - *`--connects to a windows named pipe or unix domain socket.`* - *`--connect_callback is a once callback, blocking if connect_callback is nil.`* + *`--connects to a windows named pipe or unix domain socket.`* + *`--connect_callback is a once callback, blocking if connect_callback is nil.`* 8. `result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` - *`--connect_callback is a once callback, blocking if connect_callback is nil.`* + *`--connect_callback is a once callback, blocking if connect_callback is nil.`* 9. `result, buffer = tcp.read(socket[, timeout])` 10. `result, buffer = tcp.read(socket[, read_callback(result, buffer, socket)])` - *`--read_callback is a continues callback, blocking if read_callback is nil.`* + *`--read_callback is a continues callback, blocking if read_callback is nil.`* 11. `result, error = tcp.write(socket/fd, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` *`--write a tcp socket or directly on a tcp fd(tcp.fd()) where the socket must enable shared write in advance.`* - *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* + *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* 12. `tcp.set_rwopt(socket, option_table)` - *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* + *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* 13. `option_table = tcp.get_rwopt(socket)` - *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* + *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* 14. `tcp.set_nodelay(socket, enable)` - *`--change tcp socket write 'nodelay' option. Enable nodelay if 'enable' is true or disable it if 'enable' is false.`* + *`--change tcp socket write 'nodelay' option. Enable nodelay if 'enable' is true or disable it if 'enable' is false.`* 15. `tcp.set_wshared(socket, enable)` - *`--change tcp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false. tcp.set_rwopt will be choked or invalid if write shared is enabled. So if you want to call both tcp.set_wshared and tcp.set_rwopt, call tcp.set_rwopt first!`* + *`--change tcp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false. tcp.set_rwopt will be choked or invalid if write shared is enabled. So if you want to call both tcp.set_wshared and tcp.set_rwopt, call tcp.set_rwopt first!`* 16. `local_addr = tcp.local_addr(socket)` - *`--socket can't be a listen socket.`* + *`--socket can't be a listen socket.`* 17. `remote_addr = tcp.remote_addr(socket)` - *`--socket can't be a listen socket.`* + *`--socket can't be a listen socket.`* 18. `local_port = tcp.local_port(socket)` - *`--socket can't be a listen socket`* + *`--socket can't be a listen socket`* 19. `remote_port = tcp.remote_port(socket)` - *`--socket can't be a listen socket.`* + *`--socket can't be a listen socket.`* 20. `tcp.close(socket)` - *`--close the tcp socket directly.`* + *`--close the tcp socket directly.`* 21. `is_closed = tcp.is_closed(socket)` - *`--check whether the tcp socket is closed.`* + *`--check whether the tcp socket is closed.`* 22. `fd = tcp.fd(socket)` - *`--get tcp socket lua fd`* + *`--get tcp socket lua fd`* ### context api 1. `result, error = context.send(handle, data1[, ...])` - *`--send data1, data2, ... directy to context specified by handle noblocking.`* + *`--send data1, data2, ... directy to context specified by handle noblocking.`* 2. `result, query_data1, ... = context.query(handle, data1[, ... [, query_callback(result, query_data1[, ...])]])` *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* - *`--query_callback is a once callback, blocking if query_callback is nil.`* + *`--query_callback is a once callback, blocking if query_callback is nil.`* 3. `result, query_data1, ... = context.timed_query(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]])` - *`--query context specified by handle with data1, data2, ... in timeout seconds`* - *`--query_callback is a once callback, blocking if query_callback is nil.`* + *`--query context specified by handle with data1, data2, ... in timeout seconds`* + *`--query_callback is a once callback, blocking if query_callback is nil.`* 4. `result, error = context.reply(handle, session, data1[, ...])` - *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* + *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* 5. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, timeout])` *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* - *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* + *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* -5. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)])` +6. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)])` *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* -6. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` +7. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* - *`--callback is a once callback, blocking if callback is nil.`* + *`--callback is a once callback, blocking if callback is nil.`* -7. `error = context.strerror(errno)` - *`--convert error number to error string. Error number is always the next argument after result in most apis.`* +8. `error = context.strerror(errno)` + *`--convert error number to error string. Error number is always the next argument after result in most apis.`* -8. `handle = context.create(file_name[, arg1[, ...]])` - *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* +9. `handle = context.create(file_name[, arg1[, ...]])` + *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* -9. `handle = context.destroy([handle[, message]])` - *`--destroy a context specified by handle with a string message. You'll kill the context itself if handle is nil and message is a optional argument.`* +10. `handle = context.destroy([handle[, message]])` + *`--destroy a context specified by handle with a string message. You'll kill the context itself if handle is nil and message is a optional argument.`* -10. `thread = context.thread()` - *`--return the running thread index.`* +11. `thread = context.thread()` + *`--return the running thread index.`* -11. `context.winos` - *`--whether the running system is windows.`* +12. `context.winos` + *`--whether the running system is windows.`* -12. `context.self` - *`--the running context id.`* +13. `context.self` + *`--the running context id.`* -13. `context.parent` - *`--the running context parent id.`* +14. `context.parent` + *`--the running context parent id.`* ### timer api 1. `timer.sleep(seconds)` - *`--blocking for seconds.`* + *`--blocking for seconds.`* 2. `timer.timeout(seconds, ..., callback(...))` - *`--make a tiimeout callback in seconds.`* + *`--make a tiimeout callback in seconds.`* 3. `timer.loop(interval, repeat_time, ..., callback(...))` - *`--make a repeated callback. The first time callback will be triggered in interval seconds and then repeated in repeat_time`* + *`--make a repeated callback. The first time callback will be triggered in interval seconds and then repeated in repeat_time`* ### buffer api From 8f87f7a8eb27e0eff899e9da770dc14cea79a5a7 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 15 Apr 2016 00:04:09 +0800 Subject: [PATCH 053/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a2e7ca..af01812 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--get tcp socket lua fd`* ### context api -1. `result, error = context.send(handle, data1[, ...])` +1. `result, error = **context.send**(handle, data1[, ...])` *`--send data1, data2, ... directy to context specified by handle noblocking.`* 2. `result, query_data1, ... = context.query(handle, data1[, ... [, query_callback(result, query_data1[, ...])]])` From 2853c01a41f20f74d885189989fd8cc8c06384e7 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 15 Apr 2016 00:19:11 +0800 Subject: [PATCH 054/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 79 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index af01812..46e4a1e 100644 --- a/README.md +++ b/README.md @@ -21,133 +21,134 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o ## usefull api ### tcp api -1. `result, listen_socket = tcp.listen(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` + +1. result, listen_socket = **tcp.listen**(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) *`--listen on a ipv4 address.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* -2. `result, listen_socket = tcp.listens(sock_name[, listen_callback(result, listen_socket, sock_name)])` +2. result, listen_socket = **tcp.listens**(sock_name[, listen_callback(result, listen_socket, sock_name)]) *`--listen on a windows named pipe or unix domain socket.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* -3. `result, listen_socket = tcp.listen6(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]])` +3. result, listen_socket = **tcp.listen6**(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) *`--listen on a ipv6 address.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* -4. `result, accept_socket = tcp.accept(listen_socket[, timeout])` +4. result, accept_socket = **tcp.accept**(listen_socket[, timeout]) *`--accept on a listen socket in blocking mode, timeout is activated if timeout is set.`* -5. `result, accept_socket = tcp.accept(listen_socket[, accept_callback(result, accept_socket, listen_socket)])` +5. result, accept_socket = **tcp.accept**(listen_socket[, accept_callback(result, accept_socket, listen_socket)]) *`--accept_callback is a continues callback, blocking if accept_callback is nil.`* -6. `result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` +6. result, connect_socket = **tcp.connect**(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]]) *`--connect_callback is a once callback, blocking if connect_callback is nil.`* -7. `result, connect_socket = tcp.connects(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` +7. result, connect_socket = **tcp.connects**(sock_name[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]]) *`--connects to a windows named pipe or unix domain socket.`* *`--connect_callback is a once callback, blocking if connect_callback is nil.`* -8. `result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]])` +8. result, connect_socket = **tcp.connect6**(host_addr, host_port[, timeout [, connect_callback(result, connect_socket, host_addr, host_port[, timeout])]]) *`--connect_callback is a once callback, blocking if connect_callback is nil.`* -9. `result, buffer = tcp.read(socket[, timeout])` +9. result, buffer = **tcp.read**(socket[, timeout]) -10. `result, buffer = tcp.read(socket[, read_callback(result, buffer, socket)])` +10. result, buffer = **tcp.read**(socket[, read_callback(result, buffer, socket)]) *`--read_callback is a continues callback, blocking if read_callback is nil.`* -11. `result, error = tcp.write(socket/fd, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety])` +11. result, error = **tcp.write**(socket/fd, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety]) *`--write a tcp socket or directly on a tcp fd(tcp.fd()) where the socket must enable shared write in advance.`* *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* -12. `tcp.set_rwopt(socket, option_table)` +12. **tcp.set_rwopt**(socket, option_table) *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* -13. `option_table = tcp.get_rwopt(socket)` +13. option_table = **tcp.get_rwopt**(socket) *`--get tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* -14. `tcp.set_nodelay(socket, enable)` +14. **tcp.set_nodelay**(socket, enable) *`--change tcp socket write 'nodelay' option. Enable nodelay if 'enable' is true or disable it if 'enable' is false.`* -15. `tcp.set_wshared(socket, enable)` +15. **tcp.set_wshared**(socket, enable) *`--change tcp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false. tcp.set_rwopt will be choked or invalid if write shared is enabled. So if you want to call both tcp.set_wshared and tcp.set_rwopt, call tcp.set_rwopt first!`* -16. `local_addr = tcp.local_addr(socket)` +16. local_addr = **tcp.local_addr**(socket) *`--socket can't be a listen socket.`* -17. `remote_addr = tcp.remote_addr(socket)` +17. remote_addr = **tcp.remote_addr**(socket) *`--socket can't be a listen socket.`* -18. `local_port = tcp.local_port(socket)` +18. local_port = **tcp.local_port**(socket) *`--socket can't be a listen socket`* -19. `remote_port = tcp.remote_port(socket)` +19. remote_port = **tcp.remote_port**(socket) *`--socket can't be a listen socket.`* -20. `tcp.close(socket)` +20. **tcp.close**(socket) *`--close the tcp socket directly.`* -21. `is_closed = tcp.is_closed(socket)` +21. is_closed = **tcp.is_closed**(socket) *`--check whether the tcp socket is closed.`* -22. `fd = tcp.fd(socket)` +22. fd = **tcp.fd**(socket) *`--get tcp socket lua fd`* ### context api -1. `result, error = **context.send**(handle, data1[, ...])` +1. result, error = **context.send**(handle, data1[, ...]) *`--send data1, data2, ... directy to context specified by handle noblocking.`* -2. `result, query_data1, ... = context.query(handle, data1[, ... [, query_callback(result, query_data1[, ...])]])` +2. result, query_data1, ... = **context.query**(handle, data1[, ... [, query_callback(result, query_data1[, ...])]]) *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* *`--query_callback is a once callback, blocking if query_callback is nil.`* -3. `result, query_data1, ... = context.timed_query(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]])` +3. result, query_data1, ... = **context.timed_query**(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]]) *`--query context specified by handle with data1, data2, ... in timeout seconds`* *`--query_callback is a once callback, blocking if query_callback is nil.`* -4. `result, error = context.reply(handle, session, data1[, ...])` +4. result, error = **context.reply**(handle, session, data1[, ...]) *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* -5. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, timeout])` +5. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, timeout]) *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* -6. `result, recv_handle, session, recv_data1, ... = context.recv(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)])` +6. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)]) *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* -7. `result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]])` +7. result, error = **context.wait**(handle[, timeout[, callback(result, error, handle[, timeout])]]) *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* *`--callback is a once callback, blocking if callback is nil.`* -8. `error = context.strerror(errno)` +8. error = **context.strerror**(errno) *`--convert error number to error string. Error number is always the next argument after result in most apis.`* -9. `handle = context.create(file_name[, arg1[, ...]])` +9. handle = **context.create**(file_name[, arg1[, ...]]) *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* -10. `handle = context.destroy([handle[, message]])` +10. handle = **context.destroy**([handle[, message]]) *`--destroy a context specified by handle with a string message. You'll kill the context itself if handle is nil and message is a optional argument.`* -11. `thread = context.thread()` +11. thread = **context.thread**() *`--return the running thread index.`* -12. `context.winos` +12. **context.winos** *`--whether the running system is windows.`* -13. `context.self` +13. **context.self** *`--the running context id.`* -14. `context.parent` +14. **context.parent** *`--the running context parent id.`* ### timer api -1. `timer.sleep(seconds)` +1. **timer.sleep**(seconds) *`--blocking for seconds.`* -2. `timer.timeout(seconds, ..., callback(...))` +2. **timer.timeout**(seconds, ..., callback(...)) *`--make a tiimeout callback in seconds.`* -3. `timer.loop(interval, repeat_time, ..., callback(...))` +3. **timer.loop**(interval, repeat_time, ..., callback(...)) *`--make a repeated callback. The first time callback will be triggered in interval seconds and then repeated in repeat_time`* ### buffer api From f521ed72441c0f7a114814466a4cbb87c400c56c Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 15 Apr 2016 11:15:35 +0800 Subject: [PATCH 055/173] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index 46e4a1e..05f4409 100644 --- a/README.md +++ b/README.md @@ -152,3 +152,38 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--make a repeated callback. The first time callback will be triggered in interval seconds and then repeated in repeat_time`* ### buffer api +1. buffer = **buffer.new**([string]) + *`--make a buffer. buffer will be initialized as string if string is not nil.`* + +2. buffer = **buffer.new**(capacity[, string]) + *`--make a buffer with capacity. buffer will be initialized as string if string is not nil.`* + +3. buffer = **buffer.new**(buffer) + *`--make a buffer initialized with another buffer.`* + +4. result = **buffer.append**(buffer, string/buffer1) + *`--append string/buffer1 to buffer.`* + +5. split_buffer = **buffer.split**(buffer[, split_length]) + *`--split buffer. The front split_length bytes in buffer will be splitted out as split_buffer and the front split_length bytes will be removed from buffer. The default value for split_length is the origin buffer length.`* + +6. result = **buffer.clear**(buffer) + *`--clear data in buffer.`* + +7. length = **buffer.length**(buffer) + *`--return the buffer length.`* + +8. unfill = **buffer.unfill**(buffer) + *`--return the unfilled(or usefull) space in buffer.`* + +9. position = **buffer.find**(buffer, string) + *`--find string in buffer and return the start position found.`* + +10. string = **buffer.tostring**(buffer) + *`--convert buffer to lua string. `* + +11. is_valid = **buffer.valid**(buffer) + *`--check whether the buffer is valid, in other words whether the buffer is already released. `* + +12. **buffer.release**(buffer) + *`--release the buffer. There may be some unexpected error if you operate on a released buffer, but it won't crash the program. `* \ No newline at end of file From cf306f05cba6d54c7f1e390a53e6bbccad195fae Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 15 Apr 2016 18:25:47 +0800 Subject: [PATCH 056/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0udp=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.vcxproj | 2 ++ node-lua.vcxproj.filters | 6 ++++++ src/message.h | 1 + src/request.h | 19 +++++++++++++++++++ src/uv_tcp_handle.cpp | 2 +- 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/node-lua.vcxproj b/node-lua.vcxproj index da97e90..758d1db 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -120,6 +120,7 @@ + @@ -148,6 +149,7 @@ + diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index a49f5ca..0a4e131 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -99,6 +99,9 @@ include + + include + @@ -176,5 +179,8 @@ src + + src + \ No newline at end of file diff --git a/src/message.h b/src/message.h index b1bfee8..b4df774 100644 --- a/src/message.h +++ b/src/message.h @@ -53,6 +53,7 @@ enum message_type { RESPONSE_TCP_READ, RESPONSE_TCP_WRITE, RESPONSE_TCP_CLOSING, + RESPONSE_UDP_OPEN, RESPONSE_HANDLE_CLOSE, RESPONSE_TIMEOUT }; diff --git a/src/request.h b/src/request.h index fee2c8e..06a1d00 100644 --- a/src/request.h +++ b/src/request.h @@ -7,6 +7,7 @@ class uv_handle_base_t; class uv_tcp_socket_handle_t; class uv_tcp_listen_handle_t; +class uv_udp_handle_t; class uv_timer_handle_t; #define REQUEST_SIZE_MAX 255 @@ -95,6 +96,24 @@ struct request_tcp_write_t { REQUEST_SPARE_REGION }; +struct request_udp_open_t { + uint32_t m_source; + uint32_t m_session; + uint16_t m_port; + bool m_ipv6; + REQUEST_SPARE_REGION +}; + +struct request_udp_read_t { + uv_udp_handle_t *m_socket_handle; + bool m_switch; //true : start, false : stop. + REQUEST_SPARE_REGION +}; + +struct request_udp_write_t { + REQUEST_SPARE_REGION +}; + struct request_handle_option_t { uv_handle_base_t *m_handle; uint8_t m_option_type; diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 557ad18..6bead9e 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -32,7 +32,7 @@ void uv_tcp_listen_handle_t::listen_tcp(request_tcp_listen_t& request) #ifdef CC_MSVC uv_tcp_simultaneous_accepts(server, 0); #endif - if ((!request.m_ipv6 ? uv_tcp_bind(server, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port)) == 0 : uv_tcp_bind6(server, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port))) && uv_listen((uv_stream_t*)server, request.m_backlog, on_accept) == 0) { + if ((!request.m_ipv6 ? uv_tcp_bind(server, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port)) == 0 : uv_tcp_bind6(server, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port)) == 0) && uv_listen((uv_stream_t*)server, request.m_backlog, on_accept) == 0) { if (!singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_LISTEN, (void*)this)) { uv_close((uv_handle_t*)server, on_closed); } From aac6d8b9eee6da8d1d41796d872e920072789040 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 17 Apr 2016 17:05:38 +0800 Subject: [PATCH 057/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0udp=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 05f4409..35953e9 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,9 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 10. result, buffer = **tcp.read**(socket[, read_callback(result, buffer, socket)]) *`--read_callback is a continues callback, blocking if read_callback is nil.`* -11. result, error = **tcp.write**(socket/fd, buffer_or_lstring[, send_callback(result, error, socket, buffer_or_lstring)/bool safety]) - *`--write a tcp socket or directly on a tcp fd(tcp.fd()) where the socket must enable shared write in advance.`* - *`--send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* +11. result, error = **tcp.write**(socket/fd, buffer/string[, write_callback(result, error, socket/fd, buffer/string)/bool safety]) + *`--write a tcp socket or directly on a tcp fd(tcp.fd()) where the socket must enable shared write in advance(call tcp.set_wshared(socket, true)).`* + *`--write_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* 12. **tcp.set_rwopt**(socket, option_table) *`--set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, "write_head_endian" = "L", "write_head_bytes" = 2, "write_head_max" = 65535,}`* @@ -91,6 +91,42 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 22. fd = **tcp.fd**(socket) *`--get tcp socket lua fd`* +### udp api + +1. result, socket = **udp.open**(addr, port, [callback(result, socket, addr, port)]) + *`--open a udp socket on a ipv4 address.`* + *`--callback is a once callback, blocking if callback is nil.`* + +2. result, socket = **udp.open6**(addr, port, [callback(result, socket, addr, port)]) + *`--open a udp socket on a ipv6 address.`* + *`--callback is a once callback, blocking if callback is nil.`* + +3. result, error = **udp.write**(socket/fd, buffer/string, remote_addr, remote_port[, write_callback(result, error, socket/fd, buffer/string, remote_addr, remote_port)/bool safety]) + *`--write a udp socket or directly on a udp fd(udp.fd()) where the socket must enable shared write in advance(call udp.set_wshared(socket, true)).`* + *`--write_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* + +4. result, error = **udp.write6**(socket/fd, buffer/string, remote_addr, remote_port[, write_callback(result, error, socket/fd, buffer/string, remote_addr, remote_port)/bool safety]) + *`--write a udp socket or directly on a udp fd(udp.fd()) where the socket must enable shared write in advance(call udp.set_wshared(socket, true)).`* + *`--write_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* + +5. result, buffer, remote_addr, remote_port, remote_ipv6 = **udp.read**(socket[, timeout]) + *`--udp max datagram read pack size: SHARED_READ_BUFFER_SIZE(64 * 1024).`* + +6. result, buffer, remote_addr, remote_port, remote_ipv6 = **udp.read**(socket[, read_callback(result, buffer, remote_addr, remote_port, remote_ipv6, socket)]) + *`--udp max datagram read pack size: SHARED_READ_BUFFER_SIZE(64 * 1024).`* + *`--read_callback is a continues callback, blocking if read_callback is nil.`* + +7. **udp.set_wshared**(socket, enable) + *`--change udp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false.`* + +8. **udp.close**(socket) + *`--close the udp socket directly.`* + +9. is_closed = **udp.is_closed**(socket) + *`--check whether the udp socket is closed.`* + +10. fd = **udp.fd**(socket) + *`--get udp socket lua fd`* ### context api 1. result, error = **context.send**(handle, data1[, ...]) From 9217845fd56fbfc7381f72ca75b3604a56638d23 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 17 Apr 2016 17:10:52 +0800 Subject: [PATCH 058/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 109 ++++++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 35953e9..da9dc46 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,56 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o make [release] #add release to build for release versions make install -## usefull api -### tcp api +## usefull api +### context api +1. **context.self** + *`--the running context id.`* + +2. **context.parent** + *`--the running context parent id.`* + +3. **context.winos** + *`--whether the running system is windows.`* + +4. handle = **context.create**(file_name[, arg1[, ...]]) + *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* + +5. handle = **context.destroy**([handle[, message]]) + *`--destroy a context specified by handle with a string message. You'll kill the context itself if handle is nil and message is a optional argument.`* +6. result, error = **context.send**(handle, data1[, ...]) + *`--send data1, data2, ... directy to context specified by handle noblocking.`* + +7. result, query_data1, ... = **context.query**(handle, data1[, ... [, query_callback(result, query_data1[, ...])]]) + *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* + *`--query_callback is a once callback, blocking if query_callback is nil.`* + +8. result, query_data1, ... = **context.timed_query**(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]]) + *`--query context specified by handle with data1, data2, ... in timeout seconds`* + *`--query_callback is a once callback, blocking if query_callback is nil.`* + +9. result, error = **context.reply**(handle, session, data1[, ...]) + *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* + +10. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, timeout]) + *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* + *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* + +11. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)]) + *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* + *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* + *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* + +12. result, error = **context.wait**(handle[, timeout[, callback(result, error, handle[, timeout])]]) + *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* + *`--callback is a once callback, blocking if callback is nil.`* + +13. error = **context.strerror**(errno) + *`--convert error number to error string. Error number is always the next argument after result in most apis.`* + +14. thread = **context.thread**() + *`--return the running thread index.`* +### tcp api 1. result, listen_socket = **tcp.listen**(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) *`--listen on a ipv4 address.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* @@ -90,9 +137,8 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--check whether the tcp socket is closed.`* 22. fd = **tcp.fd**(socket) - *`--get tcp socket lua fd`* -### udp api - + *`--get tcp socket lua fd`* +### udp api 1. result, socket = **udp.open**(addr, port, [callback(result, socket, addr, port)]) *`--open a udp socket on a ipv4 address.`* *`--callback is a once callback, blocking if callback is nil.`* @@ -127,56 +173,6 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 10. fd = **udp.fd**(socket) *`--get udp socket lua fd`* - -### context api -1. result, error = **context.send**(handle, data1[, ...]) - *`--send data1, data2, ... directy to context specified by handle noblocking.`* - -2. result, query_data1, ... = **context.query**(handle, data1[, ... [, query_callback(result, query_data1[, ...])]]) - *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* - *`--query_callback is a once callback, blocking if query_callback is nil.`* - -3. result, query_data1, ... = **context.timed_query**(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]]) - *`--query context specified by handle with data1, data2, ... in timeout seconds`* - *`--query_callback is a once callback, blocking if query_callback is nil.`* - -4. result, error = **context.reply**(handle, session, data1[, ...]) - *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* - -5. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, timeout]) - *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* - *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* - -6. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)]) - *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* - *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* - *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* - -7. result, error = **context.wait**(handle[, timeout[, callback(result, error, handle[, timeout])]]) - *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* - *`--callback is a once callback, blocking if callback is nil.`* - -8. error = **context.strerror**(errno) - *`--convert error number to error string. Error number is always the next argument after result in most apis.`* - -9. handle = **context.create**(file_name[, arg1[, ...]]) - *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* - -10. handle = **context.destroy**([handle[, message]]) - *`--destroy a context specified by handle with a string message. You'll kill the context itself if handle is nil and message is a optional argument.`* - -11. thread = **context.thread**() - *`--return the running thread index.`* - -12. **context.winos** - *`--whether the running system is windows.`* - -13. **context.self** - *`--the running context id.`* - -14. **context.parent** - *`--the running context parent id.`* - ### timer api 1. **timer.sleep**(seconds) *`--blocking for seconds.`* @@ -186,8 +182,7 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 3. **timer.loop**(interval, repeat_time, ..., callback(...)) *`--make a repeated callback. The first time callback will be triggered in interval seconds and then repeated in repeat_time`* - -### buffer api +### buffer api 1. buffer = **buffer.new**([string]) *`--make a buffer. buffer will be initialized as string if string is not nil.`* From 603f2f241b89eea9abd00bf50434cbf370fea723 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 17 Apr 2016 17:12:58 +0800 Subject: [PATCH 059/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index da9dc46..a6836a9 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,9 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 14. thread = **context.thread**() *`--return the running thread index.`* + ### tcp api + 1. result, listen_socket = **tcp.listen**(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) *`--listen on a ipv4 address.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* @@ -138,7 +140,9 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 22. fd = **tcp.fd**(socket) *`--get tcp socket lua fd`* + ### udp api + 1. result, socket = **udp.open**(addr, port, [callback(result, socket, addr, port)]) *`--open a udp socket on a ipv4 address.`* *`--callback is a once callback, blocking if callback is nil.`* @@ -173,7 +177,9 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 10. fd = **udp.fd**(socket) *`--get udp socket lua fd`* + ### timer api + 1. **timer.sleep**(seconds) *`--blocking for seconds.`* @@ -182,7 +188,9 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 3. **timer.loop**(interval, repeat_time, ..., callback(...)) *`--make a repeated callback. The first time callback will be triggered in interval seconds and then repeated in repeat_time`* + ### buffer api + 1. buffer = **buffer.new**([string]) *`--make a buffer. buffer will be initialized as string if string is not nil.`* From 45a241caed99d4a1f9e414777474907a8ec6501f Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 17 Apr 2016 17:26:11 +0800 Subject: [PATCH 060/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a6836a9..470b623 100644 --- a/README.md +++ b/README.md @@ -158,24 +158,21 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 4. result, error = **udp.write6**(socket/fd, buffer/string, remote_addr, remote_port[, write_callback(result, error, socket/fd, buffer/string, remote_addr, remote_port)/bool safety]) *`--write a udp socket or directly on a udp fd(udp.fd()) where the socket must enable shared write in advance(call udp.set_wshared(socket, true)).`* *`--write_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* - -5. result, buffer, remote_addr, remote_port, remote_ipv6 = **udp.read**(socket[, timeout]) - *`--udp max datagram read pack size: SHARED_READ_BUFFER_SIZE(64 * 1024).`* -6. result, buffer, remote_addr, remote_port, remote_ipv6 = **udp.read**(socket[, read_callback(result, buffer, remote_addr, remote_port, remote_ipv6, socket)]) +5. result, buffer, remote_addr, remote_port, remote_ipv6 = **udp.read**(socket, read_callback(result, buffer, remote_addr, remote_port, remote_ipv6, socket)) *`--udp max datagram read pack size: SHARED_READ_BUFFER_SIZE(64 * 1024).`* *`--read_callback is a continues callback, blocking if read_callback is nil.`* -7. **udp.set_wshared**(socket, enable) +6. **udp.set_wshared**(socket, enable) *`--change udp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false.`* -8. **udp.close**(socket) +7. **udp.close**(socket) *`--close the udp socket directly.`* -9. is_closed = **udp.is_closed**(socket) +8. is_closed = **udp.is_closed**(socket) *`--check whether the udp socket is closed.`* -10. fd = **udp.fd**(socket) +9. fd = **udp.fd**(socket) *`--get udp socket lua fd`* ### timer api From 42c7725acd1b57935d551b709c942ebddeb74572 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sun, 17 Apr 2016 19:03:07 +0800 Subject: [PATCH 061/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 470b623..c679264 100644 --- a/README.md +++ b/README.md @@ -147,32 +147,40 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o *`--open a udp socket on a ipv4 address.`* *`--callback is a once callback, blocking if callback is nil.`* -2. result, socket = **udp.open6**(addr, port, [callback(result, socket, addr, port)]) +2. result, socket = **udp.open**([callback(result, socket)]) + *`--open a udp socket on "0.0.0.0" with a random port.`* + *`--callback is a once callback, blocking if callback is nil.`* + +3. result, socket = **udp.open6**(addr, port, [callback(result, socket, addr, port)]) *`--open a udp socket on a ipv6 address.`* *`--callback is a once callback, blocking if callback is nil.`* -3. result, error = **udp.write**(socket/fd, buffer/string, remote_addr, remote_port[, write_callback(result, error, socket/fd, buffer/string, remote_addr, remote_port)/bool safety]) +4. result, socket = **udp.open6**([callback(result, socket)]) + *`--open a udp socket on "::" with a random port.`* + *`--callback is a once callback, blocking if callback is nil.`* + +5. result, error = **udp.write**(socket/fd, buffer/string, remote_addr, remote_port[, write_callback(result, error, socket/fd, buffer/string, remote_addr, remote_port)/bool safety]) *`--write a udp socket or directly on a udp fd(udp.fd()) where the socket must enable shared write in advance(call udp.set_wshared(socket, true)).`* *`--write_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* -4. result, error = **udp.write6**(socket/fd, buffer/string, remote_addr, remote_port[, write_callback(result, error, socket/fd, buffer/string, remote_addr, remote_port)/bool safety]) +6. result, error = **udp.write6**(socket/fd, buffer/string, remote_addr, remote_port[, write_callback(result, error, socket/fd, buffer/string, remote_addr, remote_port)/bool safety]) *`--write a udp socket or directly on a udp fd(udp.fd()) where the socket must enable shared write in advance(call udp.set_wshared(socket, true)).`* *`--write_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true.`* -5. result, buffer, remote_addr, remote_port, remote_ipv6 = **udp.read**(socket, read_callback(result, buffer, remote_addr, remote_port, remote_ipv6, socket)) +7. result, buffer, remote_addr, remote_port, remote_ipv6 = **udp.read**(socket, read_callback(result, buffer, remote_addr, remote_port, remote_ipv6, socket)) *`--udp max datagram read pack size: SHARED_READ_BUFFER_SIZE(64 * 1024).`* *`--read_callback is a continues callback, blocking if read_callback is nil.`* -6. **udp.set_wshared**(socket, enable) +8. **udp.set_wshared**(socket, enable) *`--change udp socket write shared option. Enable write shared if 'enable' is true or disable it if 'enable' is false.`* -7. **udp.close**(socket) +9. **udp.close**(socket) *`--close the udp socket directly.`* -8. is_closed = **udp.is_closed**(socket) +10. is_closed = **udp.is_closed**(socket) *`--check whether the udp socket is closed.`* -9. fd = **udp.fd**(socket) +11. fd = **udp.fd**(socket) *`--get udp socket lua fd`* ### timer api From 11efe9cf5fe891b690455da319560a66383f1618 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 18 Apr 2016 09:09:29 +0800 Subject: [PATCH 062/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0udp=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.vcxproj | 2 + node-lua.vcxproj.filters | 6 + src/context_lua.cpp | 1 + src/errors.h | 4 +- src/handle_base_def.h | 2 + src/lua_tcp_handle.cpp | 22 +-- src/lua_tcp_handle.h | 2 - src/lua_udp_handle.cpp | 315 +++++++++++++++++++++++++++++++++++++++ src/lua_udp_handle.h | 39 +++++ src/message.h | 6 + src/network.cpp | 5 +- src/network.h | 39 +++++ src/node_lua.h | 20 +++ src/request.h | 21 ++- src/utils.cpp | 38 ++++- src/utils.h | 3 +- src/uv_tcp_handle.cpp | 41 +---- src/uv_tcp_handle.h | 14 +- src/uv_udp_handle.cpp | 161 ++++++++++++++++++++ src/uv_udp_handle.h | 79 ++++++++++ 20 files changed, 757 insertions(+), 63 deletions(-) create mode 100644 src/lua_udp_handle.cpp create mode 100644 src/lua_udp_handle.h create mode 100644 src/uv_udp_handle.cpp create mode 100644 src/uv_udp_handle.h diff --git a/node-lua.vcxproj b/node-lua.vcxproj index 758d1db..f178cc5 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -106,6 +106,7 @@ + @@ -137,6 +138,7 @@ + diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index 0a4e131..ec3de5e 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -102,6 +102,9 @@ include + + include + @@ -182,5 +185,8 @@ src + + src + \ No newline at end of file diff --git a/src/context_lua.cpp b/src/context_lua.cpp index e6d3dee..79fb669 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -702,6 +702,7 @@ void context_lua_t::on_dropped(message_t& message) case RESPONSE_TCP_LISTEN: case RESPONSE_TCP_ACCEPT: case RESPONSE_TCP_CONNECT: + case RESPONSE_UDP_OPEN: if (message_is_userdata(message)) { uv_handle_base_t* handle = (uv_handle_base_t*)message_userdata(message); lua_handle_base_t::close_uv_handle(handle); diff --git a/src/errors.h b/src/errors.h index 7e16cf2..307a2c8 100644 --- a/src/errors.h +++ b/src/errors.h @@ -5,7 +5,7 @@ /* Expand this list if necessary. */ #define NL_ERRNO_MAP(XX) \ - XX( 200, EYIELD, "attempt to yield across a C-call boundary") \ + XX( 200, EYIELD, "attempt to yield across a C-call boundary") \ XX( 201, EYIELDFNZ, "yielding up finalize error") \ XX( 202, ESTACKLESS, "attempt to yield across a stack-less coroutine") \ XX( 203, ETCPSCLOSED, "tcp socket has been closed") \ @@ -16,6 +16,8 @@ XX( 208, ETIMEOUT, "timeout") \ XX( 209, ETCPNOWSHARED, "tcp socket not set write shared") \ XX( 210, ETCPWRITELONG, "attempt to send data too long") \ + XX( 211, EUDPSCLOSED, "udp socket has been closed") \ + XX( 212, EUDPNOWSHARED, "udp socket not set write shared") \ #define NL_ERRNO_GEN(val, name, s) NL_##name = val, typedef enum { diff --git a/src/handle_base_def.h b/src/handle_base_def.h index fd266a6..0a51c7e 100644 --- a/src/handle_base_def.h +++ b/src/handle_base_def.h @@ -8,4 +8,6 @@ typedef enum TIMER_SET = 2, } handle_set; +#define SOCKET_MAKE_FD(lua_ref, context_id) ((int64_t)(lua_ref)%1000000 + 1000000*(int64_t)(context_id)) + #endif \ No newline at end of file diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index b9588eb..22de382 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -49,7 +49,7 @@ static int32_t lua_tcp_get_fd(lua_State* L) { lua_handle_base_t* handle = lua_check_tcp_handle(L, 1); if (handle != NULL) { - int64_t fd = TCP_SOCKET_MAKE_FD(handle->get_handle_ref(), context_lua_t::lua_get_context_handle(L)); + int64_t fd = SOCKET_MAKE_FD(handle->get_handle_ref(), context_lua_t::lua_get_context_handle(L)); lua_pushinteger(L, fd); return 1; } @@ -654,7 +654,7 @@ int32_t lua_tcp_socket_handle_t::write_handle(lua_State* L) request_t& request = lctx->get_yielding_request(); request.m_type = REQUEST_TCP_WRITE; request.m_length = REQUEST_SIZE(request_tcp_write_t, 0); - request.m_tcp_write.m_socket_handle = (uv_tcp_socket_handle_t*)socket->m_uv_handle; + request.m_tcp_write.m_socket_handle = handle; request.m_tcp_write.m_source = lctx->get_handle(); request.m_tcp_write.m_shared_write = false; if (s) { @@ -957,21 +957,25 @@ int32_t lua_tcp_socket_handle_t::get_local_addr(lua_State* L) { lua_tcp_socket_handle_t* socket = check_socket_addr(L, 1); uv_os_sock_t sock = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->m_tcp_sock; - char host[512]; - if (socket_host(sock, true, host, sizeof(host), NULL)) { + char host[512] = { '\0' }; + bool ipv6 = false; + if (socket_host(sock, true, host, sizeof(host), &ipv6, NULL)) { lua_pushstring(L, host); + lua_pushboolean(L, ipv6); } else { lua_pushstring(L, "unknown address"); + lua_pushboolean(L, ipv6); } - return 1; + return 2; } int32_t lua_tcp_socket_handle_t::get_remote_addr(lua_State* L) { lua_tcp_socket_handle_t* socket = check_socket_addr(L, 1); uv_os_sock_t sock = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->m_tcp_sock; - char host[512]; - if (socket_host(sock, false, host, sizeof(host), NULL)) { + char host[512] = { '\0' }; + bool ipv6 = false; + if (socket_host(sock, false, host, sizeof(host), &ipv6, NULL)) { lua_pushstring(L, host); } else { lua_pushstring(L, "unknown address"); @@ -984,7 +988,7 @@ int32_t lua_tcp_socket_handle_t::get_local_port(lua_State* L) lua_tcp_socket_handle_t* socket = check_socket_addr(L, 1); uv_os_sock_t sock = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->m_tcp_sock; uint16_t port; - if (socket_host(sock, true, NULL, 0, &port)) { + if (socket_host(sock, true, NULL, 0, NULL, &port)) { lua_pushinteger(L, port); } else { lua_pushinteger(L, -1); @@ -997,7 +1001,7 @@ int32_t lua_tcp_socket_handle_t::get_remote_port(lua_State* L) lua_tcp_socket_handle_t* socket = check_socket_addr(L, 1); uv_os_sock_t sock = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->m_tcp_sock; uint16_t port; - if (socket_host(sock, false, NULL, 0, &port)) { + if (socket_host(sock, false, NULL, 0, NULL, &port)) { lua_pushinteger(L, port); } else { lua_pushinteger(L, -1); diff --git a/src/lua_tcp_handle.h b/src/lua_tcp_handle.h index e46138b..24a70b0 100644 --- a/src/lua_tcp_handle.h +++ b/src/lua_tcp_handle.h @@ -6,8 +6,6 @@ #include "context_lua.h" #include -#define TCP_SOCKET_MAKE_FD(lua_ref, context_id) ((int64_t)(lua_ref)%1000000 + 1000000*(int64_t)(context_id)) - class context_lua_t; class uv_handle_base_t; class uv_tcp_listen_handle_t; diff --git a/src/lua_udp_handle.cpp b/src/lua_udp_handle.cpp new file mode 100644 index 0000000..8ae625a --- /dev/null +++ b/src/lua_udp_handle.cpp @@ -0,0 +1,315 @@ +#include "lua_udp_handle.h" +#include "request.h" +#include "context_lua.h" +#include "network.h" +#include "lbuffer.h" +#include "node_lua.h" +#include "uv_udp_handle.h" + +#define UDP_SOCKET_METATABLE "class.udp_socket_handle_t" + +lua_udp_handle_t* lua_udp_handle_t::create_udp_socket(uv_udp_handle_t* handle, lua_State* L) +{ + lua_udp_handle_t* socket = new(lua_newuserdata(L, sizeof(lua_udp_handle_t)))lua_udp_handle_t(handle, L); + if (luaL_newmetatable(L, UDP_SOCKET_METATABLE)) { /* create new metatable */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, lua_udp_handle_t::release); + lua_setfield(L, -2, "__gc"); + lua_pushcfunction(L, lua_udp_handle_t::write); + lua_setfield(L, -2, "write"); + lua_pushcfunction(L, lua_udp_handle_t::write6); + lua_setfield(L, -2, "write6"); + lua_pushcfunction(L, lua_udp_handle_t::read); + lua_setfield(L, -2, "read"); + lua_pushcfunction(L, lua_udp_handle_t::set_wshared); + lua_setfield(L, -2, "set_wshared"); + lua_pushcfunction(L, lua_udp_handle_t::close); + lua_setfield(L, -2, "close"); + lua_pushcfunction(L, lua_udp_handle_t::udp_is_closed); + lua_setfield(L, -2, "is_closed"); + lua_pushcfunction(L, lua_udp_handle_t::get_fd); + lua_setfield(L, -2, "fd"); + } + lua_setmetatable(L, -2); + return socket; +} + +int32_t lua_udp_handle_t::open(lua_State* L) +{ + return _open(L, false); +} + +int32_t lua_udp_handle_t::open6(lua_State* L) +{ + return _open(L, true); +} + +int32_t lua_udp_handle_t::open_callback_adjust(lua_State* L) +{ + uv_udp_handle_t* handle = (uv_udp_handle_t*)lua_touserdata(L, -3); + if (handle) { + lua_pop(L, 3); + create_udp_socket(handle, L); + } else { + lua_pop(L, 2); + } + return 2; +} + +int32_t lua_udp_handle_t::open_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination) +{ + if (root_coro != NULL) { + context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); + request_t& request = lctx->get_yielding_request(); + request.m_udp_open.m_session = context_lua_t::lua_ref_yield_coroutine(root_coro); + singleton_ref(network_t).send_request(request); + } + return UV_OK; +} + +int32_t lua_udp_handle_t::open_yield_continue(lua_State* L, int status, lua_KContext ctx) +{ + uv_udp_handle_t* handle = (uv_udp_handle_t*)lua_touserdata(L, -3); + if (handle) { + lua_pop(L, 3); + create_udp_socket(handle, L); + } else { + lua_pop(L, 2); + if (context_lua_t::lua_get_context(L)->get_yielding_status() != UV_OK) { + context_lua_t::lua_throw(L, -1); + } + } + return 2; +} + +int32_t lua_udp_handle_t::_open(lua_State* L, bool ipv6) +{ + const char* host = NULL; + size_t host_len; + uint16_t port; + int32_t callback = false; + if (!lua_isfunction(L, 1)) { + host = luaL_checklstring(L, 1, &host_len); + port = luaL_checkunsigned(L, 2); + if (host_len + 1 > REQUEST_SPARE_SIZE(request_udp_open_t)) { + luaL_argerror(L, 1, "udp open host invalid(too long)"); + } + if (lua_gettop(L) >= 3) { + luaL_checktype(L, 3, LUA_TFUNCTION); + callback = 3; + } + } else { + host = !ipv6 ? "0.0.0.0" : "::"; + host_len = !ipv6 ? 7 : 2; + port = 0; + callback = 1; + } + context_lua_t* lctx = context_lua_t::lua_get_context(L); + request_t& request = lctx->get_yielding_request(); + request.m_type = REQUEST_UDP_OPEN; + request.m_length = REQUEST_SIZE(request_udp_open_t, host_len + 1); + request.m_udp_open.m_source = lctx->get_handle(); + request.m_udp_open.m_port = port; + request.m_udp_open.m_ipv6 = ipv6; + memcpy(REQUEST_SPARE_PTR(request.m_udp_open), host, host_len + 1); + if (callback > 0) { /* nonblocking callback */ + lua_settop(L, callback); + request.m_udp_open.m_session = context_lua_t::lua_ref_callback(L, callback - 1, LUA_REFNIL, open_callback_adjust); + singleton_ref(network_t).send_request(request); + return 0; + } else { /* blocking */ + return lctx->lua_yield_send(L, 0, open_yield_finalize, NULL, open_yield_continue); + } +} + +int32_t lua_udp_handle_t::write(lua_State* L) +{ + return _write(L, false); +} + +int32_t lua_udp_handle_t::write6(lua_State* L) +{ + return _write(L, true); +} + +int32_t lua_udp_handle_t::_write(lua_State* L, bool ipv6) +{ + lua_udp_handle_t* socket = NULL; + int64_t fd = 0; + const char *s = NULL; + uint32_t length; + buffer_t* buffer = NULL; + const char* host; + size_t host_len; + uint16_t port; + if (!lua_isinteger(L, 1)) { + socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (socket->is_closed()) { + return luaL_error(L, "attempt to send data on a invalid or closed socket"); + } + } else { + fd = lua_tointeger(L, 1); + } + if (((s = lua_tolstring(L, 2, (size_t*)&length)) == NULL) && ((buffer = (buffer_t*)luaL_testudata(L, 2, BUFFER_METATABLE)) == NULL)) { + luaL_argerror(L, 2, "string expected"); + } + if (buffer) { + length = (uint32_t)buffer_data_length(*buffer); + } + host = luaL_checklstring(L, 3, &host_len); + port = luaL_checkunsigned(L, 4); + if (host_len + 1 > REQUEST_SPARE_SIZE(request_udp_write_t)) { + luaL_argerror(L, 3, "udp send host invalid(too long)"); + } + bool safety = false; + bool nonblocking = false; + if (lua_gettop(L) >= 5) { + if (lua_isfunction(L, 5)) { + nonblocking = true; + lua_settop(L, 5); + } else { + safety = lua_toboolean(L, 5); + } + } + context_lua_t* lctx = context_lua_t::lua_get_context(L); + if (length == 0) { /* empty string or buffer */ + if (nonblocking) { + int32_t session = context_lua_t::lua_ref_callback(L, 4, LUA_REFNIL, context_lua_t::common_callback_adjust); + singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), session, RESPONSE_UDP_WRITE, UV_OK); + } else if (safety) { /* real blocking mode */ + lua_pushboolean(L, true); + lua_pushinteger(L, UV_OK); + return 2; + } + return 0; + } + request_t& request = lctx->get_yielding_request(); + request.m_type = REQUEST_UDP_WRITE; + request.m_length = REQUEST_SIZE(request_udp_write_t, host_len + 1); + if (socket != NULL) { + request.m_udp_write.m_socket_handle = (uv_udp_handle_t*)socket->m_uv_handle; + request.m_udp_write.m_shared_write = false; + } else { + request.m_udp_write.m_socket_fd = fd; + request.m_udp_write.m_shared_write = true; + } + request.m_udp_write.m_source = lctx->get_handle(); + request.m_udp_write.m_port = port; + request.m_udp_write.m_ipv6 = ipv6; + memcpy(REQUEST_SPARE_PTR(request.m_udp_write), host, host_len + 1); + if (s) { + request.m_udp_write.m_length = length; /* length > 0 */ + request.m_udp_write.m_string = (const char*)nl_memdup(s, length); + if (!request.m_udp_write.m_string) { + return luaL_error(L, "attempt to send data(length %lu) failed: memory not enough", length); + } + } else { + request.m_udp_write.m_length = 0; + request.m_udp_write.m_buffer = buffer_grab(*buffer); + } + if (nonblocking) { /*nonblocking callback mode*/ + request.m_udp_write.m_session = context_lua_t::lua_ref_callback(L, 4, LUA_REFNIL, context_lua_t::common_callback_adjust); + singleton_ref(network_t).send_request(request); + return 0; + } else { /* blocking mode */ + if (!safety) { /* wait for nothing */ + request.m_udp_write.m_session = LUA_REFNIL; + singleton_ref(network_t).send_request(request); + return 0; + } else { /* real blocking mode */ + return lctx->lua_yield_send(L, 0, write_yield_finalize, NULL, context_lua_t::common_yield_continue); + } + } +} + +int32_t lua_udp_handle_t::write_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination) +{ + if (root_coro != NULL) { //yield succeeded + context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); + request_t& request = lctx->get_yielding_request(); + request.m_udp_write.m_session = context_lua_t::lua_ref_yield_coroutine(root_coro); + singleton_ref(network_t).send_request(request); + } else { //yield failed, clear your data in case of memory leak. + context_lua_t* lctx = context_lua_t::lua_get_context(root_coro); + request_t& request = lctx->get_yielding_request(); + if (request.m_udp_write.m_length > 0) { + nl_free((void*)request.m_udp_write.m_string); + request.m_udp_write.m_string = NULL; + request.m_udp_write.m_length = 0; + } else { + buffer_release(request.m_udp_write.m_buffer); + } + } + return UV_OK; +} + +int32_t lua_udp_handle_t::read(lua_State* L) +{ + lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (socket->is_closed()) { + return luaL_error(L, "attempt to read data on a invalid or closed socket"); + } + luaL_checktype(L, 2, LUA_TFUNCTION); + lua_settop(L, 2); + socket->m_nonblocking_ref = context_lua_t::lua_ref_callback(L, 1, socket->m_nonblocking_ref, read_callback_adjust); + context_lua_t* lctx = context_lua_t::lua_get_context(L); + request_t& request = lctx->get_yielding_request(); + request.m_type = REQUEST_UDP_READ; + request.m_length = REQUEST_SIZE(request_udp_read_t, 0); + request.m_udp_read.m_socket_handle = (uv_udp_handle_t*)socket->m_uv_handle; + singleton_ref(network_t).send_request(request); +} + +int32_t lua_udp_handle_t::read_callback_adjust(lua_State* L) +{ + lua_pop(L, 2); + for (int32_t i = lua_gettop(L); i < 5; ++i) { + lua_pushnil(L); + } + return 5; +} + +int32_t lua_udp_handle_t::close(lua_State* L) +{ + lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (!socket->is_closed()) { + socket->_close(); + lua_pushboolean(L, 1); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +int32_t lua_udp_handle_t::set_wshared(lua_State* L) +{ + lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (!socket->is_closed()) { + bool enable = lua_toboolean(L, 2); + socket->set_option(OPT_UDP_WSHARED, enable ? "\x01\0" : "\x00\0", 2); + } + return 0; +} + +int32_t lua_udp_handle_t::udp_is_closed(lua_State* L) +{ + lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (socket != NULL) { + lua_pushboolean(L, socket->is_closed()); + return 1; + } + lua_pushboolean(L, 0); + return 1; +} + +int32_t lua_udp_handle_t::get_fd(lua_State* L) +{ + lua_udp_handle_t* handle = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (handle != NULL) { + int64_t fd = SOCKET_MAKE_FD(handle->get_handle_ref(), context_lua_t::lua_get_context_handle(L)); + lua_pushinteger(L, fd); + return 1; + } + return 0; +} diff --git a/src/lua_udp_handle.h b/src/lua_udp_handle.h new file mode 100644 index 0000000..e32b710 --- /dev/null +++ b/src/lua_udp_handle.h @@ -0,0 +1,39 @@ +#ifndef LUA_UDP_HANDLE_H_ +#define LUA_UDP_HANDLE_H_ +#include "common.h" +#include "message.h" +#include "lua_handle_base.h" +#include "context_lua.h" + +class lua_udp_handle_t : public lua_handle_base_t +{ +public: + lua_udp_handle_t(uv_udp_handle_t* handle, lua_State* L) + : lua_handle_base_t((uv_handle_base_t*)handle, L), + m_nonblocking_ref(LUA_REFNIL) {} + ~lua_udp_handle_t() {} +private: + int32_t m_nonblocking_ref; /* nonblocking_ref callback ref */ +public: + static int32_t open(lua_State* L); + static int32_t open6(lua_State* L); + static int32_t write(lua_State* L); + static int32_t write6(lua_State* L); + static int32_t read(lua_State* L); + static int32_t close(lua_State* L); + static int32_t udp_is_closed(lua_State* L); + static int32_t set_wshared(lua_State* L); + static int32_t get_fd(lua_State* L); +private: + static int32_t _open(lua_State* L, bool ipv6); + static int32_t open_callback_adjust(lua_State* L); + static int32_t open_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); + static int32_t open_yield_continue(lua_State* L, int status, lua_KContext ctx); + static int32_t _write(lua_State* L, bool ipv6); + static int32_t write_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); + static int32_t read_callback_adjust(lua_State* L); +public: + static lua_udp_handle_t* create_udp_socket(uv_udp_handle_t* handle, lua_State* L); +}; + +#endif \ No newline at end of file diff --git a/src/message.h b/src/message.h index b4df774..7468ddf 100644 --- a/src/message.h +++ b/src/message.h @@ -54,6 +54,8 @@ enum message_type { RESPONSE_TCP_WRITE, RESPONSE_TCP_CLOSING, RESPONSE_UDP_OPEN, + RESPONSE_UDP_READ, + RESPONSE_UDP_WRITE, RESPONSE_HANDLE_CLOSE, RESPONSE_TIMEOUT }; @@ -151,6 +153,10 @@ class message_t { message_t(uint32_t source, int32_t session, uint32_t msg_type, bson_t* bson) : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, BSON)) { m_data.m_bson = bson; } + + message_t(uint32_t source, int32_t session, uint32_t msg_type, message_array_t* array) + : m_source(source), m_session(session), + m_type(MAKE_MESSAGE_TYPE(msg_type, ARRAY)) { m_data.m_array = array; } public: uint32_t m_source; int32_t m_session; diff --git a/src/network.cpp b/src/network.cpp index bcb5c0a..2c81a15 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -14,7 +14,7 @@ initialise_singleton(network_t); -network_t::network_t() : m_exiting(0) +network_t::network_t() : m_exiting(0), m_shared_read_buffer({ 0, NULL, }) { int rc; rc = make_socketpair(&m_request_r_fd, &m_request_w_fd); @@ -31,7 +31,7 @@ network_t::network_t() : m_exiting(0) network_t::~network_t() { uv_loop_delete(m_uv_loop); - uv_tcp_socket_handle_t::free_shared_read_buffer(); + free_shared_read_buffer(); } void network_t::start() @@ -364,4 +364,3 @@ int network_t::close_socketpair( uv_os_sock_t *r, uv_os_sock_t *w ) #endif return 0; } - diff --git a/src/network.h b/src/network.h index 5b97423..053e1f6 100644 --- a/src/network.h +++ b/src/network.h @@ -1,8 +1,12 @@ #ifndef NETWORK_H_ #define NETWORK_H_ +#include #include "singleton.h" #include "request.h" +#define SHARED_READ_BUFFER_SIZE (64 * 1024) +typedef std::map shared_write_map_t; + class message_queue_t; class network_t : public singleton_t { @@ -15,6 +19,8 @@ class network_t : public singleton_t { uv_os_sock_t m_request_r_fd; uv_os_sock_t m_request_w_fd; uv_poll_t m_request_handle; + uv_buf_t m_shared_read_buffer; /* tcp and udp shared read buffer in network thread */ + shared_write_map_t m_shared_write_sockets; /* tcp and udp shared write socket in network thread */ atomic_t m_exiting; public: uv_err_code last_error() const { return uv_last_error(m_uv_loop).code; } @@ -35,6 +41,39 @@ class network_t : public singleton_t { static int close_socketpair(uv_os_sock_t *r, uv_os_sock_t *w); static int set_noneblocking(uv_os_sock_t sock); static int close_socket(uv_os_sock_t sock); +public: + FORCE_INLINE void free_shared_read_buffer() { + if (m_shared_read_buffer.base) { + nl_free(m_shared_read_buffer.base); + m_shared_read_buffer.base = NULL; + m_shared_read_buffer.len = 0; + } + } + FORCE_INLINE uv_buf_t get_shared_read_buffer() const { + return m_shared_read_buffer; + } + FORCE_INLINE uv_buf_t make_shared_read_buffer() { + if (m_shared_read_buffer.base) { + return m_shared_read_buffer; + } + m_shared_read_buffer.base = (char*)nl_malloc(SHARED_READ_BUFFER_SIZE); + assert(m_shared_read_buffer.base != NULL); + m_shared_read_buffer.len = SHARED_READ_BUFFER_SIZE; + return m_shared_read_buffer; + } + FORCE_INLINE void put_shared_write_socket(int64_t fd, uv_handle_base_t* socket) { + m_shared_write_sockets[fd] = socket; + } + FORCE_INLINE uv_handle_base_t* get_shared_write_socket(int64_t fd) const { + shared_write_map_t::const_iterator it = m_shared_write_sockets.find(fd); + if (it != m_shared_write_sockets.end()) { + return it->second; + } + return NULL; + } + FORCE_INLINE void pop_shared_write_socket(int64_t fd) { + m_shared_write_sockets.erase(fd); + } private: void request_exit(request_exit_t& request); void request_tcp_listen(request_tcp_listen_t& request); diff --git a/src/node_lua.h b/src/node_lua.h index c07b98f..131150b 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -95,6 +95,26 @@ class node_lua_t : public singleton_t { return ret; } + FORCE_INLINE bool context_send_array_release(uint32_t handle, uint32_t source, int session, int msg_type, message_array_t* array) + { + message_t msg(source, session, msg_type, array); + bool ret = context_send(handle, msg); + if (!ret) { + message_clean(msg); + } + return ret; + } + + FORCE_INLINE bool context_send_array_release(context_t* ctx, uint32_t source, int session, int msg_type, message_array_t* array) + { + message_t msg(source, session, msg_type, array); + bool ret = context_send(ctx, msg); + if (!ret) { + message_clean(msg); + } + return ret; + } + template < class type > uint32_t context_create(uint32_t parent, int32_t argc, char* argv[], char* env[]) { uint32_t handle = 0; diff --git a/src/request.h b/src/request.h index 06a1d00..6a318c6 100644 --- a/src/request.h +++ b/src/request.h @@ -25,6 +25,9 @@ enum request_type { REQUEST_TCP_CONNECTS, REQUEST_TCP_READ, REQUEST_TCP_WRITE, + REQUEST_UDP_OPEN, + REQUEST_UDP_READ, + REQUEST_UDP_WRITE, REQUEST_HANDLE_OPTION, REQUEST_HANDLE_CLOSE, REQUEST_TIMER_START @@ -106,11 +109,24 @@ struct request_udp_open_t { struct request_udp_read_t { uv_udp_handle_t *m_socket_handle; - bool m_switch; //true : start, false : stop. REQUEST_SPARE_REGION }; struct request_udp_write_t { + union { + uv_udp_handle_t *m_socket_handle; + uint64_t m_socket_fd; + }; + union { + const char* m_string; + buffer_t m_buffer; + }; + uint32_t m_length; /* judge it's string or buffer */ + uint32_t m_source; /* redundant if m_shared_write is true */ + uint32_t m_session; + uint16_t m_port; + bool m_ipv6; + bool m_shared_write; /* whether m_socket_fd is valid */ REQUEST_SPARE_REGION }; @@ -146,6 +162,9 @@ struct request_t { request_tcp_connects_t m_tcp_connects; request_tcp_read_t m_tcp_read; request_tcp_write_t m_tcp_write; + request_udp_open_t m_udp_open; + request_udp_read_t m_udp_read; + request_udp_write_t m_udp_write; request_handle_option_t m_handle_option; request_handle_close_t m_handle_close; request_timer_start_t m_timer_start; diff --git a/src/utils.cpp b/src/utils.cpp index 885cec2..47dbca7 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -44,7 +44,7 @@ extern void* nl_memdup(const void* src, uint32_t len) return NULL; } -extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, uint16_t* port) +extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, bool* ipv6, uint16_t* port) { union sock_name_u { sockaddr_in sock4; @@ -63,6 +63,9 @@ extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host if (host != NULL) { uv_ip4_name(&sock_name.sock4, host, host_len); } + if (ipv6 != NULL) { + *ipv6 = false; + } if (port != NULL) { *port = sock_name.sock4.sin_port; } @@ -72,6 +75,9 @@ extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host if (host != NULL) { uv_ip6_name(&sock_name.sock6, host, host_len); } + if (ipv6 != NULL) { + *ipv6 = true; + } if (port != NULL) { *port = sock_name.sock6.sin6_port; } @@ -79,3 +85,33 @@ extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host } return false; } + +extern bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, bool* ipv6, uint16_t* port) +{ + uint16_t family = addr->sa_family; + if (family == AF_INET) { + if (host != NULL) { + uv_ip4_name((sockaddr_in*)addr, host, host_len); + } + if (ipv6 != NULL) { + *ipv6 = false; + } + if (port != NULL) { + *port = ((sockaddr_in*)addr)->sin_port; + } + return true; + } + if (family == AF_INET6) { + if (host != NULL) { + uv_ip6_name((sockaddr_in6*)addr, host, host_len); + } + if (ipv6 != NULL) { + *ipv6 = true; + } + if (port != NULL) { + *port = ((sockaddr_in6*)addr)->sin6_port; + } + return true; + } + return false; +} diff --git a/src/utils.h b/src/utils.h index b5643be..91ae2be 100644 --- a/src/utils.h +++ b/src/utils.h @@ -4,6 +4,7 @@ extern char* filter_arg(char **param, int32_t *len); extern void* nl_memdup(const void* src, uint32_t len); -extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, uint16_t* port); +extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, bool* ipv6, uint16_t* port); +extern bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, bool* ipv6, uint16_t* port); #endif diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 6bead9e..88f0711 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -96,33 +96,12 @@ void uv_tcp_listen_handle_t::accept(request_tcp_accept_t& request) ///////////////////////////////////////////////////////////////////////////////////////////////////////// #define LARGE_UNCOMPLETE_LIMIT (1 * 1024) -#define SHARED_READ_BUFFER_SIZE (64 * 1024) -uv_buf_t uv_tcp_socket_handle_t::m_shared_read_buffer = { 0, NULL, }; -write_shared_map_t uv_tcp_socket_handle_t::m_write_shared_sockets; - -void uv_tcp_socket_handle_t::make_shared_read_buffer() -{ - if (!m_shared_read_buffer.base) { - m_shared_read_buffer.base = (char*)nl_malloc(SHARED_READ_BUFFER_SIZE); - assert(m_shared_read_buffer.base != NULL); - m_shared_read_buffer.len = SHARED_READ_BUFFER_SIZE; - } -} - -void uv_tcp_socket_handle_t::free_shared_read_buffer() -{ - if (m_shared_read_buffer.base) { - nl_free(m_shared_read_buffer.base); - m_shared_read_buffer.base = NULL; - m_shared_read_buffer.len = 0; - } -} uv_tcp_socket_handle_t::~uv_tcp_socket_handle_t() { clear_read_cached_buffers(); clear_write_cached_requests(); - m_write_shared_sockets.erase(TCP_SOCKET_MAKE_FD(m_lua_ref, m_source)); + singleton_ref(network_t).pop_shared_write_socket(SOCKET_MAKE_FD(m_lua_ref, m_source)); } void uv_tcp_socket_handle_t::on_connect(uv_connect_t* req, int status) @@ -196,9 +175,8 @@ void uv_tcp_socket_handle_t::write(request_tcp_write_t& request) { int32_t err = UV_UNKNOWN; if (request.m_shared_write) { - write_shared_map_t::iterator it = m_write_shared_sockets.find(request.m_socket_fd); - if (it != m_write_shared_sockets.end()) { - uv_tcp_socket_handle_t* handle = it->second; + uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)singleton_ref(network_t).get_shared_write_socket(request.m_socket_fd); + if (handle != NULL) { uint32_t length = request.m_length > 0 ? request.m_length : (uint32_t)buffer_data_length(request.m_buffer); if (uv_is_closing((uv_handle_t*)handle)) { err = NL_ETCPSCLOSED; @@ -263,10 +241,7 @@ uv_buf_t uv_tcp_socket_handle_t::on_read_alloc(uv_handle_t* handle, size_t sugge { uv_tcp_socket_handle_t *socket_handle = (uv_tcp_socket_handle_t*)(handle->data); if (buffer_write_size(socket_handle->m_read_buffer) < LARGE_UNCOMPLETE_LIMIT) { - if (!m_shared_read_buffer.base) { - make_shared_read_buffer(); - } - return m_shared_read_buffer; + return singleton_ref(network_t).make_shared_read_buffer(); } /* read in m_shared_read_buffer but not complete large pack(optimization for memcpy) */ uv_buf_t buf; @@ -285,7 +260,7 @@ void uv_tcp_socket_handle_t::write_read_buffer(ssize_t nread, uv_buf_t buf) return; } char* buffer = buf.base; - if (buffer != m_shared_read_buffer.base) { + if (buffer != singleton_ref(network_t).get_shared_read_buffer().base) { buffer_adjust_len(m_read_buffer, nread); if (buffer_write_size(m_read_buffer) == 0) { write_read_buffer_finish(UV_OK); @@ -446,11 +421,11 @@ void uv_tcp_socket_handle_t::set_tcp_nodelay(bool enable) void uv_tcp_socket_handle_t::set_tcp_wshared(bool enable) { if (!uv_is_closing((uv_handle_t*)(m_handle))) { - int64_t fd = TCP_SOCKET_MAKE_FD(m_lua_ref, m_source); + int64_t fd = SOCKET_MAKE_FD(m_lua_ref, m_source); if (enable) { - m_write_shared_sockets[fd] = this; + singleton_ref(network_t).put_shared_write_socket(fd, this); } else { - m_write_shared_sockets.erase(fd); + singleton_ref(network_t).pop_shared_write_socket(fd); } } } diff --git a/src/uv_tcp_handle.h b/src/uv_tcp_handle.h index f353ab3..de07184 100644 --- a/src/uv_tcp_handle.h +++ b/src/uv_tcp_handle.h @@ -6,7 +6,6 @@ #include "uv_handle_base.h" #include #include -#include #define TCP_TRANSPORT_DEFAULT_ENDIAN LITTLE_ENDIAN_VAL #define TCP_WRITE_UV_REQUEST_CACHE_MAX 32 @@ -56,8 +55,6 @@ class uv_tcp_listen_handle_t : public uv_handle_base_t since nonblocking may be treated as blocking in context thread. */ }; -typedef std::map write_shared_map_t; - class uv_tcp_socket_handle_t : public uv_handle_base_t { public: @@ -83,7 +80,7 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t static void on_connect(uv_connect_t* req, int status); static void on_write(uv_write_t* req, int status); static void on_read(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); - static uv_buf_t on_read_alloc(uv_handle_t* handle, size_t suggested_size); /* return tcp shared read buffer */ + static uv_buf_t on_read_alloc(uv_handle_t* handle, size_t suggested_size); /* return shared read buffer */ int32_t write_handle(request_tcp_write_t& request); void write_read_buffer(ssize_t nread, uv_buf_t buf); @@ -104,8 +101,6 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t void set_tcp_wshared(bool enable); uv_err_code get_read_error() const { return m_read_error; } uv_err_code get_write_error() const { return m_write_error; } - static void free_shared_read_buffer(); - static void make_shared_read_buffer(); private: uv_os_sock_t m_tcp_sock; /* read parameters */ @@ -119,7 +114,6 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t uint32_t m_read_bytes; buffer_t m_read_buffer; std::queue m_read_cached_buffers; - static uv_buf_t m_shared_read_buffer; /* tcp shared read buffer in network thread */ /* the following members are read-acceleration options and set in context thread before recv starts. */ head_option_t m_read_head_option; @@ -164,16 +158,12 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t } m_write_cached_reqs.push_back(request); } - void clear_write_cached_requests() - { + void clear_write_cached_requests() { for (int i = 0; i < m_write_cached_reqs.size(); ++i) { nl_free(m_write_cached_reqs[i]); } m_write_cached_reqs.clear(); } - -private: - static write_shared_map_t m_write_shared_sockets; }; #endif diff --git a/src/uv_udp_handle.cpp b/src/uv_udp_handle.cpp new file mode 100644 index 0000000..afb4eb5 --- /dev/null +++ b/src/uv_udp_handle.cpp @@ -0,0 +1,161 @@ +#include "message.h" +#include "network.h" +#include "node_lua.h" +#include "uv_udp_handle.h" + +uv_udp_handle_t::~uv_udp_handle_t() +{ + clear_write_cached_requests(); + singleton_ref(network_t).pop_shared_write_socket(SOCKET_MAKE_FD(m_lua_ref, m_source)); +} + +void uv_udp_handle_t::open(request_udp_open_t& request) +{ + uv_udp_t* server = (uv_udp_t*)m_handle; + if ((!request.m_ipv6 ? uv_udp_bind(server, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port), 0) == 0 : uv_udp_bind6(server, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port), 0) == 0)) { + if (!singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_UDP_OPEN, (void*)this)) { + uv_close((uv_handle_t*)server, on_closed); + } + } else { + singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_UDP_OPEN, singleton_ref(network_t).last_error()); + uv_close((uv_handle_t*)server, on_closed); + } +} + +uv_buf_t uv_udp_handle_t::on_read_alloc(uv_handle_t* handle, size_t suggested_size) +{ + return singleton_ref(network_t).make_shared_read_buffer(); +} + +void uv_udp_handle_t::on_read(uv_udp_t* handle, ssize_t nread, uv_buf_t buf, struct sockaddr* addr, unsigned flags) +{ + /* udp max datagram read pack size: SHARED_READ_BUFFER_SIZE(64 * 1024) */ + if (nread == 0) { + return; + } + uv_udp_handle_t* udp_handle = (uv_udp_handle_t*)(handle->data); + if (nread == -1) { + singleton_ref(node_lua_t).context_send(udp_handle->m_source, 0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, singleton_ref(network_t).last_error()); + return; + } + buffer_t buffer = buffer_new(nread, buf.base, nread); + char* host = (char*)nl_malloc(64); + uint16_t port = 0; + bool ipv6 = false; + *host = '\0'; + sockaddr_host(addr, host, 64, &ipv6, &port); + message_array_t* array = message_array_create(4); + array->m_array[0] = message_t(0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, buffer); + array->m_array[1] = message_t(0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, host); + array->m_array[2] = message_t(0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, (int64_t)port); + array->m_array[3] = message_t(0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, ipv6); + singleton_ref(node_lua_t).context_send_array_release(udp_handle->m_source, 0, udp_handle->m_lua_ref, RESPONSE_UDP_READ, array); +} + +void uv_udp_handle_t::read(request_udp_read_t& request) +{ + if (!m_read_started) { + if (uv_udp_recv_start((uv_udp_t*)m_handle, on_read_alloc, on_read) != 0) { + singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_UDP_READ, singleton_ref(network_t).last_error()); + return; + } + m_read_started = true; + } +} + +void uv_udp_handle_t::on_write(uv_udp_send_t* req, int status) +{ + write_uv_request_t *uv_request = (write_uv_request_t*)req->data; + uv_udp_handle_t *socket_handle = (uv_udp_handle_t*)(req->handle->data); + if (uv_request->m_length > 0) { + nl_free((void*)uv_request->m_string); + } else { + buffer_release(uv_request->m_buffer); + } + if (uv_request->m_session != LUA_REFNIL) { + singleton_ref(node_lua_t).context_send(uv_request->m_source, 0, uv_request->m_session, RESPONSE_UDP_WRITE, status == 0 ? UV_OK : singleton_ref(network_t).last_error()); + } + socket_handle->put_write_cached_request(uv_request); +} + +void uv_udp_handle_t::write(request_udp_write_t& request) +{ + int32_t err = UV_UNKNOWN; + if (request.m_shared_write) { + uv_udp_handle_t* handle = (uv_udp_handle_t*)singleton_ref(network_t).get_shared_write_socket(request.m_socket_fd); + if (handle != NULL) { + uint32_t length = request.m_length > 0 ? request.m_length : (uint32_t)buffer_data_length(request.m_buffer); + if (uv_is_closing((uv_handle_t*)handle)) { + err = NL_EUDPSCLOSED; + } else { + err = handle->write_handle(request); + } + } else { + err = NL_EUDPNOWSHARED; + } + } else { + err = request.m_socket_handle->write_handle(request); + } + if (err != UV_OK) { /* write error had been occurred */ + if (request.m_length > 0) { + nl_free((void*)request.m_string); + } else { + buffer_release(request.m_buffer); + } + if (request.m_session != LUA_REFNIL) { + singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_UDP_WRITE, (nl_err_code)err); + } + } +} + +int32_t uv_udp_handle_t::write_handle(request_udp_write_t& request) +{ + int result; + uv_buf_t uv_buf; + write_uv_request_t* uv_request = get_write_cached_request(); + uv_request->m_source = request.m_source; + uv_request->m_session = request.m_session; + uv_request->m_length = request.m_length; + if (request.m_length > 0) { + uv_request->m_string = request.m_string; + uv_buf.len = request.m_length; + uv_buf.base = (char*)request.m_string; + } else { + uv_request->m_buffer = request.m_buffer; + uv_buf.len = buffer_data_length(request.m_buffer); + uv_buf.base = buffer_data_ptr(request.m_buffer); + } + if (!request.m_ipv6) { + result = uv_udp_send(&uv_request->m_write_req, (uv_udp_t*)m_handle, &uv_buf, 1, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port), on_write); + } else { + result = uv_udp_send6(&uv_request->m_write_req, (uv_udp_t*)m_handle, &uv_buf, 1, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port), on_write); + } + if (result == 0) return UV_OK; + put_write_cached_request(uv_request); + return singleton_ref(network_t).last_error(); /* write error occurs */ +} + +void uv_udp_handle_t::set_option(uint8_t type, const char *option) +{ + udp_option_type opt_type = (udp_option_type)type; + switch (opt_type) + { + case OPT_UDP_WSHARED: + set_udp_wshared(*option); + break; + default: + break; + } +} + +void uv_udp_handle_t::set_udp_wshared(bool enable) +{ + if (!uv_is_closing((uv_handle_t*)(m_handle))) { + int64_t fd = SOCKET_MAKE_FD(m_lua_ref, m_source); + if (enable) { + singleton_ref(network_t).put_shared_write_socket(fd, this); + } else { + singleton_ref(network_t).pop_shared_write_socket(fd); + } + } +} diff --git a/src/uv_udp_handle.h b/src/uv_udp_handle.h new file mode 100644 index 0000000..e580e0e --- /dev/null +++ b/src/uv_udp_handle.h @@ -0,0 +1,79 @@ +#ifndef UV_UDP_HANDLE_H_ +#define UV_UDP_HANDLE_H_ +#include "buffer.h" +#include "request.h" +#include "uv_handle_base.h" +#include + +#define UDP_WRITE_UV_REQUEST_CACHE_MAX 32 + +enum udp_option_type { + OPT_UDP_WSHARED, +}; + +class uv_udp_handle_t : public uv_handle_base_t +{ +public: + uv_udp_handle_t(uv_loop_t* loop, uint32_t source) + : uv_handle_base_t(loop, UV_UDP, source), + m_read_started(false) {} + ~uv_udp_handle_t(); + +private: + static void on_read(uv_udp_t* handle, ssize_t nread, uv_buf_t buf, struct sockaddr* addr, unsigned flags); + static uv_buf_t on_read_alloc(uv_handle_t* handle, size_t suggested_size); + static void on_write(uv_udp_send_t* req, int status); + + int32_t write_handle(request_udp_write_t& request); +public: + void set_option(uint8_t type, const char *option); + void set_udp_wshared(bool enable); + +public: + void open(request_udp_open_t& request); + void read(request_udp_read_t& request); + static void write(request_udp_write_t& request); +private: + bool m_read_started; + + typedef struct { + uv_udp_send_t m_write_req; + union { + const char* m_string; + buffer_t m_buffer; + }; + uint32_t m_length; /* judge it's string or buffer */ + uint32_t m_source; + uint32_t m_session; + } write_uv_request_t; + + std::vector m_write_cached_reqs; + + write_uv_request_t* get_write_cached_request() { + write_uv_request_t* cache; + if (!m_write_cached_reqs.empty()) { + cache = m_write_cached_reqs.back(); + m_write_cached_reqs.pop_back(); + } + else { + cache = (write_uv_request_t*)nl_malloc(sizeof(write_uv_request_t)); + cache->m_write_req.data = cache; + } + return cache; + } + void put_write_cached_request(write_uv_request_t* request) { + if (m_write_cached_reqs.size() >= UDP_WRITE_UV_REQUEST_CACHE_MAX) { + nl_free(m_write_cached_reqs.back()); + m_write_cached_reqs.pop_back(); + } + m_write_cached_reqs.push_back(request); + } + void clear_write_cached_requests() { + for (int i = 0; i < m_write_cached_reqs.size(); ++i) { + nl_free(m_write_cached_reqs[i]); + } + m_write_cached_reqs.clear(); + } +}; + +#endif From 142ab0b6122fe42b4b7a55e3d1787955b3804423 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 18 Apr 2016 15:05:20 +0800 Subject: [PATCH 063/173] =?UTF-8?q?=E5=AE=8C=E5=96=84udp=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/main.lua | 24 +++++++++++++++++++ src/context_lua.cpp | 52 +++++++++++++++++++++++++++++++++------- src/context_lua.h | 6 ++++- src/errors.h | 2 +- src/lua_tcp_handle.cpp | 2 +- src/lua_udp_handle.cpp | 54 ++++++++++++++++++++++++++++++++++++++++-- src/lua_udp_handle.h | 2 ++ src/main.cpp | 2 +- src/message.h | 1 + src/network.cpp | 25 +++++++++++++++++++ src/network.h | 3 +++ 11 files changed, 159 insertions(+), 14 deletions(-) diff --git a/sample/main.lua b/sample/main.lua index 35d36d1..cdfff40 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -70,7 +70,31 @@ print("value", value1, value2)]] -- # define TEST_PIPENAME_2 "/tmp/uv-test-sock2" -- #endif +local result, server = udp.open("127.0.0.1", 8081) +server:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, server) + print("server read callback: ", result, buffer, remote_addr, remote_port, remote_ipv6, server) + server:write("hello, world server send!", remote_addr, 8082, true) +end) +local result, client1 = udp.open("127.0.0.1", 8082) +local result, client2 = udp.open("127.0.0.1", 8083) + +client1:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, client) + print("client1 read callback: ", result, buffer, remote_addr, remote_port, remote_ipv6, client) +end) +client2:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, client) + print("client2 read callback: ", result, buffer, remote_addr, remote_port, remote_ipv6, client) +end) + +print("client1:write ", client1:write("hello, world1!", "127.0.0.1", 8081, true)) +print("client2:write ", client2:write("hello, world2!", "127.0.0.1", 8081, true)) + + +timer.sleep(3600) + +do return end + +--context send and recv test, memery leak test local handle = context.create("sample/test.lua") diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 79fb669..2a76368 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -7,6 +7,7 @@ #include "worker.h" #include "uv_handle_base.h" #include "lua_tcp_handle.h" +#include "lua_udp_handle.h" #include "lua_timer_handle.h" #include "errors.h" @@ -108,6 +109,8 @@ void context_lua_t::on_worker_detached() LUAMOD_API int (luaopen_my_coroutine)(lua_State *L); #define LUA_TCPLIBNAME "tcp" LUAMOD_API int (luaopen_tcp)(lua_State *L); +#define LUA_UDPLIBNAME "udp" +LUAMOD_API int (luaopen_udp)(lua_State *L); #define LUA_BUFFERLIBNAME "buffer" LUAMOD_API int (luaopen_buffer)(lua_State *L); #define LUA_CONTEXTLIBNAME "context" @@ -134,6 +137,7 @@ void context_lua_t::lua_open_libs(lua_State *L) {LUA_CACHELIB, luaopen_cache}, #endif {LUA_TCPLIBNAME, luaopen_tcp}, + {LUA_UDPLIBNAME, luaopen_udp}, {LUA_BUFFERLIBNAME, luaopen_buffer}, {LUA_CONTEXTLIBNAME, luaopen_context}, {LUA_TIMERLIBNAME, luaopen_timer}, @@ -676,12 +680,24 @@ void context_lua_t::on_received(message_t& message) case RESPONSE_TCP_WRITE: response_tcp_write(message); break; - case RESPONSE_HANDLE_CLOSE: - response_handle_close(message); - break; case RESPONSE_TCP_CLOSING: response_tcp_closing(message); break; + case RESPONSE_UDP_OPEN: + response_udp_open(message); + break; + case RESPONSE_UDP_WRITE: + response_udp_write(message); + break; + case RESPONSE_UDP_READ: + response_udp_read(message); + break; + case RESPONSE_UDP_CLOSING: + response_udp_closing(message); + break; + case RESPONSE_HANDLE_CLOSE: + response_handle_close(message); + break; case RESPONSE_TIMEOUT: response_timeout(message); break; @@ -796,11 +812,6 @@ void context_lua_t::response_tcp_read(message_t& response) lua_tcp_socket_handle_t::wakeup_read(m_lstate, response); } -void context_lua_t::response_handle_close(message_t& response) -{ - lua_handle_base_t::release_ref(m_lstate, response.m_session, (handle_set)(int32_t)message_integer(response)); -} - void context_lua_t::response_tcp_closing(message_t& response) { if (message_error(response) == NL_ETCPLCLOSED) { /* listen socket */ @@ -810,6 +821,31 @@ void context_lua_t::response_tcp_closing(message_t& response) } } +void context_lua_t::response_udp_open(message_t& response) +{ + lua_udp_handle_t::wakeup_open(m_lstate, response); +} + +void context_lua_t::response_udp_write(message_t& response) +{ + wakeup_ref_session(response.m_session, response, true); +} + +void context_lua_t::response_udp_read(message_t& response) +{ + lua_udp_handle_t::wakeup_read(m_lstate, response); +} + +void context_lua_t::response_udp_closing(message_t& response) +{ + lua_udp_handle_t::wakeup_read(m_lstate, response); +} + +void context_lua_t::response_handle_close(message_t& response) +{ + lua_handle_base_t::release_ref(m_lstate, response.m_session, (handle_set)(int32_t)message_integer(response)); +} + void context_lua_t::response_timeout(message_t& response) { lua_timer_handle_t::wakeup(m_lstate, response); diff --git a/src/context_lua.h b/src/context_lua.h index 02ec2a7..af4eb61 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -99,8 +99,12 @@ class context_lua_t : public context_t { void response_tcp_connect(message_t& response); void response_tcp_write(message_t& response); void response_tcp_read(message_t& response); - void response_handle_close(message_t& response); void response_tcp_closing(message_t& response); + void response_udp_open(message_t& response); + void response_udp_write(message_t& response); + void response_udp_read(message_t& response); + void response_udp_closing(message_t& response); + void response_handle_close(message_t& response); void response_timeout(message_t& response); public: diff --git a/src/errors.h b/src/errors.h index 307a2c8..f0f2a2c 100644 --- a/src/errors.h +++ b/src/errors.h @@ -5,7 +5,7 @@ /* Expand this list if necessary. */ #define NL_ERRNO_MAP(XX) \ - XX( 200, EYIELD, "attempt to yield across a C-call boundary") \ + XX( 200, EYIELD, "attempt to yield across a C-call boundary") \ XX( 201, EYIELDFNZ, "yielding up finalize error") \ XX( 202, ESTACKLESS, "attempt to yield across a stack-less coroutine") \ XX( 203, ETCPSCLOSED, "tcp socket has been closed") \ diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 22de382..ab38688 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -1053,7 +1053,7 @@ int32_t lua_tcp_socket_handle_t::close(lua_State* L) lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)luaL_checkudata(L, 1, TCP_SOCKET_METATABLE); if (!socket->is_closed()) { context_lua_t* lctx = context_lua_t::lua_get_context(L); - /* The message will wake up all blocking coroutine only*/ + /* The message will wake up all blocking coroutine only and close the nonblocking lua ref */ singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), socket->m_lua_ref, RESPONSE_TCP_CLOSING, NL_ETCPSCLOSED); socket->_close(); socket->release_read_overflow_buffers(); diff --git a/src/lua_udp_handle.cpp b/src/lua_udp_handle.cpp index 8ae625a..1ac9a38 100644 --- a/src/lua_udp_handle.cpp +++ b/src/lua_udp_handle.cpp @@ -89,7 +89,8 @@ int32_t lua_udp_handle_t::_open(lua_State* L, bool ipv6) size_t host_len; uint16_t port; int32_t callback = false; - if (!lua_isfunction(L, 1)) { + int32_t top = lua_gettop(L); + if (!lua_isfunction(L, 1) && top > 0) { host = luaL_checklstring(L, 1, &host_len); port = luaL_checkunsigned(L, 2); if (host_len + 1 > REQUEST_SPARE_SIZE(request_udp_open_t)) { @@ -103,7 +104,7 @@ int32_t lua_udp_handle_t::_open(lua_State* L, bool ipv6) host = !ipv6 ? "0.0.0.0" : "::"; host_len = !ipv6 ? 7 : 2; port = 0; - callback = 1; + callback = top > 0 ? 1 : 0; } context_lua_t* lctx = context_lua_t::lua_get_context(L); request_t& request = lctx->get_yielding_request(); @@ -274,6 +275,9 @@ int32_t lua_udp_handle_t::close(lua_State* L) { lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); if (!socket->is_closed()) { + context_lua_t* lctx = context_lua_t::lua_get_context(L); + /* The message will close the nonblocking lua ref */ + singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), socket->m_lua_ref, RESPONSE_UDP_CLOSING, NL_EUDPSCLOSED); socket->_close(); lua_pushboolean(L, 1); } else { @@ -313,3 +317,49 @@ int32_t lua_udp_handle_t::get_fd(lua_State* L) } return 0; } + +int32_t lua_udp_handle_t::wakeup_open(lua_State* L, message_t& message) +{ + context_lua_t* lctx = context_lua_t::lua_get_context(L); + if (!lctx->wakeup_ref_session(message.m_session, message, true)) { + if (message_is_userdata(message)) { + close_uv_handle((uv_handle_base_t*)message_userdata(message)); + } + return 0; + } + return 1; +} + +int32_t lua_udp_handle_t::wakeup_read(lua_State* L, message_t& message) +{ + context_lua_t* lctx = context_lua_t::lua_get_context(L); + lua_udp_handle_t* socket = (lua_udp_handle_t*)get_lua_handle(L, message.m_session, SOCKET_SET); + if (socket) { + if (!socket->is_closed()) { + return lctx->wakeup_ref_session(socket->m_nonblocking_ref, message, false); + } else if (socket->m_nonblocking_ref != LUA_REFNIL) { /* udp socket is already closed */ + context_lua_t::lua_free_ref_session(L, socket->m_nonblocking_ref); + socket->m_nonblocking_ref = LUA_REFNIL; + return 0; + } + } + return 0; +} + +int luaopen_udp(lua_State *L) +{ + luaL_Reg l[] = { + { "open", lua_udp_handle_t::open }, + { "open6", lua_udp_handle_t::open6 }, + { "write", lua_udp_handle_t::write }, + { "write6", lua_udp_handle_t::write6 }, + { "read", lua_udp_handle_t::read }, + { "set_wshared", lua_udp_handle_t::set_wshared }, + { "close", lua_udp_handle_t::close }, + { "is_closed", lua_udp_handle_t::udp_is_closed }, + { "fd", lua_udp_handle_t::get_fd }, + { NULL, NULL }, + }; + luaL_newlib(L, l); + return 1; +} diff --git a/src/lua_udp_handle.h b/src/lua_udp_handle.h index e32b710..c236ef1 100644 --- a/src/lua_udp_handle.h +++ b/src/lua_udp_handle.h @@ -34,6 +34,8 @@ class lua_udp_handle_t : public lua_handle_base_t static int32_t read_callback_adjust(lua_State* L); public: static lua_udp_handle_t* create_udp_socket(uv_udp_handle_t* handle, lua_State* L); + static int32_t wakeup_open(lua_State* L, message_t& message); + static int32_t wakeup_read(lua_State* L, message_t& message); }; #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 9d8a7f7..35289f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,6 @@ int main(int argc, char* argv[], char* env[]) node_lua_t node(argc - 1, argv + 1, env); double duration = (uv_hrtime() - start_time) / 1e9; printf("Process used %.3f sec total!\n", duration); - //getchar(); + getchar(); return 0; } diff --git a/src/message.h b/src/message.h index 7468ddf..850f343 100644 --- a/src/message.h +++ b/src/message.h @@ -56,6 +56,7 @@ enum message_type { RESPONSE_UDP_OPEN, RESPONSE_UDP_READ, RESPONSE_UDP_WRITE, + RESPONSE_UDP_CLOSING, RESPONSE_HANDLE_CLOSE, RESPONSE_TIMEOUT }; diff --git a/src/network.cpp b/src/network.cpp index 2c81a15..dd5a7db 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -3,6 +3,7 @@ #include "buffer.h" #include "message.h" #include "uv_tcp_handle.h" +#include "uv_udp_handle.h" #include "uv_timer_handle.h" #include "network.h" #include "node_lua.h" @@ -135,6 +136,21 @@ void network_t::request_tcp_write(request_tcp_write_t& request) uv_tcp_socket_handle_t::write(request); } +void network_t::request_udp_open(request_udp_open_t& request) +{ + (new uv_udp_handle_t(m_uv_loop, request.m_source))->open(request); +} + +void network_t::request_udp_write(request_udp_write_t& request) +{ + uv_udp_handle_t::write(request); +} + +void network_t::request_udp_read(request_udp_read_t& request) +{ + request.m_socket_handle->read(request); +} + void network_t::request_handle_option(request_handle_option_t& request) { request.m_handle->set_option(request.m_option_type, REQUEST_SPARE_PTR(request)); @@ -215,6 +231,15 @@ void network_t::process_request(request_t& request) case REQUEST_TCP_READ: request_tcp_read(request.m_tcp_read); break; + case REQUEST_UDP_OPEN: + request_udp_open(request.m_udp_open); + break; + case REQUEST_UDP_WRITE: + request_udp_write(request.m_udp_write); + break; + case REQUEST_UDP_READ: + request_udp_read(request.m_udp_read); + break; case REQUEST_HANDLE_OPTION: request_handle_option(request.m_handle_option); break; diff --git a/src/network.h b/src/network.h index 053e1f6..4213406 100644 --- a/src/network.h +++ b/src/network.h @@ -83,6 +83,9 @@ class network_t : public singleton_t { void request_tcp_connects(request_tcp_connects_t& request); void request_tcp_write(request_tcp_write_t& request); void request_tcp_read(request_tcp_read_t& request); + void request_udp_open(request_udp_open_t& request); + void request_udp_write(request_udp_write_t& request); + void request_udp_read(request_udp_read_t& request); void request_handle_option(request_handle_option_t& request); void request_handle_close(request_handle_close_t& request); void request_timer_start(request_timer_start_t& request); From ee81bf748590ee5e1c1817f88155671173224d28 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 18 Apr 2016 16:32:36 +0800 Subject: [PATCH 064/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dsockaddr=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E7=AB=AF=E5=8F=A3=E5=88=B0=E4=B8=BB=E6=9C=BA=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E7=9A=84=E8=BD=AC=E6=8D=A2=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/main.lua | 2 +- src/utils.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sample/main.lua b/sample/main.lua index cdfff40..606fae8 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -73,7 +73,7 @@ print("value", value1, value2)]] local result, server = udp.open("127.0.0.1", 8081) server:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, server) print("server read callback: ", result, buffer, remote_addr, remote_port, remote_ipv6, server) - server:write("hello, world server send!", remote_addr, 8082, true) + server:write("hello, world server send!", remote_addr, remote_port, true) end) local result, client1 = udp.open("127.0.0.1", 8082) diff --git a/src/utils.cpp b/src/utils.cpp index 47dbca7..5f8a1e6 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -67,7 +67,7 @@ extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host *ipv6 = false; } if (port != NULL) { - *port = sock_name.sock4.sin_port; + *port = ntohs(sock_name.sock4.sin_port); } return true; } @@ -79,7 +79,7 @@ extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host *ipv6 = true; } if (port != NULL) { - *port = sock_name.sock6.sin6_port; + *port = ntohs(sock_name.sock6.sin6_port); } return true; } @@ -97,7 +97,7 @@ extern bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, *ipv6 = false; } if (port != NULL) { - *port = ((sockaddr_in*)addr)->sin_port; + *port = ntohs(((sockaddr_in*)addr)->sin_port); } return true; } @@ -109,7 +109,7 @@ extern bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, *ipv6 = true; } if (port != NULL) { - *port = ((sockaddr_in6*)addr)->sin6_port; + *port = ntohs(((sockaddr_in6*)addr)->sin6_port); } return true; } From 9b7ddc2906f5c6bb1d3e8e167ad9abdabb23b7c7 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 18 Apr 2016 17:03:55 +0800 Subject: [PATCH 065/173] =?UTF-8?q?=E4=BC=98=E5=8C=96udp=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +++++-- sample/main.lua | 6 ++-- src/lua_udp_handle.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++ src/lua_udp_handle.h | 4 +++ src/main.cpp | 2 +- src/uv_udp_handle.cpp | 7 ++++ src/uv_udp_handle.h | 5 ++- 7 files changed, 110 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c679264..f7723af 100644 --- a/README.md +++ b/README.md @@ -177,10 +177,18 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o 9. **udp.close**(socket) *`--close the udp socket directly.`* -10. is_closed = **udp.is_closed**(socket) +10. local_addr = **udp.local_addr**(socket) + +11. remote_addr = **udp.remote_addr**(socket) + +12. local_port = **udp.local_port**(socket) + +13. remote_port = **udp.remote_port**(socket) + +14. is_closed = **udp.is_closed**(socket) *`--check whether the udp socket is closed.`* -11. fd = **udp.fd**(socket) +15. fd = **udp.fd**(socket) *`--get udp socket lua fd`* ### timer api diff --git a/sample/main.lua b/sample/main.lua index 606fae8..d3ae523 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -76,8 +76,8 @@ server:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, serv server:write("hello, world server send!", remote_addr, remote_port, true) end) -local result, client1 = udp.open("127.0.0.1", 8082) -local result, client2 = udp.open("127.0.0.1", 8083) +local result, client1 = udp.open() +local result, client2 = udp.open() client1:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, client) print("client1 read callback: ", result, buffer, remote_addr, remote_port, remote_ipv6, client) @@ -89,6 +89,8 @@ end) print("client1:write ", client1:write("hello, world1!", "127.0.0.1", 8081, true)) print("client2:write ", client2:write("hello, world2!", "127.0.0.1", 8081, true)) +print("client1:addr ", client1:local_addr(), client1:local_port()) +print("client2:addr ", client2:local_addr(), client2:local_port()) timer.sleep(3600) diff --git a/src/lua_udp_handle.cpp b/src/lua_udp_handle.cpp index 1ac9a38..3d08cda 100644 --- a/src/lua_udp_handle.cpp +++ b/src/lua_udp_handle.cpp @@ -24,6 +24,14 @@ lua_udp_handle_t* lua_udp_handle_t::create_udp_socket(uv_udp_handle_t* handle, l lua_setfield(L, -2, "read"); lua_pushcfunction(L, lua_udp_handle_t::set_wshared); lua_setfield(L, -2, "set_wshared"); + lua_pushcfunction(L, lua_udp_handle_t::get_local_addr); + lua_setfield(L, -2, "local_addr"); + lua_pushcfunction(L, lua_udp_handle_t::get_remote_addr); + lua_setfield(L, -2, "remote_addr"); + lua_pushcfunction(L, lua_udp_handle_t::get_local_port); + lua_setfield(L, -2, "local_port"); + lua_pushcfunction(L, lua_udp_handle_t::get_remote_port); + lua_setfield(L, -2, "remote_port"); lua_pushcfunction(L, lua_udp_handle_t::close); lua_setfield(L, -2, "close"); lua_pushcfunction(L, lua_udp_handle_t::udp_is_closed); @@ -307,6 +315,74 @@ int32_t lua_udp_handle_t::udp_is_closed(lua_State* L) return 1; } +int32_t lua_udp_handle_t::get_local_addr(lua_State* L) +{ + lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (socket->is_closed()) { + luaL_error(L, "attempt to perform on a invalid or closed socket"); + } + uv_os_sock_t sock = ((uv_udp_handle_t*)socket->m_uv_handle)->m_udp_sock; + char host[512] = { '\0' }; + bool ipv6 = false; + if (socket_host(sock, true, host, sizeof(host), &ipv6, NULL)) { + lua_pushstring(L, host); + lua_pushboolean(L, ipv6); + } else { + lua_pushstring(L, "unknown address"); + lua_pushboolean(L, ipv6); + } + return 2; +} + +int32_t lua_udp_handle_t::get_remote_addr(lua_State* L) +{ + lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (socket->is_closed()) { + luaL_error(L, "attempt to perform on a invalid or closed socket"); + } + uv_os_sock_t sock = ((uv_udp_handle_t*)socket->m_uv_handle)->m_udp_sock; + char host[512] = { '\0' }; + bool ipv6 = false; + if (socket_host(sock, false, host, sizeof(host), &ipv6, NULL)) { + lua_pushstring(L, host); + } else { + lua_pushstring(L, "unknown address"); + } + return 1; +} + +int32_t lua_udp_handle_t::get_local_port(lua_State* L) +{ + lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (socket->is_closed()) { + luaL_error(L, "attempt to perform on a invalid or closed socket"); + } + uv_os_sock_t sock = ((uv_udp_handle_t*)socket->m_uv_handle)->m_udp_sock; + uint16_t port; + if (socket_host(sock, true, NULL, 0, NULL, &port)) { + lua_pushinteger(L, port); + } else { + lua_pushinteger(L, -1); + } + return 1; +} + +int32_t lua_udp_handle_t::get_remote_port(lua_State* L) +{ + lua_udp_handle_t* socket = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); + if (socket->is_closed()) { + luaL_error(L, "attempt to perform on a invalid or closed socket"); + } + uv_os_sock_t sock = ((uv_udp_handle_t*)socket->m_uv_handle)->m_udp_sock; + uint16_t port; + if (socket_host(sock, false, NULL, 0, NULL, &port)) { + lua_pushinteger(L, port); + } else { + lua_pushinteger(L, -1); + } + return 1; +} + int32_t lua_udp_handle_t::get_fd(lua_State* L) { lua_udp_handle_t* handle = (lua_udp_handle_t*)luaL_checkudata(L, 1, UDP_SOCKET_METATABLE); @@ -355,6 +431,10 @@ int luaopen_udp(lua_State *L) { "write6", lua_udp_handle_t::write6 }, { "read", lua_udp_handle_t::read }, { "set_wshared", lua_udp_handle_t::set_wshared }, + { "local_addr", lua_udp_handle_t::get_local_addr }, + { "remote_addr", lua_udp_handle_t::get_remote_addr }, + { "local_port", lua_udp_handle_t::get_local_port }, + { "remote_port", lua_udp_handle_t::get_remote_port }, { "close", lua_udp_handle_t::close }, { "is_closed", lua_udp_handle_t::udp_is_closed }, { "fd", lua_udp_handle_t::get_fd }, diff --git a/src/lua_udp_handle.h b/src/lua_udp_handle.h index c236ef1..c15b2ae 100644 --- a/src/lua_udp_handle.h +++ b/src/lua_udp_handle.h @@ -23,6 +23,10 @@ class lua_udp_handle_t : public lua_handle_base_t static int32_t close(lua_State* L); static int32_t udp_is_closed(lua_State* L); static int32_t set_wshared(lua_State* L); + static int32_t get_local_addr(lua_State* L); + static int32_t get_remote_addr(lua_State* L); + static int32_t get_local_port(lua_State* L); + static int32_t get_remote_port(lua_State* L); static int32_t get_fd(lua_State* L); private: static int32_t _open(lua_State* L, bool ipv6); diff --git a/src/main.cpp b/src/main.cpp index 35289f4..6674df8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,6 @@ int main(int argc, char* argv[], char* env[]) node_lua_t node(argc - 1, argv + 1, env); double duration = (uv_hrtime() - start_time) / 1e9; printf("Process used %.3f sec total!\n", duration); - getchar(); + //getchar(); return 0; } diff --git a/src/uv_udp_handle.cpp b/src/uv_udp_handle.cpp index afb4eb5..c9ef007 100644 --- a/src/uv_udp_handle.cpp +++ b/src/uv_udp_handle.cpp @@ -3,6 +3,12 @@ #include "node_lua.h" #include "uv_udp_handle.h" +#if defined (CC_MSVC) +#define uv_udp_fd(handle) ((handle)->socket) +#else +#define uv_udp_fd(handle) ((handle)->io_watcher.fd) +#endif + uv_udp_handle_t::~uv_udp_handle_t() { clear_write_cached_requests(); @@ -13,6 +19,7 @@ void uv_udp_handle_t::open(request_udp_open_t& request) { uv_udp_t* server = (uv_udp_t*)m_handle; if ((!request.m_ipv6 ? uv_udp_bind(server, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port), 0) == 0 : uv_udp_bind6(server, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port), 0) == 0)) { + m_udp_sock = uv_udp_fd((uv_udp_t*)server); if (!singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_UDP_OPEN, (void*)this)) { uv_close((uv_handle_t*)server, on_closed); } diff --git a/src/uv_udp_handle.h b/src/uv_udp_handle.h index e580e0e..386491a 100644 --- a/src/uv_udp_handle.h +++ b/src/uv_udp_handle.h @@ -16,9 +16,11 @@ class uv_udp_handle_t : public uv_handle_base_t public: uv_udp_handle_t(uv_loop_t* loop, uint32_t source) : uv_handle_base_t(loop, UV_UDP, source), - m_read_started(false) {} + m_read_started(false), + m_udp_sock(-1) {} ~uv_udp_handle_t(); + friend class lua_udp_handle_t; private: static void on_read(uv_udp_t* handle, ssize_t nread, uv_buf_t buf, struct sockaddr* addr, unsigned flags); static uv_buf_t on_read_alloc(uv_handle_t* handle, size_t suggested_size); @@ -35,6 +37,7 @@ class uv_udp_handle_t : public uv_handle_base_t static void write(request_udp_write_t& request); private: bool m_read_started; + uv_os_sock_t m_udp_sock; typedef struct { uv_udp_send_t m_write_req; From 6b92ac29a919ec68d8c8d785850ecf5021d9faef Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 18 Apr 2016 17:11:08 +0800 Subject: [PATCH 066/173] =?UTF-8?q?=E4=BC=98=E5=8C=96udp=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/main.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sample/main.lua b/sample/main.lua index d3ae523..c3a89bf 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -81,18 +81,23 @@ local result, client2 = udp.open() client1:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, client) print("client1 read callback: ", result, buffer, remote_addr, remote_port, remote_ipv6, client) + client1:close() end) client2:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, client) print("client2 read callback: ", result, buffer, remote_addr, remote_port, remote_ipv6, client) + client2:close() end) print("client1:write ", client1:write("hello, world1!", "127.0.0.1", 8081, true)) print("client2:write ", client2:write("hello, world2!", "127.0.0.1", 8081, true)) -print("client1:addr ", client1:local_addr(), client1:local_port()) -print("client2:addr ", client2:local_addr(), client2:local_port()) +print("client1:addr ", client1:local_addr(), client1:local_port(), client1:remote_addr(), client1:remote_port()) +print("client2:addr ", client2:local_addr(), client2:local_port(), client2:remote_addr(), client2:remote_port()) -timer.sleep(3600) +timer.sleep(0.1) +server:close() + +--timer.sleep(3600) do return end From 62f47da2ca9439a66b3368531a0df6acf2e8ff29 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 19 Apr 2016 18:37:56 +0800 Subject: [PATCH 067/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=A1=B9=E7=9B=AEwik?= =?UTF-8?q?i=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wiki/Design.md | 7 +++++++ wiki/Home.md | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 wiki/Design.md create mode 100644 wiki/Home.md diff --git a/wiki/Design.md b/wiki/Design.md new file mode 100644 index 0000000..83b5ed1 --- /dev/null +++ b/wiki/Design.md @@ -0,0 +1,7 @@ +# node-lua设计 +## 该引擎当前版本实现了以下特性: + +## node-lua在下个版本将会提供以下新功能和特性: + +## 写在最后 + diff --git a/wiki/Home.md b/wiki/Home.md new file mode 100644 index 0000000..d88049d --- /dev/null +++ b/wiki/Home.md @@ -0,0 +1,27 @@ +Welcome to the node-lua wiki! +## node-lua简介 +node-lua是一款基于lua实现的脚本和服务器引擎,它支持构建海量lua服务(context_lua)并以多线程方式运行在多核服务器上,采用了任务多路复用的设计方案,有效利用了多核优势。node-lua致力于构建一个快速、简单易用的lua脚本和服务器开发和运行环境。该引擎参考了node-js和skynet的设计思想,并对其进行了整合和优化。 + +## 该引擎当前版本实现了以下特性: +1. 引擎核心层同时支持同步阻塞和异步回调的api设计方案,让异步io等接口更加简单易用。调用同步和异步api时引擎核心层将会自动挂起正在执行的lua函数(coroutine),直接放弃占用的cpu资源; +2. 服务创建以指定lua文件为入口脚本文件,脚本直接运行在新服务的coroutine环境中,支持在入口脚本当中直接调用同步和异步api接口,支持无限循环调用同步api接口; +3. 可以创建海量独立的lua服务(context_lua),引擎会根据当前运行服务总量和物理核心数量动态调整工作线程数量,当引擎没有需要处理的服务请求时(即任务队列为空),所有物理线程将会挂起等待,直到有新的任务(lua同步和异步回调)需要被唤醒运行; +4. 支持在用户创建的lua coroutine中直接调用引擎提供的同步和异步api接口,对用户态coroutine执行不会产生任何影响; +5. 引擎会检测进程当中有效的lua服务总量,当服务总量为0时,引擎会自动安全退出(可以用node-lua作为简单的lua脚本解释器使用)。同时,lua服务也会检测服务当中运行和挂起的同步和异步回调总量,当回调总量为0时,lua服务会被标记并安全退出; +6. 引擎框架任务调度采用了线程任务队列的设计,减少了不同线程之间对任务资源的竞争。另外,任务调度也引入了work-stealing算法对调度进行了深度优化; +7. 引擎提供了tcp socket相关的大部分api接口,同时支持unix_domain_socket; +8. 引擎提供了lua服务相关的api接口,包括服务创建、销毁、通信等同步和异步接口; +9. 引擎提供了定时相关的api接口,基本满足所有的定时设计,并直接被嵌入到了其它同步和异步api接口当中(tcp,服务相关的api等); +10. 引擎提供了快速lua字符串缓存结构,可以用于高效的广播接口当中; +11. 引擎当前提供了centos,macos,windows环境下的编译和安装; + +## node-lua在下个版本将会提供以下新功能和特性: +1. udp接口支持; +2. tcp和udp socket在lua服务之间的迁移; +3. 在线服务热更新; +4. 在线服务调试; +5. 提供FreeBSD等环境下的编译和安装; +6. 提供基准测试版本; + +## 写在最后 +欢迎大家发现node-lua当中的bug,对node-lua提出更好的建议! \ No newline at end of file From 41c71128e385f95aba5603181526cb54d2359848 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 19 Apr 2016 21:05:23 +0800 Subject: [PATCH 068/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=A1=B9=E7=9B=AEwik?= =?UTF-8?q?i=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wiki/Design.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/wiki/Design.md b/wiki/Design.md index 83b5ed1..d9660f3 100644 --- a/wiki/Design.md +++ b/wiki/Design.md @@ -1,7 +1,12 @@ # node-lua设计 -## 该引擎当前版本实现了以下特性: - -## node-lua在下个版本将会提供以下新功能和特性: - -## 写在最后 - +##引擎架构 +##消息转发 +1. 多线程 任务多路复用 +2. 线程队列 +3. 优化work-stealing +##服务管理,context设计 +##网络层设计 +##同步、异步底层设计,coroutine管理,初始化设计 +##tcp,udp设计 +##timer设计 +##buffer设计 From 2e4233530b2a01675363e5d99c02f1cf91882399 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 21 Apr 2016 16:36:12 +0800 Subject: [PATCH 069/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0node=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f7723af..a15cc7a 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ For windows, just open node-lua.sln and build the whole solution. For linux or o cd node-lua make [release] #add release to build for release versions make install +## contact +See https://github.com/socoding/node-lua/wiki for detailed node-lua description. +Contact with **Email: xdczju@sina.com** or **QQ: 443231647** ## usefull api ### context api From ff934a3275e776fd75e89bc5448d29301e8629c6 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 21 Apr 2016 18:10:15 +0800 Subject: [PATCH 070/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dhttp=E5=BA=93?= =?UTF-8?q?=E5=9C=A8lua5.3=E4=B8=8B=E7=9A=84=E5=85=BC=E5=AE=B9=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lualib/ltn12.lua | 8 +++--- lualib/socket_core.lua | 1 + lualib/url.lua | 4 +-- node-lua.lua | 56 ------------------------------------------ 4 files changed, 8 insertions(+), 61 deletions(-) diff --git a/lualib/ltn12.lua b/lualib/ltn12.lua index b42689a..75471f3 100644 --- a/lualib/ltn12.lua +++ b/lualib/ltn12.lua @@ -38,14 +38,15 @@ end -- chains a bunch of filters together -- (thanks to Wim Couwenberg) function filter.chain(...) - local n = table.getn(arg) + local arg = { ... } + local n = #arg local top, index = 1, 1 local retry = "" return function(chunk) retry = chunk and retry while true do if index == top then - chunk = arg[index](chunk) + chunk = arg[index](chunk) if chunk == "" or top == n then return chunk elseif chunk then index = index + 1 else @@ -53,7 +54,7 @@ function filter.chain(...) index = top end else - chunk = arg[index](chunk or "") + chunk = arg[index](chunk or "") if chunk == "" then index = index - 1 chunk = retry @@ -186,6 +187,7 @@ end -- other, as if they were concatenated -- (thanks to Wim Couwenberg) function source.cat(...) + local arg = {...} local src = table.remove(arg, 1) return function() while src do diff --git a/lualib/socket_core.lua b/lualib/socket_core.lua index 7dcaf5a..d0c4a3a 100644 --- a/lualib/socket_core.lua +++ b/lualib/socket_core.lua @@ -103,6 +103,7 @@ end function lua_tcp_mode:settimeout(timeout) self._timeout = timeout + return true end function lua_tcp_mode:setoption(field, value) diff --git a/lualib/url.lua b/lualib/url.lua index ebf99fa..950ff21 100644 --- a/lualib/url.lua +++ b/lualib/url.lua @@ -254,7 +254,7 @@ function parse_path(path) path = path or "" --path = string.gsub(path, "%s", "") string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) - for i = 1, table.getn(parsed) do + for i = 1, #parsed do parsed[i] = unescape(parsed[i]) end if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end @@ -272,7 +272,7 @@ end ----------------------------------------------------------------------------- function build_path(parsed, unsafe) local path = "" - local n = table.getn(parsed) + local n = #parsed if unsafe then for i = 1, n-1 do path = path .. parsed[i] diff --git a/node-lua.lua b/node-lua.lua index 3ddf31c..419aa37 100644 --- a/node-lua.lua +++ b/node-lua.lua @@ -1,59 +1,3 @@ -1. result, listen_socket = tcp.listen(addr, port[, backlog, [void (*listen_callback)(result, listen_socket, addr, port[, backlog])]]) - --listen_callback is a once callback, blocking if callback is nil. -2. result, listen_socket = tcp.listens(sock_name[, void (*listen_callback)(result, listen_socket, sock_name)]) - --listen_callback is a once callback, blocking if callback is nil. -3. result, listen_socket = tcp.listen6(addr, port[, backlog, [void (*listen_callback)(result, listen_socket, addr, port[, backlog])]]) - --listen_callback is a once callback, blocking if callback is nil. -4. result, accept_socket = tcp.accept(listen_socket[, timeout]) - --accept_callback is a continues callback, blocking if callback is nil. -5. result, accept_socket = tcp.accept(listen_socket[, void (*accept_callback)(result, accept_socket, listen_socket)]) - --accept_callback is a continues callback, blocking if callback is nil. -6. result, connect_socket = tcp.connect(host_addr, host_port[, timeout [, void (*connect_callback)(result, connect_socket, host_addr, host_port[, timeout])]]) - --connect_callback is a once callback, blocking if callback is nil. -7. result, connect_socket = tcp.connects(sock_name[, timeout [, void (*connect_callback)(result, connect_socket, host_addr, host_port[, timeout])]]) - --connect_callback is a once callback, blocking if callback is nil. -8. result, connect_socket = tcp.connect6(host_addr, host_port[, timeout [, void (*connect_callback)(result, connect_socket, host_addr, host_port[, timeout])]]) - --connect_callback is a once callback, blocking if callback is nil. -9. result, buffer = tcp.read(socket[, timeout]) - --recv_callback is a continues callback, blocking if callback is nil. -10. result, buffer = tcp.read(socket[, void (*recv_callback)(result, buffer, socket)]) - --recv_callback is a continues callback, blocking if callback is nil. -11. result, error = tcp.write(socket, buffer_or_lstring[, void (*send_callback)(result, error, socket, buffer_or_lstring)/bool safety]) - --send_callback is a once callback and is safety assurance, blocking until buffer_or_lstring is sent only if safety is true. -12. tcp.set_rwopt(socket, option_table) - --set tcp_socket read and write options --e.g. { "read_head_endian" = "L", "read_head_bytes" = 2, "read_head_max" = 65535, } -13. tcp.get_rwopt(socket) - --get tcp_socket read and write options - -14. tcp.set_nodelay(socket, enable) - -15. result, error = context.send(handle, data1, data2, ...) --QUERY - -16. result, query_data1, query_data2, ... = context.query(handle, data1, data2, ... [, query_callback(result, query_data1, query_data2, ...)]]) --QUERY(real query) - --query_callback is a once callback, blocking if callback is nil. - -17. result, query_data1, query_data2, ... = context.timed_query(handle, timeout, data1, data2, ... [, query_callback(result, query_data1, query_data2, ...)]]) --QUERY(real query) - --query_callback is a once callback, blocking if callback is nil. - -18. result, error = context.reply(handle, session, data1, data2, ...) --REPLY - -19. result, recv_handle, session, data1, data2, ... = context.recv(handle[, timeout]) - --recv_callback is a continues callback, blocking if callback is nil. - -20. result, recv_handle, session, data1, data2, ... = context.recv(handle[, recv_callback(result, recv_handle, session, data1, data2, ... )]) - --recv_callback is a continues callback, blocking if callback is nil. - -21. result, error = context.wait(handle[, timeout[, callback(result, error, handle[, timeout])]]) - --connect_callback is a once callback, blocking if callback is nil. - -22. timer.sleep(seconds) - -23. timer.timeout(seconds, ..., void (*callback)(...)) - -24. timer.loop(interval, repeat_time, ..., void (*callback)(...)) - ----------------------------------------------------------------------------------------------------------------------------- - 14. 考虑lua_service的gc[考虑一直没有唤醒的服务的lua垃圾回收] 17. 研究lua hook,如何中断死循环和调试(输入) From 889c3b5ca9c6b0e22b019e61caf5cc75bf183f50 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 21 Apr 2016 18:12:49 +0800 Subject: [PATCH 071/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dhttp=E5=BA=93?= =?UTF-8?q?=E5=9C=A8lua5.3=E4=B8=8B=E7=9A=84=E5=85=BC=E5=AE=B9=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lualib/ltn12.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lualib/ltn12.lua b/lualib/ltn12.lua index 75471f3..ffdd7c4 100644 --- a/lualib/ltn12.lua +++ b/lualib/ltn12.lua @@ -46,7 +46,7 @@ function filter.chain(...) retry = chunk and retry while true do if index == top then - chunk = arg[index](chunk) + chunk = arg[index](chunk) if chunk == "" or top == n then return chunk elseif chunk then index = index + 1 else @@ -54,7 +54,7 @@ function filter.chain(...) index = top end else - chunk = arg[index](chunk or "") + chunk = arg[index](chunk or "") if chunk == "" then index = index - 1 chunk = retry From 8e999c0070944bd9f203657e7a0ccdea75416d69 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 21 Apr 2016 20:57:02 +0800 Subject: [PATCH 072/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dhttp=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E7=9B=B8=E5=85=B3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lualib/http.lua | 2 +- lualib/socket.lua | 5 ++--- lualib/socket_core.lua | 21 ++++++++++++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/lualib/http.lua b/lualib/http.lua index ccd2c3f..43a48b8 100644 --- a/lualib/http.lua +++ b/lualib/http.lua @@ -49,7 +49,7 @@ local function receiveheaders(sock, headers) -- unfold any folded values while string.find(line, "^%s") do value = value .. line - line = sock:receive() + line, err = sock:receive() if err then return nil, err end end -- save pair in table diff --git a/lualib/socket.lua b/lualib/socket.lua index 7ec753e..382bd03 100644 --- a/lualib/socket.lua +++ b/lualib/socket.lua @@ -72,7 +72,7 @@ end socket.sinkt["default"] = socket.sinkt["keep-open"] -socket.sink = socket.choose(sinkt) +socket.sink = socket.choose(socket.sinkt) socket.sourcet["by-length"] = function(sock, length) return base.setmetatable({ @@ -111,7 +111,6 @@ end socket.sourcet["default"] = socket.sourcet["until-closed"] - -socket.source = socket.choose(sourcet) +socket.source = socket.choose(socket.sourcet) return socket \ No newline at end of file diff --git a/lualib/socket_core.lua b/lualib/socket_core.lua index d0c4a3a..089651b 100644 --- a/lualib/socket_core.lua +++ b/lualib/socket_core.lua @@ -137,6 +137,7 @@ local function try_read(tcp_socket) tcp_socket._received_buffer:append(buffer) end else + --to be fix : half close http??? tcp_socket._sock:close() tcp_socket._sock = nil tcp_socket._received_buffer = nil @@ -145,45 +146,47 @@ local function try_read(tcp_socket) end -function lua_tcp_mode:receive(len) +function lua_tcp_mode:receive(len, header) local sock = self._sock if not sock or sock:is_closed() then - return false, "socket not invalid or closed" + return "", "socket not invalid or closed" end if not len or len == '*l' then if not self._received_buffer or self._received_buffer:length() == 0 then local error = try_read(self) if error then - return false, error + return "", error end end while true do local len = self._received_buffer:find("\n") if len then - return self._received_buffer:split(len):tostring() + local received = self._received_buffer:split(len):tostring() + return header and header..received or received end local error = try_read(self) if error then - return false, error + return "", error end end end if type(len) == "number" then if len <= 0 then - return false, "receive length can't be less than 0" + return "", "receive length can't be less than 0" end while not self._received_buffer or self._received_buffer:length() < len do local error = try_read(self) if error then - return false, error + return "", error end end - return self._received_buffer:split(len):tostring() + local received = self._received_buffer:split(len):tostring() + return header and header..received or received end - return false, "unsupported receive format" + return "", "unsupported receive format" end socket.tcp = lua_tcp_mode From fe82eb3e7ec91d71c09fe94a72deb65bf3c303e6 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 22 Apr 2016 16:11:39 +0800 Subject: [PATCH 073/173] =?UTF-8?q?=E4=BC=98=E5=8C=96tcp=E5=8D=8A=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E7=8A=B6=E6=80=81=E7=9A=84=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/uv_tcp_handle.cpp | 26 ++++++++++++++++++++------ src/uv_tcp_handle.h | 2 ++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 88f0711..ea2446f 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -349,14 +349,30 @@ void uv_tcp_socket_handle_t::write_read_buffer_finish(uv_err_code read_error) } } else { if (m_read_error == UV_OK) { - m_read_error = read_error; - singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_TCP_READ, m_read_error); + trigger_read_error(read_error); uv_read_stop((uv_stream_t*)m_handle); + } else { + clear_read_cached_buffers(); } - clear_read_cached_buffers(); } } +//when read error occurred, we need to send the cached buffer to lua_context in case of half closed peer socket. +//peer socket may only shut down write(half close) before totally close the socket. +void uv_tcp_socket_handle_t::trigger_read_error(uv_err_code read_error) +{ + int size = m_read_cached_buffers.size(); + for (int i = 0; i < size; ++i) { + singleton_ref(node_lua_t).context_send_buffer_release(m_source, 0, m_lua_ref, RESPONSE_TCP_READ, m_read_cached_buffers.front()); + m_read_cached_buffers.pop(); + } + buffer_release(m_read_buffer); + buffer_make_invalid(m_read_buffer); + singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_TCP_READ, m_read_error); + atomic_barrier(); + m_read_error = read_error; +} + /* When RESPONSE_TCP_READ error occurs, read request must also stop in context_lua thread. */ void uv_tcp_socket_handle_t::on_read(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { @@ -388,9 +404,7 @@ void uv_tcp_socket_handle_t::read(request_tcp_read_t& request) } if (!read_started && uv_read_start((uv_stream_t*)(m_handle), on_read_alloc, on_read) != 0) { if (!uv_is_closing((uv_handle_t*)(m_handle))) { - m_read_error = singleton_ref(network_t).last_error(); - singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_TCP_READ, m_read_error); - clear_read_cached_buffers(); + trigger_read_error(singleton_ref(network_t).last_error()); } } } diff --git a/src/uv_tcp_handle.h b/src/uv_tcp_handle.h index de07184..9564bbb 100644 --- a/src/uv_tcp_handle.h +++ b/src/uv_tcp_handle.h @@ -85,7 +85,9 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t int32_t write_handle(request_tcp_write_t& request); void write_read_buffer(ssize_t nread, uv_buf_t buf); void write_read_buffer_finish(uv_err_code err_code); + void trigger_read_error(uv_err_code read_error); void clear_read_cached_buffers(); + public: void connect_tcp(request_tcp_connect_t& request); void connect_sock(request_tcp_connects_t& request); From 71aae63554a286ef15c5b243e6a07b35efb96b07 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 25 Apr 2016 13:27:55 +0800 Subject: [PATCH 074/173] =?UTF-8?q?=E5=AE=8C=E5=96=84socket=E5=8D=8A?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E7=8A=B6=E6=80=81=E6=97=B6=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8E=A5=E6=94=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/errors.h | 17 +++++---- src/lua_tcp_handle.cpp | 84 +++++++++++++++++++++++++++--------------- src/lua_tcp_handle.h | 4 +- 3 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/errors.h b/src/errors.h index f0f2a2c..f57ad12 100644 --- a/src/errors.h +++ b/src/errors.h @@ -10,14 +10,15 @@ XX( 202, ESTACKLESS, "attempt to yield across a stack-less coroutine") \ XX( 203, ETCPSCLOSED, "tcp socket has been closed") \ XX( 204, ETCPLCLOSED, "tcp listen socket has been closed") \ - XX( 205, ENOCONTEXT, "context not exist or has been killed") \ - XX( 206, ETRANSTYPE, "transfer data type not supported") \ - XX( 207, ENOREPLY, "no reply") \ - XX( 208, ETIMEOUT, "timeout") \ - XX( 209, ETCPNOWSHARED, "tcp socket not set write shared") \ - XX( 210, ETCPWRITELONG, "attempt to send data too long") \ - XX( 211, EUDPSCLOSED, "udp socket has been closed") \ - XX( 212, EUDPNOWSHARED, "udp socket not set write shared") \ + XX( 205, ETCPNOWSHARED, "tcp socket not set write shared") \ + XX( 206, ETCPWRITELONG, "attempt to send data too long") \ + XX( 207, ETCPREADOVERFLOW,"read overflowed wake up") \ + XX( 208, EUDPSCLOSED, "udp socket has been closed") \ + XX( 209, EUDPNOWSHARED, "udp socket not set write shared") \ + XX( 210, ENOCONTEXT, "context not exist or has been killed") \ + XX( 211, ETRANSTYPE, "transfer data type not supported") \ + XX( 212, ENOREPLY, "no reply") \ + XX( 213, ETIMEOUT, "timeout") \ #define NL_ERRNO_GEN(val, name, s) NL_##name = val, typedef enum { diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index ab38688..d98b6fd 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -728,18 +728,6 @@ int32_t lua_tcp_socket_handle_t::read(lua_State* L) } /* error already occurred in network thread, stop read immediately. */ context_lua_t* lctx = context_lua_t::lua_get_context(L); - uv_err_code err = handle->get_read_error(); - if (err != UV_OK) { - if (nonblocking) { - socket->m_read_ref_sessions.make_nonblocking_callback(L, 1, context_lua_t::common_callback_adjust); - singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), socket->m_lua_ref, RESPONSE_TCP_READ, err); /* The message will wake up all blocking coroutine and nonblocking callback. */ - return 0; - } else { - lua_pushboolean(L, 0); - lua_pushinteger(L, err); - return 2; - } - } request_t& request = lctx->get_yielding_request(); request.m_type = REQUEST_TCP_READ; request.m_length = REQUEST_SIZE(request_tcp_read_t, 0); @@ -748,11 +736,11 @@ int32_t lua_tcp_socket_handle_t::read(lua_State* L) if (nonblocking) { /* nonblocking callback */ if (socket->m_read_ref_sessions.make_nonblocking_callback(L, 1, context_lua_t::common_callback_adjust)) { froze_head_option(handle->m_read_head_option); - if (socket->m_read_overflow_buffers.empty()) { + if (handle->get_read_error() == UV_OK) { singleton_ref(network_t).send_request(request); - } else { - singleton_ref(node_lua_t).context_send_buffer_release(lctx, lctx->get_handle(), socket->m_lua_ref, RESPONSE_TCP_READ, socket->m_read_overflow_buffers.front()); - socket->m_read_overflow_buffers.pop(); + } + if (!socket->m_read_overflow_buffers.empty()) { //do read over flow wake up(whether read error occurred or not)!!! + singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), socket->m_lua_ref, RESPONSE_TCP_READ, NL_ETCPREADOVERFLOW); } } return 0; @@ -769,15 +757,20 @@ int32_t lua_tcp_socket_handle_t::read_yield_finalize(lua_State *root_coro, lua_S int32_t session = socket->m_read_ref_sessions.push_blocking(root_coro); uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)socket->m_uv_handle; froze_head_option(handle->m_read_head_option); - if (socket->m_read_overflow_buffers.empty()) { - singleton_ref(network_t).send_request(lctx->get_yielding_request()); + if (handle->get_read_error() == UV_OK) { + if (socket->m_read_timeout_session_count == 0) { + singleton_ref(network_t).send_request(lctx->get_yielding_request()); + } + --socket->m_read_timeout_session_count; int64_t timeout = lctx->get_yielding_timeout(); if (timeout > 0) { context_lua_t::lua_ref_timer(main_coro, session, timeout, 0, false, socket, read_timeout); } - } else { - singleton_ref(node_lua_t).context_send_buffer_release(lctx, lctx->get_handle(), socket->m_lua_ref, RESPONSE_TCP_READ, socket->m_read_overflow_buffers.front()); - socket->m_read_overflow_buffers.pop(); + if (!socket->m_read_overflow_buffers.empty()) { //do read over flow wake up(whether read error occurred or not)!!! + singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), socket->m_lua_ref, RESPONSE_TCP_READ, NL_ETCPREADOVERFLOW); + } + } else { //wake up the blocking read directly + singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), socket->m_lua_ref, RESPONSE_TCP_READ, NL_ETCPREADOVERFLOW); } } return UV_OK; @@ -788,7 +781,11 @@ int32_t lua_tcp_socket_handle_t::read_timeout(lua_State *L, int32_t session, voi lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)userdata; context_lua_t* lctx = context_lua_t::lua_get_context(L); message_t message(0, session, RESPONSE_TCP_READ, NL_ETIMEOUT); - return socket->m_read_ref_sessions.wakeup_one_fixed(lctx, message, false); + if (socket->m_read_ref_sessions.wakeup_one_fixed(lctx, message, false)) { + ++socket->m_read_timeout_session_count; + return 1; + } + return 0; } static void opt_check_endian(lua_State* L, int32_t idx, const char* field, char *value, bool frozen) @@ -1027,15 +1024,29 @@ int32_t lua_tcp_socket_handle_t::wakeup_read(lua_State* L, message_t& message) lua_tcp_socket_handle_t* socket = (lua_tcp_socket_handle_t*)get_lua_handle(L, message.m_session, SOCKET_SET); if (socket) { if (!socket->is_closed()) { - if (message_is_buffer(message)) { - if (socket->m_read_ref_sessions.wakeup_once(lctx, message)) { + if (socket->m_read_overflow_buffers.empty()) { + if (message_is_buffer(message)) { + if (socket->m_read_ref_sessions.wakeup_once(lctx, message)) { + return 1; + } + socket->m_read_overflow_buffers.push(buffer_grab(message_buffer(message))); + return 0; + } //else empty overflow buffers + goto handle_error; + } else { + if (message_is_buffer(message)) { + socket->m_read_overflow_buffers.push(buffer_grab(message_buffer(message))); + } + while (!socket->m_read_ref_sessions.is_empty() && !socket->m_read_overflow_buffers.empty()) { + message_t overflow_message(0, socket->m_lua_ref, RESPONSE_TCP_READ, socket->m_read_overflow_buffers.front()); + socket->m_read_overflow_buffers.pop(); + socket->m_read_ref_sessions.wakeup_once(lctx, overflow_message); + buffer_release(message_buffer(overflow_message)); + } + if (!socket->m_read_overflow_buffers.empty()) { return 1; } - socket->m_read_overflow_buffers.push(buffer_grab(message_buffer(message))); - } - if (message_is_error(message)) { - socket->m_read_ref_sessions.wakeup_all(lctx, message); - return 1; + goto handle_error; } return 0; } else { /* listen socket is already closed */ @@ -1046,6 +1057,21 @@ int32_t lua_tcp_socket_handle_t::wakeup_read(lua_State* L, message_t& message) } } return 0; + +handle_error: + if (message_is_error(message)) { + uv_err_code err = ((uv_tcp_socket_handle_t*)socket->m_uv_handle)->get_read_error(); + if (err != UV_OK || message_error(message) != NL_ETCPREADOVERFLOW) { //if it's over flow wakeup, do nothing!!! + if (message_error(message) != NL_ETCPREADOVERFLOW) { + socket->m_read_ref_sessions.wakeup_all(lctx, message); + } else { + message_t error = message_t(0, socket->m_lua_ref, RESPONSE_TCP_READ, err); + socket->m_read_ref_sessions.wakeup_all(lctx, error); + } + return 1; + } + } + return 0; } int32_t lua_tcp_socket_handle_t::close(lua_State* L) diff --git a/src/lua_tcp_handle.h b/src/lua_tcp_handle.h index 24a70b0..ba02896 100644 --- a/src/lua_tcp_handle.h +++ b/src/lua_tcp_handle.h @@ -47,7 +47,8 @@ class lua_tcp_socket_handle_t : public lua_handle_base_t { public: lua_tcp_socket_handle_t(uv_tcp_socket_handle_t* handle, lua_State* L) - : lua_handle_base_t((uv_handle_base_t*)handle, L) {} + : lua_handle_base_t((uv_handle_base_t*)handle, L), + m_read_timeout_session_count(0) {} ~lua_tcp_socket_handle_t(); public: @@ -84,6 +85,7 @@ class lua_tcp_socket_handle_t : public lua_handle_base_t private: void release_read_overflow_buffers(); private: + int32_t m_read_timeout_session_count; //blocking ref_sessions_t m_read_ref_sessions; std::queue m_read_overflow_buffers; }; From 601bdbcb3854de78bc729030059026d6500396e2 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 25 Apr 2016 13:40:27 +0800 Subject: [PATCH 075/173] =?UTF-8?q?=E5=AE=8C=E5=96=84socket=E5=8D=8A?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E7=8A=B6=E6=80=81=E6=97=B6=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8E=A5=E6=94=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lua_tcp_handle.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index d98b6fd..17ad59e 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -760,8 +760,9 @@ int32_t lua_tcp_socket_handle_t::read_yield_finalize(lua_State *root_coro, lua_S if (handle->get_read_error() == UV_OK) { if (socket->m_read_timeout_session_count == 0) { singleton_ref(network_t).send_request(lctx->get_yielding_request()); + } else { + --socket->m_read_timeout_session_count; } - --socket->m_read_timeout_session_count; int64_t timeout = lctx->get_yielding_timeout(); if (timeout > 0) { context_lua_t::lua_ref_timer(main_coro, session, timeout, 0, false, socket, read_timeout); From 2dc48d553c6c925c7dc9914452b18e985f215c3e Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 25 Apr 2016 15:01:22 +0800 Subject: [PATCH 076/173] =?UTF-8?q?=E5=AE=8C=E5=96=84socket=E5=8D=8A?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E7=8A=B6=E6=80=81=E6=97=B6=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8E=A5=E6=94=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/uv_tcp_handle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index ea2446f..7b22c02 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -368,7 +368,7 @@ void uv_tcp_socket_handle_t::trigger_read_error(uv_err_code read_error) } buffer_release(m_read_buffer); buffer_make_invalid(m_read_buffer); - singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_TCP_READ, m_read_error); + singleton_ref(node_lua_t).context_send(m_source, 0, m_lua_ref, RESPONSE_TCP_READ, read_error); atomic_barrier(); m_read_error = read_error; } From c8bea6d2d8e44baf54dbc76ca0d3f547e2aea5fd Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 25 Apr 2016 19:35:06 +0800 Subject: [PATCH 077/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dhttp=E7=AC=AC?= =?UTF-8?q?=E4=B8=89=E6=96=B9=E9=9D=9E=E6=A0=B8=E5=BF=83=E5=BA=93=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lualib/http.lua | 8 ++++++-- lualib/socket_core.lua | 14 ++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lualib/http.lua b/lualib/http.lua index 43a48b8..c6e7a0a 100644 --- a/lualib/http.lua +++ b/lualib/http.lua @@ -39,6 +39,10 @@ local function receiveheaders(sock, headers) if err then return nil, err end -- headers go until a blank line is found while line ~= "" do + --header ends if line == "\r\n" + if line == "\r\n" then + return headers + end -- get field-name and value name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) if not (name and value) then return nil, "malformed reponse headers" end @@ -46,8 +50,8 @@ local function receiveheaders(sock, headers) -- get next line (value might be folded) line, err = sock:receive() if err then return nil, err end - -- unfold any folded values - while string.find(line, "^%s") do + -- unfold any folded values(header parts begin with [ \t]!) + while string.find(line, "^[ \t]") do value = value .. line line, err = sock:receive() if err then return nil, err end diff --git a/lualib/socket_core.lua b/lualib/socket_core.lua index 089651b..69feff2 100644 --- a/lualib/socket_core.lua +++ b/lualib/socket_core.lua @@ -137,10 +137,7 @@ local function try_read(tcp_socket) tcp_socket._received_buffer:append(buffer) end else - --to be fix : half close http??? - tcp_socket._sock:close() - tcp_socket._sock = nil - tcp_socket._received_buffer = nil + tcp_socket:close() return context.strerror(buffer) end end @@ -189,6 +186,15 @@ function lua_tcp_mode:receive(len, header) return "", "unsupported receive format" end +function lua_tcp_mode:close() + if self._sock then + self._sock:close() + self._sock = nil + self._received_buffer = nil + end + return true +end + socket.tcp = lua_tcp_mode return socket From 0810b958e8937863c91825d616bbc58d3f72ac1d Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 26 Apr 2016 21:24:38 +0800 Subject: [PATCH 078/173] =?UTF-8?q?tcp.connect=E5=A2=9E=E5=8A=A0dns?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.cpp | 23 +++++++++++++-- src/utils.h | 2 +- src/uv_tcp_handle.cpp | 66 +++++++++++++++++++++++++++++++++++++++---- src/uv_tcp_handle.h | 1 + 4 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/utils.cpp b/src/utils.cpp index 5f8a1e6..e25d0a1 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -29,7 +29,7 @@ char* filter_arg(char **param, int32_t *len) { } } -extern void* nl_memdup(const void* src, uint32_t len) +void* nl_memdup(const void* src, uint32_t len) { if (src) { if (len != 0) { @@ -44,7 +44,7 @@ extern void* nl_memdup(const void* src, uint32_t len) return NULL; } -extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, bool* ipv6, uint16_t* port) +bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, bool* ipv6, uint16_t* port) { union sock_name_u { sockaddr_in sock4; @@ -86,7 +86,7 @@ extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host return false; } -extern bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, bool* ipv6, uint16_t* port) +bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, bool* ipv6, uint16_t* port) { uint16_t family = addr->sa_family; if (family == AF_INET) { @@ -115,3 +115,20 @@ extern bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, } return false; } + +uv_err_code host_sockaddr(bool ipv6, const char* host, uint16_t port, struct sockaddr* addr) +{ + if (!ipv6) { + struct sockaddr_in* addr4 = (struct sockaddr_in*)addr; + memset(addr4, 0, sizeof(struct sockaddr_in)); + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port); + return uv_inet_pton(AF_INET, host, (void*)&addr4->sin_addr).code; + } else { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr; + memset(addr6, 0, sizeof(struct sockaddr_in6)); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(port); + return uv_inet_pton(AF_INET6, host, (void*)&addr6->sin6_addr).code; + } +} \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index 91ae2be..c67b2fa 100644 --- a/src/utils.h +++ b/src/utils.h @@ -6,5 +6,5 @@ extern char* filter_arg(char **param, int32_t *len); extern void* nl_memdup(const void* src, uint32_t len); extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, bool* ipv6, uint16_t* port); extern bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, bool* ipv6, uint16_t* port); - +extern uv_err_code host_sockaddr(bool ipv6, const char* host, uint16_t port, struct sockaddr* addr); #endif diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 7b22c02..19dd89d 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -97,6 +97,12 @@ void uv_tcp_listen_handle_t::accept(request_tcp_accept_t& request) ///////////////////////////////////////////////////////////////////////////////////////////////////////// #define LARGE_UNCOMPLETE_LIMIT (1 * 1024) +typedef struct { + uv_getaddrinfo_t m_request; + uv_tcp_t *m_client; + uint32_t m_session; +} uv_addr_resolver_t; + uv_tcp_socket_handle_t::~uv_tcp_socket_handle_t() { clear_read_cached_buffers(); @@ -123,6 +129,29 @@ void uv_tcp_socket_handle_t::on_connect(uv_connect_t* req, int status) nl_free(req); } +void uv_tcp_socket_handle_t::on_resolve(uv_getaddrinfo_t* req, int status, struct addrinfo* res) +{ + uv_addr_resolver_t* resolver = (uv_addr_resolver_t*)(req->data); + uv_tcp_socket_handle_t *client_handle = (uv_tcp_socket_handle_t*)resolver->m_client; + if (status == 0) { + struct sockaddr_in* addr = (struct sockaddr_in*)res->ai_addr; + uv_tcp_t* client = (uv_tcp_t*)client_handle->m_handle; + uv_connect_t* req = (uv_connect_t*)nl_malloc(sizeof(*req)); + req->data = (void*)resolver->m_session; + if ((addr->sin_family == AF_INET) ? uv_tcp_connect(req, client, *(struct sockaddr_in*)addr, on_connect) != 0 : uv_tcp_connect6(req, client, *(struct sockaddr_in6*)addr, on_connect) != 0) { + singleton_ref(node_lua_t).context_send(client_handle->m_source, 0, resolver->m_session, RESPONSE_TCP_CONNECT, singleton_ref(network_t).last_error()); + uv_close((uv_handle_t*)client, on_closed); + nl_free(req); + } + nl_free(resolver); + uv_freeaddrinfo(res); + } else { + singleton_ref(node_lua_t).context_send(client_handle->m_source, 0, resolver->m_session, RESPONSE_TCP_CONNECT, singleton_ref(network_t).last_error()); + uv_close((uv_handle_t*)client_handle, on_closed); + nl_free(resolver); + } +} + void uv_tcp_socket_handle_t::connect_tcp(request_tcp_connect_t& request) { uv_tcp_t *client = (uv_tcp_t*)m_handle; @@ -135,12 +164,39 @@ void uv_tcp_socket_handle_t::connect_tcp(request_tcp_connect_t& request) return; } } - uv_connect_t* req = (uv_connect_t*)nl_malloc(sizeof(*req)); - req->data = (void*)request.m_session; - if (!request.m_remote_ipv6 ? uv_tcp_connect(req, client, uv_ip4_addr(remote_host, request.m_remote_port), on_connect) != 0 : uv_tcp_connect6(req, client, uv_ip6_addr(remote_host, request.m_remote_port), on_connect) != 0) { - singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_CONNECT, singleton_ref(network_t).last_error()); + union { + sockaddr_in addr4; + sockaddr_in6 addr6; + } sock_addr; + uv_err_code err = host_sockaddr(request.m_remote_ipv6, remote_host, request.m_remote_port, (struct sockaddr*)&sock_addr); + if (err == UV_OK) { + uv_connect_t* req = (uv_connect_t*)nl_malloc(sizeof(*req)); + req->data = (void*)request.m_session; + if (!request.m_remote_ipv6 ? uv_tcp_connect(req, client, sock_addr.addr4, on_connect) != 0 : uv_tcp_connect6(req, client, sock_addr.addr6, on_connect) != 0) { + singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_CONNECT, singleton_ref(network_t).last_error()); + uv_close((uv_handle_t*)client, on_closed); + nl_free(req); + } + } else if (err == UV_EINVAL) { //try resolve host name + char port[8]; + struct addrinfo hints; + hints.ai_family = !request.m_remote_ipv6 ? AF_INET : AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = 0; + uv_addr_resolver_t* resolver = (uv_addr_resolver_t*)nl_malloc(sizeof(uv_addr_resolver_t)); + itoa(request.m_remote_port, port, 10); + resolver->m_client = client; + resolver->m_session = request.m_session; + resolver->m_request.data = resolver; + if (uv_getaddrinfo(client->loop, &resolver->m_request, on_resolve, remote_host, port, &hints) != 0) { + singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_CONNECT, singleton_ref(network_t).last_error()); + uv_close((uv_handle_t*)client, on_closed); + nl_free(resolver); + } + } else { + singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_CONNECT, err); uv_close((uv_handle_t*)client, on_closed); - nl_free(req); } } diff --git a/src/uv_tcp_handle.h b/src/uv_tcp_handle.h index 9564bbb..22f7e08 100644 --- a/src/uv_tcp_handle.h +++ b/src/uv_tcp_handle.h @@ -78,6 +78,7 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t friend class lua_tcp_socket_handle_t; private: static void on_connect(uv_connect_t* req, int status); + static void on_resolve(uv_getaddrinfo_t* req, int status, struct addrinfo* res); static void on_write(uv_write_t* req, int status); static void on_read(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); static uv_buf_t on_read_alloc(uv_handle_t* handle, size_t suggested_size); /* return shared read buffer */ From 8698fd2621f6f0c6995881fb198ba5b463068ed2 Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 27 Apr 2016 00:19:13 +0800 Subject: [PATCH 079/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbuffer=5Ft=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E5=86=85=E5=AD=98=E7=9A=84bug=E5=92=8C=E5=9F=9F?= =?UTF-8?q?=E5=90=8D=E8=A7=A3=E6=9E=90=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/buffer.cpp | 4 ++-- src/uv_tcp_handle.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/buffer.cpp b/src/buffer.cpp index 0b4bd39..12346d2 100644 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -62,8 +62,8 @@ bool buffer_append(buffer_t& buffer_ref, const char *data, size_t data_len) { if (new_buffer) { if (offset >= 0) data = (char*)new_buffer + offset; new_buffer->m_cap = new_cap; - new_buffer->m_len = buffer->m_len + data_len; - memcpy(new_buffer->m_data + buffer->m_len, data, data_len); + memcpy(new_buffer->m_data + new_buffer->m_len, data, data_len); + new_buffer->m_len += data_len; new_buffer->m_data[new_buffer->m_len] = 0; buffer_ref.m_ptr = new_buffer; return true; diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 19dd89d..f2eb048 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -99,7 +99,7 @@ void uv_tcp_listen_handle_t::accept(request_tcp_accept_t& request) typedef struct { uv_getaddrinfo_t m_request; - uv_tcp_t *m_client; + uv_tcp_socket_handle_t *m_client; uint32_t m_session; } uv_addr_resolver_t; @@ -186,7 +186,7 @@ void uv_tcp_socket_handle_t::connect_tcp(request_tcp_connect_t& request) hints.ai_flags = 0; uv_addr_resolver_t* resolver = (uv_addr_resolver_t*)nl_malloc(sizeof(uv_addr_resolver_t)); itoa(request.m_remote_port, port, 10); - resolver->m_client = client; + resolver->m_client = this; resolver->m_session = request.m_session; resolver->m_request.data = resolver; if (uv_getaddrinfo(client->loop, &resolver->m_request, on_resolve, remote_host, port, &hints) != 0) { From 1589bcab6f14b791fafc07bf605509b9f0c1fc15 Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 27 Apr 2016 00:30:06 +0800 Subject: [PATCH 080/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9F=9F=E5=90=8D?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.cpp | 2 +- src/uv_tcp_handle.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6674df8..9d8a7f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,6 @@ int main(int argc, char* argv[], char* env[]) node_lua_t node(argc - 1, argv + 1, env); double duration = (uv_hrtime() - start_time) / 1e9; printf("Process used %.3f sec total!\n", duration); - //getchar(); + //getchar(); return 0; } diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index f2eb048..4ae2c05 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -133,9 +133,9 @@ void uv_tcp_socket_handle_t::on_resolve(uv_getaddrinfo_t* req, int status, struc { uv_addr_resolver_t* resolver = (uv_addr_resolver_t*)(req->data); uv_tcp_socket_handle_t *client_handle = (uv_tcp_socket_handle_t*)resolver->m_client; + uv_tcp_t* client = (uv_tcp_t*)client_handle->m_handle; if (status == 0) { struct sockaddr_in* addr = (struct sockaddr_in*)res->ai_addr; - uv_tcp_t* client = (uv_tcp_t*)client_handle->m_handle; uv_connect_t* req = (uv_connect_t*)nl_malloc(sizeof(*req)); req->data = (void*)resolver->m_session; if ((addr->sin_family == AF_INET) ? uv_tcp_connect(req, client, *(struct sockaddr_in*)addr, on_connect) != 0 : uv_tcp_connect6(req, client, *(struct sockaddr_in6*)addr, on_connect) != 0) { @@ -147,7 +147,7 @@ void uv_tcp_socket_handle_t::on_resolve(uv_getaddrinfo_t* req, int status, struc uv_freeaddrinfo(res); } else { singleton_ref(node_lua_t).context_send(client_handle->m_source, 0, resolver->m_session, RESPONSE_TCP_CONNECT, singleton_ref(network_t).last_error()); - uv_close((uv_handle_t*)client_handle, on_closed); + uv_close((uv_handle_t*)client, on_closed); nl_free(resolver); } } From 2e536ebbd500b3ea0b676a9fa296ffd69d29e74b Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 28 Apr 2016 21:40:19 +0800 Subject: [PATCH 081/173] a little thing --- node-lua.lua | 32 +++++++++++++++++++++++++++++++- node-lua.v12.suo | Bin 159744 -> 159744 bytes 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/node-lua.lua b/node-lua.lua index 419aa37..358219b 100644 --- a/node-lua.lua +++ b/node-lua.lua @@ -30,4 +30,34 @@ For examples, see my page of Lua libraries: http://www.tecgraf.puc-rio.br/~lhf/f You can link liblua.a statically into your main program but you have to export its symbols by adding -Wl,-E at link time. That's how the Lua interpreter is built in Linux. -A node completation of lua which support sync and async remote procedure call, and task-multiplexing support(in muti-thread mode with no useless wakeup) \ No newline at end of file +A node completation of lua which support sync and async remote procedure call, and task-multiplexing support(in muti-thread mode with no useless wakeup) + + +未初始化的指针错误: +有一个选择打开和关闭SDL检查的位置就是:项目属性->配置属性->C/C++->SDL检查,选测是或者否。 + +按照编译错误的提示来看应该是编译器没有识别inline参数。 +查阅了一下inline是c++里面的东西,在c里面使用是会发生错误。 +#define inline __inline + +Makefile 添加宏定义: -DDEBUG +传递参数: make PLATFORM=aaaa + +VS中添加预处理宏的方法: +除了在.c及.h中添加宏定义之外,还可以采用如下方法添加宏定义: +1、若只需要定义一个宏(如#define DEBUG),可以右键点击工程-->属性-->c/c++-->预处理器-->预处理器定义,点击下拉框中的编辑,输入想要定义的宏; +2、如果还需要定义宏的内容(如#define inline __inline),可以右键点击工程-->属性-->c/c++-->命令行,在其它选项中输入如下内容: /D"inline"=__inline 。 + + +snprintf()函数并不是标准c/c++中规定的函数,所以在许多编译器中,厂商提供了其相应的实现的版本。 +在gcc中,该函数名称就 snprintf(),而在VS中称为 _snprintf。 +所以在需要使用 snprintf()时改成_snprintf就可以了,或则在预编译处加入: +#if _MSC_VER +#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp +#endif + +#define __STDC_LIMIT_MACROS + + diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 7e630ce29613f2a3eabde2226b28104dc1e48a6e..fc79ab163a1f20122fe2533a9f4e50905e455e8d 100644 GIT binary patch delta 4378 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 I!3JUdH!v{CRR910 From 6dbe8979a92f410492ae8d1dd712444b7aa3d921 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 29 Apr 2016 01:25:17 +0800 Subject: [PATCH 082/173] =?UTF-8?q?=E5=88=86=E7=A6=BBnode-lua=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clib/mime/Makefile | 61 --- clib/mime/mime.c | 711 --------------------------------- clib/mime/mime.h | 26 -- clib/mime/mime.vcxproj | 94 ----- clib/mime/mime.vcxproj.filters | 18 - clib/mime/mime.vcxproj.user | 4 - node-lua.sln | 2 +- node-lua.v12.suo | Bin 159744 -> 159232 bytes 8 files changed, 1 insertion(+), 915 deletions(-) delete mode 100644 clib/mime/Makefile delete mode 100644 clib/mime/mime.c delete mode 100644 clib/mime/mime.h delete mode 100644 clib/mime/mime.vcxproj delete mode 100644 clib/mime/mime.vcxproj.filters delete mode 100644 clib/mime/mime.vcxproj.user diff --git a/clib/mime/Makefile b/clib/mime/Makefile deleted file mode 100644 index 34fc0eb..0000000 --- a/clib/mime/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -.PHONY: all clean -CC = gcc -RM = rm -rf -##PLATFORM ?= linux - -TARGET = mime.so -all: $(TARGET) - -## source file path -SRC_PATH := . - -## used headers file path -INCLUDE_PATH := ../../deps/lua - -## used include librarys file path -LIBRARY_PATH := ../../deps/lua - -## need libs, add at here -LIBS := nlua - -## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 -ifeq (RELEASE,$(RELEASE)) -CFLAGS += -D RELEASE -endif - -## define LDFLAGS -LDFLAGS += -shared - -ifeq (darwin,$(PLATFORM)) -LDFLAGS += -undefined dynamic_lookup \ - -framework Foundation \ - -framework CoreServices \ - -framework ApplicationServices -endif - -ifeq (linux,$(PLATFORM)) -LIBS += dl -endif - - -## get all source files -SRCS += $(wildcard $(SRC_PATH)/*.c) - -## all .o based on all .c -OBJS := $(SRCS:.c=.o) - -## get all include path -CFLAGS += $(foreach dir, $(INCLUDE_PATH), -I$(dir)) -.c.o: - $(CC) -c $(CFLAGS) -o $@ $< - -## get all library path -LDFLAGS += $(foreach lib, $(LIBRARY_PATH), -L$(lib)) -## get all librarys -LDFLAGS += $(foreach lib, $(LIBS), -l$(lib)) -$(TARGET): $(OBJS) - $(CC) -o $@ $(OBJS) $(LDFLAGS) - -clean: - $(RM) *.o $(TARGET) diff --git a/clib/mime/mime.c b/clib/mime/mime.c deleted file mode 100644 index 297b957..0000000 --- a/clib/mime/mime.c +++ /dev/null @@ -1,711 +0,0 @@ -/*=========================================================================*\ -* MIME support functions -* LuaSocket toolkit -* -* RCS ID: $Id: mime.c,v 1.28 2005/11/20 07:20:23 diego Exp $ -\*=========================================================================*/ -#include - -#include "lua.h" -#include "lauxlib.h" - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include "compat-5.1.h" -#endif - -#include "mime.h" - -/*=========================================================================*\ -* Don't want to trust escape character constants -\*=========================================================================*/ -typedef unsigned char UC; -static const char CRLF[] = "\r\n"; -static const char EQCRLF[] = "=\r\n"; - -/*=========================================================================*\ -* Internal function prototypes. -\*=========================================================================*/ -static int mime_global_wrp(lua_State *L); -static int mime_global_b64(lua_State *L); -static int mime_global_unb64(lua_State *L); -static int mime_global_qp(lua_State *L); -static int mime_global_unqp(lua_State *L); -static int mime_global_qpwrp(lua_State *L); -static int mime_global_eol(lua_State *L); -static int mime_global_dot(lua_State *L); - -static size_t dot(int c, size_t state, luaL_Buffer *buffer); -static void b64setup(UC *b64unbase); -static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); -static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); -static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); - -static void qpsetup(UC *qpclass, UC *qpunbase); -static void qpquote(UC c, luaL_Buffer *buffer); -static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); -static size_t qpencode(UC c, UC *input, size_t size, - const char *marker, luaL_Buffer *buffer); -static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); - -/* code support functions */ -static luaL_Reg func[] = { - { "dot", mime_global_dot }, - { "b64", mime_global_b64 }, - { "eol", mime_global_eol }, - { "qp", mime_global_qp }, - { "qpwrp", mime_global_qpwrp }, - { "unb64", mime_global_unb64 }, - { "unqp", mime_global_unqp }, - { "wrp", mime_global_wrp }, - { NULL, NULL } -}; - -/*-------------------------------------------------------------------------*\ -* Quoted-printable globals -\*-------------------------------------------------------------------------*/ -static UC qpclass[256]; -static UC qpbase[] = "0123456789ABCDEF"; -static UC qpunbase[256]; -enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; - -/*-------------------------------------------------------------------------*\ -* Base64 globals -\*-------------------------------------------------------------------------*/ -static const UC b64base[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static UC b64unbase[256]; - -/*=========================================================================*\ -* Exported functions -\*=========================================================================*/ -/*-------------------------------------------------------------------------*\ -* Initializes module -\*-------------------------------------------------------------------------*/ -LUAMOD_API int luaopen_mime_core(lua_State *L) -{ - luaL_openlib(L, "mime", func, 0); - /* make version string available to scripts */ - lua_pushstring(L, "_VERSION"); - lua_pushstring(L, MIME_VERSION); - lua_rawset(L, -3); - /* initialize lookup tables */ - qpsetup(qpclass, qpunbase); - b64setup(b64unbase); - return 1; -} - -/*=========================================================================*\ -* Global Lua functions -\*=========================================================================*/ -/*-------------------------------------------------------------------------*\ -* Incrementaly breaks a string into lines. The string can have CRLF breaks. -* A, n = wrp(l, B, length) -* A is a copy of B, broken into lines of at most 'length' bytes. -* 'l' is how many bytes are left for the first line of B. -* 'n' is the number of bytes left in the last line of A. -\*-------------------------------------------------------------------------*/ -static int mime_global_wrp(lua_State *L) -{ - size_t size = 0; - int left = (int) luaL_checknumber(L, 1); - const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); - const UC *last = input + size; - int length = (int) luaL_optnumber(L, 3, 76); - luaL_Buffer buffer; - /* end of input black-hole */ - if (!input) { - /* if last line has not been terminated, add a line break */ - if (left < length) lua_pushstring(L, CRLF); - /* otherwise, we are done */ - else lua_pushnil(L); - lua_pushnumber(L, length); - return 2; - } - luaL_buffinit(L, &buffer); - while (input < last) { - switch (*input) { - case '\r': - break; - case '\n': - luaL_addstring(&buffer, CRLF); - left = length; - break; - default: - if (left <= 0) { - left = length; - luaL_addstring(&buffer, CRLF); - } - luaL_putchar(&buffer, *input); - left--; - break; - } - input++; - } - luaL_pushresult(&buffer); - lua_pushnumber(L, left); - return 2; -} - -/*-------------------------------------------------------------------------*\ -* Fill base64 decode map. -\*-------------------------------------------------------------------------*/ -static void b64setup(UC *b64unbase) -{ - int i; - for (i = 0; i <= 255; i++) b64unbase[i] = (UC) 255; - for (i = 0; i < 64; i++) b64unbase[b64base[i]] = (UC) i; - b64unbase['='] = 0; -} - -/*-------------------------------------------------------------------------*\ -* Acumulates bytes in input buffer until 3 bytes are available. -* Translate the 3 bytes into Base64 form and append to buffer. -* Returns new number of bytes in buffer. -\*-------------------------------------------------------------------------*/ -static size_t b64encode(UC c, UC *input, size_t size, - luaL_Buffer *buffer) -{ - input[size++] = c; - if (size == 3) { - UC code[4]; - unsigned long value = 0; - value += input[0]; value <<= 8; - value += input[1]; value <<= 8; - value += input[2]; - code[3] = b64base[value & 0x3f]; value >>= 6; - code[2] = b64base[value & 0x3f]; value >>= 6; - code[1] = b64base[value & 0x3f]; value >>= 6; - code[0] = b64base[value]; - luaL_addlstring(buffer, (char *) code, 4); - size = 0; - } - return size; -} - -/*-------------------------------------------------------------------------*\ -* Encodes the Base64 last 1 or 2 bytes and adds padding '=' -* Result, if any, is appended to buffer. -* Returns 0. -\*-------------------------------------------------------------------------*/ -static size_t b64pad(const UC *input, size_t size, - luaL_Buffer *buffer) -{ - unsigned long value = 0; - UC code[4] = {'=', '=', '=', '='}; - switch (size) { - case 1: - value = input[0] << 4; - code[1] = b64base[value & 0x3f]; value >>= 6; - code[0] = b64base[value]; - luaL_addlstring(buffer, (char *) code, 4); - break; - case 2: - value = input[0]; value <<= 8; - value |= input[1]; value <<= 2; - code[2] = b64base[value & 0x3f]; value >>= 6; - code[1] = b64base[value & 0x3f]; value >>= 6; - code[0] = b64base[value]; - luaL_addlstring(buffer, (char *) code, 4); - break; - default: - break; - } - return 0; -} - -/*-------------------------------------------------------------------------*\ -* Acumulates bytes in input buffer until 4 bytes are available. -* Translate the 4 bytes from Base64 form and append to buffer. -* Returns new number of bytes in buffer. -\*-------------------------------------------------------------------------*/ -static size_t b64decode(UC c, UC *input, size_t size, - luaL_Buffer *buffer) -{ - /* ignore invalid characters */ - if (b64unbase[c] > 64) return size; - input[size++] = c; - /* decode atom */ - if (size == 4) { - UC decoded[3]; - int valid, value = 0; - value = b64unbase[input[0]]; value <<= 6; - value |= b64unbase[input[1]]; value <<= 6; - value |= b64unbase[input[2]]; value <<= 6; - value |= b64unbase[input[3]]; - decoded[2] = (UC) (value & 0xff); value >>= 8; - decoded[1] = (UC) (value & 0xff); value >>= 8; - decoded[0] = (UC) value; - /* take care of paddding */ - valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; - luaL_addlstring(buffer, (char *) decoded, valid); - return 0; - /* need more data */ - } else return size; -} - -/*-------------------------------------------------------------------------*\ -* Incrementally applies the Base64 transfer content encoding to a string -* A, B = b64(C, D) -* A is the encoded version of the largest prefix of C .. D that is -* divisible by 3. B has the remaining bytes of C .. D, *without* encoding. -* The easiest thing would be to concatenate the two strings and -* encode the result, but we can't afford that or Lua would dupplicate -* every chunk we received. -\*-------------------------------------------------------------------------*/ -static int mime_global_b64(lua_State *L) -{ - UC atom[3]; - size_t isize = 0, asize = 0; - const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); - const UC *last = input + isize; - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* process first part of the input */ - luaL_buffinit(L, &buffer); - while (input < last) - asize = b64encode(*input++, atom, asize, &buffer); - input = (UC *) luaL_optlstring(L, 2, NULL, &isize); - /* if second part is nil, we are done */ - if (!input) { - asize = b64pad(atom, asize, &buffer); - luaL_pushresult(&buffer); - if (!(*lua_tostring(L, -1))) lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* otherwise process the second part */ - last = input + isize; - while (input < last) - asize = b64encode(*input++, atom, asize, &buffer); - luaL_pushresult(&buffer); - lua_pushlstring(L, (char *) atom, asize); - return 2; -} - -/*-------------------------------------------------------------------------*\ -* Incrementally removes the Base64 transfer content encoding from a string -* A, B = b64(C, D) -* A is the encoded version of the largest prefix of C .. D that is -* divisible by 4. B has the remaining bytes of C .. D, *without* encoding. -\*-------------------------------------------------------------------------*/ -static int mime_global_unb64(lua_State *L) -{ - UC atom[4]; - size_t isize = 0, asize = 0; - const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); - const UC *last = input + isize; - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* process first part of the input */ - luaL_buffinit(L, &buffer); - while (input < last) - asize = b64decode(*input++, atom, asize, &buffer); - input = (UC *) luaL_optlstring(L, 2, NULL, &isize); - /* if second is nil, we are done */ - if (!input) { - luaL_pushresult(&buffer); - if (!(*lua_tostring(L, -1))) lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* otherwise, process the rest of the input */ - last = input + isize; - while (input < last) - asize = b64decode(*input++, atom, asize, &buffer); - luaL_pushresult(&buffer); - lua_pushlstring(L, (char *) atom, asize); - return 2; -} - -/*-------------------------------------------------------------------------*\ -* Quoted-printable encoding scheme -* all (except CRLF in text) can be =XX -* CLRL in not text must be =XX=XX -* 33 through 60 inclusive can be plain -* 62 through 126 inclusive can be plain -* 9 and 32 can be plain, unless in the end of a line, where must be =XX -* encoded lines must be no longer than 76 not counting CRLF -* soft line-break are =CRLF -* To encode one byte, we need to see the next two. -* Worst case is when we see a space, and wonder if a CRLF is comming -\*-------------------------------------------------------------------------*/ -/*-------------------------------------------------------------------------*\ -* Split quoted-printable characters into classes -* Precompute reverse map for encoding -\*-------------------------------------------------------------------------*/ -static void qpsetup(UC *qpclass, UC *qpunbase) -{ - int i; - for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED; - for (i = 33; i <= 60; i++) qpclass[i] = QP_PLAIN; - for (i = 62; i <= 126; i++) qpclass[i] = QP_PLAIN; - qpclass['\t'] = QP_IF_LAST; - qpclass[' '] = QP_IF_LAST; - qpclass['\r'] = QP_CR; - for (i = 0; i < 256; i++) qpunbase[i] = 255; - qpunbase['0'] = 0; qpunbase['1'] = 1; qpunbase['2'] = 2; - qpunbase['3'] = 3; qpunbase['4'] = 4; qpunbase['5'] = 5; - qpunbase['6'] = 6; qpunbase['7'] = 7; qpunbase['8'] = 8; - qpunbase['9'] = 9; qpunbase['A'] = 10; qpunbase['a'] = 10; - qpunbase['B'] = 11; qpunbase['b'] = 11; qpunbase['C'] = 12; - qpunbase['c'] = 12; qpunbase['D'] = 13; qpunbase['d'] = 13; - qpunbase['E'] = 14; qpunbase['e'] = 14; qpunbase['F'] = 15; - qpunbase['f'] = 15; -} - -/*-------------------------------------------------------------------------*\ -* Output one character in form =XX -\*-------------------------------------------------------------------------*/ -static void qpquote(UC c, luaL_Buffer *buffer) -{ - luaL_putchar(buffer, '='); - luaL_putchar(buffer, qpbase[c >> 4]); - luaL_putchar(buffer, qpbase[c & 0x0F]); -} - -/*-------------------------------------------------------------------------*\ -* Accumulate characters until we are sure about how to deal with them. -* Once we are sure, output to the buffer, in the correct form. -\*-------------------------------------------------------------------------*/ -static size_t qpencode(UC c, UC *input, size_t size, - const char *marker, luaL_Buffer *buffer) -{ - input[size++] = c; - /* deal with all characters we can have */ - while (size > 0) { - switch (qpclass[input[0]]) { - /* might be the CR of a CRLF sequence */ - case QP_CR: - if (size < 2) return size; - if (input[1] == '\n') { - luaL_addstring(buffer, marker); - return 0; - } else qpquote(input[0], buffer); - break; - /* might be a space and that has to be quoted if last in line */ - case QP_IF_LAST: - if (size < 3) return size; - /* if it is the last, quote it and we are done */ - if (input[1] == '\r' && input[2] == '\n') { - qpquote(input[0], buffer); - luaL_addstring(buffer, marker); - return 0; - } else luaL_putchar(buffer, input[0]); - break; - /* might have to be quoted always */ - case QP_QUOTED: - qpquote(input[0], buffer); - break; - /* might never have to be quoted */ - default: - luaL_putchar(buffer, input[0]); - break; - } - input[0] = input[1]; input[1] = input[2]; - size--; - } - return 0; -} - -/*-------------------------------------------------------------------------*\ -* Deal with the final characters -\*-------------------------------------------------------------------------*/ -static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) -{ - size_t i; - for (i = 0; i < size; i++) { - if (qpclass[input[i]] == QP_PLAIN) luaL_putchar(buffer, input[i]); - else qpquote(input[i], buffer); - } - if (size > 0) luaL_addstring(buffer, EQCRLF); - return 0; -} - -/*-------------------------------------------------------------------------*\ -* Incrementally converts a string to quoted-printable -* A, B = qp(C, D, marker) -* Marker is the text to be used to replace CRLF sequences found in A. -* A is the encoded version of the largest prefix of C .. D that -* can be encoded without doubts. -* B has the remaining bytes of C .. D, *without* encoding. -\*-------------------------------------------------------------------------*/ -static int mime_global_qp(lua_State *L) -{ - - size_t asize = 0, isize = 0; - UC atom[3]; - const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); - const UC *last = input + isize; - const char *marker = luaL_optstring(L, 3, CRLF); - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* process first part of input */ - luaL_buffinit(L, &buffer); - while (input < last) - asize = qpencode(*input++, atom, asize, marker, &buffer); - input = (UC *) luaL_optlstring(L, 2, NULL, &isize); - /* if second part is nil, we are done */ - if (!input) { - asize = qppad(atom, asize, &buffer); - luaL_pushresult(&buffer); - if (!(*lua_tostring(L, -1))) lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* otherwise process rest of input */ - last = input + isize; - while (input < last) - asize = qpencode(*input++, atom, asize, marker, &buffer); - luaL_pushresult(&buffer); - lua_pushlstring(L, (char *) atom, asize); - return 2; -} - -/*-------------------------------------------------------------------------*\ -* Accumulate characters until we are sure about how to deal with them. -* Once we are sure, output the to the buffer, in the correct form. -\*-------------------------------------------------------------------------*/ -static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { - int d; - input[size++] = c; - /* deal with all characters we can deal */ - switch (input[0]) { - /* if we have an escape character */ - case '=': - if (size < 3) return size; - /* eliminate soft line break */ - if (input[1] == '\r' && input[2] == '\n') return 0; - /* decode quoted representation */ - c = qpunbase[input[1]]; d = qpunbase[input[2]]; - /* if it is an invalid, do not decode */ - if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3); - else luaL_putchar(buffer, (c << 4) + d); - return 0; - case '\r': - if (size < 2) return size; - if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2); - return 0; - default: - if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) - luaL_putchar(buffer, input[0]); - return 0; - } -} - -/*-------------------------------------------------------------------------*\ -* Incrementally decodes a string in quoted-printable -* A, B = qp(C, D) -* A is the decoded version of the largest prefix of C .. D that -* can be decoded without doubts. -* B has the remaining bytes of C .. D, *without* decoding. -\*-------------------------------------------------------------------------*/ -static int mime_global_unqp(lua_State *L) -{ - size_t asize = 0, isize = 0; - UC atom[3]; - const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); - const UC *last = input + isize; - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* process first part of input */ - luaL_buffinit(L, &buffer); - while (input < last) - asize = qpdecode(*input++, atom, asize, &buffer); - input = (UC *) luaL_optlstring(L, 2, NULL, &isize); - /* if second part is nil, we are done */ - if (!input) { - luaL_pushresult(&buffer); - if (!(*lua_tostring(L, -1))) lua_pushnil(L); - lua_pushnil(L); - return 2; - } - /* otherwise process rest of input */ - last = input + isize; - while (input < last) - asize = qpdecode(*input++, atom, asize, &buffer); - luaL_pushresult(&buffer); - lua_pushlstring(L, (char *) atom, asize); - return 2; -} - -/*-------------------------------------------------------------------------*\ -* Incrementally breaks a quoted-printed string into lines -* A, n = qpwrp(l, B, length) -* A is a copy of B, broken into lines of at most 'length' bytes. -* 'l' is how many bytes are left for the first line of B. -* 'n' is the number of bytes left in the last line of A. -* There are two complications: lines can't be broken in the middle -* of an encoded =XX, and there might be line breaks already -\*-------------------------------------------------------------------------*/ -static int mime_global_qpwrp(lua_State *L) -{ - size_t size = 0; - int left = (int) luaL_checknumber(L, 1); - const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); - const UC *last = input + size; - int length = (int) luaL_optnumber(L, 3, 76); - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - if (left < length) lua_pushstring(L, EQCRLF); - else lua_pushnil(L); - lua_pushnumber(L, length); - return 2; - } - /* process all input */ - luaL_buffinit(L, &buffer); - while (input < last) { - switch (*input) { - case '\r': - break; - case '\n': - left = length; - luaL_addstring(&buffer, CRLF); - break; - case '=': - if (left <= 3) { - left = length; - luaL_addstring(&buffer, EQCRLF); - } - luaL_putchar(&buffer, *input); - left--; - break; - default: - if (left <= 1) { - left = length; - luaL_addstring(&buffer, EQCRLF); - } - luaL_putchar(&buffer, *input); - left--; - break; - } - input++; - } - luaL_pushresult(&buffer); - lua_pushnumber(L, left); - return 2; -} - -/*-------------------------------------------------------------------------*\ -* Here is what we do: \n, and \r are considered candidates for line -* break. We issue *one* new line marker if any of them is seen alone, or -* followed by a different one. That is, \n\n and \r\r will issue two -* end of line markers each, but \r\n, \n\r etc will only issue *one* -* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as -* probably other more obscure conventions. -* -* c is the current character being processed -* last is the previous character -\*-------------------------------------------------------------------------*/ -#define eolcandidate(c) (c == '\r' || c == '\n') -static int eolprocess(int c, int last, const char *marker, - luaL_Buffer *buffer) -{ - if (eolcandidate(c)) { - if (eolcandidate(last)) { - if (c == last) luaL_addstring(buffer, marker); - return 0; - } else { - luaL_addstring(buffer, marker); - return c; - } - } else { - luaL_putchar(buffer, c); - return 0; - } -} - -/*-------------------------------------------------------------------------*\ -* Converts a string to uniform EOL convention. -* A, n = eol(o, B, marker) -* A is the converted version of the largest prefix of B that can be -* converted unambiguously. 'o' is the context returned by the previous -* call. 'n' is the new context. -\*-------------------------------------------------------------------------*/ -static int mime_global_eol(lua_State *L) -{ - int ctx = luaL_checkint(L, 1); - size_t isize = 0; - const char *input = luaL_optlstring(L, 2, NULL, &isize); - const char *last = input + isize; - const char *marker = luaL_optstring(L, 3, CRLF); - luaL_Buffer buffer; - luaL_buffinit(L, &buffer); - /* end of input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnumber(L, 0); - return 2; - } - /* process all input */ - while (input < last) - ctx = eolprocess(*input++, ctx, marker, &buffer); - luaL_pushresult(&buffer); - lua_pushnumber(L, ctx); - return 2; -} - -/*-------------------------------------------------------------------------*\ -* Takes one byte and stuff it if needed. -\*-------------------------------------------------------------------------*/ -static size_t dot(int c, size_t state, luaL_Buffer *buffer) -{ - luaL_putchar(buffer, c); - switch (c) { - case '\r': - return 1; - case '\n': - return (state == 1)? 2: 0; - case '.': - if (state == 2) - luaL_putchar(buffer, '.'); - default: - return 0; - } -} - -/*-------------------------------------------------------------------------*\ -* Incrementally applies smtp stuffing to a string -* A, n = dot(l, D) -\*-------------------------------------------------------------------------*/ -static int mime_global_dot(lua_State *L) -{ - size_t isize = 0, state = (size_t) luaL_checknumber(L, 1); - const char *input = luaL_optlstring(L, 2, NULL, &isize); - const char *last = input + isize; - luaL_Buffer buffer; - /* end-of-input blackhole */ - if (!input) { - lua_pushnil(L); - lua_pushnumber(L, 2); - return 2; - } - /* process all input */ - luaL_buffinit(L, &buffer); - while (input < last) - state = dot(*input++, state, &buffer); - luaL_pushresult(&buffer); - lua_pushnumber(L, state); - return 2; -} - diff --git a/clib/mime/mime.h b/clib/mime/mime.h deleted file mode 100644 index 661efae..0000000 --- a/clib/mime/mime.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef MIME_H -#define MIME_H -/*=========================================================================*\ -* Core MIME support -* LuaSocket toolkit -* -* This module provides functions to implement transfer content encodings -* and formatting conforming to RFC 2045. It is used by mime.lua, which -* provide a higher level interface to this functionality. -* -* RCS ID: $Id: mime.h,v 1.15 2007/06/11 23:44:54 diego Exp $ -\*=========================================================================*/ -#include "lua.h" - -#define luaL_putchar luaL_addchar - -/*-------------------------------------------------------------------------*\ -* Current MIME library version -\*-------------------------------------------------------------------------*/ -#define MIME_VERSION "MIME 1.0.2" -#define MIME_COPYRIGHT "Copyright (C) 2004-2007 Diego Nehab" -#define MIME_AUTHORS "Diego Nehab" - -LUAMOD_API int luaopen_mime_core(lua_State *L); - -#endif /* MIME_H */ diff --git a/clib/mime/mime.vcxproj b/clib/mime/mime.vcxproj deleted file mode 100644 index ecf0c47..0000000 --- a/clib/mime/mime.vcxproj +++ /dev/null @@ -1,94 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - - {2691C520-B01B-46AB-B585-716767F72A9F} - Win32Proj - mime - - - - DynamicLibrary - true - v120 - Unicode - - - DynamicLibrary - false - v120 - true - Unicode - - - - - - - - - - - - - true - $(ProjectDir) - - - false - - - - NotUsing - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LUA_CORE;LUA_BUILD_AS_DLL;LUA_COMPAT_5_2;LUA_COMPAT_5_1;MIME_EXPORTS;%(PreprocessorDefinitions) - true - ..\..\deps\lua; - - - Windows - true - nlua.lib - ..\..\deps\lua; - - - $(SolutionDir)install.bat $(SolutionDir) $(ProjectName) - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS;%(PreprocessorDefinitions) - true - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/clib/mime/mime.vcxproj.filters b/clib/mime/mime.vcxproj.filters deleted file mode 100644 index 3f972d8..0000000 --- a/clib/mime/mime.vcxproj.filters +++ /dev/null @@ -1,18 +0,0 @@ - - - - - {20cf0978-da51-499c-91d9-8fc26c6e8702} - - - - - src - - - - - src - - - \ No newline at end of file diff --git a/clib/mime/mime.vcxproj.user b/clib/mime/mime.vcxproj.user deleted file mode 100644 index ef5ff2a..0000000 --- a/clib/mime/mime.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/node-lua.sln b/node-lua.sln index a3f509f..ae29c52 100644 --- a/node-lua.sln +++ b/node-lua.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.30723.0 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node-lua", "node-lua.vcxproj", "{3FC7B490-78F8-4A14-812B-02D6AFA48F96}" ProjectSection(ProjectDependencies) = postProject diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 7e630ce29613f2a3eabde2226b28104dc1e48a6e..2473689c87424f7b14999d209c543d18c2267c33 100644 GIT binary patch delta 7437 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 delta 10562 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 From 4aaed842718b87021d45623ad05a3337300b5e2e Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 29 Apr 2016 01:51:35 +0800 Subject: [PATCH 083/173] =?UTF-8?q?=E5=88=86=E7=A6=BBluaclib=E5=BA=93?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install.bat | 4 - luaclib/cjson.dll | Bin 0 -> 56832 bytes luaclib/cjson/CMakeLists.txt | 76 + luaclib/cjson/LICENSE | 20 + luaclib/cjson/Makefile | 127 + luaclib/cjson/NEWS | 44 + luaclib/cjson/THANKS | 9 + luaclib/cjson/cjson.vcxproj | 88 + luaclib/cjson/cjson.vcxproj.filters | 27 + luaclib/cjson/cjson.vcxproj.user | 4 + luaclib/cjson/dtoa.c | 4358 +++++++++++++++++ luaclib/cjson/dtoa_config.h | 74 + luaclib/cjson/fpconv.c | 205 + luaclib/cjson/fpconv.h | 22 + luaclib/cjson/g_fmt.c | 111 + luaclib/cjson/lua-cjson-2.1devel-1.rockspec | 56 + luaclib/cjson/lua-cjson.spec | 80 + luaclib/cjson/lua/cjson/util.lua | 271 + luaclib/cjson/lua/json2lua.lua | 14 + luaclib/cjson/lua/lua2json.lua | 20 + luaclib/cjson/lua_cjson.c | 1445 ++++++ luaclib/cjson/manual.txt | 612 +++ luaclib/cjson/performance.txt | 89 + luaclib/cjson/rfc4627.txt | 563 +++ luaclib/cjson/runtests.sh | 92 + luaclib/cjson/strbuf.c | 251 + luaclib/cjson/strbuf.h | 154 + luaclib/cjson/tests/README | 4 + luaclib/cjson/tests/TestLua.pm | 70 + luaclib/cjson/tests/agentzh.t | 52 + luaclib/cjson/tests/bench.lua | 131 + luaclib/cjson/tests/example1.json | 22 + luaclib/cjson/tests/example2.json | 11 + luaclib/cjson/tests/example3.json | 26 + luaclib/cjson/tests/example4.json | 88 + luaclib/cjson/tests/example5.json | 27 + luaclib/cjson/tests/genutf8.pl | 23 + luaclib/cjson/tests/numbers.json | 7 + luaclib/cjson/tests/octets-escaped.dat | 1 + luaclib/cjson/tests/rfc-example1.json | 13 + luaclib/cjson/tests/rfc-example2.json | 22 + luaclib/cjson/tests/test.lua | 425 ++ luaclib/cjson/tests/types.json | 1 + luaclib/lfs.dll | Bin 0 -> 44032 bytes luaclib/lfs/.travis/._platform.sh | Bin 0 -> 216 bytes luaclib/lfs/.travis/._setup_lua.sh | Bin 0 -> 216 bytes luaclib/lfs/.travis/platform.sh | 15 + luaclib/lfs/.travis/setup_lua.sh | 101 + luaclib/lfs/LICENSE | 21 + luaclib/lfs/Makefile | 54 + luaclib/lfs/Makefile.bak | 25 + luaclib/lfs/Makefile.win | 25 + luaclib/lfs/README | 82 + luaclib/lfs/config | 24 + luaclib/lfs/config.win | 19 + luaclib/lfs/doc/._us | Bin 0 -> 216 bytes luaclib/lfs/doc/us/._doc.css | Bin 0 -> 216 bytes luaclib/lfs/doc/us/._examples.html | Bin 0 -> 216 bytes luaclib/lfs/doc/us/._index.html | Bin 0 -> 216 bytes luaclib/lfs/doc/us/._license.html | Bin 0 -> 216 bytes luaclib/lfs/doc/us/._luafilesystem.png | Bin 0 -> 216 bytes luaclib/lfs/doc/us/._manual.html | Bin 0 -> 216 bytes luaclib/lfs/doc/us/doc.css | 212 + luaclib/lfs/doc/us/examples.html | 103 + luaclib/lfs/doc/us/index.html | 218 + luaclib/lfs/doc/us/license.html | 122 + luaclib/lfs/doc/us/luafilesystem.png | Bin 0 -> 8535 bytes luaclib/lfs/doc/us/manual.html | 280 ++ luaclib/lfs/lfs.c | 898 ++++ luaclib/lfs/lfs.def | 5 + luaclib/lfs/lfs.h | 25 + luaclib/lfs/lfs.vcxproj | 84 + luaclib/lfs/lfs.vcxproj.filters | 18 + .../._luafilesystem-1.3.0-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.4.0-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.4.0-2.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.4.1-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.4.1rc1-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.4.2-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.5.0-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.6.0-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.6.1-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.6.2-1.rockspec | Bin 0 -> 216 bytes .../._luafilesystem-1.6.3-1.rockspec | Bin 0 -> 216 bytes .../rockspecs/._luafilesystem-cvs-1.rockspec | Bin 0 -> 216 bytes .../rockspecs/._luafilesystem-cvs-2.rockspec | Bin 0 -> 216 bytes .../rockspecs/._luafilesystem-cvs-3.rockspec | Bin 0 -> 216 bytes .../rockspecs/luafilesystem-1.3.0-1.rockspec | 27 + .../rockspecs/luafilesystem-1.4.0-1.rockspec | 27 + .../rockspecs/luafilesystem-1.4.0-2.rockspec | 43 + .../rockspecs/luafilesystem-1.4.1-1.rockspec | 43 + .../luafilesystem-1.4.1rc1-1.rockspec | 43 + .../rockspecs/luafilesystem-1.4.2-1.rockspec | 26 + .../rockspecs/luafilesystem-1.5.0-1.rockspec | 27 + .../rockspecs/luafilesystem-1.6.0-1.rockspec | 27 + .../rockspecs/luafilesystem-1.6.1-1.rockspec | 27 + .../rockspecs/luafilesystem-1.6.2-1.rockspec | 27 + .../rockspecs/luafilesystem-1.6.3-1.rockspec | 28 + .../rockspecs/luafilesystem-cvs-1.rockspec | 44 + .../rockspecs/luafilesystem-cvs-2.rockspec | 26 + .../rockspecs/luafilesystem-cvs-3.rockspec | 27 + luaclib/lfs/tests/._test.lua | Bin 0 -> 216 bytes luaclib/lfs/tests/test.lua | 175 + luaclib/lfs/vc6/._lfs.def | Bin 0 -> 216 bytes luaclib/lfs/vc6/._luafilesystem.dsw | Bin 0 -> 216 bytes luaclib/lfs/vc6/._luafilesystem_dll.dsp | Bin 0 -> 216 bytes luaclib/lfs/vc6/lfs.def | 5 + luaclib/lfs/vc6/luafilesystem.dsw | 33 + luaclib/lfs/vc6/luafilesystem_dll.dsp | 127 + luaclib/lpeg.dll | Bin 0 -> 81408 bytes luaclib/lpeg/HISTORY | 96 + luaclib/lpeg/lpcap.c | 537 ++ luaclib/lpeg/lpcap.h | 43 + luaclib/lpeg/lpcode.c | 986 ++++ luaclib/lpeg/lpcode.h | 42 + luaclib/lpeg/lpeg-128.gif | Bin 0 -> 4923 bytes luaclib/lpeg/lpeg.html | 1434 ++++++ luaclib/lpeg/lpeg.vcxproj | 93 + luaclib/lpeg/lpeg.vcxproj.filters | 45 + luaclib/lpeg/lpeg.vcxproj.user | 4 + luaclib/lpeg/lpprint.c | 244 + luaclib/lpeg/lpprint.h | 36 + luaclib/lpeg/lptree.c | 1296 +++++ luaclib/lpeg/lptree.h | 77 + luaclib/lpeg/lptypes.h | 149 + luaclib/lpeg/lpvm.c | 355 ++ luaclib/lpeg/lpvm.h | 58 + luaclib/lpeg/makefile | 55 + luaclib/lpeg/re.html | 498 ++ luaclib/lpeg/re.lua | 259 + luaclib/lpeg/test.lua | 1448 ++++++ luaclib/luaclib.sln | 46 + luaclib/luaclib.v12.suo | Bin 0 -> 71168 bytes luaclib/mime.dll | Bin 0 -> 43520 bytes luaclib/mime/Makefile | 61 + luaclib/mime/mime.c | 711 +++ luaclib/mime/mime.h | 26 + luaclib/mime/mime.vcxproj | 94 + luaclib/mime/mime.vcxproj.filters | 18 + luaclib/mime/mime.vcxproj.user | 4 + luaclib/pb/Android.mk | 29 + luaclib/pb/Makefile | 56 + luaclib/pb/Makefile.bak | 84 + luaclib/pb/README.md | 85 + luaclib/pb/binding/lua/Makefile | 11 + luaclib/pb/binding/lua/README.md | 100 + luaclib/pb/binding/lua/parser.lua | 397 ++ luaclib/pb/binding/lua/pbc-lua.c | 1098 +++++ luaclib/pb/binding/lua/protobuf.lua | 558 +++ luaclib/pb/binding/lua/test.lua | 46 + luaclib/pb/binding/lua/test2.lua | 32 + luaclib/pb/binding/lua/testparser.lua | 26 + luaclib/pb/license.txt | 19 + luaclib/pb/pb.vcxproj.filters | 87 + luaclib/pb/pb.vcxproj.user | 4 + luaclib/pb/pbc.sdf | Bin 0 -> 2555904 bytes luaclib/pb/pbc.sln | 20 + luaclib/pb/pbc.v12.suo | Bin 0 -> 26624 bytes luaclib/pb/pbc.vcxproj | 110 + luaclib/pb/pbc.vcxproj.filters | 87 + luaclib/pb/pbc.vcxproj.user | 4 + luaclib/pb/pbc.xcodeproj/project.pbxproj | 338 ++ .../contents.xcworkspacedata | 7 + .../UserInterfaceState.xcuserstate | Bin 0 -> 70687 bytes .../UserInterfaceState.xcuserstate | Bin 0 -> 9605 bytes .../dev.xcuserdatad/xcschemes/pbc.xcscheme | 59 + .../xcschemes/xcschememanagement.plist | 22 + .../juren.xcuserdatad/xcschemes/pbc.xcscheme | 59 + .../xcschemes/xcschememanagement.plist | 22 + luaclib/pb/pbc/pbc-Prefix.pch | 8 + luaclib/pb/src/alloc.c | 84 + luaclib/pb/src/alloc.h | 37 + luaclib/pb/src/array.c | 139 + luaclib/pb/src/array.h | 31 + luaclib/pb/src/bootstrap.c | 303 ++ luaclib/pb/src/bootstrap.h | 10 + luaclib/pb/src/context.c | 280 ++ luaclib/pb/src/context.h | 140 + luaclib/pb/src/decode.c | 349 ++ luaclib/pb/src/descriptor.pbc.h | 271 + luaclib/pb/src/map.c | 477 ++ luaclib/pb/src/map.h | 33 + luaclib/pb/src/pattern.c | 1134 +++++ luaclib/pb/src/pattern.h | 26 + luaclib/pb/src/pbc.h | 104 + luaclib/pb/src/proto.c | 252 + luaclib/pb/src/proto.h | 65 + luaclib/pb/src/register.c | 342 ++ luaclib/pb/src/rmessage.c | 455 ++ luaclib/pb/src/stringpool.c | 60 + luaclib/pb/src/stringpool.h | 10 + luaclib/pb/src/varint.c | 110 + luaclib/pb/src/varint.h | 20 + luaclib/pb/src/wmessage.c | 518 ++ luaclib/pb/test/addressbook.c | 132 + luaclib/pb/test/addressbook.proto | 39 + luaclib/pb/test/array.c | 33 + luaclib/pb/test/decode.c | 99 + luaclib/pb/test/descriptor.proto | 539 ++ luaclib/pb/test/float.c | 89 + luaclib/pb/test/float.proto | 4 + luaclib/pb/test/map.c | 51 + luaclib/pb/test/pattern.c | 192 + luaclib/pb/test/pbc.c | 69 + luaclib/pb/test/test.c | 59 + luaclib/pb/test/test.proto | 5 + luaclib/pb/test/varint.c | 58 + luaclib/pb/tool/dump.c | 221 + luaclib/protobuf.dll | Bin 0 -> 130048 bytes 209 files changed, 31771 insertions(+), 4 deletions(-) delete mode 100644 install.bat create mode 100644 luaclib/cjson.dll create mode 100644 luaclib/cjson/CMakeLists.txt create mode 100644 luaclib/cjson/LICENSE create mode 100644 luaclib/cjson/Makefile create mode 100644 luaclib/cjson/NEWS create mode 100644 luaclib/cjson/THANKS create mode 100644 luaclib/cjson/cjson.vcxproj create mode 100644 luaclib/cjson/cjson.vcxproj.filters create mode 100644 luaclib/cjson/cjson.vcxproj.user create mode 100644 luaclib/cjson/dtoa.c create mode 100644 luaclib/cjson/dtoa_config.h create mode 100644 luaclib/cjson/fpconv.c create mode 100644 luaclib/cjson/fpconv.h create mode 100644 luaclib/cjson/g_fmt.c create mode 100644 luaclib/cjson/lua-cjson-2.1devel-1.rockspec create mode 100644 luaclib/cjson/lua-cjson.spec create mode 100644 luaclib/cjson/lua/cjson/util.lua create mode 100644 luaclib/cjson/lua/json2lua.lua create mode 100644 luaclib/cjson/lua/lua2json.lua create mode 100644 luaclib/cjson/lua_cjson.c create mode 100644 luaclib/cjson/manual.txt create mode 100644 luaclib/cjson/performance.txt create mode 100644 luaclib/cjson/rfc4627.txt create mode 100644 luaclib/cjson/runtests.sh create mode 100644 luaclib/cjson/strbuf.c create mode 100644 luaclib/cjson/strbuf.h create mode 100644 luaclib/cjson/tests/README create mode 100644 luaclib/cjson/tests/TestLua.pm create mode 100644 luaclib/cjson/tests/agentzh.t create mode 100644 luaclib/cjson/tests/bench.lua create mode 100644 luaclib/cjson/tests/example1.json create mode 100644 luaclib/cjson/tests/example2.json create mode 100644 luaclib/cjson/tests/example3.json create mode 100644 luaclib/cjson/tests/example4.json create mode 100644 luaclib/cjson/tests/example5.json create mode 100644 luaclib/cjson/tests/genutf8.pl create mode 100644 luaclib/cjson/tests/numbers.json create mode 100644 luaclib/cjson/tests/octets-escaped.dat create mode 100644 luaclib/cjson/tests/rfc-example1.json create mode 100644 luaclib/cjson/tests/rfc-example2.json create mode 100644 luaclib/cjson/tests/test.lua create mode 100644 luaclib/cjson/tests/types.json create mode 100644 luaclib/lfs.dll create mode 100644 luaclib/lfs/.travis/._platform.sh create mode 100644 luaclib/lfs/.travis/._setup_lua.sh create mode 100644 luaclib/lfs/.travis/platform.sh create mode 100644 luaclib/lfs/.travis/setup_lua.sh create mode 100644 luaclib/lfs/LICENSE create mode 100644 luaclib/lfs/Makefile create mode 100644 luaclib/lfs/Makefile.bak create mode 100644 luaclib/lfs/Makefile.win create mode 100644 luaclib/lfs/README create mode 100644 luaclib/lfs/config create mode 100644 luaclib/lfs/config.win create mode 100644 luaclib/lfs/doc/._us create mode 100644 luaclib/lfs/doc/us/._doc.css create mode 100644 luaclib/lfs/doc/us/._examples.html create mode 100644 luaclib/lfs/doc/us/._index.html create mode 100644 luaclib/lfs/doc/us/._license.html create mode 100644 luaclib/lfs/doc/us/._luafilesystem.png create mode 100644 luaclib/lfs/doc/us/._manual.html create mode 100644 luaclib/lfs/doc/us/doc.css create mode 100644 luaclib/lfs/doc/us/examples.html create mode 100644 luaclib/lfs/doc/us/index.html create mode 100644 luaclib/lfs/doc/us/license.html create mode 100644 luaclib/lfs/doc/us/luafilesystem.png create mode 100644 luaclib/lfs/doc/us/manual.html create mode 100644 luaclib/lfs/lfs.c create mode 100644 luaclib/lfs/lfs.def create mode 100644 luaclib/lfs/lfs.h create mode 100644 luaclib/lfs/lfs.vcxproj create mode 100644 luaclib/lfs/lfs.vcxproj.filters create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.3.0-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.4.0-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.4.0-2.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.4.1-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.4.1rc1-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.4.2-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.5.0-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.6.0-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.6.1-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.6.2-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-1.6.3-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-cvs-1.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-cvs-2.rockspec create mode 100644 luaclib/lfs/rockspecs/._luafilesystem-cvs-3.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.3.0-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.4.0-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.4.0-2.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.4.1-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.4.1rc1-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.4.2-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.5.0-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.6.0-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.6.1-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.6.2-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-1.6.3-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-cvs-1.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-cvs-2.rockspec create mode 100644 luaclib/lfs/rockspecs/luafilesystem-cvs-3.rockspec create mode 100644 luaclib/lfs/tests/._test.lua create mode 100644 luaclib/lfs/tests/test.lua create mode 100644 luaclib/lfs/vc6/._lfs.def create mode 100644 luaclib/lfs/vc6/._luafilesystem.dsw create mode 100644 luaclib/lfs/vc6/._luafilesystem_dll.dsp create mode 100644 luaclib/lfs/vc6/lfs.def create mode 100644 luaclib/lfs/vc6/luafilesystem.dsw create mode 100644 luaclib/lfs/vc6/luafilesystem_dll.dsp create mode 100644 luaclib/lpeg.dll create mode 100644 luaclib/lpeg/HISTORY create mode 100644 luaclib/lpeg/lpcap.c create mode 100644 luaclib/lpeg/lpcap.h create mode 100644 luaclib/lpeg/lpcode.c create mode 100644 luaclib/lpeg/lpcode.h create mode 100644 luaclib/lpeg/lpeg-128.gif create mode 100644 luaclib/lpeg/lpeg.html create mode 100644 luaclib/lpeg/lpeg.vcxproj create mode 100644 luaclib/lpeg/lpeg.vcxproj.filters create mode 100644 luaclib/lpeg/lpeg.vcxproj.user create mode 100644 luaclib/lpeg/lpprint.c create mode 100644 luaclib/lpeg/lpprint.h create mode 100644 luaclib/lpeg/lptree.c create mode 100644 luaclib/lpeg/lptree.h create mode 100644 luaclib/lpeg/lptypes.h create mode 100644 luaclib/lpeg/lpvm.c create mode 100644 luaclib/lpeg/lpvm.h create mode 100644 luaclib/lpeg/makefile create mode 100644 luaclib/lpeg/re.html create mode 100644 luaclib/lpeg/re.lua create mode 100644 luaclib/lpeg/test.lua create mode 100644 luaclib/luaclib.sln create mode 100644 luaclib/luaclib.v12.suo create mode 100644 luaclib/mime.dll create mode 100644 luaclib/mime/Makefile create mode 100644 luaclib/mime/mime.c create mode 100644 luaclib/mime/mime.h create mode 100644 luaclib/mime/mime.vcxproj create mode 100644 luaclib/mime/mime.vcxproj.filters create mode 100644 luaclib/mime/mime.vcxproj.user create mode 100644 luaclib/pb/Android.mk create mode 100644 luaclib/pb/Makefile create mode 100644 luaclib/pb/Makefile.bak create mode 100644 luaclib/pb/README.md create mode 100644 luaclib/pb/binding/lua/Makefile create mode 100644 luaclib/pb/binding/lua/README.md create mode 100644 luaclib/pb/binding/lua/parser.lua create mode 100644 luaclib/pb/binding/lua/pbc-lua.c create mode 100644 luaclib/pb/binding/lua/protobuf.lua create mode 100644 luaclib/pb/binding/lua/test.lua create mode 100644 luaclib/pb/binding/lua/test2.lua create mode 100644 luaclib/pb/binding/lua/testparser.lua create mode 100644 luaclib/pb/license.txt create mode 100644 luaclib/pb/pb.vcxproj.filters create mode 100644 luaclib/pb/pb.vcxproj.user create mode 100644 luaclib/pb/pbc.sdf create mode 100644 luaclib/pb/pbc.sln create mode 100644 luaclib/pb/pbc.v12.suo create mode 100644 luaclib/pb/pbc.vcxproj create mode 100644 luaclib/pb/pbc.vcxproj.filters create mode 100644 luaclib/pb/pbc.vcxproj.user create mode 100644 luaclib/pb/pbc.xcodeproj/project.pbxproj create mode 100644 luaclib/pb/pbc.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 luaclib/pb/pbc.xcodeproj/project.xcworkspace/xcuserdata/dev.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 luaclib/pb/pbc.xcodeproj/project.xcworkspace/xcuserdata/juren.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 luaclib/pb/pbc.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/pbc.xcscheme create mode 100644 luaclib/pb/pbc.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 luaclib/pb/pbc.xcodeproj/xcuserdata/juren.xcuserdatad/xcschemes/pbc.xcscheme create mode 100644 luaclib/pb/pbc.xcodeproj/xcuserdata/juren.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 luaclib/pb/pbc/pbc-Prefix.pch create mode 100644 luaclib/pb/src/alloc.c create mode 100644 luaclib/pb/src/alloc.h create mode 100644 luaclib/pb/src/array.c create mode 100644 luaclib/pb/src/array.h create mode 100644 luaclib/pb/src/bootstrap.c create mode 100644 luaclib/pb/src/bootstrap.h create mode 100644 luaclib/pb/src/context.c create mode 100644 luaclib/pb/src/context.h create mode 100644 luaclib/pb/src/decode.c create mode 100644 luaclib/pb/src/descriptor.pbc.h create mode 100644 luaclib/pb/src/map.c create mode 100644 luaclib/pb/src/map.h create mode 100644 luaclib/pb/src/pattern.c create mode 100644 luaclib/pb/src/pattern.h create mode 100644 luaclib/pb/src/pbc.h create mode 100644 luaclib/pb/src/proto.c create mode 100644 luaclib/pb/src/proto.h create mode 100644 luaclib/pb/src/register.c create mode 100644 luaclib/pb/src/rmessage.c create mode 100644 luaclib/pb/src/stringpool.c create mode 100644 luaclib/pb/src/stringpool.h create mode 100644 luaclib/pb/src/varint.c create mode 100644 luaclib/pb/src/varint.h create mode 100644 luaclib/pb/src/wmessage.c create mode 100644 luaclib/pb/test/addressbook.c create mode 100644 luaclib/pb/test/addressbook.proto create mode 100644 luaclib/pb/test/array.c create mode 100644 luaclib/pb/test/decode.c create mode 100644 luaclib/pb/test/descriptor.proto create mode 100644 luaclib/pb/test/float.c create mode 100644 luaclib/pb/test/float.proto create mode 100644 luaclib/pb/test/map.c create mode 100644 luaclib/pb/test/pattern.c create mode 100644 luaclib/pb/test/pbc.c create mode 100644 luaclib/pb/test/test.c create mode 100644 luaclib/pb/test/test.proto create mode 100644 luaclib/pb/test/varint.c create mode 100644 luaclib/pb/tool/dump.c create mode 100644 luaclib/protobuf.dll diff --git a/install.bat b/install.bat deleted file mode 100644 index d31c319..0000000 --- a/install.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -REM lua dll is essential but not mime -if /i "%~2" == "lua" (copy "%~1\deps\lua\nlua.dll" "%~1" & exit) -if /i "%~2" == "mime" (copy "%~1\clib\mime\mime.dll" "%~1\clib\" & exit) diff --git a/luaclib/cjson.dll b/luaclib/cjson.dll new file mode 100644 index 0000000000000000000000000000000000000000..99d69ad928d5b5d1a0ce0e31122916f7d7250d8a GIT binary patch literal 56832 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 j@-*lV>yPM<>W@KYC-i>(2 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/luaclib/cjson/Makefile b/luaclib/cjson/Makefile new file mode 100644 index 0000000..980195d --- /dev/null +++ b/luaclib/cjson/Makefile @@ -0,0 +1,127 @@ +##### Available defines for CJSON_CFLAGS ##### +## +## USE_INTERNAL_ISINF: Workaround for Solaris platforms missing isinf(). +## DISABLE_INVALID_NUMBERS: Permanently disable invalid JSON numbers: +## NaN, Infinity, hex. +## +## Optional built-in number conversion uses the following defines: +## USE_INTERNAL_FPCONV: Use builtin strtod/dtoa for numeric conversions. +## IEEE_BIG_ENDIAN: Required on big endian architectures. +## MULTIPLE_THREADS: Must be set when Lua CJSON may be used in a +## multi-threaded application. Requries _pthreads_. + +##### Build defaults ##### +LUA_VERSION = 5.1 +TARGET = cjson.so +PREFIX = /usr/local +#CFLAGS = -g -Wall -pedantic -fno-inline +CFLAGS = -O3 -Wall -pedantic -DNDEBUG +CJSON_CFLAGS = -fpic +CJSON_LDFLAGS = -shared +LUA_INCLUDE_DIR = $(PREFIX)/include +LUA_CMODULE_DIR = $(PREFIX)/lib/lua/$(LUA_VERSION) +LUA_MODULE_DIR = $(PREFIX)/share/lua/$(LUA_VERSION) +LUA_BIN_DIR = $(PREFIX)/bin + +##### Platform overrides ##### +## +## Tweak one of the platform sections below to suit your situation. +## +## See http://lua-users.org/wiki/BuildingModules for further platform +## specific details. + +## Linux + +## FreeBSD +#LUA_INCLUDE_DIR = $(PREFIX)/include/lua51 + +## MacOSX (Macports) +#PREFIX = /opt/local +#CJSON_LDFLAGS = -bundle -undefined dynamic_lookup + +## Solaris +#PREFIX = /home/user/opt +#CC = gcc +#CJSON_CFLAGS = -fpic -DUSE_INTERNAL_ISINF + +## Windows (MinGW) +#TARGET = cjson.dll +#PREFIX = /home/user/opt +#CJSON_CFLAGS = -DDISABLE_INVALID_NUMBERS +#CJSON_LDFLAGS = -shared -L$(PREFIX)/lib -llua51 +#LUA_BIN_SUFFIX = .lua + +#added by xdczju@sina.com +ifeq ($(OS),Windows_NT) + TARGET = cjson.dll + LDFLAGS2 += -lluajit51 +endif + +##### Number conversion configuration ##### + +## Use Libc support for number conversion (default) +FPCONV_OBJS = fpconv.o + +## Use built in number conversion +#FPCONV_OBJS = g_fmt.o dtoa.o +#CJSON_CFLAGS += -DUSE_INTERNAL_FPCONV + +## Compile built in number conversion for big endian architectures +#CJSON_CFLAGS += -DIEEE_BIG_ENDIAN + +## Compile built in number conversion to support multi-threaded +## applications (recommended) +#CJSON_CFLAGS += -pthread -DMULTIPLE_THREADS +#CJSON_LDFLAGS += -pthread + +##### End customisable sections ##### + +TEST_FILES = README bench.lua genutf8.pl test.lua octets-escaped.dat \ + example1.json example2.json example3.json example4.json \ + example5.json numbers.json rfc-example1.json \ + rfc-example2.json types.json +DATAPERM = 644 +EXECPERM = 755 + +ASCIIDOC = asciidoc + +BUILD_CFLAGS = -I$(LUA_INCLUDE_DIR) $(CJSON_CFLAGS) +OBJS = lua_cjson.o strbuf.o $(FPCONV_OBJS) + +.PHONY: all clean install install-extra doc + +.SUFFIXES: .html .txt + +.c.o: + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(BUILD_CFLAGS) -o $@ $< + +.txt.html: + $(ASCIIDOC) -n -a toc $< + +all: $(TARGET) + +doc: manual.html performance.html + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) $(CJSON_LDFLAGS) -o $@ $(OBJS) $(LDFLAGS2) + +install: $(TARGET) + mkdir -p $(DESTDIR)/$(LUA_CMODULE_DIR) + rm -f $(DESTDIR)/$(LUA_CMODULE_DIR)/$(TARGET) + cp $(TARGET) $(DESTDIR)/$(LUA_CMODULE_DIR) + chmod $(EXECPERM) $(DESTDIR)/$(LUA_CMODULE_DIR)/$(TARGET) + +install-extra: + mkdir -p $(DESTDIR)/$(LUA_MODULE_DIR)/cjson/tests \ + $(DESTDIR)/$(LUA_BIN_DIR) + cp lua/cjson/util.lua $(DESTDIR)/$(LUA_MODULE_DIR)/cjson + chmod $(DATAPERM) $(DESTDIR)/$(LUA_MODULE_DIR)/cjson/util.lua + cp lua/lua2json.lua $(DESTDIR)/$(LUA_BIN_DIR)/lua2json$(LUA_BIN_SUFFIX) + chmod $(EXECPERM) $(DESTDIR)/$(LUA_BIN_DIR)/lua2json$(LUA_BIN_SUFFIX) + cp lua/json2lua.lua $(DESTDIR)/$(LUA_BIN_DIR)/json2lua$(LUA_BIN_SUFFIX) + chmod $(EXECPERM) $(DESTDIR)/$(LUA_BIN_DIR)/json2lua$(LUA_BIN_SUFFIX) + cd tests; cp $(TEST_FILES) $(DESTDIR)/$(LUA_MODULE_DIR)/cjson/tests + cd tests; chmod $(DATAPERM) $(TEST_FILES); chmod $(EXECPERM) *.lua *.pl + +clean: + rm -f *.o $(TARGET) diff --git a/luaclib/cjson/NEWS b/luaclib/cjson/NEWS new file mode 100644 index 0000000..8927d6e --- /dev/null +++ b/luaclib/cjson/NEWS @@ -0,0 +1,44 @@ +Version 2.1.0 (Mar 1 2012) +* Added cjson.safe module interface which returns nil after an error +* Improved Makefile compatibility with Solaris make + +Version 2.0.0 (Jan 22 2012) +* Improved platform compatibility for strtod/sprintf locale workaround +* Added option to build with David Gay's dtoa.c for improved performance +* Added support for Lua 5.2 +* Added option to encode infinity/NaN as JSON null +* Fixed encode bug with a raised default limit and deeply nested tables +* Updated Makefile for compatibility with non-GNU make implementations +* Added CMake build support +* Added HTML manual +* Increased default nesting limit to 1000 +* Added support for re-entrant use of encode and decode +* Added support for installing lua2json and json2lua utilities +* Added encode_invalid_numbers() and decode_invalid_numbers() +* Added decode_max_depth() +* Removed registration of global cjson module table +* Removed refuse_invalid_numbers() + +Version 1.0.4 (Nov 30 2011) +* Fixed numeric conversion under locales with a comma decimal separator + +Version 1.0.3 (Sep 15 2011) +* Fixed detection of objects with numeric string keys +* Provided work around for missing isinf() on Solaris + +Version 1.0.2 (May 30 2011) +* Portability improvements for Windows + - No longer links with -lm + - Use "socket" instead of "posix" for sub-second timing +* Removed UTF-8 test dependency on Perl Text::Iconv +* Added simple CLI commands for testing Lua <-> JSON conversions +* Added cjson.encode_number_precision() + +Version 1.0.1 (May 10 2011) +* Added build support for OSX +* Removed unnecessary whitespace from JSON output +* Added cjson.encode_keep_buffer() +* Fixed memory leak on Lua stack overflow exception + +Version 1.0 (May 9 2011) +* Initial release diff --git a/luaclib/cjson/THANKS b/luaclib/cjson/THANKS new file mode 100644 index 0000000..4aade13 --- /dev/null +++ b/luaclib/cjson/THANKS @@ -0,0 +1,9 @@ +The following people have helped with bug reports, testing and/or +suggestions: + +- Louis-Philippe Perron (@loopole) +- Ondřej Jirman +- Steve Donovan +- Zhang "agentzh" Yichun + +Thanks! diff --git a/luaclib/cjson/cjson.vcxproj b/luaclib/cjson/cjson.vcxproj new file mode 100644 index 0000000..b3cbd97 --- /dev/null +++ b/luaclib/cjson/cjson.vcxproj @@ -0,0 +1,88 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {933BAD43-4B46-4BC1-A943-7825C5946B23} + cjson + + + + DynamicLibrary + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + $(ProjectDir) + + + + Level3 + Disabled + false + ..\..\deps\lua; + WIN32;_DEBUG;_WINDOWS;_USRDLL;LUA_CORE;LUA_BUILD_AS_DLL;LUA_COMPAT_5_2;LUA_COMPAT_5_1;%(PreprocessorDefinitions) + /D"inline"=__inline /D"snprintf"=_snprintf /D"strncasecmp"=strnicmp %(AdditionalOptions) + + + true + ..\..\deps\lua; + nlua.lib + + + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/luaclib/cjson/cjson.vcxproj.filters b/luaclib/cjson/cjson.vcxproj.filters new file mode 100644 index 0000000..aa1e759 --- /dev/null +++ b/luaclib/cjson/cjson.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {61e8bb3e-7ce4-4806-95b8-6f7000191bff} + + + + + src + + + src + + + src + + + + + src + + + src + + + \ No newline at end of file diff --git a/luaclib/cjson/cjson.vcxproj.user b/luaclib/cjson/cjson.vcxproj.user new file mode 100644 index 0000000..ef5ff2a --- /dev/null +++ b/luaclib/cjson/cjson.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/luaclib/cjson/dtoa.c b/luaclib/cjson/dtoa.c new file mode 100644 index 0000000..56398ba --- /dev/null +++ b/luaclib/cjson/dtoa.c @@ -0,0 +1,4358 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_8087 for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_MC68k for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. This will cause dtoa modes 4 and 5 to be + * treated the same as modes 2 and 3 for some inputs. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS + * is also #defined, fegetround() will be queried for the rounding mode. + * Note that both FLT_ROUNDS and fegetround() are specified by the C99 + * standard (and are specified to be consistent, with fesetround() + * affecting the value of FLT_ROUNDS), but that some (Linux) systems + * do not work correctly in this regard, so using fegetround() is more + * portable than using FLT_ROUNDS directly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic + * that rounds toward +Infinity. + * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased + * rounding when the underlying floating-point arithmetic uses + * unbiased rounding. This prevent using ordinary floating-point + * arithmetic when the result could be computed with one rounding error. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. Similarly, if you + * want something other than the system's free() to be called to + * recycle memory acquired from MALLOC, #define FREE to be the + * name of the alternate routine. (FREE or free is only called in + * pathological cases, e.g., in a dtoa call after a dtoa return in + * mode 3 with thousands of digits requested.) + * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making + * memory allocations from a private pool of memory when possible. + * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions in single-threaded executions with 8-byte + * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte + * pointers, PRIVATE_MEM >= 7112 appears adequate. + * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK + * #defined automatically on IEEE systems. On such systems, + * when INFNAN_CHECK is #defined, strtod checks + * for Infinity and NaN (case insensitively). On some systems + * (e.g., some HP systems), it may be necessary to #define NAN_WORD0 + * appropriately -- to the most significant word of a quiet NaN. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod also accepts (case insensitively) strings of the form + * NaN(x), where x is a string of hexadecimal digits and spaces; + * if there is only one string of hexadecimal digits, it is taken + * for the 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + * #define NO_HEX_FP to omit recognition of hexadecimal floating-point + * values by strtod. + * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now) + * to disable logic for "fast" testing of very long input strings + * to strtod. This testing proceeds by initially truncating the + * input string, then if necessary comparing the whole string with + * a decimal expansion to decide close cases. This logic is only + * used for input more than STRTOD_DIGLIM digits long (default 40). + */ + +#include "dtoa_config.h" + +#ifndef Long +#define Long long +#endif +#ifndef ULong +typedef unsigned Long ULong; +#endif + +#ifdef DEBUG +#include "stdio.h" +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#include "stdlib.h" +#include "string.h" + +#ifdef USE_LOCALE +#include "locale.h" +#endif + +#ifdef Honor_FLT_ROUNDS +#ifndef Trust_FLT_ROUNDS +#include +#endif +#endif + +#ifdef MALLOC +#ifdef KR_headers +extern char *MALLOC(); +#else +extern void *MALLOC(size_t); +#endif +#else +#define MALLOC malloc +#endif + +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_MC68k +#define IEEE_Arith +#endif +#ifdef IEEE_8087 +#define IEEE_Arith +#endif + +#ifdef IEEE_Arith +#ifndef NO_INFNAN_CHECK +#undef INFNAN_CHECK +#define INFNAN_CHECK +#endif +#else +#undef INFNAN_CHECK +#define NO_STRTOD_BIGCOMP +#endif + +#include "errno.h" + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include "float.h" +#endif /* Bad_float_h */ + +#ifndef __MATH_H__ +#include "math.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONST +#ifdef KR_headers +#define CONST /* blank */ +#else +#define CONST const +#endif +#endif + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#ifdef IEEE_8087 +#define word0(x) (x)->L[1] +#define word1(x) (x)->L[0] +#else +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] +#endif +#define dval(x) (x)->d + +#ifndef STRTOD_DIGLIM +#define STRTOD_DIGLIM 40 +#endif + +#ifdef DIGLIM_DEBUG +extern int strtod_diglim; +#else +#define strtod_diglim STRTOD_DIGLIM +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_8087) + defined(VAX) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +((unsigned short *)a)[0] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Nbits 53 +#define Bias 1023 +#define Emax 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Nbits 56 +#define Bias 65 +#define Emax 248 +#define Emin (-260) +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Nbits 56 +#define Bias 129 +#define Emax 126 +#define Emin (-129) +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#else +#ifdef ROUND_BIASED_without_Round_Up +#undef ROUND_BIASED +#define ROUND_BIASED +#endif +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +#ifdef KR_headers +extern double rnd_prod(), rnd_quot(); +#else +extern double rnd_prod(double, double), rnd_quot(double, double); +#endif +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +typedef struct BCinfo BCinfo; + struct +BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; }; + +#ifdef KR_headers +#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) +#else +#define FFFFFFFF 0xffffffffUL +#endif + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#endif + +#define Kmax 7 + +#ifdef __cplusplus +extern "C" double fpconv_strtod(const char *s00, char **se); +extern "C" char *dtoa(double d, int mode, int ndigits, + int *decpt, int *sign, char **rve); +#endif + + struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; + }; + + typedef struct Bigint Bigint; + + static Bigint *freelist[Kmax+1]; + + static Bigint * +Balloc +#ifdef KR_headers + (k) int k; +#else + (int k) +#endif +{ + int x; + Bigint *rv; +#ifndef Omit_Private_Memory + unsigned int len; +#endif + + ACQUIRE_DTOA_LOCK(0); + /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ + /* but this case seems very unlikely. */ + if (k <= Kmax && (rv = freelist[k])) + freelist[k] = rv->next; + else { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { + rv = (Bigint*)pmem_next; + pmem_next += len; + } + else + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); + rv->sign = rv->wds = 0; + return rv; + } + + static void +Bfree +#ifdef KR_headers + (v) Bigint *v; +#else + (Bigint *v) +#endif +{ + if (v) { + if (v->k > Kmax) +#ifdef FREE + FREE((void*)v); +#else + free((void*)v); +#endif + else { + ACQUIRE_DTOA_LOCK(0); + v->next = freelist[v->k]; + freelist[v->k] = v; + FREE_DTOA_LOCK(0); + } + } + } + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(Long) + 2*sizeof(int)) + + static Bigint * +multadd +#ifdef KR_headers + (b, m, a) Bigint *b; int m, a; +#else + (Bigint *b, int m, int a) /* multiply by m and add a */ +#endif +{ + int i, wds; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } + while(++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = carry; + b->wds = wds; + } + return b; + } + + static Bigint * +s2b +#ifdef KR_headers + (s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9; +#else + (const char *s, int nd0, int nd, ULong y9, int dplen) +#endif +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); + s += dplen; + } + else + s += dplen + 9; + for(; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; + } + + static int +hi0bits +#ifdef KR_headers + (x) ULong x; +#else + (ULong x) +#endif +{ + int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; + } + + static int +lo0bits +#ifdef KR_headers + (y) ULong *y; +#else + (ULong *y) +#endif +{ + int k; + ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; + } + + static Bigint * +i2b +#ifdef KR_headers + (i) int i; +#else + (int i) +#endif +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; + } + + static Bigint * +mult +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for(; xb < xbe; xc0++) { + if ((y = *xb++)) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = z & FFFFFFFF; + } + while(x < xae); + *xc = carry; + } + } +#else +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; + } + + static Bigint *p5s; + + static Bigint * +pow5mult +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3)) + b = multadd(b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + if (!(p5 = p5s)) { + /* first time */ +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p5 = p5s)) { + p5 = p5s = i2b(625); + p5->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p5 = p5s = i2b(625); + p5->next = 0; +#endif + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p51 = p5->next = mult(p5,p5); + p51->next = 0; +#endif + } + p5 = p51; + } + return b; + } + + static Bigint * +lshift +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if ((*x1 = z)) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; + } + + static int +cmp +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; + } + + static Bigint * +diff +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; + } + + static double +ulp +#ifdef KR_headers + (x) U *x; +#else + (U *x) +#endif +{ + Long L; + U u; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(&u) = L; + word1(&u) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(&u) = 0x80000 >> L; + word1(&u) = 0; + } + else { + word0(&u) = 0; + L -= Exp_shift; + word1(&u) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(&u); + } + + static double +b2d +#ifdef KR_headers + (a, e) Bigint *a; int *e; +#else + (Bigint *a, int *e) +#endif +{ + ULong *xa, *xa0, w, y, z; + int k; + U d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(&d) +#define d1 word1(&d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> (Ebits - k); + w = xa > xa0 ? *--xa : 0; + d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> (32 - k); + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif + ret_d: +#ifdef VAX + word0(&d) = d0 >> 16 | d0 << 16; + word1(&d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(&d); + } + + static Bigint * +d2b +#ifdef KR_headers + (d, e, bits) U *d; int *e, *bits; +#else + (U *d, int *e, int *bits) +#endif +{ + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if ((de = (int)(d0 >> Exp_shift))) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if ((y = d1)) { + if ((k = lo0bits(&y))) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; + } +#undef d0 +#undef d1 + + static double +ratio +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + U da, db; + int k, ka, kb; + + dval(&da) = b2d(a, &ka); + dval(&db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(&da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(&da) *= 1 << k; + } + else { + k = -k; + word0(&db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(&db) *= 1 << k; + } +#else + if (k > 0) + word0(&da) += k*Exp_msk1; + else { + k = -k; + word0(&db) += k*Exp_msk1; + } +#endif + return dval(&da) / dval(&db); + } + + static CONST double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif + }; + + static CONST double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-256 */ +#else + 1e-256 +#endif + }; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +#undef Need_Hexdig +#ifdef INFNAN_CHECK +#ifndef No_Hex_NaN +#define Need_Hexdig +#endif +#endif + +#ifndef Need_Hexdig +#ifndef NO_HEX_FP +#define Need_Hexdig +#endif +#endif + +#ifdef Need_Hexdig /*{*/ +static unsigned char hexdig[256]; + + static void +#ifdef KR_headers +htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc; +#else +htinit(unsigned char *h, unsigned char *s, int inc) +#endif +{ + int i, j; + for(i = 0; (j = s[i]) !=0; i++) + h[j] = i + inc; + } + + static void +#ifdef KR_headers +hexdig_init() +#else +hexdig_init(void) +#endif +{ +#define USC (unsigned char *) + htinit(hexdig, USC "0123456789", 0x10); + htinit(hexdig, USC "abcdef", 0x10 + 10); + htinit(hexdig, USC "ABCDEF", 0x10 + 10); + } +#endif /* } Need_Hexdig */ + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + + static int +match +#ifdef KR_headers + (sp, t) char **sp, *t; +#else + (const char **sp, const char *t) +#endif +{ + int c, d; + CONST char *s = *sp; + + while((d = *t++)) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; + } + +#ifndef No_Hex_NaN + static void +hexnan +#ifdef KR_headers + (rvp, sp) U *rvp; CONST char **sp; +#else + (U *rvp, const char **sp) +#endif +{ + ULong c, x[2]; + CONST char *s; + int c1, havedig, udx0, xshift; + + if (!hexdig['0']) + hexdig_init(); + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + /* allow optional initial 0x or 0X */ + while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') + ++s; + if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) + s += 2; + while((c = *(CONST unsigned char*)++s)) { + if ((c1 = hexdig[c])) + c = c1 & 0xf; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } +#ifdef GDTOA_NON_PEDANTIC_NANCHECK + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ +#else + else { + do { + if (/*(*/ c == ')') { + *sp = s + 1; + break; + } + } while((c = *++s)); + break; + } +#endif + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(rvp) = Exp_mask | x[0]; + word1(rvp) = x[1]; + } + } +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + +#ifdef Pack_32 +#define ULbits 32 +#define kshift 5 +#define kmask 31 +#else +#define ULbits 16 +#define kshift 4 +#define kmask 15 +#endif + +#if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/ + static Bigint * +#ifdef KR_headers +increment(b) Bigint *b; +#else +increment(Bigint *b) +#endif +{ + ULong *x, *xe; + Bigint *b1; + + x = b->x; + xe = x + b->wds; + do { + if (*x < (ULong)0xffffffffL) { + ++*x; + return b; + } + *x++ = 0; + } while(x < xe); + { + if (b->wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1,b); + Bfree(b); + b = b1; + } + b->x[b->wds++] = 1; + } + return b; + } + +#endif /*}*/ + +#ifndef NO_HEX_FP /*{*/ + + static void +#ifdef KR_headers +rshift(b, k) Bigint *b; int k; +#else +rshift(Bigint *b, int k) +#endif +{ + ULong *x, *x1, *xe, y; + int n; + + x = x1 = b->x; + n = k >> kshift; + if (n < b->wds) { + xe = x + b->wds; + x += n; + if (k &= kmask) { + n = 32 - k; + y = *x++ >> k; + while(x < xe) { + *x1++ = (y | (*x << n)) & 0xffffffff; + y = *x++ >> k; + } + if ((*x1 = y) !=0) + x1++; + } + else + while(x < xe) + *x1++ = *x++; + } + if ((b->wds = x1 - b->x) == 0) + b->x[0] = 0; + } + + static ULong +#ifdef KR_headers +any_on(b, k) Bigint *b; int k; +#else +any_on(Bigint *b, int k) +#endif +{ + int n, nwds; + ULong *x, *x0, x1, x2; + + x = b->x; + nwds = b->wds; + n = k >> kshift; + if (n > nwds) + n = nwds; + else if (n < nwds && (k &= kmask)) { + x1 = x2 = x[n]; + x1 >>= k; + x1 <<= k; + if (x1 != x2) + return 1; + } + x0 = x; + x += n; + while(x > x0) + if (*--x) + return 1; + return 0; + } + +enum { /* rounding values: same as FLT_ROUNDS */ + Round_zero = 0, + Round_near = 1, + Round_up = 2, + Round_down = 3 + }; + + void +#ifdef KR_headers +gethex(sp, rvp, rounding, sign) + CONST char **sp; U *rvp; int rounding, sign; +#else +gethex( CONST char **sp, U *rvp, int rounding, int sign) +#endif +{ + Bigint *b; + CONST unsigned char *decpt, *s0, *s, *s1; + Long e, e1; + ULong L, lostbits, *x; + int big, denorm, esign, havedig, k, n, nbits, up, zret; +#ifdef IBM + int j; +#endif + enum { +#ifdef IEEE_Arith /*{{*/ + emax = 0x7fe - Bias - P + 1, + emin = Emin - P + 1 +#else /*}{*/ + emin = Emin - P, +#ifdef VAX + emax = 0x7ff - Bias - P + 1 +#endif +#ifdef IBM + emax = 0x7f - Bias - P +#endif +#endif /*}}*/ + }; +#ifdef USE_LOCALE + int i; +#ifdef NO_LOCALE_CACHE + const unsigned char *decimalpoint = (unsigned char*) + localeconv()->decimal_point; +#else + const unsigned char *decimalpoint; + static unsigned char *decimalpoint_cache; + if (!(s0 = decimalpoint_cache)) { + s0 = (unsigned char*)localeconv()->decimal_point; + if ((decimalpoint_cache = (unsigned char*) + MALLOC(strlen((CONST char*)s0) + 1))) { + strcpy((char*)decimalpoint_cache, (CONST char*)s0); + s0 = decimalpoint_cache; + } + } + decimalpoint = s0; +#endif +#endif + + if (!hexdig['0']) + hexdig_init(); + havedig = 0; + s0 = *(CONST unsigned char **)sp + 2; + while(s0[havedig] == '0') + havedig++; + s0 += havedig; + s = s0; + decpt = 0; + zret = 0; + e = 0; + if (hexdig[*s]) + havedig++; + else { + zret = 1; +#ifdef USE_LOCALE + for(i = 0; decimalpoint[i]; ++i) { + if (s[i] != decimalpoint[i]) + goto pcheck; + } + decpt = s += i; +#else + if (*s != '.') + goto pcheck; + decpt = ++s; +#endif + if (!hexdig[*s]) + goto pcheck; + while(*s == '0') + s++; + if (hexdig[*s]) + zret = 0; + havedig = 1; + s0 = s; + } + while(hexdig[*s]) + s++; +#ifdef USE_LOCALE + if (*s == *decimalpoint && !decpt) { + for(i = 1; decimalpoint[i]; ++i) { + if (s[i] != decimalpoint[i]) + goto pcheck; + } + decpt = s += i; +#else + if (*s == '.' && !decpt) { + decpt = ++s; +#endif + while(hexdig[*s]) + s++; + }/*}*/ + if (decpt) + e = -(((Long)(s-decpt)) << 2); + pcheck: + s1 = s; + big = esign = 0; + switch(*s) { + case 'p': + case 'P': + switch(*++s) { + case '-': + esign = 1; + /* no break */ + case '+': + s++; + } + if ((n = hexdig[*s]) == 0 || n > 0x19) { + s = s1; + break; + } + e1 = n - 0x10; + while((n = hexdig[*++s]) !=0 && n <= 0x19) { + if (e1 & 0xf8000000) + big = 1; + e1 = 10*e1 + n - 0x10; + } + if (esign) + e1 = -e1; + e += e1; + } + *sp = (char*)s; + if (!havedig) + *sp = (char*)s0 - 1; + if (zret) + goto retz1; + if (big) { + if (esign) { +#ifdef IEEE_Arith + switch(rounding) { + case Round_up: + if (sign) + break; + goto ret_tiny; + case Round_down: + if (!sign) + break; + goto ret_tiny; + } +#endif + goto retz; +#ifdef IEEE_Arith + ret_tiny: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + word0(rvp) = 0; + word1(rvp) = 1; + return; +#endif /* IEEE_Arith */ + } + switch(rounding) { + case Round_near: + goto ovfl1; + case Round_up: + if (!sign) + goto ovfl1; + goto ret_big; + case Round_down: + if (sign) + goto ovfl1; + goto ret_big; + } + ret_big: + word0(rvp) = Big0; + word1(rvp) = Big1; + return; + } + n = s1 - s0 - 1; + for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) + k++; + b = Balloc(k); + x = b->x; + n = 0; + L = 0; +#ifdef USE_LOCALE + for(i = 0; decimalpoint[i+1]; ++i); +#endif + while(s1 > s0) { +#ifdef USE_LOCALE + if (*--s1 == decimalpoint[i]) { + s1 -= i; + continue; + } +#else + if (*--s1 == '.') + continue; +#endif + if (n == ULbits) { + *x++ = L; + L = 0; + n = 0; + } + L |= (hexdig[*s1] & 0x0f) << n; + n += 4; + } + *x++ = L; + b->wds = n = x - b->x; + n = ULbits*n - hi0bits(L); + nbits = Nbits; + lostbits = 0; + x = b->x; + if (n > nbits) { + n -= nbits; + if (any_on(b,n)) { + lostbits = 1; + k = n - 1; + if (x[k>>kshift] & 1 << (k & kmask)) { + lostbits = 2; + if (k > 0 && any_on(b,k)) + lostbits = 3; + } + } + rshift(b, n); + e += n; + } + else if (n < nbits) { + n = nbits - n; + b = lshift(b, n); + e -= n; + x = b->x; + } + if (e > Emax) { + ovfl: + Bfree(b); + ovfl1: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + word0(rvp) = Exp_mask; + word1(rvp) = 0; + return; + } + denorm = 0; + if (e < emin) { + denorm = 1; + n = emin - e; + if (n >= nbits) { +#ifdef IEEE_Arith /*{*/ + switch (rounding) { + case Round_near: + if (n == nbits && (n < 2 || any_on(b,n-1))) + goto ret_tiny; + break; + case Round_up: + if (!sign) + goto ret_tiny; + break; + case Round_down: + if (sign) + goto ret_tiny; + } +#endif /* } IEEE_Arith */ + Bfree(b); + retz: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + retz1: + rvp->d = 0.; + return; + } + k = n - 1; + if (lostbits) + lostbits = 1; + else if (k > 0) + lostbits = any_on(b,k); + if (x[k>>kshift] & 1 << (k & kmask)) + lostbits |= 2; + nbits -= n; + rshift(b,n); + e = emin; + } + if (lostbits) { + up = 0; + switch(rounding) { + case Round_zero: + break; + case Round_near: + if (lostbits & 2 + && (lostbits & 1) | (x[0] & 1)) + up = 1; + break; + case Round_up: + up = 1 - sign; + break; + case Round_down: + up = sign; + } + if (up) { + k = b->wds; + b = increment(b); + x = b->x; + if (denorm) { +#if 0 + if (nbits == Nbits - 1 + && x[nbits >> kshift] & 1 << (nbits & kmask)) + denorm = 0; /* not currently used */ +#endif + } + else if (b->wds > k + || ((n = nbits & kmask) !=0 + && hi0bits(x[k-1]) < 32-n)) { + rshift(b,1); + if (++e > Emax) + goto ovfl; + } + } + } +#ifdef IEEE_Arith + if (denorm) + word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0; + else + word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20); + word1(rvp) = b->x[0]; +#endif +#ifdef IBM + if ((j = e & 3)) { + k = b->x[0] & ((1 << j) - 1); + rshift(b,j); + if (k) { + switch(rounding) { + case Round_up: + if (!sign) + increment(b); + break; + case Round_down: + if (sign) + increment(b); + break; + case Round_near: + j = 1 << (j-1); + if (k & j && ((k & (j-1)) | lostbits)) + increment(b); + } + } + } + e >>= 2; + word0(rvp) = b->x[1] | ((e + 65 + 13) << 24); + word1(rvp) = b->x[0]; +#endif +#ifdef VAX + /* The next two lines ignore swap of low- and high-order 2 bytes. */ + /* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */ + /* word1(rvp) = b->x[0]; */ + word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16); + word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16); +#endif + Bfree(b); + } +#endif /*!NO_HEX_FP}*/ + + static int +#ifdef KR_headers +dshift(b, p2) Bigint *b; int p2; +#else +dshift(Bigint *b, int p2) +#endif +{ + int rv = hi0bits(b->x[b->wds-1]) - 4; + if (p2 > 0) + rv -= p2; + return rv & kmask; + } + + static int +quorem +#ifdef KR_headers + (b, S) Bigint *b, *S; +#else + (Bigint *b, Bigint *S) +#endif +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG +#ifdef NO_STRTOD_BIGCOMP + /*debug*/ if (q > 9) +#else + /* An oversized q is possible when quorem is called from bigcomp and */ + /* the input is near, e.g., twice the smallest denormalized number. */ + /*debug*/ if (q > 15) +#endif + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; + } + +#if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/ + static double +sulp +#ifdef KR_headers + (x, bc) U *x; BCinfo *bc; +#else + (U *x, BCinfo *bc) +#endif +{ + U u; + double rv; + int i; + + rv = ulp(x); + if (!bc->scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) + return rv; /* Is there an example where i <= 0 ? */ + word0(&u) = Exp_1 + (i << Exp_shift); + word1(&u) = 0; + return rv * u.d; + } +#endif /*}*/ + +#ifndef NO_STRTOD_BIGCOMP + static void +bigcomp +#ifdef KR_headers + (rv, s0, bc) + U *rv; CONST char *s0; BCinfo *bc; +#else + (U *rv, const char *s0, BCinfo *bc) +#endif +{ + Bigint *b, *d; + int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase; + + dsign = bc->dsign; + nd = bc->nd; + nd0 = bc->nd0; + p5 = nd + bc->e0 - 1; + speccase = 0; +#ifndef Sudden_Underflow + if (rv->d == 0.) { /* special case: value near underflow-to-zero */ + /* threshold was rounded to zero */ + b = i2b(1); + p2 = Emin - P + 1; + bbits = 1; +#ifdef Avoid_Underflow + word0(rv) = (P+2) << Exp_shift; +#else + word1(rv) = 1; +#endif + i = 0; +#ifdef Honor_FLT_ROUNDS + if (bc->rounding == 1) +#endif + { + speccase = 1; + --p2; + dsign = 0; + goto have_i; + } + } + else +#endif + b = d2b(rv, &p2, &bbits); +#ifdef Avoid_Underflow + p2 -= bc->scale; +#endif + /* floor(log2(rv)) == bbits - 1 + p2 */ + /* Check for denormal case. */ + i = P - bbits; + if (i > (j = P - Emin - 1 + p2)) { +#ifdef Sudden_Underflow + Bfree(b); + b = i2b(1); + p2 = Emin; + i = P - 1; +#ifdef Avoid_Underflow + word0(rv) = (1 + bc->scale) << Exp_shift; +#else + word0(rv) = Exp_msk1; +#endif + word1(rv) = 0; +#else + i = j; +#endif + } +#ifdef Honor_FLT_ROUNDS + if (bc->rounding != 1) { + if (i > 0) + b = lshift(b, i); + if (dsign) + b = increment(b); + } + else +#endif + { + b = lshift(b, ++i); + b->x[0] |= 1; + } +#ifndef Sudden_Underflow + have_i: +#endif + p2 -= p5 + i; + d = i2b(1); + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + */ + if (p5 > 0) + d = pow5mult(d, p5); + else if (p5 < 0) + b = pow5mult(b, -p5); + if (p2 > 0) { + b2 = p2; + d2 = 0; + } + else { + b2 = 0; + d2 = -p2; + } + i = dshift(d, d2); + if ((b2 += i) > 0) + b = lshift(b, b2); + if ((d2 += i) > 0) + d = lshift(d, d2); + + /* Now b/d = exactly half-way between the two floating-point values */ + /* on either side of the input string. Compute first digit of b/d. */ + + if (!(dig = quorem(b,d))) { + b = multadd(b, 10, 0); /* very unlikely */ + dig = quorem(b,d); + } + + /* Compare b/d with s0 */ + + for(i = 0; i < nd0; ) { + if ((dd = s0[i++] - '0' - dig)) + goto ret; + if (!b->x[0] && b->wds == 1) { + if (i < nd) + dd = 1; + goto ret; + } + b = multadd(b, 10, 0); + dig = quorem(b,d); + } + for(j = bc->dp1; i++ < nd;) { + if ((dd = s0[j++] - '0' - dig)) + goto ret; + if (!b->x[0] && b->wds == 1) { + if (i < nd) + dd = 1; + goto ret; + } + b = multadd(b, 10, 0); + dig = quorem(b,d); + } + if (b->x[0] || b->wds > 1) + dd = -1; + ret: + Bfree(b); + Bfree(d); +#ifdef Honor_FLT_ROUNDS + if (bc->rounding != 1) { + if (dd < 0) { + if (bc->rounding == 0) { + if (!dsign) + goto retlow1; + } + else if (dsign) + goto rethi1; + } + else if (dd > 0) { + if (bc->rounding == 0) { + if (dsign) + goto rethi1; + goto ret1; + } + if (!dsign) + goto rethi1; + dval(rv) += 2.*sulp(rv,bc); + } + else { + bc->inexact = 0; + if (dsign) + goto rethi1; + } + } + else +#endif + if (speccase) { + if (dd <= 0) + rv->d = 0.; + } + else if (dd < 0) { + if (!dsign) /* does not happen for round-near */ +retlow1: + dval(rv) -= sulp(rv,bc); + } + else if (dd > 0) { + if (dsign) { + rethi1: + dval(rv) += sulp(rv,bc); + } + } + else { + /* Exact half-way case: apply round-even rule. */ + if ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <= 0) { + i = 1 - j; + if (i <= 31) { + if (word1(rv) & (0x1 << i)) + goto odd; + } + else if (word0(rv) & (0x1 << (i-32))) + goto odd; + } + else if (word1(rv) & 1) { + odd: + if (dsign) + goto rethi1; + goto retlow1; + } + } + +#ifdef Honor_FLT_ROUNDS + ret1: +#endif + return; + } +#endif /* NO_STRTOD_BIGCOMP */ + + double +fpconv_strtod +#ifdef KR_headers + (s00, se) CONST char *s00; char **se; +#else + (const char *s00, char **se) +#endif +{ + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1; + int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign; + CONST char *s, *s0, *s1; + double aadj, aadj1; + Long L; + U aadj2, adj, rv, rv0; + ULong y, z; + BCinfo bc; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef Avoid_Underflow + ULong Lsb, Lsb1; +#endif +#ifdef SET_INEXACT + int oldinexact; +#endif +#ifndef NO_STRTOD_BIGCOMP + int req_bigcomp = 0; +#endif +#ifdef Honor_FLT_ROUNDS /*{*/ +#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ + bc.rounding = Flt_Rounds; +#else /*}{*/ + bc.rounding = 1; + switch(fegetround()) { + case FE_TOWARDZERO: bc.rounding = 0; break; + case FE_UPWARD: bc.rounding = 2; break; + case FE_DOWNWARD: bc.rounding = 3; + } +#endif /*}}*/ +#endif /*}*/ +#ifdef USE_LOCALE + CONST char *s2; +#endif + + sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0; + dval(&rv) = 0.; + for(s = s00;;s++) switch(*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } + break2: + if (*s == '0') { +#ifndef NO_HEX_FP /*{*/ + switch(s[1]) { + case 'x': + case 'X': +#ifdef Honor_FLT_ROUNDS + gethex(&s, &rv, bc.rounding, sign); +#else + gethex(&s, &rv, 1, sign); +#endif + goto ret; + } +#endif /*}*/ + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; + bc.dp0 = bc.dp1 = s - s0; + for(s1 = s; s1 > s0 && *--s1 == '0'; ) + ++nz1; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for(;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + c = *++s; + bc.dp1 = s - s0; + bc.dplen = bc.dp1 - bc.dp0; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + bc.dp0 = s0 - s; + bc.dp1 = bc.dp0 + bc.dplen; + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = nz1 = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + if (!bc.dplen) + switch(c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(&rv) = 0x7ff00000; + word1(&rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(&rv) = NAN_WORD0; + word1(&rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ + ret0: + s = s00; + sign = 0; + } + goto ret; + } + bc.e0 = e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + dval(&rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(&rv) = tens[k - 9] * dval(&rv) + z; + } + bd0 = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; +#ifndef ROUND_BIASED_without_Round_Up + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(&rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + e -= i; + dval(&rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + word0(&rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(&rv), tens[e]); + if ((word0(&rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(&rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(&rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(&rv), tens[-e]); + goto ret; + } +#endif +#endif /* ROUND_BIASED_without_Round_Up */ + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + bc.inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + bc.scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if (bc.rounding >= 2) { + if (sign) + bc.rounding = bc.rounding == 2 ? 0 : 2; + else + if (bc.rounding != 2) + bc.rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if ((i = e1 & 15)) + dval(&rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch(bc.rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(&rv) = Big0; + word1(&rv) = Big1; + break; + default: + word0(&rv) = Exp_mask; + word1(&rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(&rv) = Exp_mask; + word1(&rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(&rv0) = 1e300; + dval(&rv0) *= dval(&rv0); +#endif +#else /*IEEE_Arith*/ + word0(&rv) = Big0; + word1(&rv) = Big1; +#endif /*IEEE_Arith*/ + range_err: + if (bd0) { + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + } +#ifndef NO_ERRNO + errno = ERANGE; +#endif + goto ret; + } + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(&rv) -= P*Exp_msk1; + dval(&rv) *= bigtens[j]; + if ((z = word0(&rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(&rv) = Big0; + word1(&rv) = Big1; + } + else + word0(&rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if ((i = e1 & 15)) + dval(&rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + bc.scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= tinytens[j]; + if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; clear j low bits */ + if (j >= 32) { + if (j > 54) + goto undfl; + word1(&rv) = 0; + if (j >= 53) + word0(&rv) = (P+2)*Exp_msk1; + else + word0(&rv) &= 0xffffffff << (j-32); + } + else + word1(&rv) &= 0xffffffff << j; + } +#else + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(&rv0) = dval(&rv); + dval(&rv) *= tinytens[j]; + if (!dval(&rv)) { + dval(&rv) = 2.*dval(&rv0); + dval(&rv) *= tinytens[j]; +#endif + if (!dval(&rv)) { + undfl: + dval(&rv) = 0.; + goto range_err; + } +#ifndef Avoid_Underflow + word0(&rv) = Tiny0; + word1(&rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bc.nd = nd - nz1; +#ifndef NO_STRTOD_BIGCOMP + bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */ + /* to silence an erroneous warning about bc.nd0 */ + /* possibly not being initialized. */ + if (nd > strtod_diglim) { + /* ASSERT(strtod_diglim >= 18); 18 == one more than the */ + /* minimum number of decimal digits to distinguish double values */ + /* in IEEE arithmetic. */ + i = j = 18; + if (i > nd0) + j += bc.dplen; + for(;;) { + if (--j < bc.dp1 && j >= bc.dp0) + j = bc.dp0 - 1; + if (s0[j] != '0') + break; + --i; + } + e += nd - i; + nd = i; + if (nd0 > nd) + nd0 = nd; + if (nd < 9) { /* must recompute y */ + y = 0; + for(i = 0; i < nd0; ++i) + y = 10*y + s0[i] - '0'; + for(j = bc.dp1; i < nd; ++i) + y = 10*y + s0[j++] - '0'; + } + } +#endif + bd0 = s2b(s0, nd0, nd, y, bc.dplen); + + for(;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(&rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (bc.rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + Lsb = LSB; + Lsb1 = 0; + j = bbe - bc.scale; + i = j + bbbits - 1; /* logb(rv) */ + j = P + 1 - bbbits; + if (i < Emin) { /* denormal */ + i = Emin - i; + j -= i; + if (i < 32) + Lsb <<= i; + else if (i < 52) + Lsb1 = Lsb << (i-32); + else + Lsb1 = Exp_mask; + } +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += bc.scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + bc.dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifndef NO_STRTOD_BIGCOMP /*{*/ + if (bc.nd > nd && i <= 0) { + if (bc.dsign) { + /* Must use bigcomp(). */ + req_bigcomp = 1; + break; + } +#ifdef Honor_FLT_ROUNDS + if (bc.rounding != 1) { + if (i < 0) { + req_bigcomp = 1; + break; + } + } + else +#endif + i = -1; /* Discarded digits make delta smaller. */ + } +#endif /*}*/ +#ifdef Honor_FLT_ROUNDS /*{*/ + if (bc.rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + bc.inexact = 0; +#endif + break; + } + if (bc.rounding) { + if (bc.dsign) { + adj.d = 1.; + goto apply_adj; + } + } + else if (!bc.dsign) { + adj.d = -1.; + if (!word1(&rv) + && !(word0(&rv) & Frac_mask)) { + y = word0(&rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!bc.scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (cmp(delta, bs) <= 0) + adj.d = -0.5; + } + } + apply_adj: +#ifdef Avoid_Underflow /*{*/ + if (bc.scale && (y = word0(&rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(&adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= + P*Exp_msk1) { + word0(&rv) += P*Exp_msk1; + dval(&rv) += adj.d*ulp(dval(&rv)); + word0(&rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow}*/ + dval(&rv) += adj.d*ulp(&rv); + } + break; + } + adj.d = ratio(delta, bs); + if (adj.d < 1.) + adj.d = 1.; + if (adj.d <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj.d; + if (y != adj.d) { + if (!((bc.rounding>>1) ^ bc.dsign)) + y++; + adj.d = y; + } + } +#ifdef Avoid_Underflow /*{*/ + if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(&adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { + word0(&rv) += P*Exp_msk1; + adj.d *= ulp(dval(&rv)); + if (bc.dsign) + dval(&rv) += adj.d; + else + dval(&rv) -= adj.d; + word0(&rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow}*/ + adj.d *= ulp(&rv); + if (bc.dsign) { + if (word0(&rv) == Big0 && word1(&rv) == Big1) + goto ovfl; + dval(&rv) += adj.d; + } + else + dval(&rv) -= adj.d; + goto cont; + } +#endif /*}Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask +#ifdef IEEE_Arith /*{*/ +#ifdef Avoid_Underflow + || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(&rv) & Exp_mask) <= Exp_msk1 +#endif +#endif /*}*/ + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + bc.inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + bc.inexact = 0; +#endif + break; + } + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (bc.dsign) { + if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 + && word1(&rv) == ( +#ifdef Avoid_Underflow + (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + if (word0(&rv) == Big0 && word1(&rv) == Big1) + goto ovfl; + word0(&rv) = (word0(&rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(&rv) = 0; +#ifdef Avoid_Underflow + bc.dsign = 0; +#endif + break; + } + } + else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(&rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (bc.scale) { + L = word0(&rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(&rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(&rv) = L | Bndry_mask1; + word1(&rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else +#ifndef NO_STRTOD_BIGCOMP + if (bc.nd > nd) + goto cont; +#endif + break; +#endif + } +#ifndef ROUND_BIASED +#ifdef Avoid_Underflow + if (Lsb1) { + if (!(word0(&rv) & Lsb1)) + break; + } + else if (!(word1(&rv) & Lsb)) + break; +#else + if (!(word1(&rv) & LSB)) + break; +#endif +#endif + if (bc.dsign) +#ifdef Avoid_Underflow + dval(&rv) += sulp(&rv, &bc); +#else + dval(&rv) += ulp(&rv); +#endif +#ifndef ROUND_BIASED + else { +#ifdef Avoid_Underflow + dval(&rv) -= sulp(&rv, &bc); +#else + dval(&rv) -= ulp(&rv); +#endif +#ifndef Sudden_Underflow + if (!dval(&rv)) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } +#endif + } +#ifdef Avoid_Underflow + bc.dsign = 1 - bc.dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (bc.dsign) + aadj = aadj1 = 1.; + else if (word1(&rv) || word0(&rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(&rv) == Tiny1 && !word0(&rv)) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } +#endif + aadj = 1.; + aadj1 = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = bc.dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(bc.rounding) { + case 2: /* towards +infinity */ + aadj1 -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + aadj1 += 0.5; + } +#else + if (Flt_Rounds == 0) + aadj1 += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(&rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(&rv0) = dval(&rv); + word0(&rv) -= P*Exp_msk1; + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + if ((word0(&rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(&rv0) == Big0 && word1(&rv0) == Big1) + goto ovfl; + word0(&rv) = Big0; + word1(&rv) = Big1; + goto cont; + } + else + word0(&rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (bc.scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = aadj) <= 0) + z = 1; + aadj = z; + aadj1 = bc.dsign ? aadj : -aadj; + } + dval(&aadj2) = aadj1; + word0(&aadj2) += (2*P+1)*Exp_msk1 - y; + aadj1 = dval(&aadj2); + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + if (rv.d == 0.) +#ifdef NO_STRTOD_BIGCOMP + goto undfl; +#else + { + if (bc.nd > nd) + bc.dsign = 1; + break; + } +#endif + } + else { + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + } +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { + dval(&rv0) = dval(&rv); + word0(&rv) += P*Exp_msk1; + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; +#ifdef IBM + if ((word0(&rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(&rv0) == Tiny0 + && word1(&rv0) == Tiny1) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + word0(&rv) = Tiny0; + word1(&rv) = Tiny1; + goto cont; + } + else + word0(&rv) -= P*Exp_msk1; + } + else { + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + aadj1 = (double)(int)(aadj + 0.5); + if (!bc.dsign) + aadj1 = -aadj1; + } + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(&rv) & Exp_mask; +#ifndef SET_INEXACT + if (bc.nd == nd) { +#ifdef Avoid_Underflow + if (!bc.scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } + } +#endif + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); +#ifndef NO_STRTOD_BIGCOMP + if (req_bigcomp) { + bd0 = 0; + bc.e0 += nz1; + bigcomp(&rv, s0, &bc); + y = word0(&rv) & Exp_mask; + if (y == Exp_mask) + goto ovfl; + if (y == 0 && rv.d == 0.) + goto undfl; + } +#endif +#ifdef SET_INEXACT + if (bc.inexact) { + if (!oldinexact) { + word0(&rv0) = Exp_1 + (70 << Exp_shift); + word1(&rv0) = 0; + dval(&rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (bc.scale) { + word0(&rv0) = Exp_1 - 2*P*Exp_msk1; + word1(&rv0) = 0; + dval(&rv) *= dval(&rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ +#ifdef IEEE_Arith + if (!(word0(&rv) & Exp_mask)) +#else + if (word0(&rv) == 0 && word1(&rv) == 0) +#endif + errno = ERANGE; +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (bc.inexact && !(word0(&rv) & Exp_mask)) { + /* set underflow bit */ + dval(&rv0) = 1e-300; + dval(&rv0) *= dval(&rv0); + } +#endif + ret: + if (se) + *se = (char *)s; + return sign ? -dval(&rv) : dval(&rv); + } + +#ifndef MULTIPLE_THREADS + static char *dtoa_result; +#endif + + static char * +#ifdef KR_headers +rv_alloc(i) int i; +#else +rv_alloc(int i) +#endif +{ + int j, k, *r; + + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; + j <<= 1) + k++; + r = (int*)Balloc(k); + *r = k; + return +#ifndef MULTIPLE_THREADS + dtoa_result = +#endif + (char *)(r+1); + } + + static char * +#ifdef KR_headers +nrv_alloc(s, rve, n) char *s, **rve; int n; +#else +nrv_alloc(const char *s, char **rve, int n) +#endif +{ + char *rv, *t; + + t = rv = rv_alloc(n); + while((*t = *s++)) t++; + if (rve) + *rve = t; + return rv; + } + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + + void +#ifdef KR_headers +freedtoa(s) char *s; +#else +freedtoa(char *s) +#endif +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(b); +#ifndef MULTIPLE_THREADS + if (s == dtoa_result) + dtoa_result = 0; +#endif + } + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + + char * +dtoa +#ifdef KR_headers + (dd, mode, ndigits, decpt, sign, rve) + double dd; int mode, ndigits, *decpt, *sign; char **rve; +#else + (double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) +#endif +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo, *mhi, *S; + U d2, eps, u; + double ds; + char *s, *s0; +#ifndef No_leftright +#ifdef IEEE_Arith + U eps1; +#endif +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS /*{*/ + int Rounding; +#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ + Rounding = Flt_Rounds; +#else /*}{*/ + Rounding = 1; + switch(fegetround()) { + case FE_TOWARDZERO: Rounding = 0; break; + case FE_UPWARD: Rounding = 2; break; + case FE_DOWNWARD: Rounding = 3; + } +#endif /*}}*/ +#endif /*}*/ + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif + + u.d = dd; + if (word0(&u) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(&u) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(&u) & Exp_mask) == Exp_mask) +#else + if (word0(&u) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(&u) && !(word0(&u) & 0xfffff)) + return nrv_alloc("Infinity", rve, 8); +#endif + return nrv_alloc("NaN", rve, 3); + } +#endif +#ifdef IBM + dval(&u) += 0; /* normalize */ +#endif + if (!dval(&u)) { + *decpt = 1; + return nrv_alloc("0", rve, 1); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if (Rounding >= 2) { + if (*sign) + Rounding = Rounding == 2 ? 0 : 2; + else + if (Rounding != 2) + Rounding = 0; + } +#endif + + b = d2b(&u, &be, &bbits); +#ifdef Sudden_Underflow + i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { +#endif + dval(&d2) = dval(&u); + word0(&d2) &= Frac_mask1; + word0(&d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(&d2) & Frac_mask)) + dval(&d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) + : word1(&u) << (32 - i); + dval(&d2) = x; + word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(&u) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ + /* silence erroneous "gcc -Wall" warning. */ + switch(mode) { + case 0: + case 1: + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(i); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && Rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(&d2) = dval(&u); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(&u) /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(&u) /= ds; + } + else if ((j1 = -k)) { + dval(&u) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(&u) *= bigtens[i]; + } + } + if (k_check && dval(&u) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(&u) *= 10.; + ieps++; + } + dval(&eps) = ieps*dval(&u) + 7.; + word0(&eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(&u) -= 5.; + if (dval(&u) > dval(&eps)) + goto one_digit; + if (dval(&u) < -dval(&eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); +#ifdef IEEE_Arith + if (k0 < 0 && j1 >= 307) { + eps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */ + word0(&eps1) -= Exp_msk1 * (Bias+P-1); + dval(&eps1) *= tens[j1 & 0xf]; + for(i = 0, j = (j1-256) >> 4; j; j >>= 1, i++) + if (j & 1) + dval(&eps1) *= bigtens[i]; + if (eps.d < eps1.d) + eps.d = eps1.d; + } +#endif + for(i = 0;;) { + L = dval(&u); + dval(&u) -= L; + *s++ = '0' + (int)L; + if (1. - dval(&u) < dval(&eps)) + goto bump_up; + if (dval(&u) < dval(&eps)) + goto ret1; + if (++i >= ilim) + break; + dval(&eps) *= 10.; + dval(&u) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(&eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(&u) *= 10.) { + L = (Long)(dval(&u)); + if (!(dval(&u) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(&u) > 0.5 + dval(&eps)) + goto bump_up; + else if (dval(&u) < 0.5 - dval(&eps)) { + while(*--s == '0'); + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + dval(&u) = dval(&d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(&u) <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1;; i++, dval(&u) *= 10.) { + L = (Long)(dval(&u) / ds); + dval(&u) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(&u) < 0) { + L--; + dval(&u) += ds; + } +#endif + *s++ = '0' + (int)L; + if (!dval(&u)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(Rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(&u) += dval(&u); +#ifdef ROUND_BIASED + if (dval(&u) >= ds) +#else + if (dval(&u) > ds || (dval(&u) == ds && L & 1)) +#endif + { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + if ((j = b5 - m5)) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && Rounding == 1 +#endif + ) { + if (!word1(&u) && !(word0(&u) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(&u) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ + i = dshift(S, s2); + b2 += i; + m2 += i; + s2 += i; + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ + no_digits: + k = -1 - ndigits; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(&u) & 1) +#ifdef Honor_FLT_ROUNDS + && Rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || (j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(&u) & 1) +#endif + )) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(Rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); +#ifdef ROUND_BIASED + if (j1 >= 0 /*)*/ +#else + if ((j1 > 0 || (j1 == 0 && dig & 1)) +#endif + && dig++ == '9') + goto round_9_up; + } + accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!Rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS + keep_dig: +#endif + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch(Rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(b, 1); + j = cmp(b, S); +#ifdef ROUND_BIASED + if (j >= 0) +#else + if (j > 0 || (j == 0 && dig & 1)) +#endif + { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { +#ifdef Honor_FLT_ROUNDS + trimzeros: +#endif + while(*--s == '0'); + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(&u) = Exp_1 + (70 << Exp_shift); + word1(&u) = 0; + dval(&u) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + } +#ifdef __cplusplus +} +#endif diff --git a/luaclib/cjson/dtoa_config.h b/luaclib/cjson/dtoa_config.h new file mode 100644 index 0000000..380e83b --- /dev/null +++ b/luaclib/cjson/dtoa_config.h @@ -0,0 +1,74 @@ +#ifndef _DTOA_CONFIG_H +#define _DTOA_CONFIG_H + +#include +#include +#include + +/* Ensure dtoa.c does not USE_LOCALE. Lua CJSON must not use locale + * aware conversion routines. */ +#undef USE_LOCALE + +/* dtoa.c should not touch errno, Lua CJSON does not use it, and it + * may not be threadsafe */ +#define NO_ERRNO + +#define Long int32_t +#define ULong uint32_t +#define Llong int64_t +#define ULLong uint64_t + +#ifdef IEEE_BIG_ENDIAN +#define IEEE_MC68k +#else +#define IEEE_8087 +#endif + +#define MALLOC(n) xmalloc(n) + +static void *xmalloc(size_t size) +{ + void *p; + + p = malloc(size); + if (!p) { + fprintf(stderr, "Out of memory"); + abort(); + } + + return p; +} + +#ifdef MULTIPLE_THREADS + +/* Enable locking to support multi-threaded applications */ + +#include + +static pthread_mutex_t private_dtoa_lock[2] = { + PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER +}; + +#define ACQUIRE_DTOA_LOCK(n) do { \ + int r = pthread_mutex_lock(&private_dtoa_lock[n]); \ + if (r) { \ + fprintf(stderr, "pthread_mutex_lock failed with %d\n", r); \ + abort(); \ + } \ +} while (0) + +#define FREE_DTOA_LOCK(n) do { \ + int r = pthread_mutex_unlock(&private_dtoa_lock[n]); \ + if (r) { \ + fprintf(stderr, "pthread_mutex_unlock failed with %d\n", r);\ + abort(); \ + } \ +} while (0) + +#endif /* MULTIPLE_THREADS */ + +#endif /* _DTOA_CONFIG_H */ + +/* vi:ai et sw=4 ts=4: + */ diff --git a/luaclib/cjson/fpconv.c b/luaclib/cjson/fpconv.c new file mode 100644 index 0000000..7990831 --- /dev/null +++ b/luaclib/cjson/fpconv.c @@ -0,0 +1,205 @@ +/* fpconv - Floating point conversion routines + * + * Copyright (c) 2011-2012 Mark Pulford + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries + * with locale support will break when the decimal separator is a comma. + * + * fpconv_* will around these issues with a translation buffer if required. + */ + +#include +#include +#include +#include + +#include "fpconv.h" + +/* Lua CJSON assumes the locale is the same for all threads within a + * process and doesn't change after initialisation. + * + * This avoids the need for per thread storage or expensive checks + * for call. */ +static char locale_decimal_point = '.'; + +/* In theory multibyte decimal_points are possible, but + * Lua CJSON only supports UTF-8 and known locales only have + * single byte decimal points ([.,]). + * + * localconv() may not be thread safe (=>crash), and nl_langinfo() is + * not supported on some platforms. Use sprintf() instead - if the + * locale does change, at least Lua CJSON won't crash. */ +static void fpconv_update_locale() +{ + char buf[8]; + + snprintf(buf, sizeof(buf), "%g", 0.5); + + /* Failing this test might imply the platform has a buggy dtoa + * implementation or wide characters */ + if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) { + fprintf(stderr, "Error: wide characters found or printf() bug."); + abort(); + } + + locale_decimal_point = buf[1]; +} + +/* Check for a valid number character: [-+0-9a-yA-Y.] + * Eg: -0.6e+5, infinity, 0xF0.F0pF0 + * + * Used to find the probable end of a number. It doesn't matter if + * invalid characters are counted - strtod() will find the valid + * number if it exists. The risk is that slightly more memory might + * be allocated before a parse error occurs. */ +static inline int valid_number_character(char ch) +{ + char lower_ch; + + if ('0' <= ch && ch <= '9') + return 1; + if (ch == '-' || ch == '+' || ch == '.') + return 1; + + /* Hex digits, exponent (e), base (p), "infinity",.. */ + lower_ch = ch | 0x20; + if ('a' <= lower_ch && lower_ch <= 'y') + return 1; + + return 0; +} + +/* Calculate the size of the buffer required for a strtod locale + * conversion. */ +static int strtod_buffer_size(const char *s) +{ + const char *p = s; + + while (valid_number_character(*p)) + p++; + + return p - s; +} + +/* Similar to strtod(), but must be passed the current locale's decimal point + * character. Guaranteed to be called at the start of any valid number in a string */ +double fpconv_strtod(const char *nptr, char **endptr) +{ + char localbuf[FPCONV_G_FMT_BUFSIZE]; + char *buf, *endbuf, *dp; + int buflen; + double value; + + /* System strtod() is fine when decimal point is '.' */ + if (locale_decimal_point == '.') + return strtod(nptr, endptr); + + buflen = strtod_buffer_size(nptr); + if (!buflen) { + /* No valid characters found, standard strtod() return */ + *endptr = (char *)nptr; + return 0; + } + + /* Duplicate number into buffer */ + if (buflen >= FPCONV_G_FMT_BUFSIZE) { + /* Handle unusually large numbers */ + buf = malloc(buflen + 1); + if (!buf) { + fprintf(stderr, "Out of memory"); + abort(); + } + } else { + /* This is the common case.. */ + buf = localbuf; + } + memcpy(buf, nptr, buflen); + buf[buflen] = 0; + + /* Update decimal point character if found */ + dp = strchr(buf, '.'); + if (dp) + *dp = locale_decimal_point; + + value = strtod(buf, &endbuf); + *endptr = (char *)&nptr[endbuf - buf]; + if (buflen >= FPCONV_G_FMT_BUFSIZE) + free(buf); + + return value; +} + +/* "fmt" must point to a buffer of at least 6 characters */ +static void set_number_format(char *fmt, int precision) +{ + int d1, d2, i; + + assert(1 <= precision && precision <= 14); + + /* Create printf format (%.14g) from precision */ + d1 = precision / 10; + d2 = precision % 10; + fmt[0] = '%'; + fmt[1] = '.'; + i = 2; + if (d1) { + fmt[i++] = '0' + d1; + } + fmt[i++] = '0' + d2; + fmt[i++] = 'g'; + fmt[i] = 0; +} + +/* Assumes there is always at least 32 characters available in the target buffer */ +int fpconv_g_fmt(char *str, double num, int precision) +{ + char buf[FPCONV_G_FMT_BUFSIZE]; + char fmt[6]; + int len; + char *b; + + set_number_format(fmt, precision); + + /* Pass through when decimal point character is dot. */ + if (locale_decimal_point == '.') + return snprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num); + + /* snprintf() to a buffer then translate for other decimal point characters */ + len = snprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num); + + /* Copy into target location. Translate decimal point if required */ + b = buf; + do { + *str++ = (*b == locale_decimal_point ? '.' : *b); + } while(*b++); + + return len; +} + +void fpconv_init() +{ + fpconv_update_locale(); +} + +/* vi:ai et sw=4 ts=4: + */ diff --git a/luaclib/cjson/fpconv.h b/luaclib/cjson/fpconv.h new file mode 100644 index 0000000..0124908 --- /dev/null +++ b/luaclib/cjson/fpconv.h @@ -0,0 +1,22 @@ +/* Lua CJSON floating point conversion routines */ + +/* Buffer required to store the largest string representation of a double. + * + * Longest double printed with %.14g is 21 characters long: + * -1.7976931348623e+308 */ +# define FPCONV_G_FMT_BUFSIZE 32 + +#ifdef USE_INTERNAL_FPCONV +static inline void fpconv_init() +{ + /* Do nothing - not required */ +} +#else +extern inline void fpconv_init(); +#endif + +extern int fpconv_g_fmt(char*, double, int); +extern double fpconv_strtod(const char*, char**); + +/* vi:ai et sw=4 ts=4: + */ diff --git a/luaclib/cjson/g_fmt.c b/luaclib/cjson/g_fmt.c new file mode 100644 index 0000000..50d6a1d --- /dev/null +++ b/luaclib/cjson/g_fmt.c @@ -0,0 +1,111 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 1996 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* g_fmt(buf,x) stores the closest decimal approximation to x in buf; + * it suffices to declare buf + * char buf[32]; + */ + +#ifdef __cplusplus +extern "C" { +#endif + extern char *dtoa(double, int, int, int *, int *, char **); + extern int g_fmt(char *, double, int); + extern void freedtoa(char*); +#ifdef __cplusplus + } +#endif + +int +fpconv_g_fmt(char *b, double x, int precision) +{ + register int i, k; + register char *s; + int decpt, j, sign; + char *b0, *s0, *se; + + b0 = b; +#ifdef IGNORE_ZERO_SIGN + if (!x) { + *b++ = '0'; + *b = 0; + goto done; + } +#endif + s = s0 = dtoa(x, 2, precision, &decpt, &sign, &se); + if (sign) + *b++ = '-'; + if (decpt == 9999) /* Infinity or Nan */ { + while((*b++ = *s++)); + /* "b" is used to calculate the return length. Decrement to exclude the + * Null terminator from the length */ + b--; + goto done0; + } + if (decpt <= -4 || decpt > precision) { + *b++ = *s++; + if (*s) { + *b++ = '.'; + while((*b = *s++)) + b++; + } + *b++ = 'e'; + /* sprintf(b, "%+.2d", decpt - 1); */ + if (--decpt < 0) { + *b++ = '-'; + decpt = -decpt; + } + else + *b++ = '+'; + for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10); + for(;;) { + i = decpt / k; + *b++ = i + '0'; + if (--j <= 0) + break; + decpt -= i*k; + decpt *= 10; + } + *b = 0; + } + else if (decpt <= 0) { + *b++ = '0'; + *b++ = '.'; + for(; decpt < 0; decpt++) + *b++ = '0'; + while((*b++ = *s++)); + b--; + } + else { + while((*b = *s++)) { + b++; + if (--decpt == 0 && *s) + *b++ = '.'; + } + for(; decpt > 0; decpt--) + *b++ = '0'; + *b = 0; + } + done0: + freedtoa(s0); +#ifdef IGNORE_ZERO_SIGN + done: +#endif + return b - b0; + } diff --git a/luaclib/cjson/lua-cjson-2.1devel-1.rockspec b/luaclib/cjson/lua-cjson-2.1devel-1.rockspec new file mode 100644 index 0000000..154e333 --- /dev/null +++ b/luaclib/cjson/lua-cjson-2.1devel-1.rockspec @@ -0,0 +1,56 @@ +package = "lua-cjson" +version = "2.1devel-1" + +source = { + url = "http://www.kyne.com.au/~mark/software/download/lua-cjson-2.1devel.zip", +} + +description = { + summary = "A fast JSON encoding/parsing module", + detailed = [[ + The Lua CJSON module provides JSON support for Lua. It features: + - Fast, standards compliant encoding/parsing routines + - Full support for JSON with UTF-8, including decoding surrogate pairs + - Optional run-time support for common exceptions to the JSON specification + (infinity, NaN,..) + - No dependencies on other libraries + ]], + homepage = "http://www.kyne.com.au/~mark/software/lua-cjson.php", + license = "MIT" +} + +dependencies = { + "lua >= 5.1" +} + +build = { + type = "builtin", + modules = { + cjson = { + sources = { "lua_cjson.c", "strbuf.c", "fpconv.c" }, + defines = { +-- LuaRocks does not support platform specific configuration for Solaris. +-- Uncomment the line below on Solaris platforms if required. +-- "USE_INTERNAL_ISINF" + } + } + }, + install = { + lua = { + ["cjson.util"] = "lua/cjson/util.lua" + }, + bin = { + json2lua = "lua/json2lua.lua", + lua2json = "lua/lua2json.lua" + } + }, + -- Override default build options (per platform) + platforms = { + win32 = { modules = { cjson = { defines = { + "DISABLE_INVALID_NUMBERS" + } } } } + }, + copy_directories = { "tests" } +} + +-- vi:ai et sw=4 ts=4: diff --git a/luaclib/cjson/lua-cjson.spec b/luaclib/cjson/lua-cjson.spec new file mode 100644 index 0000000..13fc56d --- /dev/null +++ b/luaclib/cjson/lua-cjson.spec @@ -0,0 +1,80 @@ +%define luaver 5.1 +%define lualibdir %{_libdir}/lua/%{luaver} +%define luadatadir %{_datadir}/lua/%{luaver} + +Name: lua-cjson +Version: 2.1devel +Release: 1%{?dist} +Summary: A fast JSON encoding/parsing module for Lua + +Group: Development/Libraries +License: MIT +URL: http://www.kyne.com.au/~mark/software/lua-cjson/ +Source0: http://www.kyne.com.au/~mark/software/lua-cjson/download/lua-cjson-%{version}.tar.gz +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +BuildRequires: lua >= %{luaver}, lua-devel >= %{luaver} +Requires: lua >= %{luaver} + +%description +The Lua CJSON module provides JSON support for Lua. It features: +- Fast, standards compliant encoding/parsing routines +- Full support for JSON with UTF-8, including decoding surrogate pairs +- Optional run-time support for common exceptions to the JSON specification + (infinity, NaN,..) +- No dependencies on other libraries + + +%prep +%setup -q + + +%build +make %{?_smp_mflags} CFLAGS="%{optflags}" LUA_INCLUDE_DIR="%{_includedir}" + + +%install +rm -rf "$RPM_BUILD_ROOT" +make install DESTDIR="$RPM_BUILD_ROOT" LUA_CMODULE_DIR="%{lualibdir}" +make install-extra DESTDIR="$RPM_BUILD_ROOT" LUA_MODULE_DIR="%{luadatadir}" \ + LUA_BIN_DIR="%{_bindir}" + + +%clean +rm -rf "$RPM_BUILD_ROOT" + + +%preun +/bin/rm -f "%{luadatadir}/cjson/tests/utf8.dat" + + +%files +%defattr(-,root,root,-) +%doc LICENSE NEWS performance.html performance.txt manual.html manual.txt rfc4627.txt THANKS +%{lualibdir}/* +%{luadatadir}/* +%{_bindir}/* + + +%changelog +* Thu Mar 1 2012 Mark Pulford - 2.1.0-1 +- Update for 2.1.0 + +* Sun Jan 22 2012 Mark Pulford - 2.0.0-1 +- Update for 2.0.0 +- Install lua2json / json2lua utilities + +* Wed Nov 27 2011 Mark Pulford - 1.0.4-1 +- Update for 1.0.4 + +* Wed Sep 15 2011 Mark Pulford - 1.0.3-1 +- Update for 1.0.3 + +* Sun May 29 2011 Mark Pulford - 1.0.2-1 +- Update for 1.0.2 + +* Sun May 10 2011 Mark Pulford - 1.0.1-1 +- Update for 1.0.1 + +* Sun May 1 2011 Mark Pulford - 1.0-1 +- Initial package diff --git a/luaclib/cjson/lua/cjson/util.lua b/luaclib/cjson/lua/cjson/util.lua new file mode 100644 index 0000000..6916dad --- /dev/null +++ b/luaclib/cjson/lua/cjson/util.lua @@ -0,0 +1,271 @@ +local json = require "cjson" + +-- Various common routines used by the Lua CJSON package +-- +-- Mark Pulford + +-- Determine with a Lua table can be treated as an array. +-- Explicitly returns "not an array" for very sparse arrays. +-- Returns: +-- -1 Not an array +-- 0 Empty table +-- >0 Highest index in the array +local function is_array(table) + local max = 0 + local count = 0 + for k, v in pairs(table) do + if type(k) == "number" then + if k > max then max = k end + count = count + 1 + else + return -1 + end + end + if max > count * 2 then + return -1 + end + + return max +end + +local serialise_value + +local function serialise_table(value, indent, depth) + local spacing, spacing2, indent2 + if indent then + spacing = "\n" .. indent + spacing2 = spacing .. " " + indent2 = indent .. " " + else + spacing, spacing2, indent2 = " ", " ", false + end + depth = depth + 1 + if depth > 50 then + return "Cannot serialise any further: too many nested tables" + end + + local max = is_array(value) + + local comma = false + local fragment = { "{" .. spacing2 } + if max > 0 then + -- Serialise array + for i = 1, max do + if comma then + table.insert(fragment, "," .. spacing2) + end + table.insert(fragment, serialise_value(value[i], indent2, depth)) + comma = true + end + elseif max < 0 then + -- Serialise table + for k, v in pairs(value) do + if comma then + table.insert(fragment, "," .. spacing2) + end + table.insert(fragment, + ("[%s] = %s"):format(serialise_value(k, indent2, depth), + serialise_value(v, indent2, depth))) + comma = true + end + end + table.insert(fragment, spacing .. "}") + + return table.concat(fragment) +end + +function serialise_value(value, indent, depth) + if indent == nil then indent = "" end + if depth == nil then depth = 0 end + + if value == json.null then + return "json.null" + elseif type(value) == "string" then + return ("%q"):format(value) + elseif type(value) == "nil" or type(value) == "number" or + type(value) == "boolean" then + return tostring(value) + elseif type(value) == "table" then + return serialise_table(value, indent, depth) + else + return "\"<" .. type(value) .. ">\"" + end +end + +local function file_load(filename) + local file + if filename == nil then + file = io.stdin + else + local err + file, err = io.open(filename, "rb") + if file == nil then + error(("Unable to read '%s': %s"):format(filename, err)) + end + end + local data = file:read("*a") + + if filename ~= nil then + file:close() + end + + if data == nil then + error("Failed to read " .. filename) + end + + return data +end + +local function file_save(filename, data) + local file + if filename == nil then + file = io.stdout + else + local err + file, err = io.open(filename, "wb") + if file == nil then + error(("Unable to write '%s': %s"):format(filename, err)) + end + end + file:write(data) + if filename ~= nil then + file:close() + end +end + +local function compare_values(val1, val2) + local type1 = type(val1) + local type2 = type(val2) + if type1 ~= type2 then + return false + end + + -- Check for NaN + if type1 == "number" and val1 ~= val1 and val2 ~= val2 then + return true + end + + if type1 ~= "table" then + return val1 == val2 + end + + -- check_keys stores all the keys that must be checked in val2 + local check_keys = {} + for k, _ in pairs(val1) do + check_keys[k] = true + end + + for k, v in pairs(val2) do + if not check_keys[k] then + return false + end + + if not compare_values(val1[k], val2[k]) then + return false + end + + check_keys[k] = nil + end + for k, _ in pairs(check_keys) do + -- Not the same if any keys from val1 were not found in val2 + return false + end + return true +end + +local test_count_pass = 0 +local test_count_total = 0 + +local function run_test_summary() + return test_count_pass, test_count_total +end + +local function run_test(testname, func, input, should_work, output) + local function status_line(name, status, value) + local statusmap = { [true] = ":success", [false] = ":error" } + if status ~= nil then + name = name .. statusmap[status] + end + print(("[%s] %s"):format(name, serialise_value(value, false))) + end + + local result = { pcall(func, unpack(input)) } + local success = table.remove(result, 1) + + local correct = false + if success == should_work and compare_values(result, output) then + correct = true + test_count_pass = test_count_pass + 1 + end + test_count_total = test_count_total + 1 + + local teststatus = { [true] = "PASS", [false] = "FAIL" } + print(("==> Test [%d] %s: %s"):format(test_count_total, testname, + teststatus[correct])) + + status_line("Input", nil, input) + if not correct then + status_line("Expected", should_work, output) + end + status_line("Received", success, result) + print() + + return correct, result +end + +local function run_test_group(tests) + local function run_helper(name, func, input) + if type(name) == "string" and #name > 0 then + print("==> " .. name) + end + -- Not a protected call, these functions should never generate errors. + func(unpack(input or {})) + print() + end + + for _, v in ipairs(tests) do + -- Run the helper if "should_work" is missing + if v[4] == nil then + run_helper(unpack(v)) + else + run_test(unpack(v)) + end + end +end + +-- Run a Lua script in a separate environment +local function run_script(script, env) + local env = env or {} + local func + + -- Use setfenv() if it exists, otherwise assume Lua 5.2 load() exists + if _G.setfenv then + func = loadstring(script) + if func then + setfenv(func, env) + end + else + func = load(script, nil, nil, env) + end + + if func == nil then + error("Invalid syntax.") + end + func() + + return env +end + +-- Export functions +return { + serialise_value = serialise_value, + file_load = file_load, + file_save = file_save, + compare_values = compare_values, + run_test_summary = run_test_summary, + run_test = run_test, + run_test_group = run_test_group, + run_script = run_script +} + +-- vi:ai et sw=4 ts=4: diff --git a/luaclib/cjson/lua/json2lua.lua b/luaclib/cjson/lua/json2lua.lua new file mode 100644 index 0000000..014416d --- /dev/null +++ b/luaclib/cjson/lua/json2lua.lua @@ -0,0 +1,14 @@ +#!/usr/bin/env lua + +-- usage: json2lua.lua [json_file] +-- +-- Eg: +-- echo '[ "testing" ]' | ./json2lua.lua +-- ./json2lua.lua test.json + +local json = require "cjson" +local util = require "cjson.util" + +local json_text = util.file_load(arg[1]) +local t = json.decode(json_text) +print(util.serialise_value(t)) diff --git a/luaclib/cjson/lua/lua2json.lua b/luaclib/cjson/lua/lua2json.lua new file mode 100644 index 0000000..aee8869 --- /dev/null +++ b/luaclib/cjson/lua/lua2json.lua @@ -0,0 +1,20 @@ +#!/usr/bin/env lua + +-- usage: lua2json.lua [lua_file] +-- +-- Eg: +-- echo '{ "testing" }' | ./lua2json.lua +-- ./lua2json.lua test.lua + +local json = require "cjson" +local util = require "cjson.util" + +local env = { + json = { null = json.null }, + null = json.null +} + +local t = util.run_script("data = " .. util.file_load(arg[1]), env) +print(json.encode(t.data)) + +-- vi:ai et sw=4 ts=4: diff --git a/luaclib/cjson/lua_cjson.c b/luaclib/cjson/lua_cjson.c new file mode 100644 index 0000000..97f2350 --- /dev/null +++ b/luaclib/cjson/lua_cjson.c @@ -0,0 +1,1445 @@ +/* Lua CJSON - JSON support for Lua + * + * Copyright (c) 2010-2012 Mark Pulford + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* Caveats: + * - JSON "null" values are represented as lightuserdata since Lua + * tables cannot contain "nil". Compare with cjson.null. + * - Invalid UTF-8 characters are not detected and will be passed + * untouched. If required, UTF-8 error checking should be done + * outside this library. + * - Javascript comments are not part of the JSON spec, and are not + * currently supported. + * + * Note: Decoding is slower than encoding. Lua spends significant + * time (30%) managing tables when parsing JSON since it is + * difficult to know object/array sizes ahead of time. + */ + +#include +#include +#include +#include +#include +#include + +#include "strbuf.h" +#include "fpconv.h" + +#ifndef CJSON_MODNAME +#define CJSON_MODNAME "cjson" +#endif + +#ifndef CJSON_VERSION +#define CJSON_VERSION "2.1devel" +#endif + +/* Workaround for Solaris platforms missing isinf() */ +#if !defined(isinf) && (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF)) +#define isinf(x) (!isnan(x) && isnan((x) - (x))) +#endif + +#define DEFAULT_SPARSE_CONVERT 0 +#define DEFAULT_SPARSE_RATIO 2 +#define DEFAULT_SPARSE_SAFE 10 +#define DEFAULT_ENCODE_MAX_DEPTH 1000 +#define DEFAULT_DECODE_MAX_DEPTH 1000 +#define DEFAULT_ENCODE_INVALID_NUMBERS 0 +#define DEFAULT_DECODE_INVALID_NUMBERS 1 +#define DEFAULT_ENCODE_KEEP_BUFFER 1 +#define DEFAULT_ENCODE_NUMBER_PRECISION 14 +#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 1 + +#ifdef DISABLE_INVALID_NUMBERS +#undef DEFAULT_DECODE_INVALID_NUMBERS +#define DEFAULT_DECODE_INVALID_NUMBERS 0 +#endif + +typedef enum { + T_OBJ_BEGIN, + T_OBJ_END, + T_ARR_BEGIN, + T_ARR_END, + T_STRING, + T_NUMBER, + T_BOOLEAN, + T_NULL, + T_COLON, + T_COMMA, + T_END, + T_WHITESPACE, + T_ERROR, + T_UNKNOWN +} json_token_type_t; + +static const char *json_token_type_name[] = { + "T_OBJ_BEGIN", + "T_OBJ_END", + "T_ARR_BEGIN", + "T_ARR_END", + "T_STRING", + "T_NUMBER", + "T_BOOLEAN", + "T_NULL", + "T_COLON", + "T_COMMA", + "T_END", + "T_WHITESPACE", + "T_ERROR", + "T_UNKNOWN", + NULL +}; + +typedef struct { + json_token_type_t ch2token[256]; + char escape2char[256]; /* Decoding */ + + /* encode_buf is only allocated and used when + * encode_keep_buffer is set */ + strbuf_t encode_buf; + + int encode_sparse_convert; + int encode_sparse_ratio; + int encode_sparse_safe; + int encode_max_depth; + int encode_invalid_numbers; /* 2 => Encode as "null" */ + int encode_number_precision; + int encode_keep_buffer; + int encode_empty_table_as_object; + + int decode_invalid_numbers; + int decode_max_depth; +} json_config_t; + +typedef struct { + const char *data; + const char *ptr; + strbuf_t *tmp; /* Temporary storage for strings */ + json_config_t *cfg; + int current_depth; +} json_parse_t; + +typedef struct { + json_token_type_t type; + int index; + union { + const char *string; + double number; + int boolean; + } value; + int string_len; +} json_token_t; + +static const char *char2escape[256] = { + "\\u0000", "\\u0001", "\\u0002", "\\u0003", + "\\u0004", "\\u0005", "\\u0006", "\\u0007", + "\\b", "\\t", "\\n", "\\u000b", + "\\f", "\\r", "\\u000e", "\\u000f", + "\\u0010", "\\u0011", "\\u0012", "\\u0013", + "\\u0014", "\\u0015", "\\u0016", "\\u0017", + "\\u0018", "\\u0019", "\\u001a", "\\u001b", + "\\u001c", "\\u001d", "\\u001e", "\\u001f", + NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "\\\\", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\u007f", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +/* ===== CONFIGURATION ===== */ + +static json_config_t *json_fetch_config(lua_State *l) +{ + json_config_t *cfg; + + cfg = lua_touserdata(l, lua_upvalueindex(1)); + if (!cfg) + luaL_error(l, "BUG: Unable to fetch CJSON configuration"); + + return cfg; +} + +/* Ensure the correct number of arguments have been provided. + * Pad with nil to allow other functions to simply check arg[i] + * to find whether an argument was provided */ +static json_config_t *json_arg_init(lua_State *l, int args) +{ + luaL_argcheck(l, lua_gettop(l) <= args, args + 1, + "found too many arguments"); + + while (lua_gettop(l) < args) + lua_pushnil(l); + + return json_fetch_config(l); +} + +/* Process integer options for configuration functions */ +static int json_integer_option(lua_State *l, int optindex, int *setting, + int min, int max) +{ + char errmsg[64]; + int value; + + if (!lua_isnil(l, optindex)) { + value = luaL_checkinteger(l, optindex); + snprintf(errmsg, sizeof(errmsg), "expected integer between %d and %d", min, max); + luaL_argcheck(l, min <= value && value <= max, 1, errmsg); + *setting = value; + } + + lua_pushinteger(l, *setting); + + return 1; +} + +/* Process enumerated arguments for a configuration function */ +static int json_enum_option(lua_State *l, int optindex, int *setting, + const char **options, int bool_true) +{ + static const char *bool_options[] = { "off", "on", NULL }; + + if (!options) { + options = bool_options; + bool_true = 1; + } + + if (!lua_isnil(l, optindex)) { + if (bool_true && lua_isboolean(l, optindex)) + *setting = lua_toboolean(l, optindex) * bool_true; + else + *setting = luaL_checkoption(l, optindex, NULL, options); + } + + if (bool_true && (*setting == 0 || *setting == bool_true)) + lua_pushboolean(l, *setting); + else + lua_pushstring(l, options[*setting]); + + return 1; +} + +/* Configures handling of extremely sparse arrays: + * convert: Convert extremely sparse arrays into objects? Otherwise error. + * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio + * safe: Always use an array when the max index <= safe */ +static int json_cfg_encode_sparse_array(lua_State *l) +{ + json_config_t *cfg = json_arg_init(l, 3); + + json_enum_option(l, 1, &cfg->encode_sparse_convert, NULL, 1); + json_integer_option(l, 2, &cfg->encode_sparse_ratio, 0, INT_MAX); + json_integer_option(l, 3, &cfg->encode_sparse_safe, 0, INT_MAX); + + return 3; +} + +/* Configures the maximum number of nested arrays/objects allowed when + * encoding */ +static int json_cfg_encode_max_depth(lua_State *l) +{ + json_config_t *cfg = json_arg_init(l, 1); + + return json_integer_option(l, 1, &cfg->encode_max_depth, 1, INT_MAX); +} + +/* Configures the maximum number of nested arrays/objects allowed when + * encoding */ +static int json_cfg_decode_max_depth(lua_State *l) +{ + json_config_t *cfg = json_arg_init(l, 1); + + return json_integer_option(l, 1, &cfg->decode_max_depth, 1, INT_MAX); +} + +/* Configures number precision when converting doubles to text */ +static int json_cfg_encode_number_precision(lua_State *l) +{ + json_config_t *cfg = json_arg_init(l, 1); + + return json_integer_option(l, 1, &cfg->encode_number_precision, 1, 14); +} + +/* Configures how to treat empty table when encode lua table */ +static int json_cfg_encode_empty_table_as_object(lua_State *l) +{ + json_config_t *cfg = json_arg_init(l, 1); + + return json_enum_option(l, 1, &cfg->encode_empty_table_as_object, NULL, 1); +} + +/* Configures JSON encoding buffer persistence */ +static int json_cfg_encode_keep_buffer(lua_State *l) +{ + json_config_t *cfg = json_arg_init(l, 1); + int old_value; + + old_value = cfg->encode_keep_buffer; + + json_enum_option(l, 1, &cfg->encode_keep_buffer, NULL, 1); + + /* Init / free the buffer if the setting has changed */ + if (old_value ^ cfg->encode_keep_buffer) { + if (cfg->encode_keep_buffer) + strbuf_init(&cfg->encode_buf, 0); + else + strbuf_free(&cfg->encode_buf); + } + + return 1; +} + +#if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV) +void json_verify_invalid_number_setting(lua_State *l, int *setting) +{ + if (*setting == 1) { + *setting = 0; + luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported."); + } +} +#else +#define json_verify_invalid_number_setting(l, s) do { } while(0) +#endif + +static int json_cfg_encode_invalid_numbers(lua_State *l) +{ + static const char *options[] = { "off", "on", "null", NULL }; + json_config_t *cfg = json_arg_init(l, 1); + + json_enum_option(l, 1, &cfg->encode_invalid_numbers, options, 1); + + json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers); + + return 1; +} + +static int json_cfg_decode_invalid_numbers(lua_State *l) +{ + json_config_t *cfg = json_arg_init(l, 1); + + json_enum_option(l, 1, &cfg->decode_invalid_numbers, NULL, 1); + + json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers); + + return 1; +} + +static int json_destroy_config(lua_State *l) +{ + json_config_t *cfg; + + cfg = lua_touserdata(l, 1); + if (cfg) + strbuf_free(&cfg->encode_buf); + cfg = NULL; + + return 0; +} + +static void json_create_config(lua_State *l) +{ + json_config_t *cfg; + int i; + + cfg = lua_newuserdata(l, sizeof(*cfg)); + + /* Create GC method to clean up strbuf */ + lua_newtable(l); + lua_pushcfunction(l, json_destroy_config); + lua_setfield(l, -2, "__gc"); + lua_setmetatable(l, -2); + + cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; + cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; + cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; + cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH; + cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH; + cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS; + cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS; + cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER; + cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION; + cfg->encode_empty_table_as_object = DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT; + +#if DEFAULT_ENCODE_KEEP_BUFFER > 0 + strbuf_init(&cfg->encode_buf, 0); +#endif + + /* Decoding init */ + + /* Tag all characters as an error */ + for (i = 0; i < 256; i++) + cfg->ch2token[i] = T_ERROR; + + /* Set tokens that require no further processing */ + cfg->ch2token['{'] = T_OBJ_BEGIN; + cfg->ch2token['}'] = T_OBJ_END; + cfg->ch2token['['] = T_ARR_BEGIN; + cfg->ch2token[']'] = T_ARR_END; + cfg->ch2token[','] = T_COMMA; + cfg->ch2token[':'] = T_COLON; + cfg->ch2token['\0'] = T_END; + cfg->ch2token[' '] = T_WHITESPACE; + cfg->ch2token['\t'] = T_WHITESPACE; + cfg->ch2token['\n'] = T_WHITESPACE; + cfg->ch2token['\r'] = T_WHITESPACE; + + /* Update characters that require further processing */ + cfg->ch2token['f'] = T_UNKNOWN; /* false? */ + cfg->ch2token['i'] = T_UNKNOWN; /* inf, ininity? */ + cfg->ch2token['I'] = T_UNKNOWN; + cfg->ch2token['n'] = T_UNKNOWN; /* null, nan? */ + cfg->ch2token['N'] = T_UNKNOWN; + cfg->ch2token['t'] = T_UNKNOWN; /* true? */ + cfg->ch2token['"'] = T_UNKNOWN; /* string? */ + cfg->ch2token['+'] = T_UNKNOWN; /* number? */ + cfg->ch2token['-'] = T_UNKNOWN; + for (i = 0; i < 10; i++) + cfg->ch2token['0' + i] = T_UNKNOWN; + + /* Lookup table for parsing escape characters */ + for (i = 0; i < 256; i++) + cfg->escape2char[i] = 0; /* String error */ + cfg->escape2char['"'] = '"'; + cfg->escape2char['\\'] = '\\'; + cfg->escape2char['/'] = '/'; + cfg->escape2char['b'] = '\b'; + cfg->escape2char['t'] = '\t'; + cfg->escape2char['n'] = '\n'; + cfg->escape2char['f'] = '\f'; + cfg->escape2char['r'] = '\r'; + cfg->escape2char['u'] = 'u'; /* Unicode parsing required */ +} + +/* ===== ENCODING ===== */ + +static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex, + const char *reason) +{ + if (!cfg->encode_keep_buffer) + strbuf_free(json); + luaL_error(l, "Cannot serialise %s: %s", + lua_typename(l, lua_type(l, lindex)), reason); +} + +/* json_append_string args: + * - lua_State + * - JSON strbuf + * - String (Lua stack index) + * + * Returns nothing. Doesn't remove string from Lua stack */ +static void json_append_string(lua_State *l, strbuf_t *json, int lindex) +{ + const char *escstr; + int i; + const char *str; + size_t len; + + str = lua_tolstring(l, lindex, &len); + + /* Worst case is len * 6 (all unicode escapes). + * This buffer is reused constantly for small strings + * If there are any excess pages, they won't be hit anyway. + * This gains ~5% speedup. */ + strbuf_ensure_empty_length(json, len * 6 + 2); + + strbuf_append_char_unsafe(json, '\"'); + for (i = 0; i < len; i++) { + escstr = char2escape[(unsigned char)str[i]]; + if (escstr) + strbuf_append_string(json, escstr); + else + strbuf_append_char_unsafe(json, str[i]); + } + strbuf_append_char_unsafe(json, '\"'); +} + +/* Find the size of the array on the top of the Lua stack + * -1 object (not a pure array) + * >=0 elements in array + */ +static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json) +{ + double k; + int max; + int items; + + max = 0; + items = 0; + + lua_pushnil(l); + /* table, startkey */ + while (lua_next(l, -2) != 0) { + /* table, key, value */ + if (lua_type(l, -2) == LUA_TNUMBER && + (k = lua_tonumber(l, -2))) { + /* Integer >= 1 ? */ + if (floor(k) == k && k >= 1) { + if (k > max) + max = k; + items++; + lua_pop(l, 1); + continue; + } + } + + /* Must not be an array (non integer key) */ + lua_pop(l, 2); + return -1; + } + + /* Encode excessively sparse arrays as objects (if enabled) */ + if (cfg->encode_sparse_ratio > 0 && + max > items * cfg->encode_sparse_ratio && + max > cfg->encode_sparse_safe) { + if (!cfg->encode_sparse_convert) + json_encode_exception(l, cfg, json, -1, "excessively sparse array"); + + return -1; + } + + return max; +} + +static void json_check_encode_depth(lua_State *l, json_config_t *cfg, + int current_depth, strbuf_t *json) +{ + /* Ensure there are enough slots free to traverse a table (key, + * value) and push a string for a potential error message. + * + * Unlike "decode", the key and value are still on the stack when + * lua_checkstack() is called. Hence an extra slot for luaL_error() + * below is required just in case the next check to lua_checkstack() + * fails. + * + * While this won't cause a crash due to the EXTRA_STACK reserve + * slots, it would still be an improper use of the API. */ + if (current_depth <= cfg->encode_max_depth && lua_checkstack(l, 3)) + return; + + if (!cfg->encode_keep_buffer) + strbuf_free(json); + + luaL_error(l, "Cannot serialise, excessive nesting (%d)", + current_depth); +} + +static void json_append_data(lua_State *l, json_config_t *cfg, + int current_depth, strbuf_t *json); + +/* json_append_array args: + * - lua_State + * - JSON strbuf + * - Size of passwd Lua array (top of stack) */ +static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth, + strbuf_t *json, int array_length) +{ + int comma, i; + + strbuf_append_char(json, '['); + + comma = 0; + for (i = 1; i <= array_length; i++) { + if (comma) + strbuf_append_char(json, ','); + else + comma = 1; + + lua_rawgeti(l, -1, i); + json_append_data(l, cfg, current_depth, json); + lua_pop(l, 1); + } + + strbuf_append_char(json, ']'); +} + +static void json_append_number(lua_State *l, json_config_t *cfg, + strbuf_t *json, int lindex) +{ + double num = lua_tonumber(l, lindex); + int len; + + if (cfg->encode_invalid_numbers == 0) { + /* Prevent encoding invalid numbers */ + if (isinf(num) || isnan(num)) + json_encode_exception(l, cfg, json, lindex, + "must not be NaN or Infinity"); + } else if (cfg->encode_invalid_numbers == 1) { + /* Encode NaN/Infinity separately to ensure Javascript compatible + * values are used. */ + if (isnan(num)) { + strbuf_append_mem(json, "NaN", 3); + return; + } + if (isinf(num)) { + if (num < 0) + strbuf_append_mem(json, "-Infinity", 9); + else + strbuf_append_mem(json, "Infinity", 8); + return; + } + } else { + /* Encode invalid numbers as "null" */ + if (isinf(num) || isnan(num)) { + strbuf_append_mem(json, "null", 4); + return; + } + } + + strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE); + len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision); + strbuf_extend_length(json, len); +} + +static void json_append_object(lua_State *l, json_config_t *cfg, + int current_depth, strbuf_t *json) +{ + int comma, keytype; + + /* Object */ + strbuf_append_char(json, '{'); + + lua_pushnil(l); + /* table, startkey */ + comma = 0; + while (lua_next(l, -2) != 0) { + if (comma) + strbuf_append_char(json, ','); + else + comma = 1; + + /* table, key, value */ + keytype = lua_type(l, -2); + if (keytype == LUA_TNUMBER) { + strbuf_append_char(json, '"'); + json_append_number(l, cfg, json, -2); + strbuf_append_mem(json, "\":", 2); + } else if (keytype == LUA_TSTRING) { + json_append_string(l, json, -2); + strbuf_append_char(json, ':'); + } else { + json_encode_exception(l, cfg, json, -2, + "table key must be a number or string"); + /* never returns */ + } + + /* table, key, value */ + json_append_data(l, cfg, current_depth, json); + lua_pop(l, 1); + /* table, key */ + } + + strbuf_append_char(json, '}'); +} + +/* Serialise Lua data into JSON string. */ +static void json_append_data(lua_State *l, json_config_t *cfg, + int current_depth, strbuf_t *json) +{ + int len; + + switch (lua_type(l, -1)) { + case LUA_TSTRING: + json_append_string(l, json, -1); + break; + case LUA_TNUMBER: + json_append_number(l, cfg, json, -1); + break; + case LUA_TBOOLEAN: + if (lua_toboolean(l, -1)) + strbuf_append_mem(json, "true", 4); + else + strbuf_append_mem(json, "false", 5); + break; + case LUA_TTABLE: + current_depth++; + json_check_encode_depth(l, cfg, current_depth, json); + len = lua_array_length(l, cfg, json); + if (len > 0 || (len == 0 && !cfg->encode_empty_table_as_object)) + json_append_array(l, cfg, current_depth, json, len); + else + json_append_object(l, cfg, current_depth, json); + break; + case LUA_TNIL: + strbuf_append_mem(json, "null", 4); + break; + case LUA_TLIGHTUSERDATA: + if (lua_touserdata(l, -1) == NULL) { + strbuf_append_mem(json, "null", 4); + break; + } + default: + /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, + * and LUA_TLIGHTUSERDATA) cannot be serialised */ + json_encode_exception(l, cfg, json, -1, "type not supported"); + /* never returns */ + } +} + +static int json_encode(lua_State *l) +{ + json_config_t *cfg = json_fetch_config(l); + strbuf_t local_encode_buf; + strbuf_t *encode_buf; + char *json; + int len; + + luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); + + if (!cfg->encode_keep_buffer) { + /* Use private buffer */ + encode_buf = &local_encode_buf; + strbuf_init(encode_buf, 0); + } else { + /* Reuse existing buffer */ + encode_buf = &cfg->encode_buf; + strbuf_reset(encode_buf); + } + + json_append_data(l, cfg, 0, encode_buf); + json = strbuf_string(encode_buf, &len); + + lua_pushlstring(l, json, len); + + if (!cfg->encode_keep_buffer) + strbuf_free(encode_buf); + + return 1; +} + +/* ===== DECODING ===== */ + +static void json_process_value(lua_State *l, json_parse_t *json, + json_token_t *token); + +static int hexdigit2int(char hex) +{ + if ('0' <= hex && hex <= '9') + return hex - '0'; + + /* Force lowercase */ + hex |= 0x20; + if ('a' <= hex && hex <= 'f') + return 10 + hex - 'a'; + + return -1; +} + +static int decode_hex4(const char *hex) +{ + int digit[4]; + int i; + + /* Convert ASCII hex digit to numeric digit + * Note: this returns an error for invalid hex digits, including + * NULL */ + for (i = 0; i < 4; i++) { + digit[i] = hexdigit2int(hex[i]); + if (digit[i] < 0) { + return -1; + } + } + + return (digit[0] << 12) + + (digit[1] << 8) + + (digit[2] << 4) + + digit[3]; +} + +/* Converts a Unicode codepoint to UTF-8. + * Returns UTF-8 string length, and up to 4 bytes in *utf8 */ +static int codepoint_to_utf8(char *utf8, int codepoint) +{ + /* 0xxxxxxx */ + if (codepoint <= 0x7F) { + utf8[0] = codepoint; + return 1; + } + + /* 110xxxxx 10xxxxxx */ + if (codepoint <= 0x7FF) { + utf8[0] = (codepoint >> 6) | 0xC0; + utf8[1] = (codepoint & 0x3F) | 0x80; + return 2; + } + + /* 1110xxxx 10xxxxxx 10xxxxxx */ + if (codepoint <= 0xFFFF) { + utf8[0] = (codepoint >> 12) | 0xE0; + utf8[1] = ((codepoint >> 6) & 0x3F) | 0x80; + utf8[2] = (codepoint & 0x3F) | 0x80; + return 3; + } + + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint <= 0x1FFFFF) { + utf8[0] = (codepoint >> 18) | 0xF0; + utf8[1] = ((codepoint >> 12) & 0x3F) | 0x80; + utf8[2] = ((codepoint >> 6) & 0x3F) | 0x80; + utf8[3] = (codepoint & 0x3F) | 0x80; + return 4; + } + + return 0; +} + + +/* Called when index pointing to beginning of UTF-16 code escape: \uXXXX + * \u is guaranteed to exist, but the remaining hex characters may be + * missing. + * Translate to UTF-8 and append to temporary token string. + * Must advance index to the next character to be processed. + * Returns: 0 success + * -1 error + */ +static int json_append_unicode_escape(json_parse_t *json) +{ + char utf8[4]; /* Surrogate pairs require 4 UTF-8 bytes */ + int codepoint; + int surrogate_low; + int len; + int escape_len = 6; + + /* Fetch UTF-16 code unit */ + codepoint = decode_hex4(json->ptr + 2); + if (codepoint < 0) + return -1; + + /* UTF-16 surrogate pairs take the following 2 byte form: + * 11011 x yyyyyyyyyy + * When x = 0: y is the high 10 bits of the codepoint + * x = 1: y is the low 10 bits of the codepoint + * + * Check for a surrogate pair (high or low) */ + if ((codepoint & 0xF800) == 0xD800) { + /* Error if the 1st surrogate is not high */ + if (codepoint & 0x400) + return -1; + + /* Ensure the next code is a unicode escape */ + if (*(json->ptr + escape_len) != '\\' || + *(json->ptr + escape_len + 1) != 'u') { + return -1; + } + + /* Fetch the next codepoint */ + surrogate_low = decode_hex4(json->ptr + 2 + escape_len); + if (surrogate_low < 0) + return -1; + + /* Error if the 2nd code is not a low surrogate */ + if ((surrogate_low & 0xFC00) != 0xDC00) + return -1; + + /* Calculate Unicode codepoint */ + codepoint = (codepoint & 0x3FF) << 10; + surrogate_low &= 0x3FF; + codepoint = (codepoint | surrogate_low) + 0x10000; + escape_len = 12; + } + + /* Convert codepoint to UTF-8 */ + len = codepoint_to_utf8(utf8, codepoint); + if (!len) + return -1; + + /* Append bytes and advance parse index */ + strbuf_append_mem_unsafe(json->tmp, utf8, len); + json->ptr += escape_len; + + return 0; +} + +static void json_set_token_error(json_token_t *token, json_parse_t *json, + const char *errtype) +{ + token->type = T_ERROR; + token->index = json->ptr - json->data; + token->value.string = errtype; +} + +static void json_next_string_token(json_parse_t *json, json_token_t *token) +{ + char *escape2char = json->cfg->escape2char; + char ch; + + /* Caller must ensure a string is next */ + assert(*json->ptr == '"'); + + /* Skip " */ + json->ptr++; + + /* json->tmp is the temporary strbuf used to accumulate the + * decoded string value. + * json->tmp is sized to handle JSON containing only a string value. + */ + strbuf_reset(json->tmp); + + while ((ch = *json->ptr) != '"') { + if (!ch) { + /* Premature end of the string */ + json_set_token_error(token, json, "unexpected end of string"); + return; + } + + /* Handle escapes */ + if (ch == '\\') { + /* Fetch escape character */ + ch = *(json->ptr + 1); + + /* Translate escape code and append to tmp string */ + ch = escape2char[(unsigned char)ch]; + if (ch == 'u') { + if (json_append_unicode_escape(json) == 0) + continue; + + json_set_token_error(token, json, + "invalid unicode escape code"); + return; + } + if (!ch) { + json_set_token_error(token, json, "invalid escape code"); + return; + } + + /* Skip '\' */ + json->ptr++; + } + /* Append normal character or translated single character + * Unicode escapes are handled above */ + strbuf_append_char_unsafe(json->tmp, ch); + json->ptr++; + } + json->ptr++; /* Eat final quote (") */ + + strbuf_ensure_null(json->tmp); + + token->type = T_STRING; + token->value.string = strbuf_string(json->tmp, &token->string_len); +} + +/* JSON numbers should take the following form: + * -?(0|[1-9]|[1-9][0-9]+)(.[0-9]+)?([eE][-+]?[0-9]+)? + * + * json_next_number_token() uses strtod() which allows other forms: + * - numbers starting with '+' + * - NaN, -NaN, infinity, -infinity + * - hexadecimal numbers + * - numbers with leading zeros + * + * json_is_invalid_number() detects "numbers" which may pass strtod()'s + * error checking, but should not be allowed with strict JSON. + * + * json_is_invalid_number() may pass numbers which cause strtod() + * to generate an error. + */ +static int json_is_invalid_number(json_parse_t *json) +{ + const char *p = json->ptr; + + /* Reject numbers starting with + */ + if (*p == '+') + return 1; + + /* Skip minus sign if it exists */ + if (*p == '-') + p++; + + /* Reject numbers starting with 0x, or leading zeros */ + if (*p == '0') { + int ch2 = *(p + 1); + + if ((ch2 | 0x20) == 'x' || /* Hex */ + ('0' <= ch2 && ch2 <= '9')) /* Leading zero */ + return 1; + + return 0; + } else if (*p <= '9') { + return 0; /* Ordinary number */ + } + + /* Reject inf/nan */ + if (!strncasecmp(p, "inf", 3)) + return 1; + if (!strncasecmp(p, "nan", 3)) + return 1; + + /* Pass all other numbers which may still be invalid, but + * strtod() will catch them. */ + return 0; +} + +static void json_next_number_token(json_parse_t *json, json_token_t *token) +{ + char *endptr; + + token->type = T_NUMBER; + token->value.number = fpconv_strtod(json->ptr, &endptr); + if (json->ptr == endptr) + json_set_token_error(token, json, "invalid number"); + else + json->ptr = endptr; /* Skip the processed number */ + + return; +} + +/* Fills in the token struct. + * T_STRING will return a pointer to the json_parse_t temporary string + * T_ERROR will leave the json->ptr pointer at the error. + */ +static void json_next_token(json_parse_t *json, json_token_t *token) +{ + const json_token_type_t *ch2token = json->cfg->ch2token; + int ch; + + /* Eat whitespace. */ + while (1) { + ch = (unsigned char)*(json->ptr); + token->type = ch2token[ch]; + if (token->type != T_WHITESPACE) + break; + json->ptr++; + } + + /* Store location of new token. Required when throwing errors + * for unexpected tokens (syntax errors). */ + token->index = json->ptr - json->data; + + /* Don't advance the pointer for an error or the end */ + if (token->type == T_ERROR) { + json_set_token_error(token, json, "invalid token"); + return; + } + + if (token->type == T_END) { + return; + } + + /* Found a known single character token, advance index and return */ + if (token->type != T_UNKNOWN) { + json->ptr++; + return; + } + + /* Process characters which triggered T_UNKNOWN + * + * Must use strncmp() to match the front of the JSON string. + * JSON identifier must be lowercase. + * When strict_numbers if disabled, either case is allowed for + * Infinity/NaN (since we are no longer following the spec..) */ + if (ch == '"') { + json_next_string_token(json, token); + return; + } else if (ch == '-' || ('0' <= ch && ch <= '9')) { + if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) { + json_set_token_error(token, json, "invalid number"); + return; + } + json_next_number_token(json, token); + return; + } else if (!strncmp(json->ptr, "true", 4)) { + token->type = T_BOOLEAN; + token->value.boolean = 1; + json->ptr += 4; + return; + } else if (!strncmp(json->ptr, "false", 5)) { + token->type = T_BOOLEAN; + token->value.boolean = 0; + json->ptr += 5; + return; + } else if (!strncmp(json->ptr, "null", 4)) { + token->type = T_NULL; + json->ptr += 4; + return; + } else if (json->cfg->decode_invalid_numbers && + json_is_invalid_number(json)) { + /* When decode_invalid_numbers is enabled, only attempt to process + * numbers we know are invalid JSON (Inf, NaN, hex) + * This is required to generate an appropriate token error, + * otherwise all bad tokens will register as "invalid number" + */ + json_next_number_token(json, token); + return; + } + + /* Token starts with t/f/n but isn't recognised above. */ + json_set_token_error(token, json, "invalid token"); +} + +/* This function does not return. + * DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED. + * The only supported exception is the temporary parser string + * json->tmp struct. + * json and token should exist on the stack somewhere. + * luaL_error() will long_jmp and release the stack */ +static void json_throw_parse_error(lua_State *l, json_parse_t *json, + const char *exp, json_token_t *token) +{ + const char *found; + + strbuf_free(json->tmp); + + if (token->type == T_ERROR) + found = token->value.string; + else + found = json_token_type_name[token->type]; + + /* Note: token->index is 0 based, display starting from 1 */ + luaL_error(l, "Expected %s but found %s at character %d", + exp, found, token->index + 1); +} + +static inline void json_decode_ascend(json_parse_t *json) +{ + json->current_depth--; +} + +static void json_decode_descend(lua_State *l, json_parse_t *json, int slots) +{ + json->current_depth++; + + if (json->current_depth <= json->cfg->decode_max_depth && + lua_checkstack(l, slots)) { + return; + } + + strbuf_free(json->tmp); + luaL_error(l, "Found too many nested data structures (%d) at character %d", + json->current_depth, json->ptr - json->data); +} + +static void json_parse_object_context(lua_State *l, json_parse_t *json) +{ + json_token_t token; + + /* 3 slots required: + * .., table, key, value */ + json_decode_descend(l, json, 3); + + lua_newtable(l); + + json_next_token(json, &token); + + /* Handle empty objects */ + if (token.type == T_OBJ_END) { + json_decode_ascend(json); + return; + } + + while (1) { + if (token.type != T_STRING) + json_throw_parse_error(l, json, "object key string", &token); + + /* Push key */ + lua_pushlstring(l, token.value.string, token.string_len); + + json_next_token(json, &token); + if (token.type != T_COLON) + json_throw_parse_error(l, json, "colon", &token); + + /* Fetch value */ + json_next_token(json, &token); + json_process_value(l, json, &token); + + /* Set key = value */ + lua_rawset(l, -3); + + json_next_token(json, &token); + + if (token.type == T_OBJ_END) { + json_decode_ascend(json); + return; + } + + if (token.type != T_COMMA) + json_throw_parse_error(l, json, "comma or object end", &token); + + json_next_token(json, &token); + } +} + +/* Handle the array context */ +static void json_parse_array_context(lua_State *l, json_parse_t *json) +{ + json_token_t token; + int i; + + /* 2 slots required: + * .., table, value */ + json_decode_descend(l, json, 2); + + lua_newtable(l); + + json_next_token(json, &token); + + /* Handle empty arrays */ + if (token.type == T_ARR_END) { + json_decode_ascend(json); + return; + } + + for (i = 1; ; i++) { + json_process_value(l, json, &token); + lua_rawseti(l, -2, i); /* arr[i] = value */ + + json_next_token(json, &token); + + if (token.type == T_ARR_END) { + json_decode_ascend(json); + return; + } + + if (token.type != T_COMMA) + json_throw_parse_error(l, json, "comma or array end", &token); + + json_next_token(json, &token); + } +} + +/* Handle the "value" context */ +static void json_process_value(lua_State *l, json_parse_t *json, + json_token_t *token) +{ + switch (token->type) { + case T_STRING: + lua_pushlstring(l, token->value.string, token->string_len); + break;; + case T_NUMBER: + lua_pushnumber(l, token->value.number); + break;; + case T_BOOLEAN: + lua_pushboolean(l, token->value.boolean); + break;; + case T_OBJ_BEGIN: + json_parse_object_context(l, json); + break;; + case T_ARR_BEGIN: + json_parse_array_context(l, json); + break;; + case T_NULL: + /* In Lua, setting "t[k] = nil" will delete k from the table. + * Hence a NULL pointer lightuserdata object is used instead */ + lua_pushlightuserdata(l, NULL); + break;; + default: + json_throw_parse_error(l, json, "value", token); + } +} + +static int json_decode(lua_State *l) +{ + json_parse_t json; + json_token_t token; + size_t json_len; + + luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); + + json.cfg = json_fetch_config(l); + json.data = luaL_checklstring(l, 1, &json_len); + json.current_depth = 0; + json.ptr = json.data; + + /* Detect Unicode other than UTF-8 (see RFC 4627, Sec 3) + * + * CJSON can support any simple data type, hence only the first + * character is guaranteed to be ASCII (at worst: '"'). This is + * still enough to detect whether the wrong encoding is in use. */ + if (json_len >= 2 && (!json.data[0] || !json.data[1])) + luaL_error(l, "JSON parser does not support UTF-16 or UTF-32"); + + /* Ensure the temporary buffer can hold the entire string. + * This means we no longer need to do length checks since the decoded + * string must be smaller than the entire json string */ + json.tmp = strbuf_new(json_len); + + json_next_token(&json, &token); + json_process_value(l, &json, &token); + + /* Ensure there is no more input left */ + json_next_token(&json, &token); + + if (token.type != T_END) + json_throw_parse_error(l, &json, "the end", &token); + + strbuf_free(json.tmp); + + return 1; +} + +/* ===== INITIALISATION ===== */ + +#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502 +/* Compatibility for Lua 5.1. + * + * luaL_setfuncs() is used to create a module table where the functions have + * json_config_t as their first upvalue. Code borrowed from Lua 5.2 source. */ +static void luaL_setfuncs (lua_State *l, const luaL_Reg *reg, int nup) +{ + int i; + + luaL_checkstack(l, nup, "too many upvalues"); + for (; reg->name != NULL; reg++) { /* fill the table with given functions */ + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(l, -nup); + lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */ + lua_setfield(l, -(nup + 2), reg->name); + } + lua_pop(l, nup); /* remove upvalues */ +} +#endif + +/* Call target function in protected mode with all supplied args. + * Assumes target function only returns a single non-nil value. + * Convert and return thrown errors as: nil, "error message" */ +static int json_protect_conversion(lua_State *l) +{ + int err; + + /* Deliberately throw an error for invalid arguments */ + luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); + + /* pcall() the function stored as upvalue(1) */ + lua_pushvalue(l, lua_upvalueindex(1)); + lua_insert(l, 1); + err = lua_pcall(l, 1, 1, 0); + if (!err) + return 1; + + if (err == LUA_ERRRUN) { + lua_pushnil(l); + lua_insert(l, -2); + return 2; + } + + /* Since we are not using a custom error handler, the only remaining + * errors are memory related */ + return luaL_error(l, "Memory allocation error in CJSON protected call"); +} + +/* Return cjson module table */ +static int lua_cjson_new(lua_State *l) +{ + luaL_Reg reg[] = { + { "encode", json_encode }, + { "decode", json_decode }, + { "encode_empty_table_as_object", json_cfg_encode_empty_table_as_object }, + { "encode_sparse_array", json_cfg_encode_sparse_array }, + { "encode_max_depth", json_cfg_encode_max_depth }, + { "decode_max_depth", json_cfg_decode_max_depth }, + { "encode_number_precision", json_cfg_encode_number_precision }, + { "encode_keep_buffer", json_cfg_encode_keep_buffer }, + { "encode_invalid_numbers", json_cfg_encode_invalid_numbers }, + { "decode_invalid_numbers", json_cfg_decode_invalid_numbers }, + { "new", lua_cjson_new }, + { NULL, NULL } + }; + + /* Initialise number conversions */ + fpconv_init(); + + /* cjson module table */ + lua_newtable(l); + + /* Register functions with config data as upvalue */ + json_create_config(l); + luaL_setfuncs(l, reg, 1); + + /* Set cjson.null */ + lua_pushlightuserdata(l, NULL); + lua_setfield(l, -2, "null"); + + /* Set module name / version fields */ + lua_pushliteral(l, CJSON_MODNAME); + lua_setfield(l, -2, "_NAME"); + lua_pushliteral(l, CJSON_VERSION); + lua_setfield(l, -2, "_VERSION"); + + return 1; +} + +/* Return cjson.safe module table */ +static int lua_cjson_safe_new(lua_State *l) +{ + const char *func[] = { "decode", "encode", NULL }; + int i; + + lua_cjson_new(l); + + /* Fix new() method */ + lua_pushcfunction(l, lua_cjson_safe_new); + lua_setfield(l, -2, "new"); + + for (i = 0; func[i]; i++) { + lua_getfield(l, -1, func[i]); + lua_pushcclosure(l, json_protect_conversion, 1); + lua_setfield(l, -2, func[i]); + } + + return 1; +} + +int luaopen_cjson(lua_State *l) +{ + lua_cjson_new(l); + +#ifdef ENABLE_CJSON_GLOBAL + /* Register a global "cjson" table. */ + lua_pushvalue(l, -1); + lua_setglobal(l, CJSON_MODNAME); +#endif + + /* Return cjson table */ + return 1; +} + +int luaopen_cjson_safe(lua_State *l) +{ + lua_cjson_safe_new(l); + + /* Return cjson.safe table */ + return 1; +} + +/* vi:ai et sw=4 ts=4: + */ diff --git a/luaclib/cjson/manual.txt b/luaclib/cjson/manual.txt new file mode 100644 index 0000000..a12e378 --- /dev/null +++ b/luaclib/cjson/manual.txt @@ -0,0 +1,612 @@ += Lua CJSON 2.1devel Manual = +Mark Pulford +:revdate: 1st March 2012 + +Overview +-------- + +The Lua CJSON module provides JSON support for Lua. + +*Features*:: +- Fast, standards compliant encoding/parsing routines +- Full support for JSON with UTF-8, including decoding surrogate pairs +- Optional run-time support for common exceptions to the JSON + specification (infinity, NaN,..) +- No dependencies on other libraries + +*Caveats*:: +- UTF-16 and UTF-32 are not supported + +Lua CJSON is covered by the MIT license. Review the file +LICENSE+ for +details. + +The latest version of this software is available from the +http://www.kyne.com.au/%7Emark/software/lua-cjson.php[Lua CJSON website]. + +Feel free to email me if you have any patches, suggestions, or comments. + + +Installation +------------ + +Lua CJSON requires either http://www.lua.org[Lua] 5.1, Lua 5.2, or +http://www.luajit.org[LuaJIT] to build. + +The build method can be selected from 4 options: + +Make:: Unix (including Linux, BSD, Mac OSX & Solaris), Windows +CMake:: Unix, Windows +RPM:: Linux +LuaRocks:: Unix, Windows + + +Make +~~~~ + +The included +Makefile+ has generic settings. + +First, review and update the included makefile to suit your platform (if +required). + +Next, build and install the module: + +[source,sh] +make install + +Or install manually into your Lua module directory: + +[source,sh] +make +cp cjson.so $LUA_MODULE_DIRECTORY + + +CMake +~~~~~ + +http://www.cmake.org[CMake] can generate build configuration for many +different platforms (including Unix and Windows). + +First, generate the makefile for your platform using CMake. If CMake is +unable to find Lua, manually set the +LUA_DIR+ environment variable to +the base prefix of your Lua 5.1 installation. + +While +cmake+ is used in the example below, +ccmake+ or +cmake-gui+ may +be used to present an interface for changing the default build options. + +[source,sh] +mkdir build +cd build +# Optional: export LUA_DIR=$LUA51_PREFIX +cmake .. + +Next, build and install the module: + +[source,sh] +make install +# Or: +make +cp cjson.so $LUA_MODULE_DIRECTORY + +Review the +http://www.cmake.org/cmake/help/documentation.html[CMake documentation] +for further details. + + +RPM +~~~ + +Linux distributions using http://rpm.org[RPM] can create a package via +the included RPM spec file. Ensure the +rpm-build+ package (or similar) +has been installed. + +Build and install the module via RPM: + +[source,sh] +rpmbuild -tb lua-cjson-2.1devel.tar.gz +rpm -Uvh $LUA_CJSON_RPM + + +LuaRocks +~~~~~~~~ + +http://luarocks.org[LuaRocks] can be used to install and manage Lua +modules on a wide range of platforms (including Windows). + +First, extract the Lua CJSON source package. + +Next, install the module: + +[source,sh] +cd lua-cjson-2.1devel +luarocks make + +[NOTE] +LuaRocks does not support platform specific configuration for Solaris. +On Solaris, you may need to manually uncomment +USE_INTERNAL_ISINF+ in +the rockspec before building this module. + +Review the http://luarocks.org/en/Documentation[LuaRocks documentation] +for further details. + + +[[build_options]] +Build Options (#define) +~~~~~~~~~~~~~~~~~~~~~~~ + +Lua CJSON offers several +#define+ build options to address portability +issues, and enable non-default features. Some build methods may +automatically set platform specific options if required. Other features +should be enabled manually. + +USE_INTERNAL_ISINF:: Workaround for Solaris platforms missing +isinf+. +DISABLE_INVALID_NUMBERS:: Recommended on platforms where +strtod+ / + +sprintf+ are not POSIX compliant (eg, Windows MinGW). Prevents + +cjson.encode_invalid_numbers+ and +cjson.decode_invalid_numbers+ from + being enabled. However, +cjson.encode_invalid_numbers+ may still be + set to +"null"+. When using the Lua CJSON built-in floating point + conversion this option is unnecessary and is ignored. + + +Built-in floating point conversion +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Lua CJSON may be built with David Gay's +http://www.netlib.org/fp/[floating point conversion routines]. This can +increase overall performance by up to 50% on some platforms when +converting a large amount of numeric data. However, this option reduces +portability and is disabled by default. + +USE_INTERNAL_FPCONV:: Enable internal number conversion routines. +IEEE_BIG_ENDIAN:: Must be set on big endian architectures. +MULTIPLE_THREADS:: Must be set if Lua CJSON may be used in a + multi-threaded application. Requires the _pthreads_ library. + + +API (Functions) +--------------- + +Synopsis +~~~~~~~~ + +[source,lua] +------------ +-- Module instantiation +local cjson = require "cjson" +local cjson2 = cjson.new() +local cjson_safe = require "cjson.safe" + +-- Translate Lua value to/from JSON +text = cjson.encode(value) +value = cjson.decode(text) + +-- Get and/or set Lua CJSON configuration +setting = cjson.decode_invalid_numbers([setting]) +setting = cjson.encode_invalid_numbers([setting]) +keep = cjson.encode_keep_buffer([keep]) +depth = cjson.encode_max_depth([depth]) +depth = cjson.decode_max_depth([depth]) +convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]]) +------------ + + +Module Instantiation +~~~~~~~~~~~~~~~~~~~~ + +[source,lua] +------------ +local cjson = require "cjson" +local cjson2 = cjson.new() +local cjson_safe = require "cjson.safe" +------------ + +Import Lua CJSON via the Lua +require+ function. Lua CJSON does not +register a global module table. + +The +cjson+ module will throw an error during JSON conversion if any +invalid data is encountered. Refer to <> +and <> for details. + +The +cjson.safe+ module behaves identically to the +cjson+ module, +except when errors are encountered during JSON conversion. On error, the ++cjson_safe.encode+ and +cjson_safe.decode+ functions will return ++nil+ followed by the error message. + ++cjson.new+ can be used to instantiate an independent copy of the Lua +CJSON module. The new module has a separate persistent encoding buffer, +and default settings. + +Lua CJSON can support Lua implementations using multiple preemptive +threads within a single Lua state provided the persistent encoding +buffer is not shared. This can be achieved by one of the following +methods: + +- Disabling the persistent encoding buffer with + <> +- Ensuring each thread calls <> separately (ie, + treat +cjson.encode+ as non-reentrant). +- Using a separate +cjson+ module table per preemptive thread + (+cjson.new+) + +[NOTE] +Lua CJSON uses +strtod+ and +snprintf+ to perform numeric conversion as +they are usually well supported, fast and bug free. However, these +functions require a workaround for JSON encoding/parsing under locales +using a comma decimal separator. Lua CJSON detects the current locale +during instantiation to determine and automatically implement the +workaround if required. Lua CJSON should be reinitialised via ++cjson.new+ if the locale of the current process changes. Using a +different locale per thread is not supported. + + +decode +~~~~~~ + +[source,lua] +------------ +value = cjson.decode(json_text) +------------ + ++cjson.decode+ will deserialise any UTF-8 JSON string into a Lua value +or table. + +UTF-16 and UTF-32 JSON strings are not supported. + ++cjson.decode+ requires that any NULL (ASCII 0) and double quote (ASCII +34) characters are escaped within strings. All escape codes will be +decoded and other bytes will be passed transparently. UTF-8 characters +are not validated during decoding and should be checked elsewhere if +required. + +JSON +null+ will be converted to a NULL +lightuserdata+ value. This can +be compared with +cjson.null+ for convenience. + +By default, numbers incompatible with the JSON specification (infinity, +NaN, hexadecimal) can be decoded. This default can be changed with +<>. + +.Example: Decoding +[source,lua] +json_text = '[ true, { "foo": "bar" } ]' +value = cjson.decode(json_text) +-- Returns: { true, { foo = "bar" } } + +[CAUTION] +Care must be taken after decoding JSON objects with numeric keys. Each +numeric key will be stored as a Lua +string+. Any subsequent code +assuming type +number+ may break. + + +[[decode_invalid_numbers]] +decode_invalid_numbers +~~~~~~~~~~~~~~~~~~~~~~ + +[source,lua] +------------ +setting = cjson.decode_invalid_numbers([setting]) +-- "setting" must be a boolean. Default: true. +------------ + +Lua CJSON may generate an error when trying to decode numbers not +supported by the JSON specification. _Invalid numbers_ are defined as: + +- infinity +- NaN +- hexadecimal + +Available settings: + ++true+:: Accept and decode _invalid numbers_. This is the default + setting. ++false+:: Throw an error when _invalid numbers_ are encountered. + +The current setting is always returned, and is only updated when an +argument is provided. + + +[[decode_max_depth]] +decode_max_depth +~~~~~~~~~~~~~~~~ + +[source,lua] +------------ +depth = cjson.decode_max_depth([depth]) +-- "depth" must be a positive integer. Default: 1000. +------------ + +Lua CJSON will generate an error when parsing deeply nested JSON once +the maximum array/object depth has been exceeded. This check prevents +unnecessarily complicated JSON from slowing down the application, or +crashing the application due to lack of process stack space. + +An error may be generated before the depth limit is hit if Lua is unable +to allocate more objects on the Lua stack. + +By default, Lua CJSON will reject JSON with arrays and/or objects nested +more than 1000 levels deep. + +The current setting is always returned, and is only updated when an +argument is provided. + + +[[encode]] +encode +~~~~~~ + +[source,lua] +------------ +json_text = cjson.encode(value) +------------ + ++cjson.encode+ will serialise a Lua value into a string containing the +JSON representation. + ++cjson.encode+ supports the following types: + +- +boolean+ +- +lightuserdata+ (NULL value only) +- +nil+ +- +number+ +- +string+ +- +table+ + +The remaining Lua types will generate an error: + +- +function+ +- +lightuserdata+ (non-NULL values) +- +thread+ +- +userdata+ + +By default, numbers are encoded with 14 significant digits. Refer to +<> for details. + +Lua CJSON will escape the following characters within each UTF-8 string: + +- Control characters (ASCII 0 - 31) +- Double quote (ASCII 34) +- Forward slash (ASCII 47) +- Blackslash (ASCII 92) +- Delete (ASCII 127) + +All other bytes are passed transparently. + +[CAUTION] +========= +Lua CJSON will successfully encode/decode binary strings, but this is +technically not supported by JSON and may not be compatible with other +JSON libraries. To ensure the output is valid JSON, applications should +ensure all Lua strings passed to +cjson.encode+ are UTF-8. + +Base64 is commonly used to encode binary data as the most efficient +encoding under UTF-8 can only reduce the encoded size by a further +~8%. Lua Base64 routines can be found in the +http://w3.impa.br/%7Ediego/software/luasocket/[LuaSocket] and +http://www.tecgraf.puc-rio.br/%7Elhf/ftp/lua/#lbase64[lbase64] packages. +========= + +Lua CJSON uses a heuristic to determine whether to encode a Lua table as +a JSON array or an object. A Lua table with only positive integer keys +of type +number+ will be encoded as a JSON array. All other tables will +be encoded as a JSON object. + +Lua CJSON does not use metamethods when serialising tables. + +- +rawget+ is used to iterate over Lua arrays +- +next+ is used to iterate over Lua objects + +Lua arrays with missing entries (_sparse arrays_) may optionally be +encoded in several different ways. Refer to +<> for details. + +JSON object keys are always strings. Hence +cjson.encode+ only supports +table keys which are type +number+ or +string+. All other types will +generate an error. + +[NOTE] +Standards compliant JSON must be encapsulated in either an object (+{}+) +or an array (+[]+). If strictly standards compliant JSON is desired, a +table must be passed to +cjson.encode+. + +By default, encoding the following Lua values will generate errors: + +- Numbers incompatible with the JSON specification (infinity, NaN) +- Tables nested more than 1000 levels deep +- Excessively sparse Lua arrays + +These defaults can be changed with: + +- <> +- <> +- <> + +.Example: Encoding +[source,lua] +value = { true, { foo = "bar" } } +json_text = cjson.encode(value) +-- Returns: '[true,{"foo":"bar"}]' + + +[[encode_invalid_numbers]] +encode_invalid_numbers +~~~~~~~~~~~~~~~~~~~~~~ +[source,lua] +------------ +setting = cjson.encode_invalid_numbers([setting]) +-- "setting" must a boolean or "null". Default: false. +------------ + +Lua CJSON may generate an error when encoding floating point numbers not +supported by the JSON specification (_invalid numbers_): + +- infinity +- NaN + +Available settings: + ++true+:: Allow _invalid numbers_ to be encoded using the Javascript + compatible values +NaN+ and +Infinity+. This will generate + non-standard JSON, but these values are supported by some libraries. ++"null"+:: Encode _invalid numbers_ as a JSON +null+ value. This allows + infinity and NaN to be encoded into valid JSON. ++false+:: Throw an error when attempting to encode _invalid numbers_. + This is the default setting. + +The current setting is always returned, and is only updated when an +argument is provided. + + +[[encode_keep_buffer]] +encode_keep_buffer +~~~~~~~~~~~~~~~~~~ + +[source,lua] +------------ +keep = cjson.encode_keep_buffer([keep]) +-- "keep" must be a boolean. Default: true. +------------ + +Lua CJSON can reuse the JSON encoding buffer to improve performance. + +Available settings: + ++true+:: The buffer will grow to the largest size required and is not + freed until the Lua CJSON module is garbage collected. This is the + default setting. ++false+:: Free the encode buffer after each call to +cjson.encode+. + +The current setting is always returned, and is only updated when an +argument is provided. + + +[[encode_max_depth]] +encode_max_depth +~~~~~~~~~~~~~~~~ + +[source,lua] +------------ +depth = cjson.encode_max_depth([depth]) +-- "depth" must be a positive integer. Default: 1000. +------------ + +Once the maximum table depth has been exceeded Lua CJSON will generate +an error. This prevents a deeply nested or recursive data structure from +crashing the application. + +By default, Lua CJSON will generate an error when trying to encode data +structures with more than 1000 nested tables. + +The current setting is always returned, and is only updated when an +argument is provided. + +.Example: Recursive Lua table +[source,lua] +a = {}; a[1] = a + + +[[encode_number_precision]] +encode_number_precision +~~~~~~~~~~~~~~~~~~~~~~~ + +[source,lua] +------------ +precision = cjson.encode_number_precision([precision]) +-- "precision" must be an integer between 1 and 14. Default: 14. +------------ + +The amount of significant digits returned by Lua CJSON when encoding +numbers can be changed to balance accuracy versus performance. For data +structures containing many numbers, setting ++cjson.encode_number_precision+ to a smaller integer, for example +3+, +can improve encoding performance by up to 50%. + +By default, Lua CJSON will output 14 significant digits when converting +a number to text. + +The current setting is always returned, and is only updated when an +argument is provided. + + +[[encode_sparse_array]] +encode_sparse_array +~~~~~~~~~~~~~~~~~~~ + +[source,lua] +------------ +convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]]) +-- "convert" must be a boolean. Default: false. +-- "ratio" must be a positive integer. Default: 2. +-- "safe" must be a positive integer. Default: 10. +------------ + +Lua CJSON classifies a Lua table into one of three kinds when encoding a +JSON array. This is determined by the number of values missing from the +Lua array as follows: + +Normal:: All values are available. +Sparse:: At least 1 value is missing. +Excessively sparse:: The number of values missing exceeds the configured + ratio. + +Lua CJSON encodes sparse Lua arrays as JSON arrays using JSON +null+ for +the missing entries. + +An array is excessively sparse when all the following conditions are +met: + +- +ratio+ > +0+ +- _maximum_index_ > +safe+ +- _maximum_index_ > _item_count_ * +ratio+ + +Lua CJSON will never consider an array to be _excessively sparse_ when ++ratio+ = +0+. The +safe+ limit ensures that small Lua arrays are always +encoded as sparse arrays. + +By default, attempting to encode an _excessively sparse_ array will +generate an error. If +convert+ is set to +true+, _excessively sparse_ +arrays will be converted to a JSON object. + +The current settings are always returned. A particular setting is only +changed when the argument is provided (non-++nil++). + +.Example: Encoding a sparse array +[source,lua] +cjson.encode({ [3] = "data" }) +-- Returns: '[null,null,"data"]' + +.Example: Enabling conversion to a JSON object +[source,lua] +cjson.encode_sparse_array(true) +cjson.encode({ [1000] = "excessively sparse" }) +-- Returns: '{"1000":"excessively sparse"}' + + +API (Variables) +--------------- + +_NAME +~~~~~ + +The name of the Lua CJSON module (+"cjson"+). + + +_VERSION +~~~~~~~~ + +The version number of the Lua CJSON module (+"2.1devel"+). + + +null +~~~~ + +Lua CJSON decodes JSON +null+ as a Lua +lightuserdata+ NULL pointer. ++cjson.null+ is provided for comparison. + + +[sect1] +References +---------- + +- http://tools.ietf.org/html/rfc4627[RFC 4627] +- http://www.json.org/[JSON website] + + +// vi:ft=asciidoc tw=72: diff --git a/luaclib/cjson/performance.txt b/luaclib/cjson/performance.txt new file mode 100644 index 0000000..fc3a5bb --- /dev/null +++ b/luaclib/cjson/performance.txt @@ -0,0 +1,89 @@ +JSON module performance comparison under Lua +============================================ +Mark Pulford +:revdate: January 22, 2012 + +This performance comparison aims to provide a guide of relative +performance between several fast and popular JSON modules. + +The examples used in this comparison were mostly sourced from the +http://json.org[JSON website] and +http://tools.ietf.org/html/rfc4627[RFC 4627]. + +Performance will vary widely between platforms and data sets. These +results should only be used as an approximation. + + +Modules +------- + +The following JSON modules for Lua were tested: + +http://chiselapp.com/user/dhkolf/repository/dkjson/[DKJSON 2.1]:: + - Lua implementation with no dependencies on other libraries + - Supports LPeg to improve decode performance + +https://github.com/brimworks/lua-yajl[Lua YAJL 2.0]:: + - C wrapper for the YAJL library + +http://www.kyne.com.au/%7Emark/software/lua-cjson.php[Lua CSJON 2.0.0]:: + - C implementation with no dependencies on other libraries + + +Summary +------- + +All modules were built and tested as follows: + +DKJSON:: Tested with/without LPeg 10.2. +Lua YAJL:: Tested with YAJL 2.0.4. +Lua CJSON:: Tested with Libc and internal floating point conversion + routines. + +The following Lua implementations were used for this comparison: + +- http://www.lua.org[Lua 5.1.4] (_Lua_) +- http://www.luajit.org[LuaJIT 2.0.0-beta9] (_JIT_) + +These results show the number of JSON operations per second sustained by +each module. All results have been normalised against the pure Lua +DKJSON implementation. + +.Decoding performance +............................................................................ + | DKJSON | Lua YAJL | Lua CJSON + | No LPeg With LPeg | | Libc Internal + | Lua JIT Lua JIT | Lua JIT | Lua JIT Lua JIT +example1 | 1x 2x 2.6x 3.4x | 7.1x 10x | 14x 20x 14x 20x +example2 | 1x 2.2x 2.9x 4.4x | 6.7x 9.9x | 14x 22x 14x 22x +example3 | 1x 2.1x 3x 4.3x | 6.9x 9.3x | 14x 21x 15x 22x +example4 | 1x 2x 2.5x 3.7x | 7.3x 10x | 12x 19x 12x 20x +example5 | 1x 2.2x 3x 4.5x | 7.8x 11x | 16x 24x 16x 24x +numbers | 1x 2.2x 2.3x 4x | 4.6x 5.5x | 8.9x 10x 13x 17x +rfc-example1 | 1x 2.1x 2.8x 4.3x | 6.1x 8.1x | 13x 19x 14x 21x +rfc-example2 | 1x 2.1x 3.1x 4.2x | 7.1x 9.2x | 15x 21x 17x 24x +types | 1x 2.2x 2.6x 4.3x | 5.3x 7.4x | 12x 20x 13x 21x +-------------|-------------------------|------------|----------------------- += Average => | 1x 2.1x 2.7x 4.1x | 6.5x 9x | 13x 20x 14x 21x +............................................................................ + +.Encoding performance +............................................................................. + | DKJSON | Lua YAJL | Lua CJSON + | No LPeg With LPeg | | Libc Internal + | Lua JIT Lua JIT | Lua JIT | Lua JIT Lua JIT +example1 | 1x 1.8x 0.97x 1.6x | 3.1x 5.2x | 23x 29x 23x 29x +example2 | 1x 2x 0.97x 1.7x | 2.6x 4.3x | 22x 28x 22x 28x +example3 | 1x 1.9x 0.98x 1.6x | 2.8x 4.3x | 13x 15x 16x 18x +example4 | 1x 1.7x 0.96x 1.3x | 3.9x 6.1x | 15x 19x 17x 21x +example5 | 1x 2x 0.98x 1.7x | 2.7x 4.5x | 20x 23x 20x 23x +numbers | 1x 2.3x 1x 2.2x | 1.3x 1.9x | 3.8x 4.1x 4.2x 4.6x +rfc-example1 | 1x 1.9x 0.97x 1.6x | 2.2x 3.2x | 8.5x 9.3x 11x 12x +rfc-example2 | 1x 1.9x 0.98x 1.6x | 2.6x 3.9x | 10x 11x 17x 19x +types | 1x 2.2x 0.97x 2x | 1.2x 1.9x | 11x 13x 12x 14x +-------------|-------------------------|------------|----------------------- += Average => | 1x 1.9x 0.98x 1.7x | 2.5x 3.9x | 14x 17x 16x 19x +............................................................................. + + +// vi:ft=asciidoc tw=72: diff --git a/luaclib/cjson/rfc4627.txt b/luaclib/cjson/rfc4627.txt new file mode 100644 index 0000000..67b8909 --- /dev/null +++ b/luaclib/cjson/rfc4627.txt @@ -0,0 +1,563 @@ + + + + + + +Network Working Group D. Crockford +Request for Comments: 4627 JSON.org +Category: Informational July 2006 + + + The application/json Media Type for JavaScript Object Notation (JSON) + +Status of This Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2006). + +Abstract + + JavaScript Object Notation (JSON) is a lightweight, text-based, + language-independent data interchange format. It was derived from + the ECMAScript Programming Language Standard. JSON defines a small + set of formatting rules for the portable representation of structured + data. + +1. Introduction + + JavaScript Object Notation (JSON) is a text format for the + serialization of structured data. It is derived from the object + literals of JavaScript, as defined in the ECMAScript Programming + Language Standard, Third Edition [ECMA]. + + JSON can represent four primitive types (strings, numbers, booleans, + and null) and two structured types (objects and arrays). + + A string is a sequence of zero or more Unicode characters [UNICODE]. + + An object is an unordered collection of zero or more name/value + pairs, where a name is a string and a value is a string, number, + boolean, null, object, or array. + + An array is an ordered sequence of zero or more values. + + The terms "object" and "array" come from the conventions of + JavaScript. + + JSON's design goals were for it to be minimal, portable, textual, and + a subset of JavaScript. + + + +Crockford Informational [Page 1] + +RFC 4627 JSON July 2006 + + +1.1. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + The grammatical rules in this document are to be interpreted as + described in [RFC4234]. + +2. JSON Grammar + + A JSON text is a sequence of tokens. The set of tokens includes six + structural characters, strings, numbers, and three literal names. + + A JSON text is a serialized object or array. + + JSON-text = object / array + + These are the six structural characters: + + begin-array = ws %x5B ws ; [ left square bracket + + begin-object = ws %x7B ws ; { left curly bracket + + end-array = ws %x5D ws ; ] right square bracket + + end-object = ws %x7D ws ; } right curly bracket + + name-separator = ws %x3A ws ; : colon + + value-separator = ws %x2C ws ; , comma + + Insignificant whitespace is allowed before or after any of the six + structural characters. + + ws = *( + %x20 / ; Space + %x09 / ; Horizontal tab + %x0A / ; Line feed or New line + %x0D ; Carriage return + ) + +2.1. Values + + A JSON value MUST be an object, array, number, or string, or one of + the following three literal names: + + false null true + + + +Crockford Informational [Page 2] + +RFC 4627 JSON July 2006 + + + The literal names MUST be lowercase. No other literal names are + allowed. + + value = false / null / true / object / array / number / string + + false = %x66.61.6c.73.65 ; false + + null = %x6e.75.6c.6c ; null + + true = %x74.72.75.65 ; true + +2.2. Objects + + An object structure is represented as a pair of curly brackets + surrounding zero or more name/value pairs (or members). A name is a + string. A single colon comes after each name, separating the name + from the value. A single comma separates a value from a following + name. The names within an object SHOULD be unique. + + object = begin-object [ member *( value-separator member ) ] + end-object + + member = string name-separator value + +2.3. Arrays + + An array structure is represented as square brackets surrounding zero + or more values (or elements). Elements are separated by commas. + + array = begin-array [ value *( value-separator value ) ] end-array + +2.4. Numbers + + The representation of numbers is similar to that used in most + programming languages. A number contains an integer component that + may be prefixed with an optional minus sign, which may be followed by + a fraction part and/or an exponent part. + + Octal and hex forms are not allowed. Leading zeros are not allowed. + + A fraction part is a decimal point followed by one or more digits. + + An exponent part begins with the letter E in upper or lowercase, + which may be followed by a plus or minus sign. The E and optional + sign are followed by one or more digits. + + Numeric values that cannot be represented as sequences of digits + (such as Infinity and NaN) are not permitted. + + + +Crockford Informational [Page 3] + +RFC 4627 JSON July 2006 + + + number = [ minus ] int [ frac ] [ exp ] + + decimal-point = %x2E ; . + + digit1-9 = %x31-39 ; 1-9 + + e = %x65 / %x45 ; e E + + exp = e [ minus / plus ] 1*DIGIT + + frac = decimal-point 1*DIGIT + + int = zero / ( digit1-9 *DIGIT ) + + minus = %x2D ; - + + plus = %x2B ; + + + zero = %x30 ; 0 + +2.5. Strings + + The representation of strings is similar to conventions used in the C + family of programming languages. A string begins and ends with + quotation marks. All Unicode characters may be placed within the + quotation marks except for the characters that must be escaped: + quotation mark, reverse solidus, and the control characters (U+0000 + through U+001F). + + Any character may be escaped. If the character is in the Basic + Multilingual Plane (U+0000 through U+FFFF), then it may be + represented as a six-character sequence: a reverse solidus, followed + by the lowercase letter u, followed by four hexadecimal digits that + encode the character's code point. The hexadecimal letters A though + F can be upper or lowercase. So, for example, a string containing + only a single reverse solidus character may be represented as + "\u005C". + + Alternatively, there are two-character sequence escape + representations of some popular characters. So, for example, a + string containing only a single reverse solidus character may be + represented more compactly as "\\". + + To escape an extended character that is not in the Basic Multilingual + Plane, the character is represented as a twelve-character sequence, + encoding the UTF-16 surrogate pair. So, for example, a string + containing only the G clef character (U+1D11E) may be represented as + "\uD834\uDD1E". + + + +Crockford Informational [Page 4] + +RFC 4627 JSON July 2006 + + + string = quotation-mark *char quotation-mark + + char = unescaped / + escape ( + %x22 / ; " quotation mark U+0022 + %x5C / ; \ reverse solidus U+005C + %x2F / ; / solidus U+002F + %x62 / ; b backspace U+0008 + %x66 / ; f form feed U+000C + %x6E / ; n line feed U+000A + %x72 / ; r carriage return U+000D + %x74 / ; t tab U+0009 + %x75 4HEXDIG ) ; uXXXX U+XXXX + + escape = %x5C ; \ + + quotation-mark = %x22 ; " + + unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + +3. Encoding + + JSON text SHALL be encoded in Unicode. The default encoding is + UTF-8. + + Since the first two characters of a JSON text will always be ASCII + characters [RFC0020], it is possible to determine whether an octet + stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking + at the pattern of nulls in the first four octets. + + 00 00 00 xx UTF-32BE + 00 xx 00 xx UTF-16BE + xx 00 00 00 UTF-32LE + xx 00 xx 00 UTF-16LE + xx xx xx xx UTF-8 + +4. Parsers + + A JSON parser transforms a JSON text into another representation. A + JSON parser MUST accept all texts that conform to the JSON grammar. + A JSON parser MAY accept non-JSON forms or extensions. + + An implementation may set limits on the size of texts that it + accepts. An implementation may set limits on the maximum depth of + nesting. An implementation may set limits on the range of numbers. + An implementation may set limits on the length and character contents + of strings. + + + + +Crockford Informational [Page 5] + +RFC 4627 JSON July 2006 + + +5. Generators + + A JSON generator produces JSON text. The resulting text MUST + strictly conform to the JSON grammar. + +6. IANA Considerations + + The MIME media type for JSON text is application/json. + + Type name: application + + Subtype name: json + + Required parameters: n/a + + Optional parameters: n/a + + Encoding considerations: 8bit if UTF-8; binary if UTF-16 or UTF-32 + + JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON + is written in UTF-8, JSON is 8bit compatible. When JSON is + written in UTF-16 or UTF-32, the binary content-transfer-encoding + must be used. + + Security considerations: + + Generally there are security issues with scripting languages. JSON + is a subset of JavaScript, but it is a safe subset that excludes + assignment and invocation. + + A JSON text can be safely passed into JavaScript's eval() function + (which compiles and executes a string) if all the characters not + enclosed in strings are in the set of characters that form JSON + tokens. This can be quickly determined in JavaScript with two + regular expressions and calls to the test and replace methods. + + var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test( + text.replace(/"(\\.|[^"\\])*"/g, ''))) && + eval('(' + text + ')'); + + Interoperability considerations: n/a + + Published specification: RFC 4627 + + + + + + + + +Crockford Informational [Page 6] + +RFC 4627 JSON July 2006 + + + Applications that use this media type: + + JSON has been used to exchange data between applications written + in all of these programming languages: ActionScript, C, C#, + ColdFusion, Common Lisp, E, Erlang, Java, JavaScript, Lua, + Objective CAML, Perl, PHP, Python, Rebol, Ruby, and Scheme. + + Additional information: + + Magic number(s): n/a + File extension(s): .json + Macintosh file type code(s): TEXT + + Person & email address to contact for further information: + Douglas Crockford + douglas@crockford.com + + Intended usage: COMMON + + Restrictions on usage: none + + Author: + Douglas Crockford + douglas@crockford.com + + Change controller: + Douglas Crockford + douglas@crockford.com + +7. Security Considerations + + See Security Considerations in Section 6. + +8. Examples + + This is a JSON object: + + { + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": "100" + }, + "IDs": [116, 943, 234, 38793] + + + +Crockford Informational [Page 7] + +RFC 4627 JSON July 2006 + + + } + } + + Its Image member is an object whose Thumbnail member is an object + and whose IDs member is an array of numbers. + + This is a JSON array containing two objects: + + [ + { + "precision": "zip", + "Latitude": 37.7668, + "Longitude": -122.3959, + "Address": "", + "City": "SAN FRANCISCO", + "State": "CA", + "Zip": "94107", + "Country": "US" + }, + { + "precision": "zip", + "Latitude": 37.371991, + "Longitude": -122.026020, + "Address": "", + "City": "SUNNYVALE", + "State": "CA", + "Zip": "94085", + "Country": "US" + } + ] + +9. References + +9.1. Normative References + + [ECMA] European Computer Manufacturers Association, "ECMAScript + Language Specification 3rd Edition", December 1999, + . + + [RFC0020] Cerf, V., "ASCII format for network interchange", RFC 20, + October 1969. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC4234] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", RFC 4234, October 2005. + + + +Crockford Informational [Page 8] + +RFC 4627 JSON July 2006 + + + [UNICODE] The Unicode Consortium, "The Unicode Standard Version 4.0", + 2003, . + +Author's Address + + Douglas Crockford + JSON.org + EMail: douglas@crockford.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Crockford Informational [Page 9] + +RFC 4627 JSON July 2006 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2006). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + ietf-ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is provided by the IETF + Administrative Support Activity (IASA). + + + + + + + +Crockford Informational [Page 10] + diff --git a/luaclib/cjson/runtests.sh b/luaclib/cjson/runtests.sh new file mode 100644 index 0000000..87db0bc --- /dev/null +++ b/luaclib/cjson/runtests.sh @@ -0,0 +1,92 @@ +#!/bin/sh + +PLATFORM="`uname -s`" +[ "$1" ] && VERSION="$1" || VERSION="2.1devel" + +set -e + +# Portable "ggrep -A" replacement. +# Work around Solaris awk record limit of 2559 bytes. +# contextgrep PATTERN POST_MATCH_LINES +contextgrep() { + cut -c -2500 | awk "/$1/ { count = ($2 + 1) } count > 0 { count--; print }" +} + +do_tests() { + echo + cd tests + lua -e 'print("Testing Lua CJSON version " .. require("cjson")._VERSION)' + ./test.lua | contextgrep 'FAIL|Summary' 3 | grep -v PASS | cut -c -150 + cd .. +} + +echo "===== Setting LuaRocks PATH =====" +eval "`luarocks path`" + +echo "===== Building UTF-8 test data =====" +( cd tests && ./genutf8.pl; ) + +echo "===== Cleaning old build data =====" +make clean +rm -f tests/cjson.so + +echo "===== Verifying cjson.so is not installed =====" + +cd tests +if lua -e 'require "cjson"' 2>/dev/null +then + cat < "$LOG" + RPM="`awk '/^Wrote: / && ! /debuginfo/ { print $2}' < "$LOG"`" + sudo -- rpm -Uvh \"$RPM\" + do_tests + sudo -- rpm -e lua-cjson + rm -f "$LOG" + else + echo "==> skipping, $TGZ not found" + fi +fi + +# vi:ai et sw=4 ts=4: diff --git a/luaclib/cjson/strbuf.c b/luaclib/cjson/strbuf.c new file mode 100644 index 0000000..f0f7f4b --- /dev/null +++ b/luaclib/cjson/strbuf.c @@ -0,0 +1,251 @@ +/* strbuf - String buffer routines + * + * Copyright (c) 2010-2012 Mark Pulford + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "strbuf.h" + +static void die(const char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + vfprintf(stderr, fmt, arg); + va_end(arg); + fprintf(stderr, "\n"); + + exit(-1); +} + +void strbuf_init(strbuf_t *s, int len) +{ + int size; + + if (len <= 0) + size = STRBUF_DEFAULT_SIZE; + else + size = len + 1; /* \0 terminator */ + + s->buf = NULL; + s->size = size; + s->length = 0; + s->increment = STRBUF_DEFAULT_INCREMENT; + s->dynamic = 0; + s->reallocs = 0; + s->debug = 0; + + s->buf = malloc(size); + if (!s->buf) + die("Out of memory"); + + strbuf_ensure_null(s); +} + +strbuf_t *strbuf_new(int len) +{ + strbuf_t *s; + + s = malloc(sizeof(strbuf_t)); + if (!s) + die("Out of memory"); + + strbuf_init(s, len); + + /* Dynamic strbuf allocation / deallocation */ + s->dynamic = 1; + + return s; +} + +void strbuf_set_increment(strbuf_t *s, int increment) +{ + /* Increment > 0: Linear buffer growth rate + * Increment < -1: Exponential buffer growth rate */ + if (increment == 0 || increment == -1) + die("BUG: Invalid string increment"); + + s->increment = increment; +} + +static inline void debug_stats(strbuf_t *s) +{ + if (s->debug) { + fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n", + (long)s, s->reallocs, s->length, s->size); + } +} + +/* If strbuf_t has not been dynamically allocated, strbuf_free() can + * be called any number of times strbuf_init() */ +void strbuf_free(strbuf_t *s) +{ + debug_stats(s); + + if (s->buf) { + free(s->buf); + s->buf = NULL; + } + if (s->dynamic) + free(s); +} + +char *strbuf_free_to_string(strbuf_t *s, int *len) +{ + char *buf; + + debug_stats(s); + + strbuf_ensure_null(s); + + buf = s->buf; + if (len) + *len = s->length; + + if (s->dynamic) + free(s); + + return buf; +} + +static int calculate_new_size(strbuf_t *s, int len) +{ + int reqsize, newsize; + + if (len <= 0) + die("BUG: Invalid strbuf length requested"); + + /* Ensure there is room for optional NULL termination */ + reqsize = len + 1; + + /* If the user has requested to shrink the buffer, do it exactly */ + if (s->size > reqsize) + return reqsize; + + newsize = s->size; + if (s->increment < 0) { + /* Exponential sizing */ + while (newsize < reqsize) + newsize *= -s->increment; + } else { + /* Linear sizing */ + newsize = ((newsize + s->increment - 1) / s->increment) * s->increment; + } + + return newsize; +} + + +/* Ensure strbuf can handle a string length bytes long (ignoring NULL + * optional termination). */ +void strbuf_resize(strbuf_t *s, int len) +{ + int newsize; + + newsize = calculate_new_size(s, len); + + if (s->debug > 1) { + fprintf(stderr, "strbuf(%lx) resize: %d => %d\n", + (long)s, s->size, newsize); + } + + s->size = newsize; + s->buf = realloc(s->buf, s->size); + if (!s->buf) + die("Out of memory"); + s->reallocs++; +} + +void strbuf_append_string(strbuf_t *s, const char *str) +{ + int space, i; + + space = strbuf_empty_length(s); + + for (i = 0; str[i]; i++) { + if (space < 1) { + strbuf_resize(s, s->length + 1); + space = strbuf_empty_length(s); + } + + s->buf[s->length] = str[i]; + s->length++; + space--; + } +} + +/* strbuf_append_fmt() should only be used when an upper bound + * is known for the output string. */ +void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...) +{ + va_list arg; + int fmt_len; + + strbuf_ensure_empty_length(s, len); + + va_start(arg, fmt); + fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg); + va_end(arg); + + if (fmt_len < 0) + die("BUG: Unable to convert number"); /* This should never happen.. */ + + s->length += fmt_len; +} + +/* strbuf_append_fmt_retry() can be used when the there is no known + * upper bound for the output string. */ +void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...) +{ + va_list arg; + int fmt_len, try; + int empty_len; + + /* If the first attempt to append fails, resize the buffer appropriately + * and try again */ + for (try = 0; ; try++) { + va_start(arg, fmt); + /* Append the new formatted string */ + /* fmt_len is the length of the string required, excluding the + * trailing NULL */ + empty_len = strbuf_empty_length(s); + /* Add 1 since there is also space to store the terminating NULL. */ + fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg); + va_end(arg); + + if (fmt_len <= empty_len) + break; /* SUCCESS */ + if (try > 0) + die("BUG: length of formatted string changed"); + + strbuf_resize(s, s->length + fmt_len); + } + + s->length += fmt_len; +} + +/* vi:ai et sw=4 ts=4: + */ diff --git a/luaclib/cjson/strbuf.h b/luaclib/cjson/strbuf.h new file mode 100644 index 0000000..d861108 --- /dev/null +++ b/luaclib/cjson/strbuf.h @@ -0,0 +1,154 @@ +/* strbuf - String buffer routines + * + * Copyright (c) 2010-2012 Mark Pulford + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +/* Size: Total bytes allocated to *buf + * Length: String length, excluding optional NULL terminator. + * Increment: Allocation increments when resizing the string buffer. + * Dynamic: True if created via strbuf_new() + */ + +typedef struct { + char *buf; + int size; + int length; + int increment; + int dynamic; + int reallocs; + int debug; +} strbuf_t; + +#ifndef STRBUF_DEFAULT_SIZE +#define STRBUF_DEFAULT_SIZE 1023 +#endif +#ifndef STRBUF_DEFAULT_INCREMENT +#define STRBUF_DEFAULT_INCREMENT -2 +#endif + +/* Initialise */ +extern strbuf_t *strbuf_new(int len); +extern void strbuf_init(strbuf_t *s, int len); +extern void strbuf_set_increment(strbuf_t *s, int increment); + +/* Release */ +extern void strbuf_free(strbuf_t *s); +extern char *strbuf_free_to_string(strbuf_t *s, int *len); + +/* Management */ +extern void strbuf_resize(strbuf_t *s, int len); +static int strbuf_empty_length(strbuf_t *s); +static int strbuf_length(strbuf_t *s); +static char *strbuf_string(strbuf_t *s, int *len); +static void strbuf_ensure_empty_length(strbuf_t *s, int len); +static char *strbuf_empty_ptr(strbuf_t *s); +static void strbuf_extend_length(strbuf_t *s, int len); + +/* Update */ +extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...); +extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...); +static void strbuf_append_mem(strbuf_t *s, const char *c, int len); +extern void strbuf_append_string(strbuf_t *s, const char *str); +static void strbuf_append_char(strbuf_t *s, const char c); +static void strbuf_ensure_null(strbuf_t *s); + +/* Reset string for before use */ +static inline void strbuf_reset(strbuf_t *s) +{ + s->length = 0; +} + +static inline int strbuf_allocated(strbuf_t *s) +{ + return s->buf != NULL; +} + +/* Return bytes remaining in the string buffer + * Ensure there is space for a NULL terminator. */ +static inline int strbuf_empty_length(strbuf_t *s) +{ + return s->size - s->length - 1; +} + +static inline void strbuf_ensure_empty_length(strbuf_t *s, int len) +{ + if (len > strbuf_empty_length(s)) + strbuf_resize(s, s->length + len); +} + +static inline char *strbuf_empty_ptr(strbuf_t *s) +{ + return s->buf + s->length; +} + +static inline void strbuf_extend_length(strbuf_t *s, int len) +{ + s->length += len; +} + +static inline int strbuf_length(strbuf_t *s) +{ + return s->length; +} + +static inline void strbuf_append_char(strbuf_t *s, const char c) +{ + strbuf_ensure_empty_length(s, 1); + s->buf[s->length++] = c; +} + +static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c) +{ + s->buf[s->length++] = c; +} + +static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len) +{ + strbuf_ensure_empty_length(s, len); + memcpy(s->buf + s->length, c, len); + s->length += len; +} + +static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len) +{ + memcpy(s->buf + s->length, c, len); + s->length += len; +} + +static inline void strbuf_ensure_null(strbuf_t *s) +{ + s->buf[s->length] = 0; +} + +static inline char *strbuf_string(strbuf_t *s, int *len) +{ + if (len) + *len = s->length; + + return s->buf; +} + +/* vi:ai et sw=4 ts=4: + */ diff --git a/luaclib/cjson/tests/README b/luaclib/cjson/tests/README new file mode 100644 index 0000000..39e8bd4 --- /dev/null +++ b/luaclib/cjson/tests/README @@ -0,0 +1,4 @@ +These JSON examples were taken from the JSON website +(http://json.org/example.html) and RFC 4627. + +Used with permission. diff --git a/luaclib/cjson/tests/TestLua.pm b/luaclib/cjson/tests/TestLua.pm new file mode 100644 index 0000000..cd22d83 --- /dev/null +++ b/luaclib/cjson/tests/TestLua.pm @@ -0,0 +1,70 @@ +package TestLua; + +use Test::Base -Base; +use IPC::Run3; +use Cwd; + +use Test::LongString; + +our @EXPORT = qw( run_tests ); + +$ENV{LUA_CPATH} = "../?.so;;"; +$ENV{LUA_PATH} = "../lua/?.lua;;"; +#$ENV{LUA_PATH} = ($ENV{LUA_PATH} || "" ) . ';' . getcwd . "/runtime/?.lua" . ';;'; + +sub run_test ($) { + my $block = shift; + #print $json_xs->pretty->encode(\@new_rows); + #my $res = #print $json_xs->pretty->encode($res); + my $name = $block->name; + + my $lua = $block->lua or + die "No --- lua specified for test $name\n"; + + my $luafile = "test_case.lua"; + + open my $fh, ">$luafile" or + die "Cannot open $luafile for writing: $!\n"; + + print $fh $lua; + close $fh; + + my ($res, $err); + + my @cmd; + + if ($ENV{TEST_LUA_USE_VALGRIND}) { + @cmd = ('valgrind', '-q', '--leak-check=full', 'lua', 'test_case.lua'); + } else { + @cmd = ('lua', 'test_case.lua'); + } + + run3 \@cmd, undef, \$res, \$err; + my $rc = $?; + + #warn "res:$res\nerr:$err\n"; + + if (defined $block->err) { + $err =~ /.*:.*:.*: (.*\s)?/; + $err = $1; + is $err, $block->err, "$name - err expected"; + + } elsif ($rc) { + die "Failed to execute --- lua for test $name: $err\n"; + + } else { + #is $res, $block->out, "$name - output ok"; + is $res, $block->out, "$name - output ok"; + } + + is $rc, ($block->exit || 0), "$name - exit code ok"; + #unlink 'test_case.lua' or warn "could not delete \'test_case.lua\':$!"; +} + +sub run_tests () { + for my $block (blocks()) { + run_test($block); + } +} + +1; diff --git a/luaclib/cjson/tests/agentzh.t b/luaclib/cjson/tests/agentzh.t new file mode 100644 index 0000000..e65288f --- /dev/null +++ b/luaclib/cjson/tests/agentzh.t @@ -0,0 +1,52 @@ +use TestLua; + +plan tests => 2 * blocks(); + +run_tests(); + +__DATA__ + +=== TEST 1: empty tables as objects +--- lua +local cjson = require "cjson" +print(cjson.encode({})) +print(cjson.encode({dogs = {}})) +--- out +{} +{"dogs":{}} + + + +=== TEST 2: empty tables as arrays +--- lua +local cjson = require "cjson" +cjson.encode_empty_table_as_object(false) +print(cjson.encode({})) +print(cjson.encode({dogs = {}})) +--- out +[] +{"dogs":[]} + + + +=== TEST 3: empty tables as objects (explicit) +--- lua +local cjson = require "cjson" +cjson.encode_empty_table_as_object(true) +print(cjson.encode({})) +print(cjson.encode({dogs = {}})) +--- out +{} +{"dogs":{}} + + + +=== TEST 4: & in JSON +--- lua +local cjson = require "cjson" +local a="[\"a=1&b=2\"]" +local b=cjson.decode(a) +print(cjson.encode(b)) +--- out +["a=1&b=2"] + diff --git a/luaclib/cjson/tests/bench.lua b/luaclib/cjson/tests/bench.lua new file mode 100644 index 0000000..648020b --- /dev/null +++ b/luaclib/cjson/tests/bench.lua @@ -0,0 +1,131 @@ +#!/usr/bin/env lua + +-- This benchmark script measures wall clock time and should be +-- run on an unloaded system. +-- +-- Your Mileage May Vary. +-- +-- Mark Pulford + +local json_module = os.getenv("JSON_MODULE") or "cjson" + +require "socket" +local json = require(json_module) +local util = require "cjson.util" + +local function find_func(mod, funcnames) + for _, v in ipairs(funcnames) do + if mod[v] then + return mod[v] + end + end + + return nil +end + +local json_encode = find_func(json, { "encode", "Encode", "to_string", "stringify", "json" }) +local json_decode = find_func(json, { "decode", "Decode", "to_value", "parse" }) + +local function average(t) + local total = 0 + for _, v in ipairs(t) do + total = total + v + end + return total / #t +end + +function benchmark(tests, seconds, rep) + local function bench(func, iter) + -- Use socket.gettime() to measure microsecond resolution + -- wall clock time. + local t = socket.gettime() + for i = 1, iter do + func(i) + end + t = socket.gettime() - t + + -- Don't trust any results when the run lasted for less than a + -- millisecond - return nil. + if t < 0.001 then + return nil + end + + return (iter / t) + end + + -- Roughly calculate the number of interations required + -- to obtain a particular time period. + local function calc_iter(func, seconds) + local iter = 1 + local rate + -- Warm up the bench function first. + func() + while not rate do + rate = bench(func, iter) + iter = iter * 10 + end + return math.ceil(seconds * rate) + end + + local test_results = {} + for name, func in pairs(tests) do + -- k(number), v(string) + -- k(string), v(function) + -- k(number), v(function) + if type(func) == "string" then + name = func + func = _G[name] + end + + local iter = calc_iter(func, seconds) + + local result = {} + for i = 1, rep do + result[i] = bench(func, iter) + end + + -- Remove the slowest half (round down) of the result set + table.sort(result) + for i = 1, math.floor(#result / 2) do + table.remove(result, 1) + end + + test_results[name] = average(result) + end + + return test_results +end + +function bench_file(filename) + local data_json = util.file_load(filename) + local data_obj = json_decode(data_json) + + local function test_encode() + json_encode(data_obj) + end + local function test_decode() + json_decode(data_json) + end + + local tests = {} + if json_encode then tests.encode = test_encode end + if json_decode then tests.decode = test_decode end + + return benchmark(tests, 0.1, 5) +end + +-- Optionally load any custom configuration required for this module +local success, data = pcall(util.file_load, ("bench-%s.lua"):format(json_module)) +if success then + util.run_script(data, _G) + configure(json) +end + +for i = 1, #arg do + local results = bench_file(arg[i]) + for k, v in pairs(results) do + print(("%s\t%s\t%d"):format(arg[i], k, v)) + end +end + +-- vi:ai et sw=4 ts=4: diff --git a/luaclib/cjson/tests/example1.json b/luaclib/cjson/tests/example1.json new file mode 100644 index 0000000..42486ce --- /dev/null +++ b/luaclib/cjson/tests/example1.json @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Mark up Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} diff --git a/luaclib/cjson/tests/example2.json b/luaclib/cjson/tests/example2.json new file mode 100644 index 0000000..5600991 --- /dev/null +++ b/luaclib/cjson/tests/example2.json @@ -0,0 +1,11 @@ +{"menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"} + ] + } +}} diff --git a/luaclib/cjson/tests/example3.json b/luaclib/cjson/tests/example3.json new file mode 100644 index 0000000..d7237a5 --- /dev/null +++ b/luaclib/cjson/tests/example3.json @@ -0,0 +1,26 @@ +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} diff --git a/luaclib/cjson/tests/example4.json b/luaclib/cjson/tests/example4.json new file mode 100644 index 0000000..d31a395 --- /dev/null +++ b/luaclib/cjson/tests/example4.json @@ -0,0 +1,88 @@ +{"web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500}}, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2"}}, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet"}, + + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet"}, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true}}], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*"}, + + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} diff --git a/luaclib/cjson/tests/example5.json b/luaclib/cjson/tests/example5.json new file mode 100644 index 0000000..49980ca --- /dev/null +++ b/luaclib/cjson/tests/example5.json @@ -0,0 +1,27 @@ +{"menu": { + "header": "SVG Viewer", + "items": [ + {"id": "Open"}, + {"id": "OpenNew", "label": "Open New"}, + null, + {"id": "ZoomIn", "label": "Zoom In"}, + {"id": "ZoomOut", "label": "Zoom Out"}, + {"id": "OriginalView", "label": "Original View"}, + null, + {"id": "Quality"}, + {"id": "Pause"}, + {"id": "Mute"}, + null, + {"id": "Find", "label": "Find..."}, + {"id": "FindAgain", "label": "Find Again"}, + {"id": "Copy"}, + {"id": "CopyAgain", "label": "Copy Again"}, + {"id": "CopySVG", "label": "Copy SVG"}, + {"id": "ViewSVG", "label": "View SVG"}, + {"id": "ViewSource", "label": "View Source"}, + {"id": "SaveAs", "label": "Save As"}, + null, + {"id": "Help"}, + {"id": "About", "label": "About Adobe CVG Viewer..."} + ] +}} diff --git a/luaclib/cjson/tests/genutf8.pl b/luaclib/cjson/tests/genutf8.pl new file mode 100644 index 0000000..db661a1 --- /dev/null +++ b/luaclib/cjson/tests/genutf8.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl + +# Create test comparison data using a different UTF-8 implementation. + +# The generated utf8.dat file must have the following MD5 sum: +# cff03b039d850f370a7362f3313e5268 + +use strict; + +# 0xD800 - 0xDFFF are used to encode supplementary codepoints +# 0x10000 - 0x10FFFF are supplementary codepoints +my (@codepoints) = (0 .. 0xD7FF, 0xE000 .. 0x10FFFF); + +my $utf8 = pack("U*", @codepoints); +defined($utf8) or die "Unable create UTF-8 string\n"; + +open(FH, ">:utf8", "utf8.dat") + or die "Unable to open utf8.dat: $!\n"; +print FH $utf8 + or die "Unable to write utf8.dat\n"; +close(FH); + +# vi:ai et sw=4 ts=4: diff --git a/luaclib/cjson/tests/numbers.json b/luaclib/cjson/tests/numbers.json new file mode 100644 index 0000000..4f981ff --- /dev/null +++ b/luaclib/cjson/tests/numbers.json @@ -0,0 +1,7 @@ +[ 0.110001, + 0.12345678910111, + 0.412454033640, + 2.6651441426902, + 2.718281828459, + 3.1415926535898, + 2.1406926327793 ] diff --git a/luaclib/cjson/tests/octets-escaped.dat b/luaclib/cjson/tests/octets-escaped.dat new file mode 100644 index 0000000..ee99a6b --- /dev/null +++ b/luaclib/cjson/tests/octets-escaped.dat @@ -0,0 +1 @@ +"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-.\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f" \ No newline at end of file diff --git a/luaclib/cjson/tests/rfc-example1.json b/luaclib/cjson/tests/rfc-example1.json new file mode 100644 index 0000000..73532fa --- /dev/null +++ b/luaclib/cjson/tests/rfc-example1.json @@ -0,0 +1,13 @@ +{ + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": "100" + }, + "IDs": [116, 943, 234, 38793] + } +} diff --git a/luaclib/cjson/tests/rfc-example2.json b/luaclib/cjson/tests/rfc-example2.json new file mode 100644 index 0000000..2a0cb68 --- /dev/null +++ b/luaclib/cjson/tests/rfc-example2.json @@ -0,0 +1,22 @@ +[ + { + "precision": "zip", + "Latitude": 37.7668, + "Longitude": -122.3959, + "Address": "", + "City": "SAN FRANCISCO", + "State": "CA", + "Zip": "94107", + "Country": "US" + }, + { + "precision": "zip", + "Latitude": 37.371991, + "Longitude": -122.026020, + "Address": "", + "City": "SUNNYVALE", + "State": "CA", + "Zip": "94085", + "Country": "US" + } +] diff --git a/luaclib/cjson/tests/test.lua b/luaclib/cjson/tests/test.lua new file mode 100644 index 0000000..b8fce84 --- /dev/null +++ b/luaclib/cjson/tests/test.lua @@ -0,0 +1,425 @@ +#!/usr/bin/env lua + +-- Lua CJSON tests +-- +-- Mark Pulford +-- +-- Note: The output of this script is easier to read with "less -S" + +local json = require "cjson" +local json_safe = require "cjson.safe" +local util = require "cjson.util" + +local function gen_raw_octets() + local chars = {} + for i = 0, 255 do chars[i + 1] = string.char(i) end + return table.concat(chars) +end + +-- Generate every UTF-16 codepoint, including supplementary codes +local function gen_utf16_escaped() + -- Create raw table escapes + local utf16_escaped = {} + local count = 0 + + local function append_escape(code) + local esc = ('\\u%04X'):format(code) + table.insert(utf16_escaped, esc) + end + + table.insert(utf16_escaped, '"') + for i = 0, 0xD7FF do + append_escape(i) + end + -- Skip 0xD800 - 0xDFFF since they are used to encode supplementary + -- codepoints + for i = 0xE000, 0xFFFF do + append_escape(i) + end + -- Append surrogate pair for each supplementary codepoint + for high = 0xD800, 0xDBFF do + for low = 0xDC00, 0xDFFF do + append_escape(high) + append_escape(low) + end + end + table.insert(utf16_escaped, '"') + + return table.concat(utf16_escaped) +end + +function load_testdata() + local data = {} + + -- Data for 8bit raw <-> escaped octets tests + data.octets_raw = gen_raw_octets() + data.octets_escaped = util.file_load("octets-escaped.dat") + + -- Data for \uXXXX -> UTF-8 test + data.utf16_escaped = gen_utf16_escaped() + + -- Load matching data for utf16_escaped + local utf8_loaded + utf8_loaded, data.utf8_raw = pcall(util.file_load, "utf8.dat") + if not utf8_loaded then + data.utf8_raw = "Failed to load utf8.dat - please run genutf8.pl" + end + + data.table_cycle = {} + data.table_cycle[1] = data.table_cycle + + local big = {} + for i = 1, 1100 do + big = { { 10, false, true, json.null }, "string", a = big } + end + data.deeply_nested_data = big + + return data +end + +function test_decode_cycle(filename) + local obj1 = json.decode(util.file_load(filename)) + local obj2 = json.decode(json.encode(obj1)) + return util.compare_values(obj1, obj2) +end + +-- Set up data used in tests +local Inf = math.huge; +local NaN = math.huge * 0; + +local testdata = load_testdata() + +local cjson_tests = { + -- Test API variables + { "Check module name, version", + function () return json._NAME, json._VERSION end, { }, + true, { "cjson", "2.1devel" } }, + + -- Test decoding simple types + { "Decode string", + json.decode, { '"test string"' }, true, { "test string" } }, + { "Decode numbers", + json.decode, { '[ 0.0, -5e3, -1, 0.3e-3, 1023.2, 0e10 ]' }, + true, { { 0.0, -5000, -1, 0.0003, 1023.2, 0 } } }, + { "Decode null", + json.decode, { 'null' }, true, { json.null } }, + { "Decode true", + json.decode, { 'true' }, true, { true } }, + { "Decode false", + json.decode, { 'false' }, true, { false } }, + { "Decode object with numeric keys", + json.decode, { '{ "1": "one", "3": "three" }' }, + true, { { ["1"] = "one", ["3"] = "three" } } }, + { "Decode object with string keys", + json.decode, { '{ "a": "a", "b": "b" }' }, + true, { { a = "a", b = "b" } } }, + { "Decode array", + json.decode, { '[ "one", null, "three" ]' }, + true, { { "one", json.null, "three" } } }, + + -- Test decoding errors + { "Decode UTF-16BE [throw error]", + json.decode, { '\0"\0"' }, + false, { "JSON parser does not support UTF-16 or UTF-32" } }, + { "Decode UTF-16LE [throw error]", + json.decode, { '"\0"\0' }, + false, { "JSON parser does not support UTF-16 or UTF-32" } }, + { "Decode UTF-32BE [throw error]", + json.decode, { '\0\0\0"' }, + false, { "JSON parser does not support UTF-16 or UTF-32" } }, + { "Decode UTF-32LE [throw error]", + json.decode, { '"\0\0\0' }, + false, { "JSON parser does not support UTF-16 or UTF-32" } }, + { "Decode partial JSON [throw error]", + json.decode, { '{ "unexpected eof": ' }, + false, { "Expected value but found T_END at character 21" } }, + { "Decode with extra comma [throw error]", + json.decode, { '{ "extra data": true }, false' }, + false, { "Expected the end but found T_COMMA at character 23" } }, + { "Decode invalid escape code [throw error]", + json.decode, { [[ { "bad escape \q code" } ]] }, + false, { "Expected object key string but found invalid escape code at character 16" } }, + { "Decode invalid unicode escape [throw error]", + json.decode, { [[ { "bad unicode \u0f6 escape" } ]] }, + false, { "Expected object key string but found invalid unicode escape code at character 17" } }, + { "Decode invalid keyword [throw error]", + json.decode, { ' [ "bad barewood", test ] ' }, + false, { "Expected value but found invalid token at character 20" } }, + { "Decode invalid number #1 [throw error]", + json.decode, { '[ -+12 ]' }, + false, { "Expected value but found invalid number at character 3" } }, + { "Decode invalid number #2 [throw error]", + json.decode, { '-v' }, + false, { "Expected value but found invalid number at character 1" } }, + { "Decode invalid number exponent [throw error]", + json.decode, { '[ 0.4eg10 ]' }, + false, { "Expected comma or array end but found invalid token at character 6" } }, + + -- Test decoding nested arrays / objects + { "Set decode_max_depth(5)", + json.decode_max_depth, { 5 }, true, { 5 } }, + { "Decode array at nested limit", + json.decode, { '[[[[[ "nested" ]]]]]' }, + true, { {{{{{ "nested" }}}}} } }, + { "Decode array over nested limit [throw error]", + json.decode, { '[[[[[[ "nested" ]]]]]]' }, + false, { "Found too many nested data structures (6) at character 6" } }, + { "Decode object at nested limit", + json.decode, { '{"a":{"b":{"c":{"d":{"e":"nested"}}}}}' }, + true, { {a={b={c={d={e="nested"}}}}} } }, + { "Decode object over nested limit [throw error]", + json.decode, { '{"a":{"b":{"c":{"d":{"e":{"f":"nested"}}}}}}' }, + false, { "Found too many nested data structures (6) at character 26" } }, + { "Set decode_max_depth(1000)", + json.decode_max_depth, { 1000 }, true, { 1000 } }, + { "Decode deeply nested array [throw error]", + json.decode, { string.rep("[", 1100) .. '1100' .. string.rep("]", 1100)}, + false, { "Found too many nested data structures (1001) at character 1001" } }, + + -- Test encoding nested tables + { "Set encode_max_depth(5)", + json.encode_max_depth, { 5 }, true, { 5 } }, + { "Encode nested table as array at nested limit", + json.encode, { {{{{{"nested"}}}}} }, true, { '[[[[["nested"]]]]]' } }, + { "Encode nested table as array after nested limit [throw error]", + json.encode, { { {{{{{"nested"}}}}} } }, + false, { "Cannot serialise, excessive nesting (6)" } }, + { "Encode nested table as object at nested limit", + json.encode, { {a={b={c={d={e="nested"}}}}} }, + true, { '{"a":{"b":{"c":{"d":{"e":"nested"}}}}}' } }, + { "Encode nested table as object over nested limit [throw error]", + json.encode, { {a={b={c={d={e={f="nested"}}}}}} }, + false, { "Cannot serialise, excessive nesting (6)" } }, + { "Encode table with cycle [throw error]", + json.encode, { testdata.table_cycle }, + false, { "Cannot serialise, excessive nesting (6)" } }, + { "Set encode_max_depth(1000)", + json.encode_max_depth, { 1000 }, true, { 1000 } }, + { "Encode deeply nested data [throw error]", + json.encode, { testdata.deeply_nested_data }, + false, { "Cannot serialise, excessive nesting (1001)" } }, + + -- Test encoding simple types + { "Encode null", + json.encode, { json.null }, true, { 'null' } }, + { "Encode true", + json.encode, { true }, true, { 'true' } }, + { "Encode false", + json.encode, { false }, true, { 'false' } }, + { "Encode empty object", + json.encode, { { } }, true, { '{}' } }, + { "Encode integer", + json.encode, { 10 }, true, { '10' } }, + { "Encode string", + json.encode, { "hello" }, true, { '"hello"' } }, + { "Encode Lua function [throw error]", + json.encode, { function () end }, + false, { "Cannot serialise function: type not supported" } }, + + -- Test decoding invalid numbers + { "Set decode_invalid_numbers(true)", + json.decode_invalid_numbers, { true }, true, { true } }, + { "Decode hexadecimal", + json.decode, { '0x6.ffp1' }, true, { 13.9921875 } }, + { "Decode numbers with leading zero", + json.decode, { '[ 0123, 00.33 ]' }, true, { { 123, 0.33 } } }, + { "Decode +-Inf", + json.decode, { '[ +Inf, Inf, -Inf ]' }, true, { { Inf, Inf, -Inf } } }, + { "Decode +-Infinity", + json.decode, { '[ +Infinity, Infinity, -Infinity ]' }, + true, { { Inf, Inf, -Inf } } }, + { "Decode +-NaN", + json.decode, { '[ +NaN, NaN, -NaN ]' }, true, { { NaN, NaN, NaN } } }, + { "Decode Infrared (not infinity) [throw error]", + json.decode, { 'Infrared' }, + false, { "Expected the end but found invalid token at character 4" } }, + { "Decode Noodle (not NaN) [throw error]", + json.decode, { 'Noodle' }, + false, { "Expected value but found invalid token at character 1" } }, + { "Set decode_invalid_numbers(false)", + json.decode_invalid_numbers, { false }, true, { false } }, + { "Decode hexadecimal [throw error]", + json.decode, { '0x6' }, + false, { "Expected value but found invalid number at character 1" } }, + { "Decode numbers with leading zero [throw error]", + json.decode, { '[ 0123, 00.33 ]' }, + false, { "Expected value but found invalid number at character 3" } }, + { "Decode +-Inf [throw error]", + json.decode, { '[ +Inf, Inf, -Inf ]' }, + false, { "Expected value but found invalid token at character 3" } }, + { "Decode +-Infinity [throw error]", + json.decode, { '[ +Infinity, Infinity, -Infinity ]' }, + false, { "Expected value but found invalid token at character 3" } }, + { "Decode +-NaN [throw error]", + json.decode, { '[ +NaN, NaN, -NaN ]' }, + false, { "Expected value but found invalid token at character 3" } }, + { 'Set decode_invalid_numbers("on")', + json.decode_invalid_numbers, { "on" }, true, { true } }, + + -- Test encoding invalid numbers + { "Set encode_invalid_numbers(false)", + json.encode_invalid_numbers, { false }, true, { false } }, + { "Encode NaN [throw error]", + json.encode, { NaN }, + false, { "Cannot serialise number: must not be NaN or Infinity" } }, + { "Encode Infinity [throw error]", + json.encode, { Inf }, + false, { "Cannot serialise number: must not be NaN or Infinity" } }, + { "Set encode_invalid_numbers(\"null\")", + json.encode_invalid_numbers, { "null" }, true, { "null" } }, + { "Encode NaN as null", + json.encode, { NaN }, true, { "null" } }, + { "Encode Infinity as null", + json.encode, { Inf }, true, { "null" } }, + { "Set encode_invalid_numbers(true)", + json.encode_invalid_numbers, { true }, true, { true } }, + { "Encode NaN", + json.encode, { NaN }, true, { "NaN" } }, + { "Encode +Infinity", + json.encode, { Inf }, true, { "Infinity" } }, + { "Encode -Infinity", + json.encode, { -Inf }, true, { "-Infinity" } }, + { 'Set encode_invalid_numbers("off")', + json.encode_invalid_numbers, { "off" }, true, { false } }, + + -- Test encoding tables + { "Set encode_sparse_array(true, 2, 3)", + json.encode_sparse_array, { true, 2, 3 }, true, { true, 2, 3 } }, + { "Encode sparse table as array #1", + json.encode, { { [3] = "sparse test" } }, + true, { '[null,null,"sparse test"]' } }, + { "Encode sparse table as array #2", + json.encode, { { [1] = "one", [4] = "sparse test" } }, + true, { '["one",null,null,"sparse test"]' } }, + { "Encode sparse array as object", + json.encode, { { [1] = "one", [5] = "sparse test" } }, + true, { '{"1":"one","5":"sparse test"}' } }, + { "Encode table with numeric string key as object", + json.encode, { { ["2"] = "numeric string key test" } }, + true, { '{"2":"numeric string key test"}' } }, + { "Set encode_sparse_array(false)", + json.encode_sparse_array, { false }, true, { false, 2, 3 } }, + { "Encode table with incompatible key [throw error]", + json.encode, { { [false] = "wrong" } }, + false, { "Cannot serialise boolean: table key must be a number or string" } }, + + -- Test escaping + { "Encode all octets (8-bit clean)", + json.encode, { testdata.octets_raw }, true, { testdata.octets_escaped } }, + { "Decode all escaped octets", + json.decode, { testdata.octets_escaped }, true, { testdata.octets_raw } }, + { "Decode single UTF-16 escape", + json.decode, { [["\uF800"]] }, true, { "\239\160\128" } }, + { "Decode all UTF-16 escapes (including surrogate combinations)", + json.decode, { testdata.utf16_escaped }, true, { testdata.utf8_raw } }, + { "Decode swapped surrogate pair [throw error]", + json.decode, { [["\uDC00\uD800"]] }, + false, { "Expected value but found invalid unicode escape code at character 2" } }, + { "Decode duplicate high surrogate [throw error]", + json.decode, { [["\uDB00\uDB00"]] }, + false, { "Expected value but found invalid unicode escape code at character 2" } }, + { "Decode duplicate low surrogate [throw error]", + json.decode, { [["\uDB00\uDB00"]] }, + false, { "Expected value but found invalid unicode escape code at character 2" } }, + { "Decode missing low surrogate [throw error]", + json.decode, { [["\uDB00"]] }, + false, { "Expected value but found invalid unicode escape code at character 2" } }, + { "Decode invalid low surrogate [throw error]", + json.decode, { [["\uDB00\uD"]] }, + false, { "Expected value but found invalid unicode escape code at character 2" } }, + + -- Test locale support + -- + -- The standard Lua interpreter is ANSI C online doesn't support locales + -- by default. Force a known problematic locale to test strtod()/sprintf(). + { "Set locale to cs_CZ (comma separator)", function () + os.setlocale("cs_CZ") + json.new() + end }, + { "Encode number under comma locale", + json.encode, { 1.5 }, true, { '1.5' } }, + { "Decode number in array under comma locale", + json.decode, { '[ 10, "test" ]' }, true, { { 10, "test" } } }, + { "Revert locale to POSIX", function () + os.setlocale("C") + json.new() + end }, + + -- Test encode_keep_buffer() and enable_number_precision() + { "Set encode_keep_buffer(false)", + json.encode_keep_buffer, { false }, true, { false } }, + { "Set encode_number_precision(3)", + json.encode_number_precision, { 3 }, true, { 3 } }, + { "Encode number with precision 3", + json.encode, { 1/3 }, true, { "0.333" } }, + { "Set encode_number_precision(14)", + json.encode_number_precision, { 14 }, true, { 14 } }, + { "Set encode_keep_buffer(true)", + json.encode_keep_buffer, { true }, true, { true } }, + + -- Test config API errors + -- Function is listed as '?' due to pcall + { "Set encode_number_precision(0) [throw error]", + json.encode_number_precision, { 0 }, + false, { "bad argument #1 to '?' (expected integer between 1 and 14)" } }, + { "Set encode_number_precision(\"five\") [throw error]", + json.encode_number_precision, { "five" }, + false, { "bad argument #1 to '?' (number expected, got string)" } }, + { "Set encode_keep_buffer(nil, true) [throw error]", + json.encode_keep_buffer, { nil, true }, + false, { "bad argument #2 to '?' (found too many arguments)" } }, + { "Set encode_max_depth(\"wrong\") [throw error]", + json.encode_max_depth, { "wrong" }, + false, { "bad argument #1 to '?' (number expected, got string)" } }, + { "Set decode_max_depth(0) [throw error]", + json.decode_max_depth, { "0" }, + false, { "bad argument #1 to '?' (expected integer between 1 and 2147483647)" } }, + { "Set encode_invalid_numbers(-2) [throw error]", + json.encode_invalid_numbers, { -2 }, + false, { "bad argument #1 to '?' (invalid option '-2')" } }, + { "Set decode_invalid_numbers(true, false) [throw error]", + json.decode_invalid_numbers, { true, false }, + false, { "bad argument #2 to '?' (found too many arguments)" } }, + { "Set encode_sparse_array(\"not quite on\") [throw error]", + json.encode_sparse_array, { "not quite on" }, + false, { "bad argument #1 to '?' (invalid option 'not quite on')" } }, + + { "Reset Lua CJSON configuration", function () json = json.new() end }, + -- Wrap in a function to ensure the table returned by json.new() is used + { "Check encode_sparse_array()", + function (...) return json.encode_sparse_array(...) end, { }, + true, { false, 2, 10 } }, + + { "Encode (safe) simple value", + json_safe.encode, { true }, + true, { "true" } }, + { "Encode (safe) argument validation [throw error]", + json_safe.encode, { "arg1", "arg2" }, + false, { "bad argument #1 to '?' (expected 1 argument)" } }, + { "Decode (safe) error generation", + json_safe.decode, { "Oops" }, + true, { nil, "Expected value but found invalid token at character 1" } }, + { "Decode (safe) error generation after new()", + function(...) return json_safe.new().decode(...) end, { "Oops" }, + true, { nil, "Expected value but found invalid token at character 1" } }, +} + +print(("==> Testing Lua CJSON version %s\n"):format(json._VERSION)) + +util.run_test_group(cjson_tests) + +for _, filename in ipairs(arg) do + util.run_test("Decode cycle " .. filename, test_decode_cycle, { filename }, + true, { true }) +end + +local pass, total = util.run_test_summary() + +if pass == total then + print("==> Summary: all tests succeeded") +else + print(("==> Summary: %d/%d tests failed"):format(total - pass, total)) + os.exit(1) +end + +-- vi:ai et sw=4 ts=4: diff --git a/luaclib/cjson/tests/types.json b/luaclib/cjson/tests/types.json new file mode 100644 index 0000000..c01e7d2 --- /dev/null +++ b/luaclib/cjson/tests/types.json @@ -0,0 +1 @@ +{ "array": [ 10, true, null ] } diff --git a/luaclib/lfs.dll b/luaclib/lfs.dll new file mode 100644 index 0000000000000000000000000000000000000000..8bcdf7c2cfb8763f061d9b24482e593e1596cea2 GIT binary patch literal 44032 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 R>?n&OgP%bS{L?k?{{cE4|2qHx literal 0 HcmV?d00001 diff --git a/luaclib/lfs/.travis/._platform.sh b/luaclib/lfs/.travis/._platform.sh new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/.travis/._setup_lua.sh b/luaclib/lfs/.travis/._setup_lua.sh new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/.travis/platform.sh b/luaclib/lfs/.travis/platform.sh new file mode 100644 index 0000000..4a3af0d --- /dev/null +++ b/luaclib/lfs/.travis/platform.sh @@ -0,0 +1,15 @@ +if [ -z "$PLATFORM" ]; then + PLATFORM=$TRAVIS_OS_NAME; +fi + +if [ "$PLATFORM" == "osx" ]; then + PLATFORM="macosx"; +fi + +if [ -z "$PLATFORM" ]; then + if [ "$(uname)" == "Linux" ]; then + PLATFORM="linux"; + else + PLATFORM="macosx"; + fi; +fi diff --git a/luaclib/lfs/.travis/setup_lua.sh b/luaclib/lfs/.travis/setup_lua.sh new file mode 100644 index 0000000..373e24d --- /dev/null +++ b/luaclib/lfs/.travis/setup_lua.sh @@ -0,0 +1,101 @@ +#! /bin/bash + +# A script for setting up environment for travis-ci testing. +# Sets up Lua and Luarocks. +# LUA must be "lua5.1", "lua5.2" or "luajit". +# luajit2.0 - master v2.0 +# luajit2.1 - master v2.1 + +LUAJIT_BASE="LuaJIT-2.0.3" + +source .travis/platform.sh + +LUAJIT="no" + +if [ "$PLATFORM" == "macosx" ]; then + if [ "$LUA" == "luajit" ]; then + LUAJIT="yes"; + fi + if [ "$LUA" == "luajit2.0" ]; then + LUAJIT="yes"; + fi + if [ "$LUA" == "luajit2.1" ]; then + LUAJIT="yes"; + fi; +elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then + LUAJIT="yes"; +fi + +if [ "$LUAJIT" == "yes" ]; then + + if [ "$LUA" == "luajit" ]; then + curl http://luajit.org/download/$LUAJIT_BASE.tar.gz | tar xz; + else + git clone http://luajit.org/git/luajit-2.0.git $LUAJIT_BASE; + fi + + cd $LUAJIT_BASE + + if [ "$LUA" == "luajit2.1" ]; then + git checkout v2.1; + fi + + make && sudo make install + + if [ "$LUA" == "luajit2.1" ]; then + sudo ln -s /usr/local/bin/luajit-2.1.0-alpha /usr/local/bin/luajit + sudo ln -s /usr/local/bin/luajit /usr/local/bin/lua; + else + sudo ln -s /usr/local/bin/luajit /usr/local/bin/lua; + fi; + +else + if [ "$LUA" == "lua5.1" ]; then + curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz + cd lua-5.1.5; + elif [ "$LUA" == "lua5.2" ]; then + curl http://www.lua.org/ftp/lua-5.2.3.tar.gz | tar xz + cd lua-5.2.3; + elif [ "$LUA" == "lua5.3" ]; then + curl http://www.lua.org/work/lua-5.3.0-beta.tar.gz | tar xz + cd lua-5.3.0-beta; + fi + sudo make $PLATFORM install; +fi + +cd $TRAVIS_BUILD_DIR; + +LUAROCKS_BASE=luarocks-$LUAROCKS + +# curl http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz + +git clone https://github.com/keplerproject/luarocks.git $LUAROCKS_BASE +cd $LUAROCKS_BASE + +git checkout v$LUAROCKS + +if [ "$LUA" == "luajit" ]; then + ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0; +elif [ "$LUA" == "luajit2.0" ]; then + ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0; +elif [ "$LUA" == "luajit2.1" ]; then + ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.1; +else + ./configure; +fi + +make build && sudo make install + +cd $TRAVIS_BUILD_DIR + +rm -rf $LUAROCKS_BASE + +if [ "$LUAJIT" == "yes" ]; then + rm -rf $LUAJIT_BASE; +elif [ "$LUA" == "lua5.1" ]; then + rm -rf lua-5.1.5; +elif [ "$LUA" == "lua5.2" ]; then + rm -rf lua-5.2.3; +elif [ "$LUA" == "lua5.3" ]; then + rm -rf lua-5.3.0-beta; +fi diff --git a/luaclib/lfs/LICENSE b/luaclib/lfs/LICENSE new file mode 100644 index 0000000..8475345 --- /dev/null +++ b/luaclib/lfs/LICENSE @@ -0,0 +1,21 @@ +Copyright © 2003-2014 Kepler Project. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/luaclib/lfs/Makefile b/luaclib/lfs/Makefile new file mode 100644 index 0000000..b1ba450 --- /dev/null +++ b/luaclib/lfs/Makefile @@ -0,0 +1,54 @@ +LFS_VERSION = 1.6.3 +LUA_VERSION = 5.1 +TARGET = lfs.so + +# See https://github.com/keplerproject/luafilesystem for platform specific +# details. + +## Linux/BSD +PREFIX ?= /usr/local +LDFLAGS += -shared + +## OSX (Macports) +#PREFIX ?= /opt/local +#LDFLAGS += -bundle -undefined dynamic_lookup + +#added by xdczju@sina.com +ifeq ($(OS),Windows_NT) + TARGET = lfs.dll + LDFLAGS2 += -lluajit51 +endif + +LUA_INCLUDE_DIR ?= $(PREFIX)/include +LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION) + +# Some versions of Solaris are missing isinf(). Add -DMISSING_ISINF to +# CFLAGS to work around this bug. + +#CFLAGS ?= -g -Wall -pedantic -fno-inline +CFLAGS ?= -g -O3 -Wall -pedantic +override CFLAGS += -fpic -I$(LUA_INCLUDE_DIR) -DVERSION=\"$(LFS_VERSION)\" + +INSTALL ?= install + +.PHONY: all clean install package + +all: $(TARGET) + +$(TARGET): lfs.o + $(CC) $(LDFLAGS) -o $@ $^ $(LDFLAGS2) + +install: + $(INSTALL) -d $(DESTDIR)/$(LUA_LIB_DIR) + $(INSTALL) $(TARGET) $(DESTDIR)/$(LUA_LIB_DIR) + +clean: + rm -f *.o *.so + +package: + git archive --prefix="lua-lfs-$(LFS_VERSION)/" master | \ + gzip -9 > "lua-lfs-$(LFS_VERSION).tar.gz" + git archive --prefix="lua-lfs-$(LFS_VERSION)/" \ + -o "lua-lfs-$(LFS_VERSION).zip" master + + diff --git a/luaclib/lfs/Makefile.bak b/luaclib/lfs/Makefile.bak new file mode 100644 index 0000000..b834a4d --- /dev/null +++ b/luaclib/lfs/Makefile.bak @@ -0,0 +1,25 @@ +# $Id: Makefile,v 1.36 2009/09/21 17:02:44 mascarenhas Exp $ + +T= lfs + +CONFIG= ./config + +include $(CONFIG) + +SRCS= src/$T.c +OBJS= src/$T.o + +lib: src/lfs.so + +src/lfs.so: $(OBJS) + MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/lfs.so $(OBJS) + +test: lib + LUA_CPATH=./src/?.so lua tests/test.lua + +install: + mkdir -p $(LUA_LIBDIR) + cp src/lfs.so $(LUA_LIBDIR) + +clean: + rm -f src/lfs.so $(OBJS) diff --git a/luaclib/lfs/Makefile.win b/luaclib/lfs/Makefile.win new file mode 100644 index 0000000..65cab81 --- /dev/null +++ b/luaclib/lfs/Makefile.win @@ -0,0 +1,25 @@ +# $Id: Makefile.win,v 1.11 2008/05/07 19:06:37 carregal Exp $ + +T= lfs + +include config.win + +SRCS= src\$T.c +OBJS= src\$T.obj + +lib: src\lfs.dll + +.c.obj: + $(CC) /c /Fo$@ $(CFLAGS) $< + +src\lfs.dll: $(OBJS) + link /dll /def:src\$T.def /out:src\lfs.dll $(OBJS) "$(LUA_LIB)" + IF EXIST src\lfs.dll.manifest mt -manifest src\lfs.dll.manifest -outputresource:src\lfs.dll;2 + +install: src\lfs.dll + IF NOT EXIST "$(LUA_LIBDIR)" mkdir "$(LUA_LIBDIR)" + copy src\lfs.dll "$(LUA_LIBDIR)" + +clean: + del src\lfs.dll $(OBJS) src\$T.lib src\$T.exp + IF EXIST src\lfs.dll.manifest del src\lfs.dll.manifest \ No newline at end of file diff --git a/luaclib/lfs/README b/luaclib/lfs/README new file mode 100644 index 0000000..005c38e --- /dev/null +++ b/luaclib/lfs/README @@ -0,0 +1,82 @@ +LuaFileSystem - File System Library for Lua +Copyright 2003 Kepler Project +http://www.keplerproject.org/luafilesystem + +Description +----------- +LuaFileSystem is a Lua library developed to complement the set of functions +related to file systems offered by the standard Lua distribution. + +LuaFileSystem offers a portable way to access the underlying directory structure and file attributes. +LuaFileSystem is free software and uses the same license as Lua 5.1 + +LuaRocks Installation +--------------------- +luarocks install luafilesystem + + +Documentation +------------- +Please check the documentation at doc/us/ for more information. + +History +------- + +Version 1.6.3 [15/Jan/2012] + * Lua 5.3 compatibility + * Assorted bugfixes + +Version 1.6.2 [??/Oct/2012] + * Full Lua 5.2 compatibility (with Lua 5.1 fallbacks) + +Version 1.6.1 [01/Oct/2012] + * fix build for Lua 5.2 + +Version 1.6.0 [26/Sep/2012] + * getcwd fix for Android + * support for Lua 5.2 + * add lfs.link + * other bug fixes + +Version 1.5.0 [20/Oct/2009] + * added explicit next and close methods to second return value of lfs.dir (the directory object), for explicit iteration or explicit closing. + * added directory locking via lfs.lock_dir function (see the manual). + +Version 1.4.2 [03/Feb/2009] + + * fixed bug [#13198] lfs.attributes(filename, 'size') overflow on files > 2 Gb again (bug report and patch by KUBO Takehiro). + * fixed bug [#39794] Compile error on Solaris 10 (bug report and patch by Aaron B). + * fixed compilation problems with Borland C. + +Version 1.4.1 [07/May/2008] + + * documentation review + * fixed Windows compilation issues + * fixed bug in the Windows tests (patch by Shmuel Zeigerman) + * fixed bug [#2185] lfs.attributes(filename, 'size') overflow on files > 2 Gb + +Version 1.4.0 [13/Feb/2008] + + * added function lfs.setmode (works only in Windows systems). + * lfs.attributes raises an error if attribute does not exist + +Version 1.3.0 [26/Oct/2007] + + * added function lfs.symlinkattributes (works only in non Windows systems). + +Version 1.2.1 [08/May/2007] + + * compatible only with Lua 5.1 (Lua 5.0 support was dropped) + +Version 1.2 [15/Mar/2006] + + * added optional argument to lfs.attributes + * added function lfs.rmdir + * bug correction on lfs.dir + +Version 1.1 [30/May/2005] + + * added function lfs.touch. + +Version 1.0 [21/Jan/2005] +Version 1.0 Beta [10/Nov/2004] diff --git a/luaclib/lfs/config b/luaclib/lfs/config new file mode 100644 index 0000000..cfd4c6a --- /dev/null +++ b/luaclib/lfs/config @@ -0,0 +1,24 @@ +# Installation directories + +# Default installation prefix +PREFIX=/usr/local + +# System's libraries directory (where binary libraries are installed) +LUA_LIBDIR= $(PREFIX)/lib/lua/5.1 + +# Lua includes directory +LUA_INC= $(PREFIX)/include + +# OS dependent +LIB_OPTION= -shared #for Linux +#LIB_OPTION= -bundle -undefined dynamic_lookup #for MacOS X + +LIBNAME= $T.so.$V + +# Compilation directives +WARN= -O2 -Wall -fPIC -W -Waggregate-return -Wcast-align -Wmissing-prototypes -Wnested-externs -Wshadow -Wwrite-strings -pedantic +INCS= -I$(LUA_INC) +CFLAGS= $(WARN) $(INCS) +CC= gcc + +# $Id: config,v 1.21 2007/10/27 22:42:32 carregal Exp $ diff --git a/luaclib/lfs/config.win b/luaclib/lfs/config.win new file mode 100644 index 0000000..50e81f6 --- /dev/null +++ b/luaclib/lfs/config.win @@ -0,0 +1,19 @@ +# Installation directories +# System's libraries directory (where binary libraries are installed) +LUA_LIBDIR= "c:\lua5.1" + +# Lua includes directory +LUA_INC= "c:\lua5.1\include" + +# Lua library +LUA_LIB= "c:\lua5.1\lua5.1.lib" + +LIBNAME= $T.dll + +# Compilation directives +WARN= /O2 +INCS= /I$(LUA_INC) +CFLAGS= /MD $(WARN) $(INCS) +CC= cl + +# $Id: config.win,v 1.7 2008/03/25 17:39:29 mascarenhas Exp $ diff --git a/luaclib/lfs/doc/._us b/luaclib/lfs/doc/._us new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/doc/us/._doc.css b/luaclib/lfs/doc/us/._doc.css new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/doc/us/._examples.html b/luaclib/lfs/doc/us/._examples.html new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/doc/us/._index.html b/luaclib/lfs/doc/us/._index.html new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/doc/us/._license.html b/luaclib/lfs/doc/us/._license.html new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/doc/us/._luafilesystem.png b/luaclib/lfs/doc/us/._luafilesystem.png new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/doc/us/._manual.html b/luaclib/lfs/doc/us/._manual.html new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/doc/us/doc.css b/luaclib/lfs/doc/us/doc.css new file mode 100644 index 0000000..e816a7e --- /dev/null +++ b/luaclib/lfs/doc/us/doc.css @@ -0,0 +1,212 @@ +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color:#ffffff; margin:0px; +} + +code { + font-family: "Andale Mono", monospace; +} + +tt { + font-family: "Andale Mono", monospace; +} + +body, td, th { font-size: 11pt; } + +h1, h2, h3, h4 { margin-left: 0em; } + +textarea, pre, tt { font-size:10pt; } +body, td, th { color:#000000; } +small { font-size:0.85em; } +h1 { font-size:1.5em; } +h2 { font-size:1.25em; } +h3 { font-size:1.15em; } +h4 { font-size:1.06em; } + +a:link { font-weight:bold; color: #004080; text-decoration: none; } +a:visited { font-weight:bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration:underline; } +hr { color:#cccccc } +img { border-width: 0px; } + +h3 { padding-top: 1em; } + +p { margin-left: 1em; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; + margin-left: 0em; +} + +blockquote { margin-left: 3em; } + +.example { + background-color: rgb(245, 245, 245); + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-style: solid; + border-right-style: solid; + border-bottom-style: solid; + border-left-style: solid; + border-top-color: silver; + border-right-color: silver; + border-bottom-color: silver; + border-left-color: silver; + padding: 1em; + margin-left: 1em; + margin-right: 1em; + font-family: "Andale Mono", monospace; + font-size: smaller; +} + +hr { + margin-left: 0em; + background: #00007f; + border: 0px; + height: 1px; +} + +ul { list-style-type: disc; } + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } +table.index ul { padding-top: 0em; margin-top: 0em; } + +table { + border: 1px solid black; + border-collapse: collapse; + margin-left: auto; + margin-right: auto; +} + +th { + border: 1px solid black; + padding: 0.5em; +} + +td { + border: 1px solid black; + padding: 0.5em; +} +div.header, div.footer { margin-left: 0em; } + +#container { + margin-left: 1em; + margin-right: 1em; + background-color: #f0f0f0; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#product_logo { +} + +#product_name { +} + +#product_description { +} + +#main { + background-color: #f0f0f0; + border-left: 2px solid #cccccc; +} + +#navigation { + float: left; + width: 12em; + margin: 0; + vertical-align: top; + background-color: #f0f0f0; + overflow:visible; +} + +#navigation h1 { + background-color:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align:left; + margin:0px; + padding:0.2em; + border-top:1px solid #dddddd; + border-bottom:1px solid #dddddd; +} + +#navigation ul { + font-size:1em; + list-style-type: none; + padding: 0; + margin: 1px; +} + +#navigation li { + text-indent: -1em; + margin: 0em 0em 0em 0.5em; + display: block; + padding: 3px 0px 0px 12px; +} + +#navigation li li a { + padding: 0px 3px 0px -1em; +} + +#content { + margin-left: 12em; + padding: 1em; + border-left: 2px solid #cccccc; + border-right: 2px solid #cccccc; + background-color: #ffffff; +} + +#about { + clear: both; + margin: 0; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 10pt "Times New Roman", "TimeNR", Times, serif; + } + a { + font-weight:bold; color: #004080; text-decoration: underline; + } + #main { + background-color: #ffffff; border-left: 0px; + } + #container { + margin-left: 2%; margin-right: 2%; background-color: #ffffff; + } + #content { + margin-left: 0px; padding: 1em; border-left: 0px; border-right: 0px; background-color: #ffffff; + } + #navigation { + display: none; + } + #product_logo { + display: none; + } + #about img { + display: none; + } + .example { + font-family: "Andale Mono", monospace; + font-size: 8pt; + page-break-inside: avoid; + } +} diff --git a/luaclib/lfs/doc/us/examples.html b/luaclib/lfs/doc/us/examples.html new file mode 100644 index 0000000..2c1644c --- /dev/null +++ b/luaclib/lfs/doc/us/examples.html @@ -0,0 +1,103 @@ + + + + LuaFileSystem + + + + + + +

+ +
+ +
LuaFileSystem
+
File System Library for the Lua Programming Language
+
+ +
+ + + +
+ +

Examples

+ +

Directory iterator

+ +

The following example iterates over a directory and recursively lists the +attributes for each file inside it.

+ +
+local lfs = require"lfs"
+
+function attrdir (path)
+    for file in lfs.dir(path) do
+        if file ~= "." and file ~= ".." then
+            local f = path..'/'..file
+            print ("\t "..f)
+            local attr = lfs.attributes (f)
+            assert (type(attr) == "table")
+            if attr.mode == "directory" then
+                attrdir (f)
+            else
+                for name, value in pairs(attr) do
+                    print (name, value)
+                end
+            end
+        end
+    end
+end
+
+attrdir (".")
+
+ +
+ +
+ +
+

Valid XHTML 1.0!

+

$Id: examples.html,v 1.8 2007/12/14 15:28:04 carregal Exp $

+
+ +
+ + + diff --git a/luaclib/lfs/doc/us/index.html b/luaclib/lfs/doc/us/index.html new file mode 100644 index 0000000..2bb7f5d --- /dev/null +++ b/luaclib/lfs/doc/us/index.html @@ -0,0 +1,218 @@ + + + + LuaFileSystem + + + + + + +
+ +
+ +
LuaFileSystem
+
File System Library for the Lua Programming Language
+
+ +
+ + + +
+ +

Overview

+ +

LuaFileSystem is a Lua library +developed to complement the set of functions related to file +systems offered by the standard Lua distribution.

+ +

LuaFileSystem offers a portable way to access +the underlying directory structure and file attributes.

+ +

LuaFileSystem is free software and uses the same +license as Lua 5.1.

+ +

Status

+ +

Current version is 1.6.3. It works with Lua 5.1, 5.2 and 5.3.

+ +

Download

+ +

LuaFileSystem source can be downloaded from its +Github +page.

+ +

History

+ +
+
Version 1.6.3 [15/Jan/2015]
+
    +
  • Lua 5.3 support.
  • +
  • Assorted bugfixes.
  • +
+ +
Version 1.6.2 [??/Oct/2012]
+
    +
  • Full Lua 5.2 compatibility (with Lua 5.1 fallbacks)
  • +
+ +
Version 1.6.1 [01/Oct/2012]
+
    +
  • fix build for Lua 5.2
  • +
+ +
Version 1.6.0 [26/Sep/2012]
+
    +
  • getcwd fix for Android
  • +
  • support for Lua 5.2
  • +
  • add lfs.link
  • +
  • other bug fixes
  • +
+ +
Version 1.5.0 [20/Oct/2009]
+
    +
  • Added explicit next and close methods to second return value of lfs.dir +(the directory object), for explicit iteration or explicit closing.
  • +
  • Added directory locking via lfs.lock_dir function (see the manual).
  • +
+
Version 1.4.2 [03/Feb/2009]
+
+
    +
  • fixed bug [#13198] + lfs.attributes(filename, 'size') overflow on files > 2 Gb again (bug report and patch by KUBO Takehiro).
  • +
  • fixed bug [#39794] + Compile error on Solaris 10 (bug report and patch by Aaron B).
  • +
  • fixed compilation problems with Borland C.
  • +
+
+ +
Version 1.4.1 [07/May/2008]
+
+
    +
  • documentation review
  • +
  • fixed Windows compilation issues
  • +
  • fixed bug in the Windows tests (patch by Shmuel Zeigerman)
  • +
  • fixed bug [#2185] + lfs.attributes(filename, 'size') overflow on files > 2 Gb +
  • +
+
+ +
Version 1.4.0 [13/Feb/2008]
+
+
    +
  • added function + lfs.setmode + (works only in Windows systems).
  • +
  • lfs.attributes + raises an error if attribute does not exist
  • +
+
+ +
Version 1.3.0 [26/Oct/2007]
+
+ +
+ +
Version 1.2.1 [08/May/2007]
+
+
    +
  • compatible only with Lua 5.1 (Lua 5.0 support was dropped)
  • +
+
+ +
Version 1.2 [15/Mar/2006]
+
+ +
+ +
Version 1.1 [30/May/2005]
+
+ +
+ +
Version 1.0 [21/Jan/2005]
+
+ +
Version 1.0 Beta [10/Nov/2004]
+
+
+ +

Credits

+ +

LuaFileSystem was designed by Roberto Ierusalimschy, +André Carregal and Tomás Guisasola as part of the +Kepler Project, +which holds its copyright. LuaFileSystem is currently maintained by Fábio Mascarenhas.

+ +

Contact us

+ +

For more information please +contact us. +Comments are welcome!

+ +

You can also reach other Kepler developers and users on the Kepler Project +mailing list.

+ +
+ +
+ +
+

Valid XHTML 1.0!

+

$Id: index.html,v 1.44 2009/02/04 21:21:33 carregal Exp $

+
+ +
+ + + diff --git a/luaclib/lfs/doc/us/license.html b/luaclib/lfs/doc/us/license.html new file mode 100644 index 0000000..3003381 --- /dev/null +++ b/luaclib/lfs/doc/us/license.html @@ -0,0 +1,122 @@ + + + + LuaFileSystem + + + + + + +
+ +
+ +
LuaFileSystem
+
File System Library for the Lua Programming Language
+
+ +
+ + + +
+ +

License

+ +

+LuaFileSystem is free software: it can be used for both academic +and commercial purposes at absolutely no cost. There are no +royalties or GNU-like "copyleft" restrictions. LuaFileSystem +qualifies as +Open Source +software. +Its licenses are compatible with +GPL. +LuaFileSystem is not in the public domain and the +Kepler Project +keep its copyright. +The legal details are below. +

+ +

The spirit of the license is that you are free to use +LuaFileSystem for any purpose at no cost without having to ask us. +The only requirement is that if you do use LuaFileSystem, then you +should give us credit by including the appropriate copyright notice +somewhere in your product or its documentation.

+ +

The LuaFileSystem library is designed and implemented by Roberto +Ierusalimschy, André Carregal and Tomás Guisasola. +The implementation is not derived from licensed software.

+ +
+

Copyright © 2003 Kepler Project.

+ +

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

+ +

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

+ +

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

+ +
+ +
+ +
+

Valid XHTML 1.0!

+

$Id: license.html,v 1.13 2008/02/11 22:42:21 carregal Exp $

+
+ +
+ + + diff --git a/luaclib/lfs/doc/us/luafilesystem.png b/luaclib/lfs/doc/us/luafilesystem.png new file mode 100644 index 0000000000000000000000000000000000000000..e1dd8c65b5211ba5dd37f2e86da987fdd517d6c6 GIT binary patch literal 8535 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 + + + LuaFileSystem + + + + + + +
+ +
+ +
LuaFileSystem
+
File System Library for the Lua Programming Language
+
+ +
+ + + +
+ +

Introduction

+ +

LuaFileSystem is a Lua library +developed to complement the set of functions related to file +systems offered by the standard Lua distribution.

+ +

LuaFileSystem offers a portable way to access +the underlying directory structure and file attributes.

+ +

Building

+ +

+LuaFileSystem should be built with Lua 5.1 so the language library +and header files for the target version must be installed properly. +

+ +

+LuaFileSystem offers a Makefile and a separate configuration file, +config, +which should be edited to suit your installation before running +make. +The file has some definitions like paths to the external libraries, +compiler options and the like. +

+ +

On Windows, the C runtime used to compile LuaFileSystem must be the same +runtime that Lua uses, or some LuaFileSystem functions will not work.

+ +

Installation

+ +

The easiest way to install LuaFileSystem is to use LuaRocks:

+ +
+luarocks install luafilesystem
+
+ +

If you prefer to install LuaFileSystem manually, the compiled binary should be copied to a directory in your +C path.

+ +

Reference

+ +

+LuaFileSystem offers the following functions: +

+ +
+
lfs.attributes (filepath [, aname])
+
Returns a table with the file attributes corresponding to + filepath (or nil followed by an error message + in case of error). + If the second optional argument is given, then only the value of the + named attribute is returned (this use is equivalent to + lfs.attributes(filepath).aname, but the table is not created + and only one attribute is retrieved from the O.S.). + The attributes are described as follows; + attribute mode is a string, all the others are numbers, + and the time related attributes use the same time reference of + os.time: +
+
dev
+
on Unix systems, this represents the device that the inode resides on. On Windows systems, + represents the drive number of the disk containing the file
+ +
ino
+
on Unix systems, this represents the inode number. On Windows systems this has no meaning
+ +
mode
+
string representing the associated protection mode (the values could be + file, directory, link, socket, + named pipe, char device, block device or + other)
+ +
nlink
+
number of hard links to the file
+ +
uid
+
user-id of owner (Unix only, always 0 on Windows)
+ +
gid
+
group-id of owner (Unix only, always 0 on Windows)
+ +
rdev
+
on Unix systems, represents the device type, for special file inodes. + On Windows systems represents the same as dev
+ +
access
+
time of last access
+ +
modification
+
time of last data modification
+ +
change
+
time of last file status change
+ +
size
+
file size, in bytes
+ +
blocks
+
block allocated for file; (Unix only)
+ +
blksize
+
optimal file system I/O blocksize; (Unix only)
+
+ This function uses stat internally thus if the given + filepath is a symbolic link, it is followed (if it points to + another link the chain is followed recursively) and the information + is about the file it refers to. + To obtain information about the link itself, see function + lfs.symlinkattributes. +
+ +
lfs.chdir (path)
+
Changes the current working directory to the given + path.
+ Returns true in case of success or nil plus an + error string.
+ +
lfs.lock_dir(path, [seconds_stale])
+
Creates a lockfile (called lockfile.lfs) in path if it does not + exist and returns the lock. If the lock already exists checks if + it's stale, using the second parameter (default for the second + parameter is INT_MAX, which in practice means the lock will never + be stale. To free the the lock call lock:free().
+ In case of any errors it returns nil and the error message. In + particular, if the lock exists and is not stale it returns the + "File exists" message.
+ +
lfs.currentdir ()
+
Returns a string with the current working directory or nil + plus an error string.
+ +
iter, dir_obj = lfs.dir (path)
+
+ Lua iterator over the entries of a given directory. + Each time the iterator is called with dir_obj it returns a directory entry's name as a string, or + nil if there are no more entries. You can also iterate by calling dir_obj:next(), and + explicitly close the directory before the iteration finished with dir_obj:close(). + Raises an error if path is not a directory. +
+ +
lfs.lock (filehandle, mode[, start[, length]])
+
Locks a file or a part of it. This function works on open files; the + file handle should be specified as the first argument. + The string mode could be either + r (for a read/shared lock) or w (for a + write/exclusive lock). The optional arguments start + and length can be used to specify a starting point and + its length; both should be numbers.
+ Returns true if the operation was successful; in + case of error, it returns nil plus an error string. +
+ +
lfs.link (old, new[, symlink])
+
Creates a link. The first argument is the object to link to + and the second is the name of the link. If the optional third + argument is true, the link will by a symbolic link (by default, a + hard link is created). +
+ +
lfs.mkdir (dirname)
+
Creates a new directory. The argument is the name of the new + directory.
+ Returns true if the operation was successful; + in case of error, it returns nil plus an error string. +
+ +
lfs.rmdir (dirname)
+
Removes an existing directory. The argument is the name of the directory.
+ Returns true if the operation was successful; + in case of error, it returns nil plus an error string.
+ +
lfs.setmode (file, mode)
+
Sets the writing mode for a file. The mode string can be either "binary" or "text". + Returns true followed the previous mode string for the file, or + nil followed by an error string in case of errors. + On non-Windows platforms, where the two modes are identical, + setting the mode has no effect, and the mode is always returned as binary. +
+ +
lfs.symlinkattributes (filepath [, aname])
+
Identical to lfs.attributes except that + it obtains information about the link itself (not the file it refers to). + On Windows this function does not yet support links, and is identical to + lfs.attributes. +
+ +
lfs.touch (filepath [, atime [, mtime]])
+
Set access and modification times of a file. This function is + a bind to utime function. The first argument is the + filename, the second argument (atime) is the access time, + and the third argument (mtime) is the modification time. + Both times are provided in seconds (which should be generated with + Lua standard function os.time). + If the modification time is omitted, the access time provided is used; + if both times are omitted, the current time is used.
+ Returns true if the operation was successful; + in case of error, it returns nil plus an error string. +
+ +
lfs.unlock (filehandle[, start[, length]])
+
Unlocks a file or a part of it. This function works on + open files; the file handle should be specified as the first + argument. The optional arguments start and + length can be used to specify a starting point and its + length; both should be numbers.
+ Returns true if the operation was successful; + in case of error, it returns nil plus an error string. +
+
+ +
+ +
+ +
+

Valid XHTML 1.0!

+

$Id: manual.html,v 1.45 2009/06/03 20:53:55 mascarenhas Exp $

+
+ +
+ + + diff --git a/luaclib/lfs/lfs.c b/luaclib/lfs/lfs.c new file mode 100644 index 0000000..4cb5875 --- /dev/null +++ b/luaclib/lfs/lfs.c @@ -0,0 +1,898 @@ +/* +** LuaFileSystem +** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem) +** +** File system manipulation library. +** This library offers these functions: +** lfs.attributes (filepath [, attributename]) +** lfs.chdir (path) +** lfs.currentdir () +** lfs.dir (path) +** lfs.lock (fh, mode) +** lfs.lock_dir (path) +** lfs.mkdir (path) +** lfs.rmdir (path) +** lfs.setmode (filepath, mode) +** lfs.symlinkattributes (filepath [, attributename]) -- thanks to Sam Roberts +** lfs.touch (filepath [, atime [, mtime]]) +** lfs.unlock (fh) +** +** $Id: lfs.c,v 1.61 2009/07/04 02:10:16 mascarenhas Exp $ +*/ + +#ifndef LFS_DO_NOT_USE_LARGE_FILE +#ifndef _WIN32 +#ifndef _AIX +#define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */ +#else +#define _LARGE_FILES 1 /* AIX */ +#endif +#endif +#endif + +#ifndef LFS_DO_NOT_USE_LARGE_FILE +#define _LARGEFILE64_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#include +#ifdef __BORLANDC__ + #include +#else + #include +#endif +#include +#else +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#include "lfs.h" + +#define LFS_VERSION "1.6.3" +#define LFS_LIBNAME "lfs" + +#if LUA_VERSION_NUM >= 503 /* Lua 5.3 */ + +#ifndef luaL_optlong +#define luaL_optlong luaL_optinteger +#endif + +#endif + +#if LUA_VERSION_NUM < 502 +# define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l)) +#endif + +/* Define 'strerror' for systems that do not implement it */ +#ifdef NO_STRERROR +#define strerror(_) "System unable to describe the error" +#endif + +/* Define 'getcwd' for systems that do not implement it */ +#ifdef NO_GETCWD +#define getcwd(p,s) NULL +#define getcwd_error "Function 'getcwd' not provided by system" +#else +#define getcwd_error strerror(errno) + #ifdef _WIN32 + /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */ + #define LFS_MAXPATHLEN MAX_PATH + #else + /* For MAXPATHLEN: */ + #include + #define LFS_MAXPATHLEN MAXPATHLEN + #endif +#endif + +#define DIR_METATABLE "directory metatable" +typedef struct dir_data { + int closed; +#ifdef _WIN32 + intptr_t hFile; + char pattern[MAX_PATH+1]; +#else + DIR *dir; +#endif +} dir_data; + +#define LOCK_METATABLE "lock metatable" + +#ifdef _WIN32 + #ifdef __BORLANDC__ + #define lfs_setmode(L,file,m) ((void)L, setmode(_fileno(file), m)) + #define STAT_STRUCT struct stati64 + #else + #define lfs_setmode(L,file,m) ((void)L, _setmode(_fileno(file), m)) + #define STAT_STRUCT struct _stati64 + #endif +#define STAT_FUNC _stati64 +#define LSTAT_FUNC STAT_FUNC +#else +#define _O_TEXT 0 +#define _O_BINARY 0 +#define lfs_setmode(L,file,m) ((void)L, (void)file, (void)m, 0) +#define STAT_STRUCT struct stat +#define STAT_FUNC stat +#define LSTAT_FUNC lstat +#endif + +/* +** Utility functions +*/ +static int pusherror(lua_State *L, const char *info) +{ + lua_pushnil(L); + if (info==NULL) + lua_pushstring(L, strerror(errno)); + else + lua_pushfstring(L, "%s: %s", info, strerror(errno)); + lua_pushinteger(L, errno); + return 3; +} + +static int pushresult(lua_State *L, int i, const char *info) +{ + if (i==-1) + return pusherror(L, info); + lua_pushinteger(L, i); + return 1; +} + + +/* +** This function changes the working (current) directory +*/ +static int change_dir (lua_State *L) { + const char *path = luaL_checkstring(L, 1); + if (chdir(path)) { + lua_pushnil (L); + lua_pushfstring (L,"Unable to change working directory to '%s'\n%s\n", + path, chdir_error); + return 2; + } else { + lua_pushboolean (L, 1); + return 1; + } +} + +/* +** This function returns the current directory +** If unable to get the current directory, it returns nil +** and a string describing the error +*/ +static int get_dir (lua_State *L) { + char *path; + /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */ + char buf[LFS_MAXPATHLEN]; + if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) { + lua_pushnil(L); + lua_pushstring(L, getcwd_error); + return 2; + } + else { + lua_pushstring(L, path); + return 1; + } +} + +/* +** Check if the given element on the stack is a file and returns it. +*/ +static FILE *check_file (lua_State *L, int idx, const char *funcname) { + FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*"); + if (fh == NULL) { + luaL_error (L, "%s: not a file", funcname); + return 0; + } else if (*fh == NULL) { + luaL_error (L, "%s: closed file", funcname); + return 0; + } else + return *fh; +} + + +/* +** +*/ +static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) { + int code; +#ifdef _WIN32 + /* lkmode valid values are: + LK_LOCK Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error. + LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error. + LK_NBRLCK Same as _LK_NBLCK. + LK_RLCK Same as _LK_LOCK. + LK_UNLCK Unlocks the specified bytes, which must have been previously locked. + + Regions should be locked only briefly and should be unlocked before closing a file or exiting the program. + + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp + */ + int lkmode; + switch (*mode) { + case 'r': lkmode = LK_NBLCK; break; + case 'w': lkmode = LK_NBLCK; break; + case 'u': lkmode = LK_UNLCK; break; + default : return luaL_error (L, "%s: invalid mode", funcname); + } + if (!len) { + fseek (fh, 0L, SEEK_END); + len = ftell (fh); + } + fseek (fh, start, SEEK_SET); +#ifdef __BORLANDC__ + code = locking (fileno(fh), lkmode, len); +#else + code = _locking (fileno(fh), lkmode, len); +#endif +#else + struct flock f; + switch (*mode) { + case 'w': f.l_type = F_WRLCK; break; + case 'r': f.l_type = F_RDLCK; break; + case 'u': f.l_type = F_UNLCK; break; + default : return luaL_error (L, "%s: invalid mode", funcname); + } + f.l_whence = SEEK_SET; + f.l_start = (off_t)start; + f.l_len = (off_t)len; + code = fcntl (fileno(fh), F_SETLK, &f); +#endif + return (code != -1); +} + +#ifdef _WIN32 +typedef struct lfs_Lock { + HANDLE fd; +} lfs_Lock; +static int lfs_lock_dir(lua_State *L) { + size_t pathl; HANDLE fd; + lfs_Lock *lock; + char *ln; + const char *lockfile = "/lockfile.lfs"; + const char *path = luaL_checklstring(L, 1, &pathl); + ln = (char*)malloc(pathl + strlen(lockfile) + 1); + if(!ln) { + lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; + } + strcpy(ln, path); strcat(ln, lockfile); + if((fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) { + int en = GetLastError(); + free(ln); lua_pushnil(L); + if(en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION) + lua_pushstring(L, "File exists"); + else + lua_pushstring(L, strerror(en)); + return 2; + } + free(ln); + lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock)); + lock->fd = fd; + luaL_getmetatable (L, LOCK_METATABLE); + lua_setmetatable (L, -2); + return 1; +} +static int lfs_unlock_dir(lua_State *L) { + lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE); + if(lock->fd != INVALID_HANDLE_VALUE) { + CloseHandle(lock->fd); + lock->fd=INVALID_HANDLE_VALUE; + } + return 0; +} +#else +typedef struct lfs_Lock { + char *ln; +} lfs_Lock; +static int lfs_lock_dir(lua_State *L) { + lfs_Lock *lock; + size_t pathl; + char *ln; + const char *lockfile = "/lockfile.lfs"; + const char *path = luaL_checklstring(L, 1, &pathl); + lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock)); + ln = (char*)malloc(pathl + strlen(lockfile) + 1); + if(!ln) { + lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; + } + strcpy(ln, path); strcat(ln, lockfile); + if(symlink("lock", ln) == -1) { + free(ln); lua_pushnil(L); + lua_pushstring(L, strerror(errno)); return 2; + } + lock->ln = ln; + luaL_getmetatable (L, LOCK_METATABLE); + lua_setmetatable (L, -2); + return 1; +} +static int lfs_unlock_dir(lua_State *L) { + lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE); + if(lock->ln) { + unlink(lock->ln); + free(lock->ln); + lock->ln = NULL; + } + return 0; +} +#endif + +static int lfs_g_setmode (lua_State *L, FILE *f, int arg) { + static const int mode[] = {_O_BINARY, _O_TEXT}; + static const char *const modenames[] = {"binary", "text", NULL}; + int op = luaL_checkoption(L, arg, NULL, modenames); + int res = lfs_setmode(L, f, mode[op]); + if (res != -1) { + int i; + lua_pushboolean(L, 1); + for (i = 0; modenames[i] != NULL; i++) { + if (mode[i] == res) { + lua_pushstring(L, modenames[i]); + goto exit; + } + } + lua_pushnil(L); + exit: + return 2; + } else { + int en = errno; + lua_pushnil(L); + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); + return 3; + } +} + +static int lfs_f_setmode(lua_State *L) { + return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2); +} + +/* +** Locks a file. +** @param #1 File handle. +** @param #2 String with lock mode ('w'rite, 'r'ead). +** @param #3 Number with start position (optional). +** @param #4 Number with length (optional). +*/ +static int file_lock (lua_State *L) { + FILE *fh = check_file (L, 1, "lock"); + const char *mode = luaL_checkstring (L, 2); + const long start = (long) luaL_optinteger (L, 3, 0); + long len = (long) luaL_optinteger (L, 4, 0); + if (_file_lock (L, fh, mode, start, len, "lock")) { + lua_pushboolean (L, 1); + return 1; + } else { + lua_pushnil (L); + lua_pushfstring (L, "%s", strerror(errno)); + return 2; + } +} + + +/* +** Unlocks a file. +** @param #1 File handle. +** @param #2 Number with start position (optional). +** @param #3 Number with length (optional). +*/ +static int file_unlock (lua_State *L) { + FILE *fh = check_file (L, 1, "unlock"); + const long start = (long) luaL_optinteger (L, 2, 0); + long len = (long) luaL_optinteger (L, 3, 0); + if (_file_lock (L, fh, "u", start, len, "unlock")) { + lua_pushboolean (L, 1); + return 1; + } else { + lua_pushnil (L); + lua_pushfstring (L, "%s", strerror(errno)); + return 2; + } +} + + +/* +** Creates a link. +** @param #1 Object to link to. +** @param #2 Name of link. +** @param #3 True if link is symbolic (optional). +*/ +static int make_link(lua_State *L) +{ +#ifndef _WIN32 + const char *oldpath = luaL_checkstring(L, 1); + const char *newpath = luaL_checkstring(L, 2); + return pushresult(L, + (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath), NULL); +#else + return pusherror(L, "make_link is not supported on Windows"); +#endif +} + + +/* +** Creates a directory. +** @param #1 Directory path. +*/ +static int make_dir (lua_State *L) { + const char *path = luaL_checkstring (L, 1); + int fail; +#ifdef _WIN32 + fail = _mkdir (path); +#else + fail = mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | + S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH ); +#endif + if (fail) { + lua_pushnil (L); + lua_pushfstring (L, "%s", strerror(errno)); + return 2; + } + lua_pushboolean (L, 1); + return 1; +} + + +/* +** Removes a directory. +** @param #1 Directory path. +*/ +static int remove_dir (lua_State *L) { + const char *path = luaL_checkstring (L, 1); + int fail; + + fail = rmdir (path); + + if (fail) { + lua_pushnil (L); + lua_pushfstring (L, "%s", strerror(errno)); + return 2; + } + lua_pushboolean (L, 1); + return 1; +} + + +/* +** Directory iterator +*/ +static int dir_iter (lua_State *L) { +#ifdef _WIN32 + struct _finddata_t c_file; +#else + struct dirent *entry; +#endif + dir_data *d = (dir_data *)luaL_checkudata (L, 1, DIR_METATABLE); + luaL_argcheck (L, d->closed == 0, 1, "closed directory"); +#ifdef _WIN32 + if (d->hFile == 0L) { /* first entry */ + if ((d->hFile = _findfirst (d->pattern, &c_file)) == -1L) { + lua_pushnil (L); + lua_pushstring (L, strerror (errno)); + d->closed = 1; + return 2; + } else { + lua_pushstring (L, c_file.name); + return 1; + } + } else { /* next entry */ + if (_findnext (d->hFile, &c_file) == -1L) { + /* no more entries => close directory */ + _findclose (d->hFile); + d->closed = 1; + return 0; + } else { + lua_pushstring (L, c_file.name); + return 1; + } + } +#else + if ((entry = readdir (d->dir)) != NULL) { + lua_pushstring (L, entry->d_name); + return 1; + } else { + /* no more entries => close directory */ + closedir (d->dir); + d->closed = 1; + return 0; + } +#endif +} + + +/* +** Closes directory iterators +*/ +static int dir_close (lua_State *L) { + dir_data *d = (dir_data *)lua_touserdata (L, 1); +#ifdef _WIN32 + if (!d->closed && d->hFile) { + _findclose (d->hFile); + } +#else + if (!d->closed && d->dir) { + closedir (d->dir); + } +#endif + d->closed = 1; + return 0; +} + + +/* +** Factory of directory iterators +*/ +static int dir_iter_factory (lua_State *L) { + const char *path = luaL_checkstring (L, 1); + dir_data *d; + lua_pushcfunction (L, dir_iter); + d = (dir_data *) lua_newuserdata (L, sizeof(dir_data)); + luaL_getmetatable (L, DIR_METATABLE); + lua_setmetatable (L, -2); + d->closed = 0; +#ifdef _WIN32 + d->hFile = 0L; + if (strlen(path) > MAX_PATH-2) + luaL_error (L, "path too long: %s", path); + else + sprintf (d->pattern, "%s/*", path); +#else + d->dir = opendir (path); + if (d->dir == NULL) + luaL_error (L, "cannot open %s: %s", path, strerror (errno)); +#endif + return 2; +} + + +/* +** Creates directory metatable. +*/ +static int dir_create_meta (lua_State *L) { + luaL_newmetatable (L, DIR_METATABLE); + + /* Method table */ + lua_newtable(L); + lua_pushcfunction (L, dir_iter); + lua_setfield(L, -2, "next"); + lua_pushcfunction (L, dir_close); + lua_setfield(L, -2, "close"); + + /* Metamethods */ + lua_setfield(L, -2, "__index"); + lua_pushcfunction (L, dir_close); + lua_setfield (L, -2, "__gc"); + return 1; +} + + +/* +** Creates lock metatable. +*/ +static int lock_create_meta (lua_State *L) { + luaL_newmetatable (L, LOCK_METATABLE); + + /* Method table */ + lua_newtable(L); + lua_pushcfunction(L, lfs_unlock_dir); + lua_setfield(L, -2, "free"); + + /* Metamethods */ + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, lfs_unlock_dir); + lua_setfield(L, -2, "__gc"); + return 1; +} + + +#ifdef _WIN32 + #ifndef S_ISDIR + #define S_ISDIR(mode) (mode&_S_IFDIR) + #endif + #ifndef S_ISREG + #define S_ISREG(mode) (mode&_S_IFREG) + #endif + #ifndef S_ISLNK + #define S_ISLNK(mode) (0) + #endif + #ifndef S_ISSOCK + #define S_ISSOCK(mode) (0) + #endif + #ifndef S_ISFIFO + #define S_ISFIFO(mode) (0) + #endif + #ifndef S_ISCHR + #define S_ISCHR(mode) (mode&_S_IFCHR) + #endif + #ifndef S_ISBLK + #define S_ISBLK(mode) (0) + #endif +#endif +/* +** Convert the inode protection mode to a string. +*/ +#ifdef _WIN32 +static const char *mode2string (unsigned short mode) { +#else +static const char *mode2string (mode_t mode) { +#endif + if ( S_ISREG(mode) ) + return "file"; + else if ( S_ISDIR(mode) ) + return "directory"; + else if ( S_ISLNK(mode) ) + return "link"; + else if ( S_ISSOCK(mode) ) + return "socket"; + else if ( S_ISFIFO(mode) ) + return "named pipe"; + else if ( S_ISCHR(mode) ) + return "char device"; + else if ( S_ISBLK(mode) ) + return "block device"; + else + return "other"; +} + + +/* +** Set access time and modification values for file +*/ +static int file_utime (lua_State *L) { + const char *file = luaL_checkstring (L, 1); + struct utimbuf utb, *buf; + + if (lua_gettop (L) == 1) /* set to current date/time */ + buf = NULL; + else { + utb.actime = (time_t)luaL_optnumber (L, 2, 0); + utb.modtime = (time_t) luaL_optinteger (L, 3, utb.actime); + buf = &utb; + } + if (utime (file, buf)) { + lua_pushnil (L); + lua_pushfstring (L, "%s", strerror (errno)); + return 2; + } + lua_pushboolean (L, 1); + return 1; +} + + +/* inode protection mode */ +static void push_st_mode (lua_State *L, STAT_STRUCT *info) { + lua_pushstring (L, mode2string (info->st_mode)); +} +/* device inode resides on */ +static void push_st_dev (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer) info->st_dev); +} +/* inode's number */ +static void push_st_ino (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer) info->st_ino); +} +/* number of hard links to the file */ +static void push_st_nlink (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer)info->st_nlink); +} +/* user-id of owner */ +static void push_st_uid (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer)info->st_uid); +} +/* group-id of owner */ +static void push_st_gid (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer)info->st_gid); +} +/* device type, for special file inode */ +static void push_st_rdev (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer) info->st_rdev); +} +/* time of last access */ +static void push_st_atime (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer) info->st_atime); +} +/* time of last data modification */ +static void push_st_mtime (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer) info->st_mtime); +} +/* time of last file status change */ +static void push_st_ctime (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer) info->st_ctime); +} +/* file size, in bytes */ +static void push_st_size (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer)info->st_size); +} +#ifndef _WIN32 +/* blocks allocated for file */ +static void push_st_blocks (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer)info->st_blocks); +} +/* optimal file system I/O blocksize */ +static void push_st_blksize (lua_State *L, STAT_STRUCT *info) { + lua_pushinteger (L, (lua_Integer)info->st_blksize); +} +#endif + + /* +** Convert the inode protection mode to a permission list. +*/ + +#ifdef _WIN32 +static const char *perm2string (unsigned short mode) { + static char perms[10] = "---------"; + int i; + for (i=0;i<9;i++) perms[i]='-'; + if (mode & _S_IREAD) + { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; } + if (mode & _S_IWRITE) + { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; } + if (mode & _S_IEXEC) + { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; } + return perms; +} +#else +static const char *perm2string (mode_t mode) { + static char perms[10] = "---------"; + int i; + for (i=0;i<9;i++) perms[i]='-'; + if (mode & S_IRUSR) perms[0] = 'r'; + if (mode & S_IWUSR) perms[1] = 'w'; + if (mode & S_IXUSR) perms[2] = 'x'; + if (mode & S_IRGRP) perms[3] = 'r'; + if (mode & S_IWGRP) perms[4] = 'w'; + if (mode & S_IXGRP) perms[5] = 'x'; + if (mode & S_IROTH) perms[6] = 'r'; + if (mode & S_IWOTH) perms[7] = 'w'; + if (mode & S_IXOTH) perms[8] = 'x'; + return perms; +} +#endif + +/* permssions string */ +static void push_st_perm (lua_State *L, STAT_STRUCT *info) { + lua_pushstring (L, perm2string (info->st_mode)); +} + +typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info); + +struct _stat_members { + const char *name; + _push_function push; +}; + +struct _stat_members members[] = { + { "mode", push_st_mode }, + { "dev", push_st_dev }, + { "ino", push_st_ino }, + { "nlink", push_st_nlink }, + { "uid", push_st_uid }, + { "gid", push_st_gid }, + { "rdev", push_st_rdev }, + { "access", push_st_atime }, + { "modification", push_st_mtime }, + { "change", push_st_ctime }, + { "size", push_st_size }, + { "permissions", push_st_perm }, +#ifndef _WIN32 + { "blocks", push_st_blocks }, + { "blksize", push_st_blksize }, +#endif + { NULL, NULL } +}; + +/* +** Get file or symbolic link information +*/ +static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) { + STAT_STRUCT info; + const char *file = luaL_checkstring (L, 1); + int i; + + if (st(file, &info)) { + lua_pushnil (L); + lua_pushfstring (L, "cannot obtain information from file `%s'", file); + return 2; + } + if (lua_isstring (L, 2)) { + const char *member = lua_tostring (L, 2); + for (i = 0; members[i].name; i++) { + if (strcmp(members[i].name, member) == 0) { + /* push member value and return */ + members[i].push (L, &info); + return 1; + } + } + /* member not found */ + return luaL_error(L, "invalid attribute name"); + } + /* creates a table if none is given */ + if (!lua_istable (L, 2)) { + lua_newtable (L); + } + /* stores all members in table on top of the stack */ + for (i = 0; members[i].name; i++) { + lua_pushstring (L, members[i].name); + members[i].push (L, &info); + lua_rawset (L, -3); + } + return 1; +} + + +/* +** Get file information using stat. +*/ +static int file_info (lua_State *L) { + return _file_info_ (L, STAT_FUNC); +} + + +/* +** Get symbolic link information using lstat. +*/ +static int link_info (lua_State *L) { + return _file_info_ (L, LSTAT_FUNC); +} + + +/* +** Assumes the table is on top of the stack. +*/ +static void set_info (lua_State *L) { + lua_pushliteral (L, "_COPYRIGHT"); + lua_pushliteral (L, "Copyright (C) 2003-2012 Kepler Project"); + lua_settable (L, -3); + lua_pushliteral (L, "_DESCRIPTION"); + lua_pushliteral (L, "LuaFileSystem is a Lua library developed to complement the set of functions related to file systems offered by the standard Lua distribution"); + lua_settable (L, -3); + lua_pushliteral (L, "_VERSION"); + lua_pushliteral (L, "LuaFileSystem "LFS_VERSION); + lua_settable (L, -3); +} + + +static const struct luaL_Reg fslib[] = { + {"attributes", file_info}, + {"chdir", change_dir}, + {"currentdir", get_dir}, + {"dir", dir_iter_factory}, + {"link", make_link}, + {"lock", file_lock}, + {"mkdir", make_dir}, + {"rmdir", remove_dir}, + {"symlinkattributes", link_info}, + {"setmode", lfs_f_setmode}, + {"touch", file_utime}, + {"unlock", file_unlock}, + {"lock_dir", lfs_lock_dir}, + {NULL, NULL}, +}; + +int luaopen_lfs (lua_State *L) { + dir_create_meta (L); + lock_create_meta (L); + luaL_newlib (L, fslib); + lua_pushvalue(L, -1); + lua_setglobal(L, LFS_LIBNAME); + set_info (L); + return 1; +} diff --git a/luaclib/lfs/lfs.def b/luaclib/lfs/lfs.def new file mode 100644 index 0000000..2b69094 --- /dev/null +++ b/luaclib/lfs/lfs.def @@ -0,0 +1,5 @@ +LIBRARY lfs.dll +DESCRIPTION "LuaFileSystem" +VERSION 1.5.0 +EXPORTS +luaopen_lfs diff --git a/luaclib/lfs/lfs.h b/luaclib/lfs/lfs.h new file mode 100644 index 0000000..ddd454d --- /dev/null +++ b/luaclib/lfs/lfs.h @@ -0,0 +1,25 @@ +/* +** LuaFileSystem +** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem) +** +** $Id: lfs.h,v 1.5 2008/02/19 20:08:23 mascarenhas Exp $ +*/ + +/* Define 'chdir' for systems that do not implement it */ +#ifdef NO_CHDIR +#define chdir(p) (-1) +#define chdir_error "Function 'chdir' not provided by system" +#else +#define chdir_error strerror(errno) + +#endif + +#ifdef _WIN32 +#define chdir(p) (_chdir(p)) +#define getcwd(d, s) (_getcwd(d, s)) +#define rmdir(p) (_rmdir(p)) +#define fileno(f) (_fileno(f)) +#endif + + +int luaopen_lfs (lua_State *L); diff --git a/luaclib/lfs/lfs.vcxproj b/luaclib/lfs/lfs.vcxproj new file mode 100644 index 0000000..65289b6 --- /dev/null +++ b/luaclib/lfs/lfs.vcxproj @@ -0,0 +1,84 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E} + lfs + + + + DynamicLibrary + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + $(ProjectDir) + + + + Level3 + Disabled + true + ..\..\deps\lua; + WIN32;_DEBUG;_WINDOWS;_USRDLL;LUA_CORE;LUA_BUILD_AS_DLL;LUA_COMPAT_5_2;LUA_COMPAT_5_1;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + ..\..\deps\lua; + nlua.lib + + + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/luaclib/lfs/lfs.vcxproj.filters b/luaclib/lfs/lfs.vcxproj.filters new file mode 100644 index 0000000..6e793af --- /dev/null +++ b/luaclib/lfs/lfs.vcxproj.filters @@ -0,0 +1,18 @@ + + + + + {395fddde-2cd4-441d-9334-8428e206d9cb} + + + + + src + + + + + src + + + \ No newline at end of file diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.3.0-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.3.0-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.4.0-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.4.0-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.4.0-2.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.4.0-2.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.4.1-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.4.1-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.4.1rc1-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.4.1rc1-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.4.2-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.4.2-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.5.0-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.5.0-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.6.0-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.6.0-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.6.1-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.6.1-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.6.2-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.6.2-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-1.6.3-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-1.6.3-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-cvs-1.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-cvs-1.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-cvs-2.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-cvs-2.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/._luafilesystem-cvs-3.rockspec b/luaclib/lfs/rockspecs/._luafilesystem-cvs-3.rockspec new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.3.0-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.3.0-1.rockspec new file mode 100644 index 0000000..d4d484f --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.3.0-1.rockspec @@ -0,0 +1,27 @@ +package = "LuaFileSystem" +version = "1.3.0-1" +source = { + url = "http://luaforge.net/frs/download.php/2679/luafilesystem-1.3.0.tar.gz" +} +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "make", + build_variables = { + LUA_INC = "$(LUA_INCDIR)", + LIB_OPTION = "$(LIBFLAG)" + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)" + } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.4.0-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.4.0-1.rockspec new file mode 100644 index 0000000..b693618 --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.4.0-1.rockspec @@ -0,0 +1,27 @@ +package = "LuaFileSystem" +version = "1.4.0-1" +source = { + url = "http://luaforge.net/frs/download.php/3158/luafilesystem-1.4.0.tar.gz" +} +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "make", + build_variables = { + LUA_INC = "$(LUA_INCDIR)", + LIB_OPTION = "$(LIBFLAG)" + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)" + } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.4.0-2.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.4.0-2.rockspec new file mode 100644 index 0000000..f7ed871 --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.4.0-2.rockspec @@ -0,0 +1,43 @@ +package = "LuaFileSystem" +version = "1.4.0-2" +source = { + url = "http://luaforge.net/frs/download.php/3158/luafilesystem-1.4.0.tar.gz" +} +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} +dependencies = { + "lua >= 5.1" +} +build = { + platforms = { + unix = { + type = "make", + build_variables = { + LIB_OPTION = "$(LIBFLAG)", + CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)", + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)" + } + }, + win32 = { + type = "make", + build_variables = { + LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib", + CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)", + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)", + LUA_DIR = "$(LUADIR)", + BIN_DIR = "$(BINDIR)" + } + } + } +} \ No newline at end of file diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.4.1-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.4.1-1.rockspec new file mode 100644 index 0000000..db3a3eb --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.4.1-1.rockspec @@ -0,0 +1,43 @@ +package = "LuaFileSystem" +version = "1.4.1-1" +source = { + url = "http://luaforge.net/frs/download.php/3345/luafilesystem-1.4.1.tar.gz", +} +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} +dependencies = { + "lua >= 5.1" +} +build = { + platforms = { + unix = { + type = "make", + build_variables = { + LIB_OPTION = "$(LIBFLAG)", + CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR) $(STAT64)", + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)" + } + }, + win32 = { + type = "make", + build_variables = { + LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib", + CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)", + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)", + LUA_DIR = "$(LUADIR)", + BIN_DIR = "$(BINDIR)" + } + } + } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.4.1rc1-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.4.1rc1-1.rockspec new file mode 100644 index 0000000..1194711 --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.4.1rc1-1.rockspec @@ -0,0 +1,43 @@ +package = "LuaFileSystem" +version = "1.4.1rc1-1" +source = { + url = "http://luafilesystem.luaforge.net/luafilesystem-1.4.1rc1.tar.gz", +} +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} +dependencies = { + "lua >= 5.1" +} +build = { + platforms = { + unix = { + type = "make", + build_variables = { + LIB_OPTION = "$(LIBFLAG)", + CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR) $(STAT64)", + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)" + } + }, + win32 = { + type = "make", + build_variables = { + LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib", + CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)", + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)", + LUA_DIR = "$(LUADIR)", + BIN_DIR = "$(BINDIR)" + } + } + } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.4.2-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.4.2-1.rockspec new file mode 100644 index 0000000..7cfe92b --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.4.2-1.rockspec @@ -0,0 +1,26 @@ +package = "LuaFileSystem" + +version = "1.4.2-1" + +source = { + url = "http://luaforge.net/frs/download.php/3931/luafilesystem-1.4.2.tar.gz", +} + +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} + +dependencies = { + "lua >= 5.1" +} + +build = { + type = "module", + modules = { lfs = "src/lfs.c" } +} \ No newline at end of file diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.5.0-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.5.0-1.rockspec new file mode 100644 index 0000000..1170ad2 --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.5.0-1.rockspec @@ -0,0 +1,27 @@ +package = "LuaFileSystem" + +version = "1.5.0-1" + +source = { + url = "http://cloud.github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.5.0.tar.gz", +} + +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} + +dependencies = { + "lua >= 5.1" +} + +build = { + type = "module", + modules = { lfs = "src/lfs.c" }, + copy_directories = { "doc", "tests" } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.6.0-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.6.0-1.rockspec new file mode 100644 index 0000000..82d349c --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.6.0-1.rockspec @@ -0,0 +1,27 @@ +package = "LuaFileSystem" + +version = "1.6.0-1" + +source = { + url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.0.tar.gz", +} + +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} + +dependencies = { + "lua >= 5.1" +} + +build = { + type = "builtin", + modules = { lfs = "src/lfs.c" }, + copy_directories = { "doc", "tests" } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.6.1-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.6.1-1.rockspec new file mode 100644 index 0000000..7f45e33 --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.6.1-1.rockspec @@ -0,0 +1,27 @@ +package = "LuaFileSystem" + +version = "1.6.1-1" + +source = { + url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.1.tar.gz", +} + +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} + +dependencies = { + "lua >= 5.1" +} + +build = { + type = "builtin", + modules = { lfs = "src/lfs.c" }, + copy_directories = { "doc", "tests" } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.6.2-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.6.2-1.rockspec new file mode 100644 index 0000000..1c11efc --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.6.2-1.rockspec @@ -0,0 +1,27 @@ +package = "LuaFileSystem" + +version = "1.6.2-1" + +source = { + url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.2.tar.gz", +} + +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} + +dependencies = { + "lua >= 5.1" +} + +build = { + type = "builtin", + modules = { lfs = "src/lfs.c" }, + copy_directories = { "doc", "tests" } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-1.6.3-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-1.6.3-1.rockspec new file mode 100644 index 0000000..89b25d4 --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-1.6.3-1.rockspec @@ -0,0 +1,28 @@ +package = "LuaFileSystem" +version = "1.6.3-1" +source = { + url = "git://github.com/keplerproject/luafilesystem", + tag = "v_1_6_3", +} +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]], + license = "MIT/X11", +} +dependencies = { + "lua >= 5.1" +} +build = { + type = "builtin", + modules = { + lfs = "src/lfs.c" + }, + copy_directories = { + "doc", "tests" + } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-cvs-1.rockspec b/luaclib/lfs/rockspecs/luafilesystem-cvs-1.rockspec new file mode 100644 index 0000000..a02d4f1 --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-cvs-1.rockspec @@ -0,0 +1,44 @@ +package = "LuaFileSystem" +version = "cvs-1" +source = { + url = "cvs://:pserver:anonymous:@cvs.luaforge.net:/cvsroot/luafilesystem", + cvs_tag = "HEAD" +} +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} +dependencies = { + "lua >= 5.1" +} +build = { + platforms = { + unix = { + type = "make", + build_variables = { + LIB_OPTION = "$(LIBFLAG)", + CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)", + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)" + } + }, + win32 = { + type = "make", + build_variables = { + LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib", + CFLAGS = "$(CFLAGS) /I$(LUA_INCDIR)", + }, + install_variables = { + LUA_LIBDIR = "$(LIBDIR)", + LUA_DIR = "$(LUADIR)", + BIN_DIR = "$(BINDIR)" + } + } + } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-cvs-2.rockspec b/luaclib/lfs/rockspecs/luafilesystem-cvs-2.rockspec new file mode 100644 index 0000000..651c7cf --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-cvs-2.rockspec @@ -0,0 +1,26 @@ +package = "LuaFileSystem" + +version = "cvs-2" + +source = { + url = "git://github.com/keplerproject/luafilesystem.git", +} + +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} + +dependencies = { + "lua >= 5.1" +} + +build = { + type = "module", + modules = { lfs = "src/lfs.c" } +} diff --git a/luaclib/lfs/rockspecs/luafilesystem-cvs-3.rockspec b/luaclib/lfs/rockspecs/luafilesystem-cvs-3.rockspec new file mode 100644 index 0000000..a4388cd --- /dev/null +++ b/luaclib/lfs/rockspecs/luafilesystem-cvs-3.rockspec @@ -0,0 +1,27 @@ +package = "LuaFileSystem" + +version = "cvs-3" + +source = { + url = "git://github.com/keplerproject/luafilesystem.git", +} + +description = { + summary = "File System Library for the Lua Programming Language", + detailed = [[ + LuaFileSystem is a Lua library developed to complement the set of + functions related to file systems offered by the standard Lua + distribution. LuaFileSystem offers a portable way to access the + underlying directory structure and file attributes. + ]] +} + +dependencies = { + "lua >= 5.1, < 5.4" +} + +build = { + type = "builtin", + modules = { lfs = "src/lfs.c" }, + copy_directories = { "doc", "tests" } +} diff --git a/luaclib/lfs/tests/._test.lua b/luaclib/lfs/tests/._test.lua new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/tests/test.lua b/luaclib/lfs/tests/test.lua new file mode 100644 index 0000000..abfbd4d --- /dev/null +++ b/luaclib/lfs/tests/test.lua @@ -0,0 +1,175 @@ +#!/usr/bin/env lua5.1 + +local tmp = "/tmp" +local sep = string.match (package.config, "[^\n]+") +local upper = ".." + +local lfs = require"lfs" +print (lfs._VERSION) + +io.write(".") +io.flush() + +function attrdir (path) + for file in lfs.dir(path) do + if file ~= "." and file ~= ".." then + local f = path..sep..file + print ("\t=> "..f.." <=") + local attr = lfs.attributes (f) + assert (type(attr) == "table") + if attr.mode == "directory" then + attrdir (f) + else + for name, value in pairs(attr) do + print (name, value) + end + end + end + end +end + +-- Checking changing directories +local current = assert (lfs.currentdir()) +local reldir = string.gsub (current, "^.*%"..sep.."([^"..sep.."])$", "%1") +assert (lfs.chdir (upper), "could not change to upper directory") +assert (lfs.chdir (reldir), "could not change back to current directory") +assert (lfs.currentdir() == current, "error trying to change directories") +assert (lfs.chdir ("this couldn't be an actual directory") == nil, "could change to a non-existent directory") + +io.write(".") +io.flush() + +-- Changing creating and removing directories +local tmpdir = current..sep.."lfs_tmp_dir" +local tmpfile = tmpdir..sep.."tmp_file" +-- Test for existence of a previous lfs_tmp_dir +-- that may have resulted from an interrupted test execution and remove it +if lfs.chdir (tmpdir) then + assert (lfs.chdir (upper), "could not change to upper directory") + assert (os.remove (tmpfile), "could not remove file from previous test") + assert (lfs.rmdir (tmpdir), "could not remove directory from previous test") +end + +io.write(".") +io.flush() + +-- tries to create a directory +assert (lfs.mkdir (tmpdir), "could not make a new directory") +local attrib, errmsg = lfs.attributes (tmpdir) +if not attrib then + error ("could not get attributes of file `"..tmpdir.."':\n"..errmsg) +end +local f = io.open(tmpfile, "w") +f:close() + +io.write(".") +io.flush() + +-- Change access time +local testdate = os.time({ year = 2007, day = 10, month = 2, hour=0}) +assert (lfs.touch (tmpfile, testdate)) +local new_att = assert (lfs.attributes (tmpfile)) +assert (new_att.access == testdate, "could not set access time") +assert (new_att.modification == testdate, "could not set modification time") + +io.write(".") +io.flush() + +-- Change access and modification time +local testdate1 = os.time({ year = 2007, day = 10, month = 2, hour=0}) +local testdate2 = os.time({ year = 2007, day = 11, month = 2, hour=0}) + +assert (lfs.touch (tmpfile, testdate2, testdate1)) +local new_att = assert (lfs.attributes (tmpfile)) +assert (new_att.access == testdate2, "could not set access time") +assert (new_att.modification == testdate1, "could not set modification time") + +io.write(".") +io.flush() + +-- Checking link (does not work on Windows) +if lfs.link (tmpfile, "_a_link_for_test_", true) then + assert (lfs.attributes"_a_link_for_test_".mode == "file") + assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link") + assert (lfs.link (tmpfile, "_a_hard_link_for_test_")) + assert (lfs.attributes (tmpfile, "nlink") == 2) + assert (os.remove"_a_link_for_test_") + assert (os.remove"_a_hard_link_for_test_") +end + +io.write(".") +io.flush() + +-- Checking text/binary modes (only has an effect in Windows) +local f = io.open(tmpfile, "w") +local result, mode = lfs.setmode(f, "binary") +assert(result) -- on non-Windows platforms, mode is always returned as "binary" +result, mode = lfs.setmode(f, "text") +assert(result and mode == "binary") +f:close() + +io.write(".") +io.flush() + +-- Restore access time to current value +assert (lfs.touch (tmpfile, attrib.access, attrib.modification)) +new_att = assert (lfs.attributes (tmpfile)) +assert (new_att.access == attrib.access) +assert (new_att.modification == attrib.modification) + +io.write(".") +io.flush() + +-- Check consistency of lfs.attributes values +local attr = lfs.attributes (tmpfile) +for key, value in pairs(attr) do + assert (value == lfs.attributes (tmpfile, key), + "lfs.attributes values not consistent") +end + +-- Remove new file and directory +assert (os.remove (tmpfile), "could not remove new file") +assert (lfs.rmdir (tmpdir), "could not remove new directory") +assert (lfs.mkdir (tmpdir..sep.."lfs_tmp_dir") == nil, "could create a directory inside a non-existent one") + +io.write(".") +io.flush() + +-- Trying to get attributes of a non-existent file +assert (lfs.attributes ("this couldn't be an actual file") == nil, "could get attributes of a non-existent file") +assert (type(lfs.attributes (upper)) == "table", "couldn't get attributes of upper directory") + +io.write(".") +io.flush() + +-- Stressing directory iterator +count = 0 +for i = 1, 4000 do + for file in lfs.dir (tmp) do + count = count + 1 + end +end + +io.write(".") +io.flush() + +-- Stressing directory iterator, explicit version +count = 0 +for i = 1, 4000 do + local iter, dir = lfs.dir(tmp) + local file = dir:next() + while file do + count = count + 1 + file = dir:next() + end + assert(not pcall(dir.next, dir)) +end + +io.write(".") +io.flush() + +-- directory explicit close +local iter, dir = lfs.dir(tmp) +dir:close() +assert(not pcall(dir.next, dir)) +print"Ok!" diff --git a/luaclib/lfs/vc6/._lfs.def b/luaclib/lfs/vc6/._lfs.def new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/vc6/._luafilesystem.dsw b/luaclib/lfs/vc6/._luafilesystem.dsw new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/vc6/._luafilesystem_dll.dsp b/luaclib/lfs/vc6/._luafilesystem_dll.dsp new file mode 100644 index 0000000000000000000000000000000000000000..240a24437c5a9158292fd9f184e1a1e425cd6024 GIT binary patch literal 216 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iHI=@oxYz5x_AdBnYYuq+Khms7+IT|877%nS{hmhC#EG9WrEaM qyBV99IGVef=^DDZI_sJ^n>g!QS{j+^nwq(o7&*F`xf;4zG5`P+F(9n~ literal 0 HcmV?d00001 diff --git a/luaclib/lfs/vc6/lfs.def b/luaclib/lfs/vc6/lfs.def new file mode 100644 index 0000000..55ec688 --- /dev/null +++ b/luaclib/lfs/vc6/lfs.def @@ -0,0 +1,5 @@ +LIBRARY lfs.dll +DESCRIPTION "LuaFileSystem" +VERSION 1.2 +EXPORTS +luaopen_lfs diff --git a/luaclib/lfs/vc6/luafilesystem.dsw b/luaclib/lfs/vc6/luafilesystem.dsw new file mode 100644 index 0000000..b4bb4b3 --- /dev/null +++ b/luaclib/lfs/vc6/luafilesystem.dsw @@ -0,0 +1,33 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "luafilesystem_dll"=.\luafilesystem_dll.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + luafilesystem + .. + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/luaclib/lfs/vc6/luafilesystem_dll.dsp b/luaclib/lfs/vc6/luafilesystem_dll.dsp new file mode 100644 index 0000000..efe6c72 --- /dev/null +++ b/luaclib/lfs/vc6/luafilesystem_dll.dsp @@ -0,0 +1,127 @@ +# Microsoft Developer Studio Project File - Name="luafilesystem_dll" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=luafilesystem_dll - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "luafilesystem_dll.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "luafilesystem_dll.mak" CFG="luafilesystem_dll - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "luafilesystem_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "luafilesystem_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "luafilesystem_dll" +# PROP Scc_LocalPath ".." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "luafilesystem_dll - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../lib/vc6" +# PROP Intermediate_Dir "luafilesystem_dll/Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LUAFILESYSTEM_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../external-src/lua50/include" /I "../../compat/src" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LUAFILESYSTEM_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x416 /d "NDEBUG" +# ADD RSC /l 0x416 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 lua50.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../bin/vc6/lfs.dll" /libpath:"../../external-src/lua50/lib/dll" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=cd ../bin/vc6 zip.exe luafilesystem-1.2-win32.zip lfs.dll +# End Special Build Tool + +!ELSEIF "$(CFG)" == "luafilesystem_dll - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../lib/vc6" +# PROP Intermediate_Dir "luafilesystem_dll/Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LUAFILESYSTEM_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../external-src/lua50/include" /I "../../compat/src" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LUAFILESYSTEM_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x416 /d "_DEBUG" +# ADD RSC /l 0x416 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 lua50.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"../bin/vc6/lfsd.dll" /pdbtype:sept /libpath:"../../external-src/lua50/lib/dll" + +!ENDIF + +# Begin Target + +# Name "luafilesystem_dll - Win32 Release" +# Name "luafilesystem_dll - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\compat\src\compat-5.1.c" +# End Source File +# Begin Source File + +SOURCE=..\src\lfs.c +# End Source File +# Begin Source File + +SOURCE=.\lfs.def +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\..\compat\src\compat-5.1.h" +# End Source File +# Begin Source File + +SOURCE=..\src\lfs.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/luaclib/lpeg.dll b/luaclib/lpeg.dll new file mode 100644 index 0000000000000000000000000000000000000000..127fc58c2232775e6de0f08761d98d9e1eea1214 GIT binary patch literal 81408 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 TlqY3JAK%6`Fs^}d4Uqo@QAJ7J literal 0 HcmV?d00001 diff --git a/luaclib/lpeg/HISTORY b/luaclib/lpeg/HISTORY new file mode 100644 index 0000000..0c10edd --- /dev/null +++ b/luaclib/lpeg/HISTORY @@ -0,0 +1,96 @@ +HISTORY for LPeg 1.0 + +* Changes from version 0.12 to 1.0 + --------------------------------- + + group "names" can be any Lua value + + some bugs fixed + + other small improvements + +* Changes from version 0.11 to 0.12 + --------------------------------- + + no "unsigned short" limit for pattern sizes + + mathtime captures considered nullable + + some bugs fixed + +* Changes from version 0.10 to 0.11 + ------------------------------- + + complete reimplementation of the code generator + + new syntax for table captures + + new functions in module 're' + + other small improvements + +* Changes from version 0.9 to 0.10 + ------------------------------- + + backtrack stack has configurable size + + better error messages + + Notation for non-terminals in 're' back to A instead o + + experimental look-behind pattern + + support for external extensions + + works with Lua 5.2 + + consumes less C stack + + - "and" predicates do not keep captures + +* Changes from version 0.8 to 0.9 + ------------------------------- + + The accumulator capture was replaced by a fold capture; + programs that used the old 'lpeg.Ca' will need small changes. + + Some support for character classes from old C locales. + + A new named-group capture. + +* Changes from version 0.7 to 0.8 + ------------------------------- + + New "match-time" capture. + + New "argument capture" that allows passing arguments into the pattern. + + Better documentation for 're'. + + Several small improvements for 're'. + + The 're' module has an incompatibility with previous versions: + now, any use of a non-terminal must be enclosed in angle brackets + (like ). + +* Changes from version 0.6 to 0.7 + ------------------------------- + + Several improvements in module 're': + - better documentation; + - support for most captures (all but accumulator); + - limited repetitions p{n,m}. + + Small improvements in efficiency. + + Several small bugs corrected (special thanks to Hans Hagen + and Taco Hoekwater). + +* Changes from version 0.5 to 0.6 + ------------------------------- + + Support for non-numeric indices in grammars. + + Some bug fixes (thanks to the luatex team). + + Some new optimizations; (thanks to Mike Pall). + + A new page layout (thanks to Andre Carregal). + + Minimal documentation for module 're'. + +* Changes from version 0.4 to 0.5 + ------------------------------- + + Several optimizations. + + lpeg.P now accepts booleans. + + Some new examples. + + A proper license. + + Several small improvements. + +* Changes from version 0.3 to 0.4 + ------------------------------- + + Static check for loops in repetitions and grammars. + + Removed label option in captures. + + The implementation of captures uses less memory. + +* Changes from version 0.2 to 0.3 + ------------------------------- + + User-defined patterns in Lua. + + Several new captures. + +* Changes from version 0.1 to 0.2 + ------------------------------- + + Several small corrections. + + Handles embedded zeros like any other character. + + Capture "name" can be any Lua value. + + Unlimited number of captures. + + Match gets an optional initial position. + +(end of HISTORY) diff --git a/luaclib/lpeg/lpcap.c b/luaclib/lpeg/lpcap.c new file mode 100644 index 0000000..c9085de --- /dev/null +++ b/luaclib/lpeg/lpcap.c @@ -0,0 +1,537 @@ +/* +** $Id: lpcap.c,v 1.6 2015/06/15 16:09:57 roberto Exp $ +** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) +*/ + +#include "lua.h" +#include "lauxlib.h" + +#include "lpcap.h" +#include "lptypes.h" + + +#define captype(cap) ((cap)->kind) + +#define isclosecap(cap) (captype(cap) == Cclose) + +#define closeaddr(c) ((c)->s + (c)->siz - 1) + +#define isfullcap(cap) ((cap)->siz != 0) + +#define getfromktable(cs,v) lua_rawgeti((cs)->L, ktableidx((cs)->ptop), v) + +#define pushluaval(cs) getfromktable(cs, (cs)->cap->idx) + + + +/* +** Put at the cache for Lua values the value indexed by 'v' in ktable +** of the running pattern (if it is not there yet); returns its index. +*/ +static int updatecache (CapState *cs, int v) { + int idx = cs->ptop + 1; /* stack index of cache for Lua values */ + if (v != cs->valuecached) { /* not there? */ + getfromktable(cs, v); /* get value from 'ktable' */ + lua_replace(cs->L, idx); /* put it at reserved stack position */ + cs->valuecached = v; /* keep track of what is there */ + } + return idx; +} + + +static int pushcapture (CapState *cs); + + +/* +** Goes back in a list of captures looking for an open capture +** corresponding to a close +*/ +static Capture *findopen (Capture *cap) { + int n = 0; /* number of closes waiting an open */ + for (;;) { + cap--; + if (isclosecap(cap)) n++; /* one more open to skip */ + else if (!isfullcap(cap)) + if (n-- == 0) return cap; + } +} + + +/* +** Go to the next capture +*/ +static void nextcap (CapState *cs) { + Capture *cap = cs->cap; + if (!isfullcap(cap)) { /* not a single capture? */ + int n = 0; /* number of opens waiting a close */ + for (;;) { /* look for corresponding close */ + cap++; + if (isclosecap(cap)) { + if (n-- == 0) break; + } + else if (!isfullcap(cap)) n++; + } + } + cs->cap = cap + 1; /* + 1 to skip last close (or entire single capture) */ +} + + +/* +** Push on the Lua stack all values generated by nested captures inside +** the current capture. Returns number of values pushed. 'addextra' +** makes it push the entire match after all captured values. The +** entire match is pushed also if there are no other nested values, +** so the function never returns zero. +*/ +static int pushnestedvalues (CapState *cs, int addextra) { + Capture *co = cs->cap; + if (isfullcap(cs->cap++)) { /* no nested captures? */ + lua_pushlstring(cs->L, co->s, co->siz - 1); /* push whole match */ + return 1; /* that is it */ + } + else { + int n = 0; + while (!isclosecap(cs->cap)) /* repeat for all nested patterns */ + n += pushcapture(cs); + if (addextra || n == 0) { /* need extra? */ + lua_pushlstring(cs->L, co->s, cs->cap->s - co->s); /* push whole match */ + n++; + } + cs->cap++; /* skip close entry */ + return n; + } +} + + +/* +** Push only the first value generated by nested captures +*/ +static void pushonenestedvalue (CapState *cs) { + int n = pushnestedvalues(cs, 0); + if (n > 1) + lua_pop(cs->L, n - 1); /* pop extra values */ +} + + +/* +** Try to find a named group capture with the name given at the top of +** the stack; goes backward from 'cap'. +*/ +static Capture *findback (CapState *cs, Capture *cap) { + lua_State *L = cs->L; + while (cap-- > cs->ocap) { /* repeat until end of list */ + if (isclosecap(cap)) + cap = findopen(cap); /* skip nested captures */ + else if (!isfullcap(cap)) + continue; /* opening an enclosing capture: skip and get previous */ + if (captype(cap) == Cgroup) { + getfromktable(cs, cap->idx); /* get group name */ + if (lp_equal(L, -2, -1)) { /* right group? */ + lua_pop(L, 2); /* remove reference name and group name */ + return cap; + } + else lua_pop(L, 1); /* remove group name */ + } + } + luaL_error(L, "back reference '%s' not found", lua_tostring(L, -1)); + return NULL; /* to avoid warnings */ +} + + +/* +** Back-reference capture. Return number of values pushed. +*/ +static int backrefcap (CapState *cs) { + int n; + Capture *curr = cs->cap; + pushluaval(cs); /* reference name */ + cs->cap = findback(cs, curr); /* find corresponding group */ + n = pushnestedvalues(cs, 0); /* push group's values */ + cs->cap = curr + 1; + return n; +} + + +/* +** Table capture: creates a new table and populates it with nested +** captures. +*/ +static int tablecap (CapState *cs) { + lua_State *L = cs->L; + int n = 0; + lua_newtable(L); + if (isfullcap(cs->cap++)) + return 1; /* table is empty */ + while (!isclosecap(cs->cap)) { + if (captype(cs->cap) == Cgroup && cs->cap->idx != 0) { /* named group? */ + pushluaval(cs); /* push group name */ + pushonenestedvalue(cs); + lua_settable(L, -3); + } + else { /* not a named group */ + int i; + int k = pushcapture(cs); + for (i = k; i > 0; i--) /* store all values into table */ + lua_rawseti(L, -(i + 1), n + i); + n += k; + } + } + cs->cap++; /* skip close entry */ + return 1; /* number of values pushed (only the table) */ +} + + +/* +** Table-query capture +*/ +static int querycap (CapState *cs) { + int idx = cs->cap->idx; + pushonenestedvalue(cs); /* get nested capture */ + lua_gettable(cs->L, updatecache(cs, idx)); /* query cap. value at table */ + if (!lua_isnil(cs->L, -1)) + return 1; + else { /* no value */ + lua_pop(cs->L, 1); /* remove nil */ + return 0; + } +} + + +/* +** Fold capture +*/ +static int foldcap (CapState *cs) { + int n; + lua_State *L = cs->L; + int idx = cs->cap->idx; + if (isfullcap(cs->cap++) || /* no nested captures? */ + isclosecap(cs->cap) || /* no nested captures (large subject)? */ + (n = pushcapture(cs)) == 0) /* nested captures with no values? */ + return luaL_error(L, "no initial value for fold capture"); + if (n > 1) + lua_pop(L, n - 1); /* leave only one result for accumulator */ + while (!isclosecap(cs->cap)) { + lua_pushvalue(L, updatecache(cs, idx)); /* get folding function */ + lua_insert(L, -2); /* put it before accumulator */ + n = pushcapture(cs); /* get next capture's values */ + lua_call(L, n + 1, 1); /* call folding function */ + } + cs->cap++; /* skip close entry */ + return 1; /* only accumulator left on the stack */ +} + + +/* +** Function capture +*/ +static int functioncap (CapState *cs) { + int n; + int top = lua_gettop(cs->L); + pushluaval(cs); /* push function */ + n = pushnestedvalues(cs, 0); /* push nested captures */ + lua_call(cs->L, n, LUA_MULTRET); /* call function */ + return lua_gettop(cs->L) - top; /* return function's results */ +} + + +/* +** Select capture +*/ +static int numcap (CapState *cs) { + int idx = cs->cap->idx; /* value to select */ + if (idx == 0) { /* no values? */ + nextcap(cs); /* skip entire capture */ + return 0; /* no value produced */ + } + else { + int n = pushnestedvalues(cs, 0); + if (n < idx) /* invalid index? */ + return luaL_error(cs->L, "no capture '%d'", idx); + else { + lua_pushvalue(cs->L, -(n - idx + 1)); /* get selected capture */ + lua_replace(cs->L, -(n + 1)); /* put it in place of 1st capture */ + lua_pop(cs->L, n - 1); /* remove other captures */ + return 1; + } + } +} + + +/* +** Return the stack index of the first runtime capture in the given +** list of captures (or zero if no runtime captures) +*/ +int finddyncap (Capture *cap, Capture *last) { + for (; cap < last; cap++) { + if (cap->kind == Cruntime) + return cap->idx; /* stack position of first capture */ + } + return 0; /* no dynamic captures in this segment */ +} + + +/* +** Calls a runtime capture. Returns number of captures removed by +** the call, including the initial Cgroup. (Captures to be added are +** on the Lua stack.) +*/ +int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) { + int n, id; + lua_State *L = cs->L; + int otop = lua_gettop(L); + Capture *open = findopen(close); + assert(captype(open) == Cgroup); + id = finddyncap(open, close); /* get first dynamic capture argument */ + close->kind = Cclose; /* closes the group */ + close->s = s; + cs->cap = open; cs->valuecached = 0; /* prepare capture state */ + luaL_checkstack(L, 4, "too many runtime captures"); + pushluaval(cs); /* push function to be called */ + lua_pushvalue(L, SUBJIDX); /* push original subject */ + lua_pushinteger(L, s - cs->s + 1); /* push current position */ + n = pushnestedvalues(cs, 0); /* push nested captures */ + lua_call(L, n + 2, LUA_MULTRET); /* call dynamic function */ + if (id > 0) { /* are there old dynamic captures to be removed? */ + int i; + for (i = id; i <= otop; i++) + lua_remove(L, id); /* remove old dynamic captures */ + *rem = otop - id + 1; /* total number of dynamic captures removed */ + } + else + *rem = 0; /* no dynamic captures removed */ + return close - open; /* number of captures of all kinds removed */ +} + + +/* +** Auxiliary structure for substitution and string captures: keep +** information about nested captures for future use, avoiding to push +** string results into Lua +*/ +typedef struct StrAux { + int isstring; /* whether capture is a string */ + union { + Capture *cp; /* if not a string, respective capture */ + struct { /* if it is a string... */ + const char *s; /* ... starts here */ + const char *e; /* ... ends here */ + } s; + } u; +} StrAux; + +#define MAXSTRCAPS 10 + +/* +** Collect values from current capture into array 'cps'. Current +** capture must be Cstring (first call) or Csimple (recursive calls). +** (In first call, fills %0 with whole match for Cstring.) +** Returns number of elements in the array that were filled. +*/ +static int getstrcaps (CapState *cs, StrAux *cps, int n) { + int k = n++; + cps[k].isstring = 1; /* get string value */ + cps[k].u.s.s = cs->cap->s; /* starts here */ + if (!isfullcap(cs->cap++)) { /* nested captures? */ + while (!isclosecap(cs->cap)) { /* traverse them */ + if (n >= MAXSTRCAPS) /* too many captures? */ + nextcap(cs); /* skip extra captures (will not need them) */ + else if (captype(cs->cap) == Csimple) /* string? */ + n = getstrcaps(cs, cps, n); /* put info. into array */ + else { + cps[n].isstring = 0; /* not a string */ + cps[n].u.cp = cs->cap; /* keep original capture */ + nextcap(cs); + n++; + } + } + cs->cap++; /* skip close */ + } + cps[k].u.s.e = closeaddr(cs->cap - 1); /* ends here */ + return n; +} + + +/* +** add next capture value (which should be a string) to buffer 'b' +*/ +static int addonestring (luaL_Buffer *b, CapState *cs, const char *what); + + +/* +** String capture: add result to buffer 'b' (instead of pushing +** it into the stack) +*/ +static void stringcap (luaL_Buffer *b, CapState *cs) { + StrAux cps[MAXSTRCAPS]; + int n; + size_t len, i; + const char *fmt; /* format string */ + fmt = lua_tolstring(cs->L, updatecache(cs, cs->cap->idx), &len); + n = getstrcaps(cs, cps, 0) - 1; /* collect nested captures */ + for (i = 0; i < len; i++) { /* traverse them */ + if (fmt[i] != '%') /* not an escape? */ + luaL_addchar(b, fmt[i]); /* add it to buffer */ + else if (fmt[++i] < '0' || fmt[i] > '9') /* not followed by a digit? */ + luaL_addchar(b, fmt[i]); /* add to buffer */ + else { + int l = fmt[i] - '0'; /* capture index */ + if (l > n) + luaL_error(cs->L, "invalid capture index (%d)", l); + else if (cps[l].isstring) + luaL_addlstring(b, cps[l].u.s.s, cps[l].u.s.e - cps[l].u.s.s); + else { + Capture *curr = cs->cap; + cs->cap = cps[l].u.cp; /* go back to evaluate that nested capture */ + if (!addonestring(b, cs, "capture")) + luaL_error(cs->L, "no values in capture index %d", l); + cs->cap = curr; /* continue from where it stopped */ + } + } + } +} + + +/* +** Substitution capture: add result to buffer 'b' +*/ +static void substcap (luaL_Buffer *b, CapState *cs) { + const char *curr = cs->cap->s; + if (isfullcap(cs->cap)) /* no nested captures? */ + luaL_addlstring(b, curr, cs->cap->siz - 1); /* keep original text */ + else { + cs->cap++; /* skip open entry */ + while (!isclosecap(cs->cap)) { /* traverse nested captures */ + const char *next = cs->cap->s; + luaL_addlstring(b, curr, next - curr); /* add text up to capture */ + if (addonestring(b, cs, "replacement")) + curr = closeaddr(cs->cap - 1); /* continue after match */ + else /* no capture value */ + curr = next; /* keep original text in final result */ + } + luaL_addlstring(b, curr, cs->cap->s - curr); /* add last piece of text */ + } + cs->cap++; /* go to next capture */ +} + + +/* +** Evaluates a capture and adds its first value to buffer 'b'; returns +** whether there was a value +*/ +static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) { + switch (captype(cs->cap)) { + case Cstring: + stringcap(b, cs); /* add capture directly to buffer */ + return 1; + case Csubst: + substcap(b, cs); /* add capture directly to buffer */ + return 1; + default: { + lua_State *L = cs->L; + int n = pushcapture(cs); + if (n > 0) { + if (n > 1) lua_pop(L, n - 1); /* only one result */ + if (!lua_isstring(L, -1)) + luaL_error(L, "invalid %s value (a %s)", what, luaL_typename(L, -1)); + luaL_addvalue(b); + } + return n; + } + } +} + + +/* +** Push all values of the current capture into the stack; returns +** number of values pushed +*/ +static int pushcapture (CapState *cs) { + lua_State *L = cs->L; + luaL_checkstack(L, 4, "too many captures"); + switch (captype(cs->cap)) { + case Cposition: { + lua_pushinteger(L, cs->cap->s - cs->s + 1); + cs->cap++; + return 1; + } + case Cconst: { + pushluaval(cs); + cs->cap++; + return 1; + } + case Carg: { + int arg = (cs->cap++)->idx; + if (arg + FIXEDARGS > cs->ptop) + return luaL_error(L, "reference to absent extra argument #%d", arg); + lua_pushvalue(L, arg + FIXEDARGS); + return 1; + } + case Csimple: { + int k = pushnestedvalues(cs, 1); + lua_insert(L, -k); /* make whole match be first result */ + return k; + } + case Cruntime: { + lua_pushvalue(L, (cs->cap++)->idx); /* value is in the stack */ + return 1; + } + case Cstring: { + luaL_Buffer b; + luaL_buffinit(L, &b); + stringcap(&b, cs); + luaL_pushresult(&b); + return 1; + } + case Csubst: { + luaL_Buffer b; + luaL_buffinit(L, &b); + substcap(&b, cs); + luaL_pushresult(&b); + return 1; + } + case Cgroup: { + if (cs->cap->idx == 0) /* anonymous group? */ + return pushnestedvalues(cs, 0); /* add all nested values */ + else { /* named group: add no values */ + nextcap(cs); /* skip capture */ + return 0; + } + } + case Cbackref: return backrefcap(cs); + case Ctable: return tablecap(cs); + case Cfunction: return functioncap(cs); + case Cnum: return numcap(cs); + case Cquery: return querycap(cs); + case Cfold: return foldcap(cs); + default: assert(0); return 0; + } +} + + +/* +** Prepare a CapState structure and traverse the entire list of +** captures in the stack pushing its results. 's' is the subject +** string, 'r' is the final position of the match, and 'ptop' +** the index in the stack where some useful values were pushed. +** Returns the number of results pushed. (If the list produces no +** results, push the final position of the match.) +*/ +int getcaptures (lua_State *L, const char *s, const char *r, int ptop) { + Capture *capture = (Capture *)lua_touserdata(L, caplistidx(ptop)); + int n = 0; + if (!isclosecap(capture)) { /* is there any capture? */ + CapState cs; + cs.ocap = cs.cap = capture; cs.L = L; + cs.s = s; cs.valuecached = 0; cs.ptop = ptop; + do { /* collect their values */ + n += pushcapture(&cs); + } while (!isclosecap(cs.cap)); + } + if (n == 0) { /* no capture values? */ + lua_pushinteger(L, r - s + 1); /* return only end position */ + n = 1; + } + return n; +} + + diff --git a/luaclib/lpeg/lpcap.h b/luaclib/lpeg/lpcap.h new file mode 100644 index 0000000..d762fdc --- /dev/null +++ b/luaclib/lpeg/lpcap.h @@ -0,0 +1,43 @@ +/* +** $Id: lpcap.h,v 1.2 2015/02/27 17:13:17 roberto Exp $ +*/ + +#if !defined(lpcap_h) +#define lpcap_h + + +#include "lptypes.h" + + +/* kinds of captures */ +typedef enum CapKind { + Cclose, Cposition, Cconst, Cbackref, Carg, Csimple, Ctable, Cfunction, + Cquery, Cstring, Cnum, Csubst, Cfold, Cruntime, Cgroup +} CapKind; + + +typedef struct Capture { + const char *s; /* subject position */ + unsigned short idx; /* extra info (group name, arg index, etc.) */ + byte kind; /* kind of capture */ + byte siz; /* size of full capture + 1 (0 = not a full capture) */ +} Capture; + + +typedef struct CapState { + Capture *cap; /* current capture */ + Capture *ocap; /* (original) capture list */ + lua_State *L; + int ptop; /* index of last argument to 'match' */ + const char *s; /* original string */ + int valuecached; /* value stored in cache slot */ +} CapState; + + +int runtimecap (CapState *cs, Capture *close, const char *s, int *rem); +int getcaptures (lua_State *L, const char *s, const char *r, int ptop); +int finddyncap (Capture *cap, Capture *last); + +#endif + + diff --git a/luaclib/lpeg/lpcode.c b/luaclib/lpeg/lpcode.c new file mode 100644 index 0000000..fbf44fe --- /dev/null +++ b/luaclib/lpeg/lpcode.c @@ -0,0 +1,986 @@ +/* +** $Id: lpcode.c,v 1.23 2015/06/12 18:36:47 roberto Exp $ +** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) +*/ + +#include + + +#include "lua.h" +#include "lauxlib.h" + +#include "lptypes.h" +#include "lpcode.h" + + +/* signals a "no-instruction */ +#define NOINST -1 + + + +static const Charset fullset_ = + {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; + +static const Charset *fullset = &fullset_; + +/* +** {====================================================== +** Analysis and some optimizations +** ======================================================= +*/ + +/* +** Check whether a charset is empty (returns IFail), singleton (IChar), +** full (IAny), or none of those (ISet). When singleton, '*c' returns +** which character it is. (When generic set, the set was the input, +** so there is no need to return it.) +*/ +static Opcode charsettype (const byte *cs, int *c) { + int count = 0; /* number of characters in the set */ + int i; + int candidate = -1; /* candidate position for the singleton char */ + for (i = 0; i < CHARSETSIZE; i++) { /* for each byte */ + int b = cs[i]; + if (b == 0) { /* is byte empty? */ + if (count > 1) /* was set neither empty nor singleton? */ + return ISet; /* neither full nor empty nor singleton */ + /* else set is still empty or singleton */ + } + else if (b == 0xFF) { /* is byte full? */ + if (count < (i * BITSPERCHAR)) /* was set not full? */ + return ISet; /* neither full nor empty nor singleton */ + else count += BITSPERCHAR; /* set is still full */ + } + else if ((b & (b - 1)) == 0) { /* has byte only one bit? */ + if (count > 0) /* was set not empty? */ + return ISet; /* neither full nor empty nor singleton */ + else { /* set has only one char till now; track it */ + count++; + candidate = i; + } + } + else return ISet; /* byte is neither empty, full, nor singleton */ + } + switch (count) { + case 0: return IFail; /* empty set */ + case 1: { /* singleton; find character bit inside byte */ + int b = cs[candidate]; + *c = candidate * BITSPERCHAR; + if ((b & 0xF0) != 0) { *c += 4; b >>= 4; } + if ((b & 0x0C) != 0) { *c += 2; b >>= 2; } + if ((b & 0x02) != 0) { *c += 1; } + return IChar; + } + default: { + assert(count == CHARSETSIZE * BITSPERCHAR); /* full set */ + return IAny; + } + } +} + + +/* +** A few basic operations on Charsets +*/ +static void cs_complement (Charset *cs) { + loopset(i, cs->cs[i] = ~cs->cs[i]); +} + +static int cs_equal (const byte *cs1, const byte *cs2) { + loopset(i, if (cs1[i] != cs2[i]) return 0); + return 1; +} + +static int cs_disjoint (const Charset *cs1, const Charset *cs2) { + loopset(i, if ((cs1->cs[i] & cs2->cs[i]) != 0) return 0;) + return 1; +} + + +/* +** If 'tree' is a 'char' pattern (TSet, TChar, TAny), convert it into a +** charset and return 1; else return 0. +*/ +int tocharset (TTree *tree, Charset *cs) { + switch (tree->tag) { + case TSet: { /* copy set */ + loopset(i, cs->cs[i] = treebuffer(tree)[i]); + return 1; + } + case TChar: { /* only one char */ + assert(0 <= tree->u.n && tree->u.n <= UCHAR_MAX); + loopset(i, cs->cs[i] = 0); /* erase all chars */ + setchar(cs->cs, tree->u.n); /* add that one */ + return 1; + } + case TAny: { + loopset(i, cs->cs[i] = 0xFF); /* add all characters to the set */ + return 1; + } + default: return 0; + } +} + + +/* +** Check whether a pattern tree has captures +*/ +int hascaptures (TTree *tree) { + tailcall: + switch (tree->tag) { + case TCapture: case TRunTime: + return 1; + case TCall: + tree = sib2(tree); goto tailcall; /* return hascaptures(sib2(tree)); */ + case TOpenCall: assert(0); + default: { + switch (numsiblings[tree->tag]) { + case 1: /* return hascaptures(sib1(tree)); */ + tree = sib1(tree); goto tailcall; + case 2: + if (hascaptures(sib1(tree))) return 1; + /* else return hascaptures(sib2(tree)); */ + tree = sib2(tree); goto tailcall; + default: assert(numsiblings[tree->tag] == 0); return 0; + } + } + } +} + + +/* +** Checks how a pattern behaves regarding the empty string, +** in one of two different ways: +** A pattern is *nullable* if it can match without consuming any character; +** A pattern is *nofail* if it never fails for any string +** (including the empty string). +** The difference is only for predicates and run-time captures; +** for other patterns, the two properties are equivalent. +** (With predicates, &'a' is nullable but not nofail. Of course, +** nofail => nullable.) +** These functions are all convervative in the following way: +** p is nullable => nullable(p) +** nofail(p) => p cannot fail +** The function assumes that TOpenCall is not nullable; +** this will be checked again when the grammar is fixed. +** Run-time captures can do whatever they want, so the result +** is conservative. +*/ +int checkaux (TTree *tree, int pred) { + tailcall: + switch (tree->tag) { + case TChar: case TSet: case TAny: + case TFalse: case TOpenCall: + return 0; /* not nullable */ + case TRep: case TTrue: + return 1; /* no fail */ + case TNot: case TBehind: /* can match empty, but can fail */ + if (pred == PEnofail) return 0; + else return 1; /* PEnullable */ + case TAnd: /* can match empty; fail iff body does */ + if (pred == PEnullable) return 1; + /* else return checkaux(sib1(tree), pred); */ + tree = sib1(tree); goto tailcall; + case TRunTime: /* can fail; match empty iff body does */ + if (pred == PEnofail) return 0; + /* else return checkaux(sib1(tree), pred); */ + tree = sib1(tree); goto tailcall; + case TSeq: + if (!checkaux(sib1(tree), pred)) return 0; + /* else return checkaux(sib2(tree), pred); */ + tree = sib2(tree); goto tailcall; + case TChoice: + if (checkaux(sib2(tree), pred)) return 1; + /* else return checkaux(sib1(tree), pred); */ + tree = sib1(tree); goto tailcall; + case TCapture: case TGrammar: case TRule: + /* return checkaux(sib1(tree), pred); */ + tree = sib1(tree); goto tailcall; + case TCall: /* return checkaux(sib2(tree), pred); */ + tree = sib2(tree); goto tailcall; + default: assert(0); return 0; + } +} + + +/* +** number of characters to match a pattern (or -1 if variable) +** ('count' avoids infinite loops for grammars) +*/ +int fixedlenx (TTree *tree, int count, int len) { + tailcall: + switch (tree->tag) { + case TChar: case TSet: case TAny: + return len + 1; + case TFalse: case TTrue: case TNot: case TAnd: case TBehind: + return len; + case TRep: case TRunTime: case TOpenCall: + return -1; + case TCapture: case TRule: case TGrammar: + /* return fixedlenx(sib1(tree), count); */ + tree = sib1(tree); goto tailcall; + case TCall: + if (count++ >= MAXRULES) + return -1; /* may be a loop */ + /* else return fixedlenx(sib2(tree), count); */ + tree = sib2(tree); goto tailcall; + case TSeq: { + len = fixedlenx(sib1(tree), count, len); + if (len < 0) return -1; + /* else return fixedlenx(sib2(tree), count, len); */ + tree = sib2(tree); goto tailcall; + } + case TChoice: { + int n1, n2; + n1 = fixedlenx(sib1(tree), count, len); + if (n1 < 0) return -1; + n2 = fixedlenx(sib2(tree), count, len); + if (n1 == n2) return n1; + else return -1; + } + default: assert(0); return 0; + }; +} + + +/* +** Computes the 'first set' of a pattern. +** The result is a conservative aproximation: +** match p ax -> x (for some x) ==> a belongs to first(p) +** or +** a not in first(p) ==> match p ax -> fail (for all x) +** +** The set 'follow' is the first set of what follows the +** pattern (full set if nothing follows it). +** +** The function returns 0 when this resulting set can be used for +** test instructions that avoid the pattern altogether. +** A non-zero return can happen for two reasons: +** 1) match p '' -> '' ==> return has bit 1 set +** (tests cannot be used because they would always fail for an empty input); +** 2) there is a match-time capture ==> return has bit 2 set +** (optimizations should not bypass match-time captures). +*/ +static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) { + tailcall: + switch (tree->tag) { + case TChar: case TSet: case TAny: { + tocharset(tree, firstset); + return 0; + } + case TTrue: { + loopset(i, firstset->cs[i] = follow->cs[i]); + return 1; /* accepts the empty string */ + } + case TFalse: { + loopset(i, firstset->cs[i] = 0); + return 0; + } + case TChoice: { + Charset csaux; + int e1 = getfirst(sib1(tree), follow, firstset); + int e2 = getfirst(sib2(tree), follow, &csaux); + loopset(i, firstset->cs[i] |= csaux.cs[i]); + return e1 | e2; + } + case TSeq: { + if (!nullable(sib1(tree))) { + /* when p1 is not nullable, p2 has nothing to contribute; + return getfirst(sib1(tree), fullset, firstset); */ + tree = sib1(tree); follow = fullset; goto tailcall; + } + else { /* FIRST(p1 p2, fl) = FIRST(p1, FIRST(p2, fl)) */ + Charset csaux; + int e2 = getfirst(sib2(tree), follow, &csaux); + int e1 = getfirst(sib1(tree), &csaux, firstset); + if (e1 == 0) return 0; /* 'e1' ensures that first can be used */ + else if ((e1 | e2) & 2) /* one of the children has a matchtime? */ + return 2; /* pattern has a matchtime capture */ + else return e2; /* else depends on 'e2' */ + } + } + case TRep: { + getfirst(sib1(tree), follow, firstset); + loopset(i, firstset->cs[i] |= follow->cs[i]); + return 1; /* accept the empty string */ + } + case TCapture: case TGrammar: case TRule: { + /* return getfirst(sib1(tree), follow, firstset); */ + tree = sib1(tree); goto tailcall; + } + case TRunTime: { /* function invalidates any follow info. */ + int e = getfirst(sib1(tree), fullset, firstset); + if (e) return 2; /* function is not "protected"? */ + else return 0; /* pattern inside capture ensures first can be used */ + } + case TCall: { + /* return getfirst(sib2(tree), follow, firstset); */ + tree = sib2(tree); goto tailcall; + } + case TAnd: { + int e = getfirst(sib1(tree), follow, firstset); + loopset(i, firstset->cs[i] &= follow->cs[i]); + return e; + } + case TNot: { + if (tocharset(sib1(tree), firstset)) { + cs_complement(firstset); + return 1; + } + /* else go through */ + } + case TBehind: { /* instruction gives no new information */ + /* call 'getfirst' only to check for math-time captures */ + int e = getfirst(sib1(tree), follow, firstset); + loopset(i, firstset->cs[i] = follow->cs[i]); /* uses follow */ + return e | 1; /* always can accept the empty string */ + } + default: assert(0); return 0; + } +} + + +/* +** If 'headfail(tree)' true, then 'tree' can fail only depending on the +** next character of the subject. +*/ +static int headfail (TTree *tree) { + tailcall: + switch (tree->tag) { + case TChar: case TSet: case TAny: case TFalse: + return 1; + case TTrue: case TRep: case TRunTime: case TNot: + case TBehind: + return 0; + case TCapture: case TGrammar: case TRule: case TAnd: + tree = sib1(tree); goto tailcall; /* return headfail(sib1(tree)); */ + case TCall: + tree = sib2(tree); goto tailcall; /* return headfail(sib2(tree)); */ + case TSeq: + if (!nofail(sib2(tree))) return 0; + /* else return headfail(sib1(tree)); */ + tree = sib1(tree); goto tailcall; + case TChoice: + if (!headfail(sib1(tree))) return 0; + /* else return headfail(sib2(tree)); */ + tree = sib2(tree); goto tailcall; + default: assert(0); return 0; + } +} + + +/* +** Check whether the code generation for the given tree can benefit +** from a follow set (to avoid computing the follow set when it is +** not needed) +*/ +static int needfollow (TTree *tree) { + tailcall: + switch (tree->tag) { + case TChar: case TSet: case TAny: + case TFalse: case TTrue: case TAnd: case TNot: + case TRunTime: case TGrammar: case TCall: case TBehind: + return 0; + case TChoice: case TRep: + return 1; + case TCapture: + tree = sib1(tree); goto tailcall; + case TSeq: + tree = sib2(tree); goto tailcall; + default: assert(0); return 0; + } +} + +/* }====================================================== */ + + + +/* +** {====================================================== +** Code generation +** ======================================================= +*/ + + +/* +** size of an instruction +*/ +int sizei (const Instruction *i) { + switch((Opcode)i->i.code) { + case ISet: case ISpan: return CHARSETINSTSIZE; + case ITestSet: return CHARSETINSTSIZE + 1; + case ITestChar: case ITestAny: case IChoice: case IJmp: case ICall: + case IOpenCall: case ICommit: case IPartialCommit: case IBackCommit: + return 2; + default: return 1; + } +} + + +/* +** state for the compiler +*/ +typedef struct CompileState { + Pattern *p; /* pattern being compiled */ + int ncode; /* next position in p->code to be filled */ + lua_State *L; +} CompileState; + + +/* +** code generation is recursive; 'opt' indicates that the code is being +** generated as the last thing inside an optional pattern (so, if that +** code is optional too, it can reuse the 'IChoice' already in place for +** the outer pattern). 'tt' points to a previous test protecting this +** code (or NOINST). 'fl' is the follow set of the pattern. +*/ +static void codegen (CompileState *compst, TTree *tree, int opt, int tt, + const Charset *fl); + + +void realloccode (lua_State *L, Pattern *p, int nsize) { + void *ud; + lua_Alloc f = lua_getallocf(L, &ud); + void *newblock = f(ud, p->code, p->codesize * sizeof(Instruction), + nsize * sizeof(Instruction)); + if (newblock == NULL && nsize > 0) + luaL_error(L, "not enough memory"); + p->code = (Instruction *)newblock; + p->codesize = nsize; +} + + +static int nextinstruction (CompileState *compst) { + int size = compst->p->codesize; + if (compst->ncode >= size) + realloccode(compst->L, compst->p, size * 2); + return compst->ncode++; +} + + +#define getinstr(cs,i) ((cs)->p->code[i]) + + +static int addinstruction (CompileState *compst, Opcode op, int aux) { + int i = nextinstruction(compst); + getinstr(compst, i).i.code = op; + getinstr(compst, i).i.aux = aux; + return i; +} + + +/* +** Add an instruction followed by space for an offset (to be set later) +*/ +static int addoffsetinst (CompileState *compst, Opcode op) { + int i = addinstruction(compst, op, 0); /* instruction */ + addinstruction(compst, (Opcode)0, 0); /* open space for offset */ + assert(op == ITestSet || sizei(&getinstr(compst, i)) == 2); + return i; +} + + +/* +** Set the offset of an instruction +*/ +static void setoffset (CompileState *compst, int instruction, int offset) { + getinstr(compst, instruction + 1).offset = offset; +} + + +/* +** Add a capture instruction: +** 'op' is the capture instruction; 'cap' the capture kind; +** 'key' the key into ktable; 'aux' is the optional capture offset +** +*/ +static int addinstcap (CompileState *compst, Opcode op, int cap, int key, + int aux) { + int i = addinstruction(compst, op, joinkindoff(cap, aux)); + getinstr(compst, i).i.key = key; + return i; +} + + +#define gethere(compst) ((compst)->ncode) + +#define target(code,i) ((i) + code[i + 1].offset) + + +/* +** Patch 'instruction' to jump to 'target' +*/ +static void jumptothere (CompileState *compst, int instruction, int target) { + if (instruction >= 0) + setoffset(compst, instruction, target - instruction); +} + + +/* +** Patch 'instruction' to jump to current position +*/ +static void jumptohere (CompileState *compst, int instruction) { + jumptothere(compst, instruction, gethere(compst)); +} + + +/* +** Code an IChar instruction, or IAny if there is an equivalent +** test dominating it +*/ +static void codechar (CompileState *compst, int c, int tt) { + if (tt >= 0 && getinstr(compst, tt).i.code == ITestChar && + getinstr(compst, tt).i.aux == c) + addinstruction(compst, IAny, 0); + else + addinstruction(compst, IChar, c); +} + + +/* +** Add a charset posfix to an instruction +*/ +static void addcharset (CompileState *compst, const byte *cs) { + int p = gethere(compst); + int i; + for (i = 0; i < (int)CHARSETINSTSIZE - 1; i++) + nextinstruction(compst); /* space for buffer */ + /* fill buffer with charset */ + loopset(j, getinstr(compst, p).buff[j] = cs[j]); +} + + +/* +** code a char set, optimizing unit sets for IChar, "complete" +** sets for IAny, and empty sets for IFail; also use an IAny +** when instruction is dominated by an equivalent test. +*/ +static void codecharset (CompileState *compst, const byte *cs, int tt) { + int c = 0; /* (=) to avoid warnings */ + Opcode op = charsettype(cs, &c); + switch (op) { + case IChar: codechar(compst, c, tt); break; + case ISet: { /* non-trivial set? */ + if (tt >= 0 && getinstr(compst, tt).i.code == ITestSet && + cs_equal(cs, getinstr(compst, tt + 2).buff)) + addinstruction(compst, IAny, 0); + else { + addinstruction(compst, ISet, 0); + addcharset(compst, cs); + } + break; + } + default: addinstruction(compst, op, c); break; + } +} + + +/* +** code a test set, optimizing unit sets for ITestChar, "complete" +** sets for ITestAny, and empty sets for IJmp (always fails). +** 'e' is true iff test should accept the empty string. (Test +** instructions in the current VM never accept the empty string.) +*/ +static int codetestset (CompileState *compst, Charset *cs, int e) { + if (e) return NOINST; /* no test */ + else { + int c = 0; + Opcode op = charsettype(cs->cs, &c); + switch (op) { + case IFail: return addoffsetinst(compst, IJmp); /* always jump */ + case IAny: return addoffsetinst(compst, ITestAny); + case IChar: { + int i = addoffsetinst(compst, ITestChar); + getinstr(compst, i).i.aux = c; + return i; + } + case ISet: { + int i = addoffsetinst(compst, ITestSet); + addcharset(compst, cs->cs); + return i; + } + default: assert(0); return 0; + } + } +} + + +/* +** Find the final destination of a sequence of jumps +*/ +static int finaltarget (Instruction *code, int i) { + while (code[i].i.code == IJmp) + i = target(code, i); + return i; +} + + +/* +** final label (after traversing any jumps) +*/ +static int finallabel (Instruction *code, int i) { + return finaltarget(code, target(code, i)); +} + + +/* +** == behind n;

(where n = fixedlen(p)) +*/ +static void codebehind (CompileState *compst, TTree *tree) { + if (tree->u.n > 0) + addinstruction(compst, IBehind, tree->u.n); + codegen(compst, sib1(tree), 0, NOINST, fullset); +} + + +/* +** Choice; optimizations: +** - when p1 is headfail or +** when first(p1) and first(p2) are disjoint, than +** a character not in first(p1) cannot go to p1, and a character +** in first(p1) cannot go to p2 (at it is not in first(p2)). +** (The optimization is not valid if p1 accepts the empty string, +** as then there is no character at all...) +** - when p2 is empty and opt is true; a IPartialCommit can reuse +** the Choice already active in the stack. +*/ +static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt, + const Charset *fl) { + int emptyp2 = (p2->tag == TTrue); + Charset cs1, cs2; + int e1 = getfirst(p1, fullset, &cs1); + if (headfail(p1) || + (!e1 && (getfirst(p2, fl, &cs2), cs_disjoint(&cs1, &cs2)))) { + /* == test (fail(p1)) -> L1 ; p1 ; jmp L2; L1: p2; L2: */ + int test = codetestset(compst, &cs1, 0); + int jmp = NOINST; + codegen(compst, p1, 0, test, fl); + if (!emptyp2) + jmp = addoffsetinst(compst, IJmp); + jumptohere(compst, test); + codegen(compst, p2, opt, NOINST, fl); + jumptohere(compst, jmp); + } + else if (opt && emptyp2) { + /* p1? == IPartialCommit; p1 */ + jumptohere(compst, addoffsetinst(compst, IPartialCommit)); + codegen(compst, p1, 1, NOINST, fullset); + } + else { + /* == + test(first(p1)) -> L1; choice L1; ; commit L2; L1: ; L2: */ + int pcommit; + int test = codetestset(compst, &cs1, e1); + int pchoice = addoffsetinst(compst, IChoice); + codegen(compst, p1, emptyp2, test, fullset); + pcommit = addoffsetinst(compst, ICommit); + jumptohere(compst, pchoice); + jumptohere(compst, test); + codegen(compst, p2, opt, NOINST, fl); + jumptohere(compst, pcommit); + } +} + + +/* +** And predicate +** optimization: fixedlen(p) = n ==> <&p> ==

; behind n +** (valid only when 'p' has no captures) +*/ +static void codeand (CompileState *compst, TTree *tree, int tt) { + int n = fixedlen(tree); + if (n >= 0 && n <= MAXBEHIND && !hascaptures(tree)) { + codegen(compst, tree, 0, tt, fullset); + if (n > 0) + addinstruction(compst, IBehind, n); + } + else { /* default: Choice L1; p1; BackCommit L2; L1: Fail; L2: */ + int pcommit; + int pchoice = addoffsetinst(compst, IChoice); + codegen(compst, tree, 0, tt, fullset); + pcommit = addoffsetinst(compst, IBackCommit); + jumptohere(compst, pchoice); + addinstruction(compst, IFail, 0); + jumptohere(compst, pcommit); + } +} + + +/* +** Captures: if pattern has fixed (and not too big) length, use +** a single IFullCapture instruction after the match; otherwise, +** enclose the pattern with OpenCapture - CloseCapture. +*/ +static void codecapture (CompileState *compst, TTree *tree, int tt, + const Charset *fl) { + int len = fixedlen(sib1(tree)); + if (len >= 0 && len <= MAXOFF && !hascaptures(sib1(tree))) { + codegen(compst, sib1(tree), 0, tt, fl); + addinstcap(compst, IFullCapture, tree->cap, tree->key, len); + } + else { + addinstcap(compst, IOpenCapture, tree->cap, tree->key, 0); + codegen(compst, sib1(tree), 0, tt, fl); + addinstcap(compst, ICloseCapture, Cclose, 0, 0); + } +} + + +static void coderuntime (CompileState *compst, TTree *tree, int tt) { + addinstcap(compst, IOpenCapture, Cgroup, tree->key, 0); + codegen(compst, sib1(tree), 0, tt, fullset); + addinstcap(compst, ICloseRunTime, Cclose, 0, 0); +} + + +/* +** Repetion; optimizations: +** When pattern is a charset, can use special instruction ISpan. +** When pattern is head fail, or if it starts with characters that +** are disjoint from what follows the repetions, a simple test +** is enough (a fail inside the repetition would backtrack to fail +** again in the following pattern, so there is no need for a choice). +** When 'opt' is true, the repetion can reuse the Choice already +** active in the stack. +*/ +static void coderep (CompileState *compst, TTree *tree, int opt, + const Charset *fl) { + Charset st; + if (tocharset(tree, &st)) { + addinstruction(compst, ISpan, 0); + addcharset(compst, st.cs); + } + else { + int e1 = getfirst(tree, fullset, &st); + if (headfail(tree) || (!e1 && cs_disjoint(&st, fl))) { + /* L1: test (fail(p1)) -> L2;

; jmp L1; L2: */ + int jmp; + int test = codetestset(compst, &st, 0); + codegen(compst, tree, 0, test, fullset); + jmp = addoffsetinst(compst, IJmp); + jumptohere(compst, test); + jumptothere(compst, jmp, test); + } + else { + /* test(fail(p1)) -> L2; choice L2; L1:

; partialcommit L1; L2: */ + /* or (if 'opt'): partialcommit L1; L1:

; partialcommit L1; */ + int commit, l2; + int test = codetestset(compst, &st, e1); + int pchoice = NOINST; + if (opt) + jumptohere(compst, addoffsetinst(compst, IPartialCommit)); + else + pchoice = addoffsetinst(compst, IChoice); + l2 = gethere(compst); + codegen(compst, tree, 0, NOINST, fullset); + commit = addoffsetinst(compst, IPartialCommit); + jumptothere(compst, commit, l2); + jumptohere(compst, pchoice); + jumptohere(compst, test); + } + } +} + + +/* +** Not predicate; optimizations: +** In any case, if first test fails, 'not' succeeds, so it can jump to +** the end. If pattern is headfail, that is all (it cannot fail +** in other parts); this case includes 'not' of simple sets. Otherwise, +** use the default code (a choice plus a failtwice). +*/ +static void codenot (CompileState *compst, TTree *tree) { + Charset st; + int e = getfirst(tree, fullset, &st); + int test = codetestset(compst, &st, e); + if (headfail(tree)) /* test (fail(p1)) -> L1; fail; L1: */ + addinstruction(compst, IFail, 0); + else { + /* test(fail(p))-> L1; choice L1;

; failtwice; L1: */ + int pchoice = addoffsetinst(compst, IChoice); + codegen(compst, tree, 0, NOINST, fullset); + addinstruction(compst, IFailTwice, 0); + jumptohere(compst, pchoice); + } + jumptohere(compst, test); +} + + +/* +** change open calls to calls, using list 'positions' to find +** correct offsets; also optimize tail calls +*/ +static void correctcalls (CompileState *compst, int *positions, + int from, int to) { + int i; + Instruction *code = compst->p->code; + for (i = from; i < to; i += sizei(&code[i])) { + if (code[i].i.code == IOpenCall) { + int n = code[i].i.key; /* rule number */ + int rule = positions[n]; /* rule position */ + assert(rule == from || code[rule - 1].i.code == IRet); + if (code[finaltarget(code, i + 2)].i.code == IRet) /* call; ret ? */ + code[i].i.code = IJmp; /* tail call */ + else + code[i].i.code = ICall; + jumptothere(compst, i, rule); /* call jumps to respective rule */ + } + } + assert(i == to); +} + + +/* +** Code for a grammar: +** call L1; jmp L2; L1: rule 1; ret; rule 2; ret; ...; L2: +*/ +static void codegrammar (CompileState *compst, TTree *grammar) { + int positions[MAXRULES]; + int rulenumber = 0; + TTree *rule; + int firstcall = addoffsetinst(compst, ICall); /* call initial rule */ + int jumptoend = addoffsetinst(compst, IJmp); /* jump to the end */ + int start = gethere(compst); /* here starts the initial rule */ + jumptohere(compst, firstcall); + for (rule = sib1(grammar); rule->tag == TRule; rule = sib2(rule)) { + positions[rulenumber++] = gethere(compst); /* save rule position */ + codegen(compst, sib1(rule), 0, NOINST, fullset); /* code rule */ + addinstruction(compst, IRet, 0); + } + assert(rule->tag == TTrue); + jumptohere(compst, jumptoend); + correctcalls(compst, positions, start, gethere(compst)); +} + + +static void codecall (CompileState *compst, TTree *call) { + int c = addoffsetinst(compst, IOpenCall); /* to be corrected later */ + getinstr(compst, c).i.key = sib2(call)->cap; /* rule number */ + assert(sib2(call)->tag == TRule); +} + + +/* +** Code first child of a sequence +** (second child is called in-place to allow tail call) +** Return 'tt' for second child +*/ +static int codeseq1 (CompileState *compst, TTree *p1, TTree *p2, + int tt, const Charset *fl) { + if (needfollow(p1)) { + Charset fl1; + getfirst(p2, fl, &fl1); /* p1 follow is p2 first */ + codegen(compst, p1, 0, tt, &fl1); + } + else /* use 'fullset' as follow */ + codegen(compst, p1, 0, tt, fullset); + if (fixedlen(p1) != 0) /* can 'p1' consume anything? */ + return NOINST; /* invalidate test */ + else return tt; /* else 'tt' still protects sib2 */ +} + + +/* +** Main code-generation function: dispatch to auxiliar functions +** according to kind of tree. ('needfollow' should return true +** only for consructions that use 'fl'.) +*/ +static void codegen (CompileState *compst, TTree *tree, int opt, int tt, + const Charset *fl) { + tailcall: + switch (tree->tag) { + case TChar: codechar(compst, tree->u.n, tt); break; + case TAny: addinstruction(compst, IAny, 0); break; + case TSet: codecharset(compst, treebuffer(tree), tt); break; + case TTrue: break; + case TFalse: addinstruction(compst, IFail, 0); break; + case TChoice: codechoice(compst, sib1(tree), sib2(tree), opt, fl); break; + case TRep: coderep(compst, sib1(tree), opt, fl); break; + case TBehind: codebehind(compst, tree); break; + case TNot: codenot(compst, sib1(tree)); break; + case TAnd: codeand(compst, sib1(tree), tt); break; + case TCapture: codecapture(compst, tree, tt, fl); break; + case TRunTime: coderuntime(compst, tree, tt); break; + case TGrammar: codegrammar(compst, tree); break; + case TCall: codecall(compst, tree); break; + case TSeq: { + tt = codeseq1(compst, sib1(tree), sib2(tree), tt, fl); /* code 'p1' */ + /* codegen(compst, p2, opt, tt, fl); */ + tree = sib2(tree); goto tailcall; + } + default: assert(0); + } +} + + +/* +** Optimize jumps and other jump-like instructions. +** * Update labels of instructions with labels to their final +** destinations (e.g., choice L1; ... L1: jmp L2: becomes +** choice L2) +** * Jumps to other instructions that do jumps become those +** instructions (e.g., jump to return becomes a return; jump +** to commit becomes a commit) +*/ +static void peephole (CompileState *compst) { + Instruction *code = compst->p->code; + int i; + for (i = 0; i < compst->ncode; i += sizei(&code[i])) { + redo: + switch (code[i].i.code) { + case IChoice: case ICall: case ICommit: case IPartialCommit: + case IBackCommit: case ITestChar: case ITestSet: + case ITestAny: { /* instructions with labels */ + jumptothere(compst, i, finallabel(code, i)); /* optimize label */ + break; + } + case IJmp: { + int ft = finaltarget(code, i); + switch (code[ft].i.code) { /* jumping to what? */ + case IRet: case IFail: case IFailTwice: + case IEnd: { /* instructions with unconditional implicit jumps */ + code[i] = code[ft]; /* jump becomes that instruction */ + code[i + 1].i.code = IAny; /* 'no-op' for target position */ + break; + } + case ICommit: case IPartialCommit: + case IBackCommit: { /* inst. with unconditional explicit jumps */ + int fft = finallabel(code, ft); + code[i] = code[ft]; /* jump becomes that instruction... */ + jumptothere(compst, i, fft); /* but must correct its offset */ + goto redo; /* reoptimize its label */ + } + default: { + jumptothere(compst, i, ft); /* optimize label */ + break; + } + } + break; + } + default: break; + } + } + assert(code[i - 1].i.code == IEnd); +} + + +/* +** Compile a pattern +*/ +Instruction *compile (lua_State *L, Pattern *p) { + CompileState compst; + compst.p = p; compst.ncode = 0; compst.L = L; + realloccode(L, p, 2); /* minimum initial size */ + codegen(&compst, p->tree, 0, NOINST, fullset); + addinstruction(&compst, IEnd, 0); + realloccode(L, p, compst.ncode); /* set final size */ + peephole(&compst); + return p->code; +} + + +/* }====================================================== */ + diff --git a/luaclib/lpeg/lpcode.h b/luaclib/lpeg/lpcode.h new file mode 100644 index 0000000..896d3c7 --- /dev/null +++ b/luaclib/lpeg/lpcode.h @@ -0,0 +1,42 @@ +/* +** $Id: lpcode.h,v 1.7 2015/06/12 18:24:45 roberto Exp $ +*/ + +#if !defined(lpcode_h) +#define lpcode_h + +#include "lua.h" + +#include "lptypes.h" +#include "lptree.h" +#include "lpvm.h" + +int tocharset (TTree *tree, Charset *cs); +int checkaux (TTree *tree, int pred); +int fixedlenx (TTree *tree, int count, int len); +int hascaptures (TTree *tree); +int lp_gc (lua_State *L); +Instruction *compile (lua_State *L, Pattern *p); +void realloccode (lua_State *L, Pattern *p, int nsize); +int sizei (const Instruction *i); + + +#define PEnullable 0 +#define PEnofail 1 + +/* +** nofail(t) implies that 't' cannot fail with any input +*/ +#define nofail(t) checkaux(t, PEnofail) + +/* +** (not nullable(t)) implies 't' cannot match without consuming +** something +*/ +#define nullable(t) checkaux(t, PEnullable) + +#define fixedlen(t) fixedlenx(t, 0, 0) + + + +#endif diff --git a/luaclib/lpeg/lpeg-128.gif b/luaclib/lpeg/lpeg-128.gif new file mode 100644 index 0000000000000000000000000000000000000000..bbf5e78b88e71044bd341a2476dcec756c252ae4 GIT binary patch literal 4923 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 + + + LPeg - Parsing Expression Grammars For Lua + + + + + + + +

+ +
+ +
LPeg
+
+ Parsing Expression Grammars For Lua, version 1.0 +
+
+ +
+ + + +
+ + +

Introduction

+ +

+LPeg is a new pattern-matching library for Lua, +based on + +Parsing Expression Grammars (PEGs). +This text is a reference manual for the library. +For a more formal treatment of LPeg, +as well as some discussion about its implementation, +see + +A Text Pattern-Matching Tool based on Parsing Expression Grammars. +(You may also be interested in my +talk about LPeg +given at the III Lua Workshop.) +

+ +

+Following the Snobol tradition, +LPeg defines patterns as first-class objects. +That is, patterns are regular Lua values +(represented by userdata). +The library offers several functions to create +and compose patterns. +With the use of metamethods, +several of these functions are provided as infix or prefix +operators. +On the one hand, +the result is usually much more verbose than the typical +encoding of patterns using the so called +regular expressions +(which typically are not regular expressions in the formal sense). +On the other hand, +first-class patterns allow much better documentation +(as it is easy to comment the code, +to break complex definitions in smaller parts, etc.) +and are extensible, +as we can define new functions to create and compose patterns. +

+ +

+For a quick glance of the library, +the following table summarizes its basic operations +for creating patterns: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
OperatorDescription
lpeg.P(string)Matches string literally
lpeg.P(n)Matches exactly n characters
lpeg.S(string)Matches any character in string (Set)
lpeg.R("xy")Matches any character between x and y (Range)
patt^nMatches at least n repetitions of patt
patt^-nMatches at most n repetitions of patt
patt1 * patt2Matches patt1 followed by patt2
patt1 + patt2Matches patt1 or patt2 + (ordered choice)
patt1 - patt2Matches patt1 if patt2 does not match
-pattEquivalent to ("" - patt)
#pattMatches patt but consumes no input
lpeg.B(patt)Matches patt behind the current position, + consuming no input
+ +

As a very simple example, +lpeg.R("09")^1 creates a pattern that +matches a non-empty sequence of digits. +As a not so simple example, +-lpeg.P(1) +(which can be written as lpeg.P(-1), +or simply -1 for operations expecting a pattern) +matches an empty string only if it cannot match a single character; +so, it succeeds only at the end of the subject. +

+ +

+LPeg also offers the re module, +which implements patterns following a regular-expression style +(e.g., [09]+). +(This module is 260 lines of Lua code, +and of course it uses LPeg to parse regular expressions and +translate them to regular LPeg patterns.) +

+ + +

Functions

+ + +

lpeg.match (pattern, subject [, init])

+

+The matching function. +It attempts to match the given pattern against the subject string. +If the match succeeds, +returns the index in the subject of the first character after the match, +or the captured values +(if the pattern captured any value). +

+ +

+An optional numeric argument init makes the match +start at that position in the subject string. +As usual in Lua libraries, +a negative value counts from the end. +

+ +

+Unlike typical pattern-matching functions, +match works only in anchored mode; +that is, it tries to match the pattern with a prefix of +the given subject string (at position init), +not with an arbitrary substring of the subject. +So, if we want to find a pattern anywhere in a string, +we must either write a loop in Lua or write a pattern that +matches anywhere. +This second approach is easy and quite efficient; +see examples. +

+ +

lpeg.type (value)

+

+If the given value is a pattern, +returns the string "pattern". +Otherwise returns nil. +

+ +

lpeg.version ()

+

+Returns a string with the running version of LPeg. +

+ +

lpeg.setmaxstack (max)

+

+Sets a limit for the size of the backtrack stack used by LPeg to +track calls and choices. +(The default limit is 400.) +Most well-written patterns need little backtrack levels and +therefore you seldom need to change this limit; +before changing it you should try to rewrite your +pattern to avoid the need for extra space. +Nevertheless, a few useful patterns may overflow. +Also, with recursive grammars, +subjects with deep recursion may also need larger limits. +

+ + +

Basic Constructions

+ +

+The following operations build patterns. +All operations that expect a pattern as an argument +may receive also strings, tables, numbers, booleans, or functions, +which are translated to patterns according to +the rules of function lpeg.P. +

+ + + +

lpeg.P (value)

+

+Converts the given value into a proper pattern, +according to the following rules: +

+
    + +
  • +If the argument is a pattern, +it is returned unmodified. +

  • + +
  • +If the argument is a string, +it is translated to a pattern that matches the string literally. +

  • + +
  • +If the argument is a non-negative number n, +the result is a pattern that matches exactly n characters. +

  • + +
  • +If the argument is a negative number -n, +the result is a pattern that +succeeds only if the input string has less than n characters left: +lpeg.P(-n) +is equivalent to -lpeg.P(n) +(see the unary minus operation). +

  • + +
  • +If the argument is a boolean, +the result is a pattern that always succeeds or always fails +(according to the boolean value), +without consuming any input. +

  • + +
  • +If the argument is a table, +it is interpreted as a grammar +(see Grammars). +

  • + +
  • +If the argument is a function, +returns a pattern equivalent to a +match-time capture over the empty string. +

  • + +
+ + +

lpeg.B(patt)

+

+Returns a pattern that +matches only if the input string at the current position +is preceded by patt. +Pattern patt must match only strings +with some fixed length, +and it cannot contain captures. +

+ +

+Like the and predicate, +this pattern never consumes any input, +independently of success or failure. +

+ + +

lpeg.R ({range})

+

+Returns a pattern that matches any single character +belonging to one of the given ranges. +Each range is a string xy of length 2, +representing all characters with code +between the codes of x and y +(both inclusive). +

+ +

+As an example, the pattern +lpeg.R("09") matches any digit, +and lpeg.R("az", "AZ") matches any ASCII letter. +

+ + +

lpeg.S (string)

+

+Returns a pattern that matches any single character that +appears in the given string. +(The S stands for Set.) +

+ +

+As an example, the pattern +lpeg.S("+-*/") matches any arithmetic operator. +

+ +

+Note that, if s is a character +(that is, a string of length 1), +then lpeg.P(s) is equivalent to lpeg.S(s) +which is equivalent to lpeg.R(s..s). +Note also that both lpeg.S("") and lpeg.R() +are patterns that always fail. +

+ + +

lpeg.V (v)

+

+This operation creates a non-terminal (a variable) +for a grammar. +The created non-terminal refers to the rule indexed by v +in the enclosing grammar. +(See Grammars for details.) +

+ + +

lpeg.locale ([table])

+

+Returns a table with patterns for matching some character classes +according to the current locale. +The table has fields named +alnum, +alpha, +cntrl, +digit, +graph, +lower, +print, +punct, +space, +upper, and +xdigit, +each one containing a correspondent pattern. +Each pattern matches any single character that belongs to its class. +

+ +

+If called with an argument table, +then it creates those fields inside the given table and +returns that table. +

+ + +

#patt

+

+Returns a pattern that +matches only if the input string matches patt, +but without consuming any input, +independently of success or failure. +(This pattern is called an and predicate +and it is equivalent to +&patt in the original PEG notation.) +

+ + +

+This pattern never produces any capture. +

+ + +

-patt

+

+Returns a pattern that +matches only if the input string does not match patt. +It does not consume any input, +independently of success or failure. +(This pattern is equivalent to +!patt in the original PEG notation.) +

+ +

+As an example, the pattern +-lpeg.P(1) matches only the end of string. +

+ +

+This pattern never produces any captures, +because either patt fails +or -patt fails. +(A failing pattern never produces captures.) +

+ + +

patt1 + patt2

+

+Returns a pattern equivalent to an ordered choice +of patt1 and patt2. +(This is denoted by patt1 / patt2 in the original PEG notation, +not to be confused with the / operation in LPeg.) +It matches either patt1 or patt2, +with no backtracking once one of them succeeds. +The identity element for this operation is the pattern +lpeg.P(false), +which always fails. +

+ +

+If both patt1 and patt2 are +character sets, +this operation is equivalent to set union. +

+
+lower = lpeg.R("az")
+upper = lpeg.R("AZ")
+letter = lower + upper
+
+ + +

patt1 - patt2

+

+Returns a pattern equivalent to !patt2 patt1. +This pattern asserts that the input does not match +patt2 and then matches patt1. +

+ +

+When successful, +this pattern produces all captures from patt1. +It never produces any capture from patt2 +(as either patt2 fails or +patt1 - patt2 fails). +

+ +

+If both patt1 and patt2 are +character sets, +this operation is equivalent to set difference. +Note that -patt is equivalent to "" - patt +(or 0 - patt). +If patt is a character set, +1 - patt is its complement. +

+ + +

patt1 * patt2

+

+Returns a pattern that matches patt1 +and then matches patt2, +starting where patt1 finished. +The identity element for this operation is the +pattern lpeg.P(true), +which always succeeds. +

+ +

+(LPeg uses the * operator +[instead of the more obvious ..] +both because it has +the right priority and because in formal languages it is +common to use a dot for denoting concatenation.) +

+ + +

patt^n

+

+If n is nonnegative, +this pattern is +equivalent to pattn patt*: +It matches n or more occurrences of patt. +

+ +

+Otherwise, when n is negative, +this pattern is equivalent to (patt?)-n: +It matches at most |n| +occurrences of patt. +

+ +

+In particular, patt^0 is equivalent to patt*, +patt^1 is equivalent to patt+, +and patt^-1 is equivalent to patt? +in the original PEG notation. +

+ +

+In all cases, +the resulting pattern is greedy with no backtracking +(also called a possessive repetition). +That is, it matches only the longest possible sequence +of matches for patt. +

+ + + +

Grammars

+ +

+With the use of Lua variables, +it is possible to define patterns incrementally, +with each new pattern using previously defined ones. +However, this technique does not allow the definition of +recursive patterns. +For recursive patterns, +we need real grammars. +

+ +

+LPeg represents grammars with tables, +where each entry is a rule. +

+ +

+The call lpeg.V(v) +creates a pattern that represents the nonterminal +(or variable) with index v in a grammar. +Because the grammar still does not exist when +this function is evaluated, +the result is an open reference to the respective rule. +

+ +

+A table is fixed when it is converted to a pattern +(either by calling lpeg.P or by using it wherein a +pattern is expected). +Then every open reference created by lpeg.V(v) +is corrected to refer to the rule indexed by v in the table. +

+ +

+When a table is fixed, +the result is a pattern that matches its initial rule. +The entry with index 1 in the table defines its initial rule. +If that entry is a string, +it is assumed to be the name of the initial rule. +Otherwise, LPeg assumes that the entry 1 itself is the initial rule. +

+ +

+As an example, +the following grammar matches strings of a's and b's that +have the same number of a's and b's: +

+
+equalcount = lpeg.P{
+  "S";   -- initial rule name
+  S = "a" * lpeg.V"B" + "b" * lpeg.V"A" + "",
+  A = "a" * lpeg.V"S" + "b" * lpeg.V"A" * lpeg.V"A",
+  B = "b" * lpeg.V"S" + "a" * lpeg.V"B" * lpeg.V"B",
+} * -1
+
+

+It is equivalent to the following grammar in standard PEG notation: +

+
+  S <- 'a' B / 'b' A / ''
+  A <- 'a' S / 'b' A A
+  B <- 'b' S / 'a' B B
+
+ + +

Captures

+ +

+A capture is a pattern that creates values +(the so called semantic information) when it matches. +LPeg offers several kinds of captures, +which produces values based on matches and combine these values to +produce new values. +Each capture may produce zero or more values. +

+ +

+The following table summarizes the basic captures: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperationWhat it Produces
lpeg.C(patt)the match for patt plus all captures + made by patt
lpeg.Carg(n)the value of the nth extra argument to + lpeg.match (matches the empty string)
lpeg.Cb(name)the values produced by the previous + group capture named name + (matches the empty string)
lpeg.Cc(values)the given values (matches the empty string)
lpeg.Cf(patt, func)a folding of the captures from patt
lpeg.Cg(patt [, name])the values produced by patt, + optionally tagged with name
lpeg.Cp()the current position (matches the empty string)
lpeg.Cs(patt)the match for patt + with the values from nested captures replacing their matches
lpeg.Ct(patt)a table with all captures from patt
patt / stringstring, with some marks replaced by captures + of patt
patt / numberthe n-th value captured by patt, +or no value when number is zero.
patt / tabletable[c], where c is the (first) + capture of patt
patt / functionthe returns of function applied to the captures + of patt
lpeg.Cmt(patt, function)the returns of function applied to the captures + of patt; the application is done at match time
+ +

+A capture pattern produces its values every time it succeeds. +For instance, +a capture inside a loop produces as many values as matched by the loop. +A capture produces a value only when it succeeds. +For instance, +the pattern lpeg.C(lpeg.P"a"^-1) +produces the empty string when there is no "a" +(because the pattern "a"? succeeds), +while the pattern lpeg.C("a")^-1 +does not produce any value when there is no "a" +(because the pattern "a" fails). +

+ +

+Usually, +LPeg evaluates all captures only after (and if) the entire match succeeds. +During match time it only gathers enough information +to produce the capture values later. +As a particularly important consequence, +most captures cannot affect the way a pattern matches a subject. +The only exception to this rule is the +so-called match-time capture. +When a match-time capture matches, +it forces the immediate evaluation of all its nested captures +and then calls its corresponding function, +which defines whether the match succeeds and also +what values are produced. +

+ +

lpeg.C (patt)

+

+Creates a simple capture, +which captures the substring of the subject that matches patt. +The captured value is a string. +If patt has other captures, +their values are returned after this one. +

+ + +

lpeg.Carg (n)

+

+Creates an argument capture. +This pattern matches the empty string and +produces the value given as the nth extra +argument given in the call to lpeg.match. +

+ + +

lpeg.Cb (name)

+

+Creates a back capture. +This pattern matches the empty string and +produces the values produced by the most recent +group capture named name +(where name can be any Lua value). +

+ +

+Most recent means the last +complete +outermost +group capture with the given name. +A Complete capture means that the entire pattern +corresponding to the capture has matched. +An Outermost capture means that the capture is not inside +another complete capture. +

+ + +

lpeg.Cc ([value, ...])

+

+Creates a constant capture. +This pattern matches the empty string and +produces all given values as its captured values. +

+ + +

lpeg.Cf (patt, func)

+

+Creates a fold capture. +If patt produces a list of captures +C1 C2 ... Cn, +this capture will produce the value +func(...func(func(C1, C2), C3)..., + Cn), +that is, it will fold +(or accumulate, or reduce) +the captures from patt using function func. +

+ +

+This capture assumes that patt should produce +at least one capture with at least one value (of any type), +which becomes the initial value of an accumulator. +(If you need a specific initial value, +you may prefix a constant capture to patt.) +For each subsequent capture, +LPeg calls func +with this accumulator as the first argument and all values produced +by the capture as extra arguments; +the first result from this call +becomes the new value for the accumulator. +The final value of the accumulator becomes the captured value. +

+ +

+As an example, +the following pattern matches a list of numbers separated +by commas and returns their addition: +

+
+-- matches a numeral and captures its numerical value
+number = lpeg.R"09"^1 / tonumber
+
+-- matches a list of numbers, capturing their values
+list = number * ("," * number)^0
+
+-- auxiliary function to add two numbers
+function add (acc, newvalue) return acc + newvalue end
+
+-- folds the list of numbers adding them
+sum = lpeg.Cf(list, add)
+
+-- example of use
+print(sum:match("10,30,43"))   --> 83
+
+ + +

lpeg.Cg (patt [, name])

+

+Creates a group capture. +It groups all values returned by patt +into a single capture. +The group may be anonymous (if no name is given) +or named with the given name +(which can be any non-nil Lua value). +

+ +

+An anonymous group serves to join values from several captures into +a single capture. +A named group has a different behavior. +In most situations, a named group returns no values at all. +Its values are only relevant for a following +back capture or when used +inside a table capture. +

+ + +

lpeg.Cp ()

+

+Creates a position capture. +It matches the empty string and +captures the position in the subject where the match occurs. +The captured value is a number. +

+ + +

lpeg.Cs (patt)

+

+Creates a substitution capture, +which captures the substring of the subject that matches patt, +with substitutions. +For any capture inside patt with a value, +the substring that matched the capture is replaced by the capture value +(which should be a string). +The final captured value is the string resulting from +all replacements. +

+ + +

lpeg.Ct (patt)

+

+Creates a table capture. +This capture creates a table and puts all values from all anonymous captures +made by patt inside this table in successive integer keys, +starting at 1. +Moreover, +for each named capture group created by patt, +the first value of the group is put into the table +with the group name as its key. +The captured value is only the table. +

+ + +

patt / string

+

+Creates a string capture. +It creates a capture string based on string. +The captured value is a copy of string, +except that the character % works as an escape character: +any sequence in string of the form %n, +with n between 1 and 9, +stands for the match of the n-th capture in patt. +The sequence %0 stands for the whole match. +The sequence %% stands for a single %. +

+ + +

patt / number

+

+Creates a numbered capture. +For a non-zero number, +the captured value is the n-th value +captured by patt. +When number is zero, +there are no captured values. +

+ + +

patt / table

+

+Creates a query capture. +It indexes the given table using as key the first value captured by +patt, +or the whole match if patt produced no value. +The value at that index is the final value of the capture. +If the table does not have that key, +there is no captured value. +

+ + +

patt / function

+

+Creates a function capture. +It calls the given function passing all captures made by +patt as arguments, +or the whole match if patt made no capture. +The values returned by the function +are the final values of the capture. +In particular, +if function returns no value, +there is no captured value. +

+ + +

lpeg.Cmt(patt, function)

+

+Creates a match-time capture. +Unlike all other captures, +this one is evaluated immediately when a match occurs. +It forces the immediate evaluation of all its nested captures +and then calls function. +

+ +

+The given function gets as arguments the entire subject, +the current position (after the match of patt), +plus any capture values produced by patt. +

+ +

+The first value returned by function +defines how the match happens. +If the call returns a number, +the match succeeds +and the returned number becomes the new current position. +(Assuming a subject s and current position i, +the returned number must be in the range [i, len(s) + 1].) +If the call returns true, +the match succeeds without consuming any input. +(So, to return true is equivalent to return i.) +If the call returns false, nil, or no value, +the match fails. +

+ +

+Any extra values returned by the function become the +values produced by the capture. +

+ + + + +

Some Examples

+ +

Using a Pattern

+

+This example shows a very simple but complete program +that builds and uses a pattern: +

+
+local lpeg = require "lpeg"
+
+-- matches a word followed by end-of-string
+p = lpeg.R"az"^1 * -1
+
+print(p:match("hello"))        --> 6
+print(lpeg.match(p, "hello"))  --> 6
+print(p:match("1 hello"))      --> nil
+
+

+The pattern is simply a sequence of one or more lower-case letters +followed by the end of string (-1). +The program calls match both as a method +and as a function. +In both sucessful cases, +the match returns +the index of the first character after the match, +which is the string length plus one. +

+ + +

Name-value lists

+

+This example parses a list of name-value pairs and returns a table +with those pairs: +

+
+lpeg.locale(lpeg)   -- adds locale entries into 'lpeg' table
+
+local space = lpeg.space^0
+local name = lpeg.C(lpeg.alpha^1) * space
+local sep = lpeg.S(",;") * space
+local pair = lpeg.Cg(name * "=" * space * name) * sep^-1
+local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset)
+t = list:match("a=b, c = hi; next = pi")  --> { a = "b", c = "hi", next = "pi" }
+
+

+Each pair has the format name = name followed by +an optional separator (a comma or a semicolon). +The pair pattern encloses the pair in a group pattern, +so that the names become the values of a single capture. +The list pattern then folds these captures. +It starts with an empty table, +created by a table capture matching an empty string; +then for each capture (a pair of names) it applies rawset +over the accumulator (the table) and the capture values (the pair of names). +rawset returns the table itself, +so the accumulator is always the table. +

+ +

Splitting a string

+

+The following code builds a pattern that +splits a string using a given pattern +sep as a separator: +

+
+function split (s, sep)
+  sep = lpeg.P(sep)
+  local elem = lpeg.C((1 - sep)^0)
+  local p = elem * (sep * elem)^0
+  return lpeg.match(p, s)
+end
+
+

+First the function ensures that sep is a proper pattern. +The pattern elem is a repetition of zero of more +arbitrary characters as long as there is not a match against +the separator. +It also captures its match. +The pattern p matches a list of elements separated +by sep. +

+ +

+If the split results in too many values, +it may overflow the maximum number of values +that can be returned by a Lua function. +In this case, +we can collect these values in a table: +

+
+function split (s, sep)
+  sep = lpeg.P(sep)
+  local elem = lpeg.C((1 - sep)^0)
+  local p = lpeg.Ct(elem * (sep * elem)^0)   -- make a table capture
+  return lpeg.match(p, s)
+end
+
+ + +

Searching for a pattern

+

+The primitive match works only in anchored mode. +If we want to find a pattern anywhere in a string, +we must write a pattern that matches anywhere. +

+ +

+Because patterns are composable, +we can write a function that, +given any arbitrary pattern p, +returns a new pattern that searches for p +anywhere in a string. +There are several ways to do the search. +One way is like this: +

+
+function anywhere (p)
+  return lpeg.P{ p + 1 * lpeg.V(1) }
+end
+
+

+This grammar has a straight reading: +it matches p or skips one character and tries again. +

+ +

+If we want to know where the pattern is in the string +(instead of knowing only that it is there somewhere), +we can add position captures to the pattern: +

+
+local I = lpeg.Cp()
+function anywhere (p)
+  return lpeg.P{ I * p * I + 1 * lpeg.V(1) }
+end
+
+print(anywhere("world"):match("hello world!"))   -> 7   12
+
+ +

+Another option for the search is like this: +

+
+local I = lpeg.Cp()
+function anywhere (p)
+  return (1 - lpeg.P(p))^0 * I * p * I
+end
+
+

+Again the pattern has a straight reading: +it skips as many characters as possible while not matching p, +and then matches p (plus appropriate captures). +

+ +

+If we want to look for a pattern only at word boundaries, +we can use the following transformer: +

+ +
+local t = lpeg.locale()
+
+function atwordboundary (p)
+  return lpeg.P{
+    [1] = p + t.alpha^0 * (1 - t.alpha)^1 * lpeg.V(1)
+  }
+end
+
+ + +

Balanced parentheses

+

+The following pattern matches only strings with balanced parentheses: +

+
+b = lpeg.P{ "(" * ((1 - lpeg.S"()") + lpeg.V(1))^0 * ")" }
+
+

+Reading the first (and only) rule of the given grammar, +we have that a balanced string is +an open parenthesis, +followed by zero or more repetitions of either +a non-parenthesis character or +a balanced string (lpeg.V(1)), +followed by a closing parenthesis. +

+ + +

Global substitution

+

+The next example does a job somewhat similar to string.gsub. +It receives a pattern and a replacement value, +and substitutes the replacement value for all occurrences of the pattern +in a given string: +

+
+function gsub (s, patt, repl)
+  patt = lpeg.P(patt)
+  patt = lpeg.Cs((patt / repl + 1)^0)
+  return lpeg.match(patt, s)
+end
+
+

+As in string.gsub, +the replacement value can be a string, +a function, or a table. +

+ + +

Comma-Separated Values (CSV)

+

+This example breaks a string into comma-separated values, +returning all fields: +

+
+local field = '"' * lpeg.Cs(((lpeg.P(1) - '"') + lpeg.P'""' / '"')^0) * '"' +
+                    lpeg.C((1 - lpeg.S',\n"')^0)
+
+local record = field * (',' * field)^0 * (lpeg.P'\n' + -1)
+
+function csv (s)
+  return lpeg.match(record, s)
+end
+
+

+A field is either a quoted field +(which may contain any character except an individual quote, +which may be written as two quotes that are replaced by one) +or an unquoted field +(which cannot contain commas, newlines, or quotes). +A record is a list of fields separated by commas, +ending with a newline or the string end (-1). +

+ +

+As it is, +the previous pattern returns each field as a separated result. +If we add a table capture in the definition of record, +the pattern will return instead a single table +containing all fields: +

+
+local record = lpeg.Ct(field * (',' * field)^0) * (lpeg.P'\n' + -1)
+
+ + +

UTF-8 and Latin 1

+

+It is not difficult to use LPeg to convert a string from +UTF-8 encoding to Latin 1 (ISO 8859-1): +

+ +
+-- convert a two-byte UTF-8 sequence to a Latin 1 character
+local function f2 (s)
+  local c1, c2 = string.byte(s, 1, 2)
+  return string.char(c1 * 64 + c2 - 12416)
+end
+
+local utf8 = lpeg.R("\0\127")
+           + lpeg.R("\194\195") * lpeg.R("\128\191") / f2
+
+local decode_pattern = lpeg.Cs(utf8^0) * -1
+
+

+In this code, +the definition of UTF-8 is already restricted to the +Latin 1 range (from 0 to 255). +Any encoding outside this range (as well as any invalid encoding) +will not match that pattern. +

+ +

+As the definition of decode_pattern demands that +the pattern matches the whole input (because of the -1 at its end), +any invalid string will simply fail to match, +without any useful information about the problem. +We can improve this situation redefining decode_pattern +as follows: +

+
+local function er (_, i) error("invalid encoding at position " .. i) end
+
+local decode_pattern = lpeg.Cs(utf8^0) * (-1 + lpeg.P(er))
+
+

+Now, if the pattern utf8^0 stops +before the end of the string, +an appropriate error function is called. +

+ + +

UTF-8 and Unicode

+

+We can extend the previous patterns to handle all Unicode code points. +Of course, +we cannot translate them to Latin 1 or any other one-byte encoding. +Instead, our translation results in a array with the code points +represented as numbers. +The full code is here: +

+
+-- decode a two-byte UTF-8 sequence
+local function f2 (s)
+  local c1, c2 = string.byte(s, 1, 2)
+  return c1 * 64 + c2 - 12416
+end
+
+-- decode a three-byte UTF-8 sequence
+local function f3 (s)
+  local c1, c2, c3 = string.byte(s, 1, 3)
+  return (c1 * 64 + c2) * 64 + c3 - 925824
+end
+
+-- decode a four-byte UTF-8 sequence
+local function f4 (s)
+  local c1, c2, c3, c4 = string.byte(s, 1, 4)
+  return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
+end
+
+local cont = lpeg.R("\128\191")   -- continuation byte
+
+local utf8 = lpeg.R("\0\127") / string.byte
+           + lpeg.R("\194\223") * cont / f2
+           + lpeg.R("\224\239") * cont * cont / f3
+           + lpeg.R("\240\244") * cont * cont * cont / f4
+
+local decode_pattern = lpeg.Ct(utf8^0) * -1
+
+ + +

Lua's long strings

+

+A long string in Lua starts with the pattern [=*[ +and ends at the first occurrence of ]=*] with +exactly the same number of equal signs. +If the opening brackets are followed by a newline, +this newline is discarded +(that is, it is not part of the string). +

+ +

+To match a long string in Lua, +the pattern must capture the first repetition of equal signs and then, +whenever it finds a candidate for closing the string, +check whether it has the same number of equal signs. +

+ +
+equals = lpeg.P"="^0
+open = "[" * lpeg.Cg(equals, "init") * "[" * lpeg.P"\n"^-1
+close = "]" * lpeg.C(equals) * "]"
+closeeq = lpeg.Cmt(close * lpeg.Cb("init"), function (s, i, a, b) return a == b end)
+string = open * lpeg.C((lpeg.P(1) - closeeq)^0) * close / 1
+
+ +

+The open pattern matches [=*[, +capturing the repetitions of equal signs in a group named init; +it also discharges an optional newline, if present. +The close pattern matches ]=*], +also capturing the repetitions of equal signs. +The closeeq pattern first matches close; +then it uses a back capture to recover the capture made +by the previous open, +which is named init; +finally it uses a match-time capture to check +whether both captures are equal. +The string pattern starts with an open, +then it goes as far as possible until matching closeeq, +and then matches the final close. +The final numbered capture simply discards +the capture made by close. +

+ + +

Arithmetic expressions

+

+This example is a complete parser and evaluator for simple +arithmetic expressions. +We write it in two styles. +The first approach first builds a syntax tree and then +traverses this tree to compute the expression value: +

+
+-- Lexical Elements
+local Space = lpeg.S(" \n\t")^0
+local Number = lpeg.C(lpeg.P"-"^-1 * lpeg.R("09")^1) * Space
+local TermOp = lpeg.C(lpeg.S("+-")) * Space
+local FactorOp = lpeg.C(lpeg.S("*/")) * Space
+local Open = "(" * Space
+local Close = ")" * Space
+
+-- Grammar
+local Exp, Term, Factor = lpeg.V"Exp", lpeg.V"Term", lpeg.V"Factor"
+G = lpeg.P{ Exp,
+  Exp = lpeg.Ct(Term * (TermOp * Term)^0);
+  Term = lpeg.Ct(Factor * (FactorOp * Factor)^0);
+  Factor = Number + Open * Exp * Close;
+}
+
+G = Space * G * -1
+
+-- Evaluator
+function eval (x)
+  if type(x) == "string" then
+    return tonumber(x)
+  else
+    local op1 = eval(x[1])
+    for i = 2, #x, 2 do
+      local op = x[i]
+      local op2 = eval(x[i + 1])
+      if (op == "+") then op1 = op1 + op2
+      elseif (op == "-") then op1 = op1 - op2
+      elseif (op == "*") then op1 = op1 * op2
+      elseif (op == "/") then op1 = op1 / op2
+      end
+    end
+    return op1
+  end
+end
+
+-- Parser/Evaluator
+function evalExp (s)
+  local t = lpeg.match(G, s)
+  if not t then error("syntax error", 2) end
+  return eval(t)
+end
+
+-- small example
+print(evalExp"3 + 5*9 / (1+1) - 12")   --> 13.5
+
+ +

+The second style computes the expression value on the fly, +without building the syntax tree. +The following grammar takes this approach. +(It assumes the same lexical elements as before.) +

+
+-- Auxiliary function
+function eval (v1, op, v2)
+  if (op == "+") then return v1 + v2
+  elseif (op == "-") then return v1 - v2
+  elseif (op == "*") then return v1 * v2
+  elseif (op == "/") then return v1 / v2
+  end
+end
+
+-- Grammar
+local V = lpeg.V
+G = lpeg.P{ "Exp",
+  Exp = lpeg.Cf(V"Term" * lpeg.Cg(TermOp * V"Term")^0, eval);
+  Term = lpeg.Cf(V"Factor" * lpeg.Cg(FactorOp * V"Factor")^0, eval);
+  Factor = Number / tonumber + Open * V"Exp" * Close;
+}
+
+-- small example
+print(lpeg.match(G, "3 + 5*9 / (1+1) - 12"))   --> 13.5
+
+

+Note the use of the fold (accumulator) capture. +To compute the value of an expression, +the accumulator starts with the value of the first term, +and then applies eval over +the accumulator, the operator, +and the new term for each repetition. +

+ + + +

Download

+ +

LPeg +source code.

+ + +

License

+ +

+Copyright © 2007-2015 Lua.org, PUC-Rio. +

+

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

+ +

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

+ +

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

+ +
+ +
+ +
+

+$Id: lpeg.html,v 1.75 2015/09/28 17:17:41 roberto Exp $ +

+
+ +
+ + + diff --git a/luaclib/lpeg/lpeg.vcxproj b/luaclib/lpeg/lpeg.vcxproj new file mode 100644 index 0000000..dfc2925 --- /dev/null +++ b/luaclib/lpeg/lpeg.vcxproj @@ -0,0 +1,93 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8} + lpeg + + + + DynamicLibrary + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + $(ProjectDir) + + + + Level3 + Disabled + true + ..\..\deps\lua; + WIN32;_DEBUG;_WINDOWS;_USRDLL;LUA_CORE;LUA_BUILD_AS_DLL;LUA_COMPAT_5_2;LUA_COMPAT_5_1;%(PreprocessorDefinitions) + + + true + ..\..\deps\lua; + nlua.lib + + + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/luaclib/lpeg/lpeg.vcxproj.filters b/luaclib/lpeg/lpeg.vcxproj.filters new file mode 100644 index 0000000..7171297 --- /dev/null +++ b/luaclib/lpeg/lpeg.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + {0c90a889-7060-4f4c-9513-678c730b15bf} + + + + + src + + + src + + + src + + + src + + + src + + + + + src + + + src + + + src + + + src + + + src + + + src + + + \ No newline at end of file diff --git a/luaclib/lpeg/lpeg.vcxproj.user b/luaclib/lpeg/lpeg.vcxproj.user new file mode 100644 index 0000000..ef5ff2a --- /dev/null +++ b/luaclib/lpeg/lpeg.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/luaclib/lpeg/lpprint.c b/luaclib/lpeg/lpprint.c new file mode 100644 index 0000000..174d168 --- /dev/null +++ b/luaclib/lpeg/lpprint.c @@ -0,0 +1,244 @@ +/* +** $Id: lpprint.c,v 1.9 2015/06/15 16:09:57 roberto Exp $ +** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) +*/ + +#include +#include +#include + + +#include "lptypes.h" +#include "lpprint.h" +#include "lpcode.h" + + +#if defined(LPEG_DEBUG) + +/* +** {====================================================== +** Printing patterns (for debugging) +** ======================================================= +*/ + + +void printcharset (const byte *st) { + int i; + printf("["); + for (i = 0; i <= UCHAR_MAX; i++) { + int first = i; + while (testchar(st, i) && i <= UCHAR_MAX) i++; + if (i - 1 == first) /* unary range? */ + printf("(%02x)", first); + else if (i - 1 > first) /* non-empty range? */ + printf("(%02x-%02x)", first, i - 1); + } + printf("]"); +} + + +static void printcapkind (int kind) { + const char *const modes[] = { + "close", "position", "constant", "backref", + "argument", "simple", "table", "function", + "query", "string", "num", "substitution", "fold", + "runtime", "group"}; + printf("%s", modes[kind]); +} + + +static void printjmp (const Instruction *op, const Instruction *p) { + printf("-> %d", (int)(p + (p + 1)->offset - op)); +} + + +void printinst (const Instruction *op, const Instruction *p) { + const char *const names[] = { + "any", "char", "set", + "testany", "testchar", "testset", + "span", "behind", + "ret", "end", + "choice", "jmp", "call", "open_call", + "commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup", + "fullcapture", "opencapture", "closecapture", "closeruntime" + }; + printf("%02ld: %s ", (long)(p - op), names[p->i.code]); + switch ((Opcode)p->i.code) { + case IChar: { + printf("'%c'", p->i.aux); + break; + } + case ITestChar: { + printf("'%c'", p->i.aux); printjmp(op, p); + break; + } + case IFullCapture: { + printcapkind(getkind(p)); + printf(" (size = %d) (idx = %d)", getoff(p), p->i.key); + break; + } + case IOpenCapture: { + printcapkind(getkind(p)); + printf(" (idx = %d)", p->i.key); + break; + } + case ISet: { + printcharset((p+1)->buff); + break; + } + case ITestSet: { + printcharset((p+2)->buff); printjmp(op, p); + break; + } + case ISpan: { + printcharset((p+1)->buff); + break; + } + case IOpenCall: { + printf("-> %d", (p + 1)->offset); + break; + } + case IBehind: { + printf("%d", p->i.aux); + break; + } + case IJmp: case ICall: case ICommit: case IChoice: + case IPartialCommit: case IBackCommit: case ITestAny: { + printjmp(op, p); + break; + } + default: break; + } + printf("\n"); +} + + +void printpatt (Instruction *p, int n) { + Instruction *op = p; + while (p < op + n) { + printinst(op, p); + p += sizei(p); + } +} + + +#if defined(LPEG_DEBUG) +static void printcap (Capture *cap) { + printcapkind(cap->kind); + printf(" (idx: %d - size: %d) -> %p\n", cap->idx, cap->siz, cap->s); +} + + +void printcaplist (Capture *cap, Capture *limit) { + printf(">======\n"); + for (; cap->s && (limit == NULL || cap < limit); cap++) + printcap(cap); + printf("=======\n"); +} +#endif + +/* }====================================================== */ + + +/* +** {====================================================== +** Printing trees (for debugging) +** ======================================================= +*/ + +static const char *tagnames[] = { + "char", "set", "any", + "true", "false", + "rep", + "seq", "choice", + "not", "and", + "call", "opencall", "rule", "grammar", + "behind", + "capture", "run-time" +}; + + +void printtree (TTree *tree, int ident) { + int i; + for (i = 0; i < ident; i++) printf(" "); + printf("%s", tagnames[tree->tag]); + switch (tree->tag) { + case TChar: { + int c = tree->u.n; + if (isprint(c)) + printf(" '%c'\n", c); + else + printf(" (%02X)\n", c); + break; + } + case TSet: { + printcharset(treebuffer(tree)); + printf("\n"); + break; + } + case TOpenCall: case TCall: { + printf(" key: %d\n", tree->key); + break; + } + case TBehind: { + printf(" %d\n", tree->u.n); + printtree(sib1(tree), ident + 2); + break; + } + case TCapture: { + printf(" cap: %d key: %d n: %d\n", tree->cap, tree->key, tree->u.n); + printtree(sib1(tree), ident + 2); + break; + } + case TRule: { + printf(" n: %d key: %d\n", tree->cap, tree->key); + printtree(sib1(tree), ident + 2); + break; /* do not print next rule as a sibling */ + } + case TGrammar: { + TTree *rule = sib1(tree); + printf(" %d\n", tree->u.n); /* number of rules */ + for (i = 0; i < tree->u.n; i++) { + printtree(rule, ident + 2); + rule = sib2(rule); + } + assert(rule->tag == TTrue); /* sentinel */ + break; + } + default: { + int sibs = numsiblings[tree->tag]; + printf("\n"); + if (sibs >= 1) { + printtree(sib1(tree), ident + 2); + if (sibs >= 2) + printtree(sib2(tree), ident + 2); + } + break; + } + } +} + + +void printktable (lua_State *L, int idx) { + int n, i; + lua_getuservalue(L, idx); + if (lua_isnil(L, -1)) /* no ktable? */ + return; + n = lua_rawlen(L, -1); + printf("["); + for (i = 1; i <= n; i++) { + printf("%d = ", i); + lua_rawgeti(L, -1, i); + if (lua_isstring(L, -1)) + printf("%s ", lua_tostring(L, -1)); + else + printf("%s ", lua_typename(L, lua_type(L, -1))); + lua_pop(L, 1); + } + printf("]\n"); + /* leave ktable at the stack */ +} + +/* }====================================================== */ + +#endif diff --git a/luaclib/lpeg/lpprint.h b/luaclib/lpeg/lpprint.h new file mode 100644 index 0000000..6329760 --- /dev/null +++ b/luaclib/lpeg/lpprint.h @@ -0,0 +1,36 @@ +/* +** $Id: lpprint.h,v 1.2 2015/06/12 18:18:08 roberto Exp $ +*/ + + +#if !defined(lpprint_h) +#define lpprint_h + + +#include "lptree.h" +#include "lpvm.h" + + +#if defined(LPEG_DEBUG) + +void printpatt (Instruction *p, int n); +void printtree (TTree *tree, int ident); +void printktable (lua_State *L, int idx); +void printcharset (const byte *st); +void printcaplist (Capture *cap, Capture *limit); +void printinst (const Instruction *op, const Instruction *p); + +#else + +#define printktable(L,idx) \ + luaL_error(L, "function only implemented in debug mode") +#define printtree(tree,i) \ + luaL_error(L, "function only implemented in debug mode") +#define printpatt(p,n) \ + luaL_error(L, "function only implemented in debug mode") + +#endif + + +#endif + diff --git a/luaclib/lpeg/lptree.c b/luaclib/lpeg/lptree.c new file mode 100644 index 0000000..ac5f515 --- /dev/null +++ b/luaclib/lpeg/lptree.c @@ -0,0 +1,1296 @@ +/* +** $Id: lptree.c,v 1.21 2015/09/28 17:01:25 roberto Exp $ +** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license) +*/ + +#include +#include +#include + + +#include "lua.h" +#include "lauxlib.h" + +#include "lptypes.h" +#include "lpcap.h" +#include "lpcode.h" +#include "lpprint.h" +#include "lptree.h" + + +/* number of siblings for each tree */ +const byte numsiblings[] = { + 0, 0, 0, /* char, set, any */ + 0, 0, /* true, false */ + 1, /* rep */ + 2, 2, /* seq, choice */ + 1, 1, /* not, and */ + 0, 0, 2, 1, /* call, opencall, rule, grammar */ + 1, /* behind */ + 1, 1 /* capture, runtime capture */ +}; + + +static TTree *newgrammar (lua_State *L, int arg); + + +/* +** returns a reasonable name for value at index 'idx' on the stack +*/ +static const char *val2str (lua_State *L, int idx) { + const char *k = lua_tostring(L, idx); + if (k != NULL) + return lua_pushfstring(L, "%s", k); + else + return lua_pushfstring(L, "(a %s)", luaL_typename(L, idx)); +} + + +/* +** Fix a TOpenCall into a TCall node, using table 'postable' to +** translate a key to its rule address in the tree. Raises an +** error if key does not exist. +*/ +static void fixonecall (lua_State *L, int postable, TTree *g, TTree *t) { + int n; + lua_rawgeti(L, -1, t->key); /* get rule's name */ + lua_gettable(L, postable); /* query name in position table */ + n = lua_tonumber(L, -1); /* get (absolute) position */ + lua_pop(L, 1); /* remove position */ + if (n == 0) { /* no position? */ + lua_rawgeti(L, -1, t->key); /* get rule's name again */ + luaL_error(L, "rule '%s' undefined in given grammar", val2str(L, -1)); + } + t->tag = TCall; + t->u.ps = n - (t - g); /* position relative to node */ + assert(sib2(t)->tag == TRule); + sib2(t)->key = t->key; +} + + +/* +** Transform left associative constructions into right +** associative ones, for sequence and choice; that is: +** (t11 + t12) + t2 => t11 + (t12 + t2) +** (t11 * t12) * t2 => t11 * (t12 * t2) +** (that is, Op (Op t11 t12) t2 => Op t11 (Op t12 t2)) +*/ +static void correctassociativity (TTree *tree) { + TTree *t1 = sib1(tree); + assert(tree->tag == TChoice || tree->tag == TSeq); + while (t1->tag == tree->tag) { + int n1size = tree->u.ps - 1; /* t1 == Op t11 t12 */ + int n11size = t1->u.ps - 1; + int n12size = n1size - n11size - 1; + memmove(sib1(tree), sib1(t1), n11size * sizeof(TTree)); /* move t11 */ + tree->u.ps = n11size + 1; + sib2(tree)->tag = tree->tag; + sib2(tree)->u.ps = n12size + 1; + } +} + + +/* +** Make final adjustments in a tree. Fix open calls in tree 't', +** making them refer to their respective rules or raising appropriate +** errors (if not inside a grammar). Correct associativity of associative +** constructions (making them right associative). Assume that tree's +** ktable is at the top of the stack (for error messages). +*/ +static void finalfix (lua_State *L, int postable, TTree *g, TTree *t) { + tailcall: + switch (t->tag) { + case TGrammar: /* subgrammars were already fixed */ + return; + case TOpenCall: { + if (g != NULL) /* inside a grammar? */ + fixonecall(L, postable, g, t); + else { /* open call outside grammar */ + lua_rawgeti(L, -1, t->key); + luaL_error(L, "rule '%s' used outside a grammar", val2str(L, -1)); + } + break; + } + case TSeq: case TChoice: + correctassociativity(t); + break; + } + switch (numsiblings[t->tag]) { + case 1: /* finalfix(L, postable, g, sib1(t)); */ + t = sib1(t); goto tailcall; + case 2: + finalfix(L, postable, g, sib1(t)); + t = sib2(t); goto tailcall; /* finalfix(L, postable, g, sib2(t)); */ + default: assert(numsiblings[t->tag] == 0); break; + } +} + + + +/* +** {=================================================================== +** KTable manipulation +** +** - The ktable of a pattern 'p' can be shared by other patterns that +** contain 'p' and no other constants. Because of this sharing, we +** should not add elements to a 'ktable' unless it was freshly created +** for the new pattern. +** +** - The maximum index in a ktable is USHRT_MAX, because trees and +** patterns use unsigned shorts to store those indices. +** ==================================================================== +*/ + +/* +** Create a new 'ktable' to the pattern at the top of the stack. +*/ +static void newktable (lua_State *L, int n) { + lua_createtable(L, n, 0); /* create a fresh table */ + lua_setuservalue(L, -2); /* set it as 'ktable' for pattern */ +} + + +/* +** Add element 'idx' to 'ktable' of pattern at the top of the stack; +** Return index of new element. +** If new element is nil, does not add it to table (as it would be +** useless) and returns 0, as ktable[0] is always nil. +*/ +static int addtoktable (lua_State *L, int idx) { + if (lua_isnil(L, idx)) /* nil value? */ + return 0; + else { + int n; + lua_getuservalue(L, -1); /* get ktable from pattern */ + n = lua_rawlen(L, -1); + if (n >= USHRT_MAX) + luaL_error(L, "too many Lua values in pattern"); + lua_pushvalue(L, idx); /* element to be added */ + lua_rawseti(L, -2, ++n); + lua_pop(L, 1); /* remove 'ktable' */ + return n; + } +} + + +/* +** Return the number of elements in the ktable at 'idx'. +** In Lua 5.2/5.3, default "environment" for patterns is nil, not +** a table. Treat it as an empty table. In Lua 5.1, assumes that +** the environment has no numeric indices (len == 0) +*/ +static int ktablelen (lua_State *L, int idx) { + if (!lua_istable(L, idx)) return 0; + else return lua_rawlen(L, idx); +} + + +/* +** Concatentate the contents of table 'idx1' into table 'idx2'. +** (Assume that both indices are negative.) +** Return the original length of table 'idx2' (or 0, if no +** element was added, as there is no need to correct any index). +*/ +static int concattable (lua_State *L, int idx1, int idx2) { + int i; + int n1 = ktablelen(L, idx1); + int n2 = ktablelen(L, idx2); + if (n1 + n2 > USHRT_MAX) + luaL_error(L, "too many Lua values in pattern"); + if (n1 == 0) return 0; /* nothing to correct */ + for (i = 1; i <= n1; i++) { + lua_rawgeti(L, idx1, i); + lua_rawseti(L, idx2 - 1, n2 + i); /* correct 'idx2' */ + } + return n2; +} + + +/* +** When joining 'ktables', constants from one of the subpatterns must +** be renumbered; 'correctkeys' corrects their indices (adding 'n' +** to each of them) +*/ +static void correctkeys (TTree *tree, int n) { + if (n == 0) return; /* no correction? */ + tailcall: + switch (tree->tag) { + case TOpenCall: case TCall: case TRunTime: case TRule: { + if (tree->key > 0) + tree->key += n; + break; + } + case TCapture: { + if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum) + tree->key += n; + break; + } + default: break; + } + switch (numsiblings[tree->tag]) { + case 1: /* correctkeys(sib1(tree), n); */ + tree = sib1(tree); goto tailcall; + case 2: + correctkeys(sib1(tree), n); + tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */ + default: assert(numsiblings[tree->tag] == 0); break; + } +} + + +/* +** Join the ktables from p1 and p2 the ktable for the new pattern at the +** top of the stack, reusing them when possible. +*/ +static void joinktables (lua_State *L, int p1, TTree *t2, int p2) { + int n1, n2; + lua_getuservalue(L, p1); /* get ktables */ + lua_getuservalue(L, p2); + n1 = ktablelen(L, -2); + n2 = ktablelen(L, -1); + if (n1 == 0 && n2 == 0) /* are both tables empty? */ + lua_pop(L, 2); /* nothing to be done; pop tables */ + else if (n2 == 0 || lp_equal(L, -2, -1)) { /* 2nd table empty or equal? */ + lua_pop(L, 1); /* pop 2nd table */ + lua_setuservalue(L, -2); /* set 1st ktable into new pattern */ + } + else if (n1 == 0) { /* first table is empty? */ + lua_setuservalue(L, -3); /* set 2nd table into new pattern */ + lua_pop(L, 1); /* pop 1st table */ + } + else { + lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */ + /* stack: new p; ktable p1; ktable p2; new ktable */ + concattable(L, -3, -1); /* from p1 into new ktable */ + concattable(L, -2, -1); /* from p2 into new ktable */ + lua_setuservalue(L, -4); /* new ktable becomes 'p' environment */ + lua_pop(L, 2); /* pop other ktables */ + correctkeys(t2, n1); /* correction for indices from p2 */ + } +} + + +/* +** copy 'ktable' of element 'idx' to new tree (on top of stack) +*/ +static void copyktable (lua_State *L, int idx) { + lua_getuservalue(L, idx); + lua_setuservalue(L, -2); +} + + +/* +** merge 'ktable' from 'stree' at stack index 'idx' into 'ktable' +** from tree at the top of the stack, and correct corresponding +** tree. +*/ +static void mergektable (lua_State *L, int idx, TTree *stree) { + int n; + lua_getuservalue(L, -1); /* get ktables */ + lua_getuservalue(L, idx); + n = concattable(L, -1, -2); + lua_pop(L, 2); /* remove both ktables */ + correctkeys(stree, n); +} + + +/* +** Create a new 'ktable' to the pattern at the top of the stack, adding +** all elements from pattern 'p' (if not 0) plus element 'idx' to it. +** Return index of new element. +*/ +static int addtonewktable (lua_State *L, int p, int idx) { + newktable(L, 1); + if (p) + mergektable(L, p, NULL); + return addtoktable(L, idx); +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Tree generation +** ======================================================= +*/ + +/* +** In 5.2, could use 'luaL_testudata'... +*/ +static int testpattern (lua_State *L, int idx) { + if (lua_touserdata(L, idx)) { /* value is a userdata? */ + if (lua_getmetatable(L, idx)) { /* does it have a metatable? */ + luaL_getmetatable(L, PATTERN_T); + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_pop(L, 2); /* remove both metatables */ + return 1; + } + } + } + return 0; +} + + +static Pattern *getpattern (lua_State *L, int idx) { + return (Pattern *)luaL_checkudata(L, idx, PATTERN_T); +} + + +static int getsize (lua_State *L, int idx) { + return (lua_rawlen(L, idx) - sizeof(Pattern)) / sizeof(TTree) + 1; +} + + +static TTree *gettree (lua_State *L, int idx, int *len) { + Pattern *p = getpattern(L, idx); + if (len) + *len = getsize(L, idx); + return p->tree; +} + + +/* +** create a pattern. Set its uservalue (the 'ktable') equal to its +** metatable. (It could be any empty sequence; the metatable is at +** hand here, so we use it.) +*/ +static TTree *newtree (lua_State *L, int len) { + size_t size = (len - 1) * sizeof(TTree) + sizeof(Pattern); + Pattern *p = (Pattern *)lua_newuserdata(L, size); + luaL_getmetatable(L, PATTERN_T); + lua_pushvalue(L, -1); + lua_setuservalue(L, -3); + lua_setmetatable(L, -2); + p->code = NULL; p->codesize = 0; + return p->tree; +} + + +static TTree *newleaf (lua_State *L, int tag) { + TTree *tree = newtree(L, 1); + tree->tag = tag; + return tree; +} + + +static TTree *newcharset (lua_State *L) { + TTree *tree = newtree(L, bytes2slots(CHARSETSIZE) + 1); + tree->tag = TSet; + loopset(i, treebuffer(tree)[i] = 0); + return tree; +} + + +/* +** add to tree a sequence where first sibling is 'sib' (with size +** 'sibsize'); returns position for second sibling +*/ +static TTree *seqaux (TTree *tree, TTree *sib, int sibsize) { + tree->tag = TSeq; tree->u.ps = sibsize + 1; + memcpy(sib1(tree), sib, sibsize * sizeof(TTree)); + return sib2(tree); +} + + +/* +** Build a sequence of 'n' nodes, each with tag 'tag' and 'u.n' got +** from the array 's' (or 0 if array is NULL). (TSeq is binary, so it +** must build a sequence of sequence of sequence...) +*/ +static void fillseq (TTree *tree, int tag, int n, const char *s) { + int i; + for (i = 0; i < n - 1; i++) { /* initial n-1 copies of Seq tag; Seq ... */ + tree->tag = TSeq; tree->u.ps = 2; + sib1(tree)->tag = tag; + sib1(tree)->u.n = s ? (byte)s[i] : 0; + tree = sib2(tree); + } + tree->tag = tag; /* last one does not need TSeq */ + tree->u.n = s ? (byte)s[i] : 0; +} + + +/* +** Numbers as patterns: +** 0 == true (always match); n == TAny repeated 'n' times; +** -n == not (TAny repeated 'n' times) +*/ +static TTree *numtree (lua_State *L, int n) { + if (n == 0) + return newleaf(L, TTrue); + else { + TTree *tree, *nd; + if (n > 0) + tree = nd = newtree(L, 2 * n - 1); + else { /* negative: code it as !(-n) */ + n = -n; + tree = newtree(L, 2 * n); + tree->tag = TNot; + nd = sib1(tree); + } + fillseq(nd, TAny, n, NULL); /* sequence of 'n' any's */ + return tree; + } +} + + +/* +** Convert value at index 'idx' to a pattern +*/ +static TTree *getpatt (lua_State *L, int idx, int *len) { + TTree *tree; + switch (lua_type(L, idx)) { + case LUA_TSTRING: { + size_t slen; + const char *s = lua_tolstring(L, idx, &slen); /* get string */ + if (slen == 0) /* empty? */ + tree = newleaf(L, TTrue); /* always match */ + else { + tree = newtree(L, 2 * (slen - 1) + 1); + fillseq(tree, TChar, slen, s); /* sequence of 'slen' chars */ + } + break; + } + case LUA_TNUMBER: { + int n = lua_tointeger(L, idx); + tree = numtree(L, n); + break; + } + case LUA_TBOOLEAN: { + tree = (lua_toboolean(L, idx) ? newleaf(L, TTrue) : newleaf(L, TFalse)); + break; + } + case LUA_TTABLE: { + tree = newgrammar(L, idx); + break; + } + case LUA_TFUNCTION: { + tree = newtree(L, 2); + tree->tag = TRunTime; + tree->key = addtonewktable(L, 0, idx); + sib1(tree)->tag = TTrue; + break; + } + default: { + return gettree(L, idx, len); + } + } + lua_replace(L, idx); /* put new tree into 'idx' slot */ + if (len) + *len = getsize(L, idx); + return tree; +} + + +/* +** create a new tree, whith a new root and one sibling. +** Sibling must be on the Lua stack, at index 1. +*/ +static TTree *newroot1sib (lua_State *L, int tag) { + int s1; + TTree *tree1 = getpatt(L, 1, &s1); + TTree *tree = newtree(L, 1 + s1); /* create new tree */ + tree->tag = tag; + memcpy(sib1(tree), tree1, s1 * sizeof(TTree)); + copyktable(L, 1); + return tree; +} + + +/* +** create a new tree, whith a new root and 2 siblings. +** Siblings must be on the Lua stack, first one at index 1. +*/ +static TTree *newroot2sib (lua_State *L, int tag) { + int s1, s2; + TTree *tree1 = getpatt(L, 1, &s1); + TTree *tree2 = getpatt(L, 2, &s2); + TTree *tree = newtree(L, 1 + s1 + s2); /* create new tree */ + tree->tag = tag; + tree->u.ps = 1 + s1; + memcpy(sib1(tree), tree1, s1 * sizeof(TTree)); + memcpy(sib2(tree), tree2, s2 * sizeof(TTree)); + joinktables(L, 1, sib2(tree), 2); + return tree; +} + + +static int lp_P (lua_State *L) { + luaL_checkany(L, 1); + getpatt(L, 1, NULL); + lua_settop(L, 1); + return 1; +} + + +/* +** sequence operator; optimizations: +** false x => false, x true => x, true x => x +** (cannot do x . false => false because x may have runtime captures) +*/ +static int lp_seq (lua_State *L) { + TTree *tree1 = getpatt(L, 1, NULL); + TTree *tree2 = getpatt(L, 2, NULL); + if (tree1->tag == TFalse || tree2->tag == TTrue) + lua_pushvalue(L, 1); /* false . x == false, x . true = x */ + else if (tree1->tag == TTrue) + lua_pushvalue(L, 2); /* true . x = x */ + else + newroot2sib(L, TSeq); + return 1; +} + + +/* +** choice operator; optimizations: +** charset / charset => charset +** true / x => true, x / false => x, false / x => x +** (x / true is not equivalent to true) +*/ +static int lp_choice (lua_State *L) { + Charset st1, st2; + TTree *t1 = getpatt(L, 1, NULL); + TTree *t2 = getpatt(L, 2, NULL); + if (tocharset(t1, &st1) && tocharset(t2, &st2)) { + TTree *t = newcharset(L); + loopset(i, treebuffer(t)[i] = st1.cs[i] | st2.cs[i]); + } + else if (nofail(t1) || t2->tag == TFalse) + lua_pushvalue(L, 1); /* true / x => true, x / false => x */ + else if (t1->tag == TFalse) + lua_pushvalue(L, 2); /* false / x => x */ + else + newroot2sib(L, TChoice); + return 1; +} + + +/* +** p^n +*/ +static int lp_star (lua_State *L) { + int size1; + int n = (int)luaL_checkinteger(L, 2); + TTree *tree1 = getpatt(L, 1, &size1); + if (n >= 0) { /* seq tree1 (seq tree1 ... (seq tree1 (rep tree1))) */ + TTree *tree = newtree(L, (n + 1) * (size1 + 1)); + if (nullable(tree1)) + luaL_error(L, "loop body may accept empty string"); + while (n--) /* repeat 'n' times */ + tree = seqaux(tree, tree1, size1); + tree->tag = TRep; + memcpy(sib1(tree), tree1, size1 * sizeof(TTree)); + } + else { /* choice (seq tree1 ... choice tree1 true ...) true */ + TTree *tree; + n = -n; + /* size = (choice + seq + tree1 + true) * n, but the last has no seq */ + tree = newtree(L, n * (size1 + 3) - 1); + for (; n > 1; n--) { /* repeat (n - 1) times */ + tree->tag = TChoice; tree->u.ps = n * (size1 + 3) - 2; + sib2(tree)->tag = TTrue; + tree = sib1(tree); + tree = seqaux(tree, tree1, size1); + } + tree->tag = TChoice; tree->u.ps = size1 + 1; + sib2(tree)->tag = TTrue; + memcpy(sib1(tree), tree1, size1 * sizeof(TTree)); + } + copyktable(L, 1); + return 1; +} + + +/* +** #p == &p +*/ +static int lp_and (lua_State *L) { + newroot1sib(L, TAnd); + return 1; +} + + +/* +** -p == !p +*/ +static int lp_not (lua_State *L) { + newroot1sib(L, TNot); + return 1; +} + + +/* +** [t1 - t2] == Seq (Not t2) t1 +** If t1 and t2 are charsets, make their difference. +*/ +static int lp_sub (lua_State *L) { + Charset st1, st2; + int s1, s2; + TTree *t1 = getpatt(L, 1, &s1); + TTree *t2 = getpatt(L, 2, &s2); + if (tocharset(t1, &st1) && tocharset(t2, &st2)) { + TTree *t = newcharset(L); + loopset(i, treebuffer(t)[i] = st1.cs[i] & ~st2.cs[i]); + } + else { + TTree *tree = newtree(L, 2 + s1 + s2); + tree->tag = TSeq; /* sequence of... */ + tree->u.ps = 2 + s2; + sib1(tree)->tag = TNot; /* ...not... */ + memcpy(sib1(sib1(tree)), t2, s2 * sizeof(TTree)); /* ...t2 */ + memcpy(sib2(tree), t1, s1 * sizeof(TTree)); /* ... and t1 */ + joinktables(L, 1, sib1(tree), 2); + } + return 1; +} + + +static int lp_set (lua_State *L) { + size_t l; + const char *s = luaL_checklstring(L, 1, &l); + TTree *tree = newcharset(L); + while (l--) { + setchar(treebuffer(tree), (byte)(*s)); + s++; + } + return 1; +} + + +static int lp_range (lua_State *L) { + int arg; + int top = lua_gettop(L); + TTree *tree = newcharset(L); + for (arg = 1; arg <= top; arg++) { + int c; + size_t l; + const char *r = luaL_checklstring(L, arg, &l); + luaL_argcheck(L, l == 2, arg, "range must have two characters"); + for (c = (byte)r[0]; c <= (byte)r[1]; c++) + setchar(treebuffer(tree), c); + } + return 1; +} + + +/* +** Look-behind predicate +*/ +static int lp_behind (lua_State *L) { + TTree *tree; + TTree *tree1 = getpatt(L, 1, NULL); + int n = fixedlen(tree1); + luaL_argcheck(L, n >= 0, 1, "pattern may not have fixed length"); + luaL_argcheck(L, !hascaptures(tree1), 1, "pattern have captures"); + luaL_argcheck(L, n <= MAXBEHIND, 1, "pattern too long to look behind"); + tree = newroot1sib(L, TBehind); + tree->u.n = n; + return 1; +} + + +/* +** Create a non-terminal +*/ +static int lp_V (lua_State *L) { + TTree *tree = newleaf(L, TOpenCall); + luaL_argcheck(L, !lua_isnoneornil(L, 1), 1, "non-nil value expected"); + tree->key = addtonewktable(L, 0, 1); + return 1; +} + + +/* +** Create a tree for a non-empty capture, with a body and +** optionally with an associated Lua value (at index 'labelidx' in the +** stack) +*/ +static int capture_aux (lua_State *L, int cap, int labelidx) { + TTree *tree = newroot1sib(L, TCapture); + tree->cap = cap; + tree->key = (labelidx == 0) ? 0 : addtonewktable(L, 1, labelidx); + return 1; +} + + +/* +** Fill a tree with an empty capture, using an empty (TTrue) sibling. +*/ +static TTree *auxemptycap (TTree *tree, int cap) { + tree->tag = TCapture; + tree->cap = cap; + sib1(tree)->tag = TTrue; + return tree; +} + + +/* +** Create a tree for an empty capture +*/ +static TTree *newemptycap (lua_State *L, int cap) { + return auxemptycap(newtree(L, 2), cap); +} + + +/* +** Create a tree for an empty capture with an associated Lua value +*/ +static TTree *newemptycapkey (lua_State *L, int cap, int idx) { + TTree *tree = auxemptycap(newtree(L, 2), cap); + tree->key = addtonewktable(L, 0, idx); + return tree; +} + + +/* +** Captures with syntax p / v +** (function capture, query capture, string capture, or number capture) +*/ +static int lp_divcapture (lua_State *L) { + switch (lua_type(L, 2)) { + case LUA_TFUNCTION: return capture_aux(L, Cfunction, 2); + case LUA_TTABLE: return capture_aux(L, Cquery, 2); + case LUA_TSTRING: return capture_aux(L, Cstring, 2); + case LUA_TNUMBER: { + int n = lua_tointeger(L, 2); + TTree *tree = newroot1sib(L, TCapture); + luaL_argcheck(L, 0 <= n && n <= SHRT_MAX, 1, "invalid number"); + tree->cap = Cnum; + tree->key = n; + return 1; + } + default: return luaL_argerror(L, 2, "invalid replacement value"); + } +} + + +static int lp_substcapture (lua_State *L) { + return capture_aux(L, Csubst, 0); +} + + +static int lp_tablecapture (lua_State *L) { + return capture_aux(L, Ctable, 0); +} + + +static int lp_groupcapture (lua_State *L) { + if (lua_isnoneornil(L, 2)) + return capture_aux(L, Cgroup, 0); + else + return capture_aux(L, Cgroup, 2); +} + + +static int lp_foldcapture (lua_State *L) { + luaL_checktype(L, 2, LUA_TFUNCTION); + return capture_aux(L, Cfold, 2); +} + + +static int lp_simplecapture (lua_State *L) { + return capture_aux(L, Csimple, 0); +} + + +static int lp_poscapture (lua_State *L) { + newemptycap(L, Cposition); + return 1; +} + + +static int lp_argcapture (lua_State *L) { + int n = (int)luaL_checkinteger(L, 1); + TTree *tree = newemptycap(L, Carg); + tree->key = n; + luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index"); + return 1; +} + + +static int lp_backref (lua_State *L) { + luaL_checkany(L, 1); + newemptycapkey(L, Cbackref, 1); + return 1; +} + + +/* +** Constant capture +*/ +static int lp_constcapture (lua_State *L) { + int i; + int n = lua_gettop(L); /* number of values */ + if (n == 0) /* no values? */ + newleaf(L, TTrue); /* no capture */ + else if (n == 1) + newemptycapkey(L, Cconst, 1); /* single constant capture */ + else { /* create a group capture with all values */ + TTree *tree = newtree(L, 1 + 3 * (n - 1) + 2); + newktable(L, n); /* create a 'ktable' for new tree */ + tree->tag = TCapture; + tree->cap = Cgroup; + tree->key = 0; + tree = sib1(tree); + for (i = 1; i <= n - 1; i++) { + tree->tag = TSeq; + tree->u.ps = 3; /* skip TCapture and its sibling */ + auxemptycap(sib1(tree), Cconst); + sib1(tree)->key = addtoktable(L, i); + tree = sib2(tree); + } + auxemptycap(tree, Cconst); + tree->key = addtoktable(L, i); + } + return 1; +} + + +static int lp_matchtime (lua_State *L) { + TTree *tree; + luaL_checktype(L, 2, LUA_TFUNCTION); + tree = newroot1sib(L, TRunTime); + tree->key = addtonewktable(L, 1, 2); + return 1; +} + +/* }====================================================== */ + + +/* +** {====================================================== +** Grammar - Tree generation +** ======================================================= +*/ + +/* +** push on the stack the index and the pattern for the +** initial rule of grammar at index 'arg' in the stack; +** also add that index into position table. +*/ +static void getfirstrule (lua_State *L, int arg, int postab) { + lua_rawgeti(L, arg, 1); /* access first element */ + if (lua_isstring(L, -1)) { /* is it the name of initial rule? */ + lua_pushvalue(L, -1); /* duplicate it to use as key */ + lua_gettable(L, arg); /* get associated rule */ + } + else { + lua_pushinteger(L, 1); /* key for initial rule */ + lua_insert(L, -2); /* put it before rule */ + } + if (!testpattern(L, -1)) { /* initial rule not a pattern? */ + if (lua_isnil(L, -1)) + luaL_error(L, "grammar has no initial rule"); + else + luaL_error(L, "initial rule '%s' is not a pattern", lua_tostring(L, -2)); + } + lua_pushvalue(L, -2); /* push key */ + lua_pushinteger(L, 1); /* push rule position (after TGrammar) */ + lua_settable(L, postab); /* insert pair at position table */ +} + +/* +** traverse grammar at index 'arg', pushing all its keys and patterns +** into the stack. Create a new table (before all pairs key-pattern) to +** collect all keys and their associated positions in the final tree +** (the "position table"). +** Return the number of rules and (in 'totalsize') the total size +** for the new tree. +*/ +static int collectrules (lua_State *L, int arg, int *totalsize) { + int n = 1; /* to count number of rules */ + int postab = lua_gettop(L) + 1; /* index of position table */ + int size; /* accumulator for total size */ + lua_newtable(L); /* create position table */ + getfirstrule(L, arg, postab); + size = 2 + getsize(L, postab + 2); /* TGrammar + TRule + rule */ + lua_pushnil(L); /* prepare to traverse grammar table */ + while (lua_next(L, arg) != 0) { + if (lua_tonumber(L, -2) == 1 || + lp_equal(L, -2, postab + 1)) { /* initial rule? */ + lua_pop(L, 1); /* remove value (keep key for lua_next) */ + continue; + } + if (!testpattern(L, -1)) /* value is not a pattern? */ + luaL_error(L, "rule '%s' is not a pattern", val2str(L, -2)); + luaL_checkstack(L, LUA_MINSTACK, "grammar has too many rules"); + lua_pushvalue(L, -2); /* push key (to insert into position table) */ + lua_pushinteger(L, size); + lua_settable(L, postab); + size += 1 + getsize(L, -1); /* update size */ + lua_pushvalue(L, -2); /* push key (for next lua_next) */ + n++; + } + *totalsize = size + 1; /* TTrue to finish list of rules */ + return n; +} + + +static void buildgrammar (lua_State *L, TTree *grammar, int frule, int n) { + int i; + TTree *nd = sib1(grammar); /* auxiliary pointer to traverse the tree */ + for (i = 0; i < n; i++) { /* add each rule into new tree */ + int ridx = frule + 2*i + 1; /* index of i-th rule */ + int rulesize; + TTree *rn = gettree(L, ridx, &rulesize); + nd->tag = TRule; + nd->key = 0; + nd->cap = i; /* rule number */ + nd->u.ps = rulesize + 1; /* point to next rule */ + memcpy(sib1(nd), rn, rulesize * sizeof(TTree)); /* copy rule */ + mergektable(L, ridx, sib1(nd)); /* merge its ktable into new one */ + nd = sib2(nd); /* move to next rule */ + } + nd->tag = TTrue; /* finish list of rules */ +} + + +/* +** Check whether a tree has potential infinite loops +*/ +static int checkloops (TTree *tree) { + tailcall: + if (tree->tag == TRep && nullable(sib1(tree))) + return 1; + else if (tree->tag == TGrammar) + return 0; /* sub-grammars already checked */ + else { + switch (numsiblings[tree->tag]) { + case 1: /* return checkloops(sib1(tree)); */ + tree = sib1(tree); goto tailcall; + case 2: + if (checkloops(sib1(tree))) return 1; + /* else return checkloops(sib2(tree)); */ + tree = sib2(tree); goto tailcall; + default: assert(numsiblings[tree->tag] == 0); return 0; + } + } +} + + +static int verifyerror (lua_State *L, int *passed, int npassed) { + int i, j; + for (i = npassed - 1; i >= 0; i--) { /* search for a repetition */ + for (j = i - 1; j >= 0; j--) { + if (passed[i] == passed[j]) { + lua_rawgeti(L, -1, passed[i]); /* get rule's key */ + return luaL_error(L, "rule '%s' may be left recursive", val2str(L, -1)); + } + } + } + return luaL_error(L, "too many left calls in grammar"); +} + + +/* +** Check whether a rule can be left recursive; raise an error in that +** case; otherwise return 1 iff pattern is nullable. +** The return value is used to check sequences, where the second pattern +** is only relevant if the first is nullable. +** Parameter 'nb' works as an accumulator, to allow tail calls in +** choices. ('nb' true makes function returns true.) +** Assume ktable at the top of the stack. +*/ +static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed, + int nb) { + tailcall: + switch (tree->tag) { + case TChar: case TSet: case TAny: + case TFalse: + return nb; /* cannot pass from here */ + case TTrue: + case TBehind: /* look-behind cannot have calls */ + return 1; + case TNot: case TAnd: case TRep: + /* return verifyrule(L, sib1(tree), passed, npassed, 1); */ + tree = sib1(tree); nb = 1; goto tailcall; + case TCapture: case TRunTime: + /* return verifyrule(L, sib1(tree), passed, npassed, nb); */ + tree = sib1(tree); goto tailcall; + case TCall: + /* return verifyrule(L, sib2(tree), passed, npassed, nb); */ + tree = sib2(tree); goto tailcall; + case TSeq: /* only check 2nd child if first is nb */ + if (!verifyrule(L, sib1(tree), passed, npassed, 0)) + return nb; + /* else return verifyrule(L, sib2(tree), passed, npassed, nb); */ + tree = sib2(tree); goto tailcall; + case TChoice: /* must check both children */ + nb = verifyrule(L, sib1(tree), passed, npassed, nb); + /* return verifyrule(L, sib2(tree), passed, npassed, nb); */ + tree = sib2(tree); goto tailcall; + case TRule: + if (npassed >= MAXRULES) + return verifyerror(L, passed, npassed); + else { + passed[npassed++] = tree->key; + /* return verifyrule(L, sib1(tree), passed, npassed); */ + tree = sib1(tree); goto tailcall; + } + case TGrammar: + return nullable(tree); /* sub-grammar cannot be left recursive */ + default: assert(0); return 0; + } +} + + +static void verifygrammar (lua_State *L, TTree *grammar) { + int passed[MAXRULES]; + TTree *rule; + /* check left-recursive rules */ + for (rule = sib1(grammar); rule->tag == TRule; rule = sib2(rule)) { + if (rule->key == 0) continue; /* unused rule */ + verifyrule(L, sib1(rule), passed, 0, 0); + } + assert(rule->tag == TTrue); + /* check infinite loops inside rules */ + for (rule = sib1(grammar); rule->tag == TRule; rule = sib2(rule)) { + if (rule->key == 0) continue; /* unused rule */ + if (checkloops(sib1(rule))) { + lua_rawgeti(L, -1, rule->key); /* get rule's key */ + luaL_error(L, "empty loop in rule '%s'", val2str(L, -1)); + } + } + assert(rule->tag == TTrue); +} + + +/* +** Give a name for the initial rule if it is not referenced +*/ +static void initialrulename (lua_State *L, TTree *grammar, int frule) { + if (sib1(grammar)->key == 0) { /* initial rule is not referenced? */ + int n = lua_rawlen(L, -1) + 1; /* index for name */ + lua_pushvalue(L, frule); /* rule's name */ + lua_rawseti(L, -2, n); /* ktable was on the top of the stack */ + sib1(grammar)->key = n; + } +} + + +static TTree *newgrammar (lua_State *L, int arg) { + int treesize; + int frule = lua_gettop(L) + 2; /* position of first rule's key */ + int n = collectrules(L, arg, &treesize); + TTree *g = newtree(L, treesize); + luaL_argcheck(L, n <= MAXRULES, arg, "grammar has too many rules"); + g->tag = TGrammar; g->u.n = n; + lua_newtable(L); /* create 'ktable' */ + lua_setuservalue(L, -2); + buildgrammar(L, g, frule, n); + lua_getuservalue(L, -1); /* get 'ktable' for new tree */ + finalfix(L, frule - 1, g, sib1(g)); + initialrulename(L, g, frule); + verifygrammar(L, g); + lua_pop(L, 1); /* remove 'ktable' */ + lua_insert(L, -(n * 2 + 2)); /* move new table to proper position */ + lua_pop(L, n * 2 + 1); /* remove position table + rule pairs */ + return g; /* new table at the top of the stack */ +} + +/* }====================================================== */ + + +static Instruction *prepcompile (lua_State *L, Pattern *p, int idx) { + lua_getuservalue(L, idx); /* push 'ktable' (may be used by 'finalfix') */ + finalfix(L, 0, NULL, p->tree); + lua_pop(L, 1); /* remove 'ktable' */ + return compile(L, p); +} + + +static int lp_printtree (lua_State *L) { + TTree *tree = getpatt(L, 1, NULL); + int c = lua_toboolean(L, 2); + if (c) { + lua_getuservalue(L, 1); /* push 'ktable' (may be used by 'finalfix') */ + finalfix(L, 0, NULL, tree); + lua_pop(L, 1); /* remove 'ktable' */ + } + printktable(L, 1); + printtree(tree, 0); + return 0; +} + + +static int lp_printcode (lua_State *L) { + Pattern *p = getpattern(L, 1); + printktable(L, 1); + if (p->code == NULL) /* not compiled yet? */ + prepcompile(L, p, 1); + printpatt(p->code, p->codesize); + return 0; +} + + +/* +** Get the initial position for the match, interpreting negative +** values from the end of the subject +*/ +static size_t initposition (lua_State *L, size_t len) { + lua_Integer ii = luaL_optinteger(L, 3, 1); + if (ii > 0) { /* positive index? */ + if ((size_t)ii <= len) /* inside the string? */ + return (size_t)ii - 1; /* return it (corrected to 0-base) */ + else return len; /* crop at the end */ + } + else { /* negative index */ + if ((size_t)(-ii) <= len) /* inside the string? */ + return len - ((size_t)(-ii)); /* return position from the end */ + else return 0; /* crop at the beginning */ + } +} + + +/* +** Main match function +*/ +static int lp_match (lua_State *L) { + Capture capture[INITCAPSIZE]; + const char *r; + size_t l; + Pattern *p = (getpatt(L, 1, NULL), getpattern(L, 1)); + Instruction *code = (p->code != NULL) ? p->code : prepcompile(L, p, 1); + const char *s = luaL_checklstring(L, SUBJIDX, &l); + size_t i = initposition(L, l); + int ptop = lua_gettop(L); + lua_pushnil(L); /* initialize subscache */ + lua_pushlightuserdata(L, capture); /* initialize caplistidx */ + lua_getuservalue(L, 1); /* initialize penvidx */ + r = match(L, s, s + i, s + l, code, capture, ptop); + if (r == NULL) { + lua_pushnil(L); + return 1; + } + return getcaptures(L, s, r, ptop); +} + + + +/* +** {====================================================== +** Library creation and functions not related to matching +** ======================================================= +*/ + +/* maximum limit for stack size */ +#define MAXLIM (INT_MAX / 100) + +static int lp_setmax (lua_State *L) { + lua_Integer lim = luaL_checkinteger(L, 1); + luaL_argcheck(L, 0 < lim && lim <= MAXLIM, 1, "out of range"); + lua_settop(L, 1); + lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); + return 0; +} + + +static int lp_version (lua_State *L) { + lua_pushstring(L, VERSION); + return 1; +} + + +static int lp_type (lua_State *L) { + if (testpattern(L, 1)) + lua_pushliteral(L, "pattern"); + else + lua_pushnil(L); + return 1; +} + + +int lp_gc (lua_State *L) { + Pattern *p = getpattern(L, 1); + realloccode(L, p, 0); /* delete code block */ + return 0; +} + + +static void createcat (lua_State *L, const char *catname, int (catf) (int)) { + TTree *t = newcharset(L); + int i; + for (i = 0; i <= UCHAR_MAX; i++) + if (catf(i)) setchar(treebuffer(t), i); + lua_setfield(L, -2, catname); +} + + +static int lp_locale (lua_State *L) { + if (lua_isnoneornil(L, 1)) { + lua_settop(L, 0); + lua_createtable(L, 0, 12); + } + else { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); + } + createcat(L, "alnum", isalnum); + createcat(L, "alpha", isalpha); + createcat(L, "cntrl", iscntrl); + createcat(L, "digit", isdigit); + createcat(L, "graph", isgraph); + createcat(L, "lower", islower); + createcat(L, "print", isprint); + createcat(L, "punct", ispunct); + createcat(L, "space", isspace); + createcat(L, "upper", isupper); + createcat(L, "xdigit", isxdigit); + return 1; +} + + +static struct luaL_Reg pattreg[] = { + {"ptree", lp_printtree}, + {"pcode", lp_printcode}, + {"match", lp_match}, + {"B", lp_behind}, + {"V", lp_V}, + {"C", lp_simplecapture}, + {"Cc", lp_constcapture}, + {"Cmt", lp_matchtime}, + {"Cb", lp_backref}, + {"Carg", lp_argcapture}, + {"Cp", lp_poscapture}, + {"Cs", lp_substcapture}, + {"Ct", lp_tablecapture}, + {"Cf", lp_foldcapture}, + {"Cg", lp_groupcapture}, + {"P", lp_P}, + {"S", lp_set}, + {"R", lp_range}, + {"locale", lp_locale}, + {"version", lp_version}, + {"setmaxstack", lp_setmax}, + {"type", lp_type}, + {NULL, NULL} +}; + + +static struct luaL_Reg metareg[] = { + {"__mul", lp_seq}, + {"__add", lp_choice}, + {"__pow", lp_star}, + {"__gc", lp_gc}, + {"__len", lp_and}, + {"__div", lp_divcapture}, + {"__unm", lp_not}, + {"__sub", lp_sub}, + {NULL, NULL} +}; + + +int luaopen_lpeg (lua_State *L); +int luaopen_lpeg (lua_State *L) { + luaL_newmetatable(L, PATTERN_T); + lua_pushnumber(L, MAXBACK); /* initialize maximum backtracking */ + lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); + luaL_setfuncs(L, metareg, 0); + luaL_newlib(L, pattreg); + lua_pushvalue(L, -1); + lua_setfield(L, -3, "__index"); + return 1; +} + +/* }====================================================== */ diff --git a/luaclib/lpeg/lptree.h b/luaclib/lpeg/lptree.h new file mode 100644 index 0000000..b69528a --- /dev/null +++ b/luaclib/lpeg/lptree.h @@ -0,0 +1,77 @@ +/* +** $Id: lptree.h,v 1.2 2013/03/24 13:51:12 roberto Exp $ +*/ + +#if !defined(lptree_h) +#define lptree_h + + +#include "lptypes.h" + + +/* +** types of trees +*/ +typedef enum TTag { + TChar = 0, TSet, TAny, /* standard PEG elements */ + TTrue, TFalse, + TRep, + TSeq, TChoice, + TNot, TAnd, + TCall, + TOpenCall, + TRule, /* sib1 is rule's pattern, sib2 is 'next' rule */ + TGrammar, /* sib1 is initial (and first) rule */ + TBehind, /* match behind */ + TCapture, /* regular capture */ + TRunTime /* run-time capture */ +} TTag; + +/* number of siblings for each tree */ +extern const byte numsiblings[]; + + +/* +** Tree trees +** The first sibling of a tree (if there is one) is immediately after +** the tree. A reference to a second sibling (ps) is its position +** relative to the position of the tree itself. A key in ktable +** uses the (unique) address of the original tree that created that +** entry. NULL means no data. +*/ +typedef struct TTree { + byte tag; + byte cap; /* kind of capture (if it is a capture) */ + unsigned short key; /* key in ktable for Lua data (0 if no key) */ + union { + int ps; /* occasional second sibling */ + int n; /* occasional counter */ + } u; +} TTree; + + +/* +** A complete pattern has its tree plus, if already compiled, +** its corresponding code +*/ +typedef struct Pattern { + union Instruction *code; + int codesize; + TTree tree[1]; +} Pattern; + + +/* number of siblings for each tree */ +extern const byte numsiblings[]; + +/* access to siblings */ +#define sib1(t) ((t) + 1) +#define sib2(t) ((t) + (t)->u.ps) + + + + + + +#endif + diff --git a/luaclib/lpeg/lptypes.h b/luaclib/lpeg/lptypes.h new file mode 100644 index 0000000..5eb7987 --- /dev/null +++ b/luaclib/lpeg/lptypes.h @@ -0,0 +1,149 @@ +/* +** $Id: lptypes.h,v 1.14 2015/09/28 17:17:41 roberto Exp $ +** LPeg - PEG pattern matching for Lua +** Copyright 2007-2015, Lua.org & PUC-Rio (see 'lpeg.html' for license) +** written by Roberto Ierusalimschy +*/ + +#if !defined(lptypes_h) +#define lptypes_h + + +#if !defined(LPEG_DEBUG) +#define NDEBUG +#endif + +#include +#include + +#include "lua.h" + + +#define VERSION "1.0.0" + + +#define PATTERN_T "lpeg-pattern" +#define MAXSTACKIDX "lpeg-maxstack" + + +/* +** compatibility with Lua 5.1 +*/ +#if (LUA_VERSION_NUM == 501) + +#define lp_equal lua_equal + +#define lua_getuservalue lua_getfenv +#define lua_setuservalue lua_setfenv + +#define lua_rawlen lua_objlen + +#define luaL_setfuncs(L,f,n) luaL_register(L,NULL,f) +#define luaL_newlib(L,f) luaL_register(L,"lpeg",f) + +#endif + + +#if !defined(lp_equal) +#define lp_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#endif + + +/* default maximum size for call/backtrack stack */ +#if !defined(MAXBACK) +#define MAXBACK 400 +#endif + + +/* maximum number of rules in a grammar */ +#if !defined(MAXRULES) +#define MAXRULES 1000 +#endif + + + +/* initial size for capture's list */ +#define INITCAPSIZE 32 + + +/* index, on Lua stack, for subject */ +#define SUBJIDX 2 + +/* number of fixed arguments to 'match' (before capture arguments) */ +#define FIXEDARGS 3 + +/* index, on Lua stack, for capture list */ +#define caplistidx(ptop) ((ptop) + 2) + +/* index, on Lua stack, for pattern's ktable */ +#define ktableidx(ptop) ((ptop) + 3) + +/* index, on Lua stack, for backtracking stack */ +#define stackidx(ptop) ((ptop) + 4) + + + +typedef unsigned char byte; + + +#define BITSPERCHAR 8 + +#define CHARSETSIZE ((UCHAR_MAX/BITSPERCHAR) + 1) + + + +typedef struct Charset { + byte cs[CHARSETSIZE]; +} Charset; + + + +#define loopset(v,b) { int v; for (v = 0; v < CHARSETSIZE; v++) {b;} } + +/* access to charset */ +#define treebuffer(t) ((byte *)((t) + 1)) + +/* number of slots needed for 'n' bytes */ +#define bytes2slots(n) (((n) - 1) / sizeof(TTree) + 1) + +/* set 'b' bit in charset 'cs' */ +#define setchar(cs,b) ((cs)[(b) >> 3] |= (1 << ((b) & 7))) + + +/* +** in capture instructions, 'kind' of capture and its offset are +** packed in field 'aux', 4 bits for each +*/ +#define getkind(op) ((op)->i.aux & 0xF) +#define getoff(op) (((op)->i.aux >> 4) & 0xF) +#define joinkindoff(k,o) ((k) | ((o) << 4)) + +#define MAXOFF 0xF +#define MAXAUX 0xFF + + +/* maximum number of bytes to look behind */ +#define MAXBEHIND MAXAUX + + +/* maximum size (in elements) for a pattern */ +#define MAXPATTSIZE (SHRT_MAX - 10) + + +/* size (in elements) for an instruction plus extra l bytes */ +#define instsize(l) (((l) + sizeof(Instruction) - 1)/sizeof(Instruction) + 1) + + +/* size (in elements) for a ISet instruction */ +#define CHARSETINSTSIZE instsize(CHARSETSIZE) + +/* size (in elements) for a IFunc instruction */ +#define funcinstsize(p) ((p)->i.aux + 2) + + + +#define testchar(st,c) (((int)(st)[((c) >> 3)] & (1 << ((c) & 7)))) + + +#endif + diff --git a/luaclib/lpeg/lpvm.c b/luaclib/lpeg/lpvm.c new file mode 100644 index 0000000..eaf2ebf --- /dev/null +++ b/luaclib/lpeg/lpvm.c @@ -0,0 +1,355 @@ +/* +** $Id: lpvm.c,v 1.6 2015/09/28 17:01:25 roberto Exp $ +** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license) +*/ + +#include +#include + + +#include "lua.h" +#include "lauxlib.h" + +#include "lpcap.h" +#include "lptypes.h" +#include "lpvm.h" +#include "lpprint.h" + + +/* initial size for call/backtrack stack */ +#if !defined(INITBACK) +#define INITBACK MAXBACK +#endif + + +#define getoffset(p) (((p) + 1)->offset) + +static const Instruction giveup = {{IGiveup, 0, 0}}; + + +/* +** {====================================================== +** Virtual Machine +** ======================================================= +*/ + + +typedef struct Stack { + const char *s; /* saved position (or NULL for calls) */ + const Instruction *p; /* next instruction */ + int caplevel; +} Stack; + + +#define getstackbase(L, ptop) ((Stack *)lua_touserdata(L, stackidx(ptop))) + + +/* +** Double the size of the array of captures +*/ +static Capture *doublecap (lua_State *L, Capture *cap, int captop, int ptop) { + Capture *newc; + if (captop >= INT_MAX/((int)sizeof(Capture) * 2)) + luaL_error(L, "too many captures"); + newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture)); + memcpy(newc, cap, captop * sizeof(Capture)); + lua_replace(L, caplistidx(ptop)); + return newc; +} + + +/* +** Double the size of the stack +*/ +static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) { + Stack *stack = getstackbase(L, ptop); + Stack *newstack; + int n = *stacklimit - stack; /* current stack size */ + int max, newn; + lua_getfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX); + max = lua_tointeger(L, -1); /* maximum allowed size */ + lua_pop(L, 1); + if (n >= max) /* already at maximum size? */ + luaL_error(L, "backtrack stack overflow (current limit is %d)", max); + newn = 2 * n; /* new size */ + if (newn > max) newn = max; + newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack)); + memcpy(newstack, stack, n * sizeof(Stack)); + lua_replace(L, stackidx(ptop)); + *stacklimit = newstack + newn; + return newstack + n; /* return next position */ +} + + +/* +** Interpret the result of a dynamic capture: false -> fail; +** true -> keep current position; number -> next position. +** Return new subject position. 'fr' is stack index where +** is the result; 'curr' is current subject position; 'limit' +** is subject's size. +*/ +static int resdyncaptures (lua_State *L, int fr, int curr, int limit) { + lua_Integer res; + if (!lua_toboolean(L, fr)) { /* false value? */ + lua_settop(L, fr - 1); /* remove results */ + return -1; /* and fail */ + } + else if (lua_isboolean(L, fr)) /* true? */ + res = curr; /* keep current position */ + else { + res = lua_tointeger(L, fr) - 1; /* new position */ + if (res < curr || res > limit) + luaL_error(L, "invalid position returned by match-time capture"); + } + lua_remove(L, fr); /* remove first result (offset) */ + return res; +} + + +/* +** Add capture values returned by a dynamic capture to the capture list +** 'base', nested inside a group capture. 'fd' indexes the first capture +** value, 'n' is the number of values (at least 1). +*/ +static void adddyncaptures (const char *s, Capture *base, int n, int fd) { + int i; + /* Cgroup capture is already there */ + assert(base[0].kind == Cgroup && base[0].siz == 0); + base[0].idx = 0; /* make it an anonymous group */ + for (i = 1; i <= n; i++) { /* add runtime captures */ + base[i].kind = Cruntime; + base[i].siz = 1; /* mark it as closed */ + base[i].idx = fd + i - 1; /* stack index of capture value */ + base[i].s = s; + } + base[i].kind = Cclose; /* close group */ + base[i].siz = 1; + base[i].s = s; +} + + +/* +** Remove dynamic captures from the Lua stack (called in case of failure) +*/ +static int removedyncap (lua_State *L, Capture *capture, + int level, int last) { + int id = finddyncap(capture + level, capture + last); /* index of 1st cap. */ + int top = lua_gettop(L); + if (id == 0) return 0; /* no dynamic captures? */ + lua_settop(L, id - 1); /* remove captures */ + return top - id + 1; /* number of values removed */ +} + + +/* +** Opcode interpreter +*/ +const char *match (lua_State *L, const char *o, const char *s, const char *e, + Instruction *op, Capture *capture, int ptop) { + Stack stackbase[INITBACK]; + Stack *stacklimit = stackbase + INITBACK; + Stack *stack = stackbase; /* point to first empty slot in stack */ + int capsize = INITCAPSIZE; + int captop = 0; /* point to first empty slot in captures */ + int ndyncap = 0; /* number of dynamic captures (in Lua stack) */ + const Instruction *p = op; /* current instruction */ + stack->p = &giveup; stack->s = s; stack->caplevel = 0; stack++; + lua_pushlightuserdata(L, stackbase); + for (;;) { +#if defined(DEBUG) + printf("s: |%s| stck:%d, dyncaps:%d, caps:%d ", + s, stack - getstackbase(L, ptop), ndyncap, captop); + printinst(op, p); + printcaplist(capture, capture + captop); +#endif + assert(stackidx(ptop) + ndyncap == lua_gettop(L) && ndyncap <= captop); + switch ((Opcode)p->i.code) { + case IEnd: { + assert(stack == getstackbase(L, ptop) + 1); + capture[captop].kind = Cclose; + capture[captop].s = NULL; + return s; + } + case IGiveup: { + assert(stack == getstackbase(L, ptop)); + return NULL; + } + case IRet: { + assert(stack > getstackbase(L, ptop) && (stack - 1)->s == NULL); + p = (--stack)->p; + continue; + } + case IAny: { + if (s < e) { p++; s++; } + else goto fail; + continue; + } + case ITestAny: { + if (s < e) p += 2; + else p += getoffset(p); + continue; + } + case IChar: { + if ((byte)*s == p->i.aux && s < e) { p++; s++; } + else goto fail; + continue; + } + case ITestChar: { + if ((byte)*s == p->i.aux && s < e) p += 2; + else p += getoffset(p); + continue; + } + case ISet: { + int c = (byte)*s; + if (testchar((p+1)->buff, c) && s < e) + { p += CHARSETINSTSIZE; s++; } + else goto fail; + continue; + } + case ITestSet: { + int c = (byte)*s; + if (testchar((p + 2)->buff, c) && s < e) + p += 1 + CHARSETINSTSIZE; + else p += getoffset(p); + continue; + } + case IBehind: { + int n = p->i.aux; + if (n > s - o) goto fail; + s -= n; p++; + continue; + } + case ISpan: { + for (; s < e; s++) { + int c = (byte)*s; + if (!testchar((p+1)->buff, c)) break; + } + p += CHARSETINSTSIZE; + continue; + } + case IJmp: { + p += getoffset(p); + continue; + } + case IChoice: { + if (stack == stacklimit) + stack = doublestack(L, &stacklimit, ptop); + stack->p = p + getoffset(p); + stack->s = s; + stack->caplevel = captop; + stack++; + p += 2; + continue; + } + case ICall: { + if (stack == stacklimit) + stack = doublestack(L, &stacklimit, ptop); + stack->s = NULL; + stack->p = p + 2; /* save return address */ + stack++; + p += getoffset(p); + continue; + } + case ICommit: { + assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); + stack--; + p += getoffset(p); + continue; + } + case IPartialCommit: { + assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); + (stack - 1)->s = s; + (stack - 1)->caplevel = captop; + p += getoffset(p); + continue; + } + case IBackCommit: { + assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL); + s = (--stack)->s; + captop = stack->caplevel; + p += getoffset(p); + continue; + } + case IFailTwice: + assert(stack > getstackbase(L, ptop)); + stack--; + /* go through */ + case IFail: + fail: { /* pattern failed: try to backtrack */ + do { /* remove pending calls */ + assert(stack > getstackbase(L, ptop)); + s = (--stack)->s; + } while (s == NULL); + if (ndyncap > 0) /* is there matchtime captures? */ + ndyncap -= removedyncap(L, capture, stack->caplevel, captop); + captop = stack->caplevel; + p = stack->p; + continue; + } + case ICloseRunTime: { + CapState cs; + int rem, res, n; + int fr = lua_gettop(L) + 1; /* stack index of first result */ + cs.s = o; cs.L = L; cs.ocap = capture; cs.ptop = ptop; + n = runtimecap(&cs, capture + captop, s, &rem); /* call function */ + captop -= n; /* remove nested captures */ + fr -= rem; /* 'rem' items were popped from Lua stack */ + res = resdyncaptures(L, fr, s - o, e - o); /* get result */ + if (res == -1) /* fail? */ + goto fail; + s = o + res; /* else update current position */ + n = lua_gettop(L) - fr + 1; /* number of new captures */ + ndyncap += n - rem; /* update number of dynamic captures */ + if (n > 0) { /* any new capture? */ + if ((captop += n + 2) >= capsize) { + capture = doublecap(L, capture, captop, ptop); + capsize = 2 * captop; + } + /* add new captures to 'capture' list */ + adddyncaptures(s, capture + captop - n - 2, n, fr); + } + p++; + continue; + } + case ICloseCapture: { + const char *s1 = s; + assert(captop > 0); + /* if possible, turn capture into a full capture */ + if (capture[captop - 1].siz == 0 && + s1 - capture[captop - 1].s < UCHAR_MAX) { + capture[captop - 1].siz = s1 - capture[captop - 1].s + 1; + p++; + continue; + } + else { + capture[captop].siz = 1; /* mark entry as closed */ + capture[captop].s = s; + goto pushcapture; + } + } + case IOpenCapture: + capture[captop].siz = 0; /* mark entry as open */ + capture[captop].s = s; + goto pushcapture; + case IFullCapture: + capture[captop].siz = getoff(p) + 1; /* save capture size */ + capture[captop].s = s - getoff(p); + /* goto pushcapture; */ + pushcapture: { + capture[captop].idx = p->i.key; + capture[captop].kind = getkind(p); + if (++captop >= capsize) { + capture = doublecap(L, capture, captop, ptop); + capsize = 2 * captop; + } + p++; + continue; + } + default: assert(0); return NULL; + } + } +} + +/* }====================================================== */ + + diff --git a/luaclib/lpeg/lpvm.h b/luaclib/lpeg/lpvm.h new file mode 100644 index 0000000..757b9e1 --- /dev/null +++ b/luaclib/lpeg/lpvm.h @@ -0,0 +1,58 @@ +/* +** $Id: lpvm.h,v 1.3 2014/02/21 13:06:41 roberto Exp $ +*/ + +#if !defined(lpvm_h) +#define lpvm_h + +#include "lpcap.h" + + +/* Virtual Machine's instructions */ +typedef enum Opcode { + IAny, /* if no char, fail */ + IChar, /* if char != aux, fail */ + ISet, /* if char not in buff, fail */ + ITestAny, /* in no char, jump to 'offset' */ + ITestChar, /* if char != aux, jump to 'offset' */ + ITestSet, /* if char not in buff, jump to 'offset' */ + ISpan, /* read a span of chars in buff */ + IBehind, /* walk back 'aux' characters (fail if not possible) */ + IRet, /* return from a rule */ + IEnd, /* end of pattern */ + IChoice, /* stack a choice; next fail will jump to 'offset' */ + IJmp, /* jump to 'offset' */ + ICall, /* call rule at 'offset' */ + IOpenCall, /* call rule number 'key' (must be closed to a ICall) */ + ICommit, /* pop choice and jump to 'offset' */ + IPartialCommit, /* update top choice to current position and jump */ + IBackCommit, /* "fails" but jump to its own 'offset' */ + IFailTwice, /* pop one choice and then fail */ + IFail, /* go back to saved state on choice and jump to saved offset */ + IGiveup, /* internal use */ + IFullCapture, /* complete capture of last 'off' chars */ + IOpenCapture, /* start a capture */ + ICloseCapture, + ICloseRunTime +} Opcode; + + + +typedef union Instruction { + struct Inst { + byte code; + byte aux; + short key; + } i; + int offset; + byte buff[1]; +} Instruction; + + +void printpatt (Instruction *p, int n); +const char *match (lua_State *L, const char *o, const char *s, const char *e, + Instruction *op, Capture *capture, int ptop); + + +#endif + diff --git a/luaclib/lpeg/makefile b/luaclib/lpeg/makefile new file mode 100644 index 0000000..7a8463e --- /dev/null +++ b/luaclib/lpeg/makefile @@ -0,0 +1,55 @@ +LIBNAME = lpeg +LUADIR = ../lua/ + +COPT = -O2 +# COPT = -DLPEG_DEBUG -g + +CWARNS = -Wall -Wextra -pedantic \ + -Waggregate-return \ + -Wcast-align \ + -Wcast-qual \ + -Wdisabled-optimization \ + -Wpointer-arith \ + -Wshadow \ + -Wsign-compare \ + -Wundef \ + -Wwrite-strings \ + -Wbad-function-cast \ + -Wdeclaration-after-statement \ + -Wmissing-prototypes \ + -Wnested-externs \ + -Wstrict-prototypes \ +# -Wunreachable-code \ + + +CFLAGS = $(CWARNS) $(COPT) -std=c99 -I$(LUADIR) -fPIC +CC = gcc + +FILES = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o + +# For Linux +linux: + make lpeg.so "DLLFLAGS = -shared -fPIC" + +# For Mac OS +macosx: + make lpeg.so "DLLFLAGS = -bundle -undefined dynamic_lookup" + +lpeg.so: $(FILES) + env $(CC) $(DLLFLAGS) $(FILES) -o lpeg.so + +$(FILES): makefile + +test: test.lua re.lua lpeg.so + ./test.lua + +clean: + rm -f $(FILES) lpeg.so + + +lpcap.o: lpcap.c lpcap.h lptypes.h +lpcode.o: lpcode.c lptypes.h lpcode.h lptree.h lpvm.h lpcap.h +lpprint.o: lpprint.c lptypes.h lpprint.h lptree.h lpvm.h lpcap.h +lptree.o: lptree.c lptypes.h lpcap.h lpcode.h lptree.h lpvm.h lpprint.h +lpvm.o: lpvm.c lpcap.h lptypes.h lpvm.h lpprint.h lptree.h + diff --git a/luaclib/lpeg/re.html b/luaclib/lpeg/re.html new file mode 100644 index 0000000..d0d9744 --- /dev/null +++ b/luaclib/lpeg/re.html @@ -0,0 +1,498 @@ + + + + LPeg.re - Regex syntax for LPEG + + + + + + + +
+ +
+ +
LPeg.re
+
+ Regex syntax for LPEG +
+
+ +
+ + + +
+ +

The re Module

+ +

+The re module +(provided by file re.lua in the distribution) +supports a somewhat conventional regex syntax +for pattern usage within LPeg. +

+ +

+The next table summarizes re's syntax. +A p represents an arbitrary pattern; +num represents a number ([0-9]+); +name represents an identifier +([a-zA-Z][a-zA-Z0-9_]*). +Constructions are listed in order of decreasing precedence. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SyntaxDescription
( p ) grouping
'string' literal string
"string" literal string
[class] character class
. any character
%namepattern defs[name] or a pre-defined pattern
namenon terminal
<name>non terminal
{} position capture
{ p } simple capture
{: p :} anonymous group capture
{:name: p :} named group capture
{~ p ~} substitution capture
{| p |} table capture
=name back reference +
p ? optional match
p * zero or more repetitions
p + one or more repetitions
p^num exactly n repetitions
p^+numat least n repetitions
p^-numat most n repetitions
p -> 'string' string capture
p -> "string" string capture
p -> num numbered capture
p -> name function/query/string capture +equivalent to p / defs[name]
p => name match-time capture +equivalent to lpeg.Cmt(p, defs[name])
& p and predicate
! p not predicate
p1 p2 concatenation
p1 / p2 ordered choice
(name <- p)+ grammar
+

+Any space appearing in a syntax description can be +replaced by zero or more space characters and Lua-style comments +(-- until end of line). +

+ +

+Character classes define sets of characters. +An initial ^ complements the resulting set. +A range x-y includes in the set +all characters with codes between the codes of x and y. +A pre-defined class %name includes all +characters of that class. +A simple character includes itself in the set. +The only special characters inside a class are ^ +(special only if it is the first character); +] +(can be included in the set as the first character, +after the optional ^); +% (special only if followed by a letter); +and - +(can be included in the set as the first or the last character). +

+ +

+Currently the pre-defined classes are similar to those from the +Lua's string library +(%a for letters, +%A for non letters, etc.). +There is also a class %nl +containing only the newline character, +which is particularly handy for grammars written inside long strings, +as long strings do not interpret escape sequences like \n. +

+ + +

Functions

+ +

re.compile (string, [, defs])

+

+Compiles the given string and +returns an equivalent LPeg pattern. +The given string may define either an expression or a grammar. +The optional defs table provides extra Lua values +to be used by the pattern. +

+ +

re.find (subject, pattern [, init])

+

+Searches the given pattern in the given subject. +If it finds a match, +returns the index where this occurrence starts and +the index where it ends. +Otherwise, returns nil. +

+ +

+An optional numeric argument init makes the search +starts at that position in the subject string. +As usual in Lua libraries, +a negative value counts from the end. +

+ +

re.gsub (subject, pattern, replacement)

+

+Does a global substitution, +replacing all occurrences of pattern +in the given subject by replacement. + +

re.match (subject, pattern)

+

+Matches the given pattern against the given subject, +returning all captures. +

+ +

re.updatelocale ()

+

+Updates the pre-defined character classes to the current locale. +

+ + +

Some Examples

+ +

A complete simple program

+

+The next code shows a simple complete Lua program using +the re module: +

+
+local re = require"re"
+
+-- find the position of the first numeral in a string
+print(re.find("the number 423 is odd", "[0-9]+"))  --> 12    14
+
+-- returns all words in a string
+print(re.match("the number 423 is odd", "({%a+} / .)*"))
+--> the    number    is    odd
+
+-- returns the first numeral in a string
+print(re.match("the number 423 is odd", "s <- {%d+} / . s"))
+--> 423
+
+print(re.gsub("hello World", "[aeiou]", "."))
+--> h.ll. W.rld
+
+ + +

Balanced parentheses

+

+The following call will produce the same pattern produced by the +Lua expression in the +balanced parentheses example: +

+
+b = re.compile[[  balanced <- "(" ([^()] / balanced)* ")"  ]]
+
+ +

String reversal

+

+The next example reverses a string: +

+
+rev = re.compile[[ R <- (!.) -> '' / ({.} R) -> '%2%1']]
+print(rev:match"0123456789")   --> 9876543210
+
+ +

CSV decoder

+

+The next example replicates the CSV decoder: +

+
+record = re.compile[[
+  record <- {| field (',' field)* |} (%nl / !.)
+  field <- escaped / nonescaped
+  nonescaped <- { [^,"%nl]* }
+  escaped <- '"' {~ ([^"] / '""' -> '"')* ~} '"'
+]]
+
+ +

Lua's long strings

+

+The next example matches Lua long strings: +

+
+c = re.compile([[
+  longstring <- ('[' {:eq: '='* :} '[' close)
+  close <- ']' =eq ']' / . close
+]])
+
+print(c:match'[==[]]===]]]]==]===[]')   --> 17
+
+ +

Abstract Syntax Trees

+

+This example shows a simple way to build an +abstract syntax tree (AST) for a given grammar. +To keep our example simple, +let us consider the following grammar +for lists of names: +

+
+p = re.compile[[
+      listname <- (name s)*
+      name <- [a-z][a-z]*
+      s <- %s*
+]]
+
+

+Now, we will add captures to build a corresponding AST. +As a first step, the pattern will build a table to +represent each non terminal; +terminals will be represented by their corresponding strings: +

+
+c = re.compile[[
+      listname <- {| (name s)* |}
+      name <- {| {[a-z][a-z]*} |}
+      s <- %s*
+]]
+
+

+Now, a match against "hi hello bye" +results in the table +{{"hi"}, {"hello"}, {"bye"}}. +

+

+For such a simple grammar, +this AST is more than enough; +actually, the tables around each single name +are already overkilling. +More complex grammars, +however, may need some more structure. +Specifically, +it would be useful if each table had +a tag field telling what non terminal +that table represents. +We can add such a tag using +named group captures: +

+
+x = re.compile[[
+      listname <- {| {:tag: '' -> 'list':} (name s)* |}
+      name <- {| {:tag: '' -> 'id':} {[a-z][a-z]*} |}
+      s <- ' '*
+]]
+
+

+With these group captures, +a match against "hi hello bye" +results in the following table: +

+
+{tag="list",
+  {tag="id", "hi"},
+  {tag="id", "hello"},
+  {tag="id", "bye"}
+}
+
+ + +

Indented blocks

+

+This example breaks indented blocks into tables, +respecting the indentation: +

+
+p = re.compile[[
+  block <- {| {:ident:' '*:} line
+           ((=ident !' ' line) / &(=ident ' ') block)* |}
+  line <- {[^%nl]*} %nl
+]]
+
+

+As an example, +consider the following text: +

+
+t = p:match[[
+first line
+  subline 1
+  subline 2
+second line
+third line
+  subline 3.1
+    subline 3.1.1
+  subline 3.2
+]]
+
+

+The resulting table t will be like this: +

+
+   {'first line'; {'subline 1'; 'subline 2'; ident = '  '};
+    'second line';
+    'third line'; { 'subline 3.1'; {'subline 3.1.1'; ident = '    '};
+                    'subline 3.2'; ident = '  '};
+    ident = ''}
+
+ +

Macro expander

+

+This example implements a simple macro expander. +Macros must be defined as part of the pattern, +following some simple rules: +

+
+p = re.compile[[
+      text <- {~ item* ~}
+      item <- macro / [^()] / '(' item* ')'
+      arg <- ' '* {~ (!',' item)* ~}
+      args <- '(' arg (',' arg)* ')'
+      -- now we define some macros
+      macro <- ('apply' args) -> '%1(%2)'
+             / ('add' args) -> '%1 + %2'
+             / ('mul' args) -> '%1 * %2'
+]]
+
+print(p:match"add(mul(a,b), apply(f,x))")   --> a * b + f(x)
+
+

+A text is a sequence of items, +wherein we apply a substitution capture to expand any macros. +An item is either a macro, +any character different from parentheses, +or a parenthesized expression. +A macro argument (arg) is a sequence +of items different from a comma. +(Note that a comma may appear inside an item, +e.g., inside a parenthesized expression.) +Again we do a substitution capture to expand any macro +in the argument before expanding the outer macro. +args is a list of arguments separated by commas. +Finally we define the macros. +Each macro is a string substitution; +it replaces the macro name and its arguments by its corresponding string, +with each %n replaced by the n-th argument. +

+ +

Patterns

+

+This example shows the complete syntax +of patterns accepted by re. +

+
+p = [=[
+
+pattern         <- exp !.
+exp             <- S (alternative / grammar)
+
+alternative     <- seq ('/' S seq)*
+seq             <- prefix*
+prefix          <- '&' S prefix / '!' S prefix / suffix
+suffix          <- primary S (([+*?]
+                            / '^' [+-]? num
+                            / '->' S (string / '{}' / name)
+                            / '=>' S name) S)*
+
+primary         <- '(' exp ')' / string / class / defined
+                 / '{:' (name ':')? exp ':}'
+                 / '=' name
+                 / '{}'
+                 / '{~' exp '~}'
+                 / '{' exp '}'
+                 / '.'
+                 / name S !arrow
+                 / '<' name '>'          -- old-style non terminals
+
+grammar         <- definition+
+definition      <- name S arrow exp
+
+class           <- '[' '^'? item (!']' item)* ']'
+item            <- defined / range / .
+range           <- . '-' [^]]
+
+S               <- (%s / '--' [^%nl]*)*   -- spaces and comments
+name            <- [A-Za-z][A-Za-z0-9_]*
+arrow           <- '<-'
+num             <- [0-9]+
+string          <- '"' [^"]* '"' / "'" [^']* "'"
+defined         <- '%' name
+
+]=]
+
+print(re.match(p, p))   -- a self description must match itself
+
+ + + +

License

+ +

+Copyright © 2008-2015 Lua.org, PUC-Rio. +

+

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

+ +

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

+ +

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

+ +
+ +
+ +
+

+$Id: re.html,v 1.23 2015/09/28 17:17:41 roberto Exp $ +

+
+ +
+ + + diff --git a/luaclib/lpeg/re.lua b/luaclib/lpeg/re.lua new file mode 100644 index 0000000..3b9974f --- /dev/null +++ b/luaclib/lpeg/re.lua @@ -0,0 +1,259 @@ +-- $Id: re.lua,v 1.44 2013/03/26 20:11:40 roberto Exp $ + +-- imported functions and modules +local tonumber, type, print, error = tonumber, type, print, error +local setmetatable = setmetatable +local m = require"lpeg" + +-- 'm' will be used to parse expressions, and 'mm' will be used to +-- create expressions; that is, 're' runs on 'm', creating patterns +-- on 'mm' +local mm = m + +-- pattern's metatable +local mt = getmetatable(mm.P(0)) + + + +-- No more global accesses after this point +local version = _VERSION +if version == "Lua 5.2" then _ENV = nil end + + +local any = m.P(1) + + +-- Pre-defined names +local Predef = { nl = m.P"\n" } + + +local mem +local fmem +local gmem + + +local function updatelocale () + mm.locale(Predef) + Predef.a = Predef.alpha + Predef.c = Predef.cntrl + Predef.d = Predef.digit + Predef.g = Predef.graph + Predef.l = Predef.lower + Predef.p = Predef.punct + Predef.s = Predef.space + Predef.u = Predef.upper + Predef.w = Predef.alnum + Predef.x = Predef.xdigit + Predef.A = any - Predef.a + Predef.C = any - Predef.c + Predef.D = any - Predef.d + Predef.G = any - Predef.g + Predef.L = any - Predef.l + Predef.P = any - Predef.p + Predef.S = any - Predef.s + Predef.U = any - Predef.u + Predef.W = any - Predef.w + Predef.X = any - Predef.x + mem = {} -- restart memoization + fmem = {} + gmem = {} + local mt = {__mode = "v"} + setmetatable(mem, mt) + setmetatable(fmem, mt) + setmetatable(gmem, mt) +end + + +updatelocale() + + + +local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end) + + +local function getdef (id, defs) + local c = defs and defs[id] + if not c then error("undefined name: " .. id) end + return c +end + + +local function patt_error (s, i) + local msg = (#s < i + 20) and s:sub(i) + or s:sub(i,i+20) .. "..." + msg = ("pattern error near '%s'"):format(msg) + error(msg, 2) +end + +local function mult (p, n) + local np = mm.P(true) + while n >= 1 do + if n%2 >= 1 then np = np * p end + p = p * p + n = n/2 + end + return np +end + +local function equalcap (s, i, c) + if type(c) ~= "string" then return nil end + local e = #c + i + if s:sub(i, e - 1) == c then return e else return nil end +end + + +local S = (Predef.space + "--" * (any - Predef.nl)^0)^0 + +local name = m.R("AZ", "az", "__") * m.R("AZ", "az", "__", "09")^0 + +local arrow = S * "<-" + +local seq_follow = m.P"/" + ")" + "}" + ":}" + "~}" + "|}" + (name * arrow) + -1 + +name = m.C(name) + + +-- a defined name only have meaning in a given environment +local Def = name * m.Carg(1) + +local num = m.C(m.R"09"^1) * S / tonumber + +local String = "'" * m.C((any - "'")^0) * "'" + + '"' * m.C((any - '"')^0) * '"' + + +local defined = "%" * Def / function (c,Defs) + local cat = Defs and Defs[c] or Predef[c] + if not cat then error ("name '" .. c .. "' undefined") end + return cat +end + +local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R + +local item = defined + Range + m.C(any) + +local Class = + "[" + * (m.C(m.P"^"^-1)) -- optional complement symbol + * m.Cf(item * (item - "]")^0, mt.__add) / + function (c, p) return c == "^" and any - p or p end + * "]" + +local function adddef (t, k, exp) + if t[k] then + error("'"..k.."' already defined as a rule") + else + t[k] = exp + end + return t +end + +local function firstdef (n, r) return adddef({n}, n, r) end + + +local function NT (n, b) + if not b then + error("rule '"..n.."' used outside a grammar") + else return mm.V(n) + end +end + + +local exp = m.P{ "Exp", + Exp = S * ( m.V"Grammar" + + m.Cf(m.V"Seq" * ("/" * S * m.V"Seq")^0, mt.__add) ); + Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^0 , mt.__mul) + * (#seq_follow + patt_error); + Prefix = "&" * S * m.V"Prefix" / mt.__len + + "!" * S * m.V"Prefix" / mt.__unm + + m.V"Suffix"; + Suffix = m.Cf(m.V"Primary" * S * + ( ( m.P"+" * m.Cc(1, mt.__pow) + + m.P"*" * m.Cc(0, mt.__pow) + + m.P"?" * m.Cc(-1, mt.__pow) + + "^" * ( m.Cg(num * m.Cc(mult)) + + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow)) + ) + + "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div)) + + m.P"{}" * m.Cc(nil, m.Ct) + + m.Cg(Def / getdef * m.Cc(mt.__div)) + ) + + "=>" * S * m.Cg(Def / getdef * m.Cc(m.Cmt)) + ) * S + )^0, function (a,b,f) return f(a,b) end ); + Primary = "(" * m.V"Exp" * ")" + + String / mm.P + + Class + + defined + + "{:" * (name * ":" + m.Cc(nil)) * m.V"Exp" * ":}" / + function (n, p) return mm.Cg(p, n) end + + "=" * name / function (n) return mm.Cmt(mm.Cb(n), equalcap) end + + m.P"{}" / mm.Cp + + "{~" * m.V"Exp" * "~}" / mm.Cs + + "{|" * m.V"Exp" * "|}" / mm.Ct + + "{" * m.V"Exp" * "}" / mm.C + + m.P"." * m.Cc(any) + + (name * -arrow + "<" * name * ">") * m.Cb("G") / NT; + Definition = name * arrow * m.V"Exp"; + Grammar = m.Cg(m.Cc(true), "G") * + m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0, + adddef) / mm.P +} + +local pattern = S * m.Cg(m.Cc(false), "G") * exp / mm.P * (-any + patt_error) + + +local function compile (p, defs) + if mm.type(p) == "pattern" then return p end -- already compiled + local cp = pattern:match(p, 1, defs) + if not cp then error("incorrect pattern", 3) end + return cp +end + +local function match (s, p, i) + local cp = mem[p] + if not cp then + cp = compile(p) + mem[p] = cp + end + return cp:match(s, i or 1) +end + +local function find (s, p, i) + local cp = fmem[p] + if not cp then + cp = compile(p) / 0 + cp = mm.P{ mm.Cp() * cp * mm.Cp() + 1 * mm.V(1) } + fmem[p] = cp + end + local i, e = cp:match(s, i or 1) + if i then return i, e - 1 + else return i + end +end + +local function gsub (s, p, rep) + local g = gmem[p] or {} -- ensure gmem[p] is not collected while here + gmem[p] = g + local cp = g[rep] + if not cp then + cp = compile(p) + cp = mm.Cs((cp / rep + 1)^0) + g[rep] = cp + end + return cp:match(s) +end + + +-- exported names +local re = { + compile = compile, + match = match, + find = find, + gsub = gsub, + updatelocale = updatelocale, +} + +if version == "Lua 5.1" then _G.re = re end + +return re diff --git a/luaclib/lpeg/test.lua b/luaclib/lpeg/test.lua new file mode 100644 index 0000000..017a3ab --- /dev/null +++ b/luaclib/lpeg/test.lua @@ -0,0 +1,1448 @@ +#!/usr/bin/env lua + +-- $Id: test.lua,v 1.109 2015/09/28 17:01:25 roberto Exp $ + +-- require"strict" -- just to be pedantic + +local m = require"lpeg" + + +-- for general use +local a, b, c, d, e, f, g, p, t + + +-- compatibility with Lua 5.2 +local unpack = rawget(table, "unpack") or unpack +local loadstring = rawget(_G, "loadstring") or load + + +local any = m.P(1) +local space = m.S" \t\n"^0 + +local function checkeq (x, y, p) +if p then print(x,y) end + if type(x) ~= "table" then assert(x == y) + else + for k,v in pairs(x) do checkeq(v, y[k], p) end + for k,v in pairs(y) do checkeq(v, x[k], p) end + end +end + + +local mt = getmetatable(m.P(1)) + + +local allchar = {} +for i=0,255 do allchar[i + 1] = i end +allchar = string.char(unpack(allchar)) +assert(#allchar == 256) + +local function cs2str (c) + return m.match(m.Cs((c + m.P(1)/"")^0), allchar) +end + +local function eqcharset (c1, c2) + assert(cs2str(c1) == cs2str(c2)) +end + + +print"General tests for LPeg library" + +assert(type(m.version()) == "string") +print("version " .. m.version()) +assert(m.type("alo") ~= "pattern") +assert(m.type(io.input) ~= "pattern") +assert(m.type(m.P"alo") == "pattern") + +-- tests for some basic optimizations +assert(m.match(m.P(false) + "a", "a") == 2) +assert(m.match(m.P(true) + "a", "a") == 1) +assert(m.match("a" + m.P(false), "b") == nil) +assert(m.match("a" + m.P(true), "b") == 1) + +assert(m.match(m.P(false) * "a", "a") == nil) +assert(m.match(m.P(true) * "a", "a") == 2) +assert(m.match("a" * m.P(false), "a") == nil) +assert(m.match("a" * m.P(true), "a") == 2) + +assert(m.match(#m.P(false) * "a", "a") == nil) +assert(m.match(#m.P(true) * "a", "a") == 2) +assert(m.match("a" * #m.P(false), "a") == nil) +assert(m.match("a" * #m.P(true), "a") == 2) + + +-- tests for locale +do + assert(m.locale(m) == m) + local t = {} + assert(m.locale(t, m) == t) + local x = m.locale() + for n,v in pairs(x) do + assert(type(n) == "string") + eqcharset(v, m[n]) + end +end + + +assert(m.match(3, "aaaa")) +assert(m.match(4, "aaaa")) +assert(not m.match(5, "aaaa")) +assert(m.match(-3, "aa")) +assert(not m.match(-3, "aaa")) +assert(not m.match(-3, "aaaa")) +assert(not m.match(-4, "aaaa")) +assert(m.P(-5):match"aaaa") + +assert(m.match("a", "alo") == 2) +assert(m.match("al", "alo") == 3) +assert(not m.match("alu", "alo")) +assert(m.match(true, "") == 1) + +local digit = m.S"0123456789" +local upper = m.S"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +local lower = m.S"abcdefghijklmnopqrstuvwxyz" +local letter = m.S"" + upper + lower +local alpha = letter + digit + m.R() + +eqcharset(m.S"", m.P(false)) +eqcharset(upper, m.R("AZ")) +eqcharset(lower, m.R("az")) +eqcharset(upper + lower, m.R("AZ", "az")) +eqcharset(upper + lower, m.R("AZ", "cz", "aa", "bb", "90")) +eqcharset(digit, m.S"01234567" + "8" + "9") +eqcharset(upper, letter - lower) +eqcharset(m.S(""), m.R()) +assert(cs2str(m.S("")) == "") + +eqcharset(m.S"\0", "\0") +eqcharset(m.S"\1\0\2", m.R"\0\2") +eqcharset(m.S"\1\0\2", m.R"\1\2" + "\0") +eqcharset(m.S"\1\0\2" - "\0", m.R"\1\2") + +local word = alpha^1 * (1 - alpha)^0 + +assert((word^0 * -1):match"alo alo") +assert(m.match(word^1 * -1, "alo alo")) +assert(m.match(word^2 * -1, "alo alo")) +assert(not m.match(word^3 * -1, "alo alo")) + +assert(not m.match(word^-1 * -1, "alo alo")) +assert(m.match(word^-2 * -1, "alo alo")) +assert(m.match(word^-3 * -1, "alo alo")) + +local eos = m.P(-1) + +assert(m.match(digit^0 * letter * digit * eos, "1298a1")) +assert(not m.match(digit^0 * letter * eos, "1257a1")) + +b = { + [1] = "(" * (((1 - m.S"()") + #m.P"(" * m.V(1))^0) * ")" +} + +assert(m.match(b, "(al())()")) +assert(not m.match(b * eos, "(al())()")) +assert(m.match(b * eos, "((al())()(é))")) +assert(not m.match(b, "(al()()")) + +assert(not m.match(letter^1 - "for", "foreach")) +assert(m.match(letter^1 - ("for" * eos), "foreach")) +assert(not m.match(letter^1 - ("for" * eos), "for")) + +function basiclookfor (p) + return m.P { + [1] = p + (1 * m.V(1)) + } +end + +function caplookfor (p) + return basiclookfor(p:C()) +end + +assert(m.match(caplookfor(letter^1), " 4achou123...") == "achou") +a = {m.match(caplookfor(letter^1)^0, " two words, one more ")} +checkeq(a, {"two", "words", "one", "more"}) + +assert(m.match( basiclookfor((#m.P(b) * 1) * m.Cp()), " ( (a)") == 7) + +a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "123")} +checkeq(a, {"123", "d"}) + +-- bug in LPeg 0.12 (nil value does not create a 'ktable') +assert(m.match(m.Cc(nil), "") == nil) + +a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "abcd")} +checkeq(a, {"abcd", "l"}) + +a = {m.match(m.Cc(10,20,30) * 'a' * m.Cp(), 'aaa')} +checkeq(a, {10,20,30,2}) +a = {m.match(m.Cp() * m.Cc(10,20,30) * 'a' * m.Cp(), 'aaa')} +checkeq(a, {1,10,20,30,2}) +a = m.match(m.Ct(m.Cp() * m.Cc(10,20,30) * 'a' * m.Cp()), 'aaa') +checkeq(a, {1,10,20,30,2}) +a = m.match(m.Ct(m.Cp() * m.Cc(7,8) * m.Cc(10,20,30) * 'a' * m.Cp()), 'aaa') +checkeq(a, {1,7,8,10,20,30,2}) +a = {m.match(m.Cc() * m.Cc() * m.Cc(1) * m.Cc(2,3,4) * m.Cc() * 'a', 'aaa')} +checkeq(a, {1,2,3,4}) + +a = {m.match(m.Cp() * letter^1 * m.Cp(), "abcd")} +checkeq(a, {1, 5}) + + +t = {m.match({[1] = m.C(m.C(1) * m.V(1) + -1)}, "abc")} +checkeq(t, {"abc", "a", "bc", "b", "c", "c", ""}) + +-- bug in 0.12 ('hascapture' did not check for captures inside a rule) +do + local pat = m.P{ + 'S'; + S1 = m.C('abc') + 3, + S = #m.V('S1') -- rule has capture, but '#' must ignore it + } + assert(pat:match'abc' == 1) +end + + +-- test for small capture boundary +for i = 250,260 do + assert(#m.match(m.C(i), string.rep('a', i)) == i) + assert(#m.match(m.C(m.C(i)), string.rep('a', i)) == i) +end + +-- tests for any*n and any*-n +for n = 1, 550, 13 do + local x_1 = string.rep('x', n - 1) + local x = x_1 .. 'a' + assert(not m.P(n):match(x_1)) + assert(m.P(n):match(x) == n + 1) + assert(n < 4 or m.match(m.P(n) + "xxx", x_1) == 4) + assert(m.C(n):match(x) == x) + assert(m.C(m.C(n)):match(x) == x) + assert(m.P(-n):match(x_1) == 1) + assert(not m.P(-n):match(x)) + assert(n < 13 or m.match(m.Cc(20) * ((n - 13) * m.P(10)) * 3, x) == 20) + local n3 = math.floor(n/3) + assert(m.match(n3 * m.Cp() * n3 * n3, x) == n3 + 1) +end + +-- true values +assert(m.P(0):match("x") == 1) +assert(m.P(0):match("") == 1) +assert(m.C(0):match("x") == "") + +assert(m.match(m.Cc(0) * m.P(10) + m.Cc(1) * "xuxu", "xuxu") == 1) +assert(m.match(m.Cc(0) * m.P(10) + m.Cc(1) * "xuxu", "xuxuxuxuxu") == 0) +assert(m.match(m.C(m.P(2)^1), "abcde") == "abcd") +p = m.Cc(0) * 1 + m.Cc(1) * 2 + m.Cc(2) * 3 + m.Cc(3) * 4 + + +-- test for alternation optimization +assert(m.match(m.P"a"^1 + "ab" + m.P"x"^0, "ab") == 2) +assert(m.match((m.P"a"^1 + "ab" + m.P"x"^0 * 1)^0, "ab") == 3) +assert(m.match(m.P"ab" + "cd" + "" + "cy" + "ak", "98") == 1) +assert(m.match(m.P"ab" + "cd" + "ax" + "cy", "ax") == 3) +assert(m.match("a" * m.P"b"^0 * "c" + "cd" + "ax" + "cy", "ax") == 3) +assert(m.match((m.P"ab" + "cd" + "ax" + "cy")^0, "ax") == 3) +assert(m.match(m.P(1) * "x" + m.S"" * "xu" + "ay", "ay") == 3) +assert(m.match(m.P"abc" + "cde" + "aka", "aka") == 4) +assert(m.match(m.S"abc" * "x" + "cde" + "aka", "ax") == 3) +assert(m.match(m.S"abc" * "x" + "cde" + "aka", "aka") == 4) +assert(m.match(m.S"abc" * "x" + "cde" + "aka", "cde") == 4) +assert(m.match(m.S"abc" * "x" + "ide" + m.S"ab" * "ka", "aka") == 4) +assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "cde" + "aka", "ax") == 3) +assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "cde" + "aka", "aka") == 4) +assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "cde" + "aka", "cde") == 4) +assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "ide" + m.S"ab" * "ka", "aka") == 4) +assert(m.match("ab" + m.S"abc" * m.P"y"^0 * "x" + "ide" + m.S"ab" * "ka", "ax") == 3) +assert(m.match(m.P(1) * "x" + "cde" + m.S"ab" * "ka", "aka") == 4) +assert(m.match(m.P(1) * "x" + "cde" + m.P(1) * "ka", "aka") == 4) +assert(m.match(m.P(1) * "x" + "cde" + m.P(1) * "ka", "cde") == 4) +assert(m.match(m.P"eb" + "cd" + m.P"e"^0 + "x", "ee") == 3) +assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x", "abcd") == 3) +assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x", "eeex") == 4) +assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x", "cd") == 3) +assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x", "x") == 1) +assert(m.match(m.P"ab" + "cd" + m.P"e"^0 + "x" + "", "zee") == 1) +assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x", "abcd") == 3) +assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x", "eeex") == 4) +assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x", "cd") == 3) +assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x", "x") == 2) +assert(m.match(m.P"ab" + "cd" + m.P"e"^1 + "x" + "", "zee") == 1) +assert(not m.match(("aa" * m.P"bc"^-1 + "aab") * "e", "aabe")) + +assert(m.match("alo" * (m.P"\n" + -1), "alo") == 4) + + +-- bug in 0.12 (rc1) +assert(m.match((m.P"\128\187\191" + m.S"abc")^0, "\128\187\191") == 4) + +assert(m.match(m.S"\0\128\255\127"^0, string.rep("\0\128\255\127", 10)) == + 4*10 + 1) + +-- optimizations with optional parts +assert(m.match(("ab" * -m.P"c")^-1, "abc") == 1) +assert(m.match(("ab" * #m.P"c")^-1, "abd") == 1) +assert(m.match(("ab" * m.B"c")^-1, "ab") == 1) +assert(m.match(("ab" * m.P"cd"^0)^-1, "abcdcdc") == 7) + +assert(m.match(m.P"ab"^-1 - "c", "abcd") == 3) + +p = ('Aa' * ('Bb' * ('Cc' * m.P'Dd'^0)^0)^0)^-1 +assert(p:match("AaBbCcDdBbCcDdDdDdBb") == 21) + + +-- bug in 0.12.2 +-- p = { ('ab' ('c' 'ef'?)*)? } +p = m.C(('ab' * ('c' * m.P'ef'^-1)^0)^-1) +s = "abcefccefc" +assert(s == p:match(s)) + + +pi = "3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510" +assert(m.match(m.Cs((m.P"1" / "a" + m.P"5" / "b" + m.P"9" / "c" + 1)^0), pi) == + m.match(m.Cs((m.P(1) / {["1"] = "a", ["5"] = "b", ["9"] = "c"})^0), pi)) +print"+" + + +-- tests for capture optimizations +assert(m.match((m.P(3) + 4 * m.Cp()) * "a", "abca") == 5) +t = {m.match(((m.P"a" + m.Cp()) * m.P"x")^0, "axxaxx")} +checkeq(t, {3, 6}) + + +-- tests for numbered captures +p = m.C(1) +assert(m.match(m.C(m.C(p * m.C(2)) * m.C(3)) / 3, "abcdefgh") == "a") +assert(m.match(m.C(m.C(p * m.C(2)) * m.C(3)) / 1, "abcdefgh") == "abcdef") +assert(m.match(m.C(m.C(p * m.C(2)) * m.C(3)) / 4, "abcdefgh") == "bc") +assert(m.match(m.C(m.C(p * m.C(2)) * m.C(3)) / 0, "abcdefgh") == 7) + +a, b, c = m.match(p * (m.C(p * m.C(2)) * m.C(3) / 4) * p, "abcdefgh") +assert(a == "a" and b == "efg" and c == "h") + +-- test for table captures +t = m.match(m.Ct(letter^1), "alo") +checkeq(t, {}) + +t, n = m.match(m.Ct(m.C(letter)^1) * m.Cc"t", "alo") +assert(n == "t" and table.concat(t) == "alo") + +t = m.match(m.Ct(m.C(m.C(letter)^1)), "alo") +assert(table.concat(t, ";") == "alo;a;l;o") + +t = m.match(m.Ct(m.C(m.C(letter)^1)), "alo") +assert(table.concat(t, ";") == "alo;a;l;o") + +t = m.match(m.Ct(m.Ct((m.Cp() * letter * m.Cp())^1)), "alo") +assert(table.concat(t[1], ";") == "1;2;2;3;3;4") + +t = m.match(m.Ct(m.C(m.C(1) * 1 * m.C(1))), "alo") +checkeq(t, {"alo", "a", "o"}) + + +-- tests for groups +p = m.Cg(1) -- no capture +assert(p:match('x') == 'x') +p = m.Cg(m.P(true)/function () end * 1) -- no value +assert(p:match('x') == 'x') +p = m.Cg(m.Cg(m.Cg(m.C(1)))) +assert(p:match('x') == 'x') +p = m.Cg(m.Cg(m.Cg(m.C(1))^0) * m.Cg(m.Cc(1) * m.Cc(2))) +t = {p:match'abc'} +checkeq(t, {'a', 'b', 'c', 1, 2}) + +p = m.Ct(m.Cg(m.Cc(10), "hi") * m.C(1)^0 * m.Cg(m.Cc(20), "ho")) +t = p:match'' +checkeq(t, {hi = 10, ho = 20}) +t = p:match'abc' +checkeq(t, {hi = 10, ho = 20, 'a', 'b', 'c'}) + +-- non-string group names +p = m.Ct(m.Cg(1, print) * m.Cg(1, 23.5) * m.Cg(1, io)) +t = p:match('abcdefghij') +assert(t[print] == 'a' and t[23.5] == 'b' and t[io] == 'c') + + +-- test for error messages +local function checkerr (msg, f, ...) + local st, err = pcall(f, ...) + assert(not st and m.match({ m.P(msg) + 1 * m.V(1) }, err)) +end + +checkerr("rule '1' may be left recursive", m.match, { m.V(1) * 'a' }, "a") +checkerr("rule '1' used outside a grammar", m.match, m.V(1), "") +checkerr("rule 'hiii' used outside a grammar", m.match, m.V('hiii'), "") +checkerr("rule 'hiii' undefined in given grammar", m.match, { m.V('hiii') }, "") +checkerr("undefined in given grammar", m.match, { m.V{} }, "") + +checkerr("rule 'A' is not a pattern", m.P, { m.P(1), A = {} }) +checkerr("grammar has no initial rule", m.P, { [print] = {} }) + +-- grammar with a long call chain before left recursion +p = {'a', + a = m.V'b' * m.V'c' * m.V'd' * m.V'a', + b = m.V'c', + c = m.V'd', + d = m.V'e', + e = m.V'f', + f = m.V'g', + g = m.P'' +} +checkerr("rule 'a' may be left recursive", m.match, p, "a") + +-- Bug in peephole optimization of LPeg 0.12 (IJmp -> ICommit) +-- the next grammar has an original sequence IJmp -> ICommit -> IJmp L1 +-- that is optimized to ICommit L1 + +p = m.P { (m.P {m.P'abc'} + 'ayz') * m.V'y'; y = m.P'x' } +assert(p:match('abcx') == 5 and p:match('ayzx') == 5 and not p:match'abc') + + +do + -- large dynamic Cc + local lim = 2^16 - 1 + local c = 0 + local function seq (n) + if n == 1 then c = c + 1; return m.Cc(c) + else + local m = math.floor(n / 2) + return seq(m) * seq(n - m) + end + end + p = m.Ct(seq(lim)) + t = p:match('') + assert(t[lim] == lim) + checkerr("too many", function () p = p / print end) + checkerr("too many", seq, lim + 1) +end + + +-- tests for non-pattern as arguments to pattern functions + +p = { ('a' * m.V(1))^-1 } * m.P'b' * { 'a' * m.V(2); m.V(1)^-1 } +assert(m.match(p, "aaabaac") == 7) + +p = m.P'abc' * 2 * -5 * true * 'de' -- mix of numbers and strings and booleans + +assert(p:match("abc01de") == 8) +assert(p:match("abc01de3456") == nil) + +p = 'abc' * (2 * (-5 * (true * m.P'de'))) + +assert(p:match("abc01de") == 8) +assert(p:match("abc01de3456") == nil) + +p = { m.V(2), m.P"abc" } * + (m.P{ "xx", xx = m.P"xx" } + { "x", x = m.P"a" * m.V"x" + "" }) +assert(p:match("abcaaaxx") == 7) +assert(p:match("abcxx") == 6) + + +-- a large table capture +t = m.match(m.Ct(m.C('a')^0), string.rep("a", 10000)) +assert(#t == 10000 and t[1] == 'a' and t[#t] == 'a') + +print('+') + + +-- bug in 0.10 (rechecking a grammar, after tail-call optimization) +m.P{ m.P { (m.P(3) + "xuxu")^0 * m.V"xuxu", xuxu = m.P(1) } } + +local V = m.V + +local Space = m.S(" \n\t")^0 +local Number = m.C(m.R("09")^1) * Space +local FactorOp = m.C(m.S("+-")) * Space +local TermOp = m.C(m.S("*/")) * Space +local Open = "(" * Space +local Close = ")" * Space + + +local function f_factor (v1, op, v2, d) + assert(d == nil) + if op == "+" then return v1 + v2 + else return v1 - v2 + end +end + + +local function f_term (v1, op, v2, d) + assert(d == nil) + if op == "*" then return v1 * v2 + else return v1 / v2 + end +end + +G = m.P{ "Exp", + Exp = m.Cf(V"Factor" * m.Cg(FactorOp * V"Factor")^0, f_factor); + Factor = m.Cf(V"Term" * m.Cg(TermOp * V"Term")^0, f_term); + Term = Number / tonumber + Open * V"Exp" * Close; +} + +G = Space * G * -1 + +for _, s in ipairs{" 3 + 5*9 / (1+1) ", "3+4/2", "3+3-3- 9*2+3*9/1- 8"} do + assert(m.match(G, s) == loadstring("return "..s)()) +end + + +-- test for grammars (errors deep in calling non-terminals) +g = m.P{ + [1] = m.V(2) + "a", + [2] = "a" * m.V(3) * "x", + [3] = "b" * m.V(3) + "c" +} + +assert(m.match(g, "abbbcx") == 7) +assert(m.match(g, "abbbbx") == 2) + + +-- tests for \0 +assert(m.match(m.R("\0\1")^1, "\0\1\0") == 4) +assert(m.match(m.S("\0\1ab")^1, "\0\1\0a") == 5) +assert(m.match(m.P(1)^3, "\0\1\0a") == 5) +assert(not m.match(-4, "\0\1\0a")) +assert(m.match("\0\1\0a", "\0\1\0a") == 5) +assert(m.match("\0\0\0", "\0\0\0") == 4) +assert(not m.match("\0\0\0", "\0\0")) + + +-- tests for predicates +assert(not m.match(-m.P("a") * 2, "alo")) +assert(m.match(- -m.P("a") * 2, "alo") == 3) +assert(m.match(#m.P("a") * 2, "alo") == 3) +assert(m.match(##m.P("a") * 2, "alo") == 3) +assert(not m.match(##m.P("c") * 2, "alo")) +assert(m.match(m.Cs((##m.P("a") * 1 + m.P(1)/".")^0), "aloal") == "a..a.") +assert(m.match(m.Cs((#((#m.P"a")/"") * 1 + m.P(1)/".")^0), "aloal") == "a..a.") +assert(m.match(m.Cs((- -m.P("a") * 1 + m.P(1)/".")^0), "aloal") == "a..a.") +assert(m.match(m.Cs((-((-m.P"a")/"") * 1 + m.P(1)/".")^0), "aloal") == "a..a.") + +p = -m.P'a' * m.Cc(1) + -m.P'b' * m.Cc(2) + -m.P'c' * m.Cc(3) +assert(p:match('a') == 2 and p:match('') == 1 and p:match('b') == 1) + +p = -m.P'a' * m.Cc(10) + #m.P'a' * m.Cc(20) +assert(p:match('a') == 20 and p:match('') == 10 and p:match('b') == 10) + + + +-- look-behind predicate +assert(not m.match(m.B'a', 'a')) +assert(m.match(1 * m.B'a', 'a') == 2) +assert(not m.match(m.B(1), 'a')) +assert(m.match(1 * m.B(1), 'a') == 2) +assert(m.match(-m.B(1), 'a') == 1) +assert(m.match(m.B(250), string.rep('a', 250)) == nil) +assert(m.match(250 * m.B(250), string.rep('a', 250)) == 251) + +-- look-behind with an open call +checkerr("pattern may not have fixed length", m.B, m.V'S1') +checkerr("too long to look behind", m.B, 260) + +B = #letter * -m.B(letter) + -letter * m.B(letter) +x = m.Ct({ (B * m.Cp())^-1 * (1 * m.V(1) + m.P(true)) }) +checkeq(m.match(x, 'ar cal c'), {1,3,4,7,9,10}) +checkeq(m.match(x, ' ar cal '), {2,4,5,8}) +checkeq(m.match(x, ' '), {}) +checkeq(m.match(x, 'aloalo'), {1,7}) + +assert(m.match(B, "a") == 1) +assert(m.match(1 * B, "a") == 2) +assert(not m.B(1 - letter):match("")) +assert((-m.B(letter)):match("") == 1) + +assert((4 * m.B(letter, 4)):match("aaaaaaaa") == 5) +assert(not (4 * m.B(#letter * 5)):match("aaaaaaaa")) +assert((4 * -m.B(#letter * 5)):match("aaaaaaaa") == 5) + +-- look-behind with grammars +assert(m.match('a' * m.B{'x', x = m.P(3)}, 'aaa') == nil) +assert(m.match('aa' * m.B{'x', x = m.P('aaa')}, 'aaaa') == nil) +assert(m.match('aaa' * m.B{'x', x = m.P('aaa')}, 'aaaaa') == 4) + + + +-- bug in 0.9 +assert(m.match(('a' * #m.P'b'), "ab") == 2) +assert(not m.match(('a' * #m.P'b'), "a")) + +assert(not m.match(#m.S'567', "")) +assert(m.match(#m.S'567' * 1, "6") == 2) + + +-- tests for Tail Calls + +p = m.P{ 'a' * m.V(1) + '' } +assert(p:match(string.rep('a', 1000)) == 1001) + +-- create a grammar for a simple DFA for even number of 0s and 1s +-- +-- ->1 <---0---> 2 +-- ^ ^ +-- | | +-- 1 1 +-- | | +-- V V +-- 3 <---0---> 4 +-- +-- this grammar should keep no backtracking information + +p = m.P{ + [1] = '0' * m.V(2) + '1' * m.V(3) + -1, + [2] = '0' * m.V(1) + '1' * m.V(4), + [3] = '0' * m.V(4) + '1' * m.V(1), + [4] = '0' * m.V(3) + '1' * m.V(2), +} + +assert(p:match(string.rep("00", 10000))) +assert(p:match(string.rep("01", 10000))) +assert(p:match(string.rep("011", 10000))) +assert(not p:match(string.rep("011", 10000) .. "1")) +assert(not p:match(string.rep("011", 10001))) + + +-- this grammar does need backtracking info. +local lim = 10000 +p = m.P{ '0' * m.V(1) + '0' } +checkerr("stack overflow", m.match, p, string.rep("0", lim)) +m.setmaxstack(2*lim) +checkerr("stack overflow", m.match, p, string.rep("0", lim)) +m.setmaxstack(2*lim + 4) +assert(m.match(p, string.rep("0", lim)) == lim + 1) + +-- this repetition should not need stack space (only the call does) +p = m.P{ ('a' * m.V(1))^0 * 'b' + 'c' } +m.setmaxstack(200) +assert(p:match(string.rep('a', 180) .. 'c' .. string.rep('b', 180)) == 362) + +m.setmaxstack(100) -- restore low limit + +-- tests for optional start position +assert(m.match("a", "abc", 1)) +assert(m.match("b", "abc", 2)) +assert(m.match("c", "abc", 3)) +assert(not m.match(1, "abc", 4)) +assert(m.match("a", "abc", -3)) +assert(m.match("b", "abc", -2)) +assert(m.match("c", "abc", -1)) +assert(m.match("abc", "abc", -4)) -- truncate to position 1 + +assert(m.match("", "abc", 10)) -- empty string is everywhere! +assert(m.match("", "", 10)) +assert(not m.match(1, "", 1)) +assert(not m.match(1, "", -1)) +assert(not m.match(1, "", 0)) + +print("+") + + +-- tests for argument captures +checkerr("invalid argument", m.Carg, 0) +checkerr("invalid argument", m.Carg, -1) +checkerr("invalid argument", m.Carg, 2^18) +checkerr("absent extra argument #1", m.match, m.Carg(1), 'a', 1) +assert(m.match(m.Carg(1), 'a', 1, print) == print) +x = {m.match(m.Carg(1) * m.Carg(2), '', 1, 10, 20)} +checkeq(x, {10, 20}) + +assert(m.match(m.Cmt(m.Cg(m.Carg(3), "a") * + m.Cmt(m.Cb("a"), function (s,i,x) + assert(s == "a" and i == 1); + return i, x+1 + end) * + m.Carg(2), function (s,i,a,b,c) + assert(s == "a" and i == 1 and c == nil); + return i, 2*a + 3*b + end) * "a", + "a", 1, false, 100, 1000) == 2*1001 + 3*100) + + +-- tests for Lua functions + +t = {} +s = "" +p = m.P(function (s1, i) assert(s == s1); t[#t + 1] = i; return nil end) * false +s = "hi, this is a test" +assert(m.match(((p - m.P(-1)) + 2)^0, s) == string.len(s) + 1) +assert(#t == string.len(s)/2 and t[1] == 1 and t[2] == 3) + +assert(not m.match(p, s)) + +p = mt.__add(function (s, i) return i end, function (s, i) return nil end) +assert(m.match(p, "alo")) + +p = mt.__mul(function (s, i) return i end, function (s, i) return nil end) +assert(not m.match(p, "alo")) + + +t = {} +p = function (s1, i) assert(s == s1); t[#t + 1] = i; return i end +s = "hi, this is a test" +assert(m.match((m.P(1) * p)^0, s) == string.len(s) + 1) +assert(#t == string.len(s) and t[1] == 2 and t[2] == 3) + +t = {} +p = m.P(function (s1, i) assert(s == s1); t[#t + 1] = i; + return i <= s1:len() and i end) * 1 +s = "hi, this is a test" +assert(m.match(p^0, s) == string.len(s) + 1) +assert(#t == string.len(s) + 1 and t[1] == 1 and t[2] == 2) + +p = function (s1, i) return m.match(m.P"a"^1, s1, i) end +assert(m.match(p, "aaaa") == 5) +assert(m.match(p, "abaa") == 2) +assert(not m.match(p, "baaa")) + +checkerr("invalid position", m.match, function () return 2^20 end, s) +checkerr("invalid position", m.match, function () return 0 end, s) +checkerr("invalid position", m.match, function (s, i) return i - 1 end, s) +checkerr("invalid position", m.match, + m.P(1)^0 * function (_, i) return i - 1 end, s) +assert(m.match(m.P(1)^0 * function (_, i) return i end * -1, s)) +checkerr("invalid position", m.match, + m.P(1)^0 * function (_, i) return i + 1 end, s) +assert(m.match(m.P(function (s, i) return s:len() + 1 end) * -1, s)) +checkerr("invalid position", m.match, m.P(function (s, i) return s:len() + 2 end) * -1, s) +assert(not m.match(m.P(function (s, i) return s:len() end) * -1, s)) +assert(m.match(m.P(1)^0 * function (_, i) return true end, s) == + string.len(s) + 1) +for i = 1, string.len(s) + 1 do + assert(m.match(function (_, _) return i end, s) == i) +end + +p = (m.P(function (s, i) return i%2 == 0 and i end) * 1 + + m.P(function (s, i) return i%2 ~= 0 and i + 2 <= s:len() and i end) * 3)^0 + * -1 +assert(p:match(string.rep('a', 14000))) + +-- tests for Function Replacements +f = function (a, ...) if a ~= "x" then return {a, ...} end end + +t = m.match(m.C(1)^0/f, "abc") +checkeq(t, {"a", "b", "c"}) + +t = m.match(m.C(1)^0/f/f, "abc") +checkeq(t, {{"a", "b", "c"}}) + +t = m.match(m.P(1)^0/f/f, "abc") -- no capture +checkeq(t, {{"abc"}}) + +t = m.match((m.P(1)^0/f * m.Cp())/f, "abc") +checkeq(t, {{"abc"}, 4}) + +t = m.match((m.C(1)^0/f * m.Cp())/f, "abc") +checkeq(t, {{"a", "b", "c"}, 4}) + +t = m.match((m.C(1)^0/f * m.Cp())/f, "xbc") +checkeq(t, {4}) + +t = m.match(m.C(m.C(1)^0)/f, "abc") +checkeq(t, {"abc", "a", "b", "c"}) + +g = function (...) return 1, ... end +t = {m.match(m.C(1)^0/g/g, "abc")} +checkeq(t, {1, 1, "a", "b", "c"}) + +t = {m.match(m.Cc(nil,nil,4) * m.Cc(nil,3) * m.Cc(nil, nil) / g / g, "")} +t1 = {1,1,nil,nil,4,nil,3,nil,nil} +for i=1,10 do assert(t[i] == t1[i]) end + +-- bug in 0.12.2: ktable with only nil could be eliminated when joining +-- with a pattern without ktable +assert((m.P"aaa" * m.Cc(nil)):match"aaa" == nil) + +t = {m.match((m.C(1) / function (x) return x, x.."x" end)^0, "abc")} +checkeq(t, {"a", "ax", "b", "bx", "c", "cx"}) + +t = m.match(m.Ct((m.C(1) / function (x,y) return y, x end * m.Cc(1))^0), "abc") +checkeq(t, {nil, "a", 1, nil, "b", 1, nil, "c", 1}) + +-- tests for Query Replacements + +assert(m.match(m.C(m.C(1)^0)/{abc = 10}, "abc") == 10) +assert(m.match(m.C(1)^0/{a = 10}, "abc") == 10) +assert(m.match(m.S("ba")^0/{ab = 40}, "abc") == 40) +t = m.match(m.Ct((m.S("ba")/{a = 40})^0), "abc") +checkeq(t, {40}) + +assert(m.match(m.Cs((m.C(1)/{a=".", d=".."})^0), "abcdde") == ".bc....e") +assert(m.match(m.Cs((m.C(1)/{f="."})^0), "abcdde") == "abcdde") +assert(m.match(m.Cs((m.C(1)/{d="."})^0), "abcdde") == "abc..e") +assert(m.match(m.Cs((m.C(1)/{e="."})^0), "abcdde") == "abcdd.") +assert(m.match(m.Cs((m.C(1)/{e=".", f="+"})^0), "eefef") == "..+.+") +assert(m.match(m.Cs((m.C(1))^0), "abcdde") == "abcdde") +assert(m.match(m.Cs(m.C(m.C(1)^0)), "abcdde") == "abcdde") +assert(m.match(1 * m.Cs(m.P(1)^0), "abcdde") == "bcdde") +assert(m.match(m.Cs((m.C('0')/'x' + 1)^0), "abcdde") == "abcdde") +assert(m.match(m.Cs((m.C('0')/'x' + 1)^0), "0ab0b0") == "xabxbx") +assert(m.match(m.Cs((m.C('0')/'x' + m.P(1)/{b=3})^0), "b0a0b") == "3xax3") +assert(m.match(m.P(1)/'%0%0'/{aa = -3} * 'x', 'ax') == -3) +assert(m.match(m.C(1)/'%0%1'/{aa = 'z'}/{z = -3} * 'x', 'ax') == -3) + +assert(m.match(m.Cs(m.Cc(0) * (m.P(1)/"")), "4321") == "0") + +assert(m.match(m.Cs((m.P(1) / "%0")^0), "abcd") == "abcd") +assert(m.match(m.Cs((m.P(1) / "%0.%0")^0), "abcd") == "a.ab.bc.cd.d") +assert(m.match(m.Cs((m.P("a") / "%0.%0" + 1)^0), "abcad") == "a.abca.ad") +assert(m.match(m.C("a") / "%1%%%0", "a") == "a%a") +assert(m.match(m.Cs((m.P(1) / ".xx")^0), "abcd") == ".xx.xx.xx.xx") +assert(m.match(m.Cp() * m.P(3) * m.Cp()/"%2%1%1 - %0 ", "abcde") == + "411 - abc ") + +assert(m.match(m.P(1)/"%0", "abc") == "a") +checkerr("invalid capture index", m.match, m.P(1)/"%1", "abc") +checkerr("invalid capture index", m.match, m.P(1)/"%9", "abc") + +p = m.C(1) +p = p * p; p = p * p; p = p * p * m.C(1) / "%9 - %1" +assert(p:match("1234567890") == "9 - 1") + +assert(m.match(m.Cc(print), "") == print) + +-- too many captures (just ignore extra ones) +p = m.C(1)^0 / "%2-%9-%0-%9" +assert(p:match"01234567890123456789" == "1-8-01234567890123456789-8") +s = string.rep("12345678901234567890", 20) +assert(m.match(m.C(1)^0 / "%9-%1-%0-%3", s) == "9-1-" .. s .. "-3") + +-- string captures with non-string subcaptures +p = m.Cc('alo') * m.C(1) / "%1 - %2 - %1" +assert(p:match'x' == 'alo - x - alo') + +checkerr("invalid capture value (a boolean)", m.match, m.Cc(true) / "%1", "a") + +-- long strings for string capture +l = 10000 +s = string.rep('a', l) .. string.rep('b', l) .. string.rep('c', l) + +p = (m.C(m.P'a'^1) * m.C(m.P'b'^1) * m.C(m.P'c'^1)) / '%3%2%1' + +assert(p:match(s) == string.rep('c', l) .. + string.rep('b', l) .. + string.rep('a', l)) + +print"+" + +-- accumulator capture +function f (x) return x + 1 end +assert(m.match(m.Cf(m.Cc(0) * m.C(1)^0, f), "alo alo") == 7) + +t = {m.match(m.Cf(m.Cc(1,2,3), error), "")} +checkeq(t, {1}) +p = m.Cf(m.Ct(true) * m.Cg(m.C(m.R"az"^1) * "=" * m.C(m.R"az"^1) * ";")^0, + rawset) +t = p:match("a=b;c=du;xux=yuy;") +checkeq(t, {a="b", c="du", xux="yuy"}) + + +-- errors in accumulator capture + +-- no initial capture +checkerr("no initial value", m.match, m.Cf(m.P(5), print), 'aaaaaa') +-- no initial capture (very long match forces fold to be a pair open-close) +checkerr("no initial value", m.match, m.Cf(m.P(500), print), + string.rep('a', 600)) + +-- nested capture produces no initial value +checkerr("no initial value", m.match, m.Cf(m.P(1) / {}, print), "alo") + + +-- tests for loop checker + +local function isnullable (p) + checkerr("may accept empty string", function (p) return p^0 end, m.P(p)) +end + +isnullable(m.P("x")^-4) +assert(m.match(((m.P(0) + 1) * m.S"al")^0, "alo") == 3) +assert(m.match((("x" + #m.P(1))^-4 * m.S"al")^0, "alo") == 3) +isnullable("") +isnullable(m.P("x")^0) +isnullable(m.P("x")^-1) +isnullable(m.P("x") + 1 + 2 + m.P("a")^-1) +isnullable(-m.P("ab")) +isnullable(- -m.P("ab")) +isnullable(# #(m.P("ab") + "xy")) +isnullable(- #m.P("ab")^0) +isnullable(# -m.P("ab")^1) +isnullable(#m.V(3)) +isnullable(m.V(3) + m.V(1) + m.P('a')^-1) +isnullable({[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(0)}) +assert(m.match(m.P{[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(1)}^0, "abc") + == 3) +assert(m.match(m.P""^-3, "a") == 1) + +local function find (p, s) + return m.match(basiclookfor(p), s) +end + + +local function badgrammar (g, expected) + local stat, msg = pcall(m.P, g) + assert(not stat) + if expected then assert(find(expected, msg)) end +end + +badgrammar({[1] = m.V(1)}, "rule '1'") +badgrammar({[1] = m.V(2)}, "rule '2'") -- invalid non-terminal +badgrammar({[1] = m.V"x"}, "rule 'x'") -- invalid non-terminal +badgrammar({[1] = m.V{}}, "rule '(a table)'") -- invalid non-terminal +badgrammar({[1] = #m.P("a") * m.V(1)}, "rule '1'") -- left-recursive +badgrammar({[1] = -m.P("a") * m.V(1)}, "rule '1'") -- left-recursive +badgrammar({[1] = -1 * m.V(1)}, "rule '1'") -- left-recursive +badgrammar({[1] = -1 + m.V(1)}, "rule '1'") -- left-recursive +badgrammar({[1] = 1 * m.V(2), [2] = m.V(2)}, "rule '2'") -- left-recursive +badgrammar({[1] = 1 * m.V(2)^0, [2] = m.P(0)}, "rule '1'") -- inf. loop +badgrammar({ m.V(2), m.V(3)^0, m.P"" }, "rule '2'") -- inf. loop +badgrammar({ m.V(2) * m.V(3)^0, m.V(3)^0, m.P"" }, "rule '1'") -- inf. loop +badgrammar({"x", x = #(m.V(1) * 'a') }, "rule '1'") -- inf. loop +badgrammar({ -(m.V(1) * 'a') }, "rule '1'") -- inf. loop +badgrammar({"x", x = m.P'a'^-1 * m.V"x"}, "rule 'x'") -- left recursive +badgrammar({"x", x = m.P'a' * m.V"y"^1, y = #m.P(1)}, "rule 'x'") + +assert(m.match({'a' * -m.V(1)}, "aaa") == 2) +assert(m.match({'a' * -m.V(1)}, "aaaa") == nil) + + +-- good x bad grammars +m.P{ ('a' * m.V(1))^-1 } +m.P{ -('a' * m.V(1)) } +m.P{ ('abc' * m.V(1))^-1 } +m.P{ -('abc' * m.V(1)) } +badgrammar{ #m.P('abc') * m.V(1) } +badgrammar{ -('a' + m.V(1)) } +m.P{ #('a' * m.V(1)) } +badgrammar{ #('a' + m.V(1)) } +m.P{ m.B{ m.P'abc' } * 'a' * m.V(1) } +badgrammar{ m.B{ m.P'abc' } * m.V(1) } +badgrammar{ ('a' + m.P'bcd')^-1 * m.V(1) } + + +-- simple tests for maximum sizes: +local p = m.P"a" +for i=1,14 do p = p * p end + +p = {} +for i=1,100 do p[i] = m.P"a" end +p = m.P(p) + + +-- strange values for rule labels + +p = m.P{ "print", + print = m.V(print), + [print] = m.V(_G), + [_G] = m.P"a", + } + +assert(p:match("a")) + +-- initial rule +g = {} +for i = 1, 10 do g["i"..i] = "a" * m.V("i"..i+1) end +g.i11 = m.P"" +for i = 1, 10 do + g[1] = "i"..i + local p = m.P(g) + assert(p:match("aaaaaaaaaaa") == 11 - i + 1) +end + +print"+" + + +-- tests for back references +checkerr("back reference 'x' not found", m.match, m.Cb('x'), '') +checkerr("back reference 'b' not found", m.match, m.Cg(1, 'a') * m.Cb('b'), 'a') + +p = m.Cg(m.C(1) * m.C(1), "k") * m.Ct(m.Cb("k")) +t = p:match("ab") +checkeq(t, {"a", "b"}) + +p = m.P(true) +for i = 1, 10 do p = p * m.Cg(1, i) end +for i = 1, 10 do + local p = p * m.Cb(i) + assert(p:match('abcdefghij') == string.sub('abcdefghij', i, i)) +end + + +t = {} +function foo (p) t[#t + 1] = p; return p .. "x" end + +p = m.Cg(m.C(2) / foo, "x") * m.Cb"x" * + m.Cg(m.Cb('x') / foo, "x") * m.Cb"x" * + m.Cg(m.Cb('x') / foo, "x") * m.Cb"x" * + m.Cg(m.Cb('x') / foo, "x") * m.Cb"x" +x = {p:match'ab'} +checkeq(x, {'abx', 'abxx', 'abxxx', 'abxxxx'}) +checkeq(t, {'ab', + 'ab', 'abx', + 'ab', 'abx', 'abxx', + 'ab', 'abx', 'abxx', 'abxxx'}) + + + +-- tests for match-time captures + +p = m.P'a' * (function (s, i) return (s:sub(i, i) == 'b') and i + 1 end) + + 'acd' + +assert(p:match('abc') == 3) +assert(p:match('acd') == 4) + +local function id (s, i, ...) + return true, ... +end + +assert(m.Cmt(m.Cs((m.Cmt(m.S'abc' / { a = 'x', c = 'y' }, id) + + m.R'09'^1 / string.char + + m.P(1))^0), id):match"acb98+68c" == "xyb\98+\68y") + +p = m.P{'S', + S = m.V'atom' * space + + m.Cmt(m.Ct("(" * space * (m.Cmt(m.V'S'^1, id) + m.P(true)) * ")" * space), id), + atom = m.Cmt(m.C(m.R("AZ", "az", "09")^1), id) +} +x = p:match"(a g () ((b) c) (d (e)))" +checkeq(x, {'a', 'g', {}, {{'b'}, 'c'}, {'d', {'e'}}}); + +x = {(m.Cmt(1, id)^0):match(string.rep('a', 500))} +assert(#x == 500) + +local function id(s, i, x) + if x == 'a' then return i, 1, 3, 7 + else return nil, 2, 4, 6, 8 + end +end + +p = ((m.P(id) * 1 + m.Cmt(2, id) * 1 + m.Cmt(1, id) * 1))^0 +assert(table.concat{p:match('abababab')} == string.rep('137', 4)) + +local function ref (s, i, x) + return m.match(x, s, i - x:len()) +end + +assert(m.Cmt(m.P(1)^0, ref):match('alo') == 4) +assert((m.P(1) * m.Cmt(m.P(1)^0, ref)):match('alo') == 4) +assert(not (m.P(1) * m.Cmt(m.C(1)^0, ref)):match('alo')) + +ref = function (s,i,x) return i == tonumber(x) and i, 'xuxu' end + +assert(m.Cmt(1, ref):match'2') +assert(not m.Cmt(1, ref):match'1') +assert(m.Cmt(m.P(1)^0, ref):match'03') + +function ref (s, i, a, b) + if a == b then return i, a:upper() end +end + +p = m.Cmt(m.C(m.R"az"^1) * "-" * m.C(m.R"az"^1), ref) +p = (any - p)^0 * p * any^0 * -1 + +assert(p:match'abbbc-bc ddaa' == 'BC') + +do -- match-time captures cannot be optimized away + local touch = 0 + f = m.P(function () touch = touch + 1; return true end) + + local function check(n) n = n or 1; assert(touch == n); touch = 0 end + + assert(m.match(f * false + 'b', 'a') == nil); check() + assert(m.match(f * false + 'b', '') == nil); check() + assert(m.match( (f * 'a')^0 * 'b', 'b') == 2); check() + assert(m.match( (f * 'a')^0 * 'b', '') == nil); check() + assert(m.match( (f * 'a')^-1 * 'b', 'b') == 2); check() + assert(m.match( (f * 'a')^-1 * 'b', '') == nil); check() + assert(m.match( ('b' + f * 'a')^-1 * 'b', '') == nil); check() + assert(m.match( (m.P'b'^-1 * f * 'a')^-1 * 'b', '') == nil); check() + assert(m.match( (-m.P(1) * m.P'b'^-1 * f * 'a')^-1 * 'b', '') == nil); + check() + assert(m.match( (f * 'a' + 'b')^-1 * 'b', '') == nil); check() + assert(m.match(f * 'a' + f * 'b', 'b') == 2); check(2) + assert(m.match(f * 'a' + f * 'b', 'a') == 2); check(1) + assert(m.match(-f * 'a' + 'b', 'b') == 2); check(1) + assert(m.match(-f * 'a' + 'b', '') == nil); check(1) +end + +c = '[' * m.Cg(m.P'='^0, "init") * '[' * + { m.Cmt(']' * m.C(m.P'='^0) * ']' * m.Cb("init"), function (_, _, s1, s2) + return s1 == s2 end) + + 1 * m.V(1) } / 0 + +assert(c:match'[==[]]====]]]]==]===[]' == 18) +assert(c:match'[[]=]====]=]]]==]===[]' == 14) +assert(not c:match'[[]=]====]=]=]==]===[]') + + +-- old bug: optimization of concat with fail removed match-time capture +p = m.Cmt(0, function (s) p = s end) * m.P(false) +assert(not p:match('alo')) +assert(p == 'alo') + + +-- ensure that failed match-time captures are not kept on Lua stack +do + local t = {__mode = "kv"}; setmetatable(t,t) + local c = 0 + + local function foo (s,i) + collectgarbage(); + assert(next(t) == "__mode" and next(t, "__mode") == nil) + local x = {} + t[x] = true + c = c + 1 + return i, x + end + + local p = m.P{ m.Cmt(0, foo) * m.P(false) + m.P(1) * m.V(1) + m.P"" } + p:match(string.rep('1', 10)) + assert(c == 11) +end + +p = (m.P(function () return true, "a" end) * 'a' + + m.P(function (s, i) return i, "aa", 20 end) * 'b' + + m.P(function (s,i) if i <= #s then return i, "aaa" end end) * 1)^0 + +t = {p:match('abacc')} +checkeq(t, {'a', 'aa', 20, 'a', 'aaa', 'aaa'}) + + +------------------------------------------------------------------- +-- Tests for 're' module +------------------------------------------------------------------- + +local re = require "re" + +local match, compile = re.match, re.compile + + + +assert(match("a", ".") == 2) +assert(match("a", "''") == 1) +assert(match("", " ! . ") == 1) +assert(not match("a", " ! . ")) +assert(match("abcde", " ( . . ) * ") == 5) +assert(match("abbcde", " [a-c] +") == 5) +assert(match("0abbc1de", "'0' [a-c]+ '1'") == 7) +assert(match("0zz1dda", "'0' [^a-c]+ 'a'") == 8) +assert(match("abbc--", " [a-c] + +") == 5) +assert(match("abbc--", " [ac-] +") == 2) +assert(match("abbc--", " [-acb] + ") == 7) +assert(not match("abbcde", " [b-z] + ")) +assert(match("abb\"de", '"abb"["]"de"') == 7) +assert(match("abceeef", "'ac' ? 'ab' * 'c' { 'e' * } / 'abceeef' ") == "eee") +assert(match("abceeef", "'ac'? 'ab'* 'c' { 'f'+ } / 'abceeef' ") == 8) +local t = {match("abceefe", "( ( & 'e' {} ) ? . ) * ")} +checkeq(t, {4, 5, 7}) +local t = {match("abceefe", "((&&'e' {})? .)*")} +checkeq(t, {4, 5, 7}) +local t = {match("abceefe", "( ( ! ! 'e' {} ) ? . ) *")} +checkeq(t, {4, 5, 7}) +local t = {match("abceefe", "(( & ! & ! 'e' {})? .)*")} +checkeq(t, {4, 5, 7}) + +assert(match("cccx" , "'ab'? ('ccc' / ('cde' / 'cd'*)? / 'ccc') 'x'+") == 5) +assert(match("cdx" , "'ab'? ('ccc' / ('cde' / 'cd'*)? / 'ccc') 'x'+") == 4) +assert(match("abcdcdx" , "'ab'? ('ccc' / ('cde' / 'cd'*)? / 'ccc') 'x'+") == 8) + +assert(match("abc", "a <- (. a)?") == 4) +b = "balanced <- '(' ([^()] / balanced)* ')'" +assert(match("(abc)", b)) +assert(match("(a(b)((c) (d)))", b)) +assert(not match("(a(b ((c) (d)))", b)) + +b = compile[[ balanced <- "(" ([^()] / balanced)* ")" ]] +assert(b == m.P(b)) +assert(b:match"((((a))(b)))") + +local g = [[ + S <- "0" B / "1" A / "" -- balanced strings + A <- "0" S / "1" A A -- one more 0 + B <- "1" S / "0" B B -- one more 1 +]] +assert(match("00011011", g) == 9) + +local g = [[ + S <- ("0" B / "1" A)* + A <- "0" / "1" A A + B <- "1" / "0" B B +]] +assert(match("00011011", g) == 9) +assert(match("000110110", g) == 9) +assert(match("011110110", g) == 3) +assert(match("000110010", g) == 1) + +s = "aaaaaaaaaaaaaaaaaaaaaaaa" +assert(match(s, "'a'^3") == 4) +assert(match(s, "'a'^0") == 1) +assert(match(s, "'a'^+3") == s:len() + 1) +assert(not match(s, "'a'^+30")) +assert(match(s, "'a'^-30") == s:len() + 1) +assert(match(s, "'a'^-5") == 6) +for i = 1, s:len() do + assert(match(s, string.format("'a'^+%d", i)) >= i + 1) + assert(match(s, string.format("'a'^-%d", i)) <= i + 1) + assert(match(s, string.format("'a'^%d", i)) == i + 1) +end +assert(match("01234567890123456789", "[0-9]^3+") == 19) + + +assert(match("01234567890123456789", "({....}{...}) -> '%2%1'") == "4560123") +t = match("0123456789", "{| {.}* |}") +checkeq(t, {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}) +assert(match("012345", "{| (..) -> '%0%0' |}")[1] == "0101") + +assert(match("abcdef", "( {.} {.} {.} {.} {.} ) -> 3") == "c") +assert(match("abcdef", "( {:x: . :} {.} {.} {.} {.} ) -> 3") == "d") +assert(match("abcdef", "( {:x: . :} {.} {.} {.} {.} ) -> 0") == 6) + +assert(not match("abcdef", "{:x: ({.} {.} {.}) -> 2 :} =x")) +assert(match("abcbef", "{:x: ({.} {.} {.}) -> 2 :} =x")) + +eqcharset(compile"[]]", "]") +eqcharset(compile"[][]", m.S"[]") +eqcharset(compile"[]-]", m.S"-]") +eqcharset(compile"[-]", m.S"-") +eqcharset(compile"[az-]", m.S"a-z") +eqcharset(compile"[-az]", m.S"a-z") +eqcharset(compile"[a-z]", m.R"az") +eqcharset(compile"[]['\"]", m.S[[]['"]]) + +eqcharset(compile"[^]]", any - "]") +eqcharset(compile"[^][]", any - m.S"[]") +eqcharset(compile"[^]-]", any - m.S"-]") +eqcharset(compile"[^]-]", any - m.S"-]") +eqcharset(compile"[^-]", any - m.S"-") +eqcharset(compile"[^az-]", any - m.S"a-z") +eqcharset(compile"[^-az]", any - m.S"a-z") +eqcharset(compile"[^a-z]", any - m.R"az") +eqcharset(compile"[^]['\"]", any - m.S[[]['"]]) + +-- tests for comments in 're' +e = compile[[ +A <- _B -- \t \n %nl .<> <- -> -- +_B <- 'x' --]] +assert(e:match'xy' == 2) + +-- tests for 're' with pre-definitions +defs = {digits = m.R"09", letters = m.R"az", _=m.P"__"} +e = compile("%letters (%letters / %digits)*", defs) +assert(e:match"x123" == 5) +e = compile("%_", defs) +assert(e:match"__" == 3) + +e = compile([[ + S <- A+ + A <- %letters+ B + B <- %digits+ +]], defs) + +e = compile("{[0-9]+'.'?[0-9]*} -> sin", math) +assert(e:match("2.34") == math.sin(2.34)) + + +function eq (_, _, a, b) return a == b end + +c = re.compile([[ + longstring <- '[' {:init: '='* :} '[' close + close <- ']' =init ']' / . close +]]) + +assert(c:match'[==[]]===]]]]==]===[]' == 17) +assert(c:match'[[]=]====]=]]]==]===[]' == 14) +assert(not c:match'[[]=]====]=]=]==]===[]') + +c = re.compile" '[' {:init: '='* :} '[' (!(']' =init ']') .)* ']' =init ']' !. " + +assert(c:match'[==[]]===]]]]==]') +assert(c:match'[[]=]====]=][]==]===[]]') +assert(not c:match'[[]=]====]=]=]==]===[]') + +assert(re.find("hi alalo", "{:x:..:} =x") == 4) +assert(re.find("hi alalo", "{:x:..:} =x", 4) == 4) +assert(not re.find("hi alalo", "{:x:..:} =x", 5)) +assert(re.find("hi alalo", "{'al'}", 5) == 6) +assert(re.find("hi aloalolo", "{:x:..:} =x") == 8) +assert(re.find("alo alohi x x", "{:word:%w+:}%W*(=word)!%w") == 11) + +-- re.find discards any captures +local a,b,c = re.find("alo", "{.}{'o'}") +assert(a == 2 and b == 3 and c == nil) + +local function match (s,p) + local i,e = re.find(s,p) + if i then return s:sub(i, e) end +end +assert(match("alo alo", '[a-z]+') == "alo") +assert(match("alo alo", '{:x: [a-z]+ :} =x') == nil) +assert(match("alo alo", "{:x: [a-z]+ :} ' ' =x") == "alo alo") + +assert(re.gsub("alo alo", "[abc]", "x") == "xlo xlo") +assert(re.gsub("alo alo", "%w+", ".") == ". .") +assert(re.gsub("hi, how are you", "[aeiou]", string.upper) == + "hI, hOw ArE yOU") + +s = 'hi [[a comment[=]=] ending here]] and [=[another]]=]]' +c = re.compile" '[' {:i: '='* :} '[' (!(']' =i ']') .)* ']' { =i } ']' " +assert(re.gsub(s, c, "%2") == 'hi and =]') +assert(re.gsub(s, c, "%0") == s) +assert(re.gsub('[=[hi]=]', c, "%2") == '=') + +assert(re.find("", "!.") == 1) +assert(re.find("alo", "!.") == 4) + +function addtag (s, i, t, tag) t.tag = tag; return i, t end + +c = re.compile([[ + doc <- block !. + block <- (start {| (block / { [^<]+ })* |} end?) => addtag + start <- '<' {:tag: [a-z]+ :} '>' + end <- '' +]], {addtag = addtag}) + +x = c:match[[ +hihellobuttotheend]] +checkeq(x, {tag='x', 'hi', {tag = 'b', 'hello'}, 'but', + {'totheend'}}) + + +-- tests for look-ahead captures +x = {re.match("alo", "&(&{.}) !{'b'} {&(...)} &{..} {...} {!.}")} +checkeq(x, {"", "alo", ""}) + +assert(re.match("aloalo", + "{~ (((&'al' {.}) -> 'A%1' / (&%l {.}) -> '%1%1') / .)* ~}") + == "AallooAalloo") + +-- bug in 0.9 (and older versions), due to captures in look-aheads +x = re.compile[[ {~ (&(. ([a-z]* -> '*')) ([a-z]+ -> '+') ' '*)* ~} ]] +assert(x:match"alo alo" == "+ +") + +-- valid capture in look-ahead (used inside the look-ahead itself) +x = re.compile[[ + S <- &({:two: .. :} . =two) {[a-z]+} / . S +]] +assert(x:match("hello aloaLo aloalo xuxu") == "aloalo") + + +p = re.compile[[ + block <- {| {:ident:space*:} line + ((=ident !space line) / &(=ident space) block)* |} + line <- {[^%nl]*} %nl + space <- '_' -- should be ' ', but '_' is simpler for editors +]] + +t= p:match[[ +1 +__1.1 +__1.2 +____1.2.1 +____ +2 +__2.1 +]] +checkeq(t, {"1", {"1.1", "1.2", {"1.2.1", "", ident = "____"}, ident = "__"}, + "2", {"2.1", ident = "__"}, ident = ""}) + + +-- nested grammars +p = re.compile[[ + s <- a b !. + b <- ( x <- ('b' x)? ) + a <- ( x <- 'a' x? ) +]] + +assert(p:match'aaabbb') +assert(p:match'aaa') +assert(not p:match'bbb') +assert(not p:match'aaabbba') + +-- testing groups +t = {re.match("abc", "{:S <- {:.:} {S} / '':}")} +checkeq(t, {"a", "bc", "b", "c", "c", ""}) + +t = re.match("1234", "{| {:a:.:} {:b:.:} {:c:.{.}:} |}") +checkeq(t, {a="1", b="2", c="4"}) +t = re.match("1234", "{|{:a:.:} {:b:{.}{.}:} {:c:{.}:}|}") +checkeq(t, {a="1", b="2", c="4"}) +t = re.match("12345", "{| {:.:} {:b:{.}{.}:} {:{.}{.}:} |}") +checkeq(t, {"1", b="2", "4", "5"}) +t = re.match("12345", "{| {:.:} {:{:b:{.}{.}:}:} {:{.}{.}:} |}") +checkeq(t, {"1", "23", "4", "5"}) +t = re.match("12345", "{| {:.:} {{:b:{.}{.}:}} {:{.}{.}:} |}") +checkeq(t, {"1", "23", "4", "5"}) + + +-- testing pre-defined names +assert(os.setlocale("C") == "C") + +function eqlpeggsub (p1, p2) + local s1 = cs2str(re.compile(p1)) + local s2 = string.gsub(allchar, "[^" .. p2 .. "]", "") + -- if s1 ~= s2 then print(#s1,#s2) end + assert(s1 == s2) +end + + +eqlpeggsub("%w", "%w") +eqlpeggsub("%a", "%a") +eqlpeggsub("%l", "%l") +eqlpeggsub("%u", "%u") +eqlpeggsub("%p", "%p") +eqlpeggsub("%d", "%d") +eqlpeggsub("%x", "%x") +eqlpeggsub("%s", "%s") +eqlpeggsub("%c", "%c") + +eqlpeggsub("%W", "%W") +eqlpeggsub("%A", "%A") +eqlpeggsub("%L", "%L") +eqlpeggsub("%U", "%U") +eqlpeggsub("%P", "%P") +eqlpeggsub("%D", "%D") +eqlpeggsub("%X", "%X") +eqlpeggsub("%S", "%S") +eqlpeggsub("%C", "%C") + +eqlpeggsub("[%w]", "%w") +eqlpeggsub("[_%w]", "_%w") +eqlpeggsub("[^%w]", "%W") +eqlpeggsub("[%W%S]", "%W%S") + +re.updatelocale() + + +-- testing nested substitutions x string captures + +p = re.compile[[ + text <- {~ item* ~} + item <- macro / [^()] / '(' item* ')' + arg <- ' '* {~ (!',' item)* ~} + args <- '(' arg (',' arg)* ')' + macro <- ('apply' args) -> '%1(%2)' + / ('add' args) -> '%1 + %2' + / ('mul' args) -> '%1 * %2' +]] + +assert(p:match"add(mul(a,b), apply(f,x))" == "a * b + f(x)") + +rev = re.compile[[ R <- (!.) -> '' / ({.} R) -> '%2%1']] + +assert(rev:match"0123456789" == "9876543210") + + +-- testing error messages in re + +local function errmsg (p, err) + checkerr(err, re.compile, p) +end + +errmsg('aaaa', "rule 'aaaa'") +errmsg('a', 'outside') +errmsg('b <- a', 'undefined') +errmsg("x <- 'a' x <- 'b'", 'already defined') +errmsg("'a' -", "near '-'") + + +print"OK" + + diff --git a/luaclib/luaclib.sln b/luaclib/luaclib.sln new file mode 100644 index 0000000..b7c7360 --- /dev/null +++ b/luaclib/luaclib.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cjson", "cjson\cjson.vcxproj", "{933BAD43-4B46-4BC1-A943-7825C5946B23}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lfs", "lfs\lfs.vcxproj", "{BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lpeg", "lpeg\lpeg.vcxproj", "{3350DD32-C039-442E-94D5-DAB4E4A0A4C8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "mime\mime.vcxproj", "{2691C520-B01B-46AB-B585-716767F72A9F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pbc", "pb\pbc.vcxproj", "{EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {933BAD43-4B46-4BC1-A943-7825C5946B23}.Debug|Win32.ActiveCfg = Debug|Win32 + {933BAD43-4B46-4BC1-A943-7825C5946B23}.Debug|Win32.Build.0 = Debug|Win32 + {933BAD43-4B46-4BC1-A943-7825C5946B23}.Release|Win32.ActiveCfg = Release|Win32 + {933BAD43-4B46-4BC1-A943-7825C5946B23}.Release|Win32.Build.0 = Release|Win32 + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Debug|Win32.ActiveCfg = Debug|Win32 + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Debug|Win32.Build.0 = Debug|Win32 + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Release|Win32.ActiveCfg = Release|Win32 + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Release|Win32.Build.0 = Release|Win32 + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Debug|Win32.ActiveCfg = Debug|Win32 + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Debug|Win32.Build.0 = Debug|Win32 + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Release|Win32.ActiveCfg = Release|Win32 + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Release|Win32.Build.0 = Release|Win32 + {2691C520-B01B-46AB-B585-716767F72A9F}.Debug|Win32.ActiveCfg = Debug|Win32 + {2691C520-B01B-46AB-B585-716767F72A9F}.Debug|Win32.Build.0 = Debug|Win32 + {2691C520-B01B-46AB-B585-716767F72A9F}.Release|Win32.ActiveCfg = Release|Win32 + {2691C520-B01B-46AB-B585-716767F72A9F}.Release|Win32.Build.0 = Release|Win32 + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Debug|Win32.Build.0 = Debug|Win32 + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Release|Win32.ActiveCfg = Release|Win32 + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/luaclib/luaclib.v12.suo b/luaclib/luaclib.v12.suo new file mode 100644 index 0000000000000000000000000000000000000000..170cbe1ef1f7cf0ffb69ed76085a351f78faf565 GIT binary patch literal 71168 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 literal 0 HcmV?d00001 diff --git a/luaclib/mime.dll b/luaclib/mime.dll new file mode 100644 index 0000000000000000000000000000000000000000..a9050677565811d9e8f31e53dbea76e420386700 GIT binary patch literal 43520 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 + +#include "lua.h" +#include "lauxlib.h" + +#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) +#include "compat-5.1.h" +#endif + +#include "mime.h" + +/*=========================================================================*\ +* Don't want to trust escape character constants +\*=========================================================================*/ +typedef unsigned char UC; +static const char CRLF[] = "\r\n"; +static const char EQCRLF[] = "=\r\n"; + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int mime_global_wrp(lua_State *L); +static int mime_global_b64(lua_State *L); +static int mime_global_unb64(lua_State *L); +static int mime_global_qp(lua_State *L); +static int mime_global_unqp(lua_State *L); +static int mime_global_qpwrp(lua_State *L); +static int mime_global_eol(lua_State *L); +static int mime_global_dot(lua_State *L); + +static size_t dot(int c, size_t state, luaL_Buffer *buffer); +static void b64setup(UC *b64unbase); +static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); +static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); + +static void qpsetup(UC *qpclass, UC *qpunbase); +static void qpquote(UC c, luaL_Buffer *buffer); +static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t qpencode(UC c, UC *input, size_t size, + const char *marker, luaL_Buffer *buffer); +static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); + +/* code support functions */ +static luaL_Reg func[] = { + { "dot", mime_global_dot }, + { "b64", mime_global_b64 }, + { "eol", mime_global_eol }, + { "qp", mime_global_qp }, + { "qpwrp", mime_global_qpwrp }, + { "unb64", mime_global_unb64 }, + { "unqp", mime_global_unqp }, + { "wrp", mime_global_wrp }, + { NULL, NULL } +}; + +/*-------------------------------------------------------------------------*\ +* Quoted-printable globals +\*-------------------------------------------------------------------------*/ +static UC qpclass[256]; +static UC qpbase[] = "0123456789ABCDEF"; +static UC qpunbase[256]; +enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; + +/*-------------------------------------------------------------------------*\ +* Base64 globals +\*-------------------------------------------------------------------------*/ +static const UC b64base[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static UC b64unbase[256]; + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +LUAMOD_API int luaopen_mime_core(lua_State *L) +{ + luaL_openlib(L, "mime", func, 0); + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, MIME_VERSION); + lua_rawset(L, -3); + /* initialize lookup tables */ + qpsetup(qpclass, qpunbase); + b64setup(b64unbase); + return 1; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Incrementaly breaks a string into lines. The string can have CRLF breaks. +* A, n = wrp(l, B, length) +* A is a copy of B, broken into lines of at most 'length' bytes. +* 'l' is how many bytes are left for the first line of B. +* 'n' is the number of bytes left in the last line of A. +\*-------------------------------------------------------------------------*/ +static int mime_global_wrp(lua_State *L) +{ + size_t size = 0; + int left = (int) luaL_checknumber(L, 1); + const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); + const UC *last = input + size; + int length = (int) luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end of input black-hole */ + if (!input) { + /* if last line has not been terminated, add a line break */ + if (left < length) lua_pushstring(L, CRLF); + /* otherwise, we are done */ + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + luaL_buffinit(L, &buffer); + while (input < last) { + switch (*input) { + case '\r': + break; + case '\n': + luaL_addstring(&buffer, CRLF); + left = length; + break; + default: + if (left <= 0) { + left = length; + luaL_addstring(&buffer, CRLF); + } + luaL_putchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Fill base64 decode map. +\*-------------------------------------------------------------------------*/ +static void b64setup(UC *b64unbase) +{ + int i; + for (i = 0; i <= 255; i++) b64unbase[i] = (UC) 255; + for (i = 0; i < 64; i++) b64unbase[b64base[i]] = (UC) i; + b64unbase['='] = 0; +} + +/*-------------------------------------------------------------------------*\ +* Acumulates bytes in input buffer until 3 bytes are available. +* Translate the 3 bytes into Base64 form and append to buffer. +* Returns new number of bytes in buffer. +\*-------------------------------------------------------------------------*/ +static size_t b64encode(UC c, UC *input, size_t size, + luaL_Buffer *buffer) +{ + input[size++] = c; + if (size == 3) { + UC code[4]; + unsigned long value = 0; + value += input[0]; value <<= 8; + value += input[1]; value <<= 8; + value += input[2]; + code[3] = b64base[value & 0x3f]; value >>= 6; + code[2] = b64base[value & 0x3f]; value >>= 6; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + size = 0; + } + return size; +} + +/*-------------------------------------------------------------------------*\ +* Encodes the Base64 last 1 or 2 bytes and adds padding '=' +* Result, if any, is appended to buffer. +* Returns 0. +\*-------------------------------------------------------------------------*/ +static size_t b64pad(const UC *input, size_t size, + luaL_Buffer *buffer) +{ + unsigned long value = 0; + UC code[4] = {'=', '=', '=', '='}; + switch (size) { + case 1: + value = input[0] << 4; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + break; + case 2: + value = input[0]; value <<= 8; + value |= input[1]; value <<= 2; + code[2] = b64base[value & 0x3f]; value >>= 6; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + break; + default: + break; + } + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Acumulates bytes in input buffer until 4 bytes are available. +* Translate the 4 bytes from Base64 form and append to buffer. +* Returns new number of bytes in buffer. +\*-------------------------------------------------------------------------*/ +static size_t b64decode(UC c, UC *input, size_t size, + luaL_Buffer *buffer) +{ + /* ignore invalid characters */ + if (b64unbase[c] > 64) return size; + input[size++] = c; + /* decode atom */ + if (size == 4) { + UC decoded[3]; + int valid, value = 0; + value = b64unbase[input[0]]; value <<= 6; + value |= b64unbase[input[1]]; value <<= 6; + value |= b64unbase[input[2]]; value <<= 6; + value |= b64unbase[input[3]]; + decoded[2] = (UC) (value & 0xff); value >>= 8; + decoded[1] = (UC) (value & 0xff); value >>= 8; + decoded[0] = (UC) value; + /* take care of paddding */ + valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; + luaL_addlstring(buffer, (char *) decoded, valid); + return 0; + /* need more data */ + } else return size; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally applies the Base64 transfer content encoding to a string +* A, B = b64(C, D) +* A is the encoded version of the largest prefix of C .. D that is +* divisible by 3. B has the remaining bytes of C .. D, *without* encoding. +* The easiest thing would be to concatenate the two strings and +* encode the result, but we can't afford that or Lua would dupplicate +* every chunk we received. +\*-------------------------------------------------------------------------*/ +static int mime_global_b64(lua_State *L) +{ + UC atom[3]; + size_t isize = 0, asize = 0; + const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + input = (UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + asize = b64pad(atom, asize, &buffer); + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process the second part */ + last = input + isize; + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally removes the Base64 transfer content encoding from a string +* A, B = b64(C, D) +* A is the encoded version of the largest prefix of C .. D that is +* divisible by 4. B has the remaining bytes of C .. D, *without* encoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_unb64(lua_State *L) +{ + UC atom[4]; + size_t isize = 0, asize = 0; + const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + input = (UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second is nil, we are done */ + if (!input) { + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise, process the rest of the input */ + last = input + isize; + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Quoted-printable encoding scheme +* all (except CRLF in text) can be =XX +* CLRL in not text must be =XX=XX +* 33 through 60 inclusive can be plain +* 62 through 126 inclusive can be plain +* 9 and 32 can be plain, unless in the end of a line, where must be =XX +* encoded lines must be no longer than 76 not counting CRLF +* soft line-break are =CRLF +* To encode one byte, we need to see the next two. +* Worst case is when we see a space, and wonder if a CRLF is comming +\*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*\ +* Split quoted-printable characters into classes +* Precompute reverse map for encoding +\*-------------------------------------------------------------------------*/ +static void qpsetup(UC *qpclass, UC *qpunbase) +{ + int i; + for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED; + for (i = 33; i <= 60; i++) qpclass[i] = QP_PLAIN; + for (i = 62; i <= 126; i++) qpclass[i] = QP_PLAIN; + qpclass['\t'] = QP_IF_LAST; + qpclass[' '] = QP_IF_LAST; + qpclass['\r'] = QP_CR; + for (i = 0; i < 256; i++) qpunbase[i] = 255; + qpunbase['0'] = 0; qpunbase['1'] = 1; qpunbase['2'] = 2; + qpunbase['3'] = 3; qpunbase['4'] = 4; qpunbase['5'] = 5; + qpunbase['6'] = 6; qpunbase['7'] = 7; qpunbase['8'] = 8; + qpunbase['9'] = 9; qpunbase['A'] = 10; qpunbase['a'] = 10; + qpunbase['B'] = 11; qpunbase['b'] = 11; qpunbase['C'] = 12; + qpunbase['c'] = 12; qpunbase['D'] = 13; qpunbase['d'] = 13; + qpunbase['E'] = 14; qpunbase['e'] = 14; qpunbase['F'] = 15; + qpunbase['f'] = 15; +} + +/*-------------------------------------------------------------------------*\ +* Output one character in form =XX +\*-------------------------------------------------------------------------*/ +static void qpquote(UC c, luaL_Buffer *buffer) +{ + luaL_putchar(buffer, '='); + luaL_putchar(buffer, qpbase[c >> 4]); + luaL_putchar(buffer, qpbase[c & 0x0F]); +} + +/*-------------------------------------------------------------------------*\ +* Accumulate characters until we are sure about how to deal with them. +* Once we are sure, output to the buffer, in the correct form. +\*-------------------------------------------------------------------------*/ +static size_t qpencode(UC c, UC *input, size_t size, + const char *marker, luaL_Buffer *buffer) +{ + input[size++] = c; + /* deal with all characters we can have */ + while (size > 0) { + switch (qpclass[input[0]]) { + /* might be the CR of a CRLF sequence */ + case QP_CR: + if (size < 2) return size; + if (input[1] == '\n') { + luaL_addstring(buffer, marker); + return 0; + } else qpquote(input[0], buffer); + break; + /* might be a space and that has to be quoted if last in line */ + case QP_IF_LAST: + if (size < 3) return size; + /* if it is the last, quote it and we are done */ + if (input[1] == '\r' && input[2] == '\n') { + qpquote(input[0], buffer); + luaL_addstring(buffer, marker); + return 0; + } else luaL_putchar(buffer, input[0]); + break; + /* might have to be quoted always */ + case QP_QUOTED: + qpquote(input[0], buffer); + break; + /* might never have to be quoted */ + default: + luaL_putchar(buffer, input[0]); + break; + } + input[0] = input[1]; input[1] = input[2]; + size--; + } + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Deal with the final characters +\*-------------------------------------------------------------------------*/ +static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) +{ + size_t i; + for (i = 0; i < size; i++) { + if (qpclass[input[i]] == QP_PLAIN) luaL_putchar(buffer, input[i]); + else qpquote(input[i], buffer); + } + if (size > 0) luaL_addstring(buffer, EQCRLF); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally converts a string to quoted-printable +* A, B = qp(C, D, marker) +* Marker is the text to be used to replace CRLF sequences found in A. +* A is the encoded version of the largest prefix of C .. D that +* can be encoded without doubts. +* B has the remaining bytes of C .. D, *without* encoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_qp(lua_State *L) +{ + + size_t asize = 0, isize = 0; + UC atom[3]; + const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + const char *marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + input = (UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + asize = qppad(atom, asize, &buffer); + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Accumulate characters until we are sure about how to deal with them. +* Once we are sure, output the to the buffer, in the correct form. +\*-------------------------------------------------------------------------*/ +static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { + int d; + input[size++] = c; + /* deal with all characters we can deal */ + switch (input[0]) { + /* if we have an escape character */ + case '=': + if (size < 3) return size; + /* eliminate soft line break */ + if (input[1] == '\r' && input[2] == '\n') return 0; + /* decode quoted representation */ + c = qpunbase[input[1]]; d = qpunbase[input[2]]; + /* if it is an invalid, do not decode */ + if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3); + else luaL_putchar(buffer, (c << 4) + d); + return 0; + case '\r': + if (size < 2) return size; + if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2); + return 0; + default: + if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) + luaL_putchar(buffer, input[0]); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Incrementally decodes a string in quoted-printable +* A, B = qp(C, D) +* A is the decoded version of the largest prefix of C .. D that +* can be decoded without doubts. +* B has the remaining bytes of C .. D, *without* decoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_unqp(lua_State *L) +{ + size_t asize = 0, isize = 0; + UC atom[3]; + const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + input = (UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally breaks a quoted-printed string into lines +* A, n = qpwrp(l, B, length) +* A is a copy of B, broken into lines of at most 'length' bytes. +* 'l' is how many bytes are left for the first line of B. +* 'n' is the number of bytes left in the last line of A. +* There are two complications: lines can't be broken in the middle +* of an encoded =XX, and there might be line breaks already +\*-------------------------------------------------------------------------*/ +static int mime_global_qpwrp(lua_State *L) +{ + size_t size = 0; + int left = (int) luaL_checknumber(L, 1); + const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); + const UC *last = input + size; + int length = (int) luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + if (left < length) lua_pushstring(L, EQCRLF); + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) { + switch (*input) { + case '\r': + break; + case '\n': + left = length; + luaL_addstring(&buffer, CRLF); + break; + case '=': + if (left <= 3) { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_putchar(&buffer, *input); + left--; + break; + default: + if (left <= 1) { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_putchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Here is what we do: \n, and \r are considered candidates for line +* break. We issue *one* new line marker if any of them is seen alone, or +* followed by a different one. That is, \n\n and \r\r will issue two +* end of line markers each, but \r\n, \n\r etc will only issue *one* +* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as +* probably other more obscure conventions. +* +* c is the current character being processed +* last is the previous character +\*-------------------------------------------------------------------------*/ +#define eolcandidate(c) (c == '\r' || c == '\n') +static int eolprocess(int c, int last, const char *marker, + luaL_Buffer *buffer) +{ + if (eolcandidate(c)) { + if (eolcandidate(last)) { + if (c == last) luaL_addstring(buffer, marker); + return 0; + } else { + luaL_addstring(buffer, marker); + return c; + } + } else { + luaL_putchar(buffer, c); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Converts a string to uniform EOL convention. +* A, n = eol(o, B, marker) +* A is the converted version of the largest prefix of B that can be +* converted unambiguously. 'o' is the context returned by the previous +* call. 'n' is the new context. +\*-------------------------------------------------------------------------*/ +static int mime_global_eol(lua_State *L) +{ + int ctx = luaL_checkint(L, 1); + size_t isize = 0; + const char *input = luaL_optlstring(L, 2, NULL, &isize); + const char *last = input + isize; + const char *marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + luaL_buffinit(L, &buffer); + /* end of input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnumber(L, 0); + return 2; + } + /* process all input */ + while (input < last) + ctx = eolprocess(*input++, ctx, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, ctx); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Takes one byte and stuff it if needed. +\*-------------------------------------------------------------------------*/ +static size_t dot(int c, size_t state, luaL_Buffer *buffer) +{ + luaL_putchar(buffer, c); + switch (c) { + case '\r': + return 1; + case '\n': + return (state == 1)? 2: 0; + case '.': + if (state == 2) + luaL_putchar(buffer, '.'); + default: + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Incrementally applies smtp stuffing to a string +* A, n = dot(l, D) +\*-------------------------------------------------------------------------*/ +static int mime_global_dot(lua_State *L) +{ + size_t isize = 0, state = (size_t) luaL_checknumber(L, 1); + const char *input = luaL_optlstring(L, 2, NULL, &isize); + const char *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnumber(L, 2); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) + state = dot(*input++, state, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, state); + return 2; +} + diff --git a/luaclib/mime/mime.h b/luaclib/mime/mime.h new file mode 100644 index 0000000..661efae --- /dev/null +++ b/luaclib/mime/mime.h @@ -0,0 +1,26 @@ +#ifndef MIME_H +#define MIME_H +/*=========================================================================*\ +* Core MIME support +* LuaSocket toolkit +* +* This module provides functions to implement transfer content encodings +* and formatting conforming to RFC 2045. It is used by mime.lua, which +* provide a higher level interface to this functionality. +* +* RCS ID: $Id: mime.h,v 1.15 2007/06/11 23:44:54 diego Exp $ +\*=========================================================================*/ +#include "lua.h" + +#define luaL_putchar luaL_addchar + +/*-------------------------------------------------------------------------*\ +* Current MIME library version +\*-------------------------------------------------------------------------*/ +#define MIME_VERSION "MIME 1.0.2" +#define MIME_COPYRIGHT "Copyright (C) 2004-2007 Diego Nehab" +#define MIME_AUTHORS "Diego Nehab" + +LUAMOD_API int luaopen_mime_core(lua_State *L); + +#endif /* MIME_H */ diff --git a/luaclib/mime/mime.vcxproj b/luaclib/mime/mime.vcxproj new file mode 100644 index 0000000..276da6f --- /dev/null +++ b/luaclib/mime/mime.vcxproj @@ -0,0 +1,94 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + {2691C520-B01B-46AB-B585-716767F72A9F} + Win32Proj + mime + + + + DynamicLibrary + true + v120 + Unicode + + + DynamicLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + true + $(ProjectDir) + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;LUA_CORE;LUA_BUILD_AS_DLL;LUA_COMPAT_5_2;LUA_COMPAT_5_1;MIME_EXPORTS;%(PreprocessorDefinitions) + true + ..\..\deps\lua; + + + Windows + true + nlua.lib + ..\..\deps\lua; + + + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MIME_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/luaclib/mime/mime.vcxproj.filters b/luaclib/mime/mime.vcxproj.filters new file mode 100644 index 0000000..3f972d8 --- /dev/null +++ b/luaclib/mime/mime.vcxproj.filters @@ -0,0 +1,18 @@ + + + + + {20cf0978-da51-499c-91d9-8fc26c6e8702} + + + + + src + + + + + src + + + \ No newline at end of file diff --git a/luaclib/mime/mime.vcxproj.user b/luaclib/mime/mime.vcxproj.user new file mode 100644 index 0000000..ef5ff2a --- /dev/null +++ b/luaclib/mime/mime.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/luaclib/pb/Android.mk b/luaclib/pb/Android.mk new file mode 100644 index 0000000..de8d38f --- /dev/null +++ b/luaclib/pb/Android.mk @@ -0,0 +1,29 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := pbc + +LOCAL_MODULE_FILENAME := libpbc + +LOCAL_SRC_FILES := \ + src/alloc.c \ +src/array.c \ +src/bootstrap.c \ +src/context.c \ +src/decode.c \ +src/map.c \ +src/pattern.c \ +src/proto.c \ +src/register.c \ +src/rmessage.c \ +src/stringpool.c \ +src/varint.c \ +src/wmessage.c \ + + + +LOCAL_C_INCLUDES+= src\ + + +include $(BUILD_STATIC_LIBRARY) diff --git a/luaclib/pb/Makefile b/luaclib/pb/Makefile new file mode 100644 index 0000000..240532c --- /dev/null +++ b/luaclib/pb/Makefile @@ -0,0 +1,56 @@ +PB_VERSION = 0.5 +LUA_VERSION = 5.1 +TARGET = protobuf.so + +# See https://github.com/cloudwu/pbc for specific details. + +## Linux/BSD +PREFIX ?= /usr/local +LDFLAGS += -shared + +## OSX (Macports) +#PREFIX ?= /opt/local +#LDFLAGS += -bundle -undefined dynamic_lookup + +#added by xdczju@sina.com +ifeq ($(OS),Windows_NT) + TARGET = protobuf.dll + LDFLAGS2 += -lluajit51 +endif + +LUA_INCLUDE_DIR ?= $(PREFIX)/include +LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION) + +# Some versions of Solaris are missing isinf(). Add -DMISSING_ISINF to +# CFLAGS to work around this bug. + +#CFLAGS ?= -g -Wall -pedantic -fno-inline +CFLAGS ?= -g -O3 -Wall -pedantic +override CFLAGS += -fpic -I$(LUA_INCLUDE_DIR) -Isrc -DVERSION=\"$(PB_VERSION)\" + +INSTALL ?= install + +.PHONY: all clean install package + +all: $(TARGET) + + +OBJS = binding/lua/pbc-lua.o src/context.o src/varint.o src/array.o src/pattern.o src/register.o src/proto.o src/map.o src/alloc.o src/rmessage.o src/wmessage.o src/bootstrap.o src/stringpool.o src/decode.o +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDFLAGS2) + +install: + $(INSTALL) -d $(DESTDIR)/$(LUA_LIB_DIR) + $(INSTALL) $(TARGET) $(DESTDIR)/$(LUA_LIB_DIR) + +clean: + rm -f *.o *.so + +package: + git archive --prefix="lua-pb-$(PB_VERSION)/" master | \ + gzip -9 > "lua-pb-$(PB_VERSION).tar.gz" + git archive --prefix="lua-pb-$(PB_VERSION)/" \ + -o "lua-pb-$(PB_VERSION).zip" master + + + diff --git a/luaclib/pb/Makefile.bak b/luaclib/pb/Makefile.bak new file mode 100644 index 0000000..63f7805 --- /dev/null +++ b/luaclib/pb/Makefile.bak @@ -0,0 +1,84 @@ +CC = gcc +CFLAGS = -O2 +AR = ar rc + +BUILD = build + +.PHONY : all lib clean tool + +LIBSRCS = context.c varint.c array.c pattern.c register.c proto.c map.c alloc.c rmessage.c wmessage.c bootstrap.c stringpool.c decode.c +LIBNAME = libpbc.a + +TESTSRCS = addressbook.c pattern.c pbc.c float.c map.c test.c decode.c +PROTOSRCS = addressbook.proto descriptor.proto float.proto test.proto + +BUILD_O = $(BUILD)/o + +all : lib test + +lib : $(LIBNAME) + +clean : + rm -rf $(BUILD) + +$(BUILD) : $(BUILD_O) + +$(BUILD_O) : + mkdir -p $@ + +TOOL := $(BUILD)/dump + +tool : $(TOOL) + +$(TOOL) : | $(BUILD) +$(TOOL) : $(LIBNAME) +$(TOOL) : tool/dump.c + cd $(BUILD) && $(CC) $(CFLAGS) -I.. -L. -o dump ../$< -lpbc + +LIB_O := + +define BUILD_temp + TAR := $(BUILD_O)/$(notdir $(basename $(1))) + LIB_O := $(LIB_O) $$(TAR).o + $$(TAR).o : | $(BUILD_O) + -include $$(TAR).d + $$(TAR).o : src/$(1) + $(CC) $(CFLAGS) -c -Isrc -I. -o $$@ -MMD $$< +endef + +$(foreach s,$(LIBSRCS),$(eval $(call BUILD_temp,$(s)))) + +$(LIBNAME) : $(LIB_O) + cd $(BUILD) && $(AR) $(LIBNAME) $(addprefix ../,$^) + +TEST := + +define TEST_temp + TAR := $(BUILD)/$(notdir $(basename $(1))) + TEST := $(TEST) $$(TAR) + $$(TAR) : | $(BUILD) + $$(TAR) : $(LIBNAME) + $$(TAR) : test/$(1) + cd $(BUILD) && $(CC) $(CFLAGS) -I.. -L. -o $$(notdir $$@) ../$$< -lpbc +endef + +$(foreach s,$(TESTSRCS),$(eval $(call TEST_temp,$(s)))) + +test : $(TEST) proto + +PROTO := + +define PROTO_temp + TAR := $(BUILD)/$(notdir $(basename $(1))) + PROTO := $(PROTO) $$(TAR).pb + $$(TAR).pb : | $(BUILD) + $$(TAR).pb : test/$(1) + protoc -o$$@ $$< +endef + +$(foreach s,$(PROTOSRCS),$(eval $(call PROTO_temp,$(s)))) + +proto : $(PROTO) + +.PHONY : all lib test proto clean + diff --git a/luaclib/pb/README.md b/luaclib/pb/README.md new file mode 100644 index 0000000..19e4624 --- /dev/null +++ b/luaclib/pb/README.md @@ -0,0 +1,85 @@ +## PBC + +PBC is a google protocol buffers library for C without code generation. + +## Quick Example + + package tutorial; + + message Person { + required string name = 1; + required int32 id = 2; // Unique ID number for this person. + optional string email = 3; + + enum PhoneType { + MOBILE = 0; + HOME = 1; + WORK = 2; + } + + message PhoneNumber { + required string number = 1; + optional PhoneType type = 2 [default = HOME]; + } + + repeated PhoneNumber phone = 4; + } + +```C +struct pbc_rmessage * m = pbc_rmessage_new(env, "tutorial.Person", slice); +printf("name = %s\n", pbc_rmessage_string(m , "name" , 0 , NULL)); +printf("id = %d\n", pbc_rmessage_integer(m , "id" , 0 , NULL)); +printf("email = %s\n", pbc_rmessage_string(m , "email" , 0 , NULL)); + +int phone_n = pbc_rmessage_size(m, "phone"); +int i; + +for (i=0;i + +#ifndef _MSC_VER +#include +#else +#define alloca _alloca +#endif + +#include +#include +#include + +#include "pbc.h" + +#if LUA_VERSION_NUM == 501 + +#define lua_rawlen lua_objlen +#define luaL_newlib(L ,reg) luaL_register(L,"protobuf.c",reg) +#define luaL_buffinit(L , _ ) +#define luaL_prepbuffsize( b , cap ) malloc(cap) +#define _Free(p) free(p) +#undef luaL_addsize +#define luaL_addsize(b , len) lua_pushlstring(L, temp , len) ; free(temp) +#define luaL_pushresult(b) +#define luaL_checkversion(L) + +#else + +#define _Free(p) + +#endif + +static inline void * +checkuserdata(lua_State *L, int index) { + void * ud = lua_touserdata(L,index); + if (ud == NULL) { + luaL_error(L, "userdata %d is nil",index); + } + return ud; +} + +static int +_env_new(lua_State *L) { + struct pbc_env * env = pbc_new(); + lua_pushlightuserdata(L, env); + return 1; +} + +static int +_env_register(lua_State *L) { + struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); + size_t sz = 0; + const char * buffer = luaL_checklstring(L, 2 , &sz); + struct pbc_slice slice; + slice.buffer = (void *)buffer; + slice.len = (int)sz; + int ret = pbc_register(env, &slice); + + if (ret) { + return luaL_error(L, "register fail"); + } + return 0; +} + +static int +_rmessage_new(lua_State *L) { + struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); + const char * type_name = luaL_checkstring(L,2); + struct pbc_slice slice; + if (lua_isstring(L,3)) { + size_t sz = 0; + slice.buffer = (void *)lua_tolstring(L,3,&sz); + slice.len = (int)sz; + } else { + slice.buffer = lua_touserdata(L,3); + slice.len = luaL_checkinteger(L,4); + } + struct pbc_rmessage * m = pbc_rmessage_new(env, type_name, &slice); + if (m==NULL) + return 0; + lua_pushlightuserdata(L,m); + return 1; +} + +static int +_rmessage_delete(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + pbc_rmessage_delete(m); + + return 0; +} + +static int +_rmessage_integer(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int index = luaL_checkinteger(L,3); + int32_t v = (int32_t)pbc_rmessage_integer(m, key, index, NULL); + + lua_pushinteger(L,v); + + return 1; +} + +static int +_rmessage_int32(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int index = luaL_checkinteger(L,3); + uint32_t v = pbc_rmessage_integer(m, key, index, NULL); + lua_pushlightuserdata(L,(void *)(intptr_t)v); + + return 1; +} + + +static int +_rmessage_int64(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int index = luaL_checkinteger(L,3); + uint32_t v[2]; + v[0] = pbc_rmessage_integer(m, key, index, &v[1]); + + lua_pushlstring(L,(const char *)v,sizeof(v)); + + return 1; +} + +static int +_rmessage_int52(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int index = luaL_checkinteger(L,3); + uint32_t hi,low; + low = pbc_rmessage_integer(m, key, index, &hi); + int64_t v = (int64_t)((uint64_t)hi << 32 | (uint64_t)low); + lua_pushnumber(L,(lua_Number)v); + + return 1; +} + +static int +_rmessage_uint52(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int index = luaL_checkinteger(L,3); + uint32_t hi,low; + low = pbc_rmessage_integer(m, key, index, &hi); + uint64_t v = (uint64_t)hi << 32 | (uint64_t)low; + lua_pushnumber(L,(lua_Number)v); + + return 1; +} + +static int +_rmessage_real(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int index = luaL_checkinteger(L,3); + double v = pbc_rmessage_real(m, key, index); + + lua_pushnumber(L,v); + + return 1; +} + +static int +_rmessage_string(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int index = lua_tointeger(L,3); + int sz = 0; + const char * v = pbc_rmessage_string(m,key,index,&sz); + lua_pushlstring(L,v,sz); + return 1; +} + +static int +_rmessage_message(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int index = lua_tointeger(L,3); + struct pbc_rmessage * v = pbc_rmessage_message(m,key,index); + lua_pushlightuserdata(L,v); + return 1; +} + +static int +_rmessage_size(lua_State *L) { + struct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + + int sz = pbc_rmessage_size(m, key); + + lua_pushinteger(L, sz); + + return 1; +} + +static int +_env_type(lua_State *L) { + lua_settop(L,3); + struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); + const char * type_name = luaL_checkstring(L,2); + if (lua_isnil(L,3)) { + int ret = pbc_type(env, type_name, NULL, NULL); + lua_pushboolean(L,ret); + return 1; + } + const char * key = luaL_checkstring(L,3); + const char * type = NULL; + int ret = pbc_type(env, type_name, key, &type); + lua_pushinteger(L,ret); + if (type == NULL) { + return 1; + } { + lua_pushstring(L, type); + return 2; + } +} + +static int +_wmessage_new(lua_State *L) { + struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); + const char * type_name = luaL_checkstring(L,2); + struct pbc_wmessage * ret = pbc_wmessage_new(env, type_name); + lua_pushlightuserdata(L,ret); + return 1; +} + +static int +_wmessage_delete(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)lua_touserdata(L,1); + pbc_wmessage_delete(m); + + return 0; +} + + +static int +_wmessage_integer(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int number = luaL_checkinteger(L,3); + uint32_t hi = 0; + if (number < 0) + hi = ~0; + pbc_wmessage_integer(m, key, number, hi); + + return 0; +} + +static int +_wmessage_real(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + double number = luaL_checknumber(L,3); + pbc_wmessage_real(m, key, number); + + return 0; +} + +static int +_wmessage_string(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + size_t len = 0; + const char * v = luaL_checklstring(L,3,&len); + int err = pbc_wmessage_string(m, key, v, (int)len); + if (err) { + return luaL_error(L, "Write string error : %s", v); + } + + return 0; +} + +static int +_wmessage_message(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + struct pbc_wmessage * ret = pbc_wmessage_message(m, key); + lua_pushlightuserdata(L, ret); + + return 1; +} + +static int +_wmessage_int32(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + if (!lua_islightuserdata(L,3)) { + return luaL_error(L,"Need a lightuserdata for int32"); + } + void *number = lua_touserdata(L,3); + pbc_wmessage_integer(m, key, (uint32_t)(intptr_t)number , 0); + return 0; +} + +static int +_wmessage_int64(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + switch (lua_type(L,3)) { + case LUA_TSTRING : { + size_t len = 0; + const char * number = lua_tolstring(L,3,&len); + if (len !=8 ) { + return luaL_error(L,"Need an 8 length string for int64"); + } + const uint32_t * v = (const uint32_t *) number; + pbc_wmessage_integer(m, key, v[0] , v[1]); + break; + } + case LUA_TLIGHTUSERDATA : { + void * v = lua_touserdata(L,3); + uint64_t v64 = (uintptr_t)v; + pbc_wmessage_integer(m, key, (uint32_t)v64 , (uint32_t)(v64>>32)); + break; + } + default : + return luaL_error(L, "Need an int64 type"); + } + return 0; +} + +static int +_wmessage_int52(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + int64_t number = (int64_t)(luaL_checknumber(L,3)); + uint32_t hi = (uint32_t)(number >> 32); + pbc_wmessage_integer(m, key, (uint32_t)number, hi); + + return 0; +} + +static int +_wmessage_uint52(lua_State *L) { + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + const char * key = luaL_checkstring(L,2); + lua_Number v = (luaL_checknumber(L,3)); + if (v < 0) { + return luaL_error(L, "negative number : %f passed to unsigned field",v); + } + uint64_t number = (uint64_t)v; + uint32_t hi = (uint32_t)(number >> 32); + pbc_wmessage_integer(m, key, (uint32_t)number, hi); + + return 0; +} + +static int +_wmessage_buffer(lua_State *L) { + struct pbc_slice slice; + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + pbc_wmessage_buffer(m , &slice); + lua_pushlightuserdata(L, slice.buffer); + lua_pushinteger(L, slice.len); + return 2; +} + +static int +_wmessage_buffer_string(lua_State *L) { + struct pbc_slice slice; + struct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1); + pbc_wmessage_buffer(m , &slice); + lua_pushlstring(L, (const char *)slice.buffer, slice.len); + return 1; +} + +/* + lightuserdata env + */ +static int +_last_error(lua_State *L) { + struct pbc_env * env = (struct pbc_env *)checkuserdata(L, 1); + const char * err = pbc_error(env); + lua_pushstring(L,err); + return 1; +} + +/* + lightuserdata env + string message + string format + */ +static int +_pattern_new(lua_State *L) { + struct pbc_env * env = (struct pbc_env *)checkuserdata(L, 1); + const char * message = luaL_checkstring(L,2); + const char * format = luaL_checkstring(L,3); + struct pbc_pattern * pat = pbc_pattern_new(env, message, format); + if (pat == NULL) { + return luaL_error(L, "create patten %s (%s) failed", message , format); + } + lua_pushlightuserdata(L,pat); + + return 1; +} + +static int +_pattern_delete(lua_State *L) { + struct pbc_pattern * pat = (struct pbc_pattern *)lua_touserdata(L,1); + pbc_pattern_delete(pat); + + return 0; +} + +static void * +_push_value(lua_State *L, char * ptr, char type) { + switch(type) { + case 'u': { + uint64_t v = *(uint64_t*)ptr; + ptr += 8; + lua_pushnumber(L,(lua_Number)v); + break; + } + case 'i': { + int32_t v = *(int32_t*)ptr; + ptr += 4; + lua_pushinteger(L,v); + break; + } + case 'b': { + int32_t v = *(int32_t*)ptr; + ptr += 4; + lua_pushboolean(L,v); + break; + } + case 'p': { + uint32_t v = *(uint32_t*)ptr; + ptr += 4; + lua_pushlightuserdata(L,(void *)(intptr_t)v); + break; + } + case 'x': { + lua_pushlstring(L,ptr,8); + ptr += 8; + break; + } + case 'd': { + int64_t v = *(int64_t*)ptr; + ptr += 8; + lua_pushnumber(L,(lua_Number)v); + break; + } + case 'r': { + double v = *(double *)ptr; + ptr += 8; + lua_pushnumber(L,v); + break; + } + case 's': { + struct pbc_slice * slice = (struct pbc_slice *)ptr; + lua_pushlstring(L,(const char *)slice->buffer, slice->len); + ptr += sizeof(struct pbc_slice); + break; + } + case 'm': { + struct pbc_slice * slice = (struct pbc_slice *)ptr; + lua_createtable(L,2,0); + lua_pushlightuserdata(L, slice->buffer); + lua_rawseti(L,-2,1); + lua_pushinteger(L,slice->len); + lua_rawseti(L,-2,2); + ptr += sizeof(struct pbc_slice); + break; + } + } + return ptr; +} + +static void +_push_array(lua_State *L, pbc_array array, char type, int index) { + switch (type) { + case 'I': { + int v = pbc_array_integer(array, index, NULL); + lua_pushinteger(L, v); + break; + } + case 'U': { + uint32_t hi = 0; + uint32_t low = pbc_array_integer(array, index, &hi); + uint64_t v = (uint64_t)hi << 32 | (uint64_t)low; + lua_pushnumber(L, (lua_Number)v); + break; + } + case 'D': { + uint32_t hi = 0; + uint32_t low = pbc_array_integer(array, index, &hi); + uint64_t v = (uint64_t)hi << 32 | (uint64_t)low; + lua_pushnumber(L, (lua_Number)((int64_t)v)); + break; + } + case 'B': { + int v = pbc_array_integer(array, index, NULL); + lua_pushboolean(L, v); + break; + } + case 'P': { + uint32_t v = pbc_array_integer(array, index, NULL); + lua_pushlightuserdata(L,(void *)(intptr_t)v); + break; + } + case 'X': { + uint32_t hi = 0; + uint32_t low = pbc_array_integer(array, index, &hi); + uint64_t v = (uint64_t)low | (uint64_t)hi << 32; + lua_pushlstring(L, (char *)&v, 8); + break; + } + case 'R': { + double v = pbc_array_real(array, index); + lua_pushnumber(L, v); + break; + } + case 'S': { + struct pbc_slice * slice = pbc_array_slice(array, index); + lua_pushlstring(L, (const char *)slice->buffer,slice->len); + break; + } + case 'M': { + struct pbc_slice * slice = pbc_array_slice(array, index); + lua_createtable(L,2,0); + lua_pushlightuserdata(L,slice->buffer); + lua_rawseti(L,-2,1); + lua_pushinteger(L,slice->len); + lua_rawseti(L,-2,2); + break; + } + } + lua_rawseti(L,-2,index+1); +} + +/* + lightuserdata pattern + string format "ixrsmb" + integer size + lightuserdata buffer + integer buffer_len + */ +static int +_pattern_unpack(lua_State *L) { + struct pbc_pattern * pat = (struct pbc_pattern *)checkuserdata(L, 1); + if (pat == NULL) { + return luaL_error(L, "unpack pattern is NULL"); + } + size_t format_sz = 0; + const char * format = lua_tolstring(L,2,&format_sz); + int size = lua_tointeger(L,3); + struct pbc_slice slice; + if (lua_isstring(L,4)) { + size_t buffer_len = 0; + const char *buffer = luaL_checklstring(L,4,&buffer_len); + slice.buffer = (void *)buffer; + slice.len = buffer_len; + } else { + if (!lua_isuserdata(L,4)) { + return luaL_error(L, "Need a userdata"); + } + slice.buffer = lua_touserdata(L,4); + slice.len = luaL_checkinteger(L,5); + } + + char * temp = (char *)alloca(size); + int ret = pbc_pattern_unpack(pat, &slice, temp); + if (ret < 0) { + return 0; + } + lua_checkstack(L, format_sz + 3); + int i; + char * ptr = temp; + bool array = false; + for (i=0;i= 'a' && type <='z') { + ptr = (char *)_push_value(L,ptr,type); + } else { + array = true; + int n = pbc_array_size((struct _pbc_array *)ptr); + lua_createtable(L,n,0); + int j; + for (j=0;jbuffer = (void*)str; + slice->len = sz; + return ptr + sizeof(struct pbc_slice); + } + case 'm': { + struct pbc_slice * slice = (struct pbc_slice *)ptr; + if (lua_istable(L,index)) { + lua_rawgeti(L,index,1); + slice->buffer = lua_touserdata(L,-1); + lua_rawgeti(L,index,2); + slice->len = lua_tointeger(L,-1); + lua_pop(L,2); + } else { + size_t sz = 0; + const char * buffer = luaL_checklstring(L, index, &sz); + slice->buffer = (void *)buffer; + slice->len = sz; + } + return ptr + sizeof(struct pbc_slice); + } + default: + luaL_error(L,"unknown format %c", type); + return ptr; + } +} + +static void +_get_array_value(lua_State *L, pbc_array array, char type) { + switch(type) { + case 'I': { + int32_t v = luaL_checkinteger(L, -1); + uint32_t hi = 0; + if (v<0) { + hi = ~0; + } + pbc_array_push_integer(array, v, hi); + break; + } + case 'U' : { + uint64_t v = (uint64_t)luaL_checknumber(L, -1); + pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32)); + break; + } + case 'D' : { + int64_t v = (int64_t)luaL_checknumber(L, -1); + pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32)); + break; + } + case 'B': { + int32_t v = lua_toboolean(L, -1); + pbc_array_push_integer(array, v ? 1: 0, 0); + break; + } + case 'P': { + void *p = lua_touserdata(L, -1); + uint32_t v = (uint32_t)(intptr_t)p; + pbc_array_push_integer(array, v, 0); + break; + } + case 'X': { + const char * i64 = luaL_checkstring(L, -1); + uint64_t v = *(uint64_t *)i64; + pbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32)); + break; + } + case 'R': { + double v = luaL_checknumber(L, -1); + pbc_array_push_real(array, v); + break; + } + case 'S': { + size_t sz = 0; + const char * str = luaL_checklstring(L, -1, &sz); + struct pbc_slice slice; + slice.buffer = (void*)str; + slice.len = sz; + pbc_array_push_slice(array, &slice); + break; + } + case 'M': { + struct pbc_slice slice; + if (lua_istable(L,-1)) { + lua_rawgeti(L,-1,1); + slice.buffer = lua_touserdata(L,-1); + lua_rawgeti(L,-2,2); + slice.len = lua_tointeger(L,-1); + lua_pop(L,2); + } else { + size_t sz = 0; + const char * buffer = luaL_checklstring(L, -1, &sz); + slice.buffer = (void *)buffer; + slice.len = sz; + } + pbc_array_push_slice(array, &slice); + break; + } + } +} + +/* + lightuserdata pattern + string format "ixrsmbp" + integer size + */ +static int +_pattern_pack(lua_State *L) { + struct pbc_pattern * pat = (struct pbc_pattern *)checkuserdata(L,1); + if (pat == NULL) { + return luaL_error(L, "pack pattern is NULL"); + } + size_t format_sz = 0; + const char * format = lua_tolstring(L,2,&format_sz); + int size = lua_tointeger(L,3); + + char * data = (char *)alloca(size); +// A trick , we don't need default value. zero buffer for array and message field. +// pbc_pattern_set_default(pat, data); + memset(data, 0 , size); + + char * ptr = data; + + int i; + + for (i=0;i= 'a' && format[i] <='z') { + ptr = _get_value(L, 4+i, ptr, format[i]); + } else { + if (!lua_istable(L,4+i)) { + luaL_error(L,"need table for array type"); + } + int j; + int n = lua_rawlen(L,4+i); + for (j=0;ji.low); + break; + case PBC_REAL: + lua_pushnumber(L, v->f); + break; + case PBC_BOOL: + lua_pushboolean(L, v->i.low); + break; + case PBC_ENUM: + lua_pushstring(L, v->e.name); + break; + case PBC_BYTES: + case PBC_STRING: + lua_pushlstring(L, (const char *)v->s.buffer , v->s.len); + break; + case PBC_MESSAGE: + lua_pushvalue(L, -3); + lua_pushstring(L, type_name); + lua_pushlstring(L, (const char *)v->s.buffer , v->s.len); + lua_call(L, 2 , 1); + break; + case PBC_FIXED64: + lua_pushlstring(L, (const char *)&(v->i), 8); + break; + case PBC_FIXED32: + lua_pushlightuserdata(L,(void *)(intptr_t)v->i.low); + break; + case PBC_INT64: { + uint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low); + lua_pushnumber(L,(lua_Number)(int64_t)v64); + break; + } + case PBC_UINT: { + uint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low); + lua_pushnumber(L,(lua_Number)v64); + break; + } + default: + luaL_error(L, "Unknown type %s", type_name); + break; + } +} + +/* + -3: function decode + -2: table key + -1: table id + */ +static void +decode_cb(void *ud, int type, const char * type_name, union pbc_value *v, int id, const char *key) { + lua_State *L = (lua_State *)ud; + if (key == NULL) { + // undefined field + return; + } + if (type & PBC_REPEATED) { + push_value(L, type & ~PBC_REPEATED, type_name, v); + new_array(L, id , key); // func.decode table.key table.id value array + int n = lua_rawlen(L,-1); + lua_insert(L, -2); // func.decode table.key table.id array value + lua_rawseti(L, -2 , n+1); // func.decode table.key table.id array + lua_pop(L,1); + } else { + push_value(L, type, type_name, v); + lua_setfield(L, -3 , key); + } +} + +/* + :1 lightuserdata env + :2 function decode_message + :3 table target + :4 string type + :5 string data + :5 lightuserdata pointer + :6 integer len + + table + */ +static int +_decode(lua_State *L) { + struct pbc_env * env = (struct pbc_env *)checkuserdata(L,1); + luaL_checktype(L, 2 , LUA_TFUNCTION); + luaL_checktype(L, 3 , LUA_TTABLE); + const char * type = luaL_checkstring(L,4); + struct pbc_slice slice; + if (lua_type(L,5) == LUA_TSTRING) { + size_t len; + slice.buffer = (void *)luaL_checklstring(L,5,&len); + slice.len = (int)len; + } else { + slice.buffer = checkuserdata(L,5); + slice.len = luaL_checkinteger(L,6); + } + lua_pushvalue(L, 2); + lua_pushvalue(L, 3); + lua_newtable(L); + + int n = pbc_decode(env, type, &slice, decode_cb, L); + if (n<0) { + lua_pushboolean(L,0); + } else { + lua_pushboolean(L,1); + } + return 1; +} + +struct gcobj { + struct pbc_env * env; + int size_pat; + int cap_pat; + struct pbc_pattern ** pat; + int size_msg; + int cap_msg; + struct pbc_rmessage ** msg; +}; + +static int +_clear_gcobj(lua_State *L) { + struct gcobj * obj = (struct gcobj *)lua_touserdata(L,1); + int i; + for (i=0;isize_pat;i++) { + pbc_pattern_delete(obj->pat[i]); + } + for (i=0;isize_msg;i++) { + pbc_rmessage_delete(obj->msg[i]); + } + free(obj->pat); + free(obj->msg); + obj->pat = NULL; + obj->msg = NULL; + pbc_delete(obj->env); + obj->env = NULL; + + return 0; +} + +static int +_gc(lua_State *L) { + struct gcobj * obj = (struct gcobj *)lua_newuserdata(L,sizeof(*obj)); + obj->env = (struct pbc_env *)lua_touserdata(L,1); + obj->size_pat = 0; + obj->cap_pat = 4; + obj->size_msg = 0; + obj->cap_msg = 4; + obj->pat = (struct pbc_pattern **)malloc(obj->cap_pat * sizeof(struct pbc_pattern *)); + obj->msg = (struct pbc_rmessage **)malloc(obj->cap_msg * sizeof(struct pbc_rmessage *)); + + lua_createtable(L,0,1); + lua_pushcfunction(L, _clear_gcobj); + lua_setfield(L,-2,"__gc"); + lua_setmetatable(L,-2); + + return 1; +} + +static int +_add_pattern(lua_State *L) { + struct gcobj * obj = (struct gcobj *)lua_touserdata(L,1); + if (obj->size_pat >= obj->cap_pat) { + obj->cap_pat *= 2; + obj->pat = (struct pbc_pattern **)realloc(obj->pat, obj->cap_pat * sizeof(struct pbc_pattern *)); + } + struct pbc_pattern * pat = (struct pbc_pattern *)lua_touserdata(L,2); + obj->pat[obj->size_pat++] = pat; + return 0; +} + +static int +_add_rmessage(lua_State *L) { + struct gcobj * obj = (struct gcobj *)lua_touserdata(L,1); + if (obj->size_msg >= obj->cap_msg) { + obj->cap_msg *= 2; + obj->msg = (struct pbc_rmessage **)realloc(obj->msg, obj->cap_msg * sizeof(struct pbc_rmessage *)); + } + struct pbc_rmessage * msg = (struct pbc_rmessage *)lua_touserdata(L,2); + obj->msg[obj->size_msg++] = msg; + return 0; +} + +int +luaopen_protobuf_c(lua_State *L) { + luaL_Reg reg[] = { + {"_env_new" , _env_new }, + {"_env_register" , _env_register }, + {"_env_type", _env_type }, + {"_rmessage_new" , _rmessage_new }, + {"_rmessage_delete" , _rmessage_delete }, + {"_rmessage_integer" , _rmessage_integer }, + {"_rmessage_int32", _rmessage_int32 }, + {"_rmessage_int64", _rmessage_int64 }, + {"_rmessage_int52", _rmessage_int52 }, + {"_rmessage_uint52", _rmessage_uint52 }, + {"_rmessage_real" , _rmessage_real }, + {"_rmessage_string" , _rmessage_string }, + {"_rmessage_message" , _rmessage_message }, + {"_rmessage_size" , _rmessage_size }, + {"_wmessage_new", _wmessage_new }, + {"_wmessage_delete", _wmessage_delete }, + {"_wmessage_integer", _wmessage_integer }, + {"_wmessage_real", _wmessage_real }, + {"_wmessage_string", _wmessage_string }, + {"_wmessage_message", _wmessage_message }, + {"_wmessage_int32", _wmessage_int32 }, + {"_wmessage_int64", _wmessage_int64 }, + {"_wmessage_int52", _wmessage_int52 }, + {"_wmessage_uint52", _wmessage_uint52 }, + {"_wmessage_buffer", _wmessage_buffer }, + {"_wmessage_buffer_string", _wmessage_buffer_string }, + {"_pattern_new", _pattern_new }, + {"_pattern_delete", _pattern_delete }, + {"_pattern_size", _pattern_size }, + {"_pattern_unpack", _pattern_unpack }, + {"_pattern_pack", _pattern_pack }, + {"_last_error", _last_error }, + {"_decode", _decode }, + {"_gc", _gc }, + {"_add_pattern", _add_pattern }, + {"_add_rmessage", _add_rmessage }, + {NULL,NULL}, + }; + + luaL_checkversion(L); + luaL_newlib(L, reg); + + return 1; +} diff --git a/luaclib/pb/binding/lua/protobuf.lua b/luaclib/pb/binding/lua/protobuf.lua new file mode 100644 index 0000000..956e990 --- /dev/null +++ b/luaclib/pb/binding/lua/protobuf.lua @@ -0,0 +1,558 @@ +local c = require "protobuf.c" + +local setmetatable = setmetatable +local type = type +local table = table +local assert = assert +local pairs = pairs +local ipairs = ipairs +local string = string +local print = print +local io = io +local tinsert = table.insert +local rawget = rawget + +--module "protobuf" +local Protobuf = {} + +local _pattern_cache = {} + +-- skynet clear +local P = c._env_new() +local GC = c._gc(P) + +function Protobuf.lasterror() + return c._last_error(P) +end + +local decode_type_cache = {} +local _R_meta = {} + +function _R_meta:__index(key) + local v = decode_type_cache[self._CType][key](self, key) + self[key] = v + return v +end + +local _reader = {} + +function _reader:int(key) + return c._rmessage_integer(self._CObj , key , 0) +end + +function _reader:real(key) + return c._rmessage_real(self._CObj , key , 0) +end + +function _reader:string(key) + return c._rmessage_string(self._CObj , key , 0) +end + +function _reader:bool(key) + return c._rmessage_integer(self._CObj , key , 0) ~= 0 +end + +function _reader:message(key, message_type) + local rmessage = c._rmessage_message(self._CObj , key , 0) + if rmessage then + local v = { + _CObj = rmessage, + _CType = message_type, + _Parent = self, + } + return setmetatable( v , _R_meta ) + end +end + +function _reader:int32(key) + return c._rmessage_int32(self._CObj , key , 0) +end + +function _reader:int64(key) + return c._rmessage_int64(self._CObj , key , 0) +end + +function _reader:int52(key) + return c._rmessage_int52(self._CObj , key , 0) +end + +function _reader:uint52(key) + return c._rmessage_uint52(self._CObj , key , 0) +end + +function _reader:int_repeated(key) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + tinsert(ret, c._rmessage_integer(cobj , key , i)) + end + return ret +end + +function _reader:real_repeated(key) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + tinsert(ret, c._rmessage_real(cobj , key , i)) + end + return ret +end + +function _reader:string_repeated(key) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + tinsert(ret, c._rmessage_string(cobj , key , i)) + end + return ret +end + +function _reader:bool_repeated(key) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + tinsert(ret, c._rmessage_integer(cobj , key , i) ~= 0) + end + return ret +end + +function _reader:message_repeated(key, message_type) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + local m = { + _CObj = c._rmessage_message(cobj , key , i), + _CType = message_type, + _Parent = self, + } + tinsert(ret, setmetatable( m , _R_meta )) + end + return ret +end + +function _reader:int32_repeated(key) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + tinsert(ret, c._rmessage_int32(cobj , key , i)) + end + return ret +end + +function _reader:int64_repeated(key) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + tinsert(ret, c._rmessage_int64(cobj , key , i)) + end + return ret +end + +function _reader:int52_repeated(key) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + tinsert(ret, c._rmessage_int52(cobj , key , i)) + end + return ret +end + +function _reader:uint52_repeated(key) + local cobj = self._CObj + local n = c._rmessage_size(cobj , key) + local ret = {} + for i=0,n-1 do + tinsert(ret, c._rmessage_uint52(cobj , key , i)) + end + return ret +end + +_reader[1] = function(msg) return _reader.int end +_reader[2] = function(msg) return _reader.real end +_reader[3] = function(msg) return _reader.bool end +_reader[4] = function(msg) return _reader.string end +_reader[5] = function(msg) return _reader.string end +_reader[6] = function(msg) + local message = _reader.message + return function(self,key) + return message(self, key, msg) + end +end +_reader[7] = function(msg) return _reader.int64 end +_reader[8] = function(msg) return _reader.int32 end +_reader[9] = _reader[5] +_reader[10] = function(msg) return _reader.int52 end +_reader[11] = function(msg) return _reader.uint52 end + +_reader[128+1] = function(msg) return _reader.int_repeated end +_reader[128+2] = function(msg) return _reader.real_repeated end +_reader[128+3] = function(msg) return _reader.bool_repeated end +_reader[128+4] = function(msg) return _reader.string_repeated end +_reader[128+5] = function(msg) return _reader.string_repeated end +_reader[128+6] = function(msg) + local message = _reader.message_repeated + return function(self,key) + return message(self, key, msg) + end +end +_reader[128+7] = function(msg) return _reader.int64_repeated end +_reader[128+8] = function(msg) return _reader.int32_repeated end +_reader[128+9] = _reader[128+5] +_reader[128+10] = function(msg) return _reader.int52_repeated end +_reader[128+11] = function(msg) return _reader.uint52_repeated end + +local _decode_type_meta = {} + +function _decode_type_meta:__index(key) + local t, msg = c._env_type(P, self._CType, key) + local func = assert(_reader[t],key)(msg) + self[key] = func + return func +end + +setmetatable(decode_type_cache , { + __index = function(self, key) + local v = setmetatable({ _CType = key } , _decode_type_meta) + self[key] = v + return v + end +}) + +local function decode_message( message , buffer, length) + local rmessage = c._rmessage_new(P, message, buffer, length) + if rmessage then + local self = { + _CObj = rmessage, + _CType = message, + } + c._add_rmessage(GC,rmessage) + return setmetatable( self , _R_meta ) + end +end + +----------- encode ---------------- + +local encode_type_cache = {} + +local function encode_message(CObj, message_type, t) + local type = encode_type_cache[message_type] + for k,v in pairs(t) do + local func = type[k] + func(CObj, k , v) + end +end + +local _writer = { + int = c._wmessage_integer, + real = c._wmessage_real, + enum = c._wmessage_string, + string = c._wmessage_string, + int64 = c._wmessage_int64, + int32 = c._wmessage_int32, + int52 = c._wmessage_int52, + uint52 = c._wmessage_uint52, +} + +function _writer:bool(k,v) + c._wmessage_integer(self, k, v and 1 or 0) +end + +function _writer:message(k, v , message_type) + local submessage = c._wmessage_message(self, k) + encode_message(submessage, message_type, v) +end + +function _writer:int_repeated(k,v) + for _,v in ipairs(v) do + c._wmessage_integer(self,k,v) + end +end + +function _writer:real_repeated(k,v) + for _,v in ipairs(v) do + c._wmessage_real(self,k,v) + end +end + +function _writer:bool_repeated(k,v) + for _,v in ipairs(v) do + c._wmessage_integer(self, k, v and 1 or 0) + end +end + +function _writer:string_repeated(k,v) + for _,v in ipairs(v) do + c._wmessage_string(self,k,v) + end +end + +function _writer:message_repeated(k,v, message_type) + for _,v in ipairs(v) do + local submessage = c._wmessage_message(self, k) + encode_message(submessage, message_type, v) + end +end + +function _writer:int32_repeated(k,v) + for _,v in ipairs(v) do + c._wmessage_int32(self,k,v) + end +end + +function _writer:int64_repeated(k,v) + for _,v in ipairs(v) do + c._wmessage_int64(self,k,v) + end +end + +function _writer:int52_repeated(k,v) + for _,v in ipairs(v) do + c._wmessage_int52(self,k,v) + end +end + +function _writer:uint52_repeated(k,v) + for _,v in ipairs(v) do + c._wmessage_uint52(self,k,v) + end +end + +_writer[1] = function(msg) return _writer.int end +_writer[2] = function(msg) return _writer.real end +_writer[3] = function(msg) return _writer.bool end +_writer[4] = function(msg) return _writer.string end +_writer[5] = function(msg) return _writer.string end +_writer[6] = function(msg) + local message = _writer.message + return function(self,key , v) + return message(self, key, v, msg) + end +end +_writer[7] = function(msg) return _writer.int64 end +_writer[8] = function(msg) return _writer.int32 end +_writer[9] = _writer[5] +_writer[10] = function(msg) return _writer.int52 end +_writer[11] = function(msg) return _writer.uint52 end + +_writer[128+1] = function(msg) return _writer.int_repeated end +_writer[128+2] = function(msg) return _writer.real_repeated end +_writer[128+3] = function(msg) return _writer.bool_repeated end +_writer[128+4] = function(msg) return _writer.string_repeated end +_writer[128+5] = function(msg) return _writer.string_repeated end +_writer[128+6] = function(msg) + local message = _writer.message_repeated + return function(self,key, v) + return message(self, key, v, msg) + end +end +_writer[128+7] = function(msg) return _writer.int64_repeated end +_writer[128+8] = function(msg) return _writer.int32_repeated end +_writer[128+9] = _writer[128+5] +_writer[128+10] = function(msg) return _writer.int52_repeated end +_writer[128+11] = function(msg) return _writer.uint52_repeated end + +local _encode_type_meta = {} + +function _encode_type_meta:__index(key) + local t, msg = c._env_type(P, self._CType, key) + local func = assert(_writer[t],key)(msg) + self[key] = func + return func +end + +setmetatable(encode_type_cache , { + __index = function(self, key) + local v = setmetatable({ _CType = key } , _encode_type_meta) + self[key] = v + return v + end +}) + +function Protobuf.encode( message, t , func , ...) + local encoder = c._wmessage_new(P, message) + assert(encoder , message) + encode_message(encoder, message, t) + if func then + local buffer, len = c._wmessage_buffer(encoder) + local ret = func(buffer, len, ...) + c._wmessage_delete(encoder) + return ret + else + local s = c._wmessage_buffer_string(encoder) + c._wmessage_delete(encoder) + return s + end +end + +--------- unpack ---------- + +local _pattern_type = { + [1] = {"%d","i"}, + [2] = {"%F","r"}, + [3] = {"%d","b"}, + [4] = {"%d","i"}, + [5] = {"%s","s"}, + [6] = {"%s","m"}, + [7] = {"%D","x"}, + [8] = {"%d","p"}, + [10] = {"%D","d"}, + [11] = {"%D","u"}, + [128+1] = {"%a","I"}, + [128+2] = {"%a","R"}, + [128+3] = {"%a","B"}, + [128+4] = {"%a","I"}, + [128+5] = {"%a","S"}, + [128+6] = {"%a","M"}, + [128+7] = {"%a","X"}, + [128+8] = {"%a","P"}, + [128+10] = {"%a", "D" }, + [128+11] = {"%a", "U" }, +} + +_pattern_type[9] = _pattern_type[5] +_pattern_type[128+9] = _pattern_type[128+5] + + +local function _pattern_create(pattern) + local iter = string.gmatch(pattern,"[^ ]+") + local message = iter() + local cpat = {} + local lua = {} + for v in iter do + local tidx = c._env_type(P, message, v) + local t = _pattern_type[tidx] + assert(t,tidx) + tinsert(cpat,v .. " " .. t[1]) + tinsert(lua,t[2]) + end + local cobj = c._pattern_new(P, message , "@" .. table.concat(cpat," ")) + if cobj == nil then + return + end + c._add_pattern(GC, cobj) + local pat = { + CObj = cobj, + format = table.concat(lua), + size = 0 + } + pat.size = c._pattern_size(pat.format) + + return pat +end + +setmetatable(_pattern_cache, { + __index = function(t, key) + local v = _pattern_create(key) + t[key] = v + return v + end +}) + +function Protobuf.unpack(pattern, buffer, length) + local pat = _pattern_cache[pattern] + return c._pattern_unpack(pat.CObj , pat.format, pat.size, buffer, length) +end + +function Protobuf.pack(pattern, ...) + local pat = _pattern_cache[pattern] + return c._pattern_pack(pat.CObj, pat.format, pat.size , ...) +end + +function Protobuf.check(typename , field) + if field == nil then + return c._env_type(P,typename) + else + return c._env_type(P,typename,field) ~=0 + end +end + +-------------- + +local default_cache = {} + +-- todo : clear default_cache, v._CObj + +local function default_table(typename) + local v = default_cache[typename] + if v then + return v + end + + v = { __index = assert(decode_message(typename , "")) } + + default_cache[typename] = v + return v +end + +local decode_message_mt = {} + +local function decode_message_cb(typename, buffer) + return setmetatable ( { typename, buffer } , decode_message_mt) +end + +function Protobuf.decode(typename, buffer, length) + local ret = {} + local ok = c._decode(P, decode_message_cb , ret , typename, buffer, length) + if ok then + return setmetatable(ret , default_table(typename)) + else + return false , c._last_error(P) + end +end + +local function expand(tbl) + local typename = rawget(tbl , 1) + local buffer = rawget(tbl , 2) + tbl[1] , tbl[2] = nil , nil + assert(c._decode(P, decode_message_cb , tbl , typename, buffer), typename) + setmetatable(tbl , default_table(typename)) +end + +function decode_message_mt.__index(tbl, key) + expand(tbl) + return tbl[key] +end + +function decode_message_mt.__pairs(tbl) + expand(tbl) + return pairs(tbl) +end + +local function set_default(typename, tbl) + for k,v in pairs(tbl) do + if type(v) == "table" then + local t, msg = c._env_type(P, typename, k) + if t == 6 then + set_default(msg, v) + elseif t == 128+6 then + for _,v in ipairs(v) do + set_default(msg, v) + end + end + end + end + return setmetatable(tbl , default_table(typename)) +end + +function Protobuf.register( buffer) + c._env_register(P, buffer) +end + +function Protobuf.register_file(filename) + local f = assert(io.open(filename , "rb")) + local buffer = f:read "*a" + c._env_register(P, buffer) + f:close() +end + +Protobuf.default=set_default + +return Protobuf diff --git a/luaclib/pb/binding/lua/test.lua b/luaclib/pb/binding/lua/test.lua new file mode 100644 index 0000000..d96a355 --- /dev/null +++ b/luaclib/pb/binding/lua/test.lua @@ -0,0 +1,46 @@ +require "protobuf" + +addr = io.open("../../build/addressbook.pb","rb") +buffer = addr:read "*a" +addr:close() + +protobuf.register(buffer) + +t = protobuf.decode("google.protobuf.FileDescriptorSet", buffer) + +proto = t.file[1] + +print(proto.name) +print(proto.package) + +message = proto.message_type + +for _,v in ipairs(message) do + print(v.name) + for _,v in ipairs(v.field) do + print("\t".. v.name .. " ["..v.number.."] " .. v.label) + end +end + +addressbook = { + name = "Alice", + id = 12345, + phone = { + { number = "1301234567" }, + { number = "87654321", type = "WORK" }, + } +} + +code = protobuf.encode("tutorial.Person", addressbook) + +decode = protobuf.decode("tutorial.Person" , code) + +print(decode.name) +print(decode.id) +for _,v in ipairs(decode.phone) do + print("\t"..v.number, v.type) +end + +phonebuf = protobuf.pack("tutorial.Person.PhoneNumber number","87654321") +buffer = protobuf.pack("tutorial.Person name id phone", "Alice", 123, { phonebuf }) +print(protobuf.unpack("tutorial.Person name id phone", buffer)) diff --git a/luaclib/pb/binding/lua/test2.lua b/luaclib/pb/binding/lua/test2.lua new file mode 100644 index 0000000..c704c06 --- /dev/null +++ b/luaclib/pb/binding/lua/test2.lua @@ -0,0 +1,32 @@ +local protobuf = require "protobuf" + +addr = io.open("../../build/addressbook.pb","rb") +buffer = addr:read "*a" +addr:close() +protobuf.register(buffer) + +local person = { + name = "Alice", + id = 123, + phone = { + { number = "123456789" , type = "MOBILE" }, + { number = "87654321" , type = "HOME" }, + } +} + +local buffer = protobuf.encode("tutorial.Person", person) + +local t = protobuf.decode("tutorial.Person", buffer) + +for k,v in pairs(t) do + if type(k) == "string" then + print(k,v) + end +end + +print(t.phone[2].type) + +for k,v in pairs(t.phone[1]) do + print(k,v) +end + diff --git a/luaclib/pb/binding/lua/testparser.lua b/luaclib/pb/binding/lua/testparser.lua new file mode 100644 index 0000000..98901b6 --- /dev/null +++ b/luaclib/pb/binding/lua/testparser.lua @@ -0,0 +1,26 @@ +protobuf = require "protobuf" +parser = require "parser" + +t = parser.register("addressbook.proto","../../test") + +addressbook = { + name = "Alice", + id = 12345, + phone = { + { number = "1301234567" }, + { number = "87654321", type = "WORK" }, + } +} + +code = protobuf.encode("tutorial.Person", addressbook) + +decode = protobuf.decode("tutorial.Person" , code) + +print(decode.name) +print(decode.id) +for _,v in ipairs(decode.phone) do + print("\t"..v.number, v.type) +end + +buffer = protobuf.pack("tutorial.Person name id", "Alice", 123) +print(protobuf.unpack("tutorial.Person name id", buffer)) \ No newline at end of file diff --git a/luaclib/pb/license.txt b/luaclib/pb/license.txt new file mode 100644 index 0000000..33e81c1 --- /dev/null +++ b/luaclib/pb/license.txt @@ -0,0 +1,19 @@ +Copyright (C) 2011 by Cloud Wu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/luaclib/pb/pb.vcxproj.filters b/luaclib/pb/pb.vcxproj.filters new file mode 100644 index 0000000..0fa14e8 --- /dev/null +++ b/luaclib/pb/pb.vcxproj.filters @@ -0,0 +1,87 @@ + + + + + {5ebe0648-0543-4f41-97a2-f6a1b350c869} + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + \ No newline at end of file diff --git a/luaclib/pb/pb.vcxproj.user b/luaclib/pb/pb.vcxproj.user new file mode 100644 index 0000000..ef5ff2a --- /dev/null +++ b/luaclib/pb/pb.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/luaclib/pb/pbc.sdf b/luaclib/pb/pbc.sdf new file mode 100644 index 0000000000000000000000000000000000000000..e90cb30a502ddf202d425584702ac0b831582ced GIT binary patch literal 2555904 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

Gv+YVQ<0U#&-OzgvoBV zTwDxSPP>cXGT*KZXJ2C3-Gna=E`zUoFu^G0Q#WQAB0o3c_)^P_Y2IZ`c4YdMZ?_9` z^&N#D=CPY_HufKD-YCK1~+>VE3#R~u~>uH(bPM)q2KRLoZXHma2r(naCEoj z*FNlBhQFh5y9XngkKvbmSOc~oRW_m-a3Rh!l}+1j)ZRDZ-C@4n8r08L;jy>gVZRfp zPrj^2+^<6z+7X6s*sVby*2UQCE^xmE?pGsL`wKc^%q|yI^}5 z=O1Jjz2b7T4F7K{(p<#{5s!V)E!1B&X_&Q}O@Y}Im`#D%6qrqc*%X*ff!P$8O@Y}Im`#D%6!@>2 z0_C+mzubZL|D{&@pWeRG`*M2A`hUA!p5GH-z7_tD(k|8~U=PXvKfMG0Swhh9A66Ff z^MjV=kYg_Xn9a;kade|@0X!);t zi=U0xYzoY#z-$W4roe0p%%;F>3e2X!YzpL3;1?hJ(Sn`${{I&ZrWJqxpZTZUaWddT zM7c_<^$ir+TAzPBPG)S1`IDpkfQM!ix=0Xx%o?WK=N}W(g_xhR@#i1(JzL?|AHQQs zNnsff^Xrc~mRZ1@V>3_l>knv{@jO3RRBjPVEH9w^j@G>yUvfg-*3suM3td26LlVItzcRX^M2%6mZj|jR>xwb z=RZ(X=TcVK%v@(P)9l&D@Xwi=no)^QB&~1OUBAu$U{TGjtdnBiY%`mmJ{&5T#=*zm z1MfR>^ia=nSIG|*m88)q0#PDPwmGK*z>Fve#?qxr$uSp8WBkL`iH@YteWyo$o5jV? zIx(hOadBUcS&Tp7q9iYLn&WDzAo`fqOgE)iZgvV;Fx}S2{fI+XhQln9wXCw3X*taM zaij~1B&}&c-A^w#H}DynrU`@gw>a#4el{Ae2Hq}{ef4f5w8`?y0)o-Iq~9$3)#OO$iODyCb` z#d6D*$kKV@@T7V72}?(&rwoRfcQq`sh-o>@`;li^mQ&>2(?zwGvPwq*WqLaEu6TN$ zPZt$i%Q9We%{KE96q4g8D$dL^m##l@;`pQ`WqjBnX6@!KJDMXai5n%|T8Iryx6G?H znlP_}{jxjOdmOWl?dv&l&@874Cx&^=pMSP9F%stHXt*K)({FvRrFOD7Gd+@;Sr95>S7fECM)0Rs& z8M2Q#i-RR2r$x(&@fs!?$s9OhQxR{y;G$A3N>KAq1XVv`%yMRs*^TOij(?8Lz*;F- z>7e^Ie!N|&(`q>Ksrnhqtus1R90kQny8vAI*&Jtf<32*O;yX5@oGW|XxW2FLKGbvY z;E_GD^t1ogRsC6qrVN8w04rIck=bA~%XxjB1<+i?;n=-2U#epnq|Z5oWN>BV%3y)H zQ2zE>BpkMm4-7EL@=d13~cg5*u|fB1__>lv7JPL5Tr%RQ!b`9y zxz#54=rt2Z$!8@uX(%84wLH35yc^-^V3KEi^j{~Az6VE>f|xt{Zxcr!g8gbi%pLuA zd9+PD0{czO+|l1m9DNi=*9l_o=vxy<-v|5kf|xsce&Xn3u)jtSXSdlDm`#D%6qrqc z*%X*ff!P$8O@Y}Im`#D%6qrqc|9&a(p0kR&AAg(hw-|pR{GH1x>JRYuCH#FDe|O{W zCj4E2zb5>l{jdJ$m){lFdy-;hlbL4x{{Pe%?^r!Sr>)dOid(?Bg=Vzv!Z<@{0vUQ1^s_w*b^(NahH0Kf26&&}rz{xQ8ns z_V@Pm;r-ify>!@$*-MsF88fLX*A=hF@mh2^(FDB28s=f>+>H)-$7XoA?~d00$!XE+ zb#lgf#`u@4Q=EEo?d=J@04qhA(~Xxg{<1^I+C|S@35*Kfju2ZwKby;#ZaN-x`FJ?} z$R8`|ULi9!85Johldc)Z>IJcaS;yRi_d_%Tp<_eWF-@+$=fu&Yy@y>>?^Ww8r=(21 z3CRG9MVW4~GN+`?Wq)nN#J-Xmh>eZVt{!9{rtTc3h&qqQ|H97-h$Q2->{rY9eJkg$(;iW1w-bE)XfxN zx?R5kgVuwh>vscW;o`jwQB$n5tsld0zOl!Z zTbPK(_?r$bd9s|Se?Fib;$5mt7=e`Yp$CvjbA$)#S^WZs|91|J&fY z64F;3iZTRd0*2WC`U373I{$MfpxMX2U*;6~ZI!^UI&`ev+?_oM3x#JpSI|vLiAQvc zSs7o%X322v;m^PW+GN>~K`^5hWP!Q@PCIJnM@$(Pokmue!%W!B@*sCuX)pIBU%sM8`AbVtzM+jY7G10kg>yE9fcCPDQ-QBTy^VZef8^~wQ zGh>`O!)bF0%2$vc9E;~V>DehjAIwba739~gGu>poEJL(!=65*<>{etpXQ>To4OReE}Gu|-KlZqH;x|P7U_iFH)4ow*b`I3or8d;}-X`1EBALrFI*~=g6 z^7@uT$lAr_MV=^#5>+pVK4zHd7P+Zk4Sw4akclbv&4@+W_v!*p`|a8IcN{v_ZZ2N* zCTJlZBa~^x3Z`4U-sY>p?^-G{axxHRSrp@7ql-1*-xs?*F0^O^H(W?4F%H;y8u z<9iMvYd4pQrLd?#1%OHiG0JpH#firX-io_atG{na$RxCOaYr)CV>v8nqIb$SVi|K< z&&ofr{B%mlA|Jx>c~}vd-h&gXnQoDK8+DC8bO_1-n8l)&y`RHuw3%mC*BEtZS-ZLP zn~0pBwaS>&O20EM5;Fbhm1zQLM}>kIWxA!`M4@o6Yy7~WC_`W-V4VGLW?ByOew=qh zVfYX-v#LQ3tvlflt&`k}MFhte@gNC}8D+Xf>upsue&mppL6Gqx$!3dp>n>1J?1o9BcF~($s&zy#Mcc1Z(u&q^U2w z*QZ_@!1{fd`+wI4y#K$;r#_Cq#%hckc#luL7Jolqp{YmTjrsiN;=TVxKD8ZV05Wk+ zz2RLx_1rr#UI2fU7zgmhcAvTl@Be>}`Tvg^aIb6X&TXH4-wkO04^rz1n|=L1GxN^> zk$EInu`x%SY(VvhS}4RYb3cE?dr&%-zlJ6> z;}WsqTCPDYSg?Pgezk6^n=aVDSf}>HLj5wfmSc$)u;oJX#;kCi|B2~tNwJ@k8Jn9J^%*tc zu}5OWFq5PxevXavwL(~9h)g|ehg@3m`(x`YH%W5Vz>WjV5R*PHID~q+W20LdB`7~t ztpsH=xibaFe_@^D6qL1c>e-2NZ;s`Vf827=tS*~5Xsa$8Z~cjjj4UV#9Iv)@7KGSr z7L&>26%<@Hdb-UY^52TmpITbfps;VPc;3!Fc>@Brhk=gKK+_jem<=W#j z{%4juHw{uM9Ox*&;jvDZKU6gEk3SsBQ^{H`+*ByjVg<$1E!8X)8p4*Ra@JLa#uZ_t z6&Pn)4*6%=4YNPD&Mu6MDMK^|P&#FfqKC?{87>VoWBh+uE}b&63z1qaid9!6b2+yw z+;Yauea;#3mrIx!{|ho>lNwS}c7Rdap&T~_s_YQUn1|7acnBjy9h>1Z=U-c{>C9=?dG2SRJGp9)#(5;&ZO^Bs5joR87K(GTCs7_4(^0anC4vFEtXC3E3IeVMek5@X>)^4cmy ze{0Feq>!qzACPL4<^V_q^>XUFCAw8&Cz|se-ADTHecX`)d-c2z6aLN;ka|+ztay~O z@Ab?oo4FfLP3mIj;&1tYA6y=^c(*xVpJK;R&bvtd-k~Q?mhq!EJo4Q^EzDtbUbx3E zY{(J6X8gM8S}Ba=|FTqMBxNAXNJd#gXV%-yGmhl>e<-Tg${KA2l>LwNJhE-LcIY+2 zWL>NOXgQPdl4r@p)M25B`OE}Z#!qUu!cvC%huP`g(aj%T6ei?3ctV>LlmRdkGRWRH zFwF{rX`XRHj*ppgIX!C^bvH^R1sy=d^~?*vQmhKYvMd{vYXOe`t3%4# z&6WO6SSY-zsUo^y4ldmmp9SgFW1y6{5@BusVnL= z_4{c5-%_fne|@8--i`LZAAfr{l&Wu`?LUOE|4T3Ssb71=r{4ISPyN+e^a-5ssq^tS zve&2HjK5#6_NkA4&8N=68h|gwG&PC#{|~VS;O?lVj<@;L{e1xy4+ZsC1K%0B(UTOv z(#W1I^J}1Mww;${J)vrYi;J4 z7qS0cR4>6A^OZB5ER0{kYhun~CU_sOCr>s#x*tG~}68 zvGTj<$jrM7P8D$<^KP&T^$mBO=`AiDaA?c0n3-3@O7oa4HuH=xh|;2R3t8eK=5m{P zW{XRg71g?!{qJBVZD#k|S&_x1%N zigo5Nb(?v{`4=iGH=iXgE#S;1cNmwSVS12O_D!bhdtj-EN0|?SaY1xT)oIMx6mi5- z2EX9=qu)VS!$&gKa{dPq`c5$Udf7-KCRn^g{^ z5FNFiqqQzFGFqi@8svU#d!M%38$1v9h0sg8y+=;$KG>TVqdFHU6>oN^f2{|h=7}bbDwdn3Xarki0q29gSW_NFQTU*S~2n;k;nte}pvk&|ytg(FgFc`+Vvm^Z|VRq))x|pilkZ z*Z9;A;M@NewEy2g`~RB%jXr`WHMRF=m@nX8ed@_iYijg0eD{y`|H@zc)HlAVsoU`W z|8G9zQ}6L=>RVse)DM2pr_TLnpZbM8n!4(TKJ{ns_o=u4(x?98Y0M3vXli-8rhcl= zr>?*l0MS_@TEDmQFK+Ur#G7+%aY$_!vi;sTigo4tbY=@vIY%}=rp|0(da?fe+P(lY z#Edhmn2pS4rV=5SUS=sX#Eddqnchxv<7bvJgUl$il3Bw{^pVR}W?6>JL1u&*V^%V2 z&e732W|^@L<_cyYy&h(NmKeue0c-nIeIpoTR%OUs%d8$Hvxsa0!^}EnlW9(peKS*} z$n0e{GMkx-!S>7uGtSfo$-a~sVn&&j%qFJq6uBv5mNR3_DrPmap4rS)GOWccWrmrR z%sQsdY+-7nm-|?L5wj2gJdpa z#!P0(rk2^nRL+r&k6Fg_w{^m%sgoE^5u2GlgUqGOP@2qDOwTEH!&FAe9AVZleOa>6 zBVC}{M)WZ?W&^W@sdUm&jakNwFl*9eU(al1YNyC1$c!>;n2pSe3>_7tM4ef3j?5Y} z$W)TsVB=#(nN>`0itKAl_K{f_#CoPSNak{8m|4lJWi~Mr%#t*@)R;kLtZh4N5=YQ%y1 za-h;opl05W*j!JN7wlyWj^>BpJp8PcTYT^bF$n2x4f4Bh-h`*5F{U z6{&qPR2NFHXAQ8guS9Z~fi%;Ek5rK3`;no@9Lf<>8_pYJbmZAdL?SqvsKU{(^SlZi zY4+fVHWYe3G=#h|Gh_nBjMMkn@}2iU@o`jSQ^uMhF;!ht%RXO@nqQD~mj)&xuV zUoA|vd`cLnEURN<%ivnEs4;g$Mb*YSQayUDSXfJ0Z=I#X!aCMU#(MU^6WJn`HLy`5 zVK*vcCcUPFfdo8Qjcmf}6QxVg9$ZZ6i~=HeQ-sVwv<23PZSxSC%Fz4^6pRqOPr3T_rA;AUYH+$;=Y zH%uk2kIE*ea0FJ3m4rG%6QLvvXoO0f)mTGlBq(iwmrzCs6B>a4r)x;%tc{=oiCjf~ z%td-z*MS@%l_htor!IQ#MTj}JU`=3^rt zjea!oWdBDxKGgofj`xoZ4G(q=jy&G~c;c}$j}AQA^@#Gwz{BkiD-WH1PtSwV2YcQX zeb>OiX`}yv!~^~J4V*lCZ`VD_U1v`89Pc`+9PR2?`p+I2I-I^Ec}Mnk<97Y_%z@Ma zaUi`vxj%cGahrZyW?yQb*q822_Gb4Qd-c7UJ*honPkMK9cecmq(R(tfR7#}M-O29k zt;VhTt(jX=w}@NPyOO)IHybzWH)n22-6U>G-mg%rB;bm>5gPa zHfbdFWajGB)#B>(RmrQeR~lF9S7xqAT_LVWU!J@?dzo>Wep%+y)TQFm^d-qlvKJc{ z>lbHMrdEoT=@rQp*^7*e^oueVrY;m0rk5v|XWNZ-y*<;GY7=egWyxjPrN&ZyX=X_Z zOGu>`Cl_ZI8H@BqnF~@EhzrsSlMAy8j0O6F%>2}RF+V*oIWIfcn5)mt%t_4=bJDHJ z)@+N>qPJucsf0+R^`xF{Hk$S3Oj8Q;(54%cjoAjHL2t;^r|Lz0x-MCltu<=(+DuKV zM%1LMlhxTOqe`#JRHiVCdAcH5k&PR1J)ViBFz6>8O-8d3Bcew#;Z#_J)1hQ28#ID? zFjJmF$9cLeS(Ys|O7+rAAcanzv_I+3YKEq38D9zmm($*)H|sGxx+hbTLT^`EO{!VN zP;@0DQbLHGPrc)wo6-LNix%w2E!``O&fUCMF^blHKc19S({xiDl6buWfPw4m8yY`kBN-tnik7>&mroR>r$Z{=hT*yOe?gX zL&)la^+7zb?a5L`68yNf+j{9N&g-0Oge(Nxi1}={9K*7doYJFe2>(Fbu$(-fQ$y$65C5LzyhP2J&kc006^+fK>*>)41PIjx zolQ7e!^NB)b9nsQF9fSTQ=eWhE-r<`ddg6Hc9p`5MIJgb5mpcE=9ZHkg{3sKl0%^( z0P`!zR#q{{uU5Et8a|qp$?C!NVnu}9P+iS_b{WoItJZ7h_G)3G`_Zz7=+=TK>_g!=?8Oitu#1Y)6w ze8?pef*Z!U3u9z!zf;tZtsl0{X3MQFG?)GG!hT8RD3Ut=E);@zZ9@cimhd2;WeB4{ zIU!7l69PCDcLBO|*-M#ETtw%PzfYnyfmCO;8hwMP4wLQEd;;PjPe8~cM_s0|-~xDgor}v)l-=U1vD0o?=}d0klr!RV|^B;OPT` zI6zq!fS*()mIW$`gG(B4YNIn#n{e)uCOT4>sZ}XtTmW89lBo)OTvkKpO=M~v{F>iN zcJ?f+hc62~%Mz8RiRc71nm?MBY5?V z*d;^=F@k4sFST8t+D{*nHP!lig{5&jG$%qnoml)4b{1x4Ij*Q z9GtIcz=MMy}&i7T2> zzwzF0C8g4q5Z?wejOoZ z>=jc3xJoqhiZ`!`C@eTw9H{2ZT8hR=6oix7g`ve}M9!^6#RS(}rGF4*+avH?R}lKj z76iOf!Np%0?VC8yya^$uX8qJ^<6|Gb;TFgn8j;p7VpTVYr>9koE#j;K!KgLsf=^Oa z0!0-!j>%6T&pE|vQ5!@fJij(LNkA;;0=Hio|GaoOPC=-nxXx?&o-|nySiBsyirT!& z&16n>;waYxD_wPnN-3Day5Ss997~KSAwrB$ z&AX>yie~|u;5=G~OC(x>7~$o!-Asp*e?0c{;h%T?T>1IwpY{AK`m>Rr_Wv~T)96n| zejNSr(2qKPFm`76OxGFZ%<0jd(dg*NANK!Y;t$XK!N4D!`TofF`oGun`(xiZ`>mmG zjeK+LYwaVazdZ8B&}(O39{b|(7usL!c_I43$fx^1o%r;b=Leo|fBx*JluwO)a`=;7 zpX^U3(r2C?K;OsNr-q&y`dG)u#y&dy(f%hBPoDY6*oTHc)b%0dL#IDD@c#DqpB-u+ zIy*Qt*fBWvJHx*-_W1DQU5_h|pMI?8vFKwX@9Tfx@S|OiDvw4V9(kz$q3F9u9_)W` zV4!{AtTAMC7|Q*p@9ViQdf&*&{*#H5XWlXJj`nx-+#9`j00Cwe7Wunx5)t^+@GdMKsnQIg1oP#5RI9iJFAG8t#F~B@1dNCkF$9~?1!4Wii=3wt($JZO9MhwBc(g^WG?njo{P(ExhTe4rVx(9^9sa| z;yA%WuEI1Z^-yk5u}#VtZ*`H9qpl{T0xT6}x(%OnAHF=tMMn<1qNyN)h!ho+3Cbyt zU~S)UMNpJ-AM4z_{1!TFW!qeblst2pD1p(Osw&9i<4Tz3v=DAl()i+|#KWM%6Ne8R zIm~lx@aM(K&FyyKc`m|o!W#--J%`fA3^UyZ=Gi|ZocyEO`3^m)FUQoAUagfXG7%hrim3D3_5}_dd5Vlz4J_IO(Z{S{y2a~leoVX2Au0nQ$1Iav6AQ`U*ni)4 zHFgb{#e(?j4<62@ojuWyVxNp z17Id#jJ>a8%AnYPt&^oykbMCw=shJx+wr{VIVI!&xFhuLB?Pxnj4^A{GCna^IgGnd)SGOOsR zVB1iuqlb&j_sthMq~wV*s~Ta^CWwA!1=B67-sT6WD;%OS5b|C~a&uWoXPV}je>}Ca zsNMqBSjt>%Gfy+yjPZ*t8Rvj_Ir5(l|F*O8Tr!0QU8fOLiSsv_%&1Se4f{XT)0g*Y z!KG7ZPywsp%7{H#`8 zt>^gh-lK=}bS|GlhbrK)Ts52mO`F?1u;v^?eMgTRw=dafj9)Q@%Kw>J~f-t)Z1wN zKYRzU>C3~%U%F)*!_2>b}-{=$RV`5LfB~mVeTSr9f?LD^V z=z+fDM~*H6F=9WL7ZhPRNVRS{E5PE7(QwUBOz7 z^du*9h`A3Ez4+?Lu~`?g z-kM+Uq9$AO6KVn0i89@qzV5C04K6w|Rx1&oazQL*mNDHseCWQ)9X=N>cPvS}aSEl2 zp%E6uQf7#G5YN2blXUuc4VrG?V9)N}gD4IKVwJK`dnkna9OFc=%1$!xY3d zcl@5d-pRDCnL_JQs5A&-oLSFw(+U{0=mcqXQp?8P%hy?oFL7ghtBbBo)(PDJD@K{qPu5Ns9ht0GAZC?<7+_W~-QriyB}T^2 zm!=!)3F)mZMzo}eHKaI8>f(52VW}%v7A}Kd>fMPiF?x&lItN>Er{jJ zDyExcnL*Phax5qAqlM+@<|#yJ(g6CTl|+d&NK&BePM)-yLGO21^uXT9^KzF%5Wew- zsUy&cra}C~o0yxyazUgei;m+PZO4YogpkAhqDKx-vf%wK4n-LPvm+jqQXn?ftGV;3qJkS(q?5VXW~QbHwStkm_RTP-yE=Bf=jd@%EOhqUd^nx& zDJry`J->l@z0E9_(D2%2(6lmNZ63SVp)$VPp(0O{C2|jV|JEEc{iyxln)#Kv!z_Nu>@AusO`ITY%q2GS%r2SnUWb?rrOfg> zV4+|YHX=1Q%b0FiZua?8mRmJCndvyw%Jh8>K^Xuu(}V1NLjm^*o&Q-U!#m!Pkkn?| z*UgVg$KBwzqDsxIaUpY=%}g_g^x-M#y!Dt<-yJyIcjCC!yv~;!-|vu|S>XPt~d@K(I8a92^O78YqQpnRGZ-i}?LrsH=zlw|mj zjxZ{M7T8q8x0zoBD+ST*jdP`eFN%4|(^cI^dv7~%3~&F;B%S2)yT>6dgJPyLk=m%n=G8)#hxNYnZFN~31YWZJYlqNhBe}X zN~hVtEv$W=bO_1-$T|agKbJ-9l;y=bS&E`)Qd@JMtSU@a3md=Bp(sz5QTzcc6!Bx` z55ZDFbc>=jE{CGXeXoTvyx*ZG_01TTv+r{X_}j$r0f!=j&zp?lPqC+nUod|LmIacI?=(cH0)T9+q6S?`AA1aLZDx!g8e!)1r3$a@~I5$i96j1UP6KCKiu@qi%YO zv{*MEv-C1);pI9fWNRxOSuoG$(Zb8$^@*SwU8<=cy-!mYU=6@i@6*()(Dwg6+Wt3V z{lCA%yZ?JGz?}ben)>9wVXl9S0eI;(P2KoupZce-`qVov*3{qpi%dlLeFw8{>siaOwy!EIr0&UVo) zu$u3S>1vbL&T)P5M0^+P6r_dZg;h}A=LnMwWAUOW3yO8J44PpU#r%Tu*o+ip4m#^p zMRM@*841Z8be70TbMSW@5;Ed42WeTBZGsrEaj($%pLA{gat>Z7*5v2l=C$2Bav4bP zD2wOcpd&;wg#YLAZ)ipeGswU9&q!z*`6tFd;E<3xA|LO63kya31M}~|h#-XjLj zg`2C5x;@=L=unlRF!LzJ8W$8$Uia3?2nTO(tJeJ?hoU@L#`9lcfd!@DO5u5FqfDA! z__j#~FGV??xpo?A-WaRdLt|I+SE%{0Lsf>tjAxuR<`i&74YenVO3i1HE18$t%*W8t zdjKQooHrFOzop}~4yZ4Z4f!3P;~#Md+ESF$auKKHGA4cVP%4OS?ca&-3s#{abKrPk zjqpjFO`Gh1llo>_mb34T1)M=z8si_eq#V6)7^On@M1@nUnHgX$9ou(o>*(yJ7p2y7XZ&L>qH@$VJ-K7fS7g&3-TTxOD)iX??WS87 z;~#g?kYn*FSzEY^)5i=mXI?Ts;n0)%X32=M?>ZC01)FuUv^OTcx8j$#WN-F*jz8_t zk*COb`C)MtdRD2766=_5@tRhTPud|ZgJMRpfrS<^WuWZ8Z##d@^M6PIvwpUHbFxUkS-Xx{K6D6G<>}R&%yl7l-Zqci7^T0DBokp_u{h#>oWtV8<+iW zJdU~kvG(7uG57x<{uVrjHTy9C|IL{H|JNA%|M0*2RQ*xR@&AUVUWqjTzK?bP4s1l5 z{s7kayFpW1G5-H0jQw9#t*Jjj+rMX@rvBqx^cVDE{lFDI^+mM(ubJahUvCYl*InpS z{}<-}f3yXDcLdZAwqw14A)oqny!+p+qy3M+kG{6)&6Fo8{(7Dn;LA`-{l;$`p;xWc z%d<9kFPUdYJ4S&`5er=5P(2 zRaod`3n575u9#$my)^UBI>#VS;45Hmrna?{`+=8yF4S}uV`n-YS1c_L z_E1R7Nf25nK`0#9PzI7Y?+eNRxu}3|5riR$z~r_$R+#+opVguf0lSIK@}80e=bGWx z$>5>*NOk<;5W+*@M;YL=%v0eQo2BVjj5XNP&Fe@fAN)z7>l_MXs7OkeI0AQUFGPk< zSJb2dOEU~Gbiy_wj+X9!Cq_&_g0$&R)a%6P09_Y!CeHAX*Ji45py4iwGC=M`1)l_{ z@FyyCKX(iHQO2Sa1%p$}5RoKhLXyrX(eYG?bn0|iu$AF`SSXul&mX~hB2)$xMMOy5 zNG8eNfZ3olGbog}KSy*rN=abfOfPYEQs_n!M>x7VokQ|4@Wy2TCi{H=nQPq#$dgqD z^@W%lC4<4n$g09J&;oBLASeUL2uwz$ARRuLf(T#DG&jotEGmR}FNKWa;Ys3>gA*vi zCi0BICvq7`!rt#Od1*^y*Z zk^~SQo%cEwLl>T-oA#^XVOUTZ(90<>_>vpR5gn)z?}T><8mT>+Oa|yappa8|(~zWr znZjcT$}oe%_Y6*p=w{$_x(`qp@Ea%ta2vDk1Md_l11&y}9!csXhC~3+#>aiY5I6}Q zb<{iv5tIQO5k_VW{o;9v;vmZa##193sT}?{+bH?}-`F^F|KAAef3;Bl7f<>`-c?Um zgr@~J17ji^4dM3)-Mm@ho}%!RA}NpK4DREBH#$8m#Oe&Z;Qw@|!C^dOsS;$~fXG$e z#&;~-jbLfuhNa_o6}SMue7}Py223705j8jRki1IbAeqcf_e3(uI=SZ;ZIQ@FJaCgF zD@4XHOoLynS&cB3P(4&kQJSvdi=iCUUKQx z$wr^kA`;{+!tOyO#PSk)DXd;6L#x7Nf&)*-;gk{wC(*`_X*@s-+R@>M%m-B@*L1+n zfF1rv@XOCam?`AsCvS5iReJR3!ms-yaN{wsXKo4nkXN=%huN6e zhcT}V@R8)iahP&}fO(a9#PSmX;4%P9D@}Csc#cUn86f@X_#@vaaX9QU?f4LUv$mu( z$lqkr9tchg%T4YiDvN7Y@h-PTL7$@v#X1gu zRLe`0fh1xg<3XX6eps2q5x2ah*yBl`+a`=j*cn#%*cSfNE`D+`pTnAb6h~|aXeWt` zpv|uXC~S`x;{@On`{5y5(>IaZ^qgtJU|2?( zF%*7mqzvgKtS64>Nmv>bXfj~S7l9| zyG9qORl3-f)R9bH(SP8Hzv{tFar=DpjKc5#-};QDJP|h2sqAs5FXgYpP(*r-NQ^OQ zX!>EiqH$~nUWpo;#l|gL)^6+W*s=B61q(V?t?pjEb<2*mH|*$M-O;Hp(di?riSZTI zv>po=>dPEQdX67Cv~VFQSiQiXbqT6`lSH4vD`F>;3PG5Q!d-aHLT{5Cn_+%Md)I-Z zz4RU$UkU6vg1`MeN9k<~r?)A4{&Nml84TIUO;XJ)RmU{VyD^p+D|9$A79AG`Eg!l2 z#J+vKM`?}sOYl}TZ;AKwFBa8nVT}dMc{cMNK@+s-C~0|{Va~|7r>Bo!km3P*mqiR#?mIu$ifEZh9Xkjh}J|$q=G=JV*uO zdRQp%lz0OeVs>NB#okF~vIrUU{kT;uXl^^CU%^|((+)`)1hZ&FSfH6%XEV>dXne7# zUJGk1WX`jhkKqcq7m;)p4G-rTU5?JO@lsKpCG7X*1)O%-82^$($ChQdZ7Q5C3NPWT zAe*SGnAnZC1CxCc95)B^(bRw#2fF7DED7t9Z!bG^WjM@y!)L`%S-_lUGw(r}yj$o9 zSKfw8jK1gCbNp`WUgo#}UMVWJm<29puC$qDA#rBf)c229i|XMafzYpIuCkeBA#q;V zu7za$HHVH&6kKmGD%6<*{)G7m7!^dfmvZKd{cgPTUfpfW!GcTfb%&}9g_(76)@WkZ z+sxf4N|brl$p{B;hR2{8DY}t&^s*g4I=irLk#7{$O0fS6nR9LCJ}A-r7tWkBKaA<4 zr;YP^``w~Ki`nywnagcvSwx&!=Hv2cK4SQ7e*W|2&7xwLu|Nm&Dw|oB508~})(=vU zZv2znM8?1D(2*y~@X5zoIyfRRfqY zuuKr$@@rzw#ns(=4jwr+$+zFXhtp}3RZkfJGslALeGRkHW}Zoo8RK8Gw9r?Xx5;WQ z?y^VThpa>DeOjG9|`D5Q` zGz7Guvw7{7HOuLc6`k)+Au};oSO5~#S|+}o=v=sbg-z%8r_iDK#;d3yjpz`~xyR`# zOwUHgX3(I0%!RV!#?H0f$e#TkNQc>|91)gM)B_d0LB0)`2EOJK6QSBrjFdZxz~)XOji;0KuhZ?{)d zfAu4udf$VZT8X&;Uc}sgSC(K7f#sUogK+@=Hh}K}@cn;_qN$(l!~B1zO4ZoM@6YV^ zq{IVD5LUTmb_zKHpb;yS(3;Q07N&BJ%s!^hY+-s)WyE^p%n&oqtYS7Yo0&?4TzZ+M z%n&omY-M^o$&H^`#tbr}%t~erGtoybTbX4UG6$IvW{g?MtT{(V>zHN6I+!b%f%JNq z{aGSSmV#Bau`~+&VOC|xT+6H;C9{ZZ0>jKYW|L`7l6^B%q{!@LHZq%;ioy2G2s6&q z2FbpZ8Dd76mCPol?-aQyW0o^x%qnIzv!2<^R5Gl^EMm-|?L5wj2gJdpa#!P0(rk2^nRL+r&k6Fg_ zw{^m%sgoE^5u2GlgUqGOP@2qDOwTEH!&FAe9AVZleOa>6BVC}{M)WZ?W&^W@sdUm& zjakNwFl*9eU(al1YNyC1$c!>;n2pSe3>_7tM4ef3j?5Y}$W)TsVB=#(nN>`0itKAl z_K{f_#CoPSNak{8m|4lJWi~Mr%#t*@)R;kL3@cBs?MpC~B$<6oKQr1#Ho_p5FzcBO zCL=pw@4<>oD4EQ1W{6qKj3nu3lo?~jnH9_`W(~8BSHZq%-l@XM>er*l?qeWR2 zMO4EoT-QnKnqwU;wyMWoxRs#v0o7ToqHeC0UJqlqiQq-pHLOX-CsbsygB1;VrxH8i zDnd0u9mE1ySci;{#YVA0w<%HuW4Ml>A!uPgA(+ClSXi&obc>yEEy33ZLjS9|R(VI)d*M(9}lhTW6(0Fo|elxjdE%VJGl38&v`Oxt60EJm!5^ z$jeN)+6Yn+t9hBHU?&h@V-!Zj0%#yh)5}Vns$qRNc2Q0TV}#O9pqvmQLIZMo?1l z&Rj{;17o;>g7B=BT52C$)b*hZmvTrOU<~U7kG_?bhqo4H)UX%y0@kXFe%h}aq>Kw# zOY1hFKqG_9a^6g(yD|;;SiG5iuEI{ZnovWiCDak>2@Qlm1}Gy02_XWldmoMwDhXAD zIzm06iJ%iovVfPM5gO0YwMb|t=!68Jh0sb65d<+xh!ZLaRfHNs9ifrXL{QoQmEa|4 zgfc>q5GFJN0W#>4WWV1OlTp{G<{(YAwUQd zDhSTK>{o`q((#qCFAsmY>&wcQPrupoX7tUG-yM0Q|Bb{OXI>w8z5VsGueHB+_SKomNhtKGkz7 zdTQhg{a;9Y;mqd;KHvWNvo8+4*zw}n=Y~Jm^*QBpr$5{C+306SKGXl1#Amu*P+n;N zbl3CB^Igv=&m}%}=GlQ~&wO&=lc%5QdFJ$R&v0~jByFuT_jLQyXFoCYiII=@e|+Sr z{-=gN*7dQ0kG6mG?32+aM?TX3k;F&NJTdS@`x9qBJoMp?4^ON=*Ym;X2S+~8|AFE6 zj|~kEbqx&~Fr z(0v{Ejh*Z`+5e8jJI>rYaPR4R&fYzAcgNjBcXiw~cIWV&BPaS#B#&p08OQWvnWL$r z;%K@**`Mt*`t-ickrXD_PajSm&K@!j>4!20Q}_%beMj<+?Cr+w`t6wmsRQCbdVg|% z_BP`-{kF`$6y7eTdy~D{y~bXBZ)Q(wkJyvmo!p)6F?#f#Oe&QUsdRU;JA12ftA1CR+lcB`>f-1bdU0}b zc9F42UzE8Zb%D4by)d~jyTDkWFUZVK%@_02^OEzjbB($B+{~QR95E-|nrzLs7%h5B zCXq^rL|RYk*=D0zZ_YHOnnY8&G1-`HFdFoROns_e)Tir`b=g{@Rvw5!d6HSPD}*rlZMdHey8dNG6;Li*P!W3}u5xP!DFxQ&{dG zU6w4%mKvpcX(o_DA6D9*^k+3g)3uB*g{gzn-lR9{F+92_QnC#+{nH7tTUL5%=DLK&eUi>2*LBkM&l zL5Oz(b%Z8D3qeT%K|+MkOo;aZ)r2~NItbM38)z|3Kqu6W0-D$;g5`uLp^{KXP*Z?L z2m*Owts&b+LV{4z2l!IEgqK#NwU!w@)k}{CpfR$~JbU6`m0n=w&ukPW8&HpX(yGY? zU=a?Cu7xdby#cE#Q<+_lJ1jjuy#yaYBa{=W@O-oCb^&9<#N#|nVKb{3F&N7#2{nXz zf-*=Zta$3BrEaa~Dt5z7gl0k`5HRZofm7H|VBd#zP|at&AS;ES5=sa)c&J;8Tl*t; z>;`MCC8wh}Kvkh<_$ga2@bIf1T|?1KSl;<5+eHRQ2&Al_N&nuB7A)udssjshV~Y%9Ihg0Mz7GGkt?BN2Xz7?;Y?1YrOwp@E;#ojV+-n??m8fVLbQ zKg+k81U;*p=~f+sAHhMFhZyx)Dp_hb<)DqC#~C!5BK#Fv$I0M!z>WPGdU2! z(<@MiM^>O_6!3_RBH$yG5h8?ILUSjOAcz#;C6p1W2@M3Dp!NY8p_C9L#0a&0X!A4> znh7n05`#j7TPT)z=a^}*2*=X6dA1PhsPW~Gpf#jL)}txTZUQg{D+x7(CPJtah!A3g zYCgtv!0b=Z$+b5E*I`1O&_GZ-fpS6|;R#m|DhXAD z20}?6pb;VjA1SpG1l2_pLJgsg&_b9)@ECxP;3sIKK$wD63N;Pun=2Ta0S|+5bVmkb z>0K~ouo`-J6i`sP40;F}fE&2ACOXb3C0isgvVc&M=|LhB0)%oxm=GgW5^4yg`fi*? zh!En0Dnc!xf#7QcLYcj&fS8q*ILzS)t_^P>S7FlW30jV;#A;GUuEX-UrQW2VGr5hBH_cHNSE*?5H+(Z7R4@F`#>$BybVa41EMflkLub^7|pAy z2}YzZE^G3_^wCc)%}zgGCko4u)df;HijrPMs3!Qb$VdMvWJr*5g%+EqgrzjFr!=RQ z-GWojZo#Q&x8M}DTX5>yEjXp^7M$vK3wsXOGs1FXS^X!DPK* z8+!HZD`PJYzdZJ(jxUY9H2hN6OUg^9zc_Mw?9}l8$KHE~IdNra+*OKom8;dQ?p7z2 z1P&N5GML~16d6otfw7Ijh60*k6S_!F*j71U8z;&E8%GM;INQj1l8q*(ouNEoXLe_I z(d_K(>`qu~XEx4^`ObT#>K1~gZSQ=~_s=IDetqh;x=vN;R;lXTbKZN%e!cvf{F?Tv z{HpSb-4~^>Uo>9KzF2y}d_jGo{Jix%;uVF1+ClkX@j3lD<+<3i#b@+qlxOS%#)0gC zl9jbe`_298{_@k-)48X`rwdPMPsu!Tp*(3nVLXw2qV%}=xcYecG3&A1W8!0leOfh& zQG7&yM0v#CYwXSLEj?^LTzp7>NO{P9(0DNWVCez#0ks;%5Y56KZI8UCc)xzXa=(3_ zabNbn(!J)r>b>QAtb20zi1*~~7Vj?X)^^Lgi+2_7)b5n;EZ(8tq1<8bGInKmm2Njb zL1e?c*}5rrlXz3%M(sxV#^O$Wr?NA5gLp&XdhL4o`r>u^b;h;!HT!q;QcNSZ^{9TR zH@~@iQ)=T!S0BD=&-xYXMy(ar99g}8Rqx8lT5QG9D-T_fU)H@eb@@jWYuIziip3P8 zTy%sY3cU*^&yUSJdeNad`Ptdo!mPqfZKgc4I76SI%&?~$)3eh{)68k=wDMGIYHq4H zwJ=4SB2Ou*x~i!5WMgu6a%qw|Nu5-lXidybOkHSSU|f*Bpme@@zIuN7JoP+tf;yo* z-Wp#Rr;Rhms$=zYjWOov73Yk~3ZssUG)87emPW`Uio^Bc%5eKEJHXgWpzNeSZ*FRL3i{2w-KJ za!dmx2m`sI^v-;wx?9}~D79qz!rCmBBZD|g(5jng&)^Jf;2g*qsvm+?XCyT=cP#yd zvs?Bcp0M{#{LPHBf%B7iqMaH)uEx`cgLrD8_a^8NVxPb`=Rlt7GIO$H$Je;}!62?$ zxhs$fV4U-lxKbA`RF_PsarMJNT%lmENdOtA%sG%NCa}Iwic-R|wFzNA8pIP7Vbc)< z8D}HsK%Q`3^>sjX>P6G1WovVremsb?4sz2ffQ+*;d$N;aOwF~g>Pg(q)2J#Zajmbv z9>iBCt*cc48E2exAYYY^QSrr3;@T{Gn~wn zR$6=I_{Tw<4dc#0CV&l`135!S3{?-~^!bbDWos`SzZk?7#%GcO$T$<61G%DdqkOFD zYS9dw&a`K>w>AGXh`Zt39moVQ!THJEQD$@P<>QxwxI^~o7y)FQjhq9ytNqj#RX(-a z%f~+t;%p>$1~LI`rOt=r)0r0&U*SOk^l=6_odQX$qUM#aR2iLY=C))1I*22jh)e)|oDwId z6I?B%YJ6~$s@_nNK(lWiU(A$0_Uk$~&R;sm3>{VEGrmd!>>#H`ncPoSm>LL40oeRgMbI8y+!+eHiA7^Fe<$)@J{kU%uPzk)8Pr01pYv-==$9_A2E4Sb$ zCoVp@vWu>^$G?^f%c=f%)A5azU|vxqUA}z#CP;p-rl0FKZ(2TT)Tjx|`|s3*W526& z>TE=1|J;0%WtlTp!>vM!|Eu$w7x^c(wIU_U*IeDVe;dF}W#-pfHFTRy59ZK z06v^u!FOn*09Iyou5dlykyPEDpv;)QKZNxgHg8&s|Hpk&-=1vo+ob!q;x(V^PxE}Phbiwrb%o#cHqHCD@B*Lf*Oc>r%i}&* zCusl{{>JB;M*n|A+W%|l{~t;7@4lZ<-ah63zeRKZ&H4t-`A2#GTMqhMUYY~o(I5F- zBi<$*L7MmPlDBAGZ_<2%U-7vbNdNzZ15^V*a{zo;@VVAmKG(;j|8J7^|7nLv|8Ip$ zxb%AM<{r-q;az-VIh8NCb>V!B`BGWw4H<@|fT6k@ih`yzsu`qA1{^X39E!>Y=`doQ$N+eD5F8Z(vtjU@2sj#Pb<&s^c&-eNZ2-r`!SRjYgeLI31bBWkctHzzVJkQ> z2~KJQC$|%wPebiM)09qdY8N;S903rsm$-OvE; zjDt5ef;TmRHz&Y+Gtt=%qXkX3w1T%L!Q0xv+uOli9pD|E;GGzYlkQ4^yA|;6G;$^sDSjKAAAVKG19{f+#3KNL7|NFXb9YgavABd2>5su zd?E%ui2@qwsRr=rIJm!&=Z7=wa4}8}Tz9)g7W8mil;1`167enBe z!r=Q6@PjCLI7W1KqbQ^4%MIXH;^0>s!LK!eUr&JFXa>L80)DF%{B{!jP8;~$cJQw{ z!0&Z}-|qsCq(EB%KTLx^$bdf-^28sB;E!G4Ut_#d`iTepsTcekjP^)>i(yOYXA<~# z4E*~5_zywwXo%?SMk$P@pGUxdjDo+2f&V0fzia^iIS&4+5&V}X@Lv<)ubaW&w1B^D z1%HjwYm0srI$|Lg-l z_JhYHqF)pk{iyDTCBR z5M!;NoCF)%z<4{@*a0?mf{8A$IR&;TU~3voX23S#FtJ?(J6vF=8|?CcDKF944FzN3 zQrZt@Byb1=hX%mYg5c>P@Qg5cW&|7-1K#V(-b#2)dNoR zg42EA3_mzi0%tLBb^x3c1TPAKbHm`g2sl3qE{K8MGMH-s7skOwjo`&i;Nk>$Ni%q9 z3wT*8xFiW)-Ucph2bXn#S9F3`c7e-N;0lH4?1q*`)5;9EN<2zj?E-t;;2ICO)(ful zf$RO?RT6kL12+V~jX`iz2;3Y7dn2G81-Hb&tunZ+0o)!3cQk_6G=bM9!0Vd9>s!DZ zTEU%3@WwXqrgre=4lv(Ibaun&LeniN@Ky!9Ee+l-d_>$Of_J#UJKf-29&oo8yxRxf z;|K4R!21|@e*oMQ1kDimKp1>50zMQ4AC7^0W$=*(@X-(cXI0r0IL_;v_bIzd)4$+aWzkrA>1pF><>?}gq>E2kPpVIrXdGR6 zqWHM>xcIpBm`Zg3#y*8A0klWON3BOxssk|gDto&hEGl%)}L{XzM`!UH)PKR3;+ zY46c#^t^C?j%oo+8aub|)$f(>Ezrn$`EK*>EY$?)G;&_J>*$@voeGVdYj=ouSi4jj zH#crqZZF=ZQ9Xclt9onc7K5q*iiT#0hLu&@%4*V{B=E?-x;Hg|3L8uOa$HTDjDhrFY(J-5BQ&D@sVW^dKE%3BLta$Cx}sb_V& zSLn4itD8%kj7`d>;zn(wxY636ZYW)CT&-MPyh^)Dyvkayt}m@K)+y_XYqhoFT5FBE zrqpBfC_Tm1+Uh;4lvTx*+DdVyrKwtJg|R|eQCzMq7nfUCs#lh-Fs@LpC@#~MiOZ~| z>eABX#^uW8#UNU*XPUg3-faG%5%-R*}3*bI#mOxb4s&~*~;wVENzxJ%bKaqEX^=z zT)#M7n=VebXjH#6)tIVGEz+32IK@&`wL~NO%H-lCZIU=?)I|G2{X+S|!Ueet$~2yz zJ>Nc0KTkfdFd;`H`sVoTczc{aP99enn;Tm`*E~0Su02K{BabPJ&W$dgW1e$3t7XNk zHA)>-I@>r~IlDMg8!3*oMyMl7!wnkkFP^2HC7xvsQ-_t#G|p6Lyk9#*Ji|I&rO|%l zH08AJq2(dwkn9jUqi19q>CdIhim7C2tY1&bsX|w-tK4aJW;<;f@s~Ra?Kv9rH`}sp zc2ZBu$wKSV7K6t8i_KcI*lZ=#M5)PWQksf1?k_f4aW!6QFdCGGqO8fHY{k@ADQZNO zXfdKu7JwC2!@VInR0!sR<$xK;QXYWLWLA)Jlm%e=vwqvBQw~7EoAZ`ECS?HFZrv@r z3pD;;7ELiL+H{8hbms3rzlNUwU#ZRiUolJgb#4Yf|GVgt;9OOHgQ76$w+i^XH27~B z@FQd+N@XEW{C5%jy$k$<8~hIs_@7?zzkJ|-`@#Q_!2f079|Pc@P?RtIIRt(j29HIE zBvcT^f*1o`GU#pqJ#o;BDt^h=1o{)8)C{r~FwhDHlf>$NxI%4c3b%ui4lvpY#=1Z` z1vV&PJPkGqdx%XUm~es3Zm`7zwtB&&4{Y;;?Go6*z|H{J6$DcuPzi(S2$+e2Lt@}i z89c24JUtGc(FmT|1P)7pXEhU@-5B12rV*{+$Rv1n8#t;R%yxk1bb_P1z%eQCTm>AP z2FGQ<@xoE!1Q9&X1)lE)FYtgDdclc4aFQRKEP*Nmrv$*ML2z0KoQ}jsX+{K`83kv> zz}Yf5rvbbuPIPu-ZX=rJA=y!yp8yv$gWWA)t`%IE1Q)e|7o*TbTHFC%(g|ML1zv_6 zNok1!UY-V*X24}aY$n}Iir|$laJd^?;Q=)yRZ1&;;40*eN~wNL_)6gya#;23%-c#TrdN@-E4>y3Uq||`bO_Z)QXvAqfm~kc zO_U-@Z^_`>4d6S-q?O)9Dy{S$a%rW{A(>YCd^7lk7VwL$;Fpr%`)%L{$hDOYcYsAC z2uoi^eUtQ+6!=vI{2FqGrLSkeZ-~9bZ@R#5xxsIH!0&j8&Tf3yho-+m@~-qf3H&}X zj-?|3&<=thBK=tUK^XiY5^|*BMF|_1`cZn&*~sLyD_{IO(VL%kty(O1ss(Ivl;Ll z@epye3moGH&-H*~z2G<>INlFVkihd8czyu9AP8O<0w;#SNfB^z6jWp26d9b_08Wd8 z(;LAVP2kJ~II9_)-2%>O1usexo!yw*hNgM#;QS77K_}SV1?E!VLIqru1~1Nli-jY^ zOGNNe7kHT)T;c&Q_kv4(;4(jWg#=#7z~upOMG(|N;L0$#Dgv&Kf;};CjSQ}B0N2IA z^^M?FP2klDqO%(tn$fhe1>DpMZcc)|ZJ^!`Zs`EGc7ofw!0jn;hXP)c2Co&460bwC zhIG9Pyul6b^nf>d!JCjdF5T=0^AJ3e3P>H|}Xf)4eEsl{!v*akk-4nEug?(GC0=>i{3f%_Eju{8L2 z2BgUmXVDjj3w+8AKJ5YbdqE3D6w(1d_>2TT%fROX;K3mHd8nI6!=92 z{8AcxKLdU+1UxLHh(!_nvJ3o*8~myV{F)d1I!ZUBZ}`D)O5nE``0W7rogmTKjqirg z^jBfc_>Sn^!n@a>yxSW-*{DdwfKrgmH*bu>dU2<466GtzNk^QMIkph51`SjW|;xpEPBbIK-R$+gRa_LP{0I;9ZDU-hNWbVoG z6DH-++mGvy%a0c*i@v0-Rj*X(gaW_bN-_{%{#Mq+LSpj z-%;3=+f}B#`RwiXZTf98=>gx}D^>x$QE*NWF#qzF*jVeC*y6F}Q8Znw6n+e%xFt;*Ko7Hx~T z#nM&1)Enz9Y|d>iZ!$M!H`yEYjq=9AhTMkor+EI)uCiC^E9I31EvJ=Nm@Bd??B)7$ zd3oW=+?C}k%qy~2*vs@~^0LCx+|u&p=H=PT?IrpWc}d~2+-2oUQVndIW4vKb4wQ)l+mA? zQ=V;7R=+(sS?Vw-T4wIg~&jugVVaGt6Fia{+X2CaY^C{Z1N!itjiDW3nY zzcJsvmY)BwuYLYMv{Lxu(bfC{fXF75Zw08{{rSjE5ryigP#?c9+=epo2E1JKUleHq zk{Lo%XSn_NR?lQ=O&#Bch-dUBD&(X3V=AJqT~B3I2%FLyc2-=`Tc`#Sp13RgBzJzi z=K!sw_IK3oJ#@Jcs*1~a$d1q!@1|8`$lJ~csohkibG*G&O&Fkt-Tc>1GveoNY!R(0 z(G8ni?5oy9wo*eBcT&+N6vDMpnH&{wWh%8|N2c=ydi&E`OWe;eL7$u2g zYp95k{}qN%;#6Tq+knG5w6ZE%Z~Oo^#r!Ox75BBQvWzd*D6Z91noYpyil06e`co27 zA_l4|4UPHL_}I|McfPVizC9;xr7F1--^)(g8aipKeA3p&x>kN5D|^c580|xmU4x5W zIMz*{=FRR=J;!bFDc3CE7@2fraENarw>u-d{iDfZkpTT1&X05A2o(uBS_f__0u1|r zFcsHI^hs6}6%a|Hvf8KVFR4P1nkz?qCk``T3sO7W6%*rzRLV+4vJ$B_uy(4E^w2gO zsIJOY`6Lvqh-!MUqJ0sQHt@y1qf$LCpY)C5Dc;DtelM+`_JbdBT6guhH-5H1!+3!Q zy^im9>Im;am2QaB<-|`JpRw}E-quw4bO&2oh)zL?f1s5LX^bCYlb(*`__kKb zd#QuaLFU_vA;)mvk*2M}=wtNw6R>eV364}Rc>IsNbg~7UT1@(o;iqy!A}=S5td=lh zV`1EILESM}#)o;B0pzyI)}~(T$Aa;!i65+EqKxA z0rwt)7iip1ND$~sszeUbfv#*tBvw5& zYMMr!&=fndso}(?#uJ;GdRL+znO{FDJ(V^gjx;oP3ne7gi-T^xNq`2A;RBU`L0yx#3ALD zO2?7tmtKHd@eNNGeg38twZ^;f&J6EqrX!FC zj|$rHZN0Br(k*^8SCE6`Dij$`TT)qt7@H#mad%QF)b?PpVkQq?Bm|$W{%s>Xg^pZA zotAq>M9M?`8`u2GwFwXJG9I?%G#y&Gla8v4G5)@H(K%6j>B2aF8wT~;kgpM~90=q# z;55LAKzohUg?1!PkUpNm{fg8QMb<+UsSKpZLiY_#Kyt+#!CkwzKH6K7446Zgy8gYD zsIjT_2z`d=WYvovE#khavSTS)YEIFgF|)5NLyPe^9XM7Ip~%pYVa|~W(2US6*Ku>c% z;dBhQPPB%~r3N=?m44MmZLJt=IPPn~L#{paVYwm|A&DR@lL8~53qT%L6lqvdFa3Gc z2S`Wgs4^f%8xWNNk=_i4xZR~=%|8)0wYB;H&(AP*`S z5oQa);3xv4vnnV9NkF8H@K$9ps8a?i7f$LA)EkhM>OO}%#Yi1P%#tC>=Lz#Wb$Sa@ zQ$5uV={^jXM+g{53Sz7#h!K`xS8S#bMEE-x=p`Ux8blx{$a-hdF8~FI(=G>FdNo=B zpwOoIs_FzT+KDg{oWjUv3X2~RkiHT|u1XjIH*e)Mb_ujUmHXL>u7RH#WF(`~9LYS?mZ{lZIH^1km8(4l^k!K{+w^Gd#npS)$f2i2S@0s6Kzgzx}^_|>z#P1Zo zt$kbmcJW*Kx0G+$-!#6N{igB_{p-rt?XMYM%YLo&Rr9O%SB$S@zf$_L`DOLX<)T&0 z6~$uVuy$BJT>L=)K%pEA`TgvdN|b+5`a-_~qxqitUin>%VlU#mg?CDCn{TUci*FU) z)ZUaS??Qh=dBZLkg)C)Wn1{^Qp|}XGMeF6<%i_z0mo&<^D88t_sJv*uU{JG|yQ zrGw@{lcFs;S1y2RLC(_l%ll=@uqZrfQC@{fIThJ`xknv6Me*UnLynfB@}T{I@j$`U z%-kN8GAP9RlzYo}%Xf>rvv;a@h`S26Yq!gkC1Kxc+-lvDyG1n)J*hn@bKOSei5z8Y z$d6SN55z|bd$qmt-XcY5$`4w!Ugd$TncY+3ng+RhMOv>#ItB)57(kOz*(Kht-=^?2 zXDR!_yhXjGY*Q;EuI?g z5C$qWX{D;v9VahvIj&mc_jP`&?x~{2O{OSZ$T@{5aXZ4fidSoFbKdOy%+quj^l#PX zP1|~|<-e`&-5=__I9{E-n@DSj3LxW*a5@w9IIFMz%-2rTv#L5%AbwYM_8)^dn?!F7 z2%wLXaXJ(AU_~{ryeH3SqfR!l(ti%(XELoOB!E87Am=73NZLr9x9&wdg_4?0+c&Q4 z!5nurAChqFzXtK7(#m83jMY#R2I?HxqZ8){%pd#j0sK@-cWB!2K0l1xA(BgP2DT+&9~F6I?GpU+ce(a#HDp}=3G(Z`j2(4ot2$kJ)^LP)403yI45%sG)0d; zPkN?8byl>k+qP_9wJn9&w1{meb1_;T-7L2B^06lrw$( zxz3&AzA|rAjITVw=^TREpVdEhn(_j_cvSZct(8ymnn?{a=^w87U=!y+ zpVTLvvrnw|T3xPuV9ne|nzO6M{wx!H2_L&o>1!xo{|L@AYiy@HxcbM=VWAU{%DRP< z&e`WarK3@N<>zybt+Ac{QU8(EezlyWe|S#mY$A6sopVZ!?eq`&)~|i#2ksx zIdnFlvST5>`s4}x^g9-;^Fv$BU(RQCB`t}(U|ggda@2c+tLX-D`$_I{!u&Iq^+uOHnO7(2naz0kV4?_Oq zXx&CR8(BHnj<@=s1NI~83zf;8o%P2))B1bp)Yu}NWEyR{iE<0H3;lcWXSvRUv#riy z%~Qig0?0TUIR`qdki9ssdRQy76rSS1R^Bksp>3$!FlR&mQinGFnb!Yl4sBzd2RerQ zZ5 znd_&+eXi?5KG!dnGS{}C-xa#s=h{c}|7CakT!&lzuFGitzkeF$|-;upO*J{!M_+5|RwTtHeYb70kH&>H(z#n|BZ$IOAEqK%K`qdViEASkjtK$~> z9o7F|L~{WCJ=OnTyMn$~^M2QpzsqRr>G^+6b^IUC|3i-cp6^HXG;FFn($10pOZAn+ zXIlTK=_}239-L3f=_|KT!)yU$oN>-i*jL7mIdxwdJLZJGQa!LOb(`gE=3nZ-wtlAd ze~JTpELrEF{=n{{hIRpDoQ<3V9aw0r&=jBiYol`c!uqNQtF6wJZtR8ox{uNg?EtM#;3ApoN>;94i-W(q$J4?7QZ54Rn=qFS?9^|{FgdbU7uO5fQ@N$mTon*HOAmfa4e!^olb_`ZkJyuGcC&%+&>R6>e)A~R8u@a7D>O5fQ@N#a0 zHQ{>BqH@Lez> zWjm@564)C4(Fh+8J*Ar#?%;IJbdCL)Z-S4VR`nM+?ubx4oX13P_lUfBp|^~X2T!%!tKyF)`L`#3je4d}*4E1}c{Vw|&fof^%@zLlPW>Rweh+SaW-TWZ}1 ze;z)7n`XgH2a1F+TRV2kf zu$36%Tty!lI(prUu1SbFtfGESa%fj?+I-C>a(H~qVPu`d{tdwS8sV!?p1?IiivO!S zr}JW-1Qdle2>Gt=K_p;Hiod0LVLJPi&N{f8p`1f%?ClhKfV=7+J3E|P=Q+FX?51OP@-ZCY<8w~w zXEOINpL0%)?Z_C`o!@yc9|YhshUkCemv2iAtNoOYjjnU&9B`)(LIO|}Zsr_EWL&9l zpgzd*Q5py2eQ?`#y*(#%z%g~+`n{v)1o^sKIGbzi-s(ridl$X0`l3DoZ@sGr>VfB; z(pww%kl{?%*q@;XjyMJo+WUO2Kfmg8J@h2$@cq{3dha(r*X%#} zTqSz$zu{`q?IRt)=Scr=Op>1Amqc8@y4L41=zkkM|G!Dk{`1!QT>mnIVg^3Ht6_)F zwSTDJHE}3C*L!@fZO_u*5AnI)aQj@dp7FVUnfAGMx#(|61MqW-&$UGKxxU=XTq{zD ztJ6Bx9{BlHo)yCR&|Y<3lV=MFr$-){CQQ#)e*yhJ2Khe*^*;vjKL+hT2I)Trqm)R1gQEk z$oVm-`BB~%0g`=`R!D#(AA_D=-*!S)k3lz&K^>1l9FIX2k0valEHVjzpdEvH9fNos zYXVvT$kDNOpcBXdo*01vAs`IIfCeA|v;yrw2cQ6AH^BoiAOM62ecKsBOC!(>B!M=d z9q0hM00j_w2}mbnNKIo5KvEhD0TDn3AbQ5)KqHUbtq zi**7}%wj1(0n$JQK&=210TS9fVdHZwo%`9LgI*}0F(hSRQNE+ z8!@OGF;wX=H-I7^<^_BJN^=;Bd>B-X7(|U2G>sS}jTjV-7zB+N^o$tfj2P667{rVi zw2T;}j2I-07!-^c1dLb<0Qn*Y^&-|r=-W={7EuQ#Kv{(PCjp8g)FBBF384;2fGh~5 zlMBi1|aG|9g+a)4hFRj27wL+O%76{BS4XZx+Vd791L56$GXL8Nl63@Bn^50)jvohyjo(U`;>^&<1n>P#Ivt9)cV25c;+gA_B|@ zKtg~%I|2j*SO5qDAs`GuJAke-gctys0Qvw4NuUEj^*>7kuKfg5?=uwXGt}ZU6x%b@ z)HBr2GnC9T@el!p@yrhdfG~i<_P*^z9Xo3SP?Szr8G;8ug*ihxIejS-P&Cd^EzVFN zPTztA)PFOSd^1#hQy(LsuA8B(o1uD}p?I6R905h!)a3{$*`}^WKovG6LlaT}3ac6F zr|HX(fa>YK?Zk*ZLk%@U2{l6nHA4Y4P47oQ`7}e_G((Lv!^k^BZ8Sq^G($}^P5wtf z6*NQnGeea#eS;EE%gj)?%uuV$P?yY5ip)@n%usgBT7V9q6TpOcECnb)n$WkM8MI*b zI)>TnmK+5iP`(Etf`8-f=I08t>aGSCDh2z}exjFuLl4d?_EK%l&M<_5fgACLe{k;y^; z*OQKO4e10lq!|~9?tn0~l;T>@X=p(+E&@FiBG3#P&&&3%OyB3U z-1oE6wu0w%Yww8f6i8K1e!KXV_Lj`^yD>AJMs@YYf?iMx#Y5U5nUwWVSzmljdrf@J zdNucI`4#gOmDKf4mhUaRPSoVHnf0mT?%%|0-%THNP<(|qvnI)w?^9l8d^5fRy$lNYGradMjcu=(;ko?D4M#dkm{bX2f5wm{m2@(?#of; zc;Q}+l=q7F==Ui1*moPGy;s_8?pAk~@3QX7-Ib^6`_die9qJwBT^7~f_ve;>vMg}n zxVh`>8;l#WH&FM71!!(m9_R7V@;OS`OF@*r@Y!)om(xgF09g4$)wSzuT)mrnxSR2 z5>@G|E6U5Q<+51XI`ORQC?;(%aKlBVd;vc^3vkvIw|$pON=GiC8f(u(&{T; zYF(PUR3yDV?GpKt;$nR(ds=i;4^Ng$gP58M$n()NOXFq}gXJ$Sn{T6y|HB z+E<*X&r{~va}Cn%D_vw>q+V2>V^Qrs=Hn~PGH0o?$}=sh-4|yTW@s~HQt#8JE7R?1 z#6|>)hPA`7zlsrP1bSmDK#Kb8_d1=M+fMPtF!c>7$fU zHfj20&n}HLN2(*sBP^=w7e^F^Yr|#I_0!K%&a#II!wP3=pJ*OGo$CATw2{uHOQi6p zD&>@w%BAvM*{%{P{HdMg4yz;AA(F|U&Kh;xqTkf1&B=tYdCA*5EE-GCA z?|VbPZ(mK%|Kn<(|GTN^JY9)3Lq^`Y{>~5udb&V;4t*04yaeeYA51^Mu)H7u6XiN| z!$63j@!}{vg1+BC^39|#{sxGi6g$4yk17eICuW}KY8}MRz zlMkjJkbnRhw+3NGU|ti2DZ{)z4(>z+5krj?YsPZE1!fZFttcsCoiOj{f{7w5dhVg+ zyE8Cd-DKY9CNeKf(+ATJNI(#ckA%T}5i~>r8Ou*Lz>EV;ShgT9z*=BF+X}N2=1VE? zl{ENT2FCT4Cw|y}EfCL24`1vsSCDhAFAH>ky1oLan;5S;qZza*(3G;gj zXlKA52zhFD5u_hS!GA<)8$)RugTOf591#)(>0evG-|%|8Hkkj`0hT+7biYLA9~78r zK-@#i|Lr2uJv*6y^nri&qXAWIbdOGTRHBH|Efyw7o(N1Crqlp44m4polz`a+GujHX z3uYn(QvuR|c$nY3xWp37rTgWxqiC=eib%|bwgAoWIJqBN92 zaKQk`)T;wXqzk;d(>mo?MhSVt&@&pCT zzfEH~0}KINd20NDPX?t=#w9-IL*kR6=$5(`0s5Yd3wvIS zx?P5&#Q9k$GbpW(E+u32uUPiw7nuf0+;P0}>D*NOuKcMqu6> z1MhDD%{ZD-f=u54gl07EZ3Q1qq5+l2tOLtWbi(Wc6oRwO`_pINH z>-mO@NZ&tXe#Zxs!Tf#zW(eko5%7n+IJ*JnPvS&pyMNM13oL>5pEbj5h4~LjnC&os z-UocrKux`LECI8H;CH)PVYi{#iz;R6(`2#~ zOa;hbIV|iaQv}=uNrq-4^8$WCb*tS?5?Y|x$ROCrLIf!ZrA7v!Mh2Zmdc3E`t_GNK z0P>8i3E;AfLm|t^pvuUS09Rui1`Q#`^%qB^V5SMus0>WkAu>n1i4-LubF2@h1aks| z8H9O32xbK4q$ttZ&GYPa~d0q$1PM`}=(6}%SGXsc6 zX!#Nsk+}gcmM{0glwe-LUs&;-@Q`^UqzsuKfRG_wYpC&76s1ddL7kAk$OsT6WY8p}%MJme zEYcom5z-Zhz{M>fL`WAL`psS_5VADP$1*TQfrmZ_Pz`jp_ysN-_!25x=yrA%-KcR{ zzycQpe3MH7zRg7d-{taupM(4#O92Wn1b^~@kRp@oYPeu|2+~)*Fro6txV+ytA@4^4 z68hD5Am~RC5;DIBB|pZ+`#$6YbM6n_-xGw7KDXy{>gP)DneS!aE4^#Ho8?OUSzZsG zeY^CQS*OJhExtS{@s(aTU(dc?dJT2qrB}^Y)mKY35rgte=1b~JT|VVe%x*6~Qsfoih!Z$9<%I_|Qs*x|p!Y=ziloo4?6L0`?l0V@RigwV>GMOM zuW)yc=C((SpmdjcmwH!;YxE&XkiDZsv)e1X?Avv&(y!mPpEUX_8hs_hFtUc7H}Xog zM!d*X`igvR`@&9*D#R^P>W5Najz&n-rXnuR68X166pT1q$Zg11K$=eEBwXGs) z^=n(?Ek#||Wxd#|_bNOxfC_SLlf0?0@hDY~XSrT~_Uh7A29F8o>*e*ub$VY^ptwd~ zqpY!epxJM)HdZUE?N!FA?5fgAW91=D(`2oh`u!!+?^iCi7wI+e0G$;4>~5o5>9!Xb z3zVvcKcWHhyy9Gat}?esD*nnv#X0&MWlnLnPD=hz@>6CNXKFkekegASZcWckFHf_$ zmY+2>H&vWkpjbdzHPx(Y^GHCEtN9ft>Jyc^Sb)Jb{h{e+PcSBACzQq;r0QQ9XO2_H zmB(77>o1NiP$WP+w=hN{W&h%6eY8S#^2RyYbL^~b%VUtws08hR!Il3FmSwhN zNLi`mH~b3M{#SfOukMw-MUU>0Jw;OgSKLLH?ow)=|BFBK#W&FN|K*tE)p;G6AvjrT z!jWmtbx+{)|FQp9#{UtWrDq`mPXa)gmcAqi1EvEYe9QWC0uaZoUY`Y#CkP;>OAki` zo+^O2E~^Xc^7H}3b{WqhKzx@WfXjINcECU{0=taIb$Q4asRxXw93afgP8Q|mxd;gL zvf3H^L>}?&Pf#+W)j)KKBz#}_iH(4&g4R`=A-~;>skMJ;90U!v3fG`jNc(^A9 z3o#$oAM$CW#lG!C{D&ogW&klD#zR0!vLsg3T*wZUo!I)F}~ z3rGP9kOne4gw*9v!$LeS|R{~SnOmmtp3ClM6*~k zfQT030WF@Vf~Xeb$ts9!F&^0BX)7r#DnJ^@0OB5k3vdG-zzg^QKOg~&(6^ldv;=_= z5C$SZ6o>&b&;Z1NMgUPTmH?W87N8YK5+GzxW;@UUbOK#K3Q&MFkO73l1QBonZh*(a zykt2W>aB~OF}#as+#q7cLI9#>ECNIUM9!EDAbQ4l@Qml-AcDsF186)g2T?S}gJ^AJ zkqAGQKTU>?v!PT5M}O%CJb)MQ0e(ON7!Ux0KnMr}5g-c002yci;y@$N1SEg~V{`5J zZ3oZ^bO9+qA@pr$8Z8+>JW6l@ZomV00UvPcm|YleLEw%>f&RE%0~Qgyqh}rhPeeih zkMa0j3oHcj=(&f0Kpur#2ngoU!%xk2BCtoP0t5v}1HwlH5pV%+zyo*zAK(WhfB^v@ z2!wzz5CNh<43L2aAPzJVB!3gk1ken$0Ifh0Xd^fW)Zb1ElGK6rPM`}&0Sb@?GC+Sm z6vBwCE{e!=q!3DE{gFhTGKFv=>yIY#3@U^aSzSbtXH_Ar$oiv-HFL_*bPxC)pHhy# zm&iOx$`ySt(J%f#O0{y1C>uQGiXl+Sc$}0cT_IS?c&rp*QdSow_IR;;M{? zRe9zYVykp@C-59F#8>I+PDlfYvC`F@!1KZoXQit-M zD$n!k>*d$1*K(8rPV!41mhBezvEy+FY%!F0ZmyoA4ms+IMFD@-yu3awj=Y4re@iP4~ z&6Z~uXzo6lp7`~d%1oPP@5|08O*f~j)n|TjT4Aa-Ri+vI^eM^| zTQ%sZzeF1T>g3X-*rduczfCIs*$Yb-m=~xtkDqmZ?tJn5!g(6ar3a{T{Le(skx((}JrTflgDmN5LwGx*g9*{#m?EWq`FPd0MI(_b-sL^qs-y3r%y zD79e-iEerb$B!Vt>h?T3G+T4H#@B%)-4@dw5Fm%QE$W;hdn9#SK5wt`BjAtcq4uzW!OI2Tfs`?eE< zUX14}W8jPNaW9^^jKMF)$G(umEQJS5V#d%I<0E4{of*SpjE|1>CpKf8jP(zbDOki< z8Os1-FTn-40T18>d<17h!+x|#00a0yS`ZdS(^we5h#HFmF+c_y0F10LKBCqHD*-eE zEdYkr7#~?{gVhdn0G&V=kOCAS4P*de4?zT6gud-`(}EQ7pxq1j06!oB3Le6-WYYKs(R@bOK#K3Q&MF!P(GA1}(yV0w33N!NTAk z>mS?mVG#p-tZra0h&GJwvAV%Mp7)IrK6bJJKAsScQ9f2T$j6h!G1ABQKp)b@`?eFK zek=tj07m{8ANUgwk>vv1fCumbKEMx100RO*5C{QbAOb{z7$5@;KpbcUnt%k*4732P zKoV#p^lfK5S~`GEpbJO=3XldefN+E$0xrM}cmOZp1N?vlFdzT~fe;V|B0v;~0W#14 z#DPYj2}l6Vgud-;K}#!;1loXhpabXxx_}g*0BJxtO2C*ReJ2szfCs?fB7G+j`o|U- z7I~IEMj08OAT4^bTzd>ZQo;kFZ}idG&}jcCB+tmlP$WH(6Y54Hd8$5!BN-o!Ou`%Mhb7$t4G6|OM21X$_6aihF_Ou68b5|H86U+&Lcg=2F`n3uaZT2r-H!oI##8(; z$jNw~KL$D(Pxi-PC*v9a81SUfFrk0Ev%d-eBcH5p;FDJdVDyvq4}S7O0gQk$J^;!~ z1~3ZBFbLYWoxF$uBchBCi1wEgU}%)Z0nC)ccy$3}_E|H)>kL|9C4n}e9YF1YBo9=4 zz&>@+fwQ49MAGRBPY41bAPhu+C=df=fX^8dht&x1!i5AZsI1c!p3n*;0n9)|S9k&@ z8KEmYfmb=CU_p|duJD8mFa!|u1YQH-hUFpjZKoG4KEMx100VfrL=aX8=r5dzVlf8r z$srnG@nVWbSWQ3zXa@QVERtAk1KI&zZ_x>>3rGP9kOne##Da?go0rmsCKbM1HK8T$bA-%FNR9o5h67xx#Q)}EG03;rWMrY}BO zctU$ZCRKR-apiIQG2^l9VdAkA2uG&K3sapqOw@I__m3LdabGyaeg}aW@*na=>e_@xlOWsxFqx<%4 z#%~YMnBT`|C8v zpWSY>XWL6{Ce89!PFl%aQcM8%!Ep_{iSHGKcg|*Sc;o* zm1g^^jQtm6jpq9+#`KsHv!e#h_*dei|K+enbN-3pLP!hAH1D4t+#kpV#6W>*Oy=|c zefs?Wr}mG2Zj)!S@Vn~xKiB`;Q=|VU9Gg%lm{7SgaeXPSuk!*-~SFRw0e^PwB0ldl*_4-Ob?AKR0p&w4JbJy>l)=K>l zEAQg$sIhy5O#+0@@Sd7i-pv(-dN%EVNBU7GexjbzS(-Z-$9Z;*?TA8E|Jd=DXZdCl zVuDP~@=e-C5-_S&g~Ge4I!04Y>Ggc>X(8wQ8ha}#G_5Dq-+FNuFIQ>Wx?%mQ9_%DH z>UMMLDIG56PF8YiHMVnZ*LTgqL~^E`(pwMruz~aH8rwOy>pSMaGEK*(R~-eNPoVnK zk@P}maM4^)xMsr6a1PWnBl#}sSe2f+b=8*jz1uc#*}iG(`n8*SR#&vW#HIanE98&O zsCp08c|Wym-A2;d>J@6EzWmSg71_FtTJLe%Xfp@#fnWdMW$R`Q=%u2-h7J%vK~4_R zJgZNl8YT(&w{_d<4eM7Pw==T`af46(L_ImU8CXxQqMUY|n>hoxapte_lN*|%i&&ZZ zqmgUN4K$NNnB>bzz?{0pyyfeA>FnCfCj+VKtzA^-%kk~ZVk2=cppU!>NBy_*$`<~}=Nc`sP%$f6^HfP#7|Kk?REyu3Zz^;6WyI~H!7=l~?72YY5 z%|c$d_Rm^1Fc4SqjLJH_vaVh3^o@Bm%?v~t&0N)gi`LbN>Ult3?g!$@9z@^P-)|FY#f!E9-#d9+(CrnTn5}s+Rc*`6rv~^j6DN5K* zk;TF@Z>L`C(?L+Om`c%vUzqk348t}uGm)ITof_B;Z>HI})hA*^O>JnFfXQN<`1?^kz4B5Z^a?pPCj-VZXd(i&Eo}hjGmxA^$VEcdIuYz_6e@|Q$ zvfD~R_Gf+)v@gRP04HvN&HhJ&cF8{m?dM_tZ{s(E_5^JI-HpG%PS^mvENHj>DrA5D z-LUch4?+8K?nB#k6I!7a?Anncf&z@{|VUtI~lYe`srQ2-;eMA zkF4^<_{a`*r(8?WY9GH8FEnlT%6Hfo-=S$fho<=)n&xxZ1K(lCd54Bj92!D#*rVNH zZ*zwo$DOh$&`cC}0ahR25CI}cus5>9PQwnn3Onq_>%<85ign@y`>#6euecJp-D z!_#4JPQ;MCI30H2bl7*(X-Zy>h!E_P<}4!E6V2fuU5CBS9NOS=*ipdY=u?NC0vvV# zaQNBZDT-bJd7_GFCgOzM1q6vOQAW@jmP2b;4y|E1wFJKxBb`79Kn$aF^JAvN4^j?4 zIXV2Yy?aQppP4fz%if%bAm%2s3hu$IMGG~F!Qt%A{Iuwv5hFl6yZ*2 z_*SHjC?U#-aw0-h5es6gzHR_dfTn-58RjFP@^eU!TGTXar*Xdu4dbL2W;(ApU z?PXjddKJ~HO1-Mqt6IIP*Q-XoYSyb3y|UUR6i2U$^eUuR#d;+(!@G95{#Bt@F}rxv|ZlDnZIy$b79sa{3(sz$Hs^{Pp)0+OGhkY1JPRfS$v>Q#+i z)$3K0UbW~|La#XR=`uIW0Z*vD0LLFWGB31D-YiqO)6kT|QAZ9(9XT9zgwq{)QbdG^ zFu|b@4u?LV?g1PD;3SAPLLCDv!Xen@-(i=3hh6<0+Q@L&Z{A^-d7Rh)yUaW6GVhcV z>@DxGqdd+wfZgLAc8_=1JszWK!Tk!T{=W!PbtVTZki9d;CUXi33QE?^Vv8H|Pp zpdke`JOF!kIqccxuxFRU&Rl3D0e0p>O9`+Gm%}bx4!dwUv=`v8_m;!nTTUX1CbX4k zBdjjKAp%4Z5hB>*$6=2jToC|%zK1Tr!Na&f0319FU4S3!aj5_Tan!;hg5P%?e&2QY zeb?dlU5DRy9e&z%_-PkIXaIiDb@(mU;kR6epK%?2!A0u=AUW<1xQP~GArU7Mgf$G< zghK?03aS6aQLLO8QAt!093OX?Tf%X14u`^_Nd!0w&fzFHhsMnu8aHz|0M6miHHSmj z92zKdXrRoYfij1q)*Oynb2wVf;TScC!_yo~p=@o!A&Q6~5h99-5`u%$9GU`hI3CU6 zcr+(Ua1@$TO>h7jt`h*qo;e(Q=5VALE*n6cND!@r6$Nas3fY08lsk{CmM(r zB2KgtZA3{QP)<}3QKE*ZBN_;fv_e}4B#1UbxqwY@coQz!07o`C9Mptr1#mnQY7~$l zS_x|yu!#T>Btk@(C?QITaw0;+h)SZ0s3ABs3GFJtQArNR2ss=cL5*#e!go$E;25uZ0xN*t| zj+1dJ2#%A%=?!p*49;wTqhrvb02~;DlN#V~7_=imf>0*`i?9iY2oOOcM1%>Bc5zCH zG9p4m3661bstAr`aX5$tXB5DHO()$?cce$=PknOqlii=RUSWTJ>!q;|r9Kq<(D;k} zFD71`c!6W|C;w~&Gr3PaKZ92x8!oEjJ%=*}9+pXi_H8|v%mo7_LL zzjOc8z9Waa4_SxC4yF#q4vu5&e`0Xr6^;s+*gdqnWB25)kzJj;rtTWOtNSkNuCbk| zow1$cz5Tt~3P8t>$?YTCJGW158{O8u&Du7Wwgk|>HL-P~XQ-#6XY$UGJ3H^3x?}W? z?mMhI#%@pD9ur#toR@y+){a{zUpw;J&eu-eGAh;p#$J&be)zihbw{sFUORQo=r!HfSl5hQox1v@ z*aJLq<;aztS59pi-O|0q+A@4a{EDNOCoeyK+1ATWUg};Nz4XW>?Ux+e+_m{cXJ4o4 z98SiQM=wrZeEg!V7oB{S`>N=xj$GJ&;js(4E;w<1-}&nN;Z5;PM>i%n9^bHa!^!pT z`sn&2>)O{HTidnPT06ETwI;Ua$UJQR4Xx-{F}ZwXdFS$}W$v<$Ws^%smUb?kS~9w% zdx^DVY;kIFZ1MP_{zZvJ6Kz9n9c_~`+J7oBn&?hgiLrPp9*d7J>|dC`c>k^Q{O&)R z9`&EBo~jzH>aMb?#wt^lvC8pSe=HH3hz>x&X~?;i3z0e4In8Te#=~9Ovb5oEIK40S@tUIJC>5g)D~_ zvK)@;!u1T`ST2XdxNtoKID!k;GawEih6%bkatl{9fP=PhMFTiq3s*FNL$z>412{?x zS2TbFvm6f0!i5Xq;0A|gu^gJka%dLI;kX98g8(?L0WTteHo`gq*n~p_2pYx0RSDo| z23(Z@+QLE%X$=c^FSvDdhyW2Hiir}Ulqe@6M2x5;YKS_bo@gYRh!$cYQPKsJ5)mRw zR1#H0HBm#<5e-Bm(L^i&5W^O_7ZM4gm0(|d$0FDb-w6;wB1F*Al*3N<4*T0X>~HU| ztG&an_6|GGJM28~u*H}<|hzJtJLA=&mMe3HEx& z9TCt-G!revLLx!55^aPv4A?}BU~hD%il`xKiF%@eXd;@4g+!c45N(7y0$7AYu#34< z1R#d&U+%Dfxl>HgaFoNYbb%MciTUaHpDJ?{J5` z!<~AffoLR}i3LOp!M@;5f@me$2C1PS*0cG&ORDIv-TcKLSL<=bIzZ-*Vd z9rp2d*vA_&tfQM9yPZa&iC93i5DB7{uucFr!Cu?ABLvuM8|NOtzS<5uQsagWXeHVR zcAv(R3&6h64!c1+>;{b|5`bNu9rki|*umLpCfKdnVYg;HjPOlaNrLW01iLdk7C}2s z4tp&-?6r({TmU;PJM5$Eu#d9Cp2-e-COhnz?66a^!%oQ#`y)H-kL<8Nvcvw!4m;eU zc?8(a7A+&dZnkI{0rs$U*uxghBfuWEXdVIft3?divla~`z)rOeyV5%BO6#yMENUdc zzObl~0Q!vCBV+FsFnabzdG#iifRe4 zzbon{!2Yfd`@5oU0_^IF7_ze~swhxGloC-QMpP2jL=90()DsOvBhgGOAnK0;4MY>s zOe`Q;hy>9}sFQ$2*hGLRB7#JS2oog$VpvLd8BtC|i5O8yR1wugEm23*6AeTo(M&8L zT8M>2oM0Ag50cQsK<)DaCtBhgH> z5OrNZJ<&uo6AOt1(MqVTfJN9u5fLOpM3^WhN{KR}oQM!nB1Tja)kF<|7}n8UPc#sX zL^H8~Xd&W6f@mdFA7B#>5hOxHF;PO45#>Y$5hW^#Dx&rn&_INb10_T$QBFjN3L*wD z59zKU>WBuSk!U7bh&a(osOVLQ9N`c}M34v(#Y7oVPE-&vqLQd4YKU5*o@gK%iDqH} z(L%(D1b`T}(QPFGn+Om^M34v(#Y72FN|X`hL zX@GW}aQXtYzJxOl;9O4*Z7AWK!ee%rpfMz;lBgkQU`JK$mmG- zh&3`coEnY|kH543or!l&ykqDc9q%|+pl^TbvDjndkM=*Bcy!_|Lt?vc7UK`?}v`y=m;B)I+g{#)tZc5@Nxx!<~HN$QwJ~IQ8J@gWUy3_`COa z+&_8W$bFsnP2D?sZ}+{{y<>+`hhj69{DuZQ1}6tb2090(4vZe?K42Xf>rc(t@|)Pd zbw6$S_3umUo7g+Fw`1=l?D=)>nYw56o=hMA@!kEq6T2sN4ejdKHF?*_U7dGL?Ht|N zz0=w`)|>2|IxRc@R?pa-sXJqLj^ELLN8*l&+lOxNxP9`rk=x?89WVGSpO~@jH*!YsCMt3;QojTsU#T5Ul)7 zoHn$c z|NieU|F?eh{~t@4f5|IIx@j$-K$j>QgnbFtcb=qg9kz zgxWobWNuS?a*|o(vNzvgYTKS(%H8AdVV)|ewpbKa3YUA_reja~V8lokH{j0ROW&Q| z=F>?Zp=^nSy9#P8lJHjx+dXd6=P-RR z5-iKyeGX6UDyX+kG%gmN?{ObMYcik?;`S|Taf4EH2YLq%?vc*K*?nPm`?SolrnzKq zJ4-zxyc>)uGGEcf+-CH!o9UN|#zdM;R+`;?{ubqKpR|dJF2X7iS}JVwxaZrV+*43( zg(!3gS9#oL-lFXB=^(dcF)d0aLn{>B)xx=3l&t>Qd-I5x6Yfz2Y^e_l9|Ox2nXlBm zmjHCuPhSFZ3v8cH)x^SF0;tg{N-aX|o^OHeFQ~Ry6jlnCd)#MUV0}IvBtjNbV41uO zE4s^tXINnUc|=Ts{TTwb)JKIcfE9|&S76>t017PMCE$Qh)I`Eu0w~cYLJ6UEpH>^G zD+i7@mw*AE7I$$m?a0UBw$xXJN5POHdrMa2LwKIYZL%?aut^-6f6tXPCmRp>w9H|qo_rk}EOlJ? z4KS+6eDx&iHlbJbOmn<_|K4r8_sI=c?#X?xPuavo=V_(rByyNiarx)Jjnz}9r!oyc zVwtWgr|v7Lv`948eqA0BQ)Ha= zz*4^!{s4?9GGCEJ+|2DbPHnmQF{6z{DE-v&dY`I^g)XkBXtWCB9=EBK{^BZFDNj96 zP;0S-ze2d&<2C~m(g!2WvbeJk*K()d;8QUNm;nR-gbkMZS1_#Tt`_FYN1kM60NOy# z0JH~vT1MN98~A60A5&yR7!{g3I&AhXbKlWTzi|$|-ypnlMHUOogl8~{r0WXP5W90o z{R>1Y6d4vqgn352sdpCHPre+q7e~-n|GPo^#=SxN*WU@+{d+=o+3i95xj#qWe*C@s z;gEg9w}bXS{8P}r7h?cQ|1xMlbxX+Zz&L=vd`r;2?bkv3S35(t`|6-w|47jO@UMdQ zd7lp1U;P@w420}oe>G?it_j&;te?0cWUsm*Xn$h}V-F^S_Aj@F?EWaHqr!NArla>9 z2z04#K5b%o6&i)ts|{*39?LrLr(OJ|U2A4sYiC^RW?buMTpMOw8)sabW?UVr-Q&*a zbcn7|&uDe1j9Q1v=yj-!Vh3VqV%ecGs+rJdOGV+m-dLKj8Ol0||JrmewJXN7L;iW! zW_!EDhH0kST8T4#>pa$J^B&DKncthz$LiEE3?8M!*dVdsHs**4pKGR`YsP>5%rB}l zT>9RGfBF}5HWNlBR^C|fDEiwdA(~$%j$C_v>)36SBN(31)#=r_z?hj_)VXJJi=pY5 z>9yIONfo#M-;#?PBxg5C-8OYW=b$NPZ%$_C*#GxAY3d>4wPB{lnR>75jH$hu*fK@@ z#d>OLx~Z+RAKRV|+k~}x=FHT}Y#A7$$seuYuZe4B&ZGZ7pUZ8syEPV}O zJ=DjqlU8Y+)DLf1bEj0NZiBS-8xY!DA)Zc3b7RM&bi3${9sQkNu4$i)oz8n*KKWAp z%EO&KzKna}`0Dzg%h!lzOA7>$8sCe9jP^cjk=bb=j-ojpOO$puU@8YO-tf{7aTOV8YU& zv;FnPOW#Xq&YpKVr%YR*^E$Uy&mPDBQ=v1Q`Lz@}H%~WDPp6dfg*ba0b*}S#(sfPO z7+p)u9fkIj$$fpkn)4@9hNiaq&(71;*eGqSsiFGp(#PsjW$N`_-Bx+)$!r>L&<`qS zc{T^m=D;h?flWVeT{;j*s%`1#|K+f;6jh5PTz>cZld)}u7hKPm>AwTC!<1gc&l1`N z(aTT6O7U-7k=df;``Mq)%lLT|HjntX-S208#?O`#rTDkQ?`Lzy&r=A4f4zP`T^T z@5%Vt2fH2oJ5bclueupOFJ}CF3vuCJzhCQ<89$ikm~$PggML3h%lLT^WyQby{C=h~ ze)bh3KKOf`-%lBBwdmzelokJ8@9|^yon4>JfwMVqHV4k;z}Xx)n*(Qa;A{?@&4IHy za5e|d=D;h@f#%J&{ijab{vrO3;_q$v+l9YN@fXM6eib7}WkWQHvFrVj2P20gFM^5CrIF&u1NgVavMRaQgk`B} zc#ORWZ;8l=cNg~+V_zALY{YTT;`l9*M3xu&sfC}4M5GTMy1hHGtAe}QBC8`WAn?ZW zrt(Iw2Ob=OkA{}=X8-mQY>#b$svSA(-&e^{7e^kKI6dg!Th6_!5uL+6J*bspUrn|e zwpQ_oZYCf9?8st&8X35GoOo0tcGmfh!sZx{IgC{D zxW!qi*1#BM>Uv1-^5dK`Sw!lEkRt>HoZ zEQzdV$;rlQ_bL@S94V0>&dF<3MIE-3L{{=(*;tH?H5DhjFbNRi{G4oSfS+R2D~a;8 zs`z+xfV^aF?@Y6F5QIdZ*<6=4r6 zrw%=UO*LXX=rN{=f8v$4gJLum6r=f`7{_|YI1W3;Va+j)U5=H)=3wZ7bkG&}QBg(6 z09l_{X0W}Q;-$$5{<+fX3sI*(0_$G6~MoS8F~02|}jSdZgbdM4Z9ZKg0K(TQOUP}EvD z-EmZro7o^5I`6BPY4$Oo3FZ}RN}@M1uhR#5{MEv!VyF$(fz1F;EeW#`8|x~NsiDQF zhm2<;@;G896`gMQL=6+aWz1qU4~R+>&hlzvA!}4O!h9}WRtaw4K{y-5Z$n>7h0u6m z(_#F18z8n`%;9EuSzP4qP>aJv#qc&2VpVw-`X%XLnvQH!byoWh)TZba-2E)lrV~M{ z7F8T0UBzL|RUB9z(t9`rygV?B7(FjZN}mPlN>!v2QlGq51re|A2pS>8By{ptRWt&> zFUcw8sSMKA!beN=CRL$B7t4UUV$kFm=HvuujH}o>2GG_X=A`1haRhBd=;;J${z1}q+ILCkn_$X$Bn1Gi?kC#&JV0(HPC-ehZyUH;z12u#V z3(5v{hP6g6Pg=m{LYer<9jX+{Gr9?EC@z7L&7)>Ew_-DDEZS`Z%j(%DK|YQWEFrQ;Z6NQb4d!W9#T$ptx`Z!CLih8U{84oJ10k*mdy zQf|u1ZyZsFST1aChpAU{Zm`XJ5dRoCoIp5Ra_)HKhLEkQaUdWk`O3oxGy3V%9F-^$ zX`4wvl)HR61Jx34evvVq@mY*b5ft(Ra)NoPEwV^5DRTTqxh8K3t%c)-8`82gjF7ePkh&;fUG*HbvmS7`fSof9cbd`y<%DD2V-~IHOP( zai%iz+*OHP%_ZEWTPVil1zpp*yAiu}IZ0e*_0xppmoo2Iev*GY(q_OR2F#X3Y8*FL zV{^TY&E+ph&A>B&iAo7}wKOv@W+m?|Ji!IH)53A34`OHfTx5V@>}Xtoqsrmm1Qo=_ z`Y?T)vX#4Iv%40%<3-&4yfj5Kxe>(G!?@rE5Nnni(h2bjY{}f_1yA5kL~c2y z3eVhcnM-UD_VZR-qM@rY!iW!Fr;6Ad@~&VtPg%INi*2vmrRXMFpK)#Q-|id(N?_|F zfJ{n6)Sb${0SEN8n+ zeCotl;;8lUDa>Hm{o&CMZGAotTNRzpVAjd^Vt&b|$Dizfa^i`hCniRQM*4>n!~O3_ zyd(9t*xM!_pL(?8Es00Q9`1b8#L&=?^~Ts6Chi})f9eqII}T1Bi1lyXH??Q-p6=bF zcWK*-Q`<+kcW<}0k8MkBi)|ZEO>Q08+PQVAXSAogC!Y<5&fBJL9ldo5wiFYuNxZuM z=G0BGn^HH%ZXCa%|Atg|tb4r6*jDJirt|8Kt0rM1adJ!l<%!EDE=^uCwRv=N_vXpu z#Kof*4ZW)4LhFLqrqssq_2cXM*Cp0XtWB()STnR{Y;|gNZ1s3Ye@CKYqJ5~n`#kGB z&S>b$T!xb?Mlg?IVtN0vp`{&5JC;n+f?->CVshcs0;_qXal9Tg4pxs=cE*M(M$0El zQzf0@kzjXV1OprX!}^OaAH?_nU#0E;$@u@S-^;T<290q{d0*ZcdWPm08Sz^LQ=-VA zuvmEJGhaO9(~;N#W+2N+xGnVuFs$e<7tTHEXrK?C%`lHQ`9zGU8No6IuVsoX7M2QW z=AaK_CVUGWQDL& zxC?DGljU1nEw!sR)yF^I{5X%~kuo!DWTc8kq^z(MZuJ6+GK_>CqBZ@NJQAjeSZx<5 zvO(A^%s*pD_Ow6gK~277J(@?;BrBs?ENV5v`3<6a%%{bqb1?(o{vB>Sgrh5trTzqW znJ}N0cMvktX6#Vpj2eI3r)pxM2fjr_qgq($ar5lD4;3Gg@h+(NoONw)>b~r0w$!P& z7L=)%pcm(G7bN&EeXx;oEtdu;cFj@`-{#XXhnOLXnM@2Ty32)U*jT(hkBBL$5V8d~ zbHXrKp~!qCh^!~!@ z7bK@$ST1Z5o@N3M^wRW8?kMD8pQwq1PT&HOSS4KPanCP-y!dfJ->|F&B`683l(N%v zidMm0t;l={toDoxMhWiTH_&@vP%Jg%rt)1rWfK#f%39G`DqQSw&nuOuo+zlbLc-rD zT<>w4VVUWJP5#V1Ec4X63+i1U8dnK7d)#JNCOg7;7S}To+|Gl0_T*klPd!;s?^@Bg zMR=3PeF$yW9vJrU^kbx~TjX+x>!H-1gWCK{wqcK_d|D=^rpBBnHRfVrJ6NH}d^N^* z&gVNNp7x2FNSJe;60IT>7i#ysD$DeHd|Lhlc1qIj7H$R`6`3!AjqW1!BTXBfNsqhE zIWboFY$6@@MZrW#C%0Jy&lR5IanCEcr`}sot6jpsNO+;gJ^yp#eFgP8MWai&#p9m$ zxiS5IpPr{U;k48qDabzIUa&%u`HIt5Uv&$Y+qiweCu$;L>MJE$MJO)R?)eqqGX=F4 zOZaPq9Uk}m3-H;3dh11_Q}`;6+cY-*#;tH;bHu0RFT4X%Y=?vcAm*SF2y?0S|(iLanG+5pDU|(4Bmxb(eVFTcEw}tF2m;>;~ znD=iF#{U1)rm+16jQbD2He|p5TS0qeIAnh*6tcT8_ut>X5VG(7M$rDl%^~}-uLtdF ztUrEJ(7xi~pnYNh^8#Y-zf*q^v>)FbvX`z7+Fu$A+THm3^%2bZ*A=uIUCjS?#8TH@ z|I)!jc>ce%Lq{;z{@?$8Wot`{-Zu2 zPhrZF(sNRb9}#{KELCKW+9{@}jPLZ?Ep<6TaL>-&`*r{a2K02?BB3kKsgL>ejJ__z zatXaf*z9r7s|=?|O_;IjAk@?bA;zrRz=(NquH118>QJ1ne7Q6W zQ=bHJ%bTH}^og2C=nSn8iMX)Eo?zgdCw(1*LHUGY+=B1-nrAC z$s^Y$!SdTXCvo>ZGs}}Sr&aeYZbowc|@>-2bBKiCHG=3-ge(`%E#jFf+nxUW93mK12N9BQL@7d^ zhKM&MU&t%M7M$O>N!F0CxXXoei`;VvhnUOt7kwf|)Vx>6I70+a28AJ^F-OLLJc~QK zIWjf$AyIvVIDhLbAFrpvQN##5HB#{#P?wEB4JF}EX>y&WxY!;VAJ_! zpQ?$4ZjV|-W3_OV$30&=ieD+HwoVi-6mIgk&4;A)!6swefV@)YOSbG+_wMvDpN=`i zoU@s{42w>=aPCUzIi1w>cpec`U{R=Eh89ezB4MR4UxA&L$>YE9Nt!6=(yA7L#lkj^ zTc;~7^~mG|)^3)`KW*-tyVG|yUoEJ$Ou}C;TtOXY%;#J}pLriz&Jo+{+PPwjX4*FkjJSy=mH=_iM;Ee4-{2y6|d6VySSk$9*P+ z*EeGV@S8p@q(K&wz$*N@2v0GzaY!}`XG@^dQ)EB=y`bHCXUP5xp8YQ`57|G(v;SQe zhHM-5|K9snJm>!=Xn*EzybJhe*y`IIwBPVr*!aWWCt>^VI{f|PT|xW)f5&@)I=mOa zJAkFH4%weA3fWiVJ;2X@AGG^m15m*R;L}gwxZj2BkKjGPnsV7 z$hdH}%7vZonOLa(j!)UdL>F4C=&a6R3Nhe63v!+XpJdtPVRj3(-z})LPBbpd;e0IA ze$S_5VrYsilbd1DD;J(&k^OZZ5mRKeov;S)WO>^}vZF!%XC3c5#6lKokNZ?jEOc?z ziNXsz~m$CODxA_gclC7 zT9~iudoLUXjClXRCu$;LE*unEDng5e+C8sqoc^It3qi|b5?GI4>lGOjHVgA5(AyZ} z{bJr89e?9fHL);_G4&RSQmatAnZh&b(ebwhWtK|NYje0O-F&1Emh1ou^yv7JPsbc$ zPU%c0hDEJhIQJ=?)&1+oc|=S}!DfrXa3(M)tQO`gDQ{Jr=?{?my7DJJQ4nTnuJ^d-e*^lnf_fK-21e~6g_}L@`F$<>xlap$%3=zy z5x*|LJ7l)UWQ{Oi;d$HRS-W%Lqk>z^X06sp~=^E?0@(~O(aZ1L!qT2v{A%RTBO+!ga!p!u&bQ=agB$R?hxS?Vk(EUoT>>7T)Y}pUF41-#inv_ngAB zH{JofpF;MVi$it;`T%@zSIFLg zJ^2pE*r=vl8>uAXSPkj4-0^j}@pTIkUE?b@d^Phd?KG^^NAL;M^+y41_>$e|NYQy5p z-(o!K@i&&v*MD)-1!=c@h2X{`@)?jW)w%xNKe|v{f+d$^+m3hRhj`~BaE@GdYb|0CIfB4-XG%5&fj>>{$y7ECH(v2|Cts4R{wt0o|QjsIr|r7?O&9${}WmJbra?B zbiC~{&o8ya`{S(pYz~~wfwMVqHV4k;z}Xx)n*(Qa;A{^3Uzh`n9{$LS_v8D2?OL69 z`TigOz5LM6L({*p^)CP8rFrqh$A$|P85ULx^SyXF&5oV_;uAHIFfS}Aw^W1{3$=TG zFP(l{P-}&Rf4*>|$DRKT@SGhx|1~Y>e;_wKEiELj((}3mKe2Gk;+gcc{9kjZaCbGj zGGs5?(U)_d8qD5^&vP7ZU97h6-#3V^xLG|qPtKvk*E&@*FN;jT{LphiX6iOuWbLxA zWEf*G51U4>E&!lhcgcm*m3I@} zZV^&l#Ll)^8h^;E!Pvuo5?Ccf5%x2TgZe(w)A2nD%Lz_?bd$#|8^G5F|fBR110gz?R#$xW>?eZn%3q zrI%ZFCZgsnGBGjt5LDxwph}%9)NT%2>cxfDUv@<<2lwsV-MeQ;Px`unkv{m9WiUpa zvUt72GP~+pQMy=ozQ=89jK2`QHD>!RWUY6Ih?=&2Vp^IXlNpeOPN^i{!dmKLuuj;g zwqa~v?io?%w&1fC3(+L7VE#HjaT6JxzYQXFp730cTbFA*Cx0E6_e~J?=x3+)RG^^X zY7u#raHGe4I$3MR79oq$C*yRHPmH^`n0mVfZcE)Nyb`Q{NmtB!CCyFleL#iVs#?{y zf!@@C?Ym~O*JSfdJ(A*2w+2C91Wbf<_QphRsc^B!{R*--R8Vk*h@2-}<#C@`pFejx z>{CIe$zpnQW%9KG9j@4yn#|W8usw}nY-qYYkc?z->Bgrxj~EK^VHV%*@M@{Mg?E4@ zio92@ez}d09^ZHGf!%|>Js8@%N5)Bbi>$;aXXJH}l}X^$!l=h>8t~i}CvO8@T2QD? z0&mITAr+T@{zgU{Q#!O`|G{m0dgBs}bR8@!sFM(d<-(;Nw?5>-TH z-z=wFxlhR)WJ-$nR+f5`a4#6aNUHoLrH6m$lG?L>-(CF6DXoZ4(nLX*R#XJ)h1DMS znUoe{=v#h*@Bce53fcel(V+eAw+HQWK7g_L|Ap`VKgW3gdxG|TO(FZ=8^iYFKgGBG zM)dFhNyt9$Cqeu3`2K(KheGxb@a_NZr-Sx?|1HM$uMgR6hj2W;|KE(ie;o|kk6`@& zLae`d3AUjh!2jBYeg+Q(?f3!M7Z?iKH>860WHe+SMBjha6|$c>Tz>R*c>aH8osQ@% zb@7&B`3^&Rf@bv#{F~im!!_7SuXVR5l3LdEE1eDJN6k-i!^FdQ|ub zSgy!?Ekn6mg&QSZ-%!tb@9O3AYxY>xN}r;Mfv#>95`LYq%Huwh>Xtrfs|pG=O5jU# zXu9>!-Z-REgZuaT3ah%H&I(ajEo}F==TlfUJ|&cdEO-Tl$9_vaj$bzj%Y=18nlRwy z(6_i{a;I@{UtenbJv}Ktn&*^NtxwQIK$lg61fLKt@VNWZcjD55W>j5$C*C*Pop@bA zp+yq-dBPPQ_clCV?8HBRS?RmQZ3lPm?8R+{|8DVAeL=C+B5;u~6ZwoQeX!Z!Dwkt# zb-m!mbnR;>DAFmxcL}fdxO-4ee1n4G^e%W}5_17kO1v=?N8EFXnr`&znZt1+!)d9v z2^(;TrQQyAl`!Ay$tt%2y^%TYysIZ&Ls(6E`9321bZ+wLnt13cQX?ub;sM1LkK2@- zzl!K|>XJJMt&Kf{zO${lpdJi)KnW&1z!e_%nT~lfqJsgCugFFdLnH|lhlwKh0S1@B2TLgk-N^E z3KI7Tnh59$5|Q9*g_R!nJlgw2L7@f-JRw}*ahnqJw;=@@tJZ=-izM)N;W-|+sq*QA zO}^vQ=B<0)#;UEL*cuV&%%Qo8`KyP%#hvXcwy2=arJ`_+@G6hnT*Z9vfeYT^F7_#z zoG>-;W~qC33STWXkUXs#IQvy>iBHf(z|=qnU#rMUp>~^!fz95f(5bw%piqMZzDT&x z<2Dt;Ujyf;7|RNZEfs-vIW!d`eXvQHo4;Z#FQ~Io6s{0%_PFPNAzR_oGf^}bvaKi( zOYIh>z-3bA0M1HoC4fidMUDmB;-G-Zrc( zD7Z#MUL`!=8id-t8{;b1s@$y9RvLD%U(38)zgF_{ zs2S*gYIQ-a774#Shi8zN|AK!1F8<2#4&cb&1?_cT4%&Z#vH!3668iMx*?-q>LiV4~ z|9|-LpxuUd0ADy9w6AQyn1Bxj?Ry^$+9f{@+M{^>--y3&)`sj`{)lJ%C-IE`=Ac~% z8vxHfjQ0f?`~U45gZ3Ri2-?4YSI~Y_CB_h748Rzk|F?|5c3>Ri|BvALAMXG@QSs1E zUytYi->ugrDbN2WXnUUJh(%Yj={3HL;Vv$w+-VliQtubO11wWyzH--3V0deXQ)ocy zbWW+S^$D5?m}?hkqscm`!IkxA#{dY_ny zrOC%<;Mr0i6+R1=De`plah9`ZgHO;zz~m!?uM-h3Pa_}G=MEB(ZihA&RB9BBl{uVe zK5p`f`SX!x+AQ^H;Zd+$k=k(Eea5p{r#}VabIyHeU3>R!-@ii}fVR9%`uRRd69t`< z6(Ufd!_&ygoEH6pf=bPzu|l}mU+A9Z)FlPQE)bc^gqe{-NG@ z7u<)k%S7MK?C)*aw}_`MFDSWOWIBZBdffAxEZ)+~#Ft`d}mI&iS(OTA!Rb(v;x6Qg&|< z-Un7HGG7T+y7hS4*SE|1Z8UFHW+}z%e6l7Qx)iHLWTo&NkNXvs;`Ie3+eK!haIMFE zFFM)mz{4&Q?Ol+u{N#P_?j3`>1si@XA^T^q3fbG=9xBr&+2kk$;MxCIn?m*h`~@-o|1h5W+uswkzq}!2Uke)mld$_Yh&}+NPX+Dg@ciFV6SBwg z+h!#mTQ~(Oww+4G+@V~Fn8!_)gR||EA#;&N3pf{ANo26eNm4O^F#cU_@k59ZTs z>Z2xtsA3Qvj+re7YH-Z5ICi!`Y1X*Z z!^ir1_*gkxTq>}mhDpzfWi9rsh)1zICvU^pwIqVxRi(_^#WlIzL`snQUeZH-+cTERpHCn1t*X{3lu_n5XFeH zKp31d6%(6gN~H=%uV{m(hAg>^hX_2h*TfM@dcN7rt^{_)OOITkGlVlmbEaubehs0t z3xb~dlR%7C2jf?&QqF|T*?d=X67x)mG3;v%02NGZ&goKtJ&P>v_9e9p+ge(H(&y3{ z#p!$zMkeTb%rn2Jh?C8~1l7fuE#8hSE^jLLs4u|Ym5$#_OL=o9lqPyBNmHv{-xGWaYBdPfuR*mkd z>Bjs_)JmDzdY*Djh>Y|*QQ06RgP-B8SE*R_k=s=X8-jEcBVC@9VG?LLL3D|7rew4o zX^)kKJU)PP3MD$@x%RX?M@nW6u(lS6#!Tpu7iJD9%T>sZZ*(>fGa;oDRb9}NCw}#X zJ!axnwe>d4T&~+p)^eUI&qWe5@h%#^ohLCbuc+y!!lk2A+`cta@VYSkRm$#~(@X6M zPpz9hlvul`hRyD!_!uI}6I{PGx!Vs?1pq}G{QUz(d&8P6}xgi^{- z^t|N$5X!JCmK|sbeanfDJexgQl}F)4-&iyva>Z=OGu0Wcbh9-Rg9r{t_%}K(CoG5W z^sMM|oXzVkT)LIPg(h8Kbtlijb192{1Ti~|1dL!l`PFPTXTk~{&p8EV@r;AA+nA!ROP{zn@O6 zkj8J8+7d>v3;ngF^yHnYCV^{8AL_=7GiBKTzvY>#9**{?=**SU*G^$y+|$xn@g9}P zv?l@Vj%6QFhE4UJBdYPcA#+3oMO5Ocy_sm(TW?pzJa-O9+K@nfAKuLhDaqvpnR^${ zBqNLiRv{=Gdw2?DDr(t+z9b(VEhs~9NvB)B7x)A zsdI{n3ZiBBdUcL-1PBumLGpT4EVrd7zBYu#oASpcOg4J*kOA^W4e{e$4exFkcr}i^ zsF`SUfg%KcQ904lcO|2z?@elxH>xu6-+265g-ac3hy;eaB)Ru!!RF@j_M1>zjmY>m zDHIlkzIw1I((?Ldh%wL$;!uaoDrRk59Kpq&yRdNqHa1wuvW74bA!>;D3BX1UHq5a* z?MuQL{$=McrzS@yyC<#5u@k8iv0se*tn+6RKk4{M>c_DkkN>FuM~NRz{B6e%Cci)O z{m$=CO^i--PgoQE-%EUN;=4oN?fCBGcSgR``JJh6Ti;InW&gLVZ>GN9{TE}$#=kQD z^2nD*zcl*A$bi=93Q{bB7N4vYb$FJ|dzVo`NYe%o0xO()e{ws$rPh2)}>F6chmyC6$Iy;h+ z7k6GX^{Uu~;}=YB8rd|qA+;f~eqvq6+Q~JE)e{}D^Tt=D&W)YheU5dGwR~(@|I)gRuc|8MKd8vp-l-wPD&F*6W~lUP~m=fb04 znIiMOobrD9*Dt4X-b%g3Cuky|-%3R!_$5Mo{)CivzoNHNw-l7bw^qnpm_ze&5j(xh zTrU@2TTtv`k-1iQrN@2dZ=}*)4sP|ynW&nVi!?24DULR?6bz>J#Z2dD2`8R~Bpca95hLHhs4!nAy{Jpmuij32JSB2Yh&z3vCK5VBD@9_N zaEZtL3i{^t6cjv1MAivAJZ|%`%b%TkrrSJUL{DuksI^hTzdDEJ)Jq?1ieZjZZ#v}@ zGsl_YW3NX`Z5OgfWF@Zd`TJPv?=s%v(?bSw3UC_&;bO)Fn`r0)tQL_K!et)!D=0vw zAiv;J=(1yFPiBz3Bt8AbX(tZkVoJ?O>rx9#zzssoz6`(GZ9ZiC zznvGk93m!4u%a?B7|$J`Gkup&QR`cW{UjoY%$rSEKS7+aXkz7sa`q{I6 zf8YH*+AKwO)_T)=H^Sj!(rRL&(;5+-g~CRUdna@cV5p(LG=tI;0#niMO$}yiQX^e~ z?kOnQCNisp=Xl(MFh8&tiS?g_+RVaW@7_LLbFwV~?D1(a8eGg({$=d9)VGCS0m~KH zgKPYDmC{}_M29$5)}DdwsePueM^2-*7sqok8ERsnGqgg&PY9bm?pKtd`wB`f7Mb&e zD?RS~8OoDClc8}b$xApb^+W8(6NK<@z+y%634(Sie2ZJ`8KQ?Na6Fe^c0}@? z@@$m37+n(&ou{Ru(jsj3xO;I|$c~2oJat_5BJ15JR!*?;b$c2tD3%a`#W~bBpt-l8 zmdnAF`=pvM2~sQF>4QEI?&4yMCuDLmEV)`K%y;|AKGCJ#+fN3SuK$PfD4F);@3G%f ze-!=#EK?-w|1Pv&z9l{6wrBgUUi3+r{c3wJ4(DPD%S6Dm&kVj*L|TN}o!?puPXIa9 zX0_6CUqLlImtg;eIn=%4W-Bc=mwCFy>128MH>*PSUH=-i|F|GzzYTT(mfnGW{^$d+ z`E4QlhnV|sC;tA3F#vD<0_N{KAM*n&583CV55PA!;@dxL0Q_ue$i4@C0RCf1$bQFX zf_4J^06z6MLHiQ)0r<{f$nN=J(Ei<5gZ4vJA-nv>ko`Qy0Cb=qz%hLP@16?U|A0OK z{q6Yvk3Im;U;goTKZxi5&u`KZ%pLzfeZMcOOiIi>^PjNaQY-M{z*7GKcbQN>|L5A! zD07=((!*R-IEPh%6ZmyLX%iJwCn&d2e+zafv3DZ`agdb@?^f)$F) zr&N(Mwybb5KIl_7vC+jC6RkzUR*!q0?eH55iY*g?3xw-D?!9QV2Jp{cjv<$G_oZu0 z-Wxr)pyoxQ(-L)Xh{MU``e%RTOSKbE`GZ%zyPXWH=2=)OSepq|maS={-oKC+fnE67! zLi6gvs{(ggD05@V{plNFzH{M{FGc0pSBm=z3XvtkJ$R_zHp`8$PSKv!wq9*L3?8BB-#NjMRHgp$Pyu&JKA#aEvD-2Ke#XFWP0};Le&VX87(Vq0c2<% zQv5=eE4LLhx8Cw_6t`~cpvgOP(SI_Jq{+dIWU)xr3g_AQJ>?TKF*cUPnco*m%xZ-# z!dL!Y;Ax+(iHE-K$3QLs*`Q|~D#wq69z&*2%q7dY$_F*#}O)iOC5 z7O6^MzKUPye12~pB~xacBPi@&eFh_U^51?`h~?tgq| z&~C*XfG=Mbw69(lvVU3~vbVtoz@O0f|EV_E5WrY~k8cjyn=uC9Ym*`SR*VDqHJ<%n zkFo#iDBeT-;y>U2Mm+yV)BXR?$DLqM{kPN~$+V<$c@wH{5Rl|S~TI5UZS}EU`YpPw(_?(@pyZ3Q4+4Ovh4P7U-4Fm;U}U~6b=U^ zN`PHI)H)NvfXn@o?dZ!9R?Cx=O1gFu(Na;op;6I5JP>e?wTBaK0GWV2&{bQ}m0P*+ z9ajO~Vsf$Y4=INqM%NTe9Fj9hmZXO9O3vZ|vOq^KB5i*7*6H+fE1ifPeFt>et6k3SO|wmq4}%{Vizq~2=BWfKc}CIQ%zl&u1Usnf0ZBg(p* z7(v-&{33JWnZx+dgN1qN4Go)Y_2a{1I;M=jyWCdKE7ye+-fb&o&SY^B*6%s`WL?zQZ zaG+Nmo1>DT^lr17*%sxIndnA!XvUk%IA->m&EYU}HhU>!j<{W(9dRC9HWT2x=pVb` zExiO>;~LItfoIA`XAnH)L?Ou|Ga>PpVoGLPX1vY1-<>(clPC)fNP3C;gVk9#6KHNU z^no+!=1*5|^Kv--BRR7Xc@v-ckPLMZ1rH-OLs~-Lqg7&+hh2Sp@>7mW5|Y81pB|IKq*YSJ*zYnAn&Nu5n=P zb$d2vJ6oxN$RWn4MYv*dN#YOJO0KYh+qR}%7PoP!#Fq?lB;Ba8aYf`0JBgOiWo@ggXzy>T5Oc<@6zR1JytQ*Eg5o5F%IF?p7 z8pjhK7aRYQaaCCsa2XS|rP@(^(aP6G?xSdK<8rx$|E%iJZpF~;Rw-`gk}RV}T%6Sk zF;H7vRgD!lAvRrXS?sOLE>lT)ScmU;+{WJLTnORex?a5t4J2|mkW}g|>O&TD1wb9B zPp-w9iyMxjg>~b&`FIXLw;n;{nW9HkQnfot`cN@hg_GC>DQvN$;UiHMhrdOTDnU76 zn^oc}mE415C95CCr)Vm1Id-WFx;PO39e73HaYWAT%xW{ZJ$;C&14^GbN!jD#&IArF zdU6?Yn%awt5}a|_HiJwZK!Kr5W_G|4_x{ikNg|f41L-|*n>vu*VnRSPhs-ALI?gyC zQ_@Q^j&K968s=|SYa~Ik4|%&8Kg|-?2~W!Js9uR1K-uIhGn?SBUF_bvs|Y!tuB!1k zqwR7#;v#k5O~>hpbn8QH)B)H@(+kT+>VS&7*dpK_{?LmnD`^KrNq&aovI3YYE@>V4 z8F0BJy|@8!U`JxcmyWOAp}jpXIhB-9*e(UoCL{wq+n74qe2#O4|4F+FVnfS#4!J9o zD<^g`iI~_nl0skj!33ZVq+^Ar45IG#7DK~-gdMk`EZ&mwB({X{%0!mU@R!g| z&9K@k!IvQlLr4JwOX66U4i_aHx8g_K@Wad!oJejm;fBM3hr|;J8!OOCj$?)TTxUI)Pd&sN)a!a7E6gsxD$m zUyK2+11?)}8*Ydqd&1%9r6!s-j(MZ-e2df>Vmb>B5{HF#AVkD+n3=kmBx$9Ae; z3|i$bs?hQaBpk)>|BK_llOH+L27Lh6FD~W{b@n@$wJ1ZruOl~l+~(ze`d|jY#m)b6 z|I{-Dg)WxBuN7YDahnf4GdVpY#M+tHG_*VYY+6oARv#oZ-^fsN5di63&g>i6kvTM2 zSe5D0%&6r1^p|hKx6wINxVsuBUG}2CXbxs?L<#9Hap}2LvcC8|H-`?3Aor`{nN2MB z!8tV0Tp-6t?{cQIBtAcfN)Un9Dbl;-n<0%I3d@x4irVL&TJF#0km787wfMr9y==pG zgZ;C7Ce<%#G5TTCw)CbL}YOTE{*@}OYQB=E=2B?GIXau>JyX$0rOoXld)m>NT(k+vDfxQJLVPDrj4 zE&+=%+)trn!U0r>UbwOrx7g*Se&>PSUVO7XxL0~U^9_h8sZ*cu$r*WbQZw+FNO+mQ zvhxzzm)pU5`jb8#6HSw>RoI~CJG9h!a90TPC9A^aI5A09=Gu~*xKH^+O(b;UVj@wO z!!u9Zr+qs9#I2FU=_wu8!X1_;%zTLpyV6ycWwv+VuH008#;0b~b*f4v>}U?pJXN3d z>3C8l>Ctm3UL|hMrC1_!4CbrvB`$mX^CaHUyQg<>7JI^<^XVCVovtzoy*Y>Z(^cU5 z@_C<>KWW!UqV!yb*TP+)$b8qA3h7{{uP=QE2X@J+Ch%WczTnd}@h}yVDy^dB<$RKO z>Wc-X7K_MQVTZ>(?@Nn1#W6};%w0)#+BS&DRl>_XZq8k>4aV%!2kRi@VTdQeU+BiD~0*$qVDYJsf+2Go!n;R zm`~TlL)S$;E8}9(^772;qAv%0Kfn1h=J~^S|KD62wBNiJ_WFMtv|nfr*%y2X-}K)K zTmD}R+W&}t|1NC*SN?O*{_ta%AKE{jmRk z;?qHU``_Su|EGfX5c>W%V(!0B4q(mzeEP%tIcR?bw*N0r!8TwrXb+sk zJOab`{(nTNU;X`k2Zvz)??JZKW;uD4ijQxXU)6n=smt8jTCALUqKQ~Q#EDj-#s%t# zMxvQmNVE~oFi=Dk6JqC*ReP8$*E1HwcpL9>JoEgCvBHi)tWXgU#P3D6RvLlcE48K9b| zBN~YoqLr|Z06~Iw@|-A9OEeKJM1ru60s$gKln~`aB~eE-5phBt2LeQhC?zV07*R#k z5)A|`13Ga+od5zv2|@FK4lVLIWq7UY(6FIXNz@Q^L<7-8(2Sr%Gl5Ph4wMkIZs^cb zp+ob4PCY^Eg{TJr4GW_50h&T|Xe-buIReB0oFR2|FCY>`(NUm+s3Pi!CUG5ytC5Hk z&Pkw{s32;HCL%#N7%}Y>5hVnt7`t4iO-Vh#(Ors)@#7 zp!Eb$#OA)3s3!g&=H5KOY4gtim*h*2$F?kcJojPEK*&LoF%U=yfpIv(6&OJd5<(aO z10fI?bA?>Q&V6T`gxqOR4ss_rXPY!FPVeq+cidyUZFgI|-R*97w=M3u+il?cc|Wpd zJT{&Q^!LZl39tF+v8<2u=+X6g9=$(8kXEh{XaQP*HlQ7d0vgZ(bOK^GK>{3r6L0}; zzyrtt1H3>D-~;?X08oG+paLNv4AcS12CMJdL;g&pn&Jb(-^zzfs>KEMwI00jsFDi8v~KrPS=v;eI@8_*6!0S)K?IssvjAOaHL z0GxmeaC0Q7nYIDmAP$udk=oPTWT%8?)zm{xqZtVG6T*N8?T7(hpa$>(exP}P&;qmq z%?B|Fv;u8FI}imlpabXxgh7G`NPq)y0+GXnI-mt;1=@giAPQ(e2ha&L1!?Cu11g$9 z2nYkUKm@1*{D%kuKmme42yMnOKyU&szzui+8DM}Hr~!O{9|!;npG2bz01Ds`s2w>0 z7vKgwfDACe3)BE@Q9?Tq1vH=o5cUy7Kmr_q6L0};zyruY8(MNZ5Ct@#1Ly>VL4pWK zK(jy%q6KILB2hveP!GsmgmxebXg~)b^bkZq0vv!7Z~>8iLM?AkXNC_`dt%tlEJ>B@ zI7nYL0WNBLbCXkiI9=jja!T^O*n0=xO}wkUn|mkqPVAk7ZztZ?-p*xGnOG)&AblWy zpzxOYmj0IbR_0CPP4&&}8;LixH*&A1UXQ(=e=Yr5{I$ZX=BxUv;;Wfgj91iGNaO5f z?d9A{sh46e<@cxe$M+XrG+)$T6kp7|V7#EdkbOS!y!L$Vxzuy9=kjLSjGKjh=01I& zxG(dp@vQo6_H&8PX`jnIlX@ohO#bQg)A6SZPnl2YPl-=uo;03RpUggyctU$3_ju~@ z*yH)f(vQU-D?DmGsy`||n%QgYRrh8eNj#!Gl6yGyaEuhy(htQ+Rn1K6X)&D{Fb33t z?1PC1wFh$#q#lSpaPa<~`^Eb+_Zj!8_hs)*+^gN2yC-!|?4JDH>AT~17w$6e((e-Q z%G_z(sot5rBXNgzNAC92?XlbQx2123-&VNQyj8zdyft%+af^COHkC+esa!IZj3x6o zr*DqmT-amo(f5dZGB+7FsW)YBOx&p5n7bi$L+pn9_37*5*B7ocuhXv+ugmNfv`piDPPwdOAGu9nmYp&JTifaef#McxI)6fmk$n+Y$YHxORVzst9cV+6z z*p>NJ=~eMng)7V}^eedJkW>z9j{XD%}?Q!mS|NUYFS%Ctd}F>kKYKyq0_}p_yxw{0yzJb> zTxi*)=EUaYXQyY!XBW;l&)3fv&xf*|8qanoy0z}ytkkU7to+RMOz7O1=jrE(=VfMe z&nTR0o~xfLo|~C&OjoC8&qY%J0&qi zo06NHnjD*)pOl^yC2hP^EEdamrMu!?g)_}F^)tmYGiMlQsAptPPn@ouo|~AO7@L?s zEqz-2w8E+8srsqnshLxZQ`A$kCnrwUPR>n8O^8j%pOii+eo|q)IbI(xj?avPwqCX~ z(W!OjI#M06j=YxE;#whUM)jx|&9ocsYJ0XV(WbTKT2rmD)_hC4CEikKHk5~Yl2h^m+s67+5eVEq{uYIk|hwamTISsv9H3CS=SVS-93A~*4^)Vb_ zI6*zFI6CRUI!-(ONd={!q>Fa~REvKmkA9OW?yAE@>^xTY~NNmQszqz zRIqwDvPwtP5hy<4V~2D{`cb)u2G05td#A9D2ab8ynY92gX(=P_T*tR(qyW|5lsU40 zWmn!!R3Hksaqb~{1rP#MeSBZh#PBC+b)T%JH;h;FMp0RT5MaW`-Z0z0-FOKNet0g-s+t+A+FJ31;#gS z**NAXfWI&EZm*3U9*3{-++!)LS7-I!s3U`;x;mLVnZ`M##6IB*O7du~%pq+G|JXg* z!!;}OT2?rZdlbNTtGKau;EUu`6b^9iCq@LYTF*wr(zc^3Nsm3^z?NLC5D)uanP+=V ztescS{hU(46Vu6o#1uaE@i5ZYMDAq<=Q$^{IRvp zbOsyky?Ej1Ka}~he`fE(x2ZrBe#7|=(JO$}cA+ ze@Nd!Z*eqIkrD;a(W;=2RjCEgv#OxmRB7oav;k6*fR0baLBUrg0MrBM-&7=lQi!3G zQ$Z)Ef=*5aotz3fIhA?RprXiKS;Q)fyp=^wl||BE#o}F+ zMS;qqFm0!cCkErI*%_o=+|Wx1@0*VVU{;Ei2AWW!KqufiKnMY@C@L8U0wKUTuukw$ zW*xpj7fmRhgX^sNK;|~9T&5yL0fIo&AfXuu28&xVJg-_=6sjz0sVow^Dwf46i`s== z!L`TV$k$iw>J|JhpaEzG+5xqPPzy8w5|w$Z_Tnbf-vUH|NDrYA@X(~EnJ-qrbQ2It zt`l55u@wIzOp}VwUiIN}e`QgivdBqw$Cy>oyc$bqvC4h4!?-`I&HAzbB0wD=Vkb%f z1H3>z?FL3^@90oyz#j2*6>AY|XO(;5*E%R_;J2;RuT_q&ZV#oM;mbjnw}O6QS`(h@ zla{Ua&!zo7KtPw7f__>BU119PX%+NjDd^u+&?TjylT$$llY*X31)W3+dV3V~Thba5 z&`+aCy%z~C$^~Rq2~GIf03GEMi$`z`O(;r`^8V0~$>(vP=Vsyx0LDv@ExM=G%I!Nv;2FN3Y2=F8SO+uO9&+iPPBv?4oZVWXD#a-qtJvB z2AtGD9F`L|nXCn918S%-I4M_CzrCY+$g>CFM%78Mk2IpVvSIzs@&@S$x;u<=&Q?XT*(O%l~ zQ5-u>R11oew#8#rS__$ej5_hWP+YZIfer|3)f#BOxhdn9HPsfRgN-LKa;8zEWKn8>tP^lhD`ajU2tj(%fC2=8(10PhJrjyQXc?etaU3KxQaQ6ukTo!^?Ta3! z3)!6F%zk>Lq8k`G?^(OBgG{B9K=&S$><*c>_*#s^EE+e*W0sRJZ7sSMiwIk%O6w<9 z`2@@|p8rIoS(w!#BA7c;I=59WVHRrz9hk)j)S%Eh*OFX0?NCfxCl?o{LqHg)2O5Az zpb4lc^sVr)&ENZSSYOO44uPkzt+u{X8!5XN52ZdJKsl#-A>F=!amM(rRvTDyN za&%V|$ykupoP#i}6A^=H-THaSr2Eq4{Lr88nau0H8Q)vCyDel|`_)QCNoTZH{6wTR zQY63uH~|;nCY1faQ&}We7O~1AZ)K6xRk3(yWs$qGNUkjMRu=gxivpEJ!OEggWl?Qq zQC($GLuFA@Wf6wFIVp)Aou2s~!oWAB+P>k3;n42ldun76-*2TwhrX5mR{ER0-{|_f z@U_9O?E9oY+kG(jesexQ^w1j!TK4Ppy<{sl7^`7kAiMzGCb9bfg zirtmJGks_L&cYq$9r_*O9huvW+tu5%wt{RZ)d*!9MB>D}?&g=^#2CU$AN^qu0)%noCRx+A+iv(4D1Zp$VT38P=_&u-0b zNo>)!Za_~iL14%a~o3|?NJVi_1gMeU#c(GmtPlKms*=!lUfs7lQ&c& z+nZaRS{+-RzcPJg{K~>AbCteIT$Q=PxI(=myE3s-Tba8&b$RUa{AKCO;+GXxm@D)Z z;)=|r#--||+9kP*Qy0fBPF$p2lv|!!9$TJYmR@FO*c0^(jb%`mX00rHi&Kj;i;P9; zqU^%NLTzDgL25y4L4JOEetdr60`mg>0`Y>(JYyclF6eWjvvcQb=O6Aiy9=|-S^6w- zR%WI#Q=OSTFE?W!jZZMA_n*^!c5qsja`L6lik+33g3NsB$??gBN%2XAm>JV!Vl2~T zbg5n0GYe-NJbhqd?`d793a1Q~j4ud|&yFi}nw@&5*qP}tI@FG=me4fK8dH#M8))rq z>1r051{?O(_t$ktg0N8cTzf^lIV_*PG(48NvS&dk%y65iVwFvDsFq~0Sqyt%fFqA8v~=1nk3!o z_<#`L7^H_C%6(nDA#>8C;-}+Wag*htYsbnn^# z)YE+$b0zs%w)ossIuR+I2pue$t+{lf^Ki*Gp5S`aqP4WvXvu`sRWi{^8}Fnowr>R6 zP#IxVMrhDl8hzPcycG*q7Ws+`E1An*S>&d@;iS5;AL#kmM8*rO>mKm))IpbY3ZL}){!l+YgCfFGy@nt(PS zN;j}d6K-}}fp(x1kZ|uC092qBs0SJWZx12VONam%4O_fB5xe_nKqJ5Dvu@iM6(~{K zX~h{lnC35r;NmsEc-N1&M~W>L?~o{XheQeDS)mnZz_WrQh{J|z2Fou#9y)q15d7ij zDtZzH8UeAJ-~>E?7w`i?f?RYMB3r2i>VO77>>)S+7vKRHPy_h+Bpx8>D720^nxN1R zp#yMqQS)>Gt!Sf8Y^d`P1=)DQTmB1~CKU#Fff@jVnQ0cSxMCRAtYBEPf?>@HhBec3 zJ^{m;Y3I^T!*FEVHw5Umm0~tGBDpPh+0ad=lm6nuYp_mU%8yMm z*pGESnpEV$)#L%F1DXy}i*5nh0LK7rR2?AVk${ir_0kbS8IHLRjK)<&tTTq%Qk07t zA4b3`7@ewM{3*2nS~Yc$ejNguQA15M%kbfZ(`bl-2ucKK0UQ)RP@D$|9v}on0O=6H z1q6XG;66-XKrJ8$v{`;22spb49>CX4P=F8+;XoZU0G@pWFHjq$on8+#0TNn>3y^^t zAON%+=I0{Rhka_m@K*}w*uj=&Jkoa{%+W#-0j2X09(?H$P4VJF5CJ6KFvuFJj~YBO zh7T5(O?UNnO6SU=HtP)P#lu!{F0HbtCde-W*5w03`aO1x1w;E44DDAiw4b(=fT8`= zgb5hhuV84uf}#Di^@I@ia68ZmIB@b&0p$Rp76=X!LO?BAg7W}vjtd9_5x^->+lurP zoc(nC)CQ?xxcVuw;ia0iBg_0v1?%~-jvkmDNI6fJP2TPrsen!pwD?F5HLvD=iqB}p z)2e@PE}tmQ8lXv9CxV~mqQ*)H56~s=IliPitYa;jU<5s0ui8?!=q~aZ*D|8Lur0Wdr zcPktg?WP3@2!cwzIJE#ZfD^y z2jIXZ#0AvuBh&$bAgyemix31tKrIlVqh#pfyv=FPx8pvc0iU6`&pb=;WT7h;z z1MvC}3jmE&eM|!!w7*yf?JxQTL8Rk=skE0_Bkg6@4zvyuMA~z#1_%KSfJiq0%nkSe zF-SL$9)3%OtGgA4z)Ndru6ATu=%QM88Ugzg2kCd{ci@d^7Wg@rFvz=84y}*K@C>UW>h!e>MGT{MEuM<|~Dl z&A;kRiNZ7HGx{^)GwRdXrxH)4o{Z76{K$7B5|5gD^N*w-i9b?!*nC)jSbRA1knxcE zP&S<(NDssZ3J;nO>JRDtfgCcjxGh z26b03epUT+RP%cs}H*A@8N3dWi)Bj20ujrSH-o2&KJ;_A$m#+B-o z*;R>E+N#_YsVibv}?|<%MPDGJTo2ETbE`-Xr#8 zmKyx2KCwhwlDjZA;=&?rQEXv;L1Df*U!O0|&s<lV8+vy55ltnAFhOl@ZFywrKI^YSy&Gjivq&W)X$pPrr` zpI$h}JV!rAJV!k{J1sFyo0glJni`v$It%X|BqnQ<)k#K7jb*zMU0PS}%+#5&GxKMp z&xoH9$8s{dt>G*D#CKzrSSRFzBhkBTeFn`npvl(asSU(m1 z%1dN5fDgcp2nztUfI^Ue7lf$-{AwSDRfli>To1DWXat%7-0?7sE?~H_Qt+P;C3u`p z4R!~ixVlbfCrZWvxcgxaf?VT-i7PsD10FyI7*Ioy!#SUp>FGj~b zlL2)1GIaMc^qW!l3w^y>g^7NBR*UJi5twxZdv(_~pnO9k%A0@|OmAw1=^P~US{ISI z0S_Pp45%Tg_NVIs!B+JPv5J3smJoiIg#ZWf#b`C~WuWe*BufB`iq{Hl*=ukTm= zC=UQZeEBUEW(YtxocwnYm~}uSroY<+69EqSM;goypc9ayRQOX2(2(;Op&|cVCNc*2 zG5t#n*^vJmV>aYphf!P$G-CP>2$#@dP3Hd~Xu=RQk^c`phO7hT5d=`|wLT(t(H)D6 z(pJ#d=xddo=w_AOUeH^EVn0kjf-NivGl-B23&RW}@WSd~)*<}D5Pp#x(KE@=Q!BTi zt5$B4dx)noB13G3p{JhVo}T%E0H6RtKn21Cd1@_8JUy{`LUFBK(;HBNdvtkb3(R(y z=WF1c4ipHzWM05;{vsIRE3E!6061ZN(7Tw zJw+*tFmDXQY=e1MJIpAc0UbamARZ)0KpjDTz7gCn4-&uN1wX1G(!osTmjW;qK*jVY zVWPd#UyY#X>-FF_8^Lck5m^h&ziR{kJ__bK!0!ok6D$8f0)OZrG8fDryJ30&hUuUB zz`P#?3e101!C!<>Pz&>y5twyA1Ezn~2(t-j!E~V&W*ZR2^dB^sodkQ$|3~bm@;^&N z=7jmF3#J?J0F2-vVI9~tfDiBk3W3ylVX8nF)4p1m5ugreK%v?Qvk7Rybfgt#8_*7D zC~WG0DfAK~g52hS=>%Ma;u^c#JovIxM!6T}Ni{HiKmgOH2EmCc3PM0Frn~CEN%bgb z02+a26i#ae&uItG)xh&Qh)hV5*)0;81oM0+I7bHOd%=Z1aIv4r6qrkcFhekxg<(br z_L^T@hmr<-xuOZYyal|X6~$4Qy&d41P85g(WcE404K8q_2i(NKYrI6}gW2zg832Nq z-l4(_!@RZ@W(26m^bHL#n_%u~0h4XuEm80`jmSCx;Q&D**lT{b10_zt1-Jp3AV0`p zdVw0i2lxr{BMSIv5Ctj_0%}qCR0L)nP!BYq@YyENY(_yV%oo~VwgVcbU+#d}35W*? z4ubrK6Q&FB5bPDs$S7fe7w{3}_x&&ffC8u}{3rx74AcS{$Q&?#?}X`w`6mxd8DKyS3jgAR z=?4OU0;mK^#~p$l25Nx_p}5K(sg5ROPXkC7Yx=ecXa-tl{Sp1YCdzh0QWd23WW0p5{8?;D`MmY9D65koW?gnG>H^KcD>|@qzY1?)}938a+Ly zNOvGdx&!;((ccl@$qe;piy8BPen32s;hF<@hAzBez7c<;@Ot|7`0ItD;(+x8oqi?$ zO8?91%h{KVm&BJc`}O_ee)Glni}@GQFT`IcJa0Z9f4=aX`JDb-!8A?X6wS;&TWLUi zHuE{-bL!{1pD8?T4yg1`Mv4A@x6sd%#!En zu7~pJbUIGY)2RWCs|%^67nyT#q+wfeQZxL{y0$sD zDZ%^IjiQ2pxG{5;epO*Zn)Cy5>(RTO?KAqszOHq-wW+l+-oLJ`$r?t5azNrrjX#sC ztFpY0Jwv(y;>t|%iTu!t)QZ@O{E%iq?2kA8jWgWrom`X8?yC@dbK`VcQ|53^oSTSYxUYf*bK+Rg^)R< z1W*W?K|Lr2O+{A<0W+Wn#6ZSx_|;OuU@hs-}A)fc; zf5ZrX`A7V*|HpXjmw$rie)*s9;4l9(#^lOBg|3VIGYGrLhcI41&THVmK-)$Bc_;X< zLO=1}MDQ09`0ozzKb+t%UEqJZ!T<7r|1E>R;*o`4BeEd>2B8J{Fk%aG0l@|Nw}>vt zzvGdG-y^ah{{f)|`HzS#*qiYu#2DoNK@39v-w60;9&q?S1RUhQAmSi@ijaeR1ThEs zD1r_ir+~17EF$h8O9(v3j&{%)1zj5G?f^XqJjn7mkcS>*FJ6O?X+R>;hX{o1M+ia= zAO;~T2tvp~L?L7qVF)<{-8nhTqY<@;M#vFASO+P(;&wRed4!??5em5xAqu$(F$%dE zQgw0*4^^}xR3Wz^Rw1_|SRqFnK&=t%;E{_?L@wlU2wlkIA#Nw1#3L9J5W$d7j)JFX z;Hf;EaT>xI@9{DV2P{~svoM&&wG#(f^ z8-Wq|97IOs=?IO;=OQ*D&p=Q_J`W;$@=P8ZnT6Ph+>PLf97l9SJ|E!`d3HTGhet`~ zB1$69LzqOq0C5s|J_053f>v-LkC!Y$yhL7%fQfve1}@=olck88$UO+0$hrhBL+C_a z?gTG#ffu{MOFTq-GcH9aMP7keihLP@De~orrpPPNgDqcyE^K)f`mp6I6>v2Vv-Bd& zA{&Ua$ZNvjS{`m$hj5GBhj@#;z8>7b!!1`K+#+v8yhXmc8QjFfE}Ic{k*{e3x3q&> zqhP-VCOW`vo#1w1khntxcS_(c2hrY)Yn>?C?E2eq9AZK8vkctFLqcW^?B@^@lArg3F9g6B6>vX~5WR#5k^FK9d<8Kg`BemopWKU24Y3>n+@Pwh!)8Q5H6B4&EVTSYV;1GM)JD|8_Dk>ZX~}SCE9!A0}Vx=?*PBh z34SOF^j!Rr1d;+V@narT`VwBClE2JDO9v5JlCy{{$)6y&B!2~OR>@!GF{ZB}#w33o z!6o?{h%U+B#4A_ww|J20+Xynre}gEK{I_@uOa40^Z2As@P4eF(+9VI+#Vk38H?!pL z^3c=w5PFio4{0s=2QA<~KwQh-j2}W)PX5Ps@JBpA^IDB;j1qq;fj@JA zhn!%ZN3H(F4g2RjcJ;4_UCIB3;FbIfyz?Rddky#>KJb@3p7oyr*#D(~|IK4tzfxiU znn$>Pg9w*=7$GjX5CMM+1u*${_2BOtz(4TV*B=r4vNz*T&G_PfcqHt95ebw33~5dI z|9C*`FHzW^YT%I$@MtH|LvMC=(S(S&7-gjb9S+dRqhl@?Y&VaQdGPXzEXyEcpqEF@ zY7jM(eGu!E{XBRUK=4df6fnqRXewf8atJb>a+rtGY7t74BN4C;5w+rWxatvDlN%bq zMjl^lLVQhbhUllt+3m8u&o_>XfkD{B5E4g(E)Zs6HOi`g5xFdBnLPF!~f)y zUEnEh@Kg_Y8V}k{M9@w?9Z@^^4213EGZD9wyAZgOV~E_zlMuR-CnI(zPeJfbJ}U%H zMGVj0jA;nv$!8;$C!bRXPDe;jJ{Pe(c}636UK2Qz2li$muqSu7f^ob(D4)-xe6ypl z=V;*E4sc#4c!AJMoG*e4BygbvT;v27^8nz52ms1U5CN2zA_OS+AO1<>1LaE;qP-cH^3dQ4ga+ly5F3;)4}&Xti0}%82<26E;FUa5xEhf{xfh{A z*+8sNUV|4P<+VIyxDFvhxeqZzd3`&$Aqrllfg3x(tA&2zCK22$f!8>|ElzN&3+(5C z!~_C~@-`XV&f|$Y5KokM)_}VZRK9&oP=KFWypW<2Ia(c?AX6F%@sKloGtd|CmY34)(f!DmC@ zzA$Lkg3m?3=Xs#?g?iX8Hh}wi(DbDy*e^GOue5-#wt}ylNZ$!a2HSnzt@IWV+ z5eA8Gi{LvF_^tzd&k4ToBHEkrfg44i_kdsEaoP_V?2mY~_KS$t${+i{FY%!5ml3p; z4Gxw4V@SNGQXjqkZsDCYDI4ZU*-(8uLu2L(q-z*Ekb5ifmikuroB20V zq-dCZ-FRJm-6TE3{Hv)~wO6yGW+=X5z8rr!Pg;iBOWFO#P;?>nf<`)q#`EIy=5vE) z!c=)&q3~?_+1Rr=(l1m$m!W?70;w0qp3YIvyh_@Ih$^I?h>>z(;&GKm+v}uTn0_?& zXzyNeFX9P#QY_RS&QkBZNF(ou;|a!t;)CV`@dxtvr|#EyG(o)2yf=Pto|FnT8h?NI zt~8Ck&)u0Ijlv9#yf5%rLXO7WtG8uHpRjOC`j*%&IZ`K7sn1?d7D$^Ak%Yt^m6Qqf zo02?=V9*$RlQaqQ)N`+0mnB6)L=ocG=1GrGqaJ*N#^aki;yZHN6Qo6$q2BvKB27w! zxqhMF+#08Td&Cd2*BIA`*O;5*q(GS3q|vB+L=Vi3@s0VbQdenLWj7cb#0@5C59VoP zzSfr|<-q|SJ4mci*JMa_ut5F!F&dwrSglfTzD}d_)2m|Cm!F`q`I(hE_2j2%WPa|l z1gQ;XXk32b(&(kxON>jzOU#So7b9k%k;Wlb@YzOcp1blLli6>dntke4ubo{XCz2DFhf20g^6j>4a`wLzIs}QR09jt ziyu2BN1A~u_2KIi3ZxhqJE@n{0?l#pae3;&*E+K_reEwZNhvTNO+~e6mUIHec9Wt4 zc~S|~TC*(%#RSaecyqof)ufR^;NgZesRQPCG$2FTfQ3jp5{u+W8BndwgmsDrq(d

|0kZ*vA^|2T0`}880GS%SrapKf-tsD!uE|=Zqdmv#&8m#Sp)PRoPd7L&)|fMF%+Hr`xs6X zT5yntz`+Tqa2}@)RPyM5jNu0QEq<=zVx@BQar=0(Xe2-VWfdQ`Qc8$?G?L~A5+;Fl zoSOw?AL*m%5uYU0Y*G;x$IqX;c=ghrixwKVPtsB` zw1h431>af1(O;K2v7O44b_}Upkhjaq*yZN7hjXJ~DgI$WB_C4!L*}lH>qe%E5sv<5 z3@=D<7NXsR!xmIIZ5gl<4=|I?kgrkSYaM(o4@d}`ulX2Q=L{wb*Njj5^_UDj} z6uv7~UttVC%`|I`0J=H7oYmTcmE?4@v8Hcxc@6${3`Z^GA}oMj&Jd@iYi3aCh)kmhtJcxqja#>@?&^xgRu3P{!qMNCIki{9YK;z|jTWqO21~d_i1Po+ye36DO)0{b zYLZn)|1gHPc3NPa07gn^3*l9I!?o-hTYeAOtuPC3D9NLLtm4a(Bz5rRTfV&9RymLJ zY9bu{Qx!LM1x9I&!c*?TONoEJt4MD8P9< zmo4Gw|CaeEKR2NX`gs#{a{4%{9mFiD(f32bX~%AhBlg*!%lzAwW1oP>QGqC&N|Y(v zCGG&g@6C0#<-gR=h$1cefZW>I4U@;U8-7tgz^?~GL<(AU;}3p zr**QA7JoDJhgt+Ogwn|#r}=HglxJl-O0441-mGDdjQgtPtfsw)7D4H2OWa{?in~jy z;>zA#r_ii*0vP6ua3X2kE`AQdqJ}=SaoAmy^Az5SsZa53@wDrx;>_NzVP}lHQ8=q@ z7jAAmRyN=*yGpz`%e>gDXP+o0Qh_MoLMQX&q(08$I~lsleAqtiYCD~l9uh!>Q{_DI zvxIvLe`k=VS^*4khB;5@EJ59+{9`wFd(-TlH0+9TCjri}kEs!73Au_ByZ+9kRjA|X zPD7j#&d+$3*vJp31D?QXZUSeB*#xWFyl{Fqy6 zxR!GIecdh1`~@xRV#*yD@kqZR{l7a&|F5prBOO>v`2m-^rJs@hUxKv%9Q1E*-YvyQ z|L@!VZmF+_^#ACecloJ*zKfp!_ZIvAx&Hsb-&%Wbh{Z<@e)=4KY8Q@rt5k};2k;CT z7C)bXs@AtSmI$z6wW5f0_*_i@g4laQD2!C+pE1yN*RH@jsGdt=;BfOAC4qV*|$O7~Rh^(RopiM>f@(eLX8 zFvMBMY3232#$LGnH)(AWGAti^lawmn>`fZ>#<-sV=W%XQu!<9Vlcv(@)(K#UGs1Zd z36gH0e`TMflV5cx0r9c7NUh?`-lAb=jJpXGof)KNyt>SnP;DoLsyMN?Xc{f3K>!ub zdQLogLS(h&5z;bSB3LStO6vl{vJRU`I}e zYgXnC70%;++NiJM#@>PFlHWA~=;o~FtiA&qDOB@WGU_&z`L)->+I5ZG%c&JSpx3gsqdJ_$oh+%~iR7SZ9@Wz_?xUCUiW2(-bI=G!Tgu$oZPIQm zGpJyl00ueRIIA_5&z=grwal-*9#&(Caxbw8o={_H8`aem?qoJ+cZvO1G#1=6;bY(J zj@-6++{tB}7nj&}DxBiur?m)*g<2QaYN>F9BhgX4UBNvVoV_LX@umXT%DmXCXP>)< z+lkD*_&AU60jQ&j54$a%M^1YL(8bxvS*WI%aI9X&h3@4_TqT% zYH9^f=$vx$sIJc8PUdsYEwN8{Cnk@cQs&UESo`=Ju2`8nR5*|O-r>|LZtVSs$HH?2 z(8U?xthWEgOn7oynLFFPwa0>d;o~@?CH9FXJefGEw+Ya`xpMbH0_f0yD1r2qdldiL+t-O_IlxuyGh-BL4Y{|g61;i0>hzIeB@ zS9mmDvgQXa6wb)3;RWgeuK!Qs-IN31*`mHk9TlpKxjh;e<#v{o2`Y`&}@-o*5UB%p3-@$EK(X?qz|(nvmS>RDVNSuWs#2I zMKa8Oj5?$RT2MvafDpU56GJCPvlA1Hx zCAp$6+G(ZiFG`kVuSYX|tqv{AE^Vb%@YqK|aaG6xv+8}s@-fJ>SPoG~$f?;9c2Qck zatxm>$Mo4oJ{8MX7{06>GQt-!Rd|^-7o=|CR^ebLiy7tzN zYl5TU3bP7ZXnA~oYyH~?NQMlWpU^V8hf904!VO>AkSpvXIFslrb=VOv=BF94^fx+b zUy)iCeLFlu16I>ssO7qCfQt5z(%L;E4&dS6Xf(t4RzkRPc~N|)_LnTdT4;!h>Lt?W zs&@db10<~W95m}_otkKua}~tERIczwo~aZJ=0fLR=jKgdjcYD;|>FBb`)<*PsKMSyQP(Exl_|Ai**>-~|+*7N`fJfD|OS zff}F%>So>`$(d-YCO{e>;7u{gp+LY}Q+~Ye;r9rn zjOGLI?tvdK8u;-(fgfY8{TNzJOD164vme8o{TR#a$B<>eyO*RLX@A&?{Rc?#tcC;w zl~z(*Rq99-P{9~q$9$Yy>9VwkW|g1{i}r(Yzajd9G`slZAgS%mr>_~+RZ&d#5MAT& zewped_-J0z>Y@crqQ6)W%{A1lxIs(x(45L1`qE1~R>O*w&O$S|F$3}hkY+#4hUQ*2 z6K}*Wnk|f!2a~8_9D9~Jl5i`kjN-L1BwC?4q10=qQBY7nMR7ecYa&1c&{4b@~F+Vz8URN)#;=N8(j zG7c2sAVCwTU1Eg2Um9FPulS9pb)U%RanW=*1VjMeVS)mP(X~R@2`E4a@N^NpfUldN z0KOhrfZ9)}1=J)gpkW_D8YBb&6$l+7L;&h87Q%IaC)tOykln@^O{#u6W>f`eJ4}cI z4RrLVO+Y7|Pw6Pbne>T3+B3PhJq^_SNQ4mwj3s;5M)l=s8mh1eRT%c4Rbh2>@uhQ8 ze_%Wnm7cYW7xsGke&~W~-8fRc)>0cFl|)NASL4-KL;Ev8%iu?HvH1mPwg7J^oq-$a zI~)o3P$Tgcormdre$17(9)-SOXkhd^zVw#fK7mc;W*eEL)JbpyGT;ULfC8vM7>EG% zfRH3eKnoxa5d44ws6ZHK09pa>0fG-u02K%W5ugDO4-y=J3-AC8kOv7~zz3*61JDGt z0^(tU18@N{;01g@00;shpcbeDngK7)qdp)21c3-p53~asAmUW(09=3v@B%&{00e;$ zPz$)a2p)g|H3X8#=2@}=R{ci?`UGz=7gGbRj2a43W2~dn8teFML}3_(4cLu1O_uN9 z7HWf}25d<)JLu>pA;io1VO-J#i!Crr-wfTM@Fy2)fYAZcHRa8gubaK7aozKTdc2}l z&*<_>GrYi?jE2i+JI)0m`kfzdZ~5_B5M34tc%#RU7kB(Mbb;mq<<=$IO(zZqU6sh6 zNS7QIqRS*J8V7!8{80U&@ehd~Xg|n(KlT0C_w(ONe=q*M!gsar=5nc=I+*>A_IJ6z z75_HzZSC8+Z)xAkeKYmV>^BC!9{+mbYv$MVuZdsFeAW1>`qk`L5?|52lKUj}N$it+ zHl2-U3kS`E`a$tv=F7&H)h}nil%O{}av!J4v=_yXG9N;J(bkhleLnX2{0Hd|;`FYE z`M&z4BXLLScJ;Q@Eow?k#`ffIO5YT}sc@rt zW8sDrDJGiN#&&AkQ~k02{MHP;NdX0h)TY>`{MChx=0<%Z^cRe)RC`5;%F4Pxg7pU{|^9rPwP&nVjdk?eJnZ}I#^w{*=+4?l|ENx0*QaWay zsh*LWm^dwas(OkzK|e_ym(w&Y-)6QHnqy6Ry-}B~&4w~+O40psU)pQPX?NaP5KU31 zIOg0>nwQ)|{r`XLwx0ia|9|oie1b>Wl1EQ3Mo}<~y!2xy$wV|X$omRQzqR_@G0tPe zC+VURUMB+o`0Z{5)-Aw;& zEp-e#X?Za=Z{9j`Te`;Zg0Cx+idvoD)#{4|4vg56*cd*LPPC5ddE{peZN=7O^c2_7 zfaV&3@^J3hzGGXNr%7XYa+8Z%>R254SxbJl9K#a^T{D5=XFK|K?-;Q~lgIGmAqVv| zRBPl1{odPX+(p?ZX$@DSt=YI`Lw|XG(J573VKeBtfEea1U2HX1G7UA610I7-CXJ!cG7mUZu7=9rEWf*TE&h1CJ0`}X`(w)yuSb{oYvM<4jQ0FoeW}Yc5L0e zc{TsLaVkcj*rNreRdGito#`8jvCyp6D-4v@k8B_3YQbs|SWw9)=}R`#u*cQZAl4c? zj*3u2G<+Q8eM!asjOnAgoWb4DvnW+ycZqGgEbm8Td_;@oa`pD> z%U(Y?a_*?k7IOzHIaid}c8^B!$M(KVjyW1aI5J~YhpV}hjht&sY};Ykxh(17$2bP{ z9%I|i8`afjzW8mNi4xoHA}u?aC8Z=zT2>8~z5*Z|omu9`t`7TP7)J#n9|tuxGaaCIiU`y_T?gTi=F_7_&oTUw2-!YwN~!BRjojmHD*S!R|uA*zzd%Q_AXx z0Uy_Utf98Tk?v7lb#f=uIj5D_{roDkx#AFTCeeR_vvKu10-Uk?`?7xq3VG&=y}fs%)ln%RJg^ zV4tnA{PEmN2d8D*ZHJ!~X^!G2`B~b|yiq-#%)Lyjpgm-VUukTAbiEamxF=d~yw7i1i=iU9=eDWhM45e#^R3DE`>q zsHBVUwq3^Noqbg=K?_Fpcp3L{CFiOV+dgxaw@T~f!HR3o(S>DR>{Yaz<1JJ`eUqHG z5)}cgcHUHy{7tl>^XB@EeVf-+w#Y?gPVJSjTBOQdoW?n!#ID}=jFUBYHOhHq@u)t} z;C^OS@I>0=g`;|ka~~@>FD|j|{?k3uj5plUHy3-PCY29(t{sR|NR9X>76^=(tPUw{~?Y2zxoGm=}%KU z(p|r&_Xb|@NYDPxEuFpHE#x&1IvyT*2L}U7f_8oX0u6#2)1U9`hD<#i$;; zxfg@;k`ntGy3yKB|CJvUzGMr%_HB=Y!#%<%t>>~)U9aQrc5?QQu&qbd;*Y8B_~)}d zvR*!_%iY|~ZJalj*!J;Qe!nor@wjqSXLoW3dpXl3_6Z&x$xp8+b7$9#9a;H5DrgWu z#u?#UD_lkUa;-hH{WnQNMCpNi_WZfC7pu|c z8#t>uqvJlQmO7ieV!`r@VkQ2r9K+wIG;dS@8D}eJHGgz3L^ok28#iZe&)g+*<}R6i z*`y(-!qL@LoZ9D`pVGXd@V}ftD-OZxunFlPi^HVn$L2_x3&l$kD`D+K z>XaZCofSNxo!B?3s|nmmHz$orC%2aUSM9|0qq>~U-CWG6m)PqmxNeZdQu$7FC3(9+ zRIKy~Z)DJFLzzo^zu0>*LR%&ZXL8mN>jkjdL0F$`6b|9JbRyyBxmvBxZ`UJ4rOR&Bq-ecn%RSY~y!&~2pCO!;}##kXzy=8bFliIf{7VmZm9 zTZ#_Db}bhF{(srKxpfR5SnbN*&ExHN>>tAmT34|Alu^`a`>g$ri7|ZO>)P_bQ?c)- zGLBfiH*nh+esJR$Du2SFCcf>M{hQVLgSU_21fLdSsHn9y{l*T8-EXnF z=;-%lpC3QqmUe7$OFsJh@`Y~c{A=9OPe}vdnih{F(R%=C8vj3WC20X%PVWhP=#~b* z<&jpMr2qZCTe^py|6A$r ztCKy_neTX{k2^flGJ5|1NrK`B1-JC)s7Jbg&@DA}(fI#;qVP92fA{b1bM^|~o>Q`- z`xXilzdMf?K+k+`()un0S#!!>Lx89`Wv?MX(wsrjoI%i>64($RXU?EzPFZXS&@!ha zHUub{QxY2jbj+=^aZoYmx#K9A4Ov{mJPZkQ76mk*1Ly>VL4pWKfCGSJIfG)ky`o_V zmzO7>cYVQ4)aD1k6JWvL}Vmb@fE9W=>#mO2JSat1+i z20d~HIdTRyat1MS1}$<1DRKrSat0xC1|4z+8FB^{^74#zP$1`N>lpOM%d^&LDC-~$ zt!F1nL}3A~KHvbHfD3@=IKwDj%9cZ500hS=Wex!&dnscMApj^q5Wr|(E1g{!7G%aL zX$}D*x2}WR+B)=1*G${cNzzMhj zHvma-CIb)@XI_FFfu1;noH+9X0YCwQfC_{F=!jdH^0;8&LAPqnt)~i z!r}Is)Ls8qfiB0s@U5V*;S5UQ3_{@yI^hg5;S4I_3?ktS8sQ8Q;SAE?49ej4iq=CQobmj7kOyZ_ z2WJomXV3;`TpGL~3R43*0HKE<0utZ=pb5?(3C^Gh&L9ZRpa;$v05xz1F>nSga0V&x zW9IOK3OIuZID_~%gZ8(*q79G$XHWoV5CCV;|7MW?W>EiT5dUV-{$`N=W>EfSQ9uJa zfKEW@C5V6oH~=RAy>I3QFeIH}RG*da&kGAm-^>SKtUBdaBPaj{{xOJq53OeiCH(CV zj0a>8_-4@e=7|6)Z~lL0b}e7AA|Le`rn1Y{bl4nXK9h=2q*0LXbW zsChGpc{6BvGZ}!AH-nHjgN`?Yj5mXPH-mcj(0W3|n?b{yLBg9s!J9$An{oZ_M(B4l z$agcScQc50GiY}+NOv&~cDvaRM&D4R`>I;%6AJ&%6Ni zx$PBggiJT{0}$zE3IK_2%3DT&KsSRvH>E8jM1VS=9)L7Ar7j~tn43YDo3#L~07SVN zG`T5#89@U&fKC8%+ze{mbS)x4i<>zC7vKgwgrW6>4mX1gH-ic{U5g0N;AVaR3fv3= z+;lA>s6Yq^1GPW|r~~SO2A~mW0-AvqpcQBX+JPvb0UbamfW(SS1dv>jA-CetdOA_! z0*3P}%9up5Mdk%+0AyWcJn3Qp7BVlgAb{+Pj3-|V!$Jl|Hk^R59+Swz$cB?JHe(W* z7};BlYZeQwh>CG6`@1PM|C^ql_}7XJp4p&KSTK$k51!6Eub} zi7bt*EJ?|*kj;_KEQH}?j!l?E zMn^iclNCU}u7DyEqQb97F39=Rz(m^tw2C^O&azPH&XCq3G7m_st$PLMOYREQN?EsQQ zG7abeIssvTAOaHL0Gxmea05sj$z%Y@BbgVd0erx4{zwIrNFvF24#^NKB$8yvBRRC5 zJfCD8ijh>3@tl&4u#i}iH3LX4$yxy7)G`^=#nei*HN_!*P5_Qhv1Pa99GPiIMOUwbO|Wa`P-lX=qHk3Ug(+Ydp;5_f2K9^ZFS()t%WLhqs&C_3a{Q@*CUKZP`R3p^+-THI6(@ z%KU{b<`#X6xFti{{OUE?&56y!Bg@lQ$FJ_+sBO%VI)Ch{JmvO_Zz!xc*X!%W^_f1S zPbG!^#5%2*;V-`?y(YeC57m6;_y})-SHeTxwjZl45`2677;4&-2%NkxGjFiRIez+_KcN7-{xf zS^mr(omBfXOO2)K((IDN5^YKD!qkPa3-gQ9q}*RvWG>PdiHkA|50Q3%d_iHpIbWYI z&d*$cOn=#ViFq37_owE@=H}<5Dc4_NwmDm$EzZuIZ=5fZhQAS4n9uw3%&s zo7k3VHCk2D_)oNGExG1YbBt8}(@pWFLZjKJH;N^h|FrsCU8*itmyZM^Sf@(0UBuMc;7f1zSfxJIWn*Rl#>C=58>HZrv1Kzl|z)Yqy zk#zqJS(US%gh%ycN%>!M=UgdQ%#|nY|G2Z@Fde!>B=vtoQl+eD=l}cuk?*X#pZfpb zpKU$kqyN7%`ddCx9RI&#j3^1lWQQw8W@8Z2u|{TF2MLWMrQO&BaKQ+yT`2v&{J(zjLB zS9h1WvR%u3pE&q%?*`5YXFaDqN`btVerS{e6t-!ULaFEq<|wv?>#BIOgz!qedAT2z z^SE_MuCL<8-lzbrQG)=6IqNw$QojgvY|1`KOHyegbxQ0$rUc^+RlM07HSEpH{V1Hr zsaJSo6({y4DYVuRs(TEx0BbqXa|RK?vQP5=vG*SEaTNFe_wGu%qJHXDvF;=nxuSD# z*mrWrRW5WRpKZB-i)6{z^c5H|-J*9addH#@O01BcK&&JL5=df^21!Uz2!td*tmpgr z?#|xctnOrs-~W02pVy<2=Dl+}v-6p@eRd{UN0ZoGA8CM<9%^3{M@r-;DwWD28HuIn zfo?KOArWRfxLA@9=}Y1#%rw*otx%N$qMO~R%sLwJ7smz3=nzO&Fk(G?j5mKhmq-#q z(kL*EY951ygQ?7PrXk>`wK0YoHVTXs@TwzrXnduI62L~h1(2ok$k#_Tf|n^^HWNA7 zN%@fsH8=FT;qEpNbN0Jw=|e7`Vl1P^fRA{M4x^yVE0Ke*GGqT8wnZ7y}=i!tuDidAOg*ehuW zP0=`TL|Cyyl0T{@-x>GC*YqU@q#UY0SYyg1HzJFbW$ zB65VOEi!phiwqkvf;RpnL;aWW*5h2MrRzOc#!*S)w<#LOY^ZqHoyI(l{Z{{KpCloY zCi=|`qZPAwSa@TI_-uAJ(Hp$;dpUN~nOvW!tXz2d+`5y)E2?&E+(`Y-cWkVplkTqd z&3zY{bRv=F9ozh|{ViG(>WpTE=?;qi z_0Ikl@xS@FF`?2-)>zD(Z*#AssdF~cpSiJBaxNXsaow(s8|!!OqNYEkuGw$Tncj1g zq$f5NJ`)9 z|FY@tcMf~}*%#jZ&nJ(+_Vah|jJ!YYN9W95duZnipMUVcZ~pS{FHSq_rEk3P$A8WE z_~#%0;;k3os4sc${a0}pH(&-zV4wsBN?@P_21;O{1O`fApacd=V4wsBN?@P_21?-n zmnAT^y!-}w|6eiJ$UWZw53!H`ryRX4;e(Vh{P1L&gW_49^BEhS8TR%p@AiZ`Ggx7f zgW_49xv{82dNvvVS>7E9m6ou^8O)PyZt*M+-=5fv-q*7{rRPpbPi#$-Y>|6 zoi(1xa$(vZ$SOzgO(?dW1!que({0z<|F$166$Q@xX*V` zJRg-CXWU2hJqIKmku>q}cNMKrl>^Mx#8d^0_wYAW$Cs!4@Rwga^!oOpO_CHzFdAe! z3k-5lWKC|6akF;x{)9TEtT4(!aU_wOVWK0+0|}MJvc?PtkN?>CU_zZ)tgwW+z~&Y$ z-Q1X}k4>LPEWPI;Nl$Dl-abSdN0tJ2F7x=_K0F*pLo~qqDPC21p7{XLr+^LgMx}|q zCzp(F92FaOHEpKX4m845T|;F3IrY5^1NDd`E0SR}!dw=qVh**r#W6~5gnb^P9!)4W ziY2BpC)(ViXNlYv`|4S8^s$6;GgxAggQDrnhr~op|M7%MOIc$L^GusNLN71<^k;4? zYLUiRq<89cSwtKGq>2>qV3BE#J!&1DkqV<(=CDS&gU5etd^({{1uIlDN88-}Zja9-lpD_yH4gTt zJswP`G?z72Iw%gs=EhW!Y|K~Ny*0=7ggPg)!UkrY&E5az_^hNSk|>(v=d?mqCeVRN zRlXp%kNLGP9-otBMKZ);5>lgBY6R18f1QiR=MyTPz$$Z?VVheVnB^m7p9kg_63Q)L ziIvQyHn*rp`AFHv#p8jofb31UTqu)pcA*GAG*Hy*Ettk`(Rc-?+5AOpo^DbuMiV z*>^vncl!V1(!QXv|1P<}t!1UTwMVXYX(!ScfN%es#_zkzrG2{Dt?3@OR(QKhd+HIF zHk0N6{0V*gf9knz?VodLE3F<1&}#CVS^kUD~LBxU^RS zZmovK0r;un);1rY_y4*}`{vKb%-m1+|2yXyC1St-$M|^YtHpO<@|ZGyE=040UQJj+ zHC!sEF<0B%V$=?KUpj_SJ6@9nMRkhn(`ftiC~)U8WYUuh z(l*@jd;FnGm(=4gW-s|xLcK6+EM(5Lxy3gP&bZ~Fy9xD9V5Jk8({1klH<#}v)C;r5LgrkXyC2Qv`w4{> zbL6KmPqw)?Q-5tg{h1q!x~JxXlj-Iy=+?-U7V{Xb=LeFQ*iN*W8>oe-%00~eM4tl2 zYcoC_qXx$uPU#uc)(ty$t=n23+gyGq35$dn%_Wy*MmX62=JKP2dZSrs8gq)x-T&tD zDBqRz(TuDW1(}VG%=&TRMtIdR0Qa_C&C3gMSC}LIl9`kjgPXXge_3|Bo z^*G($RDLF@id2aG9vW4wWM}{P`=2M&8^uafnUihq{hPJ;xQUaHU%oZcdwv;5 zN_-3Fp`a?=ec)R-xO148c>{Tp48PM%Q*866Ab@cb*7GY#Nhpi&$Gj9Yi!y{vftgJ4 zK!aA;4ZS0Xz71QyIkMBZC$_}i??ViqQK!@ODa61u=2j{_40b6Qx&g<_+N~Jy|NMGf z=OKWZtq=N8N~55~v^8oB9K_sCN_(gXC8HOln(pJDa%n%KasRen=+aWi-bZr)oIv;g-=x0(3#sq_ zZ(gDP`*)C^*R9=LAY5_y+QLEt3$kiR&qABfZ-+LR5@Mb zz>g4FmL=+Nn#L0nE?S0koyI+cNv4hPA|BCUb7e7EKh0-WZR8e_8do35*)%Z>Lcm}P zkq+L>Tn9ftl^2$#@h2kyZ7fz8snZQPg%X@iJAR1cqfdvIUv7q@@cxj}0wuqqDj~l= zJ4B%nm8t~%p@1JhV3O(Cod@CYDXoSjHl@I{PUl~=tU5FVPA)w!0>P>y)%{qDe8Gmy zWcow&1GP_v@~tSBk~eg9tl=#cr9x5sI_vs0C3yjSI1+Yn3DG9Wh?W8}={K1WR{0T& z&rdE|s;N2}6B!&X$UuQj2+XEpNj7VN*P5_G;kTh<_l|M<=@+csB=e7ueU;tKiM6kw z7$7O?-R>2#|1iTC(Muk>`0Ynw#zwUdejzh}ZZ2t|(u}Zn6T%OFG$?+OX)zYeY~B1p znFyIqUQhwEXf$(vthW+kJ!zoS_nH9;EUk}L14l&xqLI@NVeDIRWif=Wv9yvAyW0E} za<1)Vl{1i7;}?!&UiP*{Z|i!EFm7ga5uDmULSqGtA1V~<6)(b=V4}jJ)#Q(f#cBhz z)?RBdf%^IpjXX|Bs}1;L1H>&h4i<_H%)dl_RPxj_6C3%|W)_z(~cMYBiaN8(7b%_R6~AFVN~ z);N2{)H6q7#1!JxW7dP*X?>^cY6GT3h?XMBaKr2+E7tLfUeS9S&^hcewE0~|TUY?5S3q^VF)Est&C`NssZk(~%ldd+C_Zy*fWxthBOOZ-}HFPy(TwR6yIi7u< zB6K`8jZR@;R9!>a(Y2O&{V=C0q$vB?PtiOG)JYc50LcSs4*wZ9pVV$f7GogCR53g%ZTlKrgD+o%x1Pn|+|{QM(C zge9Z#^)ET*kSbjf`#E9o;WW^-zlREwHin@*DcPz{6-dHZ!Ljgx1)FKvhxhVYf(}QE zS$w2Rze8B1C;`f7cFS7bOky&XFkhi_iFraH3gTDRhN%2?3d2S>w)N1pzhBu$H)tWO z7T5mlCWNvz9lCU}8KQ9HqDYWr6fzzn`Qg+I%WlqlHrfjt)mRXDg~+wB9sKAvC4?m# z)lUn=216Ur?U%6yr2+=$4V~6vG$q{(xORzxGvJpzGA22oNOxC|(-%?{esaJVy9!*o zl1KMMIu{nTZ8I&{z$`y==?`Iz@Ta9mqeqaG3RP%g1RfaDR1cZyz$ivASf|t)X)85W zVVx${VUQFUT9+i&VXzb!T9+)=l^d(DPTjxKh|eEgr-^le=(^jNsoGw$4P?(GyMXKj zvVOAZWN%;U)}H*~Oy$u9e&xY=e&xU%zjAjCMS5t2vUy&;ek0wCzirL|zAIDLm&v7VTRdErAGL3ft zgV`Ogfgbyj?9Y;}NQcor{j5^Sqy#t&(q=PyuSc@KND^WLQHas3c~~gN%-Zq4ZTM>( zB~gfOk{+#qE~bweuMm&rNcM@OC{kb)pD_aMNLCrnG~8cf_wMOq z?^3`bX1qKe$C2#slCVgKk=0_B2{Omp++QQBM?X!dIDu7WGs8A_|Bqzd3H9c)#$x6o zoBMc=WdAT#3PjDBOZ&UgT;A*L0gN%Aw%Av}tsAcsX;3Tb*#!w7~@^iNj*m6pK&#?Ppi1Fro$s>H>jWu)KNz=W>%V-H^gQ|>G?d444u4n$Y6(7 z>F5te8-BbdpQ+=kFr2(kuA}(?cWkI1KaLdr#vPS;Qu{)Z6iF}|dp64qW)8Bsx6^k( z+mv;bj2NT4blfd$-?eR>z26wZm~#J0C>LOfam*1+V-FLrN%_h&sz`EppBOukn|emD zdQDWZ=SxXZY%VT{DrkkOR5L4y>6p(l?gf!CU!T299VPm2Nl+xfDA7!gzLZ&Lb02Go zPMQ$=hW6-x63UgcL^X3bb2Rhol<0pYMJg^fqD05hFEMc4cygyJV7yjpFVPJ&apnf& zn@syn$p1)!A_1aA5q&v}6fjGeB8$#8+GnFV`c*>33XXpYbG*%s?=PBY&u}(V?%`D5 zv}ZK(>weBy0kFO|M!!TZf)&YxwMLf zF74GlE^YN@m-YvG@83l8|NV#F`|lg()(Xfz`4GM9pXky$_qw%B)c?PGy<59xy-O=e za%+##{D0Lqy0tf`@Bd=5A5y>nORDL+0G;0dHz>-A=|?JWN)9Q@78;4h{eR5(|4NT) zo>WBPiQI{XaT={qm9v2*qMeOXmSvU?{NeP7p zvBXGbfH{oWuV!JKe0uPj9wuH{t|dQ}#tQ`_L>fh$7_TgiZwrl6!G?OHG$&1Peo2rb zsftt>1)9Sel@9Jy{QRd<3T#GKb(+dt*%{|B;*zw)mZG(6rWGo60s?VelFdAx9F8C7 z%%NLS6{!$8gi<9d+1Z~Q>OCG)%cxR{*fjRr<5E5X8@I`+sW;eA*$>>Sk8n^D)ZS^*M_D}dR| zcn1^vsmCZ&$En9B35o=W;|N6jEKu94OZusM0B-slz&fQ(HBq$Of z3KY>-vPdzroGG%%Cjkm!nqzq+aI_?$;xLYX26M8_{Wb3HN+m&&T2ZEW(K(V|ceCNNQKBD zRI6CY&i>?3@9~>jm@>z1>`yb%K{wVM-($u=9~!t9&XXT6DC_weusK$ko|xi81Fu4_ zvzn>Heaz#`iavDk$TWxFe%m8G-mg|F`%vlq!ui;r|Ju`b?Cw|T8-Uf@>HeO+{l997 zODlWJr9HCMtxf;2OZ(0_ZfzAk1Ne}h0W{Ja06inzTIU+Me*3kuwtm!1LK`MFCQKGChcM&ti4|F%o}xXGnmN;bRFtv&cHmo|2tTl-dr zOIsXqYrpbS-23VKfBFVs)w-k4-JHBu(H7a#?_aD8Zkxv|wB_@axw`4+r5`jwHz5Pa z0(?LLPz00$exMT2))G$ z4fue3pa>`d$^bv0>?b4v$v_I=0^EQH@B*no8jucT0GU7*kPYMkg+MV-1`Gx&0PO(5 z1*8GlKmkw!3H{b!hKq`<1qyw3N56A)XfPA13 z7zC66Wk3Z`2_*RmZXgxN0I~rekPj3AWx!yd9Pk4HpaQ4_lm>zdXh0H>45R=qzzukS ze4rfAbV4eS0b~NXKoKwqC19*W{zy}lpWk3K(IY>wc zGJs4V3&;fuff8UaP!9Nk08jx`0?J{63TQwQkP2i0c|bl;02BhnKsn$Cl0GGPflMF^ z$OlS*0H7%gDIAajqykw$E>H**0VO~wPzDSJ$^q3+NCJ`p7my010qH;{kOlaFe4qd* z1d4zXU@#B>lxji}kOH^?58wsTfh-^g$Onpm5}*ty2mC+)s32I!L1j6uQ2`A|0+N9g zzy-L09H0Og1QY{hz+k`+R02tB3CTbzkOkxd1waW<4yX-;WFQ6b0BJxb-~;jqRyy;s zrT{1eihw~tF;D`O0%btbAwn{c0=NJ--~qfqDv$=G0~tUjkOgD|J|G9k1@eG=pb#hm zih&Y>mCjPEDFX%r<$xau02M$bpd2QsfCeN1$v_I=0^EQXNC&ck93T%U0E&PTpbRJn z0zf68X4CB3$pBAzkJ;|6bn>kCJl8!>bI+68^KAA!eLc@t&$HAkA=*3%;Hl?%hIyV+ zo~MuJ`QrWXRo4=D!grqLo#%DuDcyMvcb>kTr)tM6?OvXko#$ldnb>*i_1Ib0t#tCl z>pbT=&$Q0-tMjbtJeN98pUyL$0=d8-pcL=}+96wcy66YBCqgz*0F(d$pc2py6H)*#kPc)3 zJ|G_$1e5`Opc2rOMYI`^3S2TJ4EmRnLs{J02BkIz+fN%R07&zLNee6yg)jT4dem^Krv7XlmP)i zJwiwZ+(0V9N@ph4zb4rBnCKo*b#cnO{{ zsc>e)Il%{KKAckv;4B1+fI&bB!85BA&N9G{-`3Ljwf05z#r78>FQ_lHKOcGC_k725 zk>`BRwLcqqR(-a;J<{%L?>N|aFmSNrnaDG~XF8s4eA@SP$5WA~)Ti2>tbMZkiPk5= zPjo-t_IT~%>f`N?MIQ4#*70cLqk%^|A8C0c_(<2otq+GE?tZB4q1uP^2ZIlGJ<$3< z_<`>G+wQNuU%kJ*Ez;&|>p0MOAaJ1bzLxuf_jTRddT;pN?t9wqsl7+Nr~U58-M+g! z?rOX%a98J@%AM_ZMDFn2(Q$j@?Sb1nZ)>?Ncw5)4t+$46?Y^b$mfBm?TiS1q-0Zu# zbkJ?!tjON z7qneadx3s_@cgdxTF(og*S)80PwgIcPy6o3Zr|>Xa~sbMoZGppWmj-lS95D~xVgKj zt*N$2ZED{c+3DNa(b(7+XzXlI8rpY6cKCL5Y;W8i*xtFVWm|At*Vfjp;jP{0w4GCX zj(Se}*^#q-XLoFA+!EN*xw&O?aC6tD)=l9}-5c9B)^616gY{h-S~r9@bgyq)U%Osi z-@Y!g&bO{3(ijOuI@h+W4X*8~Ypn~{b)VICR_$5pS?y~gYkX@u&TKq0aAxNj${Fpa zuRYy&ddF#vrv*;yJhkQ2;Hh1ww4M?^rTgTzlWR{_Pi|iwS?ychv8r)ZU{&YJmX*Pk zT`O8wgjaOew$;|w>dS-6yOy;s3oq+l+P1WIsk*d%No0v{Nyp;G#ev10i&_>17j>P~ zdQ$kL?uBg&YZs~u+ZRL@_!e}`Z=4^P-#M>kUT|L5+}63_x!rTx=G4wn=d{m`%=XRh zsA;ST)O3bh!ohG?s5KN0bRXaJr@#Ksc?Cw9(gnGu}PHNACuczXA= zwrRD~)M@QgBU61-JEk;F2~6pn+%h>hxocAEr0}HfiER^WC#n4xr7~FA zRnb}zuILW51!@Copxqzw`}`f{jpc#z&cQ8%gM+)uTFb&^-KA}%wWVrldr73kSJF}3 zSR5$s9Mm!>IH;?rwJ2QFUD#GwTc{Sc7eoqt1s(Z~`GNe-yq3IRURQ2wZaB9)r!A*8 zN6l&XMSMPAM|NX&AiFcGB`cWKmD!pZ&g{-;%c#vzGuqQ5>Av)iw8peRT4!oYYB06S z+v*K_yFG25T94{!cSqblcZaLd6>xQ?w4?-6x{_Oy!^z!AZArCBYEruv(R^Bm+NcK9 zPP(lRZ+Y#BTj>4&PfjxK@wxy1!GH1(eut*_4C&(`3cR!FQEaR+CP$CgyNzaHk9iz4 zv=0rudNlf~+EwDcQ^m~3Zlz)8j^-UPD#PNc7_T-x6nU-!+RbtHq0@VY_aWn@*mLP> zHr5z@DYwL~w0a#HW9P->rm7DaeCd@-Jz`=_g!%_HQ7<9M=*H{XNK;e&&e$h)Bl?iR z>zh1&iDHk^D71CTEk zcaN5>U0yoy$Q%^aQ|b4p0mqN>01clXblAh&w5Q-ZLhSoEW_%D(7XPY-U}Yax|Jn zoikTsbHp?J+9nWg+8}B;)i^XP1IocTt}cmtqKEg_)-baYRIG z#Mgp(bojuT3e070rb9=hmkLYPxt~XUq`@(@wcax^j+DqxRLaXD>4~Kje2)ehN|lit zy=Rgn0WTPFaKiV6Mkj2K0(T}8ud+}_lF^N`p*bG{Jk2tjEU5@pQD*pJ(ZiFwyO?g~ z7HZ=DUK*Y8G0_%uD357vQ~FTBH;`%k#hZ(n%EW$qUN1G1!hJj&aQKsjruHF(4=c0j zy*Lg?U>0)&6_;+_Q+B;M4BVL??lriHL*Q)bEB6^Dt!hF;_^r3-p(1!I_koN z^Oa=u41F+VyH1=u@I@qK#c%9U+zHjFxuer1agi9~rDGOL8U4HM+|2dnrv$|qx=F$* zxwl!|XC%}yI(Cm^HKTjC;oe54<4vT+DUM3fF&9O;t!a}un@9(W6D2jVsrYs&TBKQA zyv59Zoswt9krJI0t4Uj>elTE=n9YnQ6&=1@R9IgXI7`wO=@A_cpgEK^E18D-_=YbR z`}xsOLa{0qn8BQ2bBpT_xfYLYNN~L;EU8kC*ofMU7O{sveaL0TE8>I~ST%8^L~Twb zVO23Ev!6!pTm_6L6&<15s?B)c*3OoMMM8{f%x9UA4j#kMl0rFV4^evNNP1kL1aZ&_ zk(-7hXNHMc3Rp)6oISl9OSAL>+On>GPeWw;2C+{%yVlN?L`5QuO!`=2n1lV!Kp^`W<8RG#%f# z)@`b9HczwW!a8tU!Qa_VtB;m#ce}MoGzQ=ydiTHbeHsri)uV0x zhD-Yoz4yP7#{SR$CCvvw@BL@e*#GZsa%nrsW=(c!55DNqW}WQP4%55;_3yZ}&uHww zD}L_M3TXKZz55S+=F;AI)}?Lwkn~zy+U<=lElBo<4K8iNT6+HDo=|TIYn;kF+2$7A!ss)TyOSZShz{b`b`6Dmz%jd{#DHh2G<!#3GJ=H&yw^+=}>8sQ&p~H{)oAc zn8(Aj#k-%$;{kN+j}ydMoS&d@^2{r}I!Rb0#3|Bsk!6Y7m+r5Vg=Hn%vA z$pzcj^_Oxql2C6JYn;SfU~`K`BkvZ8_x5!OwU%)Fr!Y^pxy9a|Ox0>LiBGNTB`L9? zXfJQk3RUT5zD@KgV7&GcomWBJh4T5;(O5P}sv;FeW65QWDhK=DSn3n%jbf##%*i%) z{~OE3gnBbrW443hq$f9)_$R$hk`7f38&P|o(Jxh5Naq?=`6sz^nel2bSI4+&F?+l5 z>d;Ytn$v#R-(1@KOtvLqd^6ltmlZje!#o~@D$CxIaL159_PDyK3R6Y~@>-hL3B zR>(Sv*`^f|>#XN9<_U0{lm?L|aRP+mDAu*J|NF%DgnDCHX$Ete&E4O9Lhsoj>4`EH z46SEZXILfoPuiKg>QIQByo{$Kzke&T1&s_||a?%;k9u$?@ko7{4&_CbWTNVrDHo zdO<>+LRJ{eEVH?HneWQwz1^7Xe%A)4P|t;ukgW*GsVaZr!b_nTRpqbb&Sl0sLg(tG z)HNXHYS0*}Oek~8%p=-GlC(&QXqb>2$#Qmz)owo z7Lx|cWqJ&g247+dqKAgvh#qFqeqLVg?S&z;&^+;+0?)5w40l9GRq7Tl#fYYJ7UHd& zac?x}`MU?cDH^Is`E@cX=Ob zcqCTDqq=#SJ|@)Atx_^*A9SH&>BMI2iaw<9ZoEhVz05o&s%{7MEt3qchp6LR-NI!x zb#s@}FurqFj>CI=k*_QJ5Svax^A*s`Ok>uQ6rO@hMo&_bbhk2h*}SSTL9{KgckPR# zB6>&7qM-N?6}^|>&S1vNlF^~8Zp#ijFj8PcMCrLo5)q=Hkth;Vqq^Z7_JYCy|)@;@SvlK9wSx4<)YcIR6(d(;j;#@Vsw`aXo_QZ$7Mn8hq$ zqLwz>bL2W9MZ1T_|C>Pe`}E!aS{ei3b9(o`|4f%Qa;r;wo!2-F=GN&bAU&s01k;ar2vi? zzAXh16EI*kOMD;&5VJ8@0e&L|5Q(({{8kEJHV0nI5=W!}SSbt#=rVtas2#cZPzvD4 zMXtH2h{0%@##StmCj}4z5rhNeO932-oGb-!#4tq)fbRdou*6g;fLHj^k^@YW0${QT zVK~5aDS%J-(vkzrkOE+(FdX1SDS%t}(vkzrlmgg?y5|71qyUcU4oLyhWQnj8z){^b zQULUX6^7F=TMFQ44?N)vZDNMw&lO@~xJ!z`QIdB{0YprQh0}0=qNI7;#nDS)G(9+d((j!} ztV)9tOAMC+I7+fg3g9TH5mEq0b&r$+IO<}Q6u^(vnT8WNPYU4J{pU*o9JyE^1#r~n zLMecwHeZwiI3)hoSAf4u0URaysT9CbP~B1h$3g5LQUFJL_)H4msH}fV0USmBxfHe@ihqD(gQ|fPiRDwB#0bg;{+?~?*JBo0Uc9Cgtq1#ndN{Zar&Wj!DTFn@As!2RWeQUJ#(=^-hAf%EwfTKwNMmt^#;Hd5iQUFI~O_TySs(ZT>K;#BFcm#0UUMFBn5EnSO7>2&=aD^?>}0Y9 zWIr#~w4alGj_i$O8_6ywdji=^vY!mnv>%gwg6!2~w~$>xb~srV**_F%+PBF*K=x9y z5wan&KzDD*gvgeaMjqDV%g=D`d(6o2RK2P>0vOCGvlC372MfPv`n)Vji zC&^wz_H42X$ySkdll^0!rhSL(gJdrwyN+y_te zIhythvM-RmnQRl;6=Z{Cv&sJ5r)h7KeTwY0WX~ac64?=CJ!Jost!dvS`w-c^WY?3e zAsZm8kp1nNqzmpyUanM`_y6nvyiEP%0U85%Xw>G@aS*@BgaFfRec<&aH6*hwg@Wm` zPed5QRL&MI^D4mnc_bv(+jlkkymOXVZ|*MU&jVI?`+-(brdjdFezYGAAJc?SeQK_V zKlZcu3v0xB`)wSpvve`=bJT=F!fihy(ln`7JeeW@FQfUw8wJZ8XqhA2u@eHk92V>C z#|cF_6cX!W#{i9{$Nua@IjCCs4TueSxyMRpMa+7yRi2eG>+iS1pAfTtxwU>m%=&>J z10^s}0s|#5Pyz!bFi-*mB`{C|10^s}0s|#5Py+wAl|b=FPd{@fz5oBQdH-KPH{R)o zH*+%i-ubBYs{Bu9y*ufOw^iKnx@_4P_xi^#%-ptS(T!(aJ^Q8G{m(0USl=-1Od5S} z)6U2?Kl)NMow;qx`kgzPc5H0+pSz`LS7fWdsd?9iEj#?dabv5`Ja_$>Teh#?x@$xI zncE^;x9*^cZ^aTiMl!6YdNYbUgOm(BFV+4}C4wSX0_k}h4~PMS348(HL67n3n-RQFsj9Ru3(l2TF3vfWKc0g zc5dQo;bk-#)?*B_H1Pa&8oW*8ERC;GEml`d%K;UmJgny?_mq6@yXtKf&zaChgmETh z?$>A^yBjbU^~SMVwr_2+xglmGXNb_XwUYm1d(GA@+qN`Q4^^>@CS$0S3_NACKjCwh z%GYSD=SGZ?w-FRPFYBc)YliWGCd#(Nw4vr%VC z7k-_TZePD^=T7?8`#df%`pPcmw@Ayta-akTN?@P_21;O{1O`fApacd=z)=EU?DA@h zA4=7Jl;_drG<&qyn>^as&pg^gH+rXM9b(EycF0Q(zj1pab}6u|z>07o_-k^(p+hWL$DLc+Q^q}7~F(a%N% zufZPq7uzApMX63z>B^NXE8aroZs=07Z4p+Zr}*k8JC05Q|nxPbBsP zzCEKcIcWuEHHQ*d%rr)ps2737Qcu<~y&Hyvp#eE}t#9@lV~+Uw?v5Xt=sh>aQ556z zMHRDIE1!8>L!0P5H^mVVqXyxPXaT<$^)mCB@rKO6h}RiP9S?OgXYRa(OXto(mW>R3 zb#otD%PHs}1@tm~OpFMIYLkqPk#0z9IVx?#mYo%6p2>IJrq(TeXw_15#XO^emziVE zuCSZcWGxy9M5i%)b_=n^lG?3(sGUg>j#fY~Gn=`U^R-P9Q!pl`PSX}6W7HU{sPWhD z*jQ!dbcBBtb(I-`&CJZ+)`$FA6m+x#dYL)Qc=E_>g(Y9t)O!LZ*%NSk9|@=@=>i4x zGP9YOd9uEjS>%v^ud;IP+(mV>SFZ@tRwAQ!^r3@eNC6*7yv%IoG3d-)I%k|s=gvNK zHn9%qrAc5gB@}oJIxFX{vX7B;S06fOQ>>*5=w;?H;~i8mAQK%|>7cSSyku_OlJKeH zCfU{Q?nCVy(kbEk@G^bOjWi-t1J@UMM-A1GS5H&sEn7Z!DNEUv?&(7bb2^mpkUL(c zkBI@h&g*4#Aw#KdrBzQm9(W$JkW8YH4U|935^R*m^@+1_(>D&nQZGr@?4eyy$YDl+)n53tz3t+Dr$6^&X69J zFI~NOvAuQN--pH?ilLNdse%TW&P=3{#Tr#r#z=-Es-wpyrRRY-Y6aXi&8u8S3S*e% z%wfzr9=^-jLOjNWLR~{0&e+)3+!R$3BWl!VV)I@0uREf-+Q)FRbB~ zsPsG}Nr+eq%`9C(D@qhFpIO9=cV%FXM<%kPp0Nh;nNknOkrJhM6$PzQz#?XViPFQM zagxzf`Lc(Lu5RP5?dy9hzeglRkpiRqDmngPOeuE$c}(T^s3ajG64!G3X+@y|`j`dG zjkI^|=;iR_qJwUhvaw-DQ(ZG<4O5K7T*o~YM@?K}wUSPe0(zN+Ok83?Pcp1Umm>3) zFQa2do%15=@jldUp$ID!(96tV#+%kUMM=>MF+=l~?N!5~^;R|FjOsPfolO7gi9S?s zWmV9tfSF7~)tN^OK3N3S9lM$(*^S3oZ_lWAz}juE0CT&6VG;lgF7tXRcT z_RFk;eMsHQQlM7>Gns~z^L7!fhNb4!%wsA0Ij6l3sry(8^eSK`(~!c|N{or-YOx_T zfu&-?9LtZF-*9P5$bR^`OFNgw|4S)zYu8^$WB-%I*#G1I;?llDWB;w2=F&bL;npsH z#idnDb!pFf+}a$P1MtXvm$q#(jqgWe{_Usv|Asy6(q5x+|Cj#3rTuZQOS_nC0ohw} zJzBwMZtYQ;`)|g#XpX=Rmv&CAOZ&IqtzAXq{|!D!cb3RmNYAn^Mp9A$32+Rjzlas~7gJxheA!YO(YAU|^suP(yb?#$xDYB*o*}s!<`CvcX1oU_C`c+w`W{9+ zMbl_|qcJK+zaeP}ZQ~MX0>?ayIo;+KTJj~3IXLS)`u0X#Z$-6wUX`@q1!Lr^R5?iQ zmCP#USSGZ#_Hr#G^0l?8w|u=OX$fs3UlTdz>CCA%w=rz0Uy<`=Ode7(_j)wZ} zqO$BQIoswIS(8i9n7+9VErXwW(w6|ue&+zbM-L@bUCl}xnd@xs zI=a=~K|`233lz^j>z2?L3CyElBC3j;tuC|S}{QZ3z%ih_0;_9?PK{Go9Q0DKwrPLKC+XpBKdw)wO8PqlA2IA zDsVW*J&rln=8ji^iQDG4C9T+;l`1dNiY3g^%!$l+Im5$)JVoTJu8Fd@eMen$>}2%c zkt9VDjO@)~fs>f?Z0`PL@4J$goV}N6#T*5!Vvb>Mq(PW5iJN3}Tsx*K8`p2$(PRww zY_GNNNm4@E$kt?zxQ02?=I&p%zAtHsgo*?5E3{&Y0#-4DOlTovlF?JmBMRq>zNh44 zr9EpukmQ8Ck+tz0`6Q+kHUE^4D7`+e_@N{rA`-{QS7}9^0uE=6VIoHxdZ{RJjNB0K z82KYfPRJWMn!u6QFsInu@hU6LC_o$|7tqw`Vk~e_;E%=t!o#o%ZgZ%aZ#*eJ=d9PL!*M4LNaNhUs6 z{Y26d$rO#`4O(%c0uEu0U?NjH=}$6ZZ>D3^4tx|DdyqOTNeO8qTh$!#bmnB6yMNj0 zl(a-b#oqi)TCqR@tC(Y$8>ybQ(lb@bh-_`#x~s{!>ap+1Kb53}w2`gp9PvD6jm_P^ zZ2e5q5(yRAIz%gGD_|9KG;<@pCaLe`RUR(&)0B;y>YLX)D(mNxl2A5sHHqU5Gf%X+ z`7ZtVdY`+ox2PP+GB_ivZ>1na;S5Nlebnm~H#{Mt9-=#fG z&j4oA902dpz5h9f>HeRVAAE1l_IqjkzqPB3Bwl2W|M&QCMG^K@x(36TbtmMJhZNf`@Y z|GOz6*}vBE&!+7{j*{JET{J$SwH~b4qf2{w1E&n6oou%_>Tb*pw47D!O z*HZqJknBIp^8Y^hFMvO3L`}Wr|7Cdf>Y?x_8#Q-Y{z`c0!W$js`-$meRHd z$VSa)mj6L&e}9G_tYvbOg>ysA`0-64#Wo%ze0E#@hba9>TWtCcSpHLLjQR~xn5g-i z<$pN*n_vH$(jVLYMw!Pdh1%~EkEhbM2gpXvV#{9-zxCtAI$?^}G<*#6A8PRn| zQ68oBk2>o2SJw6)k$!PVu78h9M0JGr@A2dxt3S^2pHM?(=cu2(mOt{1yv5f4&6a=f z_4lgfzn`|xcBJop%l}K-|K~a4ce@qS^sb+0`Q!K#!uDjN=0wZ?Ju3gvV+R z0NJQfy~5pKwvSLqtif`S<$sXM=UVbRL^f)sSpI0=*fw_i4VM2$;e|KuC4U9hGS^!E z`^kSuNKXHwmj8^JH$HsA(Z0Q@BC1E}_?7S2ezfI}^V2Yg|7^?u`{64hw>#?hh~@uf z`0_9K_=hl-30ng=;QYdMAF@2jak=F`y5@_j4`|y1G5&8`{%HSx@{4UhUs?WZ$$zcG zKPR0;*jU?#%oV(tY59xtiPeu-{)cG05LqmvW=GWDJb&pi{WTR%9<^K_tk2C)Dmj5C0NB&~BzryJsQ@>AG z{t9i6ZDZ5_qUDeMi_;gg{U0rVar}wh-j^xzBKD71|B05rIQ}1^G(^oB%l|z}-+PYs zb%W)P^ZP@zZS3~1TK>1w_C@5MP0OhHjpaYOhI+q|Kgu9##%2k3bU!mjc$dFM-mbdb@<$ol6?|aVr|F`9j_8+3{W79VzTf~)IL*wH( z{7y7mYWcq$ZthGWzu5R+viuu_eoXzpZTXA*$JXzEZT`KTKZg25TEzAW zr6FooTmJinevE&E<*!iwv2CpWQ-e`*$sWTt8)# zA8gbVM{OnE&oHb9%UC>e%Dz3Ysn9`nrzfOV);WC z_DCq|t0*0o|M%(ml;YU_4>o_ge<6QpL``~uaAQ5} zRz3$U|Isyf-r=RRg<{h8cgr8gi&Nnj5-GycUo3vAg08x?aJ#G-Pc| zjt{9#v@WBV}`BJ`)>&x(KO*!~=w|LWE6IJSSz=5NFwtN)4R-+TLT z{+#!aScB!=mVb85h=*===zn7Q|CH{xocFWe9U@{&uThk19or8cD*SPLfd3InN7T%- z{14Fa`<;-Y?2qwZXZgPuo>y2#{?#%5cUb;khUd)T>v5#PGAoA(XEvqJng0hZ|2Jyh z_`_YaZEX8!9xk?jIeg_m?sWJ+VEK!1vD-gn`HSZTvGq6Dx*oRfM`O}I+36n=N?0zp z{6+kFjQ=Lfzk$llPkyoKyDY{Z?LRhs_gel?V-qr$ytv=tAG`fS4uAXB1MYzm7$|{( z5*R3fff5)ffp{fQH~S|qA4p!SyndQ3#QsIfUm^>5MfTx^%3PhDDc|zZ56_!9;J0(Z z@8p5s%?H0%0Div^{6P`;!$IJWioqY3fNzz8Z@Yn)z^PUaU$=1(VajlyuOQ z0lG6mPZsFS22*`tS`L_=3ufejnfYK=0hnC~`ij7uL11n%m{$Vkmx2XlVBuh}s2m*R z2a5w>Nd;J{tR*%3N?&9=JLmJh=cor4T%|2s~{NczQ8-MhSRkDY&K#JZmsmR}QZA zgOLDHWMf?gR;{lDHz@mw^(weg12-jso0GvUDd5>I@EkX|)dOzxg41s^N} z9~ulkTn;|s2OkZ9k5zz=SAtKdhlo#V;8RK9)5+j7Dd0gD*zN|O^?=WL!RJ%K7t+8N z)4`WAz?U<@SF*rwWP`8zz}IrX*K@%)^1yHAgNF*hjzXfy#dismw~N8=lz`tY z1;1AYet$6dgL3ePe(*;D@W&P4Tb1D3>S5wfH1Kc|*qIFeGzI*b3;ekoe8&U+!VA8e z3ci;H{xTi>RR;KeCip=X`0H%&H$L#UIpC38uq%%!vhiU)R{gF3{Cy$#ha&KggTOx( zgCCWEAD4oEE(8BE82oEF_=z9EO`}uqTs9U0Sm6L(L|d`EYAKtV+rOlXJn8JkXU7x(h&0 zA?PgvQwM=*#b9~~m{AI5mVsG=!R&I-=Ld5FU~UDNr(_fJRj@z<3zNX2WN=UlSnL8z z++e8(Ec1ecQ^E2y(4P(lGKeA@6`5F7nFS8X28a5EC5Fpf}@MT zF@wOd#o!4gV09@NECa_42FI6!6a3)B063`voLmV`QLBklHE>!II6WDhkpiCR0%y9x zSspOt1;eRCk&T)(teTw;&dC7hW`gsw!1>wW0w1_A2RtbkT$Bec&IgwifJ+O(Wkulf zL11k$xS|AHSqiQy16L0QPc8>f@q?!Zz|$(g(<{L7=)FybPL zY^-x*)p`%O!3)->f*aGoP3hp~3~);(cy< zJ>cbD@QPIM$~16aI(StEcy%UtO%`}Vl=@X=K8u{7}UbnuA`@X1W@DZb`+)586ja^RbxZ+5-W@&?0li|1>Xzp&(}WR{aovF!RI=k zZG6`EY-ykJgh$4_E7ktt_NEl3_RHJK;!}Sfwub(w>7r;+S(7)9_YTW z^}gVJo%c50>$|u8p4xl5?{2+2cz5Srjd%I(YQMAg&h9%}?+D(}d3)pSzT4YxtG%uJ z*4A5tx30ZKy`}Bu@XcK}wcHfAspH1Tjp~hUt>M#?ucckD)w?fgy(D-^=f#Z|`z~(3sP-cL!oY>?7t~(ReSYit z!Sg%MYdp_)Ui+TfJ>9!ocL#TOp4)h?@7(rXwY$2TTbqN;olT8RzNYq_wL7~TTN{Io zoefGu+m7&#uI(+`1KT^cMYgHi+O~$bcAe95PT-u5vm<&ov;^0sB+WnD{KmIjt~EQu^pm$WSoFYa2@vgqJRwI_8i zY+V>!*twu_fp0w0KBsn0_w3f$!P%WPjWxcS_Hb>uJJcEq zhB{|8&hpI)&Fng{<;1{=9Wx>`)ERBl!_&K_wM+|4>zEpus!na25}wjExn*)-a>t~| zBz02T#PGzf2`v)>6FSC6#;fDo#vKke27STy>e}k=6IxFQp3phAajb7_`-J@Ga z2S;~~Y8>So)jqOzWcP^H5y26iRgG1?s`lZv!@GyI4hs%jJ5(LoHY7ZxtFomsP}xxt zsZcB00^vZHzr`Q$ca%rU)$+E%;lW*HEoFhSj?ze}TH00;F6k<6DGn5O4EnUFwJ1>3 zQ5Y#y3)>391zq_q`GNe7yhxs!*OnX3?aFD%3FLJ6B0kmEmL1OS%4*39WOZalGS$qs zjBrLnx-Y#wtv0PYwKX-E+Uafd`n>I)T2HsT)g5$qx*AbXf8}%jVZ0tc`im69OT5h$pG+8^V~pbu zA|^78aIsWlf9kz{F7~b@A+`};VSI~LoS}eK%(2XP-Dp7{H>-$+_wL!;FfDc_+LGnqq}Bbh==gf^GD_zoXm zcJFYs`rk@gLffdXAjdp|ImPA{T5^3Q%9q}AMA8x|txyn;s{DYM#q`+R7_6b5hiVhy zd5KXx=&!E1o`*)nIzEB6B~)!@rOTNuHuu;0Ecs(eF}6@km3L^xt<2HPam;vy>gHW=BMLRn zSOb5S^n|`qu1h)g)0rpR-0{lQs6^fyjDa^|&ZkHJl2B{|3!KMnw7G?tyz3onCH^&` z>Se5SGjqSqEh^D@0_t<%jh;^=MY$5+r4<(|U=?#L6GPSQq$8VT%+t_DV`5szY3Of~ zme4jTa0owo7G)~$7>Q0p%F(|k)Y`!D?`AgI+|b%VIg{(pt>@FwigojL?A#V< zj(6BR`e{PV^I7LYrc`eHQ?5NlPg0VUv17-=*F5WWO9~<$abW%>tlK1-;zk>fv)*<^Enz54oRLd^?V=VGQPXZ!M4 z>g#h!L2NJT>wQ{LtAJI^(M;6WuK1tLH|*-=vw3<<%tl=Q3uU9O#&f(=nUihq;~r}1 zUkPRAaMa6~i)?PuB;?&H;V#_srKDwKFnSg80j-#&fK|+DCbUp|lCi$dN9o0Uop0<~ zNB=FU33a0YCv)5Dgp&gw&gN-?iTFcLqa_h9oRY`+1+w`#kW&FU}myod0QaX6DQ}zXKh> zcaDQj;0<2o$3OQd>rco0e`x>R^PpF0x!kL~;PNUd%>Vxp=Kf!e|6gMMfByG9O7vsc zt9q1k@c(=Ja2)=nLFfd$@W5C0;QjvtYwfwUM*78GvqQjx*YHbn-o>F^q1QuqcYbAfL^GEYH1HWnA!LHeVl@Yww z8%)gpt0b*5jbjfa`0kJ*<0JJQSn2S_;YION>(H>Izb>3XI9sQF=w>vW@i$}GKDI&x z$1FqgcZGK1C}w9DvT*=e%k1nDNyY)pN;6AEUTTAvN$2TE#d)s$D#^RljOLVC4W6;& z{#8=&^(jB)0Q?4UoOcX)xm1*&!-NQ08oEq6);oT!S>C%54PR(Jju=CEBSPNAjdDsx zRxl`f?h5%}W(+yC6#u@^=^`iO{mZ5B>$CnOjbFmFkBMlEHTLg2uw3$s!x0!WU@7Ya zGTs=xM)DRz2D}y6LQdgFEwmdhBUBVS-z{>l$b^|WX62R0II|uiBzfo>X}LnEgbNV0 zdUxno61S_&Y1o?SabqS@hD#1DRr;8*_uYM2r_R@AXL8=O5MMHEZpdY(`+otf}xwz(Y?GG8!J; zmjv86fps5FU_DA0gqw|wj|dTMMEfvc5bjZ+m53AlL~IP`A`*F^kLV}V37}^`Hwo7P zpoIt!9fX3`TK5n>G|+mOaE$>y`v8M*O#-dS)so&xMDswL=p#JiK+Aq0L_{YVEs97w zvT?d4iA|1}bx>&*DMfn-c^FWMz!(rC z;)MSI5Fx_JRZ`TK2f`?rXg8svd5v}r4`aVkpoi$n1D;8s6WJH-CRAigw0&%i6zw3| zCV?o?4TOU6Mtpj)6-xkNaS1>*>7$Qta;X{jouV$aVKdw{xl;0>o-1fXL~?L_6#K7~ z5(=W5(1>JYSW2jafR_jnK3r-Od^hPGK=ov+%Cltv=Kxw!1i@Fvv3rG+?;5b8E8&x_ zlKO-DfH>iu1Oj7MOZ}aMC$bhh6MaN@c)6s#K5P7=k>yg{jDI`!;>~~=;W)P9)A8qf zWbbSlz<1+OGXTC*?wAUIZ<3?a0r15?u24REEJU`o?6n`o7v+uk1n|RjeDrZ#`VL8h zIJzC))0yrWa_)ran2~GAFGsmrspB{bZEQwdINE?I@R>2&XODn_t+<&t9Ptr1Z)-TP zqc3#Gj#|VS2@zTx5txo?m$Y2!HiN)wHj>eINc8kEL~pj-=D34Kb?d-B)8QqsWvgy2 z2y;e>o2d$q+Kbtb{A;AjKe<-w>m>}Npiv0XL-y{*maS4mhn7p;L&{_-gX0LI5z#pI znvQ4>wrmki;*@p29>i^Aq+d}xE&@Y(n2n$0tW%ZLYOc#$_MI8$+x zjWbI}6XeDnR%pJsRKX_-pVn?7NrZ9D^5L+ix0Z+8SSoodN(}Z39cmmHmNap_7Z=E# zi0Ce~uscIzR_r<^R!bUB6W%ED4ye)0B!zbub~dYX0v^#rYsmj6ikGdOqlo`sE4W{A z?lF`iVE3emHE526SBkw6rly_%$mtU1%HC{=-T*c^& z^b6VN>(A=XW}hiMT`$T-V?6g{?eY3!`eWHg%a3Fq(I2TioO{^7Sc}5fQeUe*RD39n z(H5l#GY`rSmLJGsyhY{yTA`lT^VzSK@5$by-&46ehtU<)y9#%u?y6v9Md9|;?b+M( z+fujIb`*D{F{YxlJ+ocjUf!0)sEW$g+*V_2HCMp6irQFlEIn4=QreQ)B5x^g&TiH> zS8g8ra`MK>jmZtw^#zQYsI4omORuYEOBgpHXUn76QGK+6krT#9_4>l~sq1SPJCVMw zer@U6%(XH`Ph_vruc@rftu-)yqHuNU>e^MstI`-jQMxj7rF>->qbT$%DwmfpE3Qee zNe$~OoV+w=c{HFyWONqBURHJ<-@N3Y?`wQj5zz=f8cx4pJo-yZDl!|6OAnkm=5 zWm21h9t6$6(eN|(#L1$<)4wx>o0%!Ee(bCb;PKAB-vB+AIy_~Dm%z1mArgJMe=aC4|ic`9{Ge}UK+#jh-&*+!T6M42%FKwK0G0ujsvaE z5@`|-2VLWQ5FoS&eqRcUT4*UdNT#D6np`1i3qpGko*9QYJ?=)Nu&a4|KmQ>|z`|7Yh?zM3PYU0v^Iggot*c zi!cb!J|IA}5q{n=go!pHMsyQ>ggOkg5J94qh!F`w9tFHakZ2>~L?5B#0T1CLB1DYn zA=Gi8gXkk#CIFr2BGkP=h=>vi!iQQJ3lr@`oM@5Ir=$~IM0XNM66z2TAd-Y@7-%CB zgfa&BiFTr!=qEbzfI;ZvKqnDCKo?;U-pDW#L&S()qGJ%~CX$3Y1auM7FrX2^F+eAx zL?n_y0>^+Tksy=_z)uAB0ujQ8=iHcb0Pqm4L`!}(f+E`SEQd$}$^_scT8TK36n^{Q z3KOm4Yt5TITXmf}PxU!|fcx*$ah$z_tS!IM9yEW(xe(fef8J%G zb4)Z(xC?BYAMVJeFLpp1S|Bv2qCG?_;Xw<;O$0kj<6?HPbReI-JMsH2>!AxCL9;E? zlIXM)J*$YG*&2r66>Z;tNNd=I&1gUFnMDs(2K)MuB=!Sl&w`lv=7*93G?PHDp zHuf0%kaDxP+Sa8yl?(c8yP7=*=opyVErEEu85*19d-1(1G=D1E5+3n;I)~Qq^3*6; z(b~u1g%g<%@q}w^jns-b^ZtE7=p6*aMt3Iy6FsOb7WQl7fmt{}Ve(bVkW7@d*G6V5T62FAm z6M)LYqis3s9b8E}W1&6MKj4S~9`Potr?odcGg7Y`r%ta%go$1vfb*wUC&J0qQg0j4 zJp}X;(kKuj+K50Nh!7n_7m*|a6M#<0`v5oLBSK9bVBm(MxnD#U4DX#*lC3bBi>*%Dhpy8!tu7e$2)L%@7)@ z>E3|^4i4@Vrz9SQV6PV*?Nh-R*b1{N9AS%}kAcT@S3}DXtngfcjj3Y>4&dZ6a2ojV zXZ0+$L^6_p0X)!|ECLF^gYP2DSQ!&Y1CL>QVBK1%`w&$R;Un6J7?B_h!m}UnMo^3W zM2Ki5x`{qQ9Rym45D_O5gv!d_G6v`nJ4YSF-6H&oiItjA3ft_OflM2TP?ND^-J zZ=wBOh9)$>Mrt?f_kq=tmuu76HSL#Z!2K7ZAeQaghO|WAs5lJB-#v-sBU<)9fMQI zEgq|3CXOb^ZR>Y~m$DZTb58;;M$wDSfYtJtwO{0ih9CPl#}9`as9%k13QloHU!n{3 zz&{lWarVGUJA4y8L?D7hCI}azm*^s*fPbnrZJcwA?$|Qgo4S6P`Gp^PS*MpGnxX=u zfX!QK=ZmmL{xXAma6|+##}foAHEm3P@Ou|bA@g_zc3IO%!k@{ir-0pr~Ye|Z`Z$7`d0CqW1kwI);}qI zlKG@u&X)CZWp8e;fw>KZk5V7iJ}iEi{;>W*>4VG%vUnQKyeGd~ep`RL@>ULW8mey= z-b}q&d!zV<@p|>O!fPo!85j4Y_tZ3iyTm+sEoEo06?_AdRd%AL784a{07+>yGYc6;&mH0CXoZp+*z z-&Vdgi6}P3g)wh-~dqKLtTuA4O_tx*O-BrG`atDrRJcZXV zuc5MK_?C$;@5O9|+$LjFeM5RfYJGiF9zAgF{;P{uNmmSBR$IfTdb0+bvcvG z=$L1a8#acks|u@9m}yX4nO<36QCg9~T!ZrR>~ej1<)EDokIBcXIk z<`nsq^2u4uNvNEZJIOeyI=_Hf3AGc8C#FxVpHMhHHE-hB$Ur_h-dpHN^%S~uUDeJ) zXR5Ont9BGRiqUj5)t+uE;_1HsLlSRDn{2$nyG$8{1pPjJ5A=Z|2SIojxdJ1kk2%>fvviEx() zUTAZhi)_vuVe879i)?P+I_Ge$|GTNdVPWJN!7FXxj4Nt6hXe)0s#7CNZr*sy#?9N;Aazy>nPm-= zl7}16{5HR&LlgM0F!PMylQuWU>TJQtAm_j>k2xto%m|ppnB3IZZeieE!8dJgtD4}9 zvVZc;hde0`Th^i0*|r}ZKa|K51yh1^RTFdNq)n_QBipQ$i41S#qv|kcnKvuSH6rjE z1=rc!M_N%_O|6Xy3-=1%W^-HCoE4?TT&D@ua*j&kZffo!Vd4eB$8Bz_UOFquVbx1d zQYNwdsb4H(UBZkU*MTS;>^V23;S z+Sk1^Bt+^*@U=wOA5XJ`#M}<{rU??`B-zolQ)m z5nXljhB;P?)g9&ztu<#$e+!Qn1uqi3RFI3EuEzvC$0y%db8*}H?BfC3vRNx zkF306O>J!#;lCwVvbpCjuhXQ{tl1nRYgijcHi@YnBipuP-L@M>#%YjZ8rDZ^{445q|Nikxud){7|9|=CSkvz$kJ8oSRUTTd zDP33x@O_N`zXap|e~$70U&i?VgWvWj<5>T%7jppK#vFiiFbCi#82^7A*8ls*FL{+6 zo4ktWKRn8dKk_Ii{h>$swS`{g(tqMZp|^XEFZ2e}Px|dd;I;jPd_} zhOz%&j(8Pm!lP`xb@`cZxJIROuC>KAf2m~17YmOr^u{j9`?~R^CWv05kLV``2>%2S zAc91Q2on*am1rZ{i73%QbP{o*i|8g2L@&`tB#C}vfROhB3ZW7%!b5n87D6L@grA5I zI?+nB6H%gr=p^Dq7m*-(h|WnMPIMCqqKD`u45FWq4gfNt5H7+^cnB}iLih+j5g>v@ zgwTmrqK#-LI*1t2NyLdRB0=;Jy+j|8B>IT~LY9^x8ia@N5-o&A_=x}!Btk@l(1})} zorn@0M4ad%lqBFLyhID35kVqCv=VJZI}s9?^btv-pBNzIK|mo~gog+cAtFNP zL>tjgbPzEjPIM6oqL+vb1D!-Sks$gAgXkxuQ9vdX!cBMxFVRA1gr5iyK_Wy%2%Tsp z+KDI;BRYvV(M2SP9-@~>5(d#vNMnFPsDy{`5*pzn0z{Aq6A_}7Xd^oI0db;b67Ugz zB1rH(h#DrS+^JHsQ>9j?N|8=fZ-8$`P`v@lajMkeM9l^yyeLr>LM7aUhwu^_K~YVW zVwx&dG*!xHs(i_!QZ`eiYNpE9Eh^PARf=V*)XG#TlBrT7Q|%>^1f?<60Yb)W8C4-% zgq!dXUV@UBDitqPKS8}qHAsXBzSmKya;Z|@Ql+}3%GW$9wJlYOTB_8vR4HkxQp-}M zl%>kCBr1h0RfFg!q)|X2Q~)g?N0y+T0A7MZm8y@RKqaaO5F)5ZiP`~Bj}o;5paLao z2SEKv)DD2Ulc*R#A3=#p)CoY!11^GUkt$^(Rq8{kd{?DX7gD7xq)I(VwT++-Bx2Y> zcPByVN3_-eB_Gu!L0w0*)_^tjBRQm~e5>N?B7OK=L#OVr9mk?(vKqW$zLWC+62ywas)E`u-IEZsr z#ITcYN)4)18pNp!P+?G|z#y(n0EGo{b9pI@5-Q;$s33?-0?eP~DkYWArV>qA2VP^u5j2hdLp5b7X6 z9X^!;d@A+#RLbwERNq4ksko<7a8IS)o=Ukrl{$MWW%g96?5UL3Q>m_p%M3tOJ(Z$* zxYhs^(^ILXhYJos4Ly|-dg=f{={&S!fI?6)5A7I0i9D4Gc`B!(p!EVMhKJS*pcI}; z4Lrn<P;T-E>%YeSm_ zP{&U76CCBHQp8TBdL0@rfP>!9Z~@e;!(|QN7&w)Jb!fN%3e_Qo92BQgs16r4fC6>6 zx&f4@Q{_A>t3R+8H8Dm|l~avM_^F?uEF+qKKoNU}sG+J-1{D`Fpo2R}{GHN`Y9Eo9 zT#PU~`tXH%4jeG zgOG;-7vUoUM1*K3Vnh$oM;L@O253Zp2oaLHM4I?C^QjD#yzJNYuU9_FePTc-ukdl| z<65~`PD3fLv^TR?-dp}C3$47$hq(`p53A72OMOs#zxaOo{rY>Q_wY{nz4E)+cXepy z<=!#g+52|(kT=YcH!E-C-Z0*%LN_mk@z-Oo8Lw6M6!xU{)JnxtvQ(WYOr$1iP|r*6 zuD@D(HG?tP&b@3vL9g&q>ZRI?#TU~UrCr*U*@bt{FJz&jS9w17y!3qe zx$JW~-bCk~HJ+_LQ+Or?ExqE?>8I;Ym7dB#O|M+c7WHCfJO@3!>XU^hQ%}~OC_+)M z{&?x}%;WnXD?XNftp4bczO~+WU+z8w`g(;zs!+=p^JysTmA;z!s{GaRy;*4NRqn~% zW871{yKr|3@0yEurJ=M}x-)a9d}sNNEVT9}ptUF8UcQav!YfeQGj6T!DC|h>s6lTp zy}iDzv@NquhT>j!tG>08%jJw*b*wO!8mnz7LU*seIlnozxpqtOmh>(4n@cxmZkBH@ zejxy+&^p%6_SyTB4XpC+gj$ z?o7AbUGBtP)dQtKCLlxcFYDL+6<^M0K=ZGlrL#s}I{gwJ??~i4!3Bcs zo0+ZG(l2C$Mm9Bioo4B`>~q+&?3?{g=ZerT7F=X=A6dUsvZ<|%2>&6$yv;p#ztb6z z-D;@NH2N*K9YN2f(KJ?1iJ0sWeA(tcik{2mzbfyS-k>CY3_mNegW1HH#RD^$> z;98q|ZVkzHsa`Cpcfw%*u_{&ek{HEBhtCv}xPM zjbE9e2X&mol4aS<$kRo*X~FYs?jy^{c};CC6X9PbxYFk4d$UdWbG{#J$StnggoJIs zdCTS-4(X^rzNxKiMfjTpM{RD}qNbL!&GhC2Qa~D6we_YOZrbcntUP#v!<3cpW?^+o z(3Y2m1dkOwUT_oYJcr*nJ}4}j+O&P+%{QBg66tQdemK!#$}(-1)~O=k^99egxsRx{ z4$gPjvLb5LK@L&dB9Ze12L)-1C$!@;{U(c*@brZ<>fuQaYnF90WoL`9mk6e9?juUs zXD2tcwL*k{jo{@r_uTa`B1KR)L_HiCLCQ{Fct}+|rK!2~!o)3tH`v@qR22surmRx1 zs^Y)F<6?=NCpaj`Tx4Z*d{AcMUAU-=D6^@w*=uCVVbO|#Rc^GkL|91+n(iYiw}T5D zwygMCHS#~;F(HvB3JwZxl5P{{w6%BRJMR%=>NefB^``ApF>(P9O%^40`R;gQOz<nDcB=urf8eBv-RC*n<)J~GOPIa`3`HAbu&SyiLfsaJlEzvBJuAFnwq*;1iwab zmCZeOt0WZE*(zD4{cOCP-k zQd{OU*-lJj4|hOvDjeGjbYj|iI8JmC{=vo^QA*aC2e^i3c=;w8ic`~jCHKwnlJ?K= z>W~^LRMQ8>W_lfyoUxZ;$yZGuXiZ@f8R$Y~kS;>s2Sa^? zYd_FJ#4%wl?7=j(aDa#qd_|1#pfey6!`G!@4YU5jAtHb(=EVe1@mu#;qsl<@rs1VY zjmj|X)jBc5tIw(o(|frlg_xot0(N5~>><2_MzrLaSRzP-37zmoE@Fg*ekM*kzJbPU z#04TCzIqO~MsRp1(K<*MArFcIGpoLWjj&2|AbDYB98d`t;UQWG9}yrzM1*J~I*3l9 zi;yP(7vUjV2pPm#gr5izI?+Z%i5Q^_0&b#(@DTw*9|bhb zkwO4KkO&hx(MCjx7!fBDgc<=nghu#@AQ2{XqK$|WF(OWM6G{?r5gww2@DTwbL_~;I zB1&`;-Gn*>cnFOM5Me?m+K4C-BjSWI47dmn(L(r$0HN#yTx_7+qP>!)&K?MPis~v& z%#(8)oRPAPhbWgn(5`ikQw*Am}+Y7(K~T5HZfDwC*osZ zGc4}~Tttv)C1ON3ktC!^pmlf|@(iPS!Y;x`xN+4Cw-A0JM6{1LY?vl{uo;&20}&!Y zgxL!Ai~%yw@W@`Ejga>Pt&@uxNlaH4k>o4JFkdl-`HC^jSBzo4Vhr;YBTNGALXeYe;fEGd{e1x9}5J9myjCvCwLPUgUCEAG&qLYwE0hMqQUP2@MM387j ztk6OlBKOpBSkQ>J3BbeXv=BZbK*WhILS{@9LM2>;oA3}JLOXChjwSp=fCv#0qLpYT zI*3j}kq{>r;U+wUMxdt;#}eq*!LbCoY;i2nNhlG(MR%0r>!s0kDIu7k{h7-g<9&mH- zAkmA40AXUnIH1p27hf$OnrxqeaM2X~nKw%UQ-GayD zw+mQ{ulB9tx6){OPiN12c0 zkIElrKh!_0e31K~^nM1b@s;1pzNf#Jez*Qk>75K#<10Hx7MOF_({I#YFTI|5U4Ffc zHTm?{DtmH!j6Ky-p_D4sCW;ejtjt&1o!Koz?JbM7`6{pEUNK&&zFffSe6^Q~FQs3q zzgWWheDaIsUD;jwt_oJ@GhV1ZUwA(Cd<|>#rJt)mTY5Hwb^6NBWS`NWsXU#-N`2L* z3Qwh;suhb^tFJy@8qbVdGvF&v=A4xw_ zf4KB;=3)8a^4GFhwXgC}?jhr$>VpNW+gE#__(1xB`u!!W+$Z0kx-W}W`_g%94m?%m zig%~)uHR+cmAR91-V0Eat6`q6EAFFK1Z85e~v1;EJ8$Ez|^Y>-%)9w9nnRPN&5X@%vY-KbzYG4h)!bobQc75^s zG*%HTU6;8|zOH<27V8LBuE||vTvJ_Jz)FI(tBY5sudZKJ!dimzRpl$QSL#?#Fn5J< zMfLK+#Hl7999*q4i|<~!?jgKtSeYwSz4J{DX%PJ zWkG#KWqEG7vAl}41yh&SE-7A;#`=P#WtnC2vhva_Rv4^YoV(b#xO!0mYYf(w6qlrz z)EAeq%AmZsyePX!UsS<5gT{r`bRnHe*RaxHdZ>Ou>4MA!@&)Ddv*+vQSI(=STRJy` z)dtJwWX~y{J=+|A`Si(!6Q_^jlt?Eg;Rx4cQ845>2`vb)Q=KT9hSRqjM zr+pD^zjv=E?;ds~RgMElp=)W`btCV*?HZB-*O|}%;{E?VcAHzhBA=xly&_gGiP_s@ z?+-EEUePNuS8tCuA47M`2quzm+PIZnfb+hTl#jn=gncq14x%q6fAGRNtolXNW?D6U z#E&zPpY}3?|7?*Xc*|T!>}dw(wsrWJZmVC(*(c|g_$Si9;~U*ciybzsNSK{+5$Pa2 z&JaupCI#o}Xf$7=j-XfWwi&&_OB|Lg%VrUsAi_OOFlBQeNpEoe;6)BwR;m^Xhb(=D zZ!>MyFHOGl)4w&!{o*--H^f^}$gCpo6M~vxw;*2)Y@OvbKHngnK& z`&*r54qKLOv!LdQkk1i3&F1EeblP%OyT+PCOSW!ZvF(PrW~m*##9`Blv6;Svt}gE+<5Ojw*KZV+cwUqh?hESS+>peohd?IBzS?%eIyl8I=I|n>(F#{ zN*<(Zli+cJ^99X;5o6ZQ)_0@Ndt_{`3F#{w)-3C0%1#quFB81b<~Cnh-7=%(8ms>; z+H%V++07f~D!R{BHZ=-mXe4oi;Hb@QO)eG{&q|<};QzUkiw~}HShNneDoYD2-hlPw z`3jdjNzhyhY_qkq^^HvBXo5M`0vmRivP_#fxW?kVZ3D~xOFkq+Yj6CyP z|18tg=6Ydgqo6%-%k9k2*~YT1c37~EwKC9$h~FfU^8`;3oGSy(36y3A&ayn$8iz5< zxS55kM9}L5ueG_4E(o+)^`&CPTAMkzU?2C8|nQ0bx@MXSh2H!9tgP0cJ4L9Z0N z#OAgdMQ4sRe*t}!!_lXj{I_Z-19 zZ0-?^U74+|b&GKcBUf(Oy1`l3uWxGTA`v*({*olVjo{LEwyI!3%6|4o#zy zi8FzLe3#UPk#MGxNwYM5wxOwEEJKH|Zx+nj+#^WgMw}AP7P(<~<;L6Q&Ri>B{@_*2 z{m1`5f7hejaf??8;d|G$Ugadb`~M-{`>%b^qx?gcSINKVQQ~)cln?O!KaKxCz1^ea zUckD6^E}E+7kibH|Hz~K?w35uRTp`cU*f(0UB^NPfb0MLHO3F%{r^6^_g}uqtL(?S z|IPhgCHyaL<+X}OIjiJR{%{E61`fCtY1FF>J#tIz9oLZb(Dh~vh5q08zlx1UE49&) zSyoc48sCo0I!7YW`v7(ej-ZX&Jood%j?Iu0nK>SKlf#x}+pH1Ch>*_`OxfH=Tjg(X zSUog_$4ebZ)mp*R1kV;U(>HSkT=S-Pjs)K5FlCuG6SznOe3js^&3&{9yvbqp&;)8y z90^jK(^bS;#~d4eYij^Od(mRULr%z_))ddv1(#%8otH#MCEM{Mr7v+!4;N3^wRoL&;~ zcu(*Ro7;n9nnfiD5I&iX9GHmTj|0uMr_{7R2Kp?3(Vmi}Y|hByMeLGuKEBtq56^@mI{RsP2tjWigk~~jvuCu~tYHrRwx9)a_Im^76i5H2$?-JZ$bI+ZLznb}O zcQlRF*F;R77cAP`M{#D{+0@{R!pO^lR(aUJ59iFd%VEJf-YnM>q+?K)&kLR*c&?y1 z+ijh-v-RD$reiA8x`x8Gz@J8W6DtwN=(j0k^)py_6z-h^8~{AmB=n_kmDyQitG zhei0$3O;FbTd$j(XGBA~c=~ly@&xl_YFu;gby%|^YUW}>Iu?;%Bsfp-R6(8{v&|Z8 z3AVaJ)U zFCk&qOJqv$LczHb)|xjYLmENCMz-wOjxL7AoYNhfx7~EZ=8YSYGaA!^!@dM0g;ol5)=L#<)7X`_c=Qi+;<^7uP5BLs{lD%w^b_FO{~nC}??yksyHT&w zu|!ke`583+j`1jefM@@kFbBYMD*6jP_9&;IAK(Xg{$G*xDu21xquh*Ve+lydwp|!} z|6Pp#|M#pdvV+T|lfJ)Hcu>u0N#6V|PE{w3s!keJoiv%Cw39|*Cyl~R8ik!S3Oi|D zg6d8h)txk|J84vR(kKd}QSU_y5fppUDE6dL>`9~8lh#I1@kyiNlSaiSjWRMC6=JkF zK>;X@0#I6lpbFGfJgEkyQ4LB<5|o6}C<&!e5=x^al%^2Wh0>@CrBN43^AHq=(kKq4 zQ5;I6IF#lms1T)5A4;P>ltz6hEkaNvN~1`WMv*9uB2gMeqO=ZzN>Lh>qBJT+X;g}u zif1={C>y0wHcF#xlt$Sojj~aiK~OtN8z3kkr6~keq%^8XX>Nj2QX2JjG)m`a8bM_# zjmlD5fCv)Qn9`^*rBP!_(+LVqX%w2$C^V%-393zLrrK1a+^IRG#R&>eX%wE)C_JV0 z5LBPis6M472})3D{lox49V(4FRGLCij7p;zmF6a>NTpGcN~0o`Mnx*kM^KhZqb!w1 zSt^aPR2pTev8byXQ>IZ3D&{(5nl}5=bjgnOwC95<_R%u-0 zSfg&0M%^lns#O|Qt27D}Y1AIlWP&1A8bz!$idbnBvC_ms%T%(`sAQ#4$x5S=mF6cX zXQffjN~4^WMmZ}j0!+n|+EyC1tu$&|X%s`!sB@%s5R|&oD0QV#>PqV(sCT7N?@FWI zl}6iNX2q*-Furvx`X>NjQSQ^!^G^$}~RKwD^IJ8DVERBL# z8U?YY;z?mFElf}yOQSlLMs+NWBQ7;cWNDPh(mDw0WNFmN(x{WAQ722|I^r6|vNVci zX%x%SxU{xL#VpMr`U%QrY0?lt*({B+S(-{vJ4>T>mgXTSpruhjOVfaqQH}aq8uhg_>T79S5nQ9lmPU~+jUrnb zR{+t zL^qKjdWc@4k4O>*(ND;G0fkTr7cdo1H+?*WmuMk0!bkXt01+fYM3{&WI?+nB5$!~j z=pbT5ClM#Qh;AZ5^boy7ACV*sLf!``gbGZ>(?uUQ;UT<43!xD{!cPQ z;U+wUmuMk0!bkXt01+fYM3{&WI?+nB5$!~j=pbT5ClM#Qh;AYQOvST@KD|UAkt7VF zpBNzI1As!Pgo|(!9>Pns5E|hl{6v5V5+Nc?L=Y3h)X z{Q0BO3aq{@yi&fq$&*Yvluy&pFbor_5Q~FbtVyra%P$UGrG zQGPu8xc+$MvD{pD$xS_hKuqm~vwz0S|y|KQbv>~%W-cVkjU9YdNtjn!4)>X5G zY${tDEsmx~>m#L+%t-!-SDMdVZd_iyOqxR%Fg;vfRa%uYnK);O@bD?};Ih{@G>B>-U$QY_#AWe;`&z)zSS3S3IZtC3HImL6*=hV+G zot-&bKD&HY_ALFZ%9*({jWerf6wXMUQ9HeOdiwPGX{FOLr{x!>7S>KJo|-N|8)Nj+DdMupX|2a#+Z+8Y~1;!J2JUf8Lk!)wH69RsC8@EtwX%rR>dmb#KL! z^BA70yWmc_Yp$Xz?W(IKHKWRES;;E8Qjv4AAy?753gmr>0cW2|7X$vd$?(T z$%CSgWL)quo0~m}6o#2YKV^1dn1hcvY_S34$9h?DyevsSm&k>J=L^!-W{iq*eDVz? zz-^o796-6#Vb8K}c5z)NLjSVh2AkVjkPOkVf6$#4#;mf&I(f77JU!af+E!uV0l_HlF>9AlO!fHujkP}c7 z?DPwtBd?a@4tth;vs&6MnQnK(-Uhst*f!%Of!iD!y?Em`p}8|}wh1@VXT`&?so7F$ zx~-bxtel@;Q=U2udtRG8({0rhXU#mkn)38v*i?m0tAy>}&e}QiZEODEGjmw5rY$*Z zidlYkD>iq2+AZGdtiIHOsoy9!}daZMuauR+1xc4_`S9n_gQAO}ABU&i3%|+NW0!!=@^1TKR4NcD9ML zwNJa}uwb=M&YU#!({9D)&QH4=?bC!Kc*~sCJ~4Q+a1Je~FVa4h95$>-nC(-ibP8;2 z56{~YElrPrF;Tqo>o z5VQwwxt&#SW;KuwzV5JK9c$*{+0q~){;J?bf|m+z6M2}mcDBATc!bluw#`1)@C}D4 z%e0w+mx+Kk2xe_=7S~o3m@@;dMZLGKpL5dOn@tTqAdEaOShTsV5_9I>;hnf|HMRMo zu=BE@m1*|x&p&acgKs-5SjU?smXHn%ls z%vq@BaLWJs%&lx(sVV=)HUFUhcg#s1WiQ_QUjPljpM3}G@nP-1&#?C2INtrwzr>^b z^uOH7SMcutKbLxy`|%(Bdyn!7-u+*IIRL+Vx>vdWZ#~L^zws!KEy4PK|L#_P2k-u` zT#UOwyLf3%s;$)qF-xj^XJ0O9}7B4OKcua z9r=#Kf)$QgM=q4kLLG6*&PrqK7QR{&N6S-l6yqpj|=X!xsRfj ze7C8=XN8g11z)zgkGz(Auc^Hcg^ilvpV{1V*ODW@2}4OXZo+<}X`Fs3;_-h3|I_BS znl@)GI*d6j`^- zhMqge2YqH-;RbVZH$l4KqGijMa0-v;rfFOve(Er1nKvu$Y7zM5f{viYCgNiM*r#1! z{IY4{;D2+Nu#PZOl#nh!C|SYzf(r#_Ns()nTPdCIQ5Jj#-G4m$kDwpmCpT-#)d8>a z_uXFQHvC7?2T(#EK+5M;_CfnU^Isn2pE2+MUX1_$#l@O(r`M}!F|YFCe|VHLG4}t5 zOT5ZuZm;rJ?Ox?pjQ?*(AHZvEUM09*Q(kWMD)SYu^4o?-xgzaV{wCs8ZlClh9Z3)7 z|I5;%6aFdifon*5b)A_c@%(>)YetzL^b}Dvs*(Gc0JL@M<}D-J4=sS-bL5VdTV?^Q z5qU8pc#X}?6KnSAVPcU6YAKkdedvs>Nry2jrdCl5p(ws0k@E#l6*P-t<}B$Jv3v)T z2fc_nQde~tv?5@p?otu_<$|kiZfk0avwAh1n)3TiO-SoM7|f>|w* z^8`;4q&Ni^CUJZkUG+OQV^-VDMTP#@VahUX7SKWw@Y#ZA+T34M(CM>3X=-MP2zpp> zxy@}g7tRj)X0u822mjPz%gPT+t#T3aEg`H}zcl&IPyg1qF8tXX!CQs11i?Qhk@Eyk z5xf;GAK#WcK8;?ATQ|+|D(b&Gj9JFb;yFtMjU}>SY{=%e@(tehPrg~cNuT|BQ(IWh z1;O1exYg#i?v(DUBb>z!TW9Q5nOn;qOLnTDO$|2O6jdPEWc^n_FJ>K zlv;&&nRF@Gip6k4oe`!IK49c(c7yF|`G5HJ6>8F_&_`!+EW0yB z$cqFou(^+{>}pMIZ4lw#CYZCikFM8Gg`GzP@3Xm&yzKtUVb581OHpc1NaQ@h zl;B(^p4s(dop`edE&jE`oMqlDzH>z27YSZyb01mp{Y_I_H;C}>6x?oeA6@bNZBv`~ z2s@7nK4^0vdGY<7!=AJFmZ9Jtm&kd7gMxFNdgeR)#;G?;>HWRKnq}QAy|YEwO9az4 z_mP#}KQy(qNrZog;5M84=t}PwO>N#S>^v&?fX#j6rT32xd(P6k6y>% z(f@SVv!ZNWh?XN6+a+?I;7NkFipx;e+S&SU+~VCj`^#ua=6YdgtKe5`?jz66y2GB8Ggfx4L`L2wk@Exx1?Q@sjmBl>07fg=FZ5l;`hV$= zSNZ7*ud)u>fB%B#{(JHMzZLp_d;FN+f2mjbKIZ&ihWGz}t$CHPWnRUF`Tx)UFOPC; zi&rV*z5kNm^eBIVdH*+gyvo1h+5eFrd6dK-dX(?}n_J01`|lUqu=d|4&;?lJQGOk| zf6Eqll|RPXe_yHMnZN8&onhK zmtYBF0VHpiIOtgKsiFBI+ySg11Wygi^IWJ>)B~r8t(3T=BZOXrO41omlfIJB#4*=o)2s6MieG=l= zG65tYMiT2`)TY;}8W=|gn2~OQ@n9R_8@fyi1_*UHgQX5x61%2yzXg6VWh^84=Qonu zejp>Y1>x<_gzgpj>PoJbLXE}Y!rYZB-I>b?_6}n6-q2f9;SIne7MOr<5v$9Yc_!m{ zNuV03V{^f4vdSzPCwBp>c4;#oMv9li=(>q776%R1X+`EXV znJa;LCJ`I1>$Nj`R-ty$x1EO?p*>>14s2-C;e>Dm3eqev9UJ1j z#cD%1cda#tdJza}239KCg`8`wg*3KG3Yw>NJB|uAA_3?08QzXVf@Xb*V)szvPz^aP zLb57T5B7_y4A5FNGJuUpqpHOjVbq~UF=&X4_9m8a+}T(`GCsb+iu7BkpN1^AV!4MP zirc+Aq=_^qtzC8_YkbHMd zzmBMw@oX7i&P^oMY-SqmW)D_Mjp>ts7dy0~$>4clW-KQFw^>apC;fK&CYDRyLmS>U zcum)&IF^EPzZEK?>Wan=nYMtXEwZW$Kl;baAB2ZIw8Gk3tQ*Oy(%Rap;Gg-VV67@F zqlyDEV)uZAR{b5}>>XYr`3H#T7|=x+lYoCeT{!9du{;n#eefp;4JWE!L*wOdC;Cx_ z{_X>7nX8TU@9Y~%`-UuCGre2HzR_jha1Yvdvu||SH`K_*lFDn7X4WWHD0t~Q5hJ=r z0eK8aA|bjv33TLv?qSmc4&E6$7WrbvymxkQV;>hWME)JRx3Yg$@8B?3E}XGQ>}`eQL&a1YRYApe)H}Xba-%guMku&? zE=2>v3lUp6R^kC{qw3*zo-}4w`EbaoaU!sHtrTtSCaP2me8U-(if_)N1K8!H9xRLI zUV!KssN{_TfLB{&A6f-O8on9C;?1e5i~`p2TjL~Y)Nh3qoPs(ni06W-nm}Ql>9a|Q z>xe{8T?#0$6LSq_BsY^~m@&^olihV-F{{;EIKxd}A5I7OatTBtK*Ug$!U@7Z1`ME5 zVLem8eSj{ahiJjs5e^SFD#~=2EyFXsdS`kWGrbhV&WA*Z#55w<0l#>H=)#E|_anaX z7F=iJU5H@3eGC{tWa0@#CLWp;ZDu2ZBG2ALE;nmt!(aT6*q~@;zlfC>?jjpCQ#A8z zyYNBjMzF{q&M50b(RS!&$Dy0?LpKwLZYtx41m)eoR#I81=OYVt9#Y}V))Us_tPi^z zm&Gnb(w`(0WH1^@pardre*movT1B*v0U|PnRJ28E9Tet4=04^@aUPVM^$;_z0Up5} z%>6^yKgc$tSwdT}i}n-h<;CJDEpCc+~8PoIc9SqwJ{+@~GKT ziDS%Ux_HQRGFwq+aQkRAOyVMoY7(13!`diapJ=j#QT(F7g7u62I4gVuO|Whz!MtLB zLCd_-PsL*BPl|tB{CWLng+D0%er_`Rd-_l1-!1<{{w@7S#t-%H%azLa%HPd>C;RQ$ zG$#rlr}qwjH2UG#2l@BM-erNKHi9KVxjosB(3$LbLt-VrwCH+eM<C>_cbEjq(=nGP*>|pVf^eNesGba`17f(!|Sf6X9zhm`dDg(9tvXM1%$pRDwjNVjF zE>Y^vbW=ZIS~)L5a50+td(1`Ep<=HU3ZmS8JFxTt68i7n8UsC_ZI%iV;|x9|4sX=!qE(#pG^I~ zj&bVMb;R+db`w2BA0h7rsPd;$$4{kZpGs*ym3;;(mG@M36R4EcQz@aRQZ7%WDxON^ zJC)aCm6u?ZS6-FZT9xW`D&^`_>eHzdq*JLpr&4N8rNEp@SvggaF2xaq4?qkfbjOGu zLXH3)!cRnq4x)=l63QUpCVWJgXd^m^ZlaIqC)6RpLr{54rP!ECoiSA>qC}jaR+vh0 zFx52*Q1MHpx))+dEibi`phlP4Pq@bbN^7Y)LA5NEqF8D_;o1vO)k>v|l}gLosfPzk{m!N`^O5G-vLQN{=nGi$DGO5&I zLT&?;SyHL1q*6^urG}D92kQid2db zsZ<|QDK4ZA5EKnkDG;Pm3`nKsk4iNkm7+Z=WqDLe@TipAQB8fF4(jQs6wpyAo1+?p zIs|wKjR+Dt5hdb84X;X zbP>ITLCE_74L}UL55V0+^bt~I1wtfTghqskHX=&IiEbiE@M!=U4zv({B1nV@ooFMX zL?;o5tYi@aQ6ffYgMgn16Rku$fEdQ;?jjOIFCh&B3gIHWgpUXiAtFMw6756>(Mj|W zeS|^y$AAzKAzF!cqJ!up5=0+i5Xv~C1;o9H7XX%!+ucnFOM z60JlB(M|Lc1|cT_mGBT65hB`&P9j0{5(aS$;Ti&3h#=8MbQ2Q#hj0$AVhp`>YlNR* zuM~<9U}qBw4q$f@$_!wilIkVcp@f11*b{}~0un?Y!A=a-MQB8rXd_}og6Jn)<3NCD zC*nksa7_R{05R;LJ4y5t%09qNXoQ~#5v@cA(M==?_kKVlLPR^!MI;I30MJ4NhzQY6 z#EBlFpFoCSKO#WrL_5(5Acoy^_Ynr+8U*}AglHw&i5L+l5=1Xy5b_YB0l-W6i7>%FL7am?oERWnkqk=|2oO3ECE`TOAP^vQA__2ubhDpcW#7EYmjEhz z{ZR}6d%D#&g5At&Vt5ITiSa=hu?1r24M85G8SWtT2wH-!VKxjzf>6f*7vUy6L>JLb zB*)pJbPnK4RoN&>lZ)YDsQ5y50dB%Wc!?H5BYcFP2oOOcM1+Y5p$m*HK?TVJD&ZpB zgokJ$+KH}lpnpH$J^*M$J0V4o(m0VIdWc@4k4O>*(N7Ez@(`d9D&ZpBgop4FErdq+ z2tN@Zf<%Z26A?luT8TEIorn@0M2zSp;zSq0f84Qsn)}rFwEFeJ*Hd4weNy}+{Ym}f z(#M&P<&VqdY*{Z?_U85)d#fK6K1zL5`>^<7`osDMr4KS6$RCv7&%Up}UwJS0p7CDw z-NL)6cWdty-$}nyf4lT{=56_~wf%-ma;ZEqG*RDO+MU@g?=HWZeN}(8@=ER%+co#Kfh-+$!2XU#yQM~uby4U`W5XS7etbmWP(B z%ab>RZ_sW?EsHGEm!+4+mIjt)mc*9?mt+?w7KawAi<67m`nk`aN`7j1zBWHKFEUS` zm!2D&8$2A-t_@wQUYnd1o~6x7&5X>{XQr=-T@$z_ zb9Mac;MLg~i5a08>Wt)7;j6T(QlUsl2_@UZ?OJsH9I9S zB{W5ylDsl}rFLcNipUlE73s+_%YJ`HC&ecPCuJulCWa=e6O)&Q$xlvAh)mEYq%VnG z5+Hv$9t;MvZHcx}o7$GVIDD~oacX>IygojCQS73?MTf^l#_8kIV`F0jV>1`VFAQFo z9g`Rn8l#R$jt-C3MyD=_T%cc&K0kJT;QY*}_^9Bh?8wB(&`5P;azuE9HsZhl_WX;T z6*wz1G(I#qG}{tw3AAL+jGq}iGkZqjjL;eC8Ob5xA=;4C;K*QoaC%T|P=Gx1cyq8h zt0(l3uIfpD*su9hO_3(ODc#uFs5PbwA?T)zv?u>|wpvbxsu8>Q0C7ofX=1e&v4&9M1h!q41 zGWNJVXwTXbwvbJ=CDpL1sVOBwU-|#p{@%Jn1#L=6?)(3q@&7*lgJn8}oL*r}8ENOq z6API0O!nzb8Tn&g&Bd&HYi{V^E_r>GjNR6#>Nbs zUZ$h{*&-&zjSQX6m%g4k*JPhwhW;h5<|5Wv$6RT$2cDsSwdkFkp+O}?S@{FzROU5I zWN2?2Ip*fz$c-F(%&z^LMNO(3Il7v!y*Z}T0SmW)|_8fmcwwMNjG*71XR`*bde^ zy)Eww`l0DI-Kk;AdSk7or>-}Se(1SOdWJ3QjkTWkuiiNOp=sph$@yw5GO^ZGN0gV? z(IS(zJy)1SKXLUTCYPUCD~%y3tCr<6dg3^@{7hIbFXiO&GhDv6d-*iG?a@B|{3D-j znFym{Zc%2E#?P4}nHMuVsJDbyx#cICTZW#mWiGS`$^;k{e?DJ+IdhT8mTe`a#{5HX zyZl=+7v)u3%L+S~H=As^g3nsz`?V!=abC&&Eb}n)Zj&vaGHb0r^;1@oSMPn+IKupz z$(B!8%b*c4%7Vqc3KDU zqYI7re;?EO{|6^KZDVO4!2kNL(>9y-0Q@zr|KC9C0G#xBFRcM+rZ|AF(E9%ge|Flw z^K*(VSU~FnXy3mW?f<9I=i@)6_<{8QmuUaL5bXi*bDI0V4*UPLxoEFJ->76kn=(K5 z{l9ttzua4<(vnLu*W_CUxzt;ce44jRl|@5lp7EAZmD&9Ko}io0pc(GlUF?wE{~qpQ zwM9*;%ZC>_4wI%~_uaQDQA(&gp4(piqUv$724r=*f9J)w@$atq9Cu+SLG;VwZ0nn z+%{jwyC6MkN4-T(%6}HMqoE&K|F+uE*blLPckO8Ehh}e&+5p;fU{ub}?*<68QmY24e%_u2bi z4ySOlhxQ>R`*GGxH6&$8TRx*Fj&mKLvn-dFaF z8*%c%Cj7adAQSwcjx%Z({qivz(QO9`04Gj9;esguH&6%^6U1{RFiQas;04ME;!ruv z3ZN3G#>v-fVAcXYpblsth<6)dHUWM>2h>CKo0N^np~GczQx2T}k`w1$fE&mEQ3$gL zD8cbJN@02c4aey+nB_nPPzh8M#78wSYXKin2Q(1Gj~Zb%0e(OS)WZZjLHxV`rUP&S zE&vh1#jgvAGQGbp!uevL1n>~Vu|C6sBN({&+lgr4bvXWK1NbolfV+g^rw@+)E$r$M zI`6Q9E(hp#65Rr3aUob*gcBt&wNjWKK*Mom8O#cpHI*={3Atp8x*D9R#V;G`z@|p9 zxe2HJKr@cd7zA@LU^`03XW5AyxLcg-go&WtqSXzv2WLhbTTJ4p+&Uf0L{DzUFV$o8@21#@9FJQ}cffQ4F2GF?R~N!8 z0*ZkWoV?Zp&i3Mj29yC6IN4DNvkIue@q${IKA;Y$$H^s);Iby1@B=!~jFT%BWr`wJ zACI{$lf1eB=hs@|ZX@KjxX}`G8{xLamfqrRBhRlvzHw#9D5*A{zw3$TsY z+M>I!;M(FI1lAV!A+oki@O>vDY$Ld~c-RtM8-cY&;zVR^1k)Bzax`rO(iYF0h@_1m z+TsO{qKyFB;^h+&wEcAKZpO*ilr}O|zy=f$#M=&-E|~8Ln1wJuR|K;dC?&`gf5C$@ zUZ9L1zETde0;t0A*Q;UH06rXlvkqoG(1_y?n_&6@wVjSXvJu^Opa5{<gpX za57U2vjivwyg2y_4Q3fo4pidgZ>oqg!M~}-`5M57UmmN2Sr0S-O*r{yKTM^QpaM3a zfFSs{ zh~afG>wyNK5%3elXr-G>l^~Nl+J-ZBpa3W(h|4@M%V1tv4zm*Gv?`d@KrN21^1-YF z8gM+b5oQyh93a>TVvZeV0pP@OhYO|v+&~ddE-Z#w0(fw|)C*Gs%76-jOz_G|oT&n8 z2qIDo(+AW64LG@>5oQzM2bytmlX{3u8(;?t04G7jTrdUT28wWUXEDqYpcL=`8bRDv z2D1X@9hESvfEpa%RSUC@Ak%wqJD4pYGV zY7tQ;`|Bk*^^H>e)(i892D2RIhn3)Ws=<$HaM}m+`*kpzVE#l0GlRgN*^UwarvUt= zgGlckGJjnN{;nAOeJPmr5Zy*+*PW%a)a`A1=h)lvw*zmd--^7YzmBnP_ z2OiHHj2#Rd%p~H8Kq7M>ejrFI3*wIjAIm_oyW)2RdDVE}&P+TW55~K?b<=tR z{r2?!*#5x&%x!VgdV=`g;NI*WtSis%j_(fc&hCou3hv78OzaHpjP3~R$lMygHApMX zqG0a>k{ii>#}PTYeTs;1ldR;5{hKI5?!IL=<2}g%&OR` z0Iwg=SEg6QRs>e0m&cX|mS=8=-4M7Ty)3pYz^e!JrRgQHCHj)|;@INA;`E}}qQIig zh3dk@g3tnWLGt?W_3HJ>a5$`mQ=Q>XmDaY0JG73JY283-Ze*@LH$5jZN1v0Xbp!hB zc3StIxHfogc2;6mXjXP+d}eTF_L>B*flnM?F_66~epT?QY$y>5hO+I6_E39vdSZHT zdUl$BT6$_^sy;O}B{D^ylDaZ-rJh?WkeVEstWQo|9=Tk*Jat+4GVQYDr0^tdQgUK= zqDCtPLYHPIBqki8RRa1Y>0l(N2h(klHoYyyYXp+xL*ug-#V-n8l%^E|+PKu%$XIP` z>cYr{`i1E+u`&9X^yt{=!065k)C-d5htJo}PmKzX(nh65Mn>u*(<34y^bzUdvEhN? z=|C(H2xMC0t%26edGYfC=VgY)hXsaZ&W)cNIJfg0?VRM<;j^`~Q)fla(#}c^jSSU? zrduK{dQ1Au*qQp7=`&(y1kT6|i46%1$qbGU4i3%?iVq47%JQm!E?w7C{)k`qr*kU; zVvTxZx*^sOIKCnvRu`zt_~NvZKT{j84b*08;x&PqOm&>r19VntRmsY5rABK3!WCLY zlGXxb%MxY5vaA-@f?C#_@CLov+`9gFX|Oa~k|+t5WQ*g)!QyO@pI7(?j;{iUiGWDE zVy=KI?Tk2eXW9|VtpU&rQuc^lx2J6pn{G?1F;!R7)LL9Tar)O@rSJdWUd$e|V(kC_ z2jjpXZA+~wn$pqdPRh|w##qKi`0Cd&XPE4Peph;NUbQeQbTMh85V}Xh9{5bDw!C_A)_8*XsL7T!#`;x5 z|Gr@h=GAZ; zEt?ff(7wx>)czQXL(Jrs7ZCByxRHN3z+jv zw#-8=4XLFl{d}`d&8xYXb(S(uT>6A%Ew|qCaGFIy{$O|4M9T zUd^qnv!A)sWXqSDwU(Uvr8di=Crd<@9}UVYH!5HYGr&ao<$1n0^w~&WYmt-kM)8IC z;tQGcO}5NZN`?8SpN-^oc{P`?&IaaclP$Bj6oV*gE~x&Pmxx&Mpk|18b< z-+qjKcg$f^T5U@Bo_$|@jr{-SrAD&h|2Hdt;RD0_{&;TQyzAurTFqQyvIqVWn3q?t zn>8M1K4P+E{kJ~e{cBR@=hb|QbzWz_WU^)bx4r~UUH>~Qda}+K^}j~J){IM;gPFsa z=rSzm`<1XZH=xl=N4e9YC-r6hhhCU9<}eLg<|+Ns{L{}iC7f4tA?qw=nlCPGYn#&B zi}iYog8W;Vi)$$18x(Lb^E{@}iY$=-Sbj#2JE(nU;{uDIOn{M%)A{n(Gv}J@)62$% zc{LZY&N}8wlP#;JH5*S|H5Xa*Wd0bL>Q>fLc8+IOGS6Y6YA&KdILlA8CfcYpDim3B zU56YSTD^YNx{lTB*LAI5*TbP(Y!R1Z%Sjjwx*`Xk)VxPB3Q5E}jn@cU?GBL(&4r8eRQzpy& zX}wJ)TA&mt8&)q{h<}y4zhxE)c>&}8>Xi+2m2PGWvz6ID$8JTBa=XEzCe@7_8pGFK z$y{Qx`+hLaSI$>DCaqqxGQ6&%eGSPi?pSObtzAclOFFv3Yr-qncC@q(_4heTaCzQD z-NXsm!@R|0%gD;sC#N5w<5%Pryp2U}XUftre_G#My|s8NEei7QWvOnYQoU0FTbRR{ zeU)m?m5@ErUSfi;vgk>Dqg==G)mJl@ne5NFTvz8!)Fw{IKIRUSeH!K3l~?d~7U^cn z@-Tn)r(7cz1^M@~TyNxZ1zQwwIJ1A{+FPvmH5NUoFUu7gt65_i)386|a$TD@QJXj+ z`j)7=7j8J-fFT>qgZduE4ZIU9%kNSvSp9STCAt;G2LX* zvljBrRJ;ciu!T8-*;gUUZfKrX`DTltOn_0$+cIP~| zO>ZFopT+^&Xdi&*=eTX-{^7KJpT+@}`CPVdU+1r64(jFM7W3k(7(DGil% zKm{eFvJS8vCHUyKrF2zOnvHvL&_8ajr+?S%qJP(nWdam^i(+o@oerWy4fCM20-BGj zVWzL9bWbOELliIy@B!{tLJ1+4Z6~f!h2Jy*1?>bM&;(Q*A{0{~Ij!&*!2>i=tTe5t zjo=5oorLlzp$1U9355p;9zg57nvwvhU4%lQ5^#1CJb(`nhY6)X72rOCL!gq-BfX9I zjZ?XXehoAN1ztiqPz&flNh_feXab5m2|l2(i%Hy^!p%AD5bUyT7M^^!g zTM6Za9_eksZ`^H!YQWJ+r~w>Z1TWA46h;YEfTNpG3{(N?5rPM3Wa}6#pwK%TMMWs^ z6TCn@;A$m!fNDSo+--y^K|>pBMIavZA+>jlG=|(O#}u z(c4L-yO)1ieXLz6*p7CLUiw|pAd|0;P!{QVl)}i>Y)WlbyOrb-d6u?pdUxSy> z3^cV93OWge0H%WbFzefg3EsYvC;{`YeVAqK!-Q%dCfxcQ-l_B#Kt14S#UapeWEv&% z7@-q~%2z+sY6|PifhNFplu!xSI%m-v9H;;q0nvp+K@30|NM zC_F-_0t${2$^akG47iUG$^k#%_FqR=0g74)Wk5Y3+6YxZK_{UaDCi=1fO^0kB~$_h z-Gm~b63~ItBZLN^^cXC_?VXLHAlUr`4^Rg$=qM}v~ zGyyeH0^%&V57M9SHA;ud%|)lGtE1eDHe%RPT;yD{MZdNmX;=K-V+7X$`ZotDYbn&S z%)w$h=X29P@s$E1O79Aac};~EH(vxxAAFUh;Tv>_;5`tcdp3OWHecM0poX9*He>C|>;^EN4ST&$OkiI{5e;~JBAbW2j zPn@}YQ3x{ojo0LLc7#m$(`Yy z+RoID$PRr+`c@-Kom@K*+OBR-#=au|=*P&^D(w zMKiFv5>g=k-s?e(J3T=62X?$sLX?96sNoa|>B)K@eSX-Q06j`J% zN-vBp3@l7ve`tAlxwbrYL*xcMx5D65f0J1dUl3f7y*_b$$h6KN(y4c*J7OJyj?Db{ z{NViTyu`fFJat}jZg{RXH+6iaff1oVyEZ%Xz%}i(q4J?nXS;X$;i+9y{8t|75mi9V ztrbX3j7-!i_FnALz@?c9@d=2)m$)Q!iF!#g7!GQ|R9n}@`o-z-F^a~Q;nf1!afxxE zaq76_*zif~1p;F-qvNB4qq7$zE(n>{40Q2of!K(^h|KW#@Zj)lAQ1=!)IhQ|+^V&v z&WoIlUU*sreQfoew{H@6S`_5p%PO>$%Jf+UY+;UI_Em*)gVwSNb@lR9;x3DzOn^~|F5=5y&b-uQ z53CaH&Z~75Uw`x`yXHk%U zFDubDu0&vq0*+wzvl8|8y1C6FC=(zn5kxL$kxQ9|J+Ml&Kd;tReEprwsLB3}E79$F z6Llvi)$C%ODD!5M zeHvBd?!1Dxu*jXveI{G>eymmG)Ze$>W6`r#m>3n{y$aaE9Lemf!jweIm2#!y#C-Z* z-d*=v6lDsGDl?w1KbbkvWDl&$+?Q8t248?XvxizW2Y4)&SJe9DuinIBl0#(tQ7` z-L}iVNb>+_4Zu2D17N4mRad!fHrfa9t}M;_r|AjY$K1&^@Ex0tfJnLn)|+Ip+D&sh}Y z-y7AoMcK)1G&qv&i<$kbw!OX8pSK9g1Q^wJHeY@TGif;2vKmoh z%s;gFD}O|_SMsXuVTFg8_nK^3i>#Hlf6Mn?&8ztg>l|X5Z$;YH_Ew3yX+OS>6{{D7 zS1jt_#Xd%#@Z;C=>b%MdpJ%>nvOjGfl+u;!gT8LjlPQ+3<=s>`KUKgM=168=HAQ;5 zvZnMlO8bUIQKrDCEA4#!dCXZRd!TjY&Ae)hSYaJ=g~=ZHd-<)rdRti|$$Z{q%erZ; zC$4C}-^=;t$G@F7QSWm?zQO#8$v%x1?w!1XX%;!k{GQ2{wbIa3;E%JyvWxS37L?lK(%1{Qqvu{ii(uUi~et{iiX2G_C*dq%nZ6 z&vx79knjIH+WUXgP@2b2^Zy^;?X;aodjO<<>9mDt{{QdKaN4$#@Bgc7+_sx3_Fplr z0eGl_=JXGC+P+GD|A-lG+ZSm4|24G!|K}R5``4W|jXpP%?_Y}j|BoulzlNUiy|)TF zl_Tc)|6NlQf9MLn!z!9mG%;FOLmze@P!BW!exMl`1gPBvJKz9ZfEy?Tih&ZK6z~EX zP!3c8l|VI61NeY?pb_u`I?xO#hX|PdYPSOgfCF#>0&oL`KoNjxvUV?^0cAi1Pzh84 zKA;Y002+ZNKnI$EL4bOgUH1yBi812sS`-~;M` z2A~mW0{lQTpdKOEfdaq@6aqy+Dc}LTKp9XDQ~*^#HBbZifI6TaXat%79cTs=npbRB z0Xt9tVAiqS1qi?mU=p&u7$^Zs0S}-7Wk5Ml0bsJSy%z8RbwEAP2s8nHKnHAIf*mLT z9DoZD03ub`3js`iwwC~pbn@98UVzhur~vP0DCK;0KklDJAzQy z5ro3-1~9?eUJR4~rGOVe>@`3w-~;M`1^|I4>5C+vtgVMoLXI|5GF5pcqefD?Aao3JC^gdK4v>wtOy@g?jCFJVV`3A+xcT?9mxu-kzG02A5mE0%Azm{eTXrhY6UbPwfu@ zAtWe;PS`F0llQ3wA|Q4IHA93F02BJ{2pvJq5TOhx2Py!Bj-VEZPzxY(1T{Vc#EqbK zhtLeDM+kPn0XP8x6aqy6)=5zdL_oL*yGEcCmcgz7DuHUC4rm0L06)+S3<3rNwxa~Z zg|IsSCm;Ysg|HU^#Q=gr*gXJZLfAE+96(42dnJI75Ozd_u-5{J2w_J+2zw)eQrHAr z2bux(7{LY<01g0gAnY!{4HN=JfCumb8i3Fb_6nd9r~(lA!H&QWb|26PGy#495gw?8 zCD;Hgys$d}C*UGb3b7KyUI-Kc#Q+v&P#a6|0vb>TQ~;F#!aCTi0W9F4HkQx;Gy+Y4 z4m1Obm!JX;0MQ%lE9n>@Gk6ZU7M)>T$y%Iop20Ows*lPfUWw0YEgS{R=R0cbi(%Ah3N}-YFP!mkhfHI&Qr~t4y$6gH}A_KL<1Vm(@CYaCwGy-ZA9lxUD zL-gve23+U_R4P!^0R*m7g-a-2LM6}y z)E*&}93#{N%|I=#W5;#sk6cRWscNDR>XZ-$1CC>a3cv?60Xk5iOe86w1SkV4ff}G5 zXaoiU1zv(1C;_}c8Bhh(0u6u;sO^LTpb#hqyg&s|4Kx5vfDR~K1UFC&lmZ5$uLo#H zemQGC^s4%5@|Ex_+AFDKB&jFUhhnrZf9B=*%fXkkFC|_Iy`=Ka{Mw7D7a}j{FQlK3 zJs)^J^IZJ7;B(n$6TCNncQ143BTwqQKfm{h)Z>xI^~cl4_va5LvIi0eLI>0X-MRhw zLyxL7!#@0o_DJgC$iw=>>4##uJ^F(WW*Nk9huwXw+C;}?oaFw z?LSI8^#^au?n~?o?Nj$9_lEasdsBNNd-Of&-Lc()-5Jwf{p!x-j_?j`N9xwdt@^F$ zTVl5aZaKU?vR&Vvj>TeuSSEU6zkYRFa%*_2wl%dSvPIvL-W=N;*qqrE-xS=Gy*Y7n z=w|ii+0H~~s8c<@gMVbcK0iG#HZL$QGdDgrI5#^dF())fos*p1HamM=;<^y+ z;-9=We64nEYF1>HJ}W&lHZw3Yb4@(AkALWD_3Gq|@CZ-_9`c>&rEEEW3+T-p1 z_Vo1F^uYAYwD`2(wCvQx)X-FQYH~_=ik92WKYc~)iog|_$??g-$=S;jmxnG_FHiD* z{;5fkN&2Mp#Ms2Z#LT7fOM|?le`ta_A$dvo677;yZdd}{S)BL$PiP@c z)so(@SM#Pk5s&Ukm&Qs1rJ0gA@A{u84i&4#$)a$PR+K7?6za!!{*Q~G$hs1)kV|zX zonfcuOgSRCz5fFR8GGCwv}bJzTgax`l4@Ah)RYn-4}bGt=WB11|9=L>mpcA)c#85H z)$sq(k)9ak-?&~xhg!UZ9<_K`0}r8NEt2S2i&xOK7O$djEncevUq=^Pyn#NpcoUs$ z@fLd7;%#)Z#XI%jyA9xb=x&Sm(ccyypu;UbhyJ!W+zh7B?G~R$zgv6(9dGf)0`N=d ze~T}p11`RT9=Q0b0RICWaq%_u#KqUq6&L?mOq93r4Rp-Kf1zhCzKO26IN}A<=%I^m zp^Gj)L?2yz8=Z9V9rV)0e^-GYp|dW&i{85U9=hw|`#$gob>I){!5^XDE`E%TyZ8xu z?&7E)%%JZseu~aJMR);!jy^oac>#ZcUcC4vI`QIv(Tf+q65y}VnHRr7Z(jTs-FbN% zzeBfP{6F;TDH;rT4BdN?MgLy>0UdntNA&Q;pU}k@e?}i){G}57YZdr6boj;pp~o-& zjxN9WhY$QG$Bg?|J?xL+0EkZ-i4-{wj(||%2?(1GvO^#W2Elf~FAz=}=(2;N0Hhc_ z#6q|UqR0gn!&}JRhbVF5R4IH1;eqoYyu~2zwIIsiM2K>D5u(BiR>GMORq!Q5bvalA zmqOISrx3m>unw+;s7KF4G@xH08hv0Byba;62lWQ98Lo#I1m8mphVvnY=-?UfLByGZ zz?Q+_Q1vMBEI1?LY)wkcmbRiF&bWr7z4LOTv!H@I!G96stH6snvRxbe7!iacBQEiQ6X4H? zOX1Lni4EW+_%-4(xHaN(KR6lQjkp5tjkt0UI0asgyp5?gIuO(B;B+`WqTK<8;P!~C z;P;3b0=ydTkGKZ@kC+JuNX$YfP+W^HoVczOoDH8y%z;xR=E5ry^UA>a zNQB`ZiR-Ju1vTKpT5u5@C9xPiOR)s~Lb0>~Tn67s+yLiEEQj|bR-of4Z)0UMPOTaQ zu7+PFXfIh}#0IXhgKObniFNR>#Co_`g0@d0ZWQ2+aJ0lt@U+CuaJ9rH_*!Cf3AhC= zm)HuQOKgMFg>ONKF}Ph~dpURuyf1Mp+%K^M{+HMZ2Tbfj=UD7U*H-NDfqUVTiG6U& z#BK1(~tX;B$&!!s!(M3$IiB3T~(Pbp`kv zc%S08a6jd3{0?rY_u zesGM^O}tPA$J)SgcJQJCaJ&P&*a^0|z@Pvxaf1^I!Apz4iN)Zg67aH8@Ny40*$ZBw zfmd>%!ztxt%iEY*fnQ9k1gBSl?bTqY2E3{koZ$nnt^=>B2WK{bvl_u`o51Uo1H{=X zIL8LgwS)5t!1)fa!wGh}z_0+XcY_NG!G%TOqGE7y3Am&bT+_M%SX8DWYvn0P)&qZu*U5g_$!nBxovpUFHOds=@wMY{p0PbHoV zKAGV-gQ>^EkE@R-4jxHF5?UfjBN&J<7a!n8j?Vqb7yW^ask2T1KXMmqxpcBgkmc4@RPKxk)nN1P%GrfGyi zy){Ac1T))XG(M4{9Rbu>A{vZlXg>gbTZ+ae)UAmv!7W{zHHsq`qEU%B?E{d$DMDis zNg9*LZj5gXY)sQ00NREmM-hy#3#?18jjYvZ{eNgpHWH5nX!XC+m7taXh#;u1O05j9 zR97Ze1XpC1$Cm4~x<7n_dP8Daa9L()Y^lC9wIoct0VEa&7iTDTpuQ-zFubsPL4Zac zBG+paIWR=y4)M+at>=$W+`#1g5Uu8q)0jh=q6TVnlQiOxogJSYn4P{Za-Bxw4Izpe z=%1CE8J?-mOwdR}=IYqh`qe2KXHaJ(t_oh2p-~1slxh#RtL+Jj7MPh9o2E}oO%2ls zLt;vBO6JPgm4~hfU6G}+g}~%AM+!_{7P>4uDLyGc;|h`EaRTEL0u$1gL}*MQ84Lxp zZE+e=NM9VeSi885*8RsW(rGLqOsoDAV}mr35Th7@sWD+1M@Z0$|I7t38bwG^j6n7L z1dSnNM#gB(e~LyB)Del{M*@+6MyvfpG@u ziU=5K&>E8UAzI-dr+9#AUxe28Cu@(=+J3zzRUNKYs}ohhs!V09Qm;%=EI_p)Q68jm zfmoSdmeRsBDu76U8BdJH1X88pQneIu0K1Ac8Vv{)WeeklhyoaKYwn~7(MUktWyAo~ zoJmK>ku8W91Pam=0Z_9iX$&B%#?=7F|2uT`Pk!JHvlz9CM&$f z)*#xy#n=qQ=AEjz29;jUyPOQ7-@ArjBR<-!1RkTO@yHa#Q*?|VXx|gZAlmK3_^o#2 za>e86o-40+{Cv+-o+{~i%G2|dx92JC zaECP~st$*(rwUrHx1MV5nyk2u+;<$Ftaw~h1Rent0VRM2lmnGOEl>|M0)C(wuz9bb z3jhLe10{e4Q~;Gg4Nwp0fUS+-0!jc6paJDT1yBRj13F;qB)EV=pcL=|6+kUe2NXmJ zg#c!rcrek#gNY^{OfT`+0ZcFPV4jEvb3#0r1wnUCz>EhE<~evUyTOAw4IXbRRmpn5 z(MiBp)*cT~0pMF`559KxU?{|caSsnhH|U}Sj9Bo9ga^Y9bY%jD3n=UGi=zZM?jCsQ z9=PNlxJ@2-L>_eaJ?PbY(0TWukM2QN+=H$*Jp}}Gi9G24c+k!9pikpzIz(s&>_-R% zfD0%Bih(Mi2~ds_>_9Wnc#Pl&RC+=^c0d57fETC$ssJC*1T+Jpl~4*e+NPeUa7Hb2 z(GD(*8u2Q$;;bRrEa7(DPJd&r{X3n~~-64LwhZ zBR&3ANzYSNJx?|DJmv3ss<3T_H4)xuk5lf>%Z#>=_T-|LvWN~nu0xk8?x*;;kW9)` zYD+IKwegv)(B?zDd(0~e{7H9zcfZ9eV09-&RPzF>1KA;g$I|)vp2=D@xfDdQ_ zY+VEaU=-a`4qzDE(*&r82pGZkV7S_YL1_<0ojtXHAHa~X2Sd2@yb~}O>B0D;2V;#M z3@>^xmgvF2p$DUc9t;V3Fbe3wz@GM^&iR zZ~{dDhO#_WKqH`d2`-=*@B$bJ@>ByD=%JQ`ptcbT02fdQVAO^3kAU$M%0B{zNIVz` z@nFEigK-THhA%uArSQ}NN+-byc&90j%c<|-=4x7cWU6sEoDXa1&~5Ze8p!mN5$Fk` z&4j5+H@4Acc9+veYlVDR&`EWvq?=FyU?QIfQ}sNUg6F~1I(m;$UX%mXKpoHo*g6R= zpcv4ADxePV1NJV08}I-=0N-SIY=;Q=j)EQ$0={o z6-&VIga<_{kplyB@f#lzIX@Nl!h{aE#!jB61ten$t^J z9-=+!j8+X(I6at}NmZPHnUGYS37F>S!MsL~OQ9Ps0m=X$&;+iT*#pb{vF68wMzonUu6 zb-hZdHK*p+sH;9Ypk|9Qqzdr15h{U_D51HVfUjw&SwQNJ5FCI2N`MLg^Kc#5P5TM1 z@h2ZWp&ou$?%5ZAJNS0?Eo0}t&ka{Tja`~=hf$v&xN1U$a{}G zt3R85CiYB#{P+0N!KbrNC7ueA2cLX0{G|3|>WRn``V;BLGY10)Gl_WO#4Lp5W8ufN z$5Q0Q>yM@%i9Hf{Btw3D@Zs!3iHAZDspQFrAJiU9JrH@|-@o@?lDzu(-protZgqEH zSD0oSs5_G6$A@l7Y|qAmu`K!T*=>n!p>46P=`AsuRe%`<#%u!Zrqqp*8}%F08)M|R zXEww)1UF>YC&+VG*X!#dYxT8}<2&}LUCGtq)!ORds>n)xWqL(yMVkEeBzfy`^3}b& zQ#6{O?@I5C?F{V9(0D>{NA}jltszQD@|N%|+AXQmob%9kN|Wot>$G(#8fDPerq{&Q z1lD9|oFN#=b|tz(T{7LNRS_C(NUw~o46Mwoh|_pOc6nlXXt~PwpxuyK7Fnh*OVgM` zU}sjX8K+ClKZ z_{eyDe454x0vBb*#m5E5WydDQhQ_L6lNW|B z)M%U_GDaVh9vvGUppk<31;Gol=O@k&(O5xpRCts&Dm5~4nmYtW&eG3H4~@~-L8c|% z5^TwynV``F^~~fM;WM-|QbQs`^dafNvB81CnL+VE!9m&PM01En5t4dX*Yp&PBk2Bg zQ>-b_l%bJ?U}Lr+(GY4-X)GaJuhpmOB6T{ACd7OJU#2!ttJEB+I#AhF(N^v)JL)~; ziI%pP_=}Gf9(H%raA~VkaU=^;Gzy^G(=-ntpenQ@X!N6ZY5l*pg57<^9RE*IqB5|% z42jlrapC7(#vj%iABtQjVJx*7%c~$(Gnbicxf+F1VE&1IiX~O~B0qg0Z=yDFLiRCt zm~6Qk#kwM=A4{FTm{;(27U^c1Z&%th^V9r8oAcOd*4VIN!*DjY{^Uy*1^EYZDd26C zm3J#(3v(p1*YzhqnT&P4;J8vR}!Ys4bk3{mfk^ z`!q`St9b>xS>#TpED`f(e@ga0EDG}PWy$WRGCiPxEzA*2V|m;H`H$u2@jW|_7j4f+ z_G=bFnE<0;$MNO6m^Ya0e?!6MTLt;`youV(3Av5A(`27U!Tx7n!8=&wQRaOnTP`58 z7VN24L4L!cCreBg^X*i?2Nke|If~g=F_%UwlnUCl>Uc5twwU+7ERr$_MnR8ffi=t( zCi^ok=x^pt)K*T&?abXK`!ovrNM6A>iyUA+V6q2Z&}oa_$pt+@>82w78*@7IIwo4` zRZ5@B``50@ZNl60asHM?PwE?`yq2#XW!`METXjQNM&!1n~+qZ?Xqk zZ-0_kt&0`5GB=uRsb+O$PPw_j(Y$gyS>hh%ev>U96Kiwprdg4i(lIrB;{-%~Uc2mO z+E2yLuN=dz`8bnT?=jZ+kogUhEgzGfEor}Z()d~~Q9sR_sGo2`e$V`s$(E0a zwbu6PKK|kVIc@XiyKTQKaoM)g`hV~5oVG`4{r|XgoVKsi`v3DO2H=-z{r|PUcG`YH z>;G@1*nj1;58&2oY3)Ak0eFD+0BEH>01i7{w&}D7z&o@Dz-6OcwvP&2w#BpuK$_P6 zchVjJA5+}F{S^Q2Zy~pBr%tf~X%B!`Y5%`Q?EiOERp!0*;!ocr|9^V!`+xZVgQLd& z|0kE!&+=x#6>MjF4%6r%uaf^* zex7iIMpp-8@-| zd+SL3#v&<`U{vGjEHIZj(_{~{8vi!0+Co-X%Uo`<2VRYTmsf8CYs8o`tIeO*YOF+y zm14!bcQ*cYuHFBCd8PKV$Ro`AO!jG1&fn)1JisC^GoLZp1FxLNEP67hWaYevs^wo4 zu!T8_+3(8PTW=|Ak(5a=DrY+j%wx_n*#oVdf5@x0h!xf{SD0+6W^H3n*<1Q!Ub#&y zv6s2sWXos4S~pMKr2i?e-rcP66=uq0%O<^N>)G$#Qobhr&v_H|El$W!nLjky@~N@5 zu)X${PVR~PC9mNBu*jd7zcbnLsj>D%PSvDG|Mgdko_uO_8l+bgRe6}6mqwpIpAZE3x668#LtKgo^u|E&*6<3X)a9wW&Z z^GxP2W{0wo1lLL_`5DdK;>N{mS9dL1HEHsciT<ujqOf+Qz)eWW#4%N_T91Y+d|H>6o!}(u(jBDpB+OeezF> zlq?h3;wC6FE>pm>nXSyl$`YzQyz`{|1AIoEJUF*_$)a@|7Z{c25NFc`N+ z6{WYk`^2IsQ()ZP`F#B`Ov}~zkP>44ArFL}L}kP3WeagScT_WhszzSH(w+WT+MIH#?e{Qu`^-~Wq#Bd9HTnJ9UUS+!GzO6PnbS6Ggv<5; z?f*BG{QtMe|G%8}{{KGh`?rkzf0v*3|D$gk4u|)A>wWV7pUgSX@c)Oj8UDY#HRCht zh?Xj)N}p|y(~>bVql_{b#o0hQlriH>wya@v+WbRe`Dz#~MdzR1Ygmo)6kTo<^GxP2 z=J7%>D^aUzydL?+`lw&Rq9^r@du!#Zk6@mBY2(OxZ@soWZi|GxkZgILrmI}5fM+w$ zV;b!a)vJ?#a%I(L!&7Jxlj6qxoX?kTV~#i3pW=C;TYHvn z>N*8Hn;BrPr>_)yd)vBrEBN)R`h1vasx|+}2TaNvcQ%?Y9%No@virWXBBe;_pf?kD zc>R>hYJWmO`T>*zNM=<;DjA8JJdn{|^E7#Jk zF0%;A1Q^+P6<@xCIoD)Mca*b9rjgpIg5zJ!n&j~N+@n^WS8WL^Y+x=o+340TQ*Q3j zmo7HO?q|@L{p3}%RGyb_%1QQKOnHW=EfH9$J%*-dhvDMM_G`)&wGx`SO#PhTV77KXq#o{Y1BD%G(>s zhN`?wn)R$Ef0O4kdg6Dv+-vUR@-p{cq04Vqz!v6t%*8Y~)m!vw!EVLkjmG>Ye#e+w z<3ScNDQ@K77{2tS%r=uPTSiKQ`6rt9CG+v%yjqL+`kR>RO*XVvQ_F8{g+n@6y)E^5_^sE=~e}7VFs9el~^J79%YGj z^n8P!X_1riMwyM}i%()+VzLKTW-WQOmhknrFgKd)0hZZOISlae(7duymfFsgd95gw zpV)1WZgts)|CiJD1^UiEe6G{>>&^6?{(sWG{6BQsUipW^HlAYteMr9l>MLkYz~3FV z`^f(vOum0|w97W(e`#~I3tYB^Uvb)wO>)_Gyy3LfQvAPX$@d>id;fop{QvnB`|nSW zJ8e7u=(PD>b=saI|9?Ei{`)ZLv@K3kJiq|O0aRSJGY`Z6w<*buA5Hpz{QuJ2%tQ0{ z|0h!3pE`DyB}e36%R2T3)vo0V*uosfG}?q^@*m4j`Z684|%X2!+q9)aiY;5OiFJ^X{?9@L7C9+zLN z_9q`lSQO-SWOaO(^08Y1TbQj(1m;GSwERSk>bOC^IC{M5M_SaRx{-|+^0g;2gC-l< z*xQ#-`Cs*;@@g&S>u+XmFxj%mta;b(7UcZAvfEhdcIGaVEx)?7Hp8d->QedS0*jt3 z5?O%nQPJI@fGy1Pm_`Bi_B|p-fT;l2E(ot$+@t(PTg0TeQGR3i(w8#ZO!mOaZ%kgT zMST5D%=ISww9D_pys}$aYCm(Q$sTz5jkV}m%kKj!xjPlGg*lwr*8^y*<~#lX_VPv; zXVH`TMiGwVt6#>PV6q2Rgcs%2TFTeo%DmBJpLP+B&np{ascz;TlRfYvyx5{=EyB-H z;l&lOg&AP>^#~g8BKZjRQi5$3IVo?H;8?!+B<3Y1dtfCP%&WD8ufK)4(PW=?30{&{ zHp)_WFn62mftTO}i=MRvQ&e_0DPRlpJm!YH{_cjp`VyB~#H6@Ue$)BViGO0aH!5HYa~KnOiawg%P+Rg;Ni8B4;Gm|!%^iJ=)NkJ`wNDvP|g>Zvh0R$AJ zL}Hb%p=)dnRugrp>gp z7(RUGY1+KM_ju-=_kHJ`C&Ep8T%{9CWtSuigd#TS?4DQYM1!8FBvGZ`B&CfKSjTiT zQ@Lrfqe(q^m}HO>@>;EWIq@Y-pU&=etzKs;yPTyqFk5u?xz_3@VxoU~vO&*St8Y?$ z-Xei@%t6dlj%q*kT)MKGzWc9))&ZWRHGr#V|9_O$0IsJsfZx)0|E=Cg_xeAyDk0kY zUw(^CdG5PbWyF81%G-4Bf9`sl@@Ja+-%9uXv*`bQYi&wDn*V?0J*zUA)&SmXvnk7H z{{I=>`+uO1RjF;YDJMRq?+T=60DkJXDJ$bvC4=_=-`jj<{(p4Tr}JN@`Tuf!834U_ z{y*|>Z1e0fc~W(9rI})=8BtT315D?7Xk;$b*}Zmvsiv~aSZY1fud~n90jL6!tDVyf zdR#RG?X)VAzDrI29Mi?TnAw`5_t#FV*3_rfbc39b*J^blCqA1wQ)l<|mZ8^FZ2>DZ zGaGcaSZp_T`&rt(Ak$kVr)HQ+hFIn(Gpw_P+Zd-n-JW^PG?jgdrJiAm2G$>qTW334 zyP0KB5TA#m;2zNT$x-yo;CFiLDAyb0guLb`dLhkDXE``Z16@NYFZx#?U0VYi)6hzL z)p(<3r+0s(Q?t7vYtxlgvqke6J*L~uH>Vr27M9f)OV~!Q>DYXM({ocOh}&Am=F@6b zC>V}`Ge2`T5;%2(A$cJuZfhZVt%=TVF74)ghvw?^w$_aX4Uq}aRsE2X`HBR(nEjdf zTKUeFYm&1?lfG)6K~LywE;xx(pTnG`vwPZC%{Nu6X9YjAQD^t6ue!-paxcp~$$V62 z3uiZaUALWmfvN1%EcGSk37su2amK!?>%n-vLGNt8sgvF!k9n9mgn129^P7&VM9Gn3 zt2P?%WZ|k!u*`g(T z+-==#Dti}89c1p)*`g(l4%Br^E;8upTN2lxlT>?pX7W2d?*SGY^n|{+2pRR#S+Ca@ zp@weA+H{50>|VEKV>e{A5^8lUO6w!XT_PD|Q(L%5KPNB|N*dJ#xlXDa3>`8mm^56zy#|2G0DP zbjH<&_=2nPEHP!Lk zzpyHcrdpM>Q*>|t=T^men@u@J^Z#N0vnoHn&Z?}VJpdUr|G$^!{+0Cq8QS}QHT{2+ z=KkIZHsx3UvMMb!_y3IM{@bshH3HiI{}j#r$BnfrAOAgF+1l5tlm-o-5$2DGnIXb zrCwo*M%EvV!}gAIRO$43gM#?HaF+MTO};IGbH*+LSFN8<`CuxCTeyybv1^U@SWDx!go6E0=(TIC^De= z&H_$;HFK%X?uGAcG8J6QBHNj_>Fi$lPQX-h56c{49?;o64*(D})q8_Ae#|_nvxTo3 zou=D8+h$YQ4_N9$rom76N8=;@o%L*63<@G0cqb;V?~`}xnZ@t)!aMIU2#O47-l><; z?DV8yFPBfZc0<;xE3IbZ!Kx;DHrBWfVdcHk^{Iku-PsK>n@&u#g}3zhI=HPHvKE#V zt*k#9owTF31Ws>Hp&+IsMsLxYP_Lr117~a=BLzD7YyNPyZ=B0?WT!zx zWI}YuACShMByb3GBr{bgmSnuewPyYCE`y@Tf#&h`oPHB?na=J-e|(pz;5ruB!Mt5( z_o_d>+f*{dGKZP>>+GKQ$Gc7SqO9=~W=v;`GtB7f-R_U?F_rx(OZ|cQE1fOI4#xht z>#@TggPz`5(L4W?d*?IE=68DItRaJ<$bsmd&uD4t=}E<2cF%jeA#2qYSF_Ktd;T-6 z0j#0>{}ze?a4+5eucS4AXR>U{(5r3AcPRGX?EW_8Q`-N3FYW(#Uu;#rw1J-C|A5v9 zXbqsDls;EyRqk3xpQCkvW3&cvRk2O^c9Bh)L+bz^(cFL45S#Kpiv72X{`aGO058z| zf5c#$@|J_151<$Tf2H~VI?Vs+|D8(*9goudzc?9egy;XCB)EZ-Gsb(nQ71NCooKf3 z@g84A_H{#6YxT1|KwIB3o?2Zjw%(UQOk7Zm?xsnK)4*^HocTFW-$^xs(r)6^w_i^>tRviSkQ4Ia1cgw#PE@mTHR=5J zGjFli-F|kS9Vh64Zpc}6a+-aPC#HCi`oV69*>qx>-D{6O*bP|=%Zj$uAB`U0aoi-G ze#oF8KA*}*GFdHEKc4(@kTZjh4o>p0K~Ly^K~C~WH{{NnlN{=X*cad=hr1!$*?HH4 zZc#cNHi(_=FO>)&D{W=gF$XhoBA6^riswJ-n>+Z+qXs>puldW>oceg?Xq^qcbAJNl zF;lIjoc`_1^*URe#N42>MXMRBuiM`Lw5jZ7mI^U<>TEG_F?xU36PITUdZJZC8~&PF?^X${ zV-9Ab4NW>Qv3I|d4(wTjp3v8ta0aKolzFqx7S&4G(7(EWGCXH0yMm=|VYcdQQLV<- z?7CW?H|U96i)#H1mE?p3)-eY&G1fGx*7n;F9nXy820fv#RqIqveF1Z>&hEw1MZ{FF zkww-pSLtlAj$o|Nt^>QiV5+yDHJ)J}(b>XpjORtSPsbCcvd^$LJY=0rU*OS7`tLWcvRe&Hb0rGXVdldH;Tz_t(%Gz;W6G zF!ds<@)Ozvu!8pge@65E-SiAV$r_vT)Vo$?_}?iepoKn1bN^3i?!WaNt5QtQ0US+O zmC+un@|#c6m31fa{J%{pTr;=N*V7hC6ZC->ol~W1&qOX)PV+=*Y#>=g2mN3#1d4!S zpadud%7Aj90;mM401JIfy*&-U_to32fDKRqJCFfn0$D&dkOSlbd4L1R2MT~fpa>`d zN`Z2q0;mM4fNG!yZ~`u%7U%;=CkZm302Uw(NC&Kd4dAcd&VrQ(^YLE1&|I zKrWCE6a!^I1yBXl0P=By4aflsfHI&Ga01F31S^mUgeu0Ln>1I$#H~fNa14 z6ai&G72pK=015^Ev8MwWKps#6Q~`1x!3tyoc|b8x4mbgM5J3UbfeauQC;*Cq3ZMq4 z1uP>8R=^Hq0@;8AC<4lWD!>J#EhN~19H0Ow1*(8rAibH82{?dapc1GB(vA~UAPdL? zih)W%d4r$=IY1Fm43q_8Tf2NVFsKsiteQ~@qP{)mtU*nkWm z2gnDCfpVYs~5}*p`16ZWV^d~?zPymzzP9QChUQlU659JgJKo6#96%9J22=skbV53i0ptROKp9XCSQZlOKrT=OQ~*+dkOrtg7LX5= z0X0DS9)cCH0V-ezGJs4%dp@)9PBxGSIDkT+6sQE`!-RAo1IPgifD)h*Z~^JZ2^l~h zPymzwkE06)?0(n3_Pz00!<%ITpR^uHf-~!~22x&k%US&DbcfC>QLer~S;q&)f_ zdId-W>_9G102BdbKn36gq(KA)NCWIZE>Hjz0cAi1-~{>r@<@ULSO6=a0-1#Nd}iaF zT)+Vo07XD4P!3c8l|U6x4b%Wmzy;I-eSp4z+)Pja3y=n+16IHWsDK^F05X9rAREX5 zatZDE%)>hlARj0I3V|Y^7$^Zsfij>Rr~oQ~Dxeyu0i1vfkoOQ2zyhQJ>3|im0V-ez zGJs4V3&;j?2<`dI#XEU`1IPyofI^@MCzz$>p znLrkh1LOe?ARj0=IYv?oioxO%B1w^1`^2V~-n zEFc@m0dj$Sz)nyv$$*&$bBF_G5zL{*FiU_^pbV%Ws3R(2Rsl}@+SpYuQGcrN;^?^*fT z@H5_L5>JPo_B@?U~sxG!piO9pUI<|6$kR*rDJd_o4VBp+`KABpwbw?0r~%IP#G1 zA;&|}gZ_iAgRuvt2O|&o9&kJmz2ASo>;Bk*-~so6`2Ns-&;G=H;rqPz$@fL}`Sv;X zMep_B>$*3#H@MfmHy#RwJfXy%@E-4;z&-AJ;=4n;J-ZWkhwt{@E#Dov%XgRKuIMiR zF4wNu&fre>&iIbd4$qFn_V9M^c6obbn{S(ATl7x-N}f!Q0%o#cvJW>bW(sF}%^cF>s6f zmiUIy2G54X`tW-1dU<_hoo}6EU39H~t!r&;O>m8SO}s7C=4nf`hFiU@a%-f;*Wzf2 z`u%>FKh`WYN1A+1j;82p|7zFj*s9}Ii^7Y%i{wR-n|(JsZjSo=K9?`HFu2gY zFkT<3_tYmAgco=h$O|Gj`EGLD6rJy%@0uT*C(Vo8xbQ~DjnNzYH@I$y%?-|V&yCLs z&GF1h%nr}?&X#9KuJ>K*A9_lRT3W6T=g|6Xl7K3BC!A3DNQX@viZ) zalvu!aq+RCv7WJsG2t=ZG4hzmXy0hZ=;$c_DA%Z%C+Kl|;v+*NJtGq%!XvyRfqJxtK-8%!#%?j!@|S7!{lL+p}wJxq0y`SSGlf=T^YR6eP#TL z&=sC55|@WB_g*ev9vR{r;usRW%zv5dve@9@VE5p-JLLAb6NAEoyo2OHkxPA-IxdY4 z^bd3mj9n7E#C=J8KxlwxK%#%Rzqh~KKXS3}V#meNe*S*0ezCe>ox3i6QRpJiMTrZ; z7kV$0FN|E^yTEZlw6DLft8c7Nu#dY>yf#$psZF@TF0V^=MVvmT!x^pd*SKn8)xm0a zb-XH6<*7v@jksZ$VX3N=; zEMJx*E1K!gbY;def*J0NxIJX|*b{14^{TQOvH5HcTh!{ex~#GEV7fa!o)${;q$Mn2 zi`ODsB8pFOC{fujyW|*6>uZO6dgV80{@x&{ zX(T}g6oALcX|U1(jF{~odYWu$OCvpoe!%3C9;*0W3foz$0}lEE}K#c7R9knXs~eY#;~V5q%yk z2apdG06fYsf>jKZ0Hpwr{L5ig5Zd!uiFc|1o)y%eEFc@m0eFIu2g?EE0|h`Kz%!3xSS3IyPzIC}+Vja%lS;f@1ylnyfD@1c1Q}2O z3y=n+16IHW@QlU|D+9;`c!HA+D+kC0@&E_GGoJ!jg+LKd43q$+0Om#Q`7Fmf6+k6W z1yln(adN_v_7G%10W3fo(Dk&6Mu+rwJe|scl?$AiSmoo#0)VGjMX-v25&$!<_I#G% zopPW8;E7ljtZJYJkPZ`MKmja38jucH0UMwKc7W$^nXs~eY#;~71@Zs~kPq+_uMk!d zPz>;luavAa`NZ4hKm||%2BZU4 zzy_#*9pE`_Caf$V8^{69%yS+1kte$aunGz7`Q+(uG2Si#N`W$<9H;;)fhwRHr~#aS z3#bL8j|eiL02Uw(NC&Kd4Nw6)kO5=@SwJ?B1LOjEfP>JU&wRX702Bg6Krv7PlmcZy zIZy#q0#!gYPy;vt7f=iI0pw2z3Sa@!fONnL*nl&W@(ldQGxIE1*+34VJ)gOFCl7D{ zJZmq2RR|OT#Xt#A3X}omKm||nsxFBz1>;&p>cSXDqZPy;vt7f=gGg9tL9 z02Uw(NC&Kd4Nw6)kU?nAXC~gs0dW)<)Fw-Y$-ajFzW0Q<~|36|ey+(DfpTJr95P#V(Gt=hL!> zw9hDp=UkMCZ55nfc#A4Y2VY1 zr=w5#pK?7FI~F|VJ{Es6@5$&<|54Y`*pc87_mTJ$p(i{~Bpwex?tNT-Jo1?DF~?)k zNBxhw9*u>AVRtxwICR)^IB_U^$a_dW6nVt=$exEi4<{Z9KjeK#ekgL#chGS#`k?D847O$FnDKPxv11J&E1n-QL~u?#SJ~yB&8&@ABW}x+}ITxXZmOzB9DbvooV_H0fB!$EIQ z4n_jLfFlsyRakq8eQUF;#v}G z3^uwO;|-w(PeWpHc(He}yg0JRx5%+5db9s#*Ud3s(C7BW7lsyk7AES$_1^lx0{4RW zO`)4SHznqW=X>YN^CRp5&brnCPAupAeehnUEMC9`7A5kB^M=jdP5Pj`fdqjg5^7 zj&YBPj}DFYj82RSkMfR^M@2k7kHZrk=^yDD85<$>ay=k0#62W_S?Ds)Wr@Mz!QR30 z;E3DjcDSR1{DWMBVwVOlbzd4E7#ipqn7AZ-iT4uulE?tx0LOr6e}8{h|JcRS#gTr# zevW?8I)9z3E_PAyBKJk{3qu!rE=*hyzQB8dd_knIudkzTw2!}!t52*pSnIBhyFxCH zE8z?~z0N?5yCz;8s`gYTs=`&?D!D3B>8o^9Ml1Xku8LTBu-si9FAJ4<$`YmFQg5kT z8Y%IWI7*_${$f{gi~`q03Vnr+!f1iNz*P{-59Yh`&T7f z_;Xx2vFu>BJ3F2g%JO6-GQ*kP%s{W_{}ltb?E5C||8Gm)|HuA+*YUse+@CkEOQ&8o z-BGcGcTucmuGZN--wX4KsonwBc$RroXZLz9%&Vrd$64xi=Bqke?4dI5h3R?^)oTVl zu5yC5Gp1Dfoh(T!nSGg;GO>rMvl#WsXSv&B)OWHs?MnthkpZzY27(Pq5xw2Z$g*EH zm0ik$%bB7E^he`Xs?IiQe#M|5J}+wWV=CA!64;kHh^g%{S|t8h90To-(ur{YomAyl z4T>TMT2)Tx^c$HAb+&L(%835e{cV0km|t zeG*v5bThlTlXzu^-QRB*^Mcj~9p_gb|z);IE(@zl5S z*Id;%`&xXfTI=fu^>dmo(5I-OOz|TYSN}vD&-w1?OKk72Lxjdzqp|^he`v zz|KyYZx|HB=S9o@k=k^>1lBPxW2S1^WarbqN1TFL;cKwD`vQ$+n^vmFWUA`+_qqy1YXAM zX4|%Q(zf3*2#O4dwuMM5i>zX5_7~r_-!;wGCeF(}%pE$r7j64JQ^CC~vX3d+M1Sl~ z+kW4mAU-eJ_Rmz+k4j)2b1<{J``J65wm&fF34N_;hjZ#J%#}L(JT&cK^Dg;^run*^ z^Rk<{U1#^AY2Pvx46(>z<^wugTzZX7+x4aQZG)b%q5ncn{I~?xF^4cyHMAJhnDx*n z4T>TMT2o)c>9;Xg>+CPSsbi-33UFTbFn8+gUNrSPrh@mf$fL}II=kmh{Ud{(v8n&c zO%2vb;1Fhao4T_O`(1;g$bo2TsI;-lYNlp?@lE}nX}$uSmp#m#I=dH5{bN(Xds*aB z=0Tm^gQga3de-qn`W}Gg^c=uDciWYPm)Mj~X#f8vdJf>@U3O&+#Q;dBX94z=)3f|L z?8;pf1MuR0R^>H%4#2gYZn2fv_!)qo)3g6$@3brL()0f<7g!aUj?3<_EB~d~e>>?J zfPz+=60W7^|0xdOcj!9+=1>fPkLmgUW<38-$EI(+Rq`gy|4*#dvc~g&rxyQT8@iqT ziJ_828N@Z`6Y`d)C9sY;m zO*wvMP!OLNZj_*AeO3bNm_wMU+$ecPYj>mOPR6A_HzkRvF9G?4CK&uT8aPa{4=&cj)Xd-jRM|ny>wwmm|!> zI=dH+^jlNGV=VGCQ#gSB*d0guok2l-UO3X5%Mw_}yquZJt8%oj)X{|v=;T88XM?23g63BvSYQ%! zoX+leWx%o}xfPae@v-hB9%so+u;S;uVB**&;}E$Xg&$FI};-%IoVU((#a ziQ)jBqPc(LT{L(9zE#;aoW3KF=Kn`%{-3kct~^RH04^PBQ(mX<0h~%}055N|E0gHE z06(Dl|GEpUij|J5x7rouO{=n}uT2?9-vjVfivM@P7Q6D=*R9HUS_AkkefM7*&HsNE zuq(}P(DVN^|DSaGiS^&2`Tt+nX?f=P{~KrB|NpmX?FG5UUS+g<;O35$Hd6kex4cE@{VgM#?H=Dl^&f5?}9 z%N)WS$?UH8b~Zp!42mKLn)lA*^j9z&bapSi*J3Kz$|6DLEjn8W8rKWefEM+#wGCgH z*-HQG_1^&{ok}y6+r<)JXMROzfAP+nZkn&RI4{3ozOS=;;k;H;!8nWjnkk%4f9#I) z+6)Tf^P=nhFFEfYB(RQoITOQc1hq1}0%F=`Iu23|k|GP5_j*~t$DF6Lg)>o3^e@^) z#NXy&_Eju)Q^92{vYy$jvwPn6W|-=2W{uaFCv^6CaNjQ0ATmw!^(N=#J?7gwyBF@8 zWh(eSi+s%dNN0;Nz0rNUUW3Rs=m|#=&iolWGgv2qmovNV%$*G+atx9p3&NQp<71h5 zOwI0vGv}HLE@P4P%x0b4b7#&o)!WP(uQ5;P>@VJ#9j5tulk@T(^KG5o3un$Z6?~sX zK4yNTvwQB$1qQvdow-i>A9>c_m_wKzX1ATWvvEbCK~iKvbLROhu#(xRvwPvpMW%vn zEV7xoQD+Oma~@X|o66nA65n8cRcC+kzFcCOueUibzhr)(vwPvorKWt zzAT(pfBYHE|5wob|3`HHfAQy5q&0vOH1{7( zdjQ^{x&JV_|NlLT{eJ`P0r=e&HsubQ{}<5we~E-~VS3|hb0XvWhWC7VgE|3Q}fC8Wp zC<01=QlJc|04jlM0_CsfeauM$OZBM2apdG0!2VEPzsa* z_0;B=yfEBP2D2H~~89*kG1>^v^Kpx-#@_|C22q*?hfC``zr~;~i z8o&kA0#Y792GRj5U;|Vj1IPrjfNUTa$Rkh=9k2_4LZBEZ0ZM^#paQ4@s(~873Dg48 zNP-L~KpKz^*Z>vC05X9rAP2|=@_>Ax04M~CffAsUKshXjT>(@A)j$p41Q3A2q5u{k z4X^?>Kn3hTCV;RLmTVvg$O9ZeK2QJ@0mT40{ z(g7=A15_Xb$ON*0Y#;|fGzp6X$Oj65LZBEZ0ZM@~pd6?Ks(@;s25>tAe}%t zw8FLlb|3@D1hRn~AQ#9396$k32owRu0D?qVN`Z2q0zg~{OBGNJI00!7K?W4S0;B;s zKrVpT4weF-h(I|khFt=b0p&miPz6*2HGp)Opa2#i4X^?>Kn3hTCXfXnZi6Kk$O9Ze zK2Qi00f^RMDFw=aa-af0Yz7NrGf)m|U^{_YKt4`T01J=?ASQ#w1|TMb#SS1Gg9YIj zEC|P7$pLZ!2apdG0!2VEPzoUKf~5ke1gd}@=1aPNFz`V5oN(*0}x=rf&dHD z!4tB8YyhzpEDiv{6sUVA6a%F|8BhV#0JVVh5kUbg0Ae6eFHXn?a)3Ml@eV8nKoL*^ zlmg{I1p##k+XeIilurlY zoHvEC2_UKfb%g{(6`-z=fPexP1QejIkbr;!76cNoAclYiF$5@wh$28;Apx-iEQlRI zT_FKs11yLbU_rzH3nB(kS4eOH2o_*LoB#_#1XvIqz=G%i7DNZIAUc2rfdMQC2w*`# z01E;FSP&4vf>;0+!~(D&7Jvm|04#_AU_k@`3nBnm@bJF{&;3&l@#Mb+PySo*x5`xZR9Pkk)`5A0K4OTe@G7Cg&MCkX*h zaMSrgz;oMlY7p?WwgnGr(+NSq3ZM$80p#ff3y=<|Kqin4J04k6L;y#d%L5U!<2qG3ZVP?$%k z21-v7vM`>g09-(+M6Rsl5h_m-(vV_0VQe5<;e>Otk!C5NBH?1BDdiE0fEu9eBq93~ zLM2cOlp$dY60SnRRwP_`attM0Ttf$o3+M}^e?lk(%7Gfd1*A!1NfgKi@_{0t6sQEM zfj&T59>ES|19?C`Pz;m-Re%eSrxVhE3?K{00}6o>pbDq~T!7R}umf2@4nXCTK6)wi zlINwwi{Tf&FUl`QIM!eE1^)}K7h;iM#2twr4;}X$Pdp!f-ut}#eB?PFNBi?X>v}f! zOz;`^Gw}}b{yup!{G|6u`N_yp-%-cW=n?-B*OAy0!6)2L#2*hm?s@#=V+*@@vVUZX zcz?kM-4Dhe2tD9=AaQ^Ae((Js9S9xp97yaB@AvMP_ebvY-RHP3y3fDQwJ&yW@Lu=5 z@x7tFp1p}sIOGk<>OJ^p)K_r!Jwce{7Laku|&*WIzZf_J&^ith^T^6X0N z4Da;rly^pU_;xsUM7R65ySB%+1-H4k#qSK=>A5qpHN4fkRZhnJJG{laMcxwG?Az?v z91Z$|u3#(>47daFO`%PmO^MsXw|j4wO`h=&Y;bRguMe&FtWT^9uk)^x*G1O));iWk z*Z9}C*2LO^ZSJ;sYpB)JnrI2Pcw6L_h~MXT_@mAKW><5pX<;v7|H+M!hLPQT&R?#N zEbuLGEQsFZzsYq|Y<_UQdwzUgXr6Q4$s2<=x^Il%5W2y0Lt<`tu6M3HH!{aJ$1x{5 z+dtbiJ9d5WdiVA5S)o~;S&5n9nckW5%*YJi49AS9*YB0Qk?Fqaj_J{9{%Njhv8lnS z?y2!9p(&mziOJ!~-pTUh$aTK!9M?rB`6sz1#U=&~&-;HgE;PY6S2?bVUg^Kmb!F^|;1%vG;+Kam_gtPB5+33m zA`gjN=DW;s+2I~M^B=s}eQ~^BsGp}_qAt+O_$s6`qPj zdAQtLE|*8jd}WTZXsN%{RT?V^mbgpe#i3$PaiS<(I3w74Z?@mLZ{Sn(>d5|MqfLyk&*n&BTi zn*08D=>C8I4ch#l@Ba_d-~T^dW>_N;3kBL@a;bER*5CFr`!X+OcKbo~j@u;54T2&A z+Una?oO}~=na&ogQs!k}q(8=zfYJ;T6 zg4VjjSisL*p|ijE)~zwk*KM4ayP4Z`b}w4jX)3sfMfNg9tLTs2XX+1R{Y-}Ae`peNc*YwR(Sf(}Rqr?WkeiBoyC)bR$k zh$pgIJTls`o4(K>C^De6G<{h)No{3r(%IskMaOQs%iGr%nF`*`A`db5>Fl20@vAe{ zJHi@2XZ}QI3s*L_;Q6}_^)t=aA2=`nVg5~L3s>&J#q)r&~u2 z{S6A@^P2P4(F9YHK4%VLdYGx4S6qkMowu`ld;<)UA`6=P&S!y@%toEv3-`UmRIrUj zHZwQsY$1rVSN95Zxp!!wsoYMMcz_ww+2U+5dT-ZXVRosh-eausQ|7xmTbwN&z4CmG z+6I~C>vx=&e=V!BZ@f&Aw%2YPJ}*7*Ch3hb>nb^n_cAoE8cEwEzDVy7xcfKlGh{bpLvA{~x7i|F5L)0{j-;{~t&(0KPQZrp%>103YYulxegF;Ad`|atq!2x6?iVKi&J6 zXb-@HKiyIHU7G(dOWyy-{NH(4KmR{9%(S-Fa1Cu?-m0@jZ5dC+F0Wg|P33m6#DmPe zI$NCi#xt?&GyiH+y~kPOL*{!rTb%hF&#-P^x4Jmt~IfJFBi%?96p8^|d;0ZfIET zT(s1;dP&1#XIm4Z!68zdbKSDGrOvjc4bF)(r#VMETiblA7yDWk4{-VxFJ88KiPN{* z*|5H?#fQ(f_!hM_w9rS_Q0y~~EZ0Ck4|L9Ia;|A@aME8bUe>m(X|->qbIP(sElsUW zjcrbmiviBohBhZ>bn3LJ^`oav9XD;pl!;TvpDED5+J2}ZUbqRI9@$0Z)(Rb3 zGD*&&b&6xUP;`-&O9Ji80%ocP%#<<%B~p9I>Q~n5Y@O=ZE>vqtua5-UnT5<$dnu^_ z17%ndYF{L%*Z*)v_w=|Fy0zpsaGg3*%wwuL8!_qHqz0s;f1!TqU;VnahE>h0eXH=h zS!xoLT4S$a(Y7J;ROaeO)-^S z!cuFQO*&g#a*Ykx)g@OtJ=LHm>RnXpU`q0^1omYPVy3EA5moNYf^f%)<1~Y!$bnX| zLpl9s=5n2#x?<1Q=xVxYzHa5b+{L_8XN%F5vF5umy7HO|-oqk~Fc0W#(bUFaZP!gb z!=QI|QxBIeqcR*~j%Q9`BCrVpOdDQw6D?cHmKxW!F7mBz>~QwXG-wHJt&!(&$~Q9? z=xoss8PA?{*5ZC>+{DRa(cL0DTF-E5mZ{cePXB)9UY#u*s$;`-^Gv-LCxjhgM|?Jp+(_iB;Kst4*o>fmL~#;sA`J7y$3l8o)KQ2JroU zHf0{I1N>&aO=+Vz07d^!R~~%DrZ|t^4f6=Pk zhjoB=3Y6c=6f1z{{=cNTe-l0XFMVQFmfySWpWmbT|C1ZFOkw`t=Z$~x56Ls`M$>Bg zK3B~TnYwbdo5l%pXRbfbpddc1xqhW|6}kQ$%sS>EW~#o*9>|q)MPF6l+M&0aZ%`BJ zn&%JWw8t_%I=g3{f0L=!5>Ed%<~p67+Vi{FTP-k^4Y1T^rl@ND(dgNoHCequL3~~` z*)VFdXC<(Xc^MN0>#Vm*-fa}URcC8<3k`xI16r$H!^uxzj?vjYYc-##)(lR6C-V-S zox0VANy7~NRcp_BteZ_Uwx2U|gn3wJ_oT;4p8JbT1&^`F(@fz2`eS#_{lx|a@p;XW zhD*cAg^n=CGp8^y(@#B4X-zRsX)tIBZOw;fbIQw@jXE21?iLyo8OJGU+U#&<%ObNO zexs@84%Ruud_ZTX_N8w20830|A7!b>nWDn=$L{n1OAQL*^J2VmH8tFiC2%Tp4pUpe zNI70fwp=IUm1PDwA+NRFLQcGu*{rjB*LKTIHE&~`6U=9IcIvh}Pve#qrrCO(v+_3c zyE?lUy}(LS!FO2XU8ZmX{joc}z$$}+_`K#!b<(xuM*EpVm{&7X^#a-mK=@L}5x{DL zno!q#X)LEbhdE1U_s*A^Of@&K&OOW>Iy<#5b+aF6HkIAWQu~;q%Js+Y^aFl_g7~~> zx{=g$Z%E(}<_Ko0en9Ly(t7av&PD<)20@Vlt@S2w^7EK;b$0Jsuhmqufps2c9?;pT zTkpJ$2--|Dc8oLg8uNtC?nPg)##HbtEb=v`a0LCaJAJ`ggM#?H=1?BVL$35Q<`m}j zOtf!j8`-qJpuTl=iZQ`DgPKs+ylD-my`8yLXZOyV)|+bXVVy(F13FvW;-up1UxBV~ zac(fxd!04jW4^7kh4&ge0b8J(ea|hXvhTChPnr7i2)jG3veBR*KC8LPXlWGHl~o3( zv3&zGm8&F|iG{1Q4?>Pl7K=}}8uWy|<}4dH^}Combhgo1GHcS6gY@kG(1BLv>$lmI z8Fc^u7n3O_|DUZ&&H$_OFg^R9cF?ZunPgLHXzu@2iu*rq13mjcf$shP-r9ce|G#VP z%AGXtFZricd5L2GU%SSpd~XcxDfp&U`5)c)-$l>KCX|)m+IA{eVztqn@qFyf1H)m%>U?Y(IFe1-fU4RIYpzpVf+$t-Olz&g}pzGnQYIq z4#s@~oz3-w1_hCTxWbR7^XuCZID~mEv%6ZkMUxpIGECOyPO@V|Ti{ zy9^5A^O^?_lg5(oZexyPQg9b~M_Z5bi9Z&{fR#78q!@hOZIBYun(Hp-gagc5bhc<# z}G0q>S{bsLxGTKwhnVvjx(Rq+2Y(VR&zIo0((sbPq4^K zOwk_tqj8+yS?_+YK|y?8^zIWV*Bc~o2y-|y)w!Vta-SpccHS#`F*)_=$p^Tlq3~zUOcI-DOh;&3PPNGB}mB1m)YniFej^wmORAc+J zg;Grp5f2#jguYgh<2m(B%ndp_bw!@HtH=GO8QaB~Imolzm~H8-pl+acJ;l5Km?peOXT zw!NHFAI%)9v(dJleOp?lwrv1=z$VaM*Od)?QX*GLxra>Urn1D%%mq3d1D_@;9%uYa z83XBoV*0-G`YBC|8%*w@oPO9KDpJtubhtE?(hV^uF{d-NI&BhvERM97g||kmYdpJ3 zDaJ^$jE@-PguGUzH*n&9<}#g~s!HvFa;aR~R!4gkQO?BItjgw7Rwa9ZO?iaw`46P| z{|{*1KackPf1T$2Gw7cGCl_0l4Y$~ote;wyr)d5^w9KYFy56n~q51zi7t!CYqrZ8X z_6kt!zbe}Mf5&}xrI7aiAEx>LK)Uz;1DgL|Pv8CbTZ;SVA7xWyIv%3=|3JF`f1uf} zT!j1o&5HEg=kLw_0mc9O)h1CtbUZv&`cp`Y|A%l+V*~s<`~3*(q&`p$K8WZ}>Oq8e zQXg`G4ID$T@Pax`(dIVvg)T0^TlZgJL z9z*yi^(n-EQlCZuDD|0K@Yy`@IYfg}pU(%6BPf&_K~yO9g(C0-f!IzmdRZy=_W8kNDXBeazI z4aAmGznKQUnGSx-3Vz!Leg{FP)bHBC?`44BM+7SM2U*|`5r|5C3z4YQw{yXh2uP*I z5RpoKCm;L~0#m8)7J}~~K9&08V(=#jQzeS=KEhS0AC!SVMbs+wLxinTe^v?pybAn9 zHTX-!u~I*Bf^meiQh!wo{u)uO)ZfUT5Pyr{R_gC8;Kzt@rT!j4uGBwR!9OC_mHHBHEUkhj3e}1M#-hd<5K53v$6i z#NASh5O_;1M%*p6q=1+#M@A{4aH(ZQU^#+usTGLErB)&wms(W@RwF8xT2lc!5u8hP zAv%{@i||}(AH?TU`#Ql35T;AL5OKQHi=;usIvMPzfEOcbm)buK9Dv|m>LrNYr4B^+ zF7;Bx?@|ZZK{vv9se=*6OT7$%ywo9xLTzO1o~31MWiov1VVkOBg;S!B7Ui(D!|bQ{H2aT+%I)30)MIF5cx|T?*u2f zz=?p)dyVN7i^N7iOmY=w}35aU~4+qW(C*Sz_lv4 z&Q27?Sf7EnHe`agWPuyA!CP~{+j7C%^T16GFpv)h3&72V;Fcorj$&|Y33z8IxUCG_ zUJmZ40C!e`yQ;vus=>Q!z}-&p9v8Sr-a`y2;9d)OZyLBS9lXy9?ze#lRH7)x{dT@_c(fFJvJ5;{4n9=@ zK3xeuQw2U-4L(-`KJNsNyTFKanD~MWo>0ISE#OOO;LGXYD^{W?#;Z2G^_mKP$qs%w z1N=%R_|+`%YuVuIh)t)ykqbrXRejicn)E`uUKSVG)^{p!KZN#)wPu74jgtk-Pae+Uo1>fxhzSkH0v3!#F6NM;> z@xBFbeUJwJG#&iV3jWLn{#*rrVF!Pi0e+MT#J=Kdl1)Rt^5W2K%@sdV8`z|Sn;|I)zE)4@|#@U)F+%cQQIevs{;k^xe9MPgbOn2wNusx=3+Au^z< z=7DwxNP!lKnFtlAW)*_jMPLr%2CBIwU>?E;s*W-+A5jF=0)!D%3oF4QL=#kt5l&Do zsUarIky+}*TV*b=ycVqJ16Im|h*b($Z2@c2KxaDWvVyfXu#XD%wSyNRRH1rdCU_Ad z7OHjGV80yj;#{ylf*7g;9N;DS;6Ow)R4*+A2O+Sb>MjNcmw=Zc%Aq=>47|J?yaFK) z)hjEBq8L{p0HQjy8XSf=i0W`Bc(pX0c#RBRtAHac;K(%4gAj@8C@VPH2980zM0Knk z9G3x(NAN^-LKZj?F%;EFIpB2&rKnEM1E(OOqB=DnoQA-P>hwa;i};G_jAC#m!Yrz@ zO2O+9ZBdn47k8xEx5T4xP{03nRLk9 zBprTzUT1;6I{TJ)>FugYHyf5r2a_?LrUKK>=|mlCgqUUR<|d)5D{CdVitz>yZ0}=Prfg_&$BO1(F$GnM)&&m%6r2hPbj`8xW`423Vrv;_k?$Q zcE|4yQk=r*UEaGA6s6F;E4I_W(?Kx`KiVFo_=M4IzHRchFhwVfZw+pBZH?aHyFcqlGmaFc6O^mZRbB@Ex@xvlwD$E}f#-i?V{LbteYiEZ$2 zaBPUI_fj;%&^q_J*jhiuB8;r@u1U0oC=y|;)!*u9jZhrIgg@kW`(w>gbGXUV6ki=& z?OGjOfUoD^lyH(Q<^zTQJI27|L)v!XM76k#wt!!sl94SHSPD8(0)r-!F` zro}0`plfP$if@WMB|Oze4*zN_V{!^1rkMKCzb zH7q*RM==D$S9z|AUm2tbg3&8{SIAd{DSlvlNN|X2NR*-n%9n))pLF}(4tHdbcTnQe z(53E6V*~vI9RnkmcrQr|2n}!#i1qjPcl3{3?7cWa5d+=*qIJGHxh{N>=c4$9!3$j% zPQM`0H`LeNH`d4B$I&NJ>#a?=LN2!}=JY!q&Pa{7CQ%)#c2~zJMxdiAQt7QsP=r8t zMXcOk?x6U9AC(3vHej^GS0a~$DKcQZC|KkwiWd3`<-%}*ry!mm%y&^#K%YZ)g!4QU z6EK+T%8lmuC?a4u+mqd#<;aR;dNUIg3(!rm0R47{J)(Lk5@5*Yw#BS|iUSx)_ogS( zLKFosX7O7bmI%cFOvoYGEyw5-KUMwVoj;`e|KlhE7G8Y+-}x!qt!+--Bae71xj=Hr zbb(|eFN)m5+@-U7xd?RFAj(-JXp2CV(llBGdW1QEIfR*N5eN_H7SJQ4ya-g^+R)On zx(Q#trC(YL8x%zjv~{5Aoc?^~T%Db29Vnd_yLFE>o&8+Xqo!hwEO0w>tHW+RYWc#|@%qH|90cbSltu%*o7IOsz3HK1y!azWQoi zV@t!?YkFr~_6dWa$biHQWgj>*XwK{ zW^BZB@Sdklg?F;pBg_YNw(uTfLw3`9o-q|Y#zL(UD)j-)YX`q&vWrp=(xALAxY9XkepnRM9aQb=kJ zYnQGku~E!oW)%|-+uTVw0+k;)t6$elSCOWcwN1+wpM4#9-k>JbHCMfu(;mqjrnBow zsil(u0m-}kV_RCLv@S8bYjWHmD{4wBWT`Zl3b~Sb5%UtJR>;(MO`22nun~itkk?9i z1t&h4IaX(*8JpOi;;UcauTVO7&w?UozoD>>YH(I6(owVJ(vlfH&| zxy}~7kFjRE-}{_?$sl}oDJ!LUl*<5f0P}JtO4&wDYIp@Q_}rwZ9UQbHMYsO4K~iKv zE9)#4Sj=3Yvqi8eV_B1XCd|GQ^A%IUl`L{QvsGtf_t-M&mJT;Gv$Qhe>s%+Up3~H_ zxV7WAx}JX3ASo&e&ZE%(`BbfXX7D?`s@B&Gk|GOQwd%z*+m@8PSz1GPiaS;-4}V6j zX>4q0Nlp>!E_BNM=GCL*H=#i6yMfbRN+F!dh3+V5rw`qfPogm1+>O?mZS^m)4f|D)eo zm4)>Ee+l}|zgw@jDVFr>2&|!DNEk*k8gO3=Kn{M_x~~f?;AMl`TwYCMb1h#7MgFK&K90XZ|h$HGf$LG zf8C%ZJ}O+r$F2hQm%yRSdUBK1bha5@6tSGQe669dZsxx74TG%6hUP0HS!5z}yv|PT zD-@24#x6_6d5wH&=fbIPnkvmo76(O}r?Y!fnSs-98ni_9h=KKDQmK_dJJZEXHL%8b z3?nj%r8j=;tm)U!nlpNWXGZ*5$Ub5}#TiaIYEAR&fJ)z%K1-A0&)>wgQ68=F$SEL^rB=9S| zM3LI4FoPt}&dg?}@(vWKQ1gzYYt%0qU@X;J21${Hu1eKSw+NhiyN3c=wNX*^uRy2O zcG4grJ|U`Y4W%+%0`1HqW<3uVI<5#%Di;$I-@JTYtR?@>8cLT;RJin zAYm-x1}fYT3A8hFnA*s^V-c;Am6jcnLvwvWI~48523?Vl^H{W>7$l5EyM+pMr3BiU zIZSQL+IPle8$|9ykB$VykG>vkXVK@SDa!TEn`kT6!?Myj}>5@=`UGPQAJ zgZN`{4A>-Fphgk{NpaL>Z=KcPhX!?#oAXwKKkK1D_iOO<&kYiyGDI(YJJnsO1lpM; zOe|AC#PH%J(p;&2&dgb3CQj?HBpW#Wi!RiHq*Ee+c4jdXGx;{UWnp;ntu|UwOCk38 zFS`)iPBK?Wpq-h;Y^0H56U|BuFI>aOIT{<98fmQ7+SbzGTh;H9YwH_V`j$8^bkY?iE($xgx7F{BoP}{t&COG|i^`+d}*N3+UN^$85?m+W+s~Y*Stf+LS3#tMco^ zR%K-~&HpJ5!1TWqZ+x5P|EB_49bo?Nnx4G>e@_1PTSJYAx)m+4i`rnMbQiY->}&~4 zbt%SJcQRj!7u8*IiT<=&MB&x1y~a7nIl?(;ePbh?VHfLv-Q3pFzrS;s6ODNDn#T5D z^+SG=jrTi4Rz=pkYP@qh0Y5gV7%Sv%D*ha4H&+PkED6*G|2z*9AHb1286O7!UDrol zClzvyvu+VhDf?kE*^jGdWh<%&KMy!lN%~s)y&?aiJYCgNw?_eg=%Ikt3{+S87tY;I z`@ugNRK$mbU*1Cr)k&b8nZ?wmm7O<3KBkq6Fic$3UUNt_>0N&^2#O4JRd46!U4J&H z=!=ELjy+VM3z>FiE;CiJsOo4B1xiFt!UgNF((xA)K`aM^NN@nt&dg<|a%TvZvOAL? zdo_Dv$7PPc8e~N_x~k3Ydg15)XAsa=B+7Lkm1`B#&Mac$3WCZsyaJeP&eE3m#p?d~ z@4r4VWLXrUt2#M14@($SL{Y_wv!5#F4hgg~i)8Hb$biUDSM_*qZud`vim{mYQvpXvpq*LBOttufVqVCLKcZx3yC5z7IK`M9O36O_ zUxrMGOm$V%ZoACCdnj;jF7qFQioPy!k$8Y=@hYaBS;9=^G89%>xD0jL$&(lhLZWIr zE|34$Bm?MNAEXRi%d|5~n5h~Q8K~15Q%j#d4+NfuDm50Ur?rkz>JOjXs$!o|r&)3fWk z{jRk(cI`F?8}&`R@Jpf?8%9^t~=hC zkWNV%nu3V1CG@od4dc{DGe_y{ly_PJ+TFpkZX|QJL*MmmP&!jG+-|T-k5Fl@U=}lL zm?9p6`0M16HrzPywI|qNz*E|eJJS?{p3v7y){j#k!W^Wt#q8O53&i}^uEn4wa;x3i zwM&PnY*#UhnJ%VwYnQ(oN_+svK$fDy_=VgR0VZxcdL(y?K}$RetYXRa&bTN!99o zEp;2PSz88dvrAwb8;sq;HW)Ct1=wIPre&KQOo`P4473>5nPF_PGs9vrFvIMvnM^WC zCK+oo$<4jVy|Hrh-Y3a(^Ij`=-uv9-J_GOf`>U#Mwc2WVc=_)wTOXZs>eTt3txl<{ z&hM1=vtF#(cW+SpK~GTIxZSV)w%f1WzA32bH~Y1HT|sU5Ccjq1eSrV{e2ez%R=@Ul zXEbYj+x=Q#59R`3{lC#0@D4#d|G(;b#4-HZGPOnf^|)U<;b4>4|Ns1^}b}^uv=%s(KpEL&;Fh~p$ zF~G@q({aNLQAZJNp@%%tN1p5l^#DPWX}yVo@n$+(h*pAz(s~34E;Z<+Wwb6P(dTqB z^t>(x&=y)3Bj{v5LoXU&z#uV1#2C10m`-m3&b2gd*2SthCHBngY0s?FklD@j6=K4? zNsO1T7PIBeVz7Ljm@1FcR9P1rdB{h-pzfpdaX+0wI-h7EpAM0e5%SqK^0_FechLD_7x{7z z`L#asl>u`95SceYeVESIN9fe1;C#yi>OR0Nz&8U7e^)2pZ{pq-ItwB4+hGP6bbcpF ze$vi>PC9?kP5!8d0sV9q2k0Cmh6t005y~O#{)Gza8sQ>~!~Uo%9mH5o8WXKI8_H38=a4b(k^kN!=5Is=4G|K=t- zn*q0;H@7e(#GUCdoe{zy+K6@_cvAh6t005yL?64s{H? zO9OQe;U)YGygx|pZ6d7}@}UsPj)iAi|C>MnO-{kh<;*_ zfzJ)mX%fTqzobmSsS+CD1%j{m==2jo`tv%SO++)%%D^{6bcP9o{%^L?8710@P6mF^ zMQ0D4ANGQ7jz8>U_yEJdGf1aN=l5cC4ig>={vZ3uDL<$Oh#=9#z@InM*+R4uAqM_& zg#1&30qu1Ds)No>qMQD|=%KTh=pzOg_}7DU4iP31BSwJWe^Dl9vix6Ecyx{M5I!LI z4}LlWM3B&lCLs7vt>k|XF(6Dt2!m)NqCoIpJILR5GN6m-CVCn8Z+&$369dE`F+{|G zK&vuLw|W532oK={oGNbh`xz1-f`m>q1HqOSI$MblG04E7Av$Ap4y#k(0uOn-7u5Z9 zE(*{YB%0_yrG-4Ll>uQo7f0wch$#I_+Ue{dy68WYDlBQqJ^>VYSCs~6OLgr5j7@OGWdG%=u+&O1VMh6#iId)nxX z5*_qE&`D<((M|L+@S#3B`-wsN9~+|6Bw~aT8N->cg1Sa{>3_yYr=JKAI^b6Eb4?6s zCR%~uOCdVLM1*K#;44u&JLo*nNoN<)L;vgYd%g8_rS$;A#($vvpz!_l_tozgzL)x* z`n|#@=}%PH>ZiXu`JLo(8)>oJ zPrqWkQuuoM>+09@UrT*W{aSw7cE9{m_NDks<$3e@(sSA8;;`S( zz<$5k@R1!P>(&O33{6uO(ouE~JWoLe8YNxuha9irO%8vYw)DCq= z;nvix>a7J>_8Yepwx_pG-kiL-d{geGO{&i?H>Nttc(eE{`oQ zU6h5jfBC}fh4Bl^$y_oi_WsF4`GV{P@e4}lXU>nEUpy~;o^f8`+|;?&Iq`E!V)0)( zD|41{R$*CcS!HQ%X>w_KNp?wWN%73|nZ}ugGty_MXXH;$o?c#@T^w6njHlyjJU^No zojA=nt#E4U)XFKjQ{tzTPR^WcoLo35byDTT+==lMON%m#j75cosfCpjawo)3C>@`H z&42N@%yGtXg$1bvl@W8KSYz{F97+!vLxsWgpgNczNDh?yv;DFDVqdyX?aTKjd&@n! zo_J5GJJW4+7rG92<~rk@C9(Q1wP)I6?WJfo8jBX&GLGH9VH6|jh!H7T4+hPOg1NB`=4)0HkI|9p47|1Y%m@y2ePpKFZ*-;q`&OT`I1%k|EediCAIRj z{eSdlFWy$d^Z&7j?7#oT{(t;`ipRMr<*T`kVn>`YywBst%^HPVC_Gch+bB1{zOZJ4 z`9`|}`^;@O?6`gRR_7k_oRwewHIi-?>^nCXh`=Snl~wNF^UjS^Jgg`un|pW9&9G~7 z@G1&6rjQGTX9}scZJy$7+i}P4o9h)XSR?6X!7koKBCu9?NtOHa6%T(?%v-$IP_T~_ z@+9F>A+?TXsn}{S*a_3@^o>sGTmv_x;5s#^hg^pWn zD?Yi2IeY1Z=6Tib6oq}l2ddn(uib%<WLuZr&2U9nVHROlfAb{4!q+#;$kl+;bGM)_KL=5`hne?^n6q?t%$D)tfc{ zUD{BMmV2msHoT7N`lUjiBs@!4ue&$~IMv-{%d|ygb%zPp$hz6EJIoCtG9kRB%Kdpe zOk`fQyG7wK;e%CfSFN_gI0o+Mo^?8lF|XXyB5^?Ye3jenpS7LknEGeiypnH=%tyix zs@!h>tnD%l`e$@rv7d;*p9uf3%I)^g+9mnt@1N~8TDAT24YbaLLM{}ZA*9ysqs`W^ zpCWAAy>;uY^#<#X8bvn;cGo;#(qAoHQRQ|^r@9%mzvn;uKJA=WD<$b~7G6>1=E@7a z8r618`=#Am)@?)i_UyQQ=S`;M#u>u8=GD4U(%&h(xyntgT`+yF?Ue!BK62fz?Kf@T zS+i*LXWcbYZk^bJO1JVRa=uDnA74A7|quIY8_H5m;!)Y|Ta8iD!bUihaZWioT zJ4Xao3NNg3f38;hthYvMcJca^w~(Pi|jwM!jy?S0n0X!Y*J^ zB-RL5Rk=S`0YB}ZS8Ic$f4y*XmAihol=ZjmZnNdTasZP1nc})*b)BpF$h=yQ zOZs0CK3(N@FR``bXM;=Zf_cThAp-9R->7oC-KF+=KK~{5xEd|DM%BiOGyRPiW5Hd&k#Ex>>OM%DEzNp)gV9W?dfLRv)&zw7;&o4t;vUyfT+b z(wl@Es@!fZ*6AL#Yht<8RsZ`>@ZA4~y?*V;d04j}&;GmqvtRqxFa6q5yaTX!Ye3uh zr+)2kzlwGHzmIqQ{kva#;g9`V?5cqF@h|+^h06lkfA}uu3;dB^`|J<>+Lw*fbM34v( zQKFA932y|@i4f67bQAr=FyR>mfx zo&!LDXdxm*2hl?e5!yi@NVF0L(N1&|eFSH3pn0yYcdmF2)!h}WzbjOKSG4}FuKK(B z>hCh^@A8dro>MN22)WS97!ekSCPK%-w-{r?-q5PRa%Xhtn_8^|_F~Y;Vdu;E^y1Ft zh(wQtdKn3uhJW^k@x(iRsiNBnz8o6C5vx>eN_ey;c&`NOh}}6IDFj~!mF#2qDhho+ z^4El*31ngwK24z|a^!I25@%=VWDI9dNMP*H8m0C1qsEU-T`Ie(VtXT(DS;;7H zjORHFv=O~TVEjsG5PgJqf?i^XXqg1siGCtD1#}X=LqG@NISfRI0YX2MAHP&Mffbh02h@a>60;)BS0hrfC7ZR^dk*VWexcpriBTJhD)t1)M0L-|1N zKoV~y$nQ_>SDo1nhrgElTJmd^uX0X<`qjeA>6eX{i+CeJ?4{C+*{WF$`R7x3FG1nC z^mE2@#j2SN%47j=Bru*SKAm|w_H+sFByi_5RG!Q~nR-%vvhYM2?9a?HGnK)x=aR$%y zOYv+x9xspP@KnEYTK=@uX)2!Vr?HxU@s!LdF+AJPVm<%zNx74fc)Fj*ivH?}g+*yR z-!CrAEQ~EIosh*7{_^p;{jHI!?ti{`3N4K@n^F$3{xS+2Qzb8LRszV-+)R zrc4#<`}0|UaWFF&!wUb|fjFM_=lYXa<3Hb*!t?$@ZyKxo7ke^2F+B0lcE`KRUAeAg zSEV!Gnd($K3mxeW1FQYJ&;8?A??2a;Y^xY~BZU?J3sq14OQCEi9xAuyu2 zQL*xWy4h$hHf5S(So=S#$MO6>7ffRH|9l`7Py+>j8teZTeHmZOSMp}@27t0B=Sg}h zS|0BJP_+VXvgKa5_3FRC^ZyT=zyI-5M47ezpY^+iHFr(i8wIZ2;d{6-vQZ&*VMu5{ z{hzyzFc*^ORh-BFvt|L%&k=9cY! zDI2LPWJqW~`k!m#>XglX_P?!q3c#GQom3<2X5?gU^&vO?#&*fo8S@p;qK6#prZ{8nU#AM{jjP>a$HQ92r*{I|<%2F?L z?hD&i|MuK~DwR_|r%IhU0a%=&MX4@emDFjUQ>xBf00q4WH!nFCph{%)bBfrnd7X0u z*k0(CO*5nMyLgQTcX4x1hJ)xTmO|>nu&`c-p@siSr^D>tQr%^??5^rG&SUdq?mmla zGU;aei|szA|9?_J4OMRzZ%5;Xv{O{>a?XV_KBtV`OKYDYu#eX5rDuLlDZ7`}b|CiA zqx8}xpHsx{rE_Ki9JQA&tkK6PK^q8adTVkL$uchh17+uLVE(h+)0GI76jB!&LOxVF+Kd!k(XG=kJ<@&pKkcY0;C$Wk{F>ajx%=V@ z{OJXsQ{wmQmWj`;^80klWQ|H~<9&o?yHX)_p&?}B9c^X`8*d1W=RW_Rc2qT9^%!zt zjk=qgFRrnEcTtT*Z2><<(QZ^oT^JJDPyV;Nk=<{LKX4Z*+w4dG&X-#@tR{t3RJY%I z@)oSnHD^85qs%vzOrRgDDIxw&KUchDO)DWon83F|G5$v!b)FO7M_ zmRXPau^7jkez3Ym+s#X(esIhSt6cIq1?>7mnX5Oes{Z(dkNd3OU0NgI9^uyCkB~~g zLh8bZa00J{*rON^dbRh@_iL98`nA%Z1+<;#`L$+z-agl_t-$9;PX@KCu?FDZV*S56 zZ^3)a@p%tx{|)_9Q2Qa){#$W3*7AqV|2_D0VhzA&?hI-tt@LYuxY4g&^D)*3*yGop zzR|D!)A}au(Tn_=x!$jR{Gnf42mAj|GP<@gjGP+jv2krE~}&Gt~LKtXoM6pD74)iyl=xi(VETT3UUEu&sKRu z&9sX0+1ffP_LP_tm7gR1FA2{QULdTiVsQeTqrwH(Ow4CT3Qi>|pRTKsbLH)mWQ`<# zz3{3kH>XZ*$AqogKard4w;(LvzH93Zdv4!#k3DuV(3Bm}{9@X9K;+ibN3YL?C^&9(|}-r8Zmj%ucGpKhF2 z?pBf5E4;hPO*zgSmTvCW2Wr8Y*SGTaUALw8)a@Zx)M&a1*cE!d@@GhPlkgH@N?31g z(V&=H$oh>q`Q~(xD{I7DakoAxc7+JI*{J@mtJAM5HJjx$6Ah`3b{=0-Bj$>`%|w|iM4%>N@g7q%ZLX1U6LP!VAxMlXwUt`TyD-Lr{8S4iR;gtq(lZKO}HpI0U=N$(KeT;+D_4tc2F+6)t&YkF?ul}#J+fWM zgWS!2U#a{~aD(`5;jRJx-LPxVja#?vKJ{jXIlm)rs-tt7{3)s8CoSK=L-q?}!tL_M z<}#*Jy;*)Sc0#Kx+X5@Yn|5x!(Uc#7Qn8NW%?%WFq&R}yQjr`M+KTaNHM((e=X))o z7+(U(n{VHRpJLqMh;45m#@!9_f4B??~O!K#H#; z98t)A;jqw_TEcXyH%PT9ZIps}j%`>~YhCr(tqlZQkl+aNOF?p2cn5yK^G-p{2Ek7J z8omRHXuCUh)@!{T4Mba!?gEAE7mf()i3a8G28y!zrd8**<82LO`7*`@=m?Z0M}+ld z-LkSFr)6tfbY}z6u!xfVFdn8TSzojt@mN+i>9nXctJAg<&fovaXSX+yHXyVRD=$)- zJVCf!F|hXk3qQtu{p$kSHy;RSXI>l7{-7Ug^Zn4T{rA7|Yxkan_wqgI*WSh7{Hw9{ z|KGji*LGv>f6G07?X{O+AAtG)fBvFhyXh{!_V0h?*IvZB|0m-6$3ORL>+!e$5v=|H z@NfKD81Mf(fcO6`{;z)RSBw2x8gu{u32XoF%HSP=6~Fch*8e+2!TSIB<#NM2`+oG7 znE(Hek0GP(W^GnH$+Y;I4zIurGMVe^PL=gVRx08C1TZiOj1aAuof^QbUKP_&CohK6 zneIArWCcCC>}kfHaLin#gneVHm9Tbbh2nb|^MdW;TDfOLm!5i)yTcL!#NFh87iEuCT)Wj6JOe7r~W%?B9M>64FMAq$@!EFoyl z_%IG`;lWKXLktHG0R0M%8(<#p7txVP6vUn?9E3t^lxRw9P+D7v!O;{}_QEVuWOoGa zuxAVi60L+b0fdQ`13>!`z-wNPTmZUV0UG_i*zFX%pD|4$icDj=v0eODW`1}I@UR3i zmLS3sgjj+gOVCXCS&RUou|5Y_AP=h~Kpg|Qa;l_>{wV$SMBPp}!_k944>3fH5Y1CS zgyF#LW9tx| z7$7_oKnu}9^b_qoxQpn)!TNqVPDf(;o8s)5ywUBkZ@JUKQEcCSrx%*;{{5I+XSbL# zjOL z$y^kku!>uWzPC6r-p=shF|<3OSy(-Y_BE)976oU=JK`K1TcI?M5FHahFA+NgG#{o5 zjosX30TI+=b3dV@v72>t(dKqy80By7J94$+vC|%a6YCQJDqb_GM~Gg+H%c$jOL!s| z;}DkEtw;of4Wf(a9S772z(gj(J`?D)fWEP7*kO-zvVRS_>C`yulZm$I`~FKXcuH1LQdHUc+JP0XyfPdgu+Vee>4 z@jbyg{I;OA9&wH=XDhtLx%3k1ML@Wd=qGy7Q^HN?58-CQdjtp)EkqZG=OD+2E;dgu z(N8o_0PVyGn=HaX!gqu&Vt^PSf-;N};Zdi-X0j3-n-erRHz+nYD0E0px$0tt=LU6+ z%2`+)D*|H_k9#gh;c4z9dWe1ioy^^VVubMGr$X3A_=y0~LbMVgB207; zokS0zP68U?A-qH@5hB6_`js~6kEq^dBj4h%ox;ZdL!-P<=ZJzRFMw;RCp(AdL}ro)#i0Su~=_cnOKA;2ve z{R2z~gRUbw!lO)viHVCGrzwc%0|FCHN=*!j5X}(;yJL0)o^U5a-0``WAtn(zQk9b~ zc)~izb>$GNl87SA$=CpQj}X0wXI&Ibc*6t0w7>{M^aGbE9vB-<_rxXyga>gsn~pck z3!^6i1c)XgL_`G#;4-Fw0l@kFFi3xle!D%QhvDx^z;FNb3De(0zdhje!xo#-XB!+@U{gx9&ww@<+zqu=f!UGz5{2DAwT+Shp>oZ(*XY2lt>T;5PX`<(Gk z;#wX&0z`-&Vwea_W9tXtw6FYOrvGxt{=wD-PuSoI z14AfWPdlbAWu3=hc4Uvg0Sp!x+hfl4d*C3hb+5w?tJle(FS3Ch$Q~-1(LnGxmu9wB zgeRaHS!o~SULl4O=>8p(xN3;SnJD`)cH%-1bIrlf1FAZ(mmQ*uN6?s&Hg=Zeu-d=lV#(K^?G*0~I{&Q+jwUj)`u8h!v{RcoO8AbwJ` z@|S~-%GH~R*4ZvaAO8d64~jp_{4Dmf(oeHLjsLV<%oUTx%2a+THKk4!evJh2=u7kSt`dI$`ep z{Cl}~%iqd(WWDmp- zl=tWMC-+yrk^e^O8|pU-uc%mqQ2lxV>kk%=GE=|sLiz>H(C4~?m1pzMrk>5`QaLqO zm`qRRo=HAak=gm`mkUp&pW-@$sVCGYj4u`U8T*Pd6Q64f<{n8tQh7N4aOz?8;lixB z_}K^J50+(J!O8>q2kbfcvHLRj#_lcMlf9>OckJ%WU70&$cb4wR-Vwi}yeGFOxu>!_ zzdN;C-Cfv~-ev46W-^&rrZkbAh)-}9etD;{Gj>~PM;7z%^S7jKQL%R5;k$EpCy#MH ze>!7iiW8ZM*hJ~}?Co)+m)lvqt*~S2)nhjguT5R6UR&6l-fV0xUX!^dc1`K(?A7tBx!PdzsyJ2}tXz@5 zqOvi+vAiL-A-^7T|1US3)dfpq<#oAr$#s>r>e@qV4qQ5MNn&+m)!~%~S6IvA%hMMb z7ZoqeTo}8sl*}gM$#SA3YXz3i&z+wCCM`@XT;7Zot`~Cj+Fv)i}UfqsCC-dspcuElg*PdCl;|D zU~ExoVRm7BVHqm|CQqnLTMOi|9-z7)HKLBBhSlLhEFCjqMKfc@%+gSHC_a=Oj1SIl zA&}};u_B<_RXD0;0M`R78CfH4WFw_;HXIL^@keL^bYa4#Q>6j^P~AhD;!1fEO~JoTC(9L=9I-kEXju* z+sQnRaaG5gpfij&h*^>jJlK;Mek9@bAQ;<}b&>IlJnyG-^ZS(dcWl2{x?ybc(8BNh zP|7NheorCw`lESL{&9AH*UH@S5EYLmB`ta z_u#*@dbUa-A5psh@!=bX+i+CSw3LUu%49^daFB`PBC3}%sQ(1|K^uY-GcArd_7?P7 zj*DMGWctGCW_5QU5qsmbB5W4Hc41}{39Qb{0NEghl1G>U*Xp-;68hVbp{jrrO~qZ(`bk6tl#KT~3ZnyB{zVPIZb7 zcfM#PD-K~v@B*oX_4NEAm$dCis4J~ z64S>qhGiXKh`mX{crZ4b;#4E15|rfZ2nxf=4eaQ&9eKT5zqhkl*QeB8FcciZ_u+GM*hk*Yw69 zi@p~7OEKY|PJuh5ugI50A2*03#DS>DMZ$DE)onc;WT$U&*kHt}T*JBCiN=5u+3Y%8ZEQV`nQU;l? za-WGE33}xN7dJOyOMGTk2m|S&QNRSpW zQ-$=&aq@dHA;mz5#^C9VC*VV$=#TV9ybC3%pyJzaz*P`C%$r`)~)2QV-;HOUnifMR1;Rv3M!BMR6p1k8eWA<8ipxlc)Ndt7k}4b zTVY=4O}0l>X2PpHGG<0jR;>gxZA~ibk|wXtdW%doJpx5KO%uR|R>dKf-TVo=q^Ni1 z1-}UpjwFKkrGar*!Vvk*1VXVPl%0mD@vmL`@1-D;)9hqKo!Q1F!yY=DiJe~fEe0-M zNLFoAm)Ra?#JA{6`IH2|onLSs3wcMLoXuit)BXe`vES}X7&M$nznIon6xh-1OH3a> z1sAIcxpMv}!>QOJC1oz1jcUt(r7KF}x5`WZ*TGN!gEyfp`;xtr^Z$pH|0N#IM43A$ zzeVPCW2VHG9b418=bKD4(O{kgn|hH#_6rvZ?HMq0bz3bi`#Y_B^eIJ|29mt1ut@GL z^a~dX>q|QGeC(ngZDP@`27(+x79rm(Be_smU$7e;W4es>rx)#RAlo6bWIvWor7T%* z_Dief&VHG0)9EQNbEb&xX&~JRp%XD%iPGdEVLj=PHK+{A#2Z_>!BnF=8i;ec*NHOe zt6#WCSYLd0x#yj5bY}x;p3o=CY27beB&;tzjPr~Wj_h*Ropyv&ojGiGHOK(xJf5JC z{lepg^}1TK<#x4g^Pk0cH<0av;6jD$7oH%jC);B2owO`AW!c(rn=%wT#k{A1Uccy( zY&;g3JT|?fox%4u&>IjvvR@%j5Z2e@>d0>S>Yu>(HBcQCRk9!F2UW>>y{X0OL#<11 za$2+g`Fno@n>U|8#9PJaw(l9;~BpPfONtqeemdkxjy0;g&kHL3sw@z0RxGZW!Be z`IZe^maka3dhLqkINBX5tU7w`#Np!+b%8?m3rB=@pPpbk)f;}QMRA!#YfkLhRd2p) zwvJ+#;z3#}+LDT7zi>oYU(vbnisF_lu|WLn&SZV|P#wWDB4aWWR8MuwEC{VUi1@ zT(`}pM}z7Ktw_olav!au?KWOqw8?&jTp+Bk?Os)9T5mc7waxfg9ci~2DW{4Y9E~<> zCW2G4$Ll2T*6Nu!Vu3>T3rB=@x4dm8HQP0FBHWg~yWWYguYuwcq;(u#;!Z_!fv|pE zy6q^E)75yicC>!?r8?TK^}|`vJ6<7mVMJ(`b{RrvZTLecXtgWovdgwywtDTtQ{s!4 zZeM1eV#XISo_(JD?uiDHXCvw&h17+H(3WJ|&e|*(Lf~f!Byk-P&C?ezU9xn0d`YeB zlMQ6gLAs|Zq%Jgsw(RM%G~p3h%#U5W0T&UGT^v7S=^4vTUvkFM?WZrU)qbjh_PI!M zsY2>PLuhNW#b<4zeLS^s84>NX7B4>i^reeOPhYa^%rllQJ#*RUQoKu|HWOcNkcso4 zGNh2YFe03nK* zA$6f4oUd^^-NsFBn$@%lCe=BGoNOSPfZVA3>8=Y6;e4$+fY0CE7|?F_2DHyS0c{`N0T74=wWmG|XyIQ6 zwC4&)A2tB*MgrPdSo>d@^eF%O+<$%NuQC7MdJ^Sxx2g5YP&y^Peru(&!io*y%QH-9 zlYoy163v8xd6J%%!@z*KO7VCn03YEe0tDxHds+?xtwe}uKLm6Toy4HBTJbbt!k{OB z34;UoM4>k_0w$UHP3rV@Jm1SgAo zIJ3~xL^KoOLxA@%;3on^6VXD1i8i90=p=fGeqw+aBurwMP>%o}!cPPVooFVwR=Oub zv=JRdC(%vx5XvZKi)n9FW`fS(8uK|&{*h-RXN;Ivr}r_FjeZPpVZ45E#Q6756> z(Mfa>-9!)3OY{-_!~ii!3=t*~BNR-E^QZuFsL|~qyo8VN69FPf$iz=h_VjQwE!>SBm6{w2ofzs8_`a1 z3c077=phCOlW2rDdZvgeGSmT9J8ZcZMnlXq1K81azW_ zXeMY~=Ao4q1`wd17$Ewl=p_b-L1Kt7i5M|Vj1bBpfHrC#+R5Sk259ewo&&eKO2yjr&rQKFsTjD3uOKW39!x;? zcnQwz_xOnb5hQeiws#nS0UFX_00wA~=Ak(tQl^&(6COOu@OTLy;U@wFt=Bv{K}$Rj z?btknCNM;pM2w)BAjV!mB{afAcnKdt^EZsV0PXoagZ#lUM3_X37$!yt+A5&30gdQW zaNVW_podm-9vU%tItdyVdT3ne86r#~M$p8;ql^J6LDNGIjqN;Mg658%jtPJUV(4u+ zb%r^9j}ZMFg+@5eG_l|5>~~E>2SIZVPrG!()1ow3(b+q63vJ_>LW;daKT{ka28khp zHYy%krg&(X;-O`VX91y302<*TyacUPFvI|~R>24j=tL9IOwfYGLkkuUEm$!200u!b z7Ed=pGZu7Gz(@Fr0MSYqLzyA;rVda{KfanC0?IKzyaCGkxpv&ZVlK|Q*pm`GLISi<@}ExW?d$5UmG+Zo+efUc#S14m*jKNuYxmBs>RzRw6cv{JY=d9~&PR zKgxU*`>6Eo?6>3JE`ON&F!^DnkT0YPYN2p2eb6{q{2=o|?1R$#+4tk`m*301mwd1C zZvNfWyXw1zZ>7IwV7`0io3U?}-Wh+#c&GSw=Iz+qrMI$g#osEwnR_$&X623i8>u(c zHwv$(UpHPazLt5-p8FnuwVco8lljVl{DIT~^*~{NdcU#1_>IgrV&5pel6@uqO8M)# zuP47=`C9&KDVYbK{;KiS;>($rV=tFp8h^=nsrX{%#n_9b7qTzJUnoDHdp`Mm<+=QG zspr(^3SUWo#rR6`+03)CXG^(kE}kn-<|dPqm1pwLq@GcqDLkEi+IYJ7<;<63UoJhB zeJcJ``AN=`uRM`|f^+2yUrK+8^W`)9V*5&uXCIG0UVbe1Sn{#TqxnZukE)Lr9!Wo9 zJW_l(^Kk6p(nHyY;t!Rxxok39vGP{RQmw*+=?9Gmi+eMBV|z;vWFLq>P`*ERfAapy zefj%R_o??4?oHoo+*`aSb59KO>9cpo?=Ih!yDNED<<9(_sXNs>3wNaNFzzVs$?S>k zDecbgj_)q-%I!+-s$}w+R7TAdCejl}ZqMJIx?R1!urrO>^~KvVx7jo7<2%Z?a+Uka zE$&SFG-k&aZ_eBtySa2z_NMqvej-I=^Kq3i#KF$h}}@SK6`!q z`f@s#PNpm4`SH>5@|N6|*OPq#>!WHQ&j4O&8GaF+YOB=Eq;v35AbL*4qE0^alPhGBF zUPz@=M(V&=YD^s~tV^#m))m)g*2dPBF3VmPzpT6_w_+<#L}YdqWGfn!rVgh|EKHzr&U8O zDjEER|ItIOU;U4G{{Qq7_85<3lvfpwh8OWVVNS_%%mJ|E!uiijLRK4NAfET zBrk&4LWR_YZNm8^yG4?>6~jrd`DABQA$4J!a6Va6WO+xiT9(q> z?wH-K&o_`?3E^Rd)Pr+sViic@EB$76WD3lUYVnsK<>p}x^Tb{(QFP)J?a zEvzStX~}pM%#5tvrZZ!7mGJ%s!eb&#>I&H{JXT@5c`0nWs)P?T5awO-1q!JPyM@Op zY&S54ZC90WzJc(1#2r>hUDzS4*RfiaR;xn>$d&U9%C9!i+yJ!^h17+e!g`tqo|TP-ZR8yVaa1twZ)u8rlf$BA)O6pi;hpJ?~LBg(K85W(B z_2`4~HyfyKhQA7q zUKGhDg^UW1O;OI)Iaiwx8YtcXl?4jfBy1PftJ`L!8CM%Nq7>5ZM{_g}HqhJ(wGoAE z5=Mo`R!XT?_N7^)Z=r$WHc=#-6f!D2HpQAz5J%6u{mH2TZ4*BKa2eL+I|a|;@!9uO zK#Sn>(vtyg_*Oipza^k8!DniFKwGmqp#9a&0c{+gf4&Lt2Dmt&{qBW;_6R=B_&j$9 zp6%oF=AM9d8b04&AJ8ts^Z#G&!n^={4yOWIx`JaT0@_`8_8&Zg_5UqJdH>~YZ~iB5 zLircx`G58L|IVLkA2z79n^4dNc*PBCjcgbGUVUTE81wCUHC5#n=!^(;VVlrysk!sE zrq4P2Ib83Y`>289t)fWk3fU$+HpQc#b00TQ+yRvZ3aJaD!p8L~g{*VVeW!uuPSGTF zg^UU(ls(EWvGyoxHWf9$cOF2r)K za8vQ7qZrxPzX8^-zIaP=!@A2>U*uHooDuE&4OH(GRZ>^TPT{eu){JUSS%1(#^=>Gc z3aJYX;a#|9+$`5d?3mdsPWlTgS6;L#DHp`iyGOBczoYiU25R>ps;Q8=&=4MzntOMw zO6^At)b0~CQdh``@Gj>!BonIIr00Z`D{&=c3(hIpj~j^HkF-pM)P)h@v4|a|WIt&j zwihxz3aJZ2LVJW;hR|7?#n=AeW)<)MT(t1+Mciq(*QZl8IyQ;?t52)V*v zR6%}LlfIiLw;&b*dU%mWLCCPsF38+TtkVU-AW>70Kd2FMg}qC+!N(bYLr~% zFRCPeT9ZDqDVy6QkHR;okh(A;oUbGyDT#fijEroo?q9#G5p%`AsKWeNP5O3G_~^_7 zr>Z;#nnGO|5zbc_`!Sk(wrrezy8L;KoGbrD73Wtq>DLx#pA?7G#Uwu>w9oyyztq{w z+Ia5sN9;w@V?cHL9I6p?Gw?+fs8o}FZGpaofEeEP#R8FruwMJ{$Bq5mQA)&tz;3AO zBK^8X(#^sbRHV=T!b!i+EsOK*cDX40?f9+FB9S!rQt+#kt;E0iXKnn|kAE;fyNGYb zShJdsV4Z98XTPbV7P&gj-}lWJ)@Og&K&KPQNAYWS_O=5hx(%P2jla_H zZ^!oAw(sE!I4~#4`RVyrb!6O%I}Rze;SUK`9N8k=i9vLS{INDm$ofCu@M+KO^=l_T z?bm+#o?pAZ)vx`Ja|7BlEq-kf?*aI6vtL{He-PH>*B<&$er*`vpWqz;n{{r_iz z2>WXs8}Msa;XMHV=J#upFZi`leE;H6y#Mbn{o4PH_5ZDZ@M~@OeEo)ic04{G4F|Nu zg}4`x#61Um{+k)l_TZx=0^0RYysG_;cU(F0R8?Nbu2=qfk`F#{QJ7f8C6!YuHl^3X zLhap{A*XxsfKvAp%|wLgA%-y3O^*@EIN&3ii7uj_FbNH_;q(B}M6?oZL=Wb7>HWkI zF-&+YOnFPm+Ql==s&a~HbeP~o&}cBSUWsx#W+-ra=w!)mAaXI*`W2@RXKM%1O$-vD zF(5*;5nV(NF+ju!WgPGjexiwJA;QEUF-+(aKnu}EbP_#8KQTze2z8QSn7|jY4(%?KugEJis&Sf+>Q4ud&T&)-#h@vmYda!n3!jX%WXq4y|7jh8wOaK951PMgD z(QMISq7!?YmxSzPU;W%?BDLn6vwpIVDYP?%enR0P3kYotS+(_A;EZ-~cVq%kxx1I} zT7aJj5`jZN7#WT>;fR2}yle=Ev~qrSYuka%Tts>cYVQ!BD&tD4mk1C|1S%X&LU^Xq zsB}UnT8J>wMsyI}M3Z?v4kIE&l;|XShWJ;H$$(oE2(OmrnRA0N9*r0 zxh}7c1$CRSsQ453mgA*IaRz;NTbtHqe~?ZK))&`TVG-YnnTWF@M39;vNpa!u5oej= zb`xtB%R!QAYr%w#PKbK^eQXA}QZR~0xb~QzM6yYZ@G@(Zk zVM1d+@)1FznFtXE(N1&`Iy+Mf5hmJ*4x*drBYf;?t!{r}JJ0TFZS{BQ38#bJKfQK) z^W31;xj`P(1QtKH-?iXHowj!46l@LPjAXFWe|qr{2Cu+a<+O_$xfUzT69EA(_TeU? zb7~w*c8{j9*!LmK)V8a02+gI3Cot~!LQEevF;1(aKs#R=(ar^*`%#nnAfb!`UZR8O zB6^8IA~Xg>h$zuT7@XEz-P&G^ka(#G&_)aq`e8tga1m^UE7cQ<351C#(S#ggDScps zXt96@(Lvxs5~bBdlrxBVw!AE7wB1j`?8*Dl-E{Oq`^@oLE0t&uiW==FT2bC;goqNI zL>ubGgZ0GmZ>G!B6eBdf$~bK@x@eKnMT?BC9?bRjO+e#K^krL`MmszOZC`8>t9kEt zTj>DCP9M=hM8|M4-H(yzW#rzCW8i>jC(%QM4gn@3+GF=HoO;&;&_e`Kv--dxV1x*u zQuQzqB|3@75qgPM1&tjhI*D$gm*^)3i3LQ^1e%Eu(IZ|9t}xL~3=+);fHq>7@Ut&P zh<2iz=qLOW=vq3_LWGHt(aRJsYl&kM&XC1yC63 zXyGT`UZ)b5ZCc23j5gJ=9@5E>dEx{RVR}qa?1Gud5n&@7h@RLA(7qELaP1x_z zK$MvX2p>dvS1U%`z!SX8Nv6Z_8lkCi#fXfi@zW3IV89*~x^ZgbT^m3@2ZA6@^41oj z`7od%Vo=VFnHRIrxClQLUgmIyA0+NiVw&#s(CDUzb}v1&T=MCmrs@4ORx)U(WYEIM zpoNh^qalM9Jcb7c8nnkTXnSMOrpBOMj6rJ{1D=CFP5;#RX|b3o#)_q>>{NWJ{FB^I zl0T{ZxcsBskCH#C{4o223nQ4oM>^t#y%5Uf1PQG1vEB{vN zE%mL!o9Q==H;Zp%-iWQu%uR>nU0BKm9f1YsIf-z8d>#>E-Op@t4al(0K<YR^E}@k=#+aHGgaBR`u4>_U!if_VUfSoAWp2 zx23kJ+X`FLTaB#;cBFQwI|{d^Z#8Z$-jcZ`cFRo6zdG&Hzs2+aMPHUb_mx@e|C<&bz(_d% zSPP1acky|zSUDg8StVhID_R2K{9wcG#Su%KD%Z63KLmI15mQa5Owm*^gB@#lYK$>v znpjzqF6?_7#~O5+TtQvwFx}O|5qAs$NJTzA-e_5f-}SMeYM!KcaYPco3$gQX#7Fsr z$3)nIM>Rzior`&_h5yJd_F$n%f-xf-%!SIRsi?yXnE2#{iZ5X)5#|(Yjr+chSjcAt zcZhtNg=2>;6mb=$0&J(NcO-E%f!(!MQJsa_P2wRwlc!7wPTMs zQlur$Rp3G=don{qLfwd#3KeEOfzOzQjMZ*TP*sLaCpqz%pyez=38%eHpd5&bg^*3f zbShW&j5EA?tM)T{(`BVgOMvdCCTv&M{;~@PcLLo<)|0Wtd!?sMA6K8AJA zZCt2`iHkUARu_0-8Q}P5JLcn)%|bO4$&V zd2>~4A8D}%U=zSA&0r!RLKWv|6K}Q9_+Lq&o5z&In7yhf?g}!6>88VB$O*#gZ7kgs zcaBTRnrDvu#p?^Q(j&0uZp?G{AFB)YC776LeSdi0aFcbw7JT_(0}BW#YQp1Pm`(h1&qK&Do(gOGBHo8C!Ye#*La4o7bu9jp z@&?|{fSnPgO}7$o*qh#xP&~F%^B=H>8q`AqX)>#ZW)4fGSny!Os`F})Ibl7?(&GE* zJH+$dJt23&R;&Z&zik^!V& zm9`zk!x29*g>OfNPl4E16Zm#pQr4LkzgLN&RCYRc5~hUP&?3<16T@!t&&ZkLx5niQ zNGKOV0`Ec@b3^QJh$Gm72f3NaBK$$^La=&s-XJj@q{7uC{dGEsQ%R;XA?1_&bH9a; ziDy{daPdglEM!bJ95fw>0IwY?DQMW2u>C@N>1?D`Ep1_BwKs%ITH-eu&D~==uyi#7 zv`ElGJbt)2dA7u3!!lh@!gaXcqP5D&BlfCF#6BV5cFtTzHRWUCOLAbriz$M--jrBT> z!zDcS^>tXASl{uruPt-m_Y|rd4K_qhxR3Xbg~T6#LZQw%l~7%$zOPVE>lO{-_Z*cO z#uSFJ?5qbicTve1}al04^;2_+5xQClB#IBNGFW?_{b8ZFihMNQ25}KF7F&PI;PZ4`Fye;70 z^dp5=cInre?+bhu@WmKOi2=hYb1}C}3ZJ3Qe4t>Zz$x=6ZG)(TSrhY9A?n6Q3jdyw zCit>|e^$QsVZ0VoO9{>C4%&}$@XP~)#qs>GIp`?b&04wb!{!$_n7>Nqv_*+Cdv6Z5 zio?qyN1bUae?giPnVA+om!x4K;oe#_7BeBm0ka<=J3eCaIiHlL1e-!ieF#eg< zE}#OeFY{NDbTlgMIrKLV{wbEm^Uc5idHw&q!jHxHIF>9pq;0sMXo&Bd*F^k5bEnkl zVv+?IwFmhbd7Mmr!cNyjunbLU|whW_oi`=`aFe2QI z3r6?iqV={%!6*3&erfI18+VLee#NDiuD$&7)|UOzDau+d%AzWgi*j#CPou1LnT=bn zxNL12W1H=gPW-S#S!ar)I$1g!qb?N2g(=}EE{#7R!eBV5=|@2=Fzfi}!2`SR+Izc5 zslIS=N?s)9=*--dPWMcZZ zVUN|;{iC;AFK#e6eDSb{05Tq(i&+&rWhJo%m5(G1m92jh%DIE#{d`=n|T9?Bom^ zjskClB4*ibw;wuu)9op9{}O6*K-D z-PgXH{<5tUt5j<_Wig?Uh=>mebz$e_gg`B^oJ4x-)~)%!o}!@3P>?RsfG{ZRyr8&3 zU_qT!&R?~aW6cO_NpV)0@%A<`^V~vnrp>W-i(QpD*Q`ZlzMHkI{#%Datz~ru3YA4r zHm>x=>zI(siUqel#5(B4vN~yD{dHS0R8J+qS~2d15U#&NYvigEpZV=x)xxIo9?9Z;jHNfz!)v zjs^F39g4N~^^7f#i3s!7X!B0{Lbfm3d>^NNoX|Ik*Z7z(VV$(DLWOKn1r(A;-1jBwVY z;4Uo0k<{pxHQTRPy=ASnIOlG7>t^}I@eb9nmM$YRSBT4e&G<}BydIUz$i-Qez%Lzk zpoMwTC_@#utXa5l_8eHeXyF+MqFQ$GzFmuEj@JtR-e{|WRi&TTh2j5C+w`qU4`5B= z+H?qdh4@{Ye!Wi|g>os(df?9s{>P1z!Luc6#Egp6#Op6xa=l-&p(K?&ZFC0ab!l5}1{Je!FSk9xDUWNnNQ*Zq%unys( zUeV&hiGS%(6Kg&*P7?hRRt1~Sr<~9KwA`uedmksL5Cibd{mAo=7=RCv_y6K8F6EC` zIhA`61MtrmxRv}pZsiNa{6B`+|L#9>DzDsyTmZQC|JVP@spRf-Dt~t+V*ej?DoI@b z|H*Ervicl+|8}Qx+apdTu*0dmi2VP{@$b`zTuSCLm-3rAxGoVeU%A>(Qp6z45{nBKfs6&DGGDC9)YGb+I0)0n zPS?}LA#TEivMRHmtIU0_`iP$}3%aTiUdXNLBt*i5nbFlQ5+yMbC(M?vc9SGw-gLE> z^buxISD8UwHOK%NB+Q_$D#Qk+>&Z;&s)I0-y2?!IDzo3JD)A66@eyXkRRcsLLBia) zYKVkMgme++W5=bpAWoQ>9T(w(BuEI6p==NOcXF(PaB8WiGw(ai?|8%ysIAK zB|hRO0iuy0(MgDeNrZHfD2b6cNsw-mBt4{;^pSp&A_f@%)AbzW5P2LZ#76AIL7c=z zn1EhYiHCTJkN8P|Xe3B<5+Y#|AzdU&VkAxyq?;s359uX+q#sPzGsPhW86bm1o&XB5 z5j$}ZCvg!sQHh6miI4b6fM_I0bP^(A5+PkAN@65V5~Q0XNe`H=XD^5Jk$#dQ1{olO zL_P`>Vk36qAWq^UZlV$o@e&{LlK|03kmw{t!X!evNR-4#oFu?>J$bJHHA#9%FXekIFN}#Y{X6+#7SJlO;q9`Ug9Hu5+E805}kxdm_$eyn677(Lt-RO5~Q0X zNe}5IeWahHh(QL(Ad#f)s5?=Jjo68UIEjn63G)T29^xfF;wJ&3ks#5*bUi~H5+)JS zMWQ4|n0ydHX`q`VNe}5IeWahHh(QL3oB|555j$}ZCvg!sQHh6miI4b6fM{U4oNnFHDRN^6C zFkMd{hcE<54G@h4iB3Xh5Z zgE)zcxWRNiRSxkGFYysS2@s70iB3W!Od_OuEI6fwvEk;Z{c z6k;QG;sDe2baIG`xQR+U#7lg{PXa_EL86lo36luvB2f|}agre2BuRQmFXqM&cwv zx=E7skY3V9`oVNPQygND0U}QVh1iIlIEa(Dh?}UyL#zXC9(Rv@7R2@O`A-dTjePo( z`p2b@GaolTDu0yysPJL>!+NDu$y6Fg%15$Co`L~R>YHvz!R^G_Hp}$dmJ^#A#dhNC1Yw6eOua;iT zyxMrB{7Uu}`IXAcxtH~qtL1#zDAy*7lj+I&OQn}GFEw5)znFcoaEki`6u+JRcK!L% z^O@%x&y}CcJ|{m{c{cZ~{%rM`{4>TgwWp=0D^KN~(x0l9@+G5Gn_4CpLmHTt| z>-Sgh%im|*SG%`(Z~ET)J*9gx_cZP<-<`c%zPoZ)?k@eV>Ye#JjXP_16z@piQ9oQd zoH=Y>QD2zz-T?Y|^ajjRNa~1Y3!`!in(;IK2{pbj5S7i4SnIp^o{i! zN;hO~Xk1^uK6|}w>Y@&(xo8#9IjTPk;*%k7NN;;R;)77E;kTFy{vv_9u%=+@u^33wavhuR*GI?2LX>O^$ zw7Mj}#8^^WES=_+{?)PE@P7>!gpl}#1;)BW|nQeUR8(Od4#_R77L zp4^;Q{5Rs|c>7iVHJr<;L~;>5QVr+BMz|I#hSH(BUeYsqBUlb*gL1H<2v`7*wSx9rV&3!b#6u9nn{+HjZMKh5?3gKuR%_%HbT|FdtIf8z@$veMtC z#>7iMB7oNBMRXHldhyJl)))Lqe>Yw$h%I9Hk{S9N8rml5BHk4v@#6=?2nvIE%|Ij! zTZ&=hh~Hz#vl(X@8M<8Zw*>cNBoC&_vP85so?pe6tZ>Ob#3*9)mWX1EFuNkjiA|Ef zB~B6}Alw?$qT4Y@G$$~KQ9KysB{mMPTfQtJvs5%qLj*XA^0+h~a#)#_S#1D!CAIZI*#73#gfR9UI#uKHyt1%>fJuD+M4O0e%uE_9@^dQFH`{ zr6A}c{Um|g_JsY%K@S-q3H0TLZ9&kBTls{0gIh5b{5^s30RLDC^RE(&40zNX=J9lx zhn`^`QX&Zi-~mdQzy4wVs)ze0fqWFWiH~R`L6l=4O!|rII8cX1Fl+?$6Z;qlk~m2b zR{>~~e0v1wQ@|TUyuC&uBu>0TAV?ylmnb8^M+}mf1o9DJCvM^;A<{>>j%KYbu^9$0 z=Da+G&w7bL_S|w9^eBo@%mfcS!dzs-+UOJItARJfC?&C-U=%SQgZO+w0_*4k ze-Q8>bpa1Z7X-2R7pPdu3w&tVg2-`@8p=uw93vo%1-GD&bR7YHETjcJBrvsE(q9$Z za5rP{QH)ho7d~3xz`DL5NE}$<7kG$9dPoAR{sR8#wZL}_#K<6V4WsxV=^F<+tK^*m zsnlf{c^DW(9|PfW&_^N#pkUE1@RBg$i6!hN2U~YaEw$vi6P+m;m|p@(Eilh!H-l$R zmhmjfGM)@s#$(}SJjz|hBidztq8}SEvs)O=)Fs`=ueBC3Gr3@rSR}~lfY*b~m4YjV zSbO?^f^m6cSXc8$1S^h;Jvn3Y#lFj2$C_&z)=D|JS#piz*J*n1FZOAUq0LeR-}Q)h z(IcD14jXAg@RcCm#mtv7){_`!1ctisvbSf}h~A@{nErx463Fpkeiws6n6CNtDBg9M zUr*v?bov83_IT>6C)LVV*wQi*uXf>A%n5|?u0Mnk_+x8MzGrfagxoHzu^_QwHH@hwN_t2T+mh=6tXTL-7sm)MH1qYu@WD*$47}?f7{jt^SyD6A z#nS3BQye(PH@D0pFWz-AZ;IKhUMwSoSYx4z2F==9T6Q*K$1wNSDz>T98&zz1r#GtD zK2L8{u@#@*sA5|`y-~#;;q*oo`;F5ZRqS0(Z&a}lI=xZR(SkQGC4dSoyK)qv@~KA1OVOd8F}h`Qhxt^23#fau4YbRg3weQLGh;g><3* zU!LZR48qHQ8(AYbsaguGX)vUX{PfxTuQ%8m)2GnSEpCkGo?%h`2xzr*Do|nC_Pj^vvg+W%*OKa^6YYXd1YB{nZB&LG{4kXT3b?Fl3r3@Tw0u2+*njzlwBk* zsw~Vc)E8D4w>ynnn8s~M zv$h&h0*@;j&Jb2J}%%II2Dd51zz+r=CWAj|ZM|2V+J>pdmUrG{# zM2-VVLhHP2tVSXvPI}1zadHND3HxL;_Q`1MiP6{-qp_n!ELx<#ipz$?NRsrk zK!Xetr_$Ibr5R*^u-8drACtyDCXM|`8hep6 zov_D9V`mZaq5<{}Y3vx%Qbaut{6r^Rq?_~+DTpn`PSBf%@koetkp$@>;UNwqanenC zNk17N$}otL1nD6uqKp71v5oT;QHhTPNrZF_VU13ZzzEPth(t(?43I%$8wU>JBrf76 zD)A66@ew}>5}kxdm_$gF#7LYZNHF5)KLBuV;-G6gh^hDaBQlO*XOeWafZkU?TU4jd#v zx=5TPNk4IIEzH|ZtzVc;eziI6z)jR8ODCj-Pb4xB_KK9VH1 z0q}pdP{BdGnM+ z3@;aXBiJvhBtEu7a`0@ox%0M-^CyS+NPq-Mj3h{s^b+?3&`Fr|kUo+k z!J{A!#F5HO5#1afoB}bDASp6HWQ0*@ZsH+6g1qn;ncx<>7>_uEz)d{CO>6;9h>7{+ z#aqoO?T}P6)vb(QJe-9$o7X+GgQv*NF?;X^yF;L0-e3||g4Gb-Vm-&GPc#pQVtj+d zrlJI89AB{$FYyzNL`j@G)-O3hAp4bz`}@o5w(& z;mzWs=2VhHSh0JF%vIb*eB*%E1!5%zycSF2bypfMtI~M&l*Y@Yu>PU$ynsm42(Q1; zJc45!M!HCn7{tcbIyj3wBtXJs_PY^j>=*Q3sQw`T1LFs^&x@a@Kd*mQ`YiKV((Lbqvod4MPxb{);qx47h4@)0rK5SIvO6ExR1Nno>`}Oxq@0H)pzMFeT ze<$;Hr*|&;srr*rG(RjW5diM3)Yx-;1SLIhLxJDrTa=lzCXUdJq@?>^Wo~*o- zdr5z(`eOb?Gysfc|{uxyG~dvz2FZ&y=37ifaN+eLcYB6WJ%^Cn}HU9@ihQ zel7ns<7>6YijSoqt3O(LH1lZVtL3j&9?3nTKazR4aZ(Pw%!By{j0bA>7w@m!m%C5D zuX=C(UgO@{J;i&{_tft$-JQ9+aaZ}SEdFY(+?l&mzq5Kr{tn}g+Tr5i^x^vLrQ0*N zH*PE6mc32Bt#T+Q{+`X}jeKpqIG!G_A1ocr9BdpYAIKh%4^;N&_Urqr`||sYeYLL? zzmon+{npa0nOhrs%X_nX<)85yfYv;E#tpUWi`NHls9vAH-nhPYUGci~b*J|ib7Mz& zM|Ow&GhPoMZ>ns}ZPYhbH{>@M8*1x|>(lG&>q_e~>l$mzYqM+RwUsrwHTs(BrTL%f z@9ygP`ST5t$uE6gePwB7W@Y2t^0`@L^{bqdJ4ZjKdUpP7*lLQQ)a0U^mL=)Q-wmy-BmO`3E%E2R)EfUk zM`+kt9IF`<@;}=mB&>)DD>RIEVDgE3FL_(sBc;TDW^vOZCWOJWd-m)*n7bW;7` z`Pa5$tgl!hAq>Rui$DyU&?oE^65=V~q7O49WZjnSnH^sm4|Y~dMG7bWtwTkuV5vt? z5wAquLi6=c5G++V@kNIste}%eF>zV?I&6KMGU#NE1 z7nt~A->&qE*#U*}b?FtYA(cvdsm%#lbDeGVh_>25wvcCc0~M&01zVFz0mP3;QWb`;I7$ zsuB$f4@o(!XS?uz)`NSeLO{AKvuzFU0XcNn$~}AbaE#_+b#y2!idBdOyb6~IW5P3p zT$#r4ukBF?iU{P<(ecsI(fvC|Z#sNvbbszHrWHV150T}?EcV}>ZN*yEFry6@ib9qM z+lmlx#cp=ygMw6G04LM1aG)rn@P(_b2y1+6p}md)Dr6}eEwlK4cefR9Rp-m&DH(&yJw|&A&3qGPi8FE=pP|(Wr2~@Mm6CeQm{B)i4+2 z0#V3fAxb{!(Y_$(Tvh#TMOag@7UO#uutcJ&Fe2LM0{A0cJgl|Xs)n@_V1Y|SQEf$t zx2G{@r4zxnBCH8nEjxk%XG^q8xKP-sWsyQRa?;G+EcVUaHodK2t0HFG7K>t52(2o$ zKA+q+CjJ=3{wB9?cT2{Z!WW^oa;&LXtIj7Fuw0_5&@VI>T+SNVdPdeP2lfEi2y=HW zT(~f|D0Oja;m$>iQkSIo<^u7CBRBVP;kLr9%6$1gE+?hLf9;LL6;Ak1RH`}s$WJx> zoz3ZsRn2Oe#59KdPwd*w>3`AHHhpVkYvz550m~(-3jIQJ=Iymcww`BZ-rfV|%)9VQ zXI`|eaH}#uubCJ7siuGWGcVpYeQQ2gGw+u$V3kBwp)TYOBWKP={RFp+ki3WwU%JTe!U3u}hoyytoJC)zSJpf04*{Phs{r_IVzkxq-DZh&N z|DE{vmp^nV_dnrO?B8)I<@24&;=5hS+ithA{ye8Lb*D=ibGeis{k}_i;7WY|$1df2 z=Qx%5hh56&xc}cK-23m>ZgMNzaPPlA-04!bz3f)%HK+0w#Q(d~PUXP~w-O&m{69A3 z-}s;ZoceS0|NjgB0ltYLJ9UjC7MeVi08tIEja7BuGM}i^NDb=_4s(5S|ZK z?ZiQx#6?u%AwHs!5Q&f|Nsu1GzHPOSq{sk~j{_TV5;swam-tDLgh&^Ok~m3_BFS(q%A3k z$OkgOuMH9UBtp7Kj3h`8=_e^-kO49XruT#L5QZqk zM(o5voWw=kgkeLfm-tD5Fh)q#3FD>I2#JyyNsw;RL;6UHNFzWYcEVm&)kWB~s(Ofz z1i*AXgB%hf5fUYF(oK@2hxC$uVvs>1j{}9+h@CiylembRsKi6O#7{&9jUZozNQ6X5 zoOF{Un676JhxCztVvs?iOaK>YOMBtxFpcOWLZT#2L^_KezUm_e5s4~9dJ2)5!i~#y zRFR58WT6nbCq&u_k!(WbnV8NhFu54By39DiQJaBGjJOCtbiiqLCm8kqC*A1nD7t#2_-dnX%3Qm9WEJWrw{QC2^7@{X`xC4&otRFjG$s z@e`fINs1_AKqWefk|Z&RJPz!{MLZ-xLL^EOq=$s3aEqyMltyDv?d8kf6ip4#fk6(I zkK^Th1*$e;Cr%Dr?50b-9N;5<5+E805f!+XdH6EOmuK^4rr5;s^86@Y#z>qbND{a& z>EX*>lH&X6XY<`yvyWc>r1Ej@WBudmN4bymk18MLK9oPKRB{!)QWbZ}t4_!I>+e_J z%i$h*?6GgWQ+g-!PUG$J+u66}w<~Yu-qPQyzL|g1c(e9K@s0Ew_18t} zTHzFT$Sb~-eyRRq>BY>8jqjJgpZ&i4{mS=p-_yTW{cird#&>Jqk-k%TA@_p*LiOAE zZyVpPJzso2{e1no(sS&~FF%`Y_UG%*RG-d2Z9H9js`ym;sd}kY%9I)t<%#S>;S_hs zD?X8aqW*a4@yz3mua&=+{hIu>%4505bX4)mY zQZZ9(6v~AxIu$Dq<{s1^tUh4%^{4Nz-&eXXb6?}$^1a!63qNCDzcgMsm^-K+tRBc8 zFb>rA7x%Z{O|Nom?pFQQ>fZcbV{h%2;w|Z0>Nl5e&fMJCQ^vjZ3cJ(0>$^(3GP@c# zm2b-4B;QooncJ!Ftmg7LBUc+Mj-|)yqovWzXyeB6joBOJ8)sh;FI`u;cI;aH+Uhm= zYm94ZR~N5NUtPbdbXDf6#+BtOvscPjR<6ihp6qLs9j#XJU#2adWDhnNPT;0 zduDrMTX|b{o4l>EHMdpYTHTW0Vr;2xE^bb5u5T)B%4}+EEN{$ils8s3#STlm;>b4Wn#i4cVxqaw$Dk?a%ic{k6VgU%Ic}Tk6g9HhRiE z*&ey4lFTLbWVJirZFJWX#Y8$$kC)<^cq3MhWn*%z63s>RXtgWfWpvdd#Yj3*50}E3 za3fR>WkYhPqUUs7uLko$BUsalT3V|kjxiHx_{;vRU-nmgIiHTZ{+&+0f9*8x|98iZ z1CRa4J}iB``S(Bj|BaFVZk-8eJ{MZfz^uJ`$LupOy{9-U@}Du0Zi%YGn2;IB56_Xa z5q)}vpftMuiXEdnwxdUHUFM1{J6ca-^_`-)|4kG}Rf$H0or*(Wbpf4-&EhWKv1aXM zm(AqAEqu{`iqigfQ5sbx8Wo;iXL;m}>Jvvc4SCH^+1nv$q0ObFS@mJ``^XBEnxu0jMoz?m&uM$J~5Ys+1& z^K|eOMgA_P8I!0g3<_tRw3{haYzWO0glo55dDe=R=dR?Z;smR7VqS-`tZw!{z^FqK zjSCkF*#~@BZSQ1 zrhS7%2ZbwzqsX|sdyXx!tFQ=n-W$Db_w6TD;iLhxd!^54tA|xD^OXE*QR;QV9WAd% zkvf`v@AC8<5HAYuLK0U*jBYSnKS$9Vt+@aew3Td4%9;azi~$!*bWpfbI4a%zWpm)> zpL`B1Y^#S=FLMr@FG{^oXw|UwxqS}I(b*}TSkzX8H34&7b4Y)V0p|+)gv*6Lw{>mt zDT@CQieDkoeqmbJsrYc=4C#!MSM|~TU%t4Pbf|>6xc$;!p!l3{fpC@Z=fA=)ZL5b> zFLQCPYnIB|T;1~e=dr>sYbzN=h=;Yu`CGhuP@-{RS~!Z`_klTX$I)FlfZ?Ni58RR4 zw|Cd*cUGP*lBV06;`3+OzgipHmGw`XYbL@Y^#}7Q*#0D5cRl2c(CPl z=LI|ucUqj@qjjuZO6&-lGiRu+3Y>3zSTpAz@Ong|ONASSopx=_nZsRM$KpGGGJEEv z+iGUj)SNk+MLo6&S>N`@Y3%F@Cswo-VNJy9B;^5XQlhG`TiEH!u@Elc37J=p;izbv zILzF*ZS5LPwK=!X>QJCHw||UL7fZBHI4B&&&&Z)Ue#xDTLe{YTaXK^bi*wqFuqI;7z<1$k)MJ`)>sodDFiF;sW8e4PjMV(NT+#-(qS2Y{Q3&f^hn;V2R>KxC% z{eVmP%EeCQ_%9=u|8F@J{UVq0#=E#S;6j)3pZ^ut0pNZBKmMUpd8FH=7#BE|$KFyE z`}uC=);Cq<`+wk52H$Wg-+k1rM6Yx!&*K_^vvCc;yN|e)6|dr2frs77l7Dn5zw)b2 zWy=be@? zX0DqrlJ+3=oSDvw8G?H7d5;zZ2{K6RLm)u(I)+y|=^_czL;A@8QI3NUi4sNHBK7!4KZyrHk|@K#P2!}7q)2##!$>cQ zjDc>FBHjY%BlZapCNbhggqsLNG-sK}*EgNp3bQOCZI-+UmlO$!47>?@f*?$KNjIt+ zP7yhX40wK`23sbYMS7!GMam)t36xggotbL!1q|cA`vT(_#*AyFz_}Q5U*G|}FJZ{J zcvb>T(zrt83T!4GWOA%#f~@A#%mDGh%uqBST39RDF^SgXk8unOCrK|!5qSdGiJv5n z0?*`nG?2&>+i)vhu0w9T>gpc3&YEjT7uTFSy|V^3(|Qe}T~ADpA|D%T`QGeN&`1PY zGFfADdfG_t^hZuj`~)Kha6w#ip)=c^nSiWW)03)^Iy$S)?X~pHu4Vhjy|e4p{;_>_ zP1-+Zk0|0x4djr-%7Utz5vuGXO|Z+9slvEcJ%F|4KFmI@DdQpxQgpvC8zoj6F@PN~ zL5yy`bF)VkY22mX^j%bri4zt7(zrt8GJnNis*>t(*p z=BQ$-GnHTm&`f$YcHE-O>9JGD3+GVL2rI~w_XY@vwN9Qw{zxbB5his;@`DG8k5+Gp#znqx;Wovv1i9kHa2PiVmibljy|5$PgsqlP5BgjpMTF(?ZYfJ+l z#iFwsH0$%;&L0__Kk}p0Al6AU_aT#Fw&$KxS~4-pjHho&Xvp6Xtg;BP=XP8Y>2bM( zM?f{E^uqLZ#7h$rOtWakLGyxzL&Y{X*0cxA1}Q@5+mKjejIp6fP_hm zbQ1&XiMI!@++wZ{9!IP1kjrl5*qe;|HNW`0vdy2s#fGyi8Z z!!EwbyoQ7LnZbTYyyE)mY59foh~KbMpftTTco2*3@GzgCs8K422>n6Q#bhvX;=vk= zR13%hGe8_uz)d`4UzN{(N%=yn&f&h>yZYHb^@2 zsv=J(K138ewq^69#PIdgMPg=}-{t~&L1cMs*-4Eze~wu4oFksJhj8MLCaXE8`IW%r zPyCgn^;35G6$>0`CK&Df6&wxmhp)McXg}!}f~Woh5^1!Qp#P*_=*L=sdkC*% zx%&~@G)m{O!W-f@a9j*)9(FY+>HqRc{v?y~VKc_u$chs23)WncVQjhyTVcDD(6M_> z_>sw>xr&Ml!UPMVvyy zi0QJLABnls+|*b@KAO8cERunr_#3=~k=HzM6MuhUA|CF~dFP1)Zyk~7#*QfwnA!Jm z$3OcE0sNZzxj)6Rl$aB4ekDjgmp{`#t$vdK#P}rras8uGMSj2Xp8R&>wTVB={8{5q z>wgmbTPiO=Kn- z-ztAA`z`rfm2c+0seiNjjr=!^Z`7VFKAC>9{`JNalaJ~TS06GSsuhdHbg^D26*7g! zgXIUa56TZ#9*`fXF?Yk=nY(g_kK8658X3od>H#zBLT2C8t;Ji@x7PQT_Gb3xZ;@`U z?8)uX_f&W1cb9ezx8xek<@B5}mK~LD2wt1I>iFeHTXF?vwl%hvx5`@^xa)zwN#AH} z$gIz;%dairYKQXbYNj$=ySR91jkKrxUG)cqxY#^3OjeOaIEt9Wx>-COnKJ%*>I z7S*&`cbD85cf(b7WnHqX;>=5~XiwYgwvsJlYba$UtMK&M|8@3LzyFu$ z|NjR@9OKa%|KB_xbWw*hCf4b$6ZqQs64iyh!cOP%`~`8VdY;R(&Xmk~I`87PQmtB; zr-J5*GFA##w7l+o#!K8cRGiM6eFm!a%-1DtWpak_VYQTJ2`^+&I9f`3g`H09HCxIP zdtchp;kHt(T9_@JFUq(;cuvdf&Mg)5caE0MKFgPBE7feN)z&4F4ei?|TqRsD;3st)sWyeH+hW?%R9Y?c&zHi`!1{t!^vTs)gCsjiQV#LTl2k&!|%CqcGB5^&N_}&O-Z8;E+U9!bL*P%DDpSty#%{`rM(LZ<=FP zZfGmes(?8wmx#$P7g}?m^%?bOeay9LN+&k96=8kDYLj2IiKdV=OTyI`v~!!pK20PE zK%4GpZg6c|+@`iNtvXoEVhPJdIaY02pYdVqWA0{cZY#q2hSjV9rjnLuO1N0qsaf7a z0(TTQ1Fi35yQVvt+jk~g+RC-+VK!~4DCJC{RioDD(`wq*wj!(vSWQC`FI?q7Q^F;} zPEGTfzkOU{yARy4_t3!ub1$=PZKYbZFdMc^lrbc<>eKpsS`FLYR)jSHt6@P*+@+fF56awH36$}VN4~BGtg`t zT`cU>IB#KkI~%`wKQ3CB^OxE5iDQ)vO4n zvO=OM;Syn|X8C5evpdap%`CFnJ*zv~%C+iYt&S{lNR(yOsP!2iwm#-=+7)d@Sl_Uk z78ga(ltdQ^J2kCkZ@*{%!Cj&Qw{5q0Wm|z(1mfsXs za=L%`np2cEfRP6zniLvBmUbsv*7iUyp)fKXVZSkZS3j%7Yde%^tsV1F))^9w3j2kp zv35+)&9=4Uy0!wX3Ycq$AtsMYcu?S6kG8>cuN~L76=6-tYSVm7WsyV^!U19DHcjuN zT9;c}vukLd~nM8Ypxa<$FJ2mU{j|E2C z%C+iYHf^COWr@(LQS0-UG;Mr3`hTpg2x|h?f$#!MrC*||Fd$^pTDE7m=1^WkpZ~IN zx|H9z$f;bp)usI7g-+$69+wha>QY|*Tc>i~J5J^I(BHoc{r)nZAAj7XoPitwA8v3d z+Y$f&d+7H+w9={k+a8zl!nsbxc+{o*C-nVqTI*8&>TIWSN5rL^xD7c0&T=YC!Y<{5 zUv=Rc0H^Z%i2onMzrPuCDR&IJ6ba9-tohML{}uiJ#xquP@OpCk0XJx?ZGgkWBu0`XMI2+z)8pdafTCqdcC?_oLcGz2HcP76V*40+ z22>It1L#mt&6^h(NAaF11~i8HYj*S*Ad{~lCcxNzq;W-hR_}3SmX(9ZEZfKQvi(FJ z2MVzf7fBAcWZRd=&`+TO)tnr&0BB4Afb_J$hn^0kt~Ki##%S!+73DHhfW{;N8sq*o z-v~M}agJ7e#-KYbK=ervC)yDZo&w#Zm*<+%(;~+2#~W>c@E-42!Wh9v0whR6r29B< zGqtZqA|y%N;~-3w3E(ABq8#O05+=$Na1kE~lOAGcvSFQc6Nwpz{Ul2Ih;0aXNQm?h zbqvIaV;tzDm#760A$`O*!MCK3c#eQLaZQ0R=_l$jz9oIcAc}M)J|H?t5G4qLBt?8< zAVK6Q5FklnI|f3eo4CfV!c<6-*vI*n^b_9%h>#xQJ_@45F$KDa?HCA>UZUbcW37wG zDG(%ak|LgA5Fshz9|1|Cj)M?M5PN}di82YoBt^VOL7X_JK#24a?HGuWe&Re1f~1Ey zQ`eweVvs?i3;{O@k~pysgAkF&_=@xs&p3z?M*-+Wo&X-AlV0(53a`3}dK^TFJ&287 zCw;`50x@D6;#(3Xy~HsLbkavWV<15c;v5G-(oJjyz9oGmWOZZ?q8r5AjAGW612cmn zR=@qspg^!C@47UC{fUEkh{*S0?u|rt6_^e zs4y5D!C5Etax}Y?xM#5yK<@q6C3PbmAHZVbVp^DZU~xqH#m%A$=sy72CckthkU)k)GzVr;*IO?Qzl zwqIh?6%t|l4I;DsUbZ?;x`}f9TFJ4(pYWUAS~k4JJp!7;%&hCZc#F;STFHgG`HB@L z#UV^jfNxqC<1j}7Hb|^Q4EojvIEuunCHT!0`x&t!c5`q99b``P;uj3+!8^1A$m2jE zHsT;Iq7pCh6OHIV{De0zqrsHI9NtA@BtatVDd*)5=CupVPJ#t5Du~6W^4By{0MZml z9zpGFtfHGWj|SJ9-#tgvJ&ro6=I>~55|h?Rh=fUmL`e)~s^%ud{4-c_F>4${Sl(fY zV-Eq5*~8rYv|)VGMPejDl9&W~9?g3&^x_RR8W1DO6ee$oD%tQ7mnY!8c@54WUz)$* zGRHEn*^>Cu+`*(cg1LKe@VjpKn))@`g1p8~; zAOQ-8QRbt@hvg5m zZJ7va9~3`Ge^7tF^nT|3#(U-WvdBeHc{lg2{%-Z1{5!@wwYQ6Jr{Au>ReCG)R^!d` zo7p$zH!E-C-pIdRey#Ru@zvTZ^_LsvayeU;%lc&XrTk0AOZgYe->-eo_#QJ2g?9z|dzgGHM=4-*}OajHPw%*aM`cVF%axq(!iH100noxNMWyK-0VF8!|Ro%uVBJ8O3o??~TK zKU_MTIo!Cte0%nG`S!|fx!d&Hs)zE2j6>PHoUe@M#`W>)!TdqvVC_KhK>9#^e`$Ya ze`8;HUv^*dXSzRtnKytr1FARXZ=B3!b8@aSmK)Q@s-yW)W3+Z-@y7Ix^&3hzWNye^ zuU}uq{Q=U~)~`ulW91I0UO92a*p8uDc>?5YWh6JEk5sqkw;S7Q+lt%L+v;0OTQgf5 zTgqFqTjVX3&AH9`=IW;WCSy}=V{v18V|_zuLuNx`eR+L$y}Z7%F1Jo!S6!Q5YpkuU zDXvMcsb5;UG;?WVb$NAmwY<8L$z}9RbvQq44A(9xUXs3~esSsI%*Bn1$`@rXk}s-U zn7dHFu(~S0%2-vqpm;(0g8KQT^E2l+&MW_a>>hl^K+Px`X``Mhr82lDKzp75-jT1E zOyjP6r9>vth?hlffLgQ|O-JiprLIg@BT|lJBXXoNeKkNvZv@N1Y_N>0047`V037p_ zJQ+_zEvs2oRx9qDTX$Dod6(g;Ig8G;v+gK4GLDA5Y|q+dd&QQs>9(qpZ^{3kzwJk7 z{}uZGuYKD5`@gmS-y9-I1!PUeIdJogpp^rcr|Vj?-xj{eo#On+LUDeCsuB$d+s=>7 zRpw1CWg>O*OvGT}i=C$^a}mlhB&rHEA{dO$rBvY$Ho-dlXc&KjY+% znptJ;{?anfl~$s(&B8UpO+xm*-aJPxV^=}LvDj#9|H-V<_Izn+E2Z;L+K6z2aJ!H# zWO;25M2w4b%I)16EhQGdxVb}#*4eyGC~>|-Rbf!raTy{*DLO5i%dolXSnp=7vA3L} z+|4NQ42h~jUD$D1BK`=m@z%0z7CilSR>^x$QSvsFIZvXhP!o1sqUN?@F41PW%{Q}3 zz4a8OZby0ZC5ohHFevP}WX<{9T(VYkPcBzF@s$qcnkS-V>2j2Hu}~K#g`KYDY4!n% zOaP(}aL#L%_O+F1)xkUoeWobkLgC7m*PXBA5!;Nol4rWhk*m7s^(ma#-&UHn6`U@2XDW-C!M02-bI)>fuf2eVmOQNj+PRh!o5(`wf3ZADlU zFq^efT92t*C)_C9A?(zw)9?B|+*Ynt53^}kic+o-S~Y5YKCPzR(N=^t0kdiUYj#w3 zwv}ns!EDygcSj|ixT~$S_7?8Id|EA0UDzY+v@7-%qUh!w<*vB-Gcf1A`0lnstxA|p z91=wg3s<$g?z}G+m*RB?F$KgLR~m2?ZM&FL2G2| zxzLP1pT2xStV+$2?)}n|&XKOg$m@hSuE*=O!k?z3`#O|l?JBRw)X$J;RM;=Xvi}qO3XBf8;L^59_8NRu#-Sxkwa{ z7A|Xf&9qks5yy|3v_1+B-qZ$p@tYUZh>x3VW3jCu>w8w)c4Fj}5={sPgq^nTmTU-} z+xAdfkyaJVwk;L~oFg1+dCenPwywQx&VtB>Fk&?h7fnbL)4l!=x0Piz&stq>#^f%R zs45H!nR$fy?b;p%_rJgIP@Y2m|Ne_z%BSCVDwiVW|97^ylzq4c;9rw2rG&o!1^D+V z`u;Q5x|HAjYuqDXqf7ZW^!q>ZHRJ)n^Ly)E$|m&xPrdF^_M`v*f9!TC-~O>fS^Ssy z-Wr#3@gpwf*OB{w+bb^R_aAa8y9Qj!Kh<%KLB@rk4_p_3e*cB+|1T&~{+VC-o&SdZ z|CgR^t?G?ZqH&WL!1#V~I$i{`ixamDS=Sh{t}*UkW8AvN;D3$5>xi}k%mAP<1AxX1 z02(s@pf?3D1AxX102(s@Xv_ehF#`a4eE>56;6y)Q1_0bo8!!WarV(ZU(3k-LXMy?Z z7+?kfjTr#Y9RZjD09_h@8351;0+<0nV+H_pi~z>fYl?)kqRa(=8`=Vf*`re#Fe?E1 z+5ocxpt>AJm=yqZ2FwbeF)M(^tN`fr0L%)2Q_Fx^0niNym=!={RseJk0cHij>GIYn zela(rh?H*z(~I{Eq}LcokMq2Mf%F;!=`lUPKzfaV^cn-{H3rh-Q=F1#486t}dY1@o z!})#2&TF$H%|!vT1Lnn`*#YNb(CkQgF=%$&xfnD%L|zP<9eyqb&5n&1gBWQ(-TAU$gV5GOkNN;p?n33M%OS9v=#h}?i*<#S_&~7nkb}Y6SG&|nf zoEAD{%z$bvB}P|cy$6g^Mn5Xw5=K{}(tvTw8bh)*1}kff9Y*&AU{EwxZ@`FXjZxTG z!vJHWu|5L^NNbF)#%9V_LwrRTt&LtSz>sZ?Va}L==sIJpv&N`qY<__8*x0rJgNGS% zEZV@(VvRw_+Rqd~%-CTwikPv(-s#w3bJkh?=prCk44Mh=#jIm+ub;uaeg^mY8Qkk< zaIc@iy?zGw`Wf8oXK*h*;4sWdKZASy4DR(axYy6%UO$6-{S5B)Gq~5!;9ft2d;JXV z^~;zMeg^RR8M5o23DOmHVsNgA*)_yl2IQja1>KB{EY%n-sxbl-{eRbEcFqd56}`1RCil-Z2m-(iHHMZlW9m-U(dm5hh9EI?78wh@F>% zM2N!6K{V1s+!8MbAyNvs$AM1b#8%*2B2R)4=_j6}AVwThKqtM#HG~UDG!i4WVW1O< zSDWahkEr7yO6&y?Bq^d!@Ga>f>J&&2_i@lgY(cC_LDEY+DG(*Du^rY`4^eD|&8r>~ z+#o&Nm-tD13dafN&Z$?zhMXcXT+rFP2BI4;HE9CakKTax5hrmGH&Ka)c!`hrNq}f1 zNOTe+5fUZJ)D7ke%@j-KRTp*)!ukN*#6x@}K!PMhA|y(r<3J&H;y!{aJH%<({dN1={nuQpyOzmk1Lex>qq?q&VuYB^sv%C*Vj zWO}mxQt744ON|%HFJ@nqU#xsT_kI2Q)$irew_p2i@w@5o*1uEwPUbs}7s@YWUyxs@ zd^`7T{oB>&^UoX4*PbgrmwvAPZ0XrdOMidvY5nQyQ~9Ti(}*EwzkfyCL%{6uZ#*VH zR(Uk{sQzg6tNE`EKhk)({BZVR`Qge#xrg+Js>OWKDAo$aLb_0Yu=HT&!NvpS2eP8? zKX<<_`u~mlYWMzZ*8tS=#e6znA1{q(#v2FA2eSv|gOvlh1NwpL{``Jpe{ElJUwU8t zE2XbwzS6k0d~5br`PRzb++KZe^_KiC#x1p*i#MlluJ0-B$?R$DF7M9nmUmZn<#tUS zDjrH7s^?4jOujK*9?v2Y{-?h`L1s^BcV>5ES9w=1Hrs~f8PGe^+SInhz z^|8`eW^Ar|6EvJrLH`_qr4-#L*7xjJa@T%xp7%KTOTQnWJVg> z%iFWtel>LV{2_oaZ7qjeRFAZ2GREAP1#NIrV6elIP#@;8_*GjpU;$s zv%~Um<&xYb`X$wi^A{Tz*Dfkvl)k8bVd=umg^g9^RoPYYs>%hq3-k-B=jYEi&aa(U zJTHA-ePwB7W@Y2t^10b_<#W^LNM}#2m`slk4WD`PT?9JaL7;v{39ipN-4$N-P)CV|w&hq!h_S8sTy{8)Ny})BKpCknG-A|KBUj z{~tB}?~YH`de?5s&iRwl% zx@gRO4Q98oRASrME*gy+HyhHtzR>k_mqkQ*#jYnE|E@=`%;nl9&@IGH>2R}qlD#vQ zzqmI(8Jj%!stEUPSih-ny)5>d%yl$VR`#wy5?pkRB)}^E+6czr-IideU>R|37SYAR zxs5_ow2OWII9==m79o{YDoQsZGCdkOO*liyxhhOI%U|3fRiT&3Ha1R4 ziVa zq?EJ~r;vC&N2mf}{zM4Of8z}*X+sZNB-AfdY;J`w>ol@MI8#_`fTu2w^|OY(Yl%|t zn)Mr^H*DOxZP;{;n532#&M5VRk5~er0%XK-p2#f~E-<+{sL?FqD|3j zw~y9j#0ruhDk&KenKiSdjmF;7iXNNIo>w@U^>x(H4J!(-Loys=uXN-M4$U324 z$TG8C3#g0LXWSn5plOS)**+#QAG7EvT_Z8u#MhuOU~>1OwgvDXT!#T`jJs)Y+3>y9WSgCHVBzrjF06nUM3CICPYUJYun6);|YtBQa0k#F8+24 zyG-ul@xg9Th>xMea1L};2u)(IPho1_G;Q5UPvxI?BzZW@l!*l0av z(Np?Hv^vE1DZ!m^qNReVD)^leH?mD5gF-&fj+a?ZZkD9=BD3bs z>BTk+{d4DxzO_7KkyG+U)VjsGqEh_3qMx>gwJ@9C~ zaEkDBAtTj~%LPqcFaEdS_EEZKyyapXO!%-a*!RIV$ zO5KRy8RGX9!V87V3u+UNV0`HLB9cv-9dRw!7{O`6Hj|q>Kdl{SoSMbctF2hScE`4j z{k!J_8?gly6Rl8m_FLpe(o>J~i7^Q|kM<$(MD2s%$-;@I=L;4!rEa8WkNCY>7!h7k zP#ZrzX|f+i`xl|W^l#j{#ad`E+98pQ54~7KR;4K;IZdM4CN$h7)AVn@b?A4%?!W)H zPW{EdJN4NZ|Np|To%(Xv{QuE?F1`PHr|y95|Hr@T)TflY^v~{g>X*Ob)PJ|Zsqfw6 z)SD)|^cUv2^y3=cdIn?vmww!-|K<^l?SIUvH{f0DXc*r-($phR(+MTW>-{hdR`>ks7qc!BmxUsbR<392e9L;urvX1;z zJ^3~_n|6P?fqaL<-0pXq$j>yB?{Nca_rX>&!)18x&vH0hMdNcFJoNca@(Tg-iyWwP ze~G(PyT8nZdhV~-$gk?;*X-oi%gAqV6KnT3IVSG@mWw>(CbJ&$+Z^k2f2V@{E{DwB z->V|OUrqj?hWsZE2fKghBY(uvVD~@Qkw503u=`)QG}8UA+!5RTZ;j+(cG}Tm4|L7q9vy=RJfc%Aa1pK9q{FP4r+D`tajQlM(*>?XIciDCy zaglj9`8yB!doFEs|Dl5XVd zbX97N{9%m>?AnQ2!!Cmhn{cf^>yM((N%gLq+vbmCM;l|?spaHp73Ara&U&_QQm!@pS-_; ze4vqhkekfAKhR7Lw2;YG@}V~JgWP@I{cs2QNGJKB0Qo34q<25oMLw?eflt`TCw1~E z?o{u7x{Q3rK|bpw_i^)jcgjsZ=K)nTo-gO2{T1X3mE?<6fP@>2ow?I8K-F7h2) z9DG+NKf{R~?)S>bgAOv|BtPo{RWv^5=AqAf$S;(WU#uX%R7rlhiu_77`PCZoYhLo} zKJpv2JE)@ZlQJIqse}BPll%`C`JZm`=N|GG<>W6b$X`{Gzpf&G zQ%(N1hWsxtdBjKNYsuf$k-x7e|KKP8*g*cNk^FNL`Ilz$uUrZ5{u^hMx&OP3{GWF6 z?;YeIr^~p90-&o(<9d0wjq}djx^3TZJgV$EzPQWmq@#>sgZ1MB3qit))um@m27V#JKD+4 z4l>Y51_NYQ5G-UzRd*K;9cMcT9)vm1LxfTwYDC zs39-*l9%|%OKZu?>d4FM$t(Qil?~*|M)ImAa#b^Vbqm?sO0I4rqwVCH4p2p7Z6^<{ z3y|xBZV4#<8o2CMIBSPsa4Jo)j^$Fr~`@B3K#qmhs1-%7p} z!fb=so4z;G=}0<%AbB8kAdC41zBhU>*C6qF@bwIA1=v2EdM*4~4weFfuV!9}zG8bN z^>X;-+)Igp&paQ+OoP;OhcL^)mrC!8?8{@0LFn1+GqGoU zm|+lkI{#GisSxHD#Gdp$nSLUI*#*hRLyu=4i(zg-`q9Xv`41&AvtacjwntJAhaS#; zForn=>4zc@<&#NRrO(2OfNvlToAmhylMjX-%)%nQ?}0Sz2;}ce-WR$r3o8P?z3F=o z?@8$!4#BIUb zGPg!Cqabxl_?Et#eK)6XirkckJ%P}T+1;_-K3Efo?8@&bSQ1F~ zhx)VIW3VHT-WJ)G#~6PomhIE}Qd`4YbFd*0#N2`CX4~e}rZ8p>B(4u$pSdoIc>^if zz0Yk(VAeq9+UT{mYg3prkXxTvA6%cojDdl*p|x3z>HF5CVJRSw5&h8WEbIjMdec`& zuFk_sKxkF=su=79q*q2(=C4e`RzUWO*cHAj(w9dr&tDd}EOTk}Qro4eOTw4rE>2t= zyf}j~e%p%F^6>IpBoPTlGO!z9Tb8;gd{GWo1A-XkkHV6E>ijUq_!H+H!1#WCX%f}~ zvP)u1d`r@>6_8()TohWAg{1)B!t{d3f;{X5gyv_@iJjwvm4HY%-;?YK!A3v~qx?N* zIJC^a)YGdCkKBRC^-QuHL-NvRXVC+4OnrU$2IrbVaOrlqEar{<<4 zrUa*CCPydRCZ{HaC*@8^oDe)=+41?~lE;OP%fha|uRGlp>Bc!VI{?HyK3D;W z!2W;I6@m?b7_9%N9T8XnNW%7i)*i$9|1>QB=WR(_$d<)x{nx(m-@AW>_x~T6-~SI? zqy=Ke`+xgB*#C={ci_WLqkQ%N(M8w}0JPC(r@0Y(8Q~;c1nu_OJwydjNzja+on}ew zG)ZEoK|gyfL92dtnkun35VY@SZzgEu&)!C~6P-kW=pt-~06S4eI0zTvCOkw1QAt!0 z)r61WJXm`@(Lgj2%><`g+dBzP7q)AM0nQn=+X+s0wpS3`F3Da^aL**WkEkR31h-JK zHxb-N$=*tI5<#My(2oGzV9D+vTtqohNpQa|o@gXm2+p3icMt)>hDoq? zJK-Rl1gFT_-9$N2K~xf)HfygYyo8UaCF+R=qLFAKT8K8Ho#1R+dndtZ)b=jIHWRQD z4#G)rLayCSloJ(1CBaF$_G-dQ_=sAfo@gK%i6)|j;PiKUJHh>M?41O6pR#umWthWl zcMvYZL(np$y^^RVyaXqF+v^F=`nER`%|!J+z)RE;^+W^FM6?iXLBX;Pc#zjjkB{G z&d&ZfdneIFuwTv2t~5LQ(Cq9yv$OBa&Q3Esd&|(mu)EC8elj~d$n5MNv$JE&&K@y4 zJH+hl1GBRW%+9VaJA1zD?D(>?-^;EY0&E1kyU;8E?Ci3$mkZ4Tz&(h z7McZs{aSW*XrXNY{6r(s1R#X$wX(Mn?F4(NPyzt$2*A!MRB3=+Pz73ZjyzCTa*T;UnsZdcsdM5=}%i(L%Hl?L;RLAi4-W0F)69!bP}=a-xE$ zB&vuS03r0!?IZj|1JO*h5UoTz(Mbe|E~1;T^#D3yCme*6a1kD&oTwlwiE5&T@De_v zmZ&HEL<7-Cv;hcVJKY^bClMfQ%K&zUpf&A1c6N8z*};K&39w_s&VCJ4 zPJsOxc6Mi=h63!yu(KD#&Q1(F`!G;p0rp*>)&lIauxovQjbMj`ojn!IWxCl@VP_YG zojnwG_DtB>F=1zqgq*zOJLe0{E7WRtvE019ZYpI0z@k#0_OmS38pdQo0?HxqZ zA)xXI&`Jb}CJj#tx)*3W1e6V+9bsR(ogLox+5iNadVnBN6$jXng7zM8;NpexDqR9l zT}ACC!p#6QP+Ri?exj3TJ_J-90osTzqL~4(GXU)jfRh1WH@>}|sAB+{soh0XGXU(v zv9n7CL0*6WG<4#_9wd$<97lk9qJ`)rf<&3N5P>7Ah+4u=G!bn?2hmNGc>xbmMR3K zdcW`f%zd%@f_SS=>djr9ygH0`@zkowD%+~`Rfg5R*vcU0*ss3QcV!0etO$*<>DTiQ%)yT?^)1cdEj_p-yEw5pv^ad4xgPrD|J@nEZbS>Goxqv@Xj7PBX~yk z^u*~QytOA!3!j!hHFatP@9pVRqNn&y$;^x4%{@CeF*h_fcXAT%?)f>XIgvTGIcdDT z`(|fm#byO(WkZQjD3qI-#5;U`MruZ6hHXX~Z}Gm9GAG7P44#<9dwghmZd!6$cv^mH zYHDPvZEAW-bczq}^0CRm$=OMXNg=$=bM}7z`0@AZ3w7o2Rv!-L1F1kHV8eTTwA0s_ z>44w1cP_2j z|7*k+~;r;Q#24RPgQya&dE%ZKS!bzFR{Mot!c zI67uc+8c=3THz$&iNfNgMP{rrYQ3ArMDC*&Ev0QlZm#&ePiZI3k7Cu96w``R6#J}c$x?- z6)rNlCmzSa_eu(0A|mUBy`$U{Y+vF-2Q7jsQPm2$k0Ci*G}0q%78Y9}=Yw@an0e+3 zx$yamFB-ErP8-S;(NmTF6Hr>CeF~hU(LF=R^#$v-s0y6=jC3auu&&=D&E2F<;$S zxmrs0izQ{NrRZEFY!^-y(k@;<9=083QQQ!#sK2<|cuJnXbqki780-B;Ka_vj zBBy??D$=Ks=}WbD!ATn3Ckl&IB;%pHP?1!jwv^Uor205A6Rn;@|#LUHa^1m;O1oOJCmP(sPYiBk%*KZpY{2FFN(f z4KDo?e*FFmPW?yN_b>J^=Jn(A{`oGw{r67&m2+JBnV)s)*^E=aCJkGGN1S@R59<#O zaQ?qdySVndx!>UZ|G7tvp!5AdIP>@NrBG?VVo6Pvx<)H8N78PAFl=%kLo4ysl7csi z$bG_lOzvZ8CB9Ztv08fvg``X9H@SJ9Oq^ginSv}f8qW=p zdUL3xR<)LaciqAUlUo%kO9OM%x1MZC)oG#>7S1-gRjIPx@Q(V{^X-zd)slY~3EPEJ zg{oLt?|A=7sM7p-2rbpV2sUVRw+M@s zW@A~qlx8VlqssF4EK*9^D9aa%$GyUpCile3^7l(>Rcl{BRJw$Ile>6XKB@-t2PH+P ziqP4@kjY)VC?8z|`A;QPt0nIi3)_WLg~dzqF*lGuv;=5$k!sSujI>`VoFP0*$b8<7 z=Q_(DtlR{#IJtMt?*8@LcSieqcWmE)wsLsMy?h(}mhdBsz6y^~&K8Q=6~c>6Zf3&< zG|>p0`43(FlJ_gdQ{{z5<2m%t7E$GgdW8E5{JlaWX9&*}7K?OEyb~i3rbzR3b~w&s z-)(J7+k?S=t7QI!%%T4ZHys~UTIYYqAf5>N9WV>{HU0zzq>3_4x zDqmDie+@ogs*#g~Q-tdvdxI8G7pqSgb)dbLbsKNM|9mMkzwREkC@Ezlf-}Y6Glg?Z zZq zrGvzXV(<2Gjp+Z(BB%mj#PW3U{zBmble-tANlaC1i7D)+vV492j%{1`pk8=9ANBG& z_#Y)Tw}{S7!W||z%MHh|tdEU_jkgwT?>}e9HDi->@IOnc-60AO3GXwxm74W&v9OgH z)EK?-dPaU;Qtv6zI3Rq*nU_QFFPWow#o!r_6NAk%^QWmyA*o>pby|g*a7&=ADsH}4}0{FY|_5J*8a_~LTp@E&#*QU`eDFDG!CpYB0O?g)7V4x-u2e2TBv#}d^f_> z2tn80!bZ5QRPW@GXA8!OHQKoDI7ln5hkynw2!M@U#M6!wj=e~1Bc5(vSB6RMur&>o z#j)2n&l+jz*N{++L^I*rhpB_itdT1MV-GbSS#G_`31illA67%SV2Zz%VQ6HylGt0^ z2v>l|JgX5S6_y%?&xs?2Et0F?bUZ#>YU+5pYUXM~M{SJmwH~Oo9&j$R{KR8DP+>jL zW3y;XsY^2(ES$G>}l(1e%5sa*!;56=ie$CnS3ADfba|0r_3);qm9WA8GM46Q!`8bU z-(hYWa1s?n8_`L45fIp_1|0mclW-qG$@UOlh}QUsa!l`Z%#sM$wS`(m7vc8;0m3~1 z)DhL%Qmvw5Cg52O_=pz51`$UD!7|#k3eFcbJnZgSgz=nxNP;e)YQP^Vh^(_ zYe=C!*i$!(o(o@VDhMx8?**EOR>Cy^R1npKliB4)+QalcP)jrr^>N$@`U+lZu+3gm zy$nZgt$tS0wd^o{>^p#5Zy-DfP0ev^>D8ttwmuYJov;&b!b6l36@+5|a1t)UO?ZfM zqJpR-d_*l#N7NI3qJd~6ng}oUjh9^Nt5%`#jXl(kP`ay{B^IrH_*o}Wvk$0Sjr~3z zuWFTZ9jt$CJQpB*yr2dbcsk^CCr`KYOpvJK={6km1mtuJ4|Wh$JkyD^9^OTz35N?C z!`paLC)x=g&luIOmcMNu06K^O5hQf%1E6B5s_NK7?Z%xDTezb^Gj0SOV-GbLH%IeT zoy)id0E#+q2u3SvKP(Nq`H*i}p+byY)ip5YkQY507Qb9ZLrcHZ1A?73dSu^v8wzce zlPD)@2-6eK|2h9J1^zDu{x1dof0F_SVX+|iK=%H`{mJ`Q@11$Cw&&2@`|j$yv*!-) z?T6zBZi|~%M}%+A-;{zCf>dEuL~d7TR}K~k!aMV(6%nES-1g-5@b<*EWwAhCc57m5 z2$lzuTf$rNn^T)3usx986y4<8l({|z>jT;A64!;U%WX`;{y^TeXMyjU%=_#qkm}7} zor3iN+tuk+(N(@xk*ij(?7K34#lYqJE<14P!AoM71TV?L)b%H#w)4{GM$h$~JKidW@S^;})WXO@ z+d|ud^!(_2-~3F8)eDg`ZD*!oZ@_m(=5*ib8SEu+_>=?lZ1d8vG2okPJNeM;#O(B} z=&WQY9E!}e%}mdTVjqFkCoY@bGi~P7z!dLfZPJnB55sOisypA6>dFQa!DJvDNOrF7 znAxti9V+Y>kZ(#gajyVhW2Pb25Nyc8Hb5Gd0g`p8+CE>8*9$uUG2BhFRoTi!WvDV- z5h+i2lI}28|EF9Lm(7)SMzQ`s;0w10xa_k`1hbA&~8 z;&m`XJghTr_ix^!s6t?r{M*F;2ZVQ<+#CvAgSc5!uh2QV3>~r882d^DrjG9V{as1D zCq(08!sktHrDyH>t&6v7?U6UXi>^E+=^Y2S)zbAU%5q{m|KBm&I4gJ9) zstSY3(tkr5KB$q?g|mbla^m_B%O92&$PCMk{ad3&`t$#2(Np?HhMp?EpCdfeL%Ae<`VThxmWL@E((!w}U9EytN0vkcP{n>o)GPq~XwCElMiCSvuHle;C0s z(`%Ag>t=Unudq^>3yLJ+e&KnivOF0*O=TBZJhLyYW<>coA4%+dt!}~y`eJtn`o#rB|hUL=L!!yjw0S01#r6d6L|lC@N{8VSgZgR z))g8BP>ll1O{P#HoEAAHZ@NSb^m58Hn_Ov07MM>qUYBPR{EPF~LrwdOO_TovAt%l_1B~5cZke6V1QMl4`e#!o9+~Ozw%b z9#ti^lH&gp!bePQRaTDb(dL&Qaq72z)2VxZ>(rlI<q&@qhfQ z`@u!&BY6M6;t8Vw%KHC<=J)@hYD=o9l4_Le6SbeAL_a1xLpWbptXvn~f(qq&ytb&u zqNntYLVd3IezkC=$$gB4+FMd|mk8Y@yv^jEXrcC%RC_=aJ|s+<+^V4cBaKq6MQL>A zHEI8W%sXE=S$LAL*uucV8y2RYp;;P!vM}FB>MVLn-^jdq;`_P61tvGE>%`aK*IP8L zar{rj@j8v1ESxDU7RSQFS|N@j&rjx9`Ynno1V$`R75~o{E;6}~DVBo`B{eS>oejb@ zCigKcnr*ZQT9ftXNYHyVaS<)O<_6KZLD*+lqAms;7H(O$3}yhtT*T-u zo|ckww~E9)!rM*miPZd7i;_wkquFlKeu4CQNjO7sCZhBLBvoYw<$RvvFrSD`Voa-nElE?jPMEA@$GdEX(i)$9hH{9K`O4-$jQR#LT-r3 z)U^D?9kL{2lO*PNsd=JBO{p8HIa~Z*Bs|mPE}ok5^fWp(tuY)tsifwGqO(?bxyfBT zNo9$iHA$_iLo+O@Dy0nLa}F(!6m@8S0Da=F6BgeGmKiy+acZD{!?vwECr{A=7pamn z(;}z>U?izCw|F$hI{pAZ>`e~T^{}s&pzw&>a`ft$(a0_ez z)V=1^_y5hQ&pg+qzxfN7z65&!{_rnOef<)=_kYQy@51{3YV-p<`zNP9Z4qn$EW}!Z z7o7UPV($NS3takNx?TD`b?|4tOHbkb|3ugUc-Q9ASEQW!&kj5FKJ)=-noD23sp*S( z%>O^@NtKBBJiJajqOFhvcFb?ZWIJQ7pA%m^9-@+HBf5wdFQ&^n`hYS{oUJFCi5AS@ z^t53%s7E^jR1(cZix=~pX&2p7e|Q<@6BG5An2tHdKv`VouNtZq<}dZ;FTR7O%UaA| zx{jF6IK9`5#Gx%<`eK`D`cj8*l@(%IGjO5i@W@hu$7SYaJr1~xnf*cSBFvjb;i#&P zuhSgmnB5($PU64Et6wq}9n|XltF_s*ia4h~FTsB|SC_kHtBKN>x9JZY1lo@PwMasL zHKq^yYgaGU{PqFBh57t`eIL+y0BFVJS$`1onEh_}SgG=(Z-rLZhN+d9r`tEY@<3a? zQuEmf2jL>Bh#JAcUd`9mw_5Xc9RwVQ0XI=jREi5Db-rrM#q`w?exi|RAvyLs3ihK7tz?WQmf$PP9r5-@zvi+*boW7gYXblgpcqO&Ei7n{f$I3 z;hDKk^H&fp2iIv{%;bI?|6xLYwWk`3EI7s3$Og%WR$Mcq*_bn}BdwTP5{~!zUB{6t zv8Y2zfUY6zl|&6uOEeJ8L>mz#Y%_r}!bMaPHAF4ZKr|C=L`QrDW@a0c$~)mM6tRXL zO+=j+^S1XQCD1-dz#DPE*Ftm}xpybQ0Z!{Scs|eEKR60X|e4Un5b@qB&g1yIH{s(@_%|>Nm%!`~4 zEm_3fM(eoEsO#qHZaKnTMLouX1a2YfF_tNCztHl+l7)^QBn#&|N8|_2I40A#dKbgW zwDG+UEpIEb%G1hLwuA7qm2HytmaVMAXiJUjE6rd0<}bBI!)jdCYW~t~w6ew-m(j`^ zU)qgU*7%|ut!&{85{?T(jz{FVWNZ9d%e?ErmALhIj_Tq%BP)*X;@U%Uci_c+2*&Z% zeXa$PWC)7bAZQ)uERhFTCX}C4Og9$7|ChGwiCY9V2K05 z%3_LII&!*}g}?!&Y2HIv@`rVeavkGktZb;o;abGF(0FUBxf&7cXmA-z{1QASu<=W} z!uY%yZ4ML9IBVROSSx1XOdqaM&kRjHXrQn@O)ls9KDy}anX(Ar-#`$8QnT!zxnT#YnucA#W62M+)NJj^uvP{rTx)?JHhX0+hPQWy*E zCGI1>+5tS%_=z^cz7Hrn2)Kw^!cXXj0SDnF>Iml%z(dp%nsyZ*SO70kHWP3Wl|4WW zQA_v*NJ-ox0oOjDoTv}1!cCB9A@m-=LAZ$uqMGpcp~T=8C&i)Ll)bGz7ii60Sgq6C zhP5os-G`TJ&EW>ZP%&^%cu{IjEmGZ8 zcp_zy##hu`-oQ~Ad_JP)08meO4*|7AJ(Aj2ci>6{mMGIu+x>k&Ss$L@>b>ibdOeE@ zKBJVgjuaj?Omzf;c3f3sv^2PTjhw@&ZiLea8a!x`I^aRQ2%0aGYG$J!-SYU1N-^p* zym9cX)X%EsDlDKH*1$RZZ#`r_t;rW&M?VI>miYk0(B!|7Z$(9ojyc zek=Nx@2w1WI}E;=O()W!bPoF+h7aW5NWBqx!}dn{BhioeK9YGohFuS{A5MHY^x@oV zN$h)=e>L@Lvz`kr-tYxk`=6xE_LSFi3JxccC#*s36Q z8cbXjx+=FaxiW{H22)q$E)QLvxGaqw21Az|!ft|z3wtn|Kfg4!G_)kQIJr2w$h`AF z20H`>&&h@p;ZQh-Jp#i$`Lk1JN6xmLojxmimhY_0nKA4Xm^~wLM(B*-=~?U(7&@sk0 zdTe@VYHmt$N_a|sa%yq}djh5>MJM?tWlo4;SHSG?In3@4AD8b=bw|2w*cUL` zW5FPH222D(fm~;@GmO0fQyq~GTSvM*iroP-ZLzjsTedZU{Q-k5*=ApJrYVNq0ke&X z#!zFfA&LC~^Zt}S;?LJ*eFe?e!~ zk#K|@xw2$gxGZl^*&}uvcK?g&K0RZL*@CkF-;&vH{`q$p|9`#k{?GCM;|ufu^|%{T zwtFuh)Bh5(bcd*}1J(cXN9lk03)rC1-6SmD|H57$)&F9M>BF5c@Vn4`H_M``LSb~m zw1~#>!sATtVx2I$VY|(U+?W{7wrE*n_*aSH|A2KG-F{(lqcrteJ&n=~ciW8!@L?itk>vn5Ef5Dc1JP^OQqpFi>3;Lk%mp8aGbEqEe5k_gNehD`3_32BHK327A@I@KaJlA6rS-1|rEjFxN_r&w++>(0RMdNnijVAX*^GX{$ zucY3CqVbIIF_T*j%UkawM=>|&e2bvU50!gv`*!AW$ znACx)rV1l|JzV-Pun4LE7&&-~c)vur(Bv*Qi{mKv#<|cU$guEF#n6M$U8|9kgdt(E z7*@pj$la@A*t==GI9_CtR6#J}c$x?-6=IAN!iIa|aU5J$Qt%QHSugAz<(}Xc7TQq6 zB4{M(NTQY_R#A4#2z!(ScxUts%x5B_z$?9|_0jQRb4cIbJ``M(9@ z{>d!e~=MQ85U;n&Qzxt<6{f{4X>UY^)dee8D`fITJHxFa~-%2?3Yw_<7GvU`k zr(U}nZG6C{{r1YA_WmB@|7Sm~;(<@^Rocr(jPZYNfW0t=Ub;SXJfpu+y81ZkgsyHG zS>^W7?c5o<-MM<1R)O&=>Dz=AG#wq%7&Sp3TOG~>x-sq)@Go1Y`8eV-9etqaA0N4< z6=(eHdmeSP3rA0=#LrJ?Av%a|aUF)sfv(aMxEDBjL?Z|jNAB1i&v2sCezaHI6?`hU z0iVh(zo&BZ->KZ=cPcmaoyrY-r*b2D^l)$`n(rt zjg17i>uu~L$_@i=K+2W zqAPx`R*Sg7)FFFI)diKSF;>GttZtm)k2$7*p{zn4wPLuxMf!_x#bALt>Osw)R=W@A z#4WxM&~ZE&^TV3>GR=+j85zIy;fTKi@FENm>3y!kw`Mm`k3$$?!hh`OrO7q)*vci& zL$K@xV_=3y{3ZSwiSELw_A;Q(`0jwS*#pow4y7=S_*0CP83S`DX$1#MTsb?!#RQ~` z?Q!g>yqeaaTJZZ(<2tywb|%8XfgTx?l%O@?kiQbSYd$VHSIaD~^&+>M2pvNYD1BlX zOwQ{ES7CkzyS-)XY&f;GeKdCkb)LZG=1az=FtTP!8?t7KJusX#@BgzZ&Cq@cWj}}r zb6`*9wjbx(Fb73_Zwjo^+QnRDAvEeoM!-iR?-~Gt*LMg2c;Oj_;#!6HnB>oYFnx0jt3u7;9#PJSONE%Q% zDhq{%?E=T%o-@^sG7N=PaWKVPIqb;SDi)xT7}g-T^~g4rQ0CNa#JS^4QELsX(vBaA z%gB$c$ySFr9X}E$Kf>NMPMpe+x+j_9Q~^Ez=+v#lA#(<|;d}c?>iPqt@_THu)gUCM zeD?K>pU=%WZq8>1Qg2kbE+pERGF`#kLwcfRVq1hp7L{Oh6k2)7D^fScOJp~qFxiyI zl?cj|qe)~hemG?$kt>myCybNGjgW619ilS)GGLN);*#JcqDxEgI)mLd%dr_tP&`gaq?K(!6o5rNI>maS>nHn3@564_wZEa#oU2K~v zcUv}KcnScG##l#du!LBTNtU0N zjH25>NEVi zavYj$xvUz;W}5u2#P=y9Qk9e%`P$5KSG>YGEv4Txy11*<99!(GM;H6@BE{YhdEe*? zr{kARrV3}rCCwuh&W;c?m#T2(_yo=VVnx5A6kj24x^K^4999M$ytkIEqsjFi$!oS(<%q47`KdD>hmd^m7M z3IFsXE467xyJ?z4GaST9oIcAEM7wsCwy1=cUi{|l;z4wYm*z0~aRkqCMI+@ngyLBI zvncKVa4PozJVek=B79&;>WujgO0y_SF3 z_Ok7z>)%JyXD@#JHXN5dZqKjM2h`%osC7zlsB_F(e<$bG)O zi9M0KgLm2zGjCmelkLXjuILT9{`~e_EZ>*kn%NTG9NCoFnAwoMCbiDH#urWYrmjw2 zm0Fp)GImAm^8BT?OJgfy%hSse7lkeiogX?cy)?5Vy(qIVvmiM?d5$j}>`9)PJR^IW zc1n6)bl$)m-)!5gbSN6~g)%c@Gr}jure!9_CTAwaCS{J#bth%!KsdNe<_JXEqAi9^ zz;r{j!Pk)S$NUHDVs*i~Y;B@8RGag~yg_faI#C^}&Q&F=!d3aoRAsO{>q&S*o}AmT z448E0%Ti^Lvb4^509bgk?5|V)fbsvv!u!9h|3C0M=?vh8h?c*2rLm}XxC?0fjTMQ{TZB7J z?qlfxz1$+G^2O*K^=Oqy#n*&Q!geA1?#CPdHHO?auj${qbM2UMmMbh$O4`W0x#BS< zdPA_sEYePv0#8%5)O;XNid3(K}~_Lp}W9ltBK zt({+dXlG?f$%jSe72%U6x01AW-`B*AoyE4ToBYTn@g%OymEUMN#tU{80RU?~( z0in?uJ9Z;4k1Pj64>vP$oFSN17B!`=I%27_L=@%=4fn*e@#>O#w}{3EgnLbHm8J-c z`7eG{+1OiB@==lbu<#j^TS-nZ8wXdHRQ;qVeOdTflUvn&>$v_=jQvC{f-0emy5FW% zBk{a8a=N%r7P9Wss)psSU|5I^ILgiTB8C#zSR_>tjKUKZfvbh*n%u@Fcw;v}^BXIO zm-Wk*sPoYX%-_1@hV|R}*RLxK%ZzRj)|OO%QWRekzF=~zqH8Tmg%mcnKpMXZT31r= zEfM*G@NJWu1!=r#A(e$DNE(C7wr*ReEN+?_gTeJBC4V9^e-a)sxmDR6TZ#-@7u(iy zo2RW?w)Y3d8PUF`q~@ULR7pW{2o1NoOIr8Be7_NGZRlEyo+^qgxSW?#gRC;MT#g)5 z!QEhyR6#Hbt|8_(2^;SJt%AGpDAdgnc1TEAaL2dnC|l^!Y;mF37O`A>-BHN8Op!L+ zEK6HqeazYpD!VCLcWhg`zGzvx{wOp(CQZYw%96GGzF%324{a)4qS%aW1Is>E47 z<0IeY-W(s?Z1G;nsi`vb-pDP(W0iA9KUF3^w8f&K0-+{&c%?ejS=ujkmE|)&^1bkQ zv9*Zzsolp_pw#D?MI>MF=-m^iB>pmu>UCZ#*3pdSHXI-c;CmI_|T3b zf~tm(lw5O;j#PtDE^GCO58hz$UdgE%PVbH4VR)~K%2CzuQQGhKSm1Z{~GoHu6OB6VgK)E=Q{Pf|K`veFc09lr7nFM_WyhR=dcxk{r|q| za_N`C{@+jLy7X-gF8vQbbLokbUAour(w|u8(kIPQD}Nhnuc3dXX`!t{qCRI;7v!NH(nf#>TJDVzi)NchHkb9sx&f+ zO_SDubPEY538xA;`;8u%-^2msbM{7b{<_nvJ9l~O9aY}h)T#CGX-DZ(f@Xxp|^Fj%(5Of#l^H7_3AYgw@8nUX`9xHn4T+~COlQhs=ys@Er0PE zqqlJT`u<)#JZ#<8yLs!n^AgTHF-(PQ zyxk(Cf~&Hz9g&->kxjxjA^VwFC@p_+2f|sYZD&5RxQyOw`VNbfk~ZShEgsJi&NR7= zbX-49oa(U9sCUKs_3K9Eo#};g=uV5G3a+Ye9f(#;BPR)`3k|!QV{^{f|5hS86HK2P{g~Tni#4pVi1o!Wlx9lIrThC+eL%`5D>PJ5I(8Smczvs&y1vED{TZ zhFi%^pw=Zz3a%BAKH+sH_k=UR}cC-8jv zutiYiy{g|`$htimIZYT67OUSbnc7~c-?9qLSc-<957+WXEQ%@wMqxQk{6AN?*yKKj z!t$Y#g4c*hzi^AmJ>kOgXi2%7MdB`D+~l4>VHtYNqGZjxZY29l8aYikN2pR#U0wLZ zh=%N2P{_POH6NROk6T1lAdKugQzR}Bo@;U|(SM|_TLNhP`en@jUvV|;_`UAbZ~VJc z_n;r((djPz1gr&k2X_B1z#afUZgJ_GVgJvLeE=T*t5ff8#ykC&o%*6Cm;Qr4V^09s z|NA4}{qKhTKR-TSg6;p4k4N9YN1b}~VW<8Z*!|n~mP@z)-l^}Kg*5;VIrT5%-TzYb z1N?iBOW%G3OY*Q5VAl6fYyK1F|8IEK6v_kZwEGU9D+iikk_1MWp2fU7%=WEnt>Oe~ zOzx-ojDn3j`@jX*2U|{XW)CL#sgq*DqYIWz3a5>^+^z7kqNA#9j7Mek$T%^cN8R+u zIBj_3r$+&^H=O!yqc1!<$`1qy=K}De#`tk3eq3%`GvWgy#p~>&PMSQD3&gADKJ)Jj zep0$Hsmv@t@+%D+nA$ROvm{597(!~X*$G!|`9ssmB zZEF%W13+M4F;;~g033vys32-#$;wkLyNDBAL<35Xr-`W2R>Ht0(M9Mp`ITrA(_nfb z`Hzl_o8z!-MK4>1C)Z;QkQ6r-w2FasTCfq<81pzee;@uDr&%1O zFyfk-t+=L<%YRrZAE!04(HB+WqFGJ2sA|kAp<%IdTr;Tw*I*{SR5^=SLC=lLPHn+u z?M3to*Hz-W)BVd9)2=8=@w2Q)h*Bqx`0D$BR@lSx)gb$PokaB!y6_{ETdqF?eSsLP#s4WYK?xBphm~QV)TXJx<-Eh z))Tv6gR9YlXgIJg1b$m=@f8f1Rk5abqd*jFp%p9?`f+%~%9#(}TuCGvC#V}H44ZL? z>w%D&2!HwE^EB7~F}~E|FxT`L7gggMN{`u>1{@lZX=hlhA?Y3^6yPPJ{m`}ZwCZ6I z2fkt1k=2)S93BaY7vI_|ytvYI-LMy4oM;X3>}a6|92$vo3%)gb2F@QZ-r6BF?tY^B zh*`H0-`cwYOET2qkSQ7Pt+nOwd75KviUx3a6MR6l6$!GRI=HhdlV ziIZ2exilJzj@1awt!M=HRvWj8`h&}1^_EA)ykH^FjXYX@7(WeG8_i}Vz97AnKYAa| z-C9^==HM61nm2-vpVqmLT%>t;FEm=TChsz>$|$jJTw7&GSHL+^WW4xEm0^O@hs&$g ztptZ_jKf`VToFOov9zF2n9H!ju(gZ7#H?bGcjLF-g4@S1Kg&`mrveC>2e-|_Z$10) z^+hz8xHZf98u;&GprIiL8gXDGfIc?MV(Sg^Mr!&Go~POOBT=yW5KW=+B;dj-6328L z#Pn$Kru_gchVGZfSDH+e0f+Zu)(@`P<1!sCHRO`QmxkMuN<75i0?X~Ja5t+kpOlq; zlrEg~BA8W1@H%04O@w8kA_E}dv0>q!I*j&6MTvJ0Hpuvt%lrfKSOlZW2p@`<9CR*& zalHtxq$OG1SSABk!OSd!!9NCt4XTaR$5gq+i!vM>DW8p0;Y9Lo5tjvTa#<(ZOcz(8 z=*V%FZnYFb-M9+vfBU$15}w3AxpM`_zloSH>A)p*3lLPtg=B-lBa&e4@-^;1+@#ekeb5dD55S;osuRUJi)|5hR6Z$f%B~m zaU%|m6xvQ|8Koh>^_nbD9!Sb-28(Q=)O6rv4IcbWhdOb{Xw+D4Ml!XX$49O2ES!@p zuSVIl8^#g6aC&NqdZK}7B3g(xqJsz!t%rb4B1kyAu%)Z_pvILEO$Ydp#Rn=6YL};i zs3ID))p(F2%KO&9+WE|N@P*KN06XC%Y6u@uN7w+nVY<1D-^=5M#oQ$Bti}RbSulcV zvmCJ~|HD7vkBns}%9mw73jI^=2caM2zMuSl`1|?qrM?&Wp6z?-??%7t`)=ktvF`-G zll^w$+o5mgvdL^Xn?IB~6ggx&l>S!qTfT2)z8U*w@SE9hB)*aTdj6}iuY|uG`(ow` zxzDFRm-?(PV|y?4PUP*-Cv6|ky%kMo-^hO?^?K&j*ekY|k}u@;`<@S{LeJWs$-|Oi z?1|*#iN|7(CO(vWB>S-K;q(U+4`q|SWON|$f$W392SX3!?)TjvzAv&jac}6};GXO~ znY*)hO2jkh>^0(%0@!b-e+tRUUEW0(aHMJ##+5N%m!`J0E_%`IOv0al~mtLD#lZu8` z2d~bqN~{X4%3YPbDtwh~W%|nKmA)%8SH!MJUOw}(+@;A&!=UwebEwcK^S@Crb94Y?Qu|ox+&OJ>g!cCrirRCK7vucbME0=!F`5 zs-)7x;`@H#GbZ;jbXh)a5ma3+s>|{?WXN8PJV`i5SiH-U)6S*WYsbizJY)O4p0TK^ zP^f+{>Rlj8=L!w?MEbpqVb;NCOA2ljk)6Vr$vxo$v#+GwZ6dKpc!$Y7fdVs>vM5>e z?|7tSN+VAa&J(JXR96>1(QVnHwP?MC3^eVkG&T#Lvk0qz7+H9#$Sf5uGP#xTKhkws z$inAK3a%HCZNg0^_k^=>e@VF;MdA+OttR&bvT*Q)l1d*C-=7seZgL+(oqy3Hs7isV z^CzIR3~1zR;c3ERb>1zTsuhZirP7ZrHZNJURalH-GhdWe2w_JBAu!y>P;6c)c+5c6x=2vap8?7_k=U@^^$UXL?S7?-{hV^ zMhdG;+G|WTA?mx?0u7 z^0+LsC?slO_;9>reaj-Nf?*`jlEF$$bpD_sNoit3_msaD&M`(cByQlts>(nA4DqAJE7XgeM7A{M6N| zQWPc>8>!j5X`J+Y+oGrRjr5!+zAqLoFu9f91Zu;lOA4+Pk(ls$llvb`PxPu59)aH} zDR+xVJRrQslo`e*K6{ujLe*Qbn}=llP0 zhmH0B>w7nCT^rqGwNv}9C1F(23Cc<`n>GVQtWD?oggLPlQ(NaRzqohB z6)P@YctP)ig^QM6xNrfzEzH~fOc6z+o$zQgp?IdyFKiKR*LKTvQx(3#XWUr)zJ2%h z{`H&3%te0BBBi8_QawpLK3zD+LT&nNNyT-d5))o;a&tuon|s9H{D&nLHP{QU*I3d!&O+DEl~mg; z3U>{PLr(RE>=vO#$tfcD-gyMlrJ5Hra6+1LL`f==#zEPT>8UeQe^$? zmybeoym)e50Q%}xJ{X^9UueS|>n+x8+$HS`k4rU(4}GPGl3L?t%|aulqXmY)#fM!5 z?+3qX@m|TPHE#6YNHD`=m3T+B#;wp8f6bzy0%0^()3kZehzm~>o-N#o7P7b{lAUY& zw{BiDrZN7yMM_B<;OuX`^Wv3Vl5hC(U$rbSC7p;`z$7v32Osm_%6jE|fviXmFJz3I|x4gF{Cm|DvvLJy#ltp%|Ou}+R;y@t7a_kHUL?Q`<6;L6p28hBQfrvc{ zMcuT}q83Vb5pC(F=-<8U|M{J#YrouBFOFUD;p?O4`2FsDbKA)?U?(a#0qF%*Qz!WOTw-s;bgI^S{7+!eop5$(Qv^LT;EZ^G0aKKZ2dgXs6WwSvMl%ip`U(tgxIp$7G8#9ax+B zk)`Gi*4e`ho9uzLnIBtf-NNU8fO&_>7Wq5A&6Hsm0#lpmqsjclQu0xji8G%u*#l}a zT|c$ddV|mZF7xXqTU^vmdQrd9{WD2WZlhDFb?PcOMgb=>aZ$r_zx2t(E~2nScwER9 zyXfbVq)39%MExvq33Hyw9&|(sDXm$)9{tp*O+Ck{y+c0#tKTI*eTw}bdB>p@EO2V~ z&Ub33e#@b~I?t&s{H8`2wzvR$neN1rxyiV;>djJ1pvs1h7s6#9E z(E5LRL~7eOx8Eb&|39)U&xg4TpJ6^_va`Lq<%F?n7O!r7JcOkzrC#FG ze~bBs$re&_@5{txBPr_+__3wx2dwlP=C4dP`aA;A9e>Rhp_q*K{k|hk{lZf7GuCl% zzxcb!#x)I_3&|a^*cieVn+s(RLHA2ZRM2Hu$bGbYCiT(J5d;d-5MeGk*PA_^JPOK`uEMVKXvuBOS)O+{K z@`(0FNmZmmbU5ghn^X<^f7RhW?T5NK&-P572h-vH)DKOkDaVFA=nnT;KV)4dS;HP^ zhf})J{m|^nY0dMGx<7x#k+}?FPqKa`y;#{aHG_kP|%|r#G61aeC2I`rpHq z?!QPHB1y(OlB!JSF4)UFK9a2qW`Y;>biqD@7yVU|6iE>M4`Ozcuwjc^j{J(0dBqhY zn9}R?-}<5DG-(;OX!(>7^M{7j`+2MRdp~4dCRxK4Enj|4JJGF1>H0@M^!m!?fP)wP zQxX)#WHg&%WdRl4T4f>8%l1en07g#Wm7OKY%w&E+jyI9d!1i*WI0o>TrM z35o<5jb<#Lej0PC$!?*MwN{$uk{eAX{Kx#(9mX@LP(;Eqg8#M@>|l|-%!tWup`fxs z%B9?L?8X$(^x&3E#K=Ar|6{3mE2|u49x&N06nUqU9((0RQyAu;%N$X5)`r%Nt+c0R zUjs7#wN!nQmEK}LXR^^lFcl;}6%}QA2n}*AUS}oSWhq<8O((!?WR77PH{o^1J>M6G zrzlgDmgbJxotxIsY+_rm9buG4P$L>S!YJx79&=S6`)#DD-n%Umwv3Z;Df2>;ZA@@( zQXI!N?XYeH*q{Nwj@IoR$5(nc1x?{k?XiED+10UFSxhZyzS7Jc3HES4lC2{-SuWF& zgc`TSOsiI9xy*ObjUX|NC8jbB`=q}$w z-TN3z%dr%Ff`#5>9yQt7d%F?X{g~d~hpOFDwUC?lTxKJ43^RLYAE%7V*4g{j$-5nL zf-=2NJoPN4Zm?EaPApbnS1?2T2HGz5RD~W3u-9*B%jWiu%+2eVTbEN36XHgnTg0bc z#awQ(MbnaRU76<{+(|?SM}ji_Tes9IRF+X@hA=BkwrEuJOYCouy}@l+1$m8j`L#+cb8;QZQ=)b zRSA(^0aG{GYv_r41N|p`!VY>Gb13AXM_zjP9bY2D-K8fGX(y391=N{_y^hARTj@XP z6Gkx99A#a5EB`7ZQFa1}Eu0TfS9)y>U1!h7MmZnlClKkN(-$hB&NOV~0y5Gk>{Rey zd#kKcaRQZ2I)AYO>P*9i_f{*7{Y#&)i<%2HnD*A=YNhf7I$KGhOaXPKVYhHz)=M%< z7_kTol$PKI_O@%0s;BA%TH8paLIHKAVQ15Vrycp)39aMmsrm$J+exQh0d=NfXH&yP ztfE(K^SX5i9($Z<%?U(zkX)q#>P*AVCW;_|#l51(x02cu$X!K3RSKvx4Lh5hTfu)l zCE7=8sXKw*)uhy*fI8E#v*~3nPof4hWqN!r>rbG%lk^%DP-hx;HdPEIRrThwNAOD-HlnqjAw~mN|B$em{~8u?1yUP zNIb3534~ggM^Y2&#^c0&eC}77FPLoOL8R^ZI^OpOU%v`); z){@x^7O(X5@nYh&)K9SH&zV0q+2U@`IYDlWPuL#z;HJ2gO0-|{-A$6bIFnJ>ol1lh zUS{rL-oVUyD`LM&TcXC2%>pE|3T00|h`K zPy`eMZlDAx1F=~U^9O9N~`4qyiyfD=FnCYKAy1@eG=pa3WYihyDOv7THd zKq*iLlmit&C4lHru4VSHnfzXrAMjY_~UZ4q3rx7&32IK&C zzyUY`9dH4;Kpv0}6aa-l5l{@cffAq;CsDK98fE>UMH~=T011=yJ$OH0$0-z8m0*V1QPy&Ax04M~CfMUQ6lmMkb8Bh*X z5PH&Ci6d1&HBbZ80(C$=&;T?79>5DU0Yd<#ji3S=U;}ahJKzAEfDX8TTp$m~2MT~f zpa>`i+&~GTC!M7@QU;U*6+k6W1ylnyKrK)Q)B_DbBj5qNKog*Z2`ZogHXsME0}j9m z=zt5z1@eG=pa3WYiU>XFEXENxPy&Iff}F|r~~SO2A~n}0A8R87y_v85j4OCC|z=1>^#GKt50a6aqy+ zG2jMDfKs3gCpbn@98h}Q?19*WZK>3KE0vccgatJ-?wBv{aZ~{8u z0&;;oARj0I3V|Y^7;pn6Kq*iLlmit&B~S%a12sS`PzTfl4L~E{0lYvHFa%IPGo@3b zFD@I91K0rv-~@EQ1>^#GKt50a6aqy+G2jMDfKs3gCf?ih#vmR&w z8UYXBC5Qs8Yr>HsfKnWwOaK~S19AX6-~gO}4!D3^AoIjsM-Sd@FMD22z7%=M_fqP` z=!^ar(=Wtc2)v-a5Pv@S{O!;ApG(JM@jzUS$BqV$sz>9`2A_35n|LPljQ5%3k;oC> zk<`=Cr~OZ-pNc&dpgqy!PX?cKKbd$U^n~|`TI4 z(ewT1r&q>S23D#o<12zI+$$2xL(9F(lgpH4@uk6~?xl$(p(WlW$v`CF3#6K(&Hm=} z;@INAVs&wRQE-uaQDR|ep?6_&L1ck%L27<f@3iE(%DM4# zg6Fu;Ik`A^(MkSE>4~w4fr;S>z6q)E(eeKA>2a}ffpO}%xG(5)`x0YAW4&XOr$V^r^8^1E;E|#>WK5xW^<$hemrxCr2rx;v<72-6IntLLQKB$Jfi;r_kpdsZ@QddA^V4~;yg*(!*O!}e zMO}VZT94@gUDe~xpwsP4I6@AuBWaJ=efCsNG{>Klw#94#n`(<|LCvit)R5{`lXP|2 z{PWAd^dFl4FL}gx$H)AClkzv?%P|ZaTS6H_v0_lfJlHi%8WjKiG7NBrnbuvGgdEBv1MOOuVc!d6r%xL*P9VrHEvF=7;mq3^y5c$6e45?~bY%Y6E;FyA!U11;dumTK>?!ta@% zm~1gpD;My|kJOH_)c-SUy194@n1(GnkL+S_(j&E}O7h3nZl`hs7?GWigTB$#iQY*DR)y(V_~Eal&3$saP`Gua~7a;wfYI;|hGj_hxVi2#bS zgtE*`uZ)ufn90DtE*aw`b&(pQw4Y?H zZ!o`Nvj1nLJ;74`J(m24`Ju@cnLqi`?wV*R_!}1aEAvk#yM>k+t)u_si$-SFV=+&; z9zU7XJxNj%wPoA^u2XKN9Jp05%Jw0q$e#GuqHc@B)k<}5-CEpf&yaLQI*eLPu*$cY z-!Rz&yijzVX{q*oR`@&fGn4&4ywi3~woE}cs}^xNJD7$o%2}?}estO?lAx$6acjSo zs&u>x?pMGEm_kteYf-UoBdo2sHd@`{&ys{iLX4XIBFntP{F=!gXw9B&srEiA{F(Ww z$^PHn;-^~b|C=?dxtPnDhApm6a=o7HExzjRd@sG!${Y zxQ&|9sVW#%z{i+EQ2cArtSZAEg(jaxv+8jtV27T*ZU)mNd668WaeafuK45;wWDm4) z`7PCc$_ib~znkp;w;!f(_8~4(QEEYpRdBxoKEf2)6aQMYrm8TzQXJQsWLFNF8O^+b&64y*dW`1uHCFo` z^IemjwK+MSwQJWG>RJ`~0X#;r0EV5aYcG=zz?uJXYF{V+|2hA5YTwA!wF`dd&{Fq0 zwKj?a@aYI$3;)KU>H8?|AH@L}NoxR}{F_r7^NCY?o#OwU{a2^<)efh&@|Owd|7D*4f2&z(j4$G{ zvMHDc&b8AIn-kE1Tp$m~2MU2Apcrrir9c@_4pahFKs8VU)B*KCBj5p=0L??l0qlSi z(1Bba56A}!fFc5=uo$)*C2Y+-^OZ~#s~2XcWtARj0uPzv3!%YbsA0;mG2ff}F|s0SK=M!*Aj zfgyl$J3$3Bzy{a>2jB#Bpa3WYihyFk4U_{FKqXKG)DS3zwXo}edY}Pl1iU~KpdKP< zfDNz%4!{ZMfD6b2@__=N5NH4z0WYAwMX&)mfCF#>I*<#%`^8oO6cH$eaDB14fl>fo zFE)6+*eZc4pc<$F>VSFxzAiTSy4bt`++1uLU;}ah2jB$Y*XrxP2TPHgZuvBBTO27eP9Tup3nHL=0f#O4K*;%3S*pb;pA zIk4@318@Q^AQ#933V=eO2q*?hfKs3wr~oQ~YM=(F1L}bWzyl~_2`ZogHoy)z04Iua8(;?MW`YLTfE>U9H~}4S0fj&jPz;m+r9c@_4pab@Ks8VU z)B<%tJ>UhJ0A)2n1#CbLfl_FP?EstrJS}XwKpp@m3tItD2$TTus<4#-!1DgkE0)_zUQGy282vml-u=9X?pa>`i+(0P+9|BuBPyti|Re&0vN2kckKRORb z2~OI5lAd^I>%AtRteDUMRJ}*Yr+pjgQbX_pRmuWNN-?4CJwndyizrc_5lVp)4_$ex zrr{a{6od(`+X*F%kH~^cpUr_Qls=YH)6h&PT1{vK9AN@{I&3*etDR0iD_o#)k_!uv z+A2Utk}Hr}rI=6-Gy>J{5ehyd)B#OEHIi&YlIxLV2a=qF)RqCI9!g5}G(r9qt!vn=;N0J?Y6VQRW_hwQKDjMmB%?k_#?4J?J zfEu6?@B%psZLF&U1waW<4paekKm#xY$SEecfC8WxC;=*fYM>tQ0%|iM2gn8TfnuNx zs08YPM!*XwZ3GvP4-^6h-+D3hqW8t*3y~LmFQlH2KJR}%{aoz1z;o(z@pv%qjwgm-nvZfye>hfz+MRJNlcx;c8Y|K{{fv6})nsW-)M4BqIzF|jYS z5Bt1DZt&fZx;}cn|N8Xa*xtZib#Hu6aF2V>q1}Pq>hAb;!Ry?#|63^HjU>a7urHk2 z72V~ho#0~E2Ch{t=J>-qe6&Mcbi1E-iNnrt@vXtF?yZT=P^Y&u*%9gRb)>dLxA?cD z+hgs4c9nOFbB7Xbp*C+@a`WoV?#+o!p-tXR$&HbXzKy93(GC6$=__Mb2Ch`Ej9(GF z!hJIZ=`Z>?9w!|+9UgEwaadGHk@5RZB zA{Y5CN?jPe&~xE?7ep@bU65K8UFBbuK0kJT;C%J`_{!i)_sYbI&|LB(6j|h3lv)^F=wFy#5L*yf zpe~5d56*YbPs|I=^Uh1ojY#wTAI*-=_Rmhwip>hlQfI|y24}iwCT4_YcxNQ1N2dFx zr~FaB-=Cfqn--X+PK%!#JlB10;+)Vq-gA;uBU61--#R;Vw)gDhS&_4RXQie@r}(F& zC&wlSCaaUyKo)DW5n4nIGj}MM_k3TekIseEg z->B5c=t%#_^oZ~X--y)k=y3n=^eM4Z0;i~_#D@ikxrZf&hK72FCWl0Z_=cpKqD}s$ zv^VArcvWxQ6ZE(}iN;W)w=vnUy20I$s1Mb9>yvenI$vF?Hd^biP1nR~Xb--ccy+Ma zU7e^3Re7tDm61wcWvU`t;jc)S$I1icD$V^*D@&KgN&}^8X}ly@;x0+JLvF7-SsW?$ z6{m`#MgF36VT|@)RSV+a|bo~6FVV?iEfoyq>6ji=7B zlpn#8XEIMW*81P0g27MJkL@wocZ#j=9rhXB}lbK?`1B zsdf`9+{cWXY>`J!cW*|+{iwo)mV$>_BW+s&^Ib?3ZLE2JjY~b+b$p{%xh_ByMSYZ z=qp{#mO4Q`cZhkV$re#Ui1YB?CZd$py zeeD*}6Hq~!i|Z0g$var)AoFgMJ&;``mP$(IR)UbA&rpGx>Et5=ZzanlJ)v*35<|&h zQZ?*stt7MA0&glIx0B`lP%`Jtp2=CZP=vgm6@l0?tz^V06n^PKUJrS(sp?krL$_J?lF0vH7ibZZ=MojjgE>ag;O5Vvb_cQM?*(ZOI3U^;3DT!tx0<}I% z)mFzE;x`sQ!@a*VuD0DRSx%2uh-+Y+PH(1@j|{vOu9ozKzPJWL&tXzE>};*j*wBji zUur$B9R~X$WzL#CleIx!1TXD}Y+pG%`HSG1EK1@cDA%2l+1@5_j3qaXaMxPt^g>Qt z1aW$!%#0I@@;jM}V5_7dk|ZvI&y&Uz3OI&2p4pF$ow8j8*GYmR0Y>{fi%-9RIoD)o zYk&RO|LZbK#SN^oleyJo58`roxuxJ97P*Ugv&kOVga#y|~K1K&MxgUg~TQqML1y1VsYG zWgb!vlb~T|>t_AiKW$?_G|ic`XEHg+>;0yF$o7@hlfT|?&Y~o)_r3LJ&Sr08IL4A2 zNw}*`I=zq+*L$4aC^O^qqWn(gdLNQBM3Ri_eU4N-XO77n>3dTYV_go%q+Z+C zw#Ds|nou`d;Y2?79Of*OjVob?(oP-Xm`^yz*d}OcN4pVj8g*Y{&$fnF=g33<^2AvBLA z&SM((;HqzzrRF-;*~)A)*@LM*YQg*wv2Bmd`^*9$Y2vv(&tjb*^T1n(V<;;*FMy*RskD z%E_l==V2Ef^w_*0=1W$6!0|W1ZMVrkNBC~XgW7^9=pLg zonio=_$H?|jm7}Jf5f4!rE!4IXz#zPFLG*b8UuKc;{T7H@6=u$MQZ>k{{PROaA+Gw zI<&Zv-S&TWZP;Ol_6)`TpW=6FZx=hYD?YPp${~j~q`vA8ihZ^6<`brjObaN# zj~V{|@UEQ|=HC@;f~T3j8O~dJ8{)s|A^6?u?Qp!+x8#8xhykZ}!V6d53O8JR8~kwf z?T7=X?|?h5eii(2^{e5KtM5cCIQ<&<Nmn$SHB67;q;r8VhY%DiwfSV5k)rkldG1Z-v$?6 z{dV~9>QM*yIe78vcj(}qaOTwyz?)aU3+}x7-TB}>@aom?gpyUTKZIAZ{v)_0>pzBHvi_3-@TYK3)_+z6{u~a<`bY3k)>9?m$EDye z;Hj+t60XYnuPVS#;IXX#x(fUa9GCUq!gE>wT`l-~I56vffCsbwM>sHxY<${?Lx1vs zpLxM_6Zn5hGx5(V_!kZQs}1~H4)}LF_z!qE>;Hs{v;Hp~{5PDO_5b98|IGut^1;h4Cc!~>Rk!LlZ>Tv<)5P{B$Ktg?aCaGus{>|iaNr}a8`PwVw? zpVk{(U?aS!bx$7Xg&(!v1V?IpNFg{BF0A@6c!lbxxWVBi;0SnE>m%V_t&f6#wLZE6 z90NCN{Z#l_i)@?*e{218I9%&vYe66UuJv(nyw=CV^ID$(Cs}=>2b|;u&u9YA90E>O z+K5wB@GK2H+Xha}0nf36=fXW(pXLPp@Y2?&yTBQ_;LJR5Rz5hp06eb{oCBwAeQq&0 z&kfEm0T+~l3*o*kvazTfhZa|W&6QvP?%ev4YH%sMy7gsn>(-aofh*wMt*>kV&u;`* zdB6+2;Dt@#MM{`>F+9EXOEj2{;z{~T&^#$M+ za0=J2ECM&cH(cN7CW>rqf~UB?xfE# zfseX=FPzl%`{1Rne;#h?`oRY9{zmWt5BQ)LJk$inhJc6Fqr`_a@L?PHNDla@9em6I zKJEmc(7`8N;8VHa(|O>Le4@z4GX*&GY$15G2#gnl&$+?pOTZUO!57QGm&(DHE5KJO z!B?xm*Q&wSYrrqmf^XD;Z`OlfYyjVC1QQD^Yvm*2Z&dKN8u&XK z`1>624|ed64x-4$r%oLDlMa670@JzR|K)*y&IkWe0RFWQ{96(D_hRrLZt$Na;J-@2 zf0u#(DF^>s0d`e_-BmY7MB>g0?y^ryjI7fR0Ac=>c^w$l>_(+##^@)X#|d z8dzW>X7W)~n1e$_cCgq1x}9K&4wkyWvRtq{53I-sD+|D?La@3BtSJU--C$h_SYHY@ zl!1-qpr-=#R)S4c;E-x?Xbm{57Cfa699|EOXaGkxf}=d(XfHUX2|RTOQDoyZ1nkpK zSHZCe*{Az#;5Y>B)5jxfpFRO$`}B#3+ow-L;6D8fMDEkiMCd+!avnG(A3Uo7Ji8E_ zS_Ga`44&%-rZKl2ySkD}$up)XGRV(QJvo8C7Q zZv@{^--vy||Ao}+k=KvD7I-cFYV=j#tI1bFuee`{zZ`fu{Zf=-6((s_gZsreMJi0w zng-wV$>&1PxoJg1Af7%NJ?f+N3?YhBIPIAf#VGV1Nzh6L_37AC{-;v3j=@Xu34>3l zPsASg(<+9@V_u3+7^F1}u}AzAoiIWx7!nT!DK=s3@Ou=O&`oO>0*BHRmC#2k7eWuX zABf){xIcX`a?nfb7J?L$Fm|7xRxLy*B4Og5Agx)5Q9Q!bT@hNb(0m|Gs}+0{i7<4B zo7O4>K9`P0qdtm67^0O5@!J9vhcHU(6q2+~!F_A|mcT7(TBYE-IeAm)CO557_-J2* z)+Z!x2;QLH5Tn%zslAcCUWz^#+@tP^?eyPNAU(jv=$-W8K7u`QCf+R+!EU2 z-V&#E23R;UErlig29FA!q@^o#Sx6mKT0tK({rP=svtQhG{-$B zPB8@2w5Gr}J4q1)-L#@0Ff&c@1AQ}+(?iqU6g@CNs|ljhd=xt{L~9AAos*(<1m3BM zvx8@=XUER+(<*|<6z`P8j861TOil<*aMS9607VRp zj(dxu1**Q-SpV1*#R~MEo;WRdntEF7RR5`|F_AG|iW3+dt&Wb3^3#fe$Vl(V#E9Ss zbwrHT3#3kooZ>yDd02XAbf}M33WSEZhs2u#v`!%E^?8$?5Umo3HwGHh6dlmlkfb#N zZi)>Us7uod0Ut#M4Ar=4eZWUm5n3CNs0>!Bl`&cwkSdRqd&?6P6HqOSmHJCl6cNx% zs{(><)g3GL)0%)tk(Z(Y25Ch=tiWH;mhaAwQyjoFtp)JWT7Zzt?TS+zz_c^!^f{9h z1<>t?+XMDA#Q^l>ByAy^n<4-Pw6q#keH{Pqx<5?VsoJM0YUcf)^Kk_{jd=z$`=DlxQlqqF#;02P9HGiovdVtujV5~lji>t_NlC8DFH$W&tAOK~Q<>SW0(oJNLeY^#Wy+U<(*`99Hi){^p`#J|BpywLfojs34H4Fm@`fG;Og*EOU*T` z)4|+ivIkLz-H%C%a*=+SisXO-p29qhnXQAkjCF-ZnYL``qf{T4^n|`qs%P-o=P}PS z*@G+9CoDDBvCcMT$Yc+qRJ)$ERNT!fcQ9`?*@NgAPf3EuR^!>q*Qo-xF&8nHGf|C~ zDXroki=Pxzyi6&hCy>ipJ6bnw?QzmPwtqY=Ns1&GHF*gObTT)YY{Mb?cvn>22qC*7 z*uE&ZvDLyIwfl&qD^hK|a@8r{psaqKIfglrnJufi$7EGr3@grU{qxJT4q*O%r}l%X zPVF*U2k_T1PAx)y0PcKej}O3`KXPab$p_%aH2;6uT=Emx?$oXw;nZ@;7vL_M{~t#2 z|6V8m|GB3)wGU|ie+9+=`@_Qy?JAo8cg%EZH+|WuRhK%oXKC(#Y7@=-)7*b^)Tw)bHH>0I^e>=m-4|^3vi$iaO3-%rQloT;Fl_JxC-W1YrwD9;y^vj zZ#IJOcyOQz=6AGd#H5Yrvcr7eLCg$>7QFAoaUICTFMpT^Gao3#_n#KQEC$>_DGq*I z2D2Qf#P?6C!Qa&2Kpo8A*TZZ8Jox@6FU%%DX(ng{{Vz6{Ie-J-|KWtG11_MDK=Zjp zu!{+qBo`_r^hM7p#qlzr9H;;)fog)DR|B&ar~~SO2B49kyS-p(6Amb=2`XSC=v6r| z?SKPt0+^q5URsMI_4wtA2AGY22k-(-fEuP>U#t;bHXsME0}jAR(AT)Y z)_m}Co(R3781{w|a8o%Lssy+2>}F>T*}Sipz8%w=yr-9bwFhPs{@JzaAu??QJ(2^{ zK@iE_so#c)N_hh>o|wD~6O;Yfx2p-~IWz?S zT0Kh802`14*a`Zh4wz0rCy3NOnu}jPg-J+PK2U`3M={^%as#FK{sQJ1UF85~8C{h? z6;MOaU$2E(2h;-%KqKHG=!qfVS8VSQzitQLb`V`WW%!N@W-gEi@DyPZQ-rP}pcrry zM2bJ)3BnJ{a2)f4t_lFNgRUBa{HPKhScMmO>_8I*;hoBeQVLAXE-%BtzXY859b8;1!lXDdU#rS;<&%)J};s7S$ zc#ACEQwbB3Z@fL0K9ncUPQ%2R3-e|!Oq=m8SNiy#ZLTtDE*j7CWoPhKSC}qy@jTgC zm?v{#n#_e+G8a#eO~dqpEC@XIx&I9>)+;QM8j zFspzXe7~|5W*tzE@0%LIHV+PXfuZ=`sWg+R0vbWzo&#QG#{mc6!uMUdF!O+Xe7~*` z+*5=DB{27ufj5=oKqbsut6eMX{q-R* z)kD2$eqEz4w2LAA@+~_|2cYBoS6nc2fjpo92j4D)Sq$@?67bulI8X*u;QMzgVO9av z`2ImH_+dTx!v-8~1ibkE(`mW+6~S$RxSA*o|M7m*99QPzIFaV09%}TZIGFKrOyE*1@a? z8UPOt4)wxp0+ja%DnTD%14rfHfE{q+`)NANT$sK*m<2E=6oHe9ai9d|#*a`Y#2TUiRNVW);j!t6|o{Y^{UY2y?v$W)sW}LtqXih(vF&d6v*afF0c8Ai8vz zTU{{oVD2aYuP(%aBEXIByGme|0_FI=yAs@6g#$G(_tk?pH-fkF1AFnUH!Di<-nU*` z{hIn(?A5@l=~tq!_+LrC9DUiJnVV0&74`9yykEILPVoiRgK?UtcW3qvjNco)*L|-MT@W+%#?FE1 z1F-{v1L}cTCbppej`ZhZpL;KgeFGDj+4|sZ?%U$~gZtgIYhd8k^er)-uaDgvps0e_ zGca{y^hW=U>3z|C{(WiQHL&e^@AZkjA)d3xj)95Yq22D?iR(ffPcRs9M-pM|7Z~3a z+@~|BskHGYr*qXo^bxrJ2|E1|*Ea<0s{Mc&$>Qqa##ov;;BzlQIvqxa+ zqUc5bi_#P~&`)#uF`CO?y-Ll@M@hCejfJGuEx^~~5A zfiu#RV!S6HA_S%;L?(DABq%*!1bK(*vigr^k7oKYr>* zW1?exV^X7|qkW@OqoSF}fWDEb5fO?En56vxy~C3{)1Md?8s;6A?1>BL9fI8ek9q@{ zod8vu?GHApjq!$HCMKY}K2aB{^U_{`!CH51f@b`^HOcBwwYNG+v;MxS6h#C)S`qAt z1{f;~@T|WP4KPrmmc-qG%)EcPDAp4TFkKKU2o$9AWBGynaGp0WnH$P==O$c1mztUT zk2(F$lq2HsIa0I(pojsOv_)(_TS|*)UM;CcGW-7pkE}dGp`Mk%lg9f$um6ARulyx5 zZTyThcp?T5AIHco^c{yiMa_X6EvdfsKb{TG8{8q)39%iVU$lldxeAt`)t|4^4A6 z?U`&2G8V#%{gBm7Sv71?t8!cFZ>@&AU&^8@A|uGPYGhs1z4SBO`<-hr-1V|_dLbtw zBjEH#2^uFBrP=?;2;uHmBn^>>CcciS%DbfDX6hyz4Rfv1DgLqe$-%iOJlD3hoozHG z-LeJ0Fq&ict67A^i12$P^q~TdVNPUb70QeV3!&Eb_D!3yH6H!FknDO*k`zfWdcZCg zxQ%(E$!<|DrJSwf{NrSq4+VeZmx6jT-7sO%sM85(zesh zO8RiE(xk?WCCge?E?u>B*{p>vGiS}7yJ*%-{L4&JdNYfp(Ue@u4@h!4vz%GSL{r+L z?2r_(H!EfsTefZ4v8AJRBZo9JH=-{}VnW<#L?ijs)0mS@wh?r9<8h5Bb8VTidE>_5 zrnOcxC~rx+BHczNtCXKoBIhuNGeS~QxU(>Z4;;85lWX0|f5hx3#?>KPrI z*B{p{z9uONWurKKeBK$%X(oG6#o7IJNmI_ z)E>@P^0`3!2+i^>NlHi?_|B|ZV3I!a+ z^f9wlhHxiAWn_)i@m)z$B*CbTDJ-ynIoD*%)sabP|FYTjJxk5=S?6-*r6zk2jr@H{ z@Yr&#Q$C>*eTX@RIf04z+>;a|_?h?%`Wbc^uMO)bO~@W2`2$H&q`)ZFv-te8nKMkb z@$A0gxM$29i{e_$zj56i@u2Tiu{LY7B)tRiInP*M^}HTvKf z<=0eTcQDUk&SYk5E16eJqpf7|==zbQC{kdwmHB-B70jh3dthzl$Cg@ceEu-=Dw92k zw(=88!F?)!lz?DcZ(DVdhmPdk|Ilk)_~17P*gko5>zj zcTZVL9%h-Rn2(xl(P~bnyMHVxiFROg_fwVMQmc7@c`kD{Gh3_4+;TImCQE<+g(NAG zV6>WrED&T~VzLL>YJO=cdNm8(%-n0T2hnPNWhrTfcieLi!J$sW`rQ}=HqO*xOh zrvzT9fTNh>nA!4}d4kF0vG<|EoXg)ziXsI@F3;lgFJ#U$*@Mbu*Y7MfSFz4|<{Fbd zhzG;pOM-H-{((wlzXFb8j$@)&5l2}1hzCPFQETFqqu+9lK+1$jRD+4@&AU?7{K%N?(e4$Eg_Rnx~{Qo!T-G2ea|NC&cQ(HUHsr`$5|8J!D|Mg#SXip8HzkkS~eR~}J zJ?#OIPB^q(UZ++_@&E6m_x|By>HWV=Q!aVk(nI(homIe z<)5hVUsS+x%&E+5b(tS-R2peacg>cL&3H~Vt#j`4Y3HAkx=4*to3mN#eCBeKJ-FKZ zm!)PW>s-$ao9w~V=D#f!_p{2~%+HzZ0n}#Ke=LcJk;6V@D!g+&{wI-B}cc!$TKo6)T|5H0&0ditMC4 z(4fGK)lKQ^uMpV?xlRr&;P<$r?ME+f8Nw@1OlX+YZVZ#M*5*xHIy`+S+AJ0Ku*zM`n@u(@E+-sGoW7%@wU1pPyK`j8 zOp=XStW$ES{@!GcVUA=qqBBNPv{$!IFHZ1k{K}B z;>BC8#LSkn#^`Jx1?sR=Yhi^enCncoDA41pkSA14E{5iDXIgZ}AJHF<%~?C2efE?^-OTlu zUEZ;UC&Nv8E=#?GtnnE0u*pVG=%D#Wd7ofoi;I@#j+w1%pmeO8Pp+lbQ9l0{m@k=Z zLu(7|eRRx+8YKI^G?UllWt)x@>&}zJ#2=&e!)q~*s>Mtv9~pS-&zJOszR~*4N``IE z=o#*Va_hGnj<4816m37t=Ai}s&~%t`YS^M(%6-5HS77W6*hkAO?1xysNzAZC%al8T z)H2r}-!hB(q1RXDjFu_)1nZVr+z&0Iff$u18Vj_x9M=mhTV}Z1okdJ|Udk=gkQD7# z`Wf#1ZagG(l}M)-a>ikE<1^dh!gyRmq}##O4jRMHTMFm5fAm3*r12bpu2 z3z*qDSH{5$w-#}sH$NPdNn%3W=vhno)E6@^FxjG&%Neq~`j%TtwesmZnCnfpXybB+ zvS{O?z)t-0%|hDe?@fpH3C;Uow~%7+|JSa)^b?0R?;YB&FVCrM{INs(C%ymQnCsN) zC)0FXm zV}44kw-mdV1s-NTXtG7qKeEt5= zZ~7idPw0zBDOt~+(HqR8l(!$64pUAITQo|!1DxPds;M7h`6e;L7R^%b0T#EJ%td)f zKlJ*_+&~_shW10tXdp(D5shU)k5a?3h>1rjxuqDAqWwxg!@b`#k5Z>drx$X@VdG>* z<1^dhswh8s;6dv6N2%eGhDd~Xlq#a?KB$0mmD*Q3-3Nlb`~M=8i$ z%mNoM4O_HwIYXA0-jSA4t$g|rbG^wHZCvh9C%E*EvJ|_D1@2)G^vp zYd@d=KIWY!TU>hOd&&u(I>tz1$F>faLQDK<2THJ-*~o06pj#GC9hYT)>Nr)>6Z%F2 zIfKtWlX;HG9_UlYX_jgWSYah|smT`oOKv09PaUUQYPInB*E83dY|-@PCSuw2$688- z`1E0Br^yygUv42Myu5e&Bt3H@!Ts4ysW;QfM+V+V#z}fYU)-N%J$puPF!$&2{m^un za%$M3`sAi^g8TD?eu(9p#0*muqcTM`OFzTC-!r$dNz&T`tZewRkVnW<# zfHV2jiGzC#$=AZA;yMHUa`~QR9{qLlA z|B3YO|5b|lcRs!U|C0RvJLvsChyK6!HHUWUHyzp+f9uc|)4Tu2zmJP8o&*u3`A<5yLkEoljD zqtT7yGtXvDGufCpZKW|nxzRa|?M0WgZt2|6!D~imE?z!;!7ORWe5$2rGYeh7Txqh= zb+H}0-25^v9ow;ICgG5G<0YZ{97#$Pizv%-D$5HLa42&$Gh10^R;E%}Zs@Bp&y~c4 zxKWtn`P4I+=a}s5g~`jCGljXJ&yt*Gskn$$&Sx$+*#jy`za%A>WCfLBPyvTBM=`UN zWN)inx1oclZ@5}BuXfWVEuk%1B~)hd`Ojq&c4V6lIh)F@|IYA(*? z2Fe$i?CeF!%P`O=vrL|L&y)n^0<9#es}yi3a||3%NMe~F!d*?`k;_t*zOPi1DSzFcFqbmq#^NBzx}dpUc@IOU(f51euqZ?CiC7qRUy=VoSk|EOHHV zo5>zT9X3mXavj!Csa~Rhr!mJfA=s`Q|Cr=39$hxHZ|>+_zay5v(y23drhp_W5@A&3 z6qcCJoMW=HKcsUvG%p!4B$1bl;u1^6rL1xhbEU~fMP5!`HuA$#W(C&L%h#_nZo9oo z-Ag4U{0bj&MXTik1y57J@yvb{XnT*t>G1`+OcE7|5CsaM`7AVtY1o4)(B+njOIhV2 z=1P-2kOEyHDH+8n3Uq{0M|nF%sV7chdnU7mTwa2-8btbtuwfg6SGK~lEsMX>N=Z|s z!6?r)tkA){!enD04^Ck613kR=$bSz`V8*@v_($xn^DPy3vdVtuZj+7jgcF$DK>M|v zbd{y#L6&)j`Gm>F`&c`PQhA#{VTTdAXlDERt(g$|edO{2OUW;=%sb4tO*SOglc+rW zm6KVeyFTmVVb_J0fHnw5|Nji~|9|%>hj!s; zTI+uS&EwPB|6E!FaA1{F8%i+%o+tnRb7}p5lIH(cQ|$l0zU0t$)BJzg-yGUQH2;6* ziw^C}%P3aBFKH}+;{LbIps|E6JG6W0-G6u!#Q{jtSVEk944R$VCVKZ*K5}TGq7O&v z^!{HEH(CY1{~r_oulr)DR7CT^l@Vi+4b-H}%;O`2>&TZ#nj#HGM>eY&wmqZScSp{+ zUJ1|9EUs5A{m^una%SJ&e4FWe^tDye5Q#9JN8Cyi)&4T(DCXJB7J9hbMAswf6D|#V6|d5=c~k55^&Kr6 zTY_zEYd3EUuHV#qNQzdsPSO|YF?!%RthR(X&t#*ebW#fBJi3er%-Nlr)^x1je5@+c znyI(TBvFwKBaVftG*YIGtc%}R{0#U0&Ul*azC6q6MVStz)6Y}DQOt47Y-O5h{XJ#c zV@M^rUQ!jQFiLU)Ys_IzGueYGNu~P=NmP_Yg`!cpxRq15Bu5f`Y)@tmHmg@ksv;Fe zR?lLMh0IwdJ9}1nOCh<@Q1K!+nL6DdNgkU~Rq;_4Rpkt#hwW3C*)p05d6B8g%nzwP zH%f{k1x6J` z>Z5drvM3tY0+(_wX-#ETFl(7@bZu>?|D+E+MPr_!jpBZ8Zr{3j{n}&K!n8|TLfa_J z5q##em=jGlo-3gxUrUX>8e3+yw=djsne=E$>B{trEs~~4v5~(jWj5t+5py{6R3=`9 zI_X(f`iOaywoYvBb=-(`homL6jr>jGGcRDyFxkl8CR&yv=P$Ek;;cQd%Wu`XaXFq@bdu-n{6 z%ds2pm&c4O9oK+%NRlE6M!Ak;fyvBCCR^lEF4xQhqIqD66_F96cXVB4Dd=aBdCXZR zdmzIgS4&EAY0jt8T%mwX%n{6NrRfawZr>=)6Rl+4DG7^&7-f1o%gkU-Guhe8v|sUk zuCWxI&qB+Xi%s@G%Jo`FNiNp~+)BX)1#DtwE7#su+B;mAX{CpHqW|rZBt;TLD}~Ht zmYKvf?Bh$+_5ZBh34jw-oa}C`T_Vpwg0cA`~Us=xAeRJT$kjf{Qno|_y2j+55Nb# zE-6m^0Q}WTm$c?r4(T@wT+&vXEcvE8rT2d6kfu=|0N+Yc|9^D-|G(3<|C{L=0QCPi z`^tO!=tgit%e#C9(qnXi(5}s8BkH>6^1GM_f}5Tw4ZsV0AOM0O1X@5Vh=4ZG0W{DB z#6Cg-Hed%1-~=up0|nH9df)*KzzcjJ0D>R{T0kp^fOgOUG|&a4eS`}rpbpdn4`>7` z2!J36fff(}?LY(KF~SaS4T0s;zP7qE| z2O2>WXaTLD0|>%Ank(Q03h)3Q2!dA74m2P}2^(+%1vG#FXa*q=0qsBoBY-_l$iM^q zparx7p__037f?Vw@Bl9efDmW{8nE>dF5m`U&;&vt0y==G6B4ik1vCO5@PlR$0iD3U zkEjQ35CCBi1@?nP9cTnzpaLK8g8*m(LC_3BAPibSD~NzL5Cxq;Iz~8v0_s5n@PQy` z1ySJmlu$qe2!JqX0Z|~HAS57zdf*0L5CCD&20DSwOLuFNfg7kG079S@bN~(5#}Rd) z9y9_k@PPnm24N5Z?LY$}b(u>&<;947jTXnxI300 zxaf%@12<4X69|KL&72^8Q4 z4L}6}Vqm*BV@xY(2c5ung0KSxct8X2g8*m-Euamw0}Y6{-WfJWd0 z3L#%mhoTq7@hXZU;TjQ}2rJ=JTn%nlBtpAJvW)-buZqzEgNR{kHmc;jPqL;#;{llW&&a$i9(y zqkJTHBzZ(Ul7Bt*y83$Iwe)M+YsFVHuf|?29nKz394;Tq9ZDY3*`4~bFDG6uzm$6^ z`I7ijK9|a=xx&HpLG57i#mtMb7fUZ>Ur4-Aem?hn@_CWnuTOoh@ND{7?b+fp!ZXI* z`U(fq2ebplr!r5)o+|Cn?oaIJ_v_0)k$OUXqVRb7aqaQqW0}WdkCn37Y$99Um)n=z zr#~8dwDd^!k;EhAhjVn#KJnrFL#c<@-j%s4 zc30`n?45}_%Xj4NNZz5-z57Z#vO5wx%G-0>liS7Z`EADC`_fyrt;H>wEwL@7&DqU~ z&E-wT{rmD8QybNdg>*WtrHg$+Uw%VsgSw%xKD}OBUtE`27h6|an_Zh&TV9h}lUyUN z$={Z`O})*yhhOp5%&oCoOSfciN!(Iim0OiurT4~qODnT069aeg%P&tYSC6Df# zF3T*7Rqo?gUYc8)Tq-Wj-<-Nxy}7U?y+m75yh*qzf8(+n)f)?o(~Gsm#Tzm=#BL}p z%F@03%Gc+vPhKxxpT913oqAniVS1squ(%+zAhw`1KRZ7$znsh^lS#ch)?J#HotKzb zo|~JStlZ5{ol}^do~_L;UYof#c5UgJEZxtqJS#UVIZK?CzdCibdUfHd^i|qb#Va#c z#;z>Q%+5^AEYHZzNX`&v}(|x=_8aFg86_8(X{}b3yEa65Zo3aen!{+>yZvRtv2ZDr4JAV5=3H~KS!~YJ9skr| zp()*@H5CJyKrB%5XZ;C(*_ZPf_xww#s#@@-y_&b!m}!hPmKw4Ri3a1Yf1)SvPPtWg zp+3#-{FkYV)s>X2l2FQWPEN|AoOh*Ms;l5kJ2hvK?*12Zll5pAmjG4S}b#U~#5V9(wMF z&9H7annTTJC0}We(UwA>gi1P)r@&Ji?ffp$5ckO#f2uc*3ARu!m;KpBPWd~ zwOA7R_tuPffJHgNe9=_K21Q<)HPPdgytHbalihC#$>$k$2zf&DX*tZg*_h8+haRv5 z1>ZykE@45GSBQH}EFt3wZ+K}_@Nt*@-!YIUepXyuoM@H#Z=oTxbZ zCe}01&DeTuH>CGJTqQEkrm=2VV=nmSw>;{D&yC5Se8e(&9?lqTOw3_gnMRpcRqJkG z_-vX-Eiw2^82h&ih3lzqIz>2zm9JtVMj!2JEQ4NW^ue~NZ|&;MeUu$Kw8eLyB_5A& zRLgEQ^0#zxQ@MHu8|#hD$PB&J=;0A-qVnbR zSj}LsvjFcgkDAKWbJy7AEi))5bZDr@YliwRoBWTN-#3-{hupd|<9$i;Y|x?co~Rk` z_bi5;)fSOyl=1OK9_Y|~HMVHT1GR?I`=7Lg;#G}jJT0IqX;e@Cml}`y;NOgm)W5&V zv4Os>+f*S2Ntj!i}_K)0mS@W&Yu| zCS9NY!~J~Cc-OEPH#3u_GLPpnZ#e2G)?@VQ$WzO!EaM9`V~%AXz)8#rrZV55$d;Iu ztvB2bML79l%}{YR`MJ!iOl2NQv4pB@Jqk7alJy_7gyZk$2YpLu>xsgkZdU%BJD8j$ zD4z*_(1&miQ&6Lf8amu{+m$pN)-mU)->gRmn*LupgNWwEbXFGAxaPw2qrpDUAw5QY z|F$(yaPpwOP=rhLUOIz(Ifh}$2LtP15`P>aIt=@mQN>qL@KKM~H*GKb; zHI?ntj+{Z9;TFfJ4Ax3mS)9t|9|$A# zzhMc3KVdMA=M-Tn&GEOHA!dY$-R-tv&eK$Gk-KSIYWdKgFmGBy@zBOjwueplHs&f* zncqC#S`#WgInmAIV?&ODg_Cd9jP*8~{>RJ@Ol2O+S{VjoT{KLrw`<1wgiZgina50J ztis{DZD)O`W8W}qJv%dUYO0~$|BfY|vB8j#hIJ$gt7wy{OxaY%Eevoeg=NqypQvrT z>wWyaa;$%}N+6?dgoM=;=q2VD=EcmafsAu_1A(gC4=!&B%4fo;CD*eMbSW-{US=v+ zKi02g{2Sf;n_>oFbxz`;AYX;rM0_|e%G?n?v9lAx0j{oU~ z8=L53*<-%aKsfnP%~<=`^bau)n#%kOj#jgIpra$>7-jJ4+2NP)3pJy@$0B`$`Ddmw z|F*M!JydSUj3c8ORrceWG5?mu`8o3^rZWGbWBnbc7@5cXhfb})U#uB8z^d%I%n_zC z{|RFKMORr^92iw!*#0kBV)CuTe}|-L%Zb9EZdU%BAC^xnLHSJZ-ywtHjL`L!pu_hc zRj;>Gu5zWP9(-gfRjG0;Xg&P=@)-nonwHoo^NMW!(41*S{>m9dwVR?EWnPi3AD=U; z$X`8!n2IT;QRWrd`r-Ku75Ug11Ric-s~zF9u1jiGWWB#oB_=<XN)!`<}j^Gqs(`;*8Tf%C)@S@KeNQ(Gr=$B+Dz4;O@InB!mM^N7rrS2 z#>HHVs$R|Y^(rCxaq$)kHcfy*W*ZY9e_YXJ8Fbm`PHNk!*K-{oI2-WimS{Y>@wp$v zrX6QaHkGl1+vwY1mtOe={kEt4|8G3`6rijh_3&S zT|@o(J?)ZaQ11VCZgok^DgXb!7P+MD^v^-L|NE||^9Ypt{~G1}PkoZkBiLQi3cB~- zZ|R!_MFYj_n*KefvWvL&)vO@~dH2?>7mo#P><^La)gxvV_Q8(rPfBgf~ zO7PAXqQ!Y^gl8P`N$VQu!KMN~XaYeH0xh5ww1Ex~1)V^O6E@%gPT&GEr~~!D4H`fr z@B$V1K>##?W)KD~AOhMzJBR`ebONE9kbn)?ffKlZ3>44+8i5!1fFA@v69|H45C$!v z6+}QA&_E{;mJuSb0XuL2CvX87)PZ{71|HA=e83L^pb0dC5D0@75CLtV9dv>&AoLLu zumJ~f0vRZv9=L%AGy*SBfgc1w6KDn@&;nXP8)yd|APO|l2}GTcfDPDz11P`^8h{u0 zKoe*NVbB61pbd0@DCh*@LBa;?zzJMH1`4PLZr}kb@Bu#vfF=+EVbB6vK?JmccF+N$ zpc8Zf@hBky8>j>IzzrIK7pTAw0-y;5K{E(}7SIYJpbfNxE?_%OIDiw#Kmm229(X_l zXas%`08Ipaf`ceGgBH*VBA^YlgANb{8t4S#r-TG-zz!V10~&!B_&@+Ofo2c_ZJ-@= zfGFq$T|hiRNCeHH9c2e_0vRZv4!D5_GypH~0Y3Blbbu((fY?XafE_r23n-ut zxPb>W054F19|S-XXeMY5Lnya^RuBR0paVofC+Gs=K|%s{-~dh_0|nH9df)*Kzzcl9 z4+02Xansa3N+9OY{v;ZZ~zyOK^>?E z9?%H9zz6)G2?Rk1gh304fHs2Wumj~TAf6y3-~dh_>etYV>fJ}L!D=I1$B8ED>dZzL z!P1)b673*#oN%8YT7d>aboH@K@)D8bgni#!S|Gag&E^Nb=sbE!oX~(rCzO4JkMSv$ z+JTcUh_cD!Xcy7mO*AeeI)GCr8V(ZnqZkLg#|h`BMAVDL8An8b*iF=f&_SXLxQ-Gk zXafPPaN#%+1+Ei>eH_-3+d&UD2hIOX-P7r%vJE37wssmkSTP|WW9=#L_jA9W9`_mcG|FZoLD<{te61sM`@|UaiSA6=tLb>jGyr-l{$b6YeyM}Js;!#2dKF|)Du-e4q zga+gjMCAAkT2;XgdZ4ky2;ewD1V9Vu02;7UH@P+$cz_Qyfe?s*cF+avUP1vL-~~Pq z1YytyG$3{pc2Ec0zzYJP8MJ{8paG$eP=FgW0Ks`#{i60_@rBF_u@_3uXP-|zUw$t4T=F^bx%{)KXVqs5&!nHxo+&<^c{=uV z=|J{C;z0SS+*9LNzJGLo@yTURs!tZ4NI#)HQG7h}cX$o#{KZJBxQ@?ugw{x;=Y);`Z{6+>YdqPq$~cC$^Wj<+dfaiQDp9 zQ(M)og)QkV+Lq$x%;wnU(x&XD#HRAb+{WZaabrH6N~`HYU%F50D{jbah;2A_mU;i; zs(f#%SM5ExGPzP*nO~7wp{^(_PcPS&7gL#3ELB>TU6xo@?#cBed&Hjn($rFQY2oJd z&DzbyC7C6$C8e9PHzjT=->BahyRo!5yEw79d_(SrY~E+>Fc%Yi`QkY zi(OY*m|d7ySYD7@kX#@x$j?vBSLYX!>7YYW$;uhFh4&dSV+%_?1;y*hDq`KsJi$*aVx@>j;MEYHl%OwJT% z=4Yg4s51)F)6=!-#c7#ov1z45Hjzk_MN+LYoInJZ#flrGO+ z9=*JHS?03XWu?j4$%)D3OLLbdFBLD%PfATvClw~9Cu$Rmmt-!9T~eBmosgJN9-kYZ z950T~U!1yFy|{2u`XcS3Vk{Gj#Y*F{;}YY_7v?TZUMOCeADbGhjxAh}zCgR6cz)*m z*!iXNvgakvE04*INsbZ6xTXU_+ zR>4F42{Drktv?;7B_(N70_K$Lu9r)|Rl9rJR(ML@6((L{%&ZY5IkK+tRl_ z@lgA}uk!n!_5Zibxc{FpT;DSxAtapA_sno7y!HNXSWc1fvkN@0ZKDlme{e$P32Bs#rZP_V z4Bx#COQ^7PZ!_Fl6#D+KUBUvTnQKjDesx8abJ?a|ZibE8|1C?@ zQ`fE{+(B#iLuQycl8Lp8%N{HPWrDG$plzqS>fzg#sC+Jr6+D*3xRN==ROV;1ttq>U%#-6}*;lr?N`Q&$NhTX$LJ;U5*Dp$Yu!PNJ@sgcBT z`NQ#=L0@8l-exg+_mX%&mgRME!S7pakNV*AO54o$EtBWrjM2s<9i~-klzFAK?iq$_n-Ti|-V%e)gz=3sPSB~AHj8j7 zE6-vYwX~1Fm_O2$NGx%ATa7Cr{=pKE&wx=u=d;P*#$0YHqk?V`hPx7i^?!BcDOW-a zzu);m&A@wDuqT=OOy%nBqb$#dWwH$)?;mT%%d;3?VSdR}uHG`r?r1_y{KH54r<&3J zkwy49^CzY<|J+-5aEftcz#I365BbBIA!Sx+nwUOQ8K3y!uZmy`NUfp6MbrC#WQoS> z96x}(i>jzmUHM;XJnDmgs~kZ7xXR>>&q0%rp~){0?j=XEa*SE+b1?ATf0`>J{+}f( zp9|x|Fqy@e&%DM|{y+FId|ET`IAIt2z{AO=^4WhFN;TtM#bPXC&NY>JJem#jpr66@ z5&v8>;8@`vn&xH9Nv1OY^jSX-cB28f>Zk8tYDSyRA|#pDn94kwHMQonmq`4iX1I%m z-L!BsnOB&~{KIZds5zq#`@hx7dQ+~ktxJ?@fzK)L@b=-)3W@BfaNOA>P~=?S{`--Htm zN$9o--`H~h9S!vRf5nH!yqWX=E4#{nx2!0>K>WaV57j#!H2(kf*mOh?!tKJp%+m6{4)mTtGe0+6cOsGnO#6p`DU*~=2`RRW&W?v7@9A0 zwPOml%!9`imB=*W)a*IE{})vP^F#T;>TKTLyy{yX^}*+rL;3%m|>=|OWVv}%pcjs;HuEGXu-l6vu91~9;UPLUsZ`` z9Bqyi9;Qh1m=`gpF!9T-R~Q=4V;rq->fOxx8(+6!W$)0-H-2pi$!EdXf6in9<}hcO z%D8LG24N-b&rcb22fOf~XAXrr_4)>(|2LLE{Ef!4wF!^VvMpzhVUA_u+Kt{}&Z1Q= zNm<_8+c$KXerpNELmSI9flc@-<`h#I2POFVZ(XL!>Ch`T_NKS=u3xcZ;67dKg~pfP z$=}rsIgf=|#=OB)#^-Ab1+{*@Dt(O4*s?K&+h7bAvHyQ95l>y8?ZTt1uE6tHc^ngU zW$iHQvvTA6O>2i;p})7p;<1etI+0Cz4s)id%$Lr(LKWkb;E<)W+|^D0(;qBh`6BX< z-_x{kV+E)%>zTN!VY?9JFXoSQuEM5AgmtOyqehKNjgC%S z#8=%jY}G+Ufc4CE!fI-Zi1HWnN51M-uQyiR1|YUN6+s3I9zyHuca>c#O|A9a_2 z`*q`<4;$&OJ(b6SXhOfeN;G5VzeqStaXw+LVy}tF%B^gn#%aGvzfkWXdRme`rW}Ufa=~nqjv?qt;d|QY;w(5Z?oxt zk@>!BxHKUP(#A9a>k zJT|W%h;lod{x+sj{tWfw#J~jr^)*B7Vv~P_xyMvS{qXnLrPsdVlrH}c$DPvOQUCu-9&<^h zJWVs}l74oa&MnYA00p`RpyBY1yBq2E|JOb;HVymzf1=Eu3|E&GV|<vTok0O7${- zaNIRl%u{S-yu^IoR6e_k?5P>+4L1Fcn0ZtAEGu$@CD^GIIVrqGmFs=xGUf{AEj4#^ zw^XUfjh0wEwo#F9V^iMDOq&k~->fP_NMB{HZ_C87Bb(-KC%w^0K%+(ZWgK<#D z-+)Km_;y;oc|(eaVmtcEn)F*@@z{K$Ay%4Ae?8MESKny(jod@uPL`irCj&L(JjkYf zfccoI%-5jxtLZdr@MKfXXa`w@*O{-F%4ob#4g1AJM@@8vV`}B04_YGeRnNE8 z5n6w53UC>71#@l9ZMC+_wraM-;<5R*LX?ec`Wu)=x%#$Zom|kivi#5yPKIg*dWcQ@ zY3Adm^4V^zaLs5r7U2l__<>C}xiNqCD^;5z12%-Kxi)?!05XPi1ZNUM^3 z)oKaFLmS)bIyT`o%;lys&oi(d^_}s(#Uhrlr!HYyI7&Y^@hiP=P!G5ptH{emX z&{~^ z)^Po7bkvOXuWb6iV*ZDz%(EG2^_mCjzMytL8$y575|6)~??Cc2$qxm%jJcADBm?a3 zEraf0$2nW7?Ljn4Fdp34XlvM{?_};Um8OXXU)9|uc$;iw@Rcgc3*Ol zq97794=d<<4nH9+gKnImU$JrX%HCC*#@>oQ8*%g;YOb(C{}NXTAdISHZ!XQ#X%z- zHX1>PoUPaYH0CtXIw^vW`tLzB=w{-#|62ObGU#@}t~-Re*Ug?i4u7hw#`8`SV+6f4 zB0z=dX4Z<)$YP8d#ZH@#89i>aDcbp`iH6sXq|Rgz4F;KL?^rR+zL9?MQ>Sn}i>9ML zj-HLZo40IS-!pyQ+yx7J=FePs-Tb+Ok^3(=P2{ok+6bNOMP%5@tkxHR>Bg>eX3m*6 zfANs5C-jf464BV9DAb#(AUw(pGows2eDu;k%b??Q8@27M>s_~EMc)o%-BxbyYI*6I zJ$;ce@(ypd+6V<4?Cru)b8)6-~O*3a!Qx|t5f>k6HaLrUH|{bm+4yn ze{o9Z+~btK_%)|A`=6cC4@H-h&Qt$?1*dd?+W*f#M*aUCqwD|opZu+te*eG!1!Mjv zQ!0!j{wL$fV~gb*RF&;O;?Wy2b0#cixg_Fo!ERq~`{x~VG$|@X1;O^|tLHBsw@XV1 zalv~|)OJqLHq$H7G~x;G)jz!4PE}YA(KGuw(|>7Cj24Am^kjy&&nJf6^eRag;@xsx zT-Yazd+GVOgL*t*$4M()5DW1*jk;K)cSu4)h{mUR1!bRCkYxH`(O;-<@i8xuc2PZ>vjpdqh3MqvNz+eY``eG_X|zUOC_C+^U4@W-QLhx z8f3v6$0HV4h|@noq8YCY0|h*vQJDaHTjd1<4|duGUp?^5RPgFLdlof~s}$pGf(ott zgF@8K=7;11-iJ`8QEdJs8pjp^3qI_?-hqWQzZLJ*>7BZl#vWwvbkM>_g-%+Bh!Z97 zCS$0)H5!Uy6|sT-C}K2TOhX*dxXLT(Nfcv@VK*Kqh$!ghR|vGJ|1qk^s*vlOMNnTHv8r8i2W;<^yMh8`>PXuL?Lhba5sc+RaX-ZA63&K95E zNHa1JxH6%rodu@aeaeLCjb7PUa!eyC36dR=XfPg8)o9038R!6jg{0Swt1MHT|Ba@s zQ+c0t`o`a}S}JqPMzGa{5}VO%Wz+NbM%iny9F^C_jS&^;8U4>T#W>UguvHrd%VVc&}aIbmh-7XdFi(h z9e+#z)@e+D<|HI5aS7WLYcNW4AV%rDHVsi-prRe4>17yXT8)By>M=~5LeQ$lyXo_B z>L8E6J88|+PD0pg`Wx*C=nqk0_rN%9uORAzO!FS4adFX@@wgz2z!-Wl9}sFedqUNU zkN4890e@gaT#wS18DGV;j_6f*VcghI^t#GR<8k@}{WAs>Y!sjVM@TPT6-8Ol@qPkB zh9*P%PFALpWk493JUy@wdSwFai4X5&6Q`Adfwl#Eqz5}zEXKsq;y5tS`}gSrO+?pa zLEjanKkSMVf-sHERi|JN=m~mi)IekRKz~u2;=4ZeUiyqTKx;Iv3wqbYKkkXr4ZG<5 z^z2Q|ZOqYbns)kv2zDJbjp&?X-=ule=^xFFx6V5wpwoC`e&W*vN?7BAgI>jAMrn+s zW3=7dE!gD@ic!Gc7!`Dp>MMI=d=$M2vx7Y+gb29jUJe%eL~1?On4cM7VJ7f15HIfNRRe7y+w{vX<%UMK%!M&8Q3&g zS?8lvs=KCv<})e`{L%Qsz}t-iO_aXFFkiY2(J@OH;w%~~M(LZMzRcLXu@NY-IFd07 z?4?u}j#d839%%A$S|gG-gO|p2Hj-6RDp9mJMo?`=z)DaZ?+~I)K8{8p76sySM#0U4 zh9|lp9OKo~m?s1s9K5tAU}H=>qd4A0vl6GN>jE1x#shZ0c4=?riSa;VqB@GkY>0R; zzAU2{%jS^Bl;~-c;^BET&URITei2?ohX8E$sS3u~bK0jzQ9vRUTTnc~`?17qpj|Tk zInK&d=w##hQ~r3$I-$2??kaO*kJ3!gKN<{KQD@>cEEs!cM69gcD2>7hJPxcMHeHOM zkBRXuQ<)~4h`fva2^g{IHS{5tm-ErxaV#hXhpdLT?Jib&978T6bn2 zMaFSnl>Xm6B1$jegWYT2ZG7lxjW~?paZ%UsMuDb=R~m~U%%Gy3{j&{xZ_+F1d&j)Y zG(&h%3U9_f7`u5^pochL4k`=X^e@V0o<>&&_Q7F4z-dIBK5B!5Bq5eDFCM|J3)t?o zKIoCA14POk#PsNGaYV;o2B&XFyupDj)2O&;XNLjCcwpFeO zg>XzF$TICu*dV>)qQ_`mW&H_)PKTv5h`Zx>5GV`C8>KHqV|c9c7^gKu%b*M1X~r0= zBMMDl>TxO zzD1*W76&w7A3y9suVusF`|&2zGwdobdjmt1m*NQHrGI>g3%hucKN=N{KRe~o6yucf zl_#gftc)|iW#|H7MxuO;#qpM7U~q^J76nmonw|~(1ydbdAYr%ZHAc~xt-Y*9RMs86 zSvUS@e7QsiW-U5oA?URRHZvz7kpa;JmQ8g+noxjN2X>4|Ou*PQ49v^u3kSMIe z)1L=sgiTH#c!N>cx4<%D@TvKYgJb{iOZxx)B-s>y_Z^S$tJzUO{>v%C_{3dQrTs$3 z#~=SdrQiQod~5_An*V?DLdyvieuBj~V>*+aKAFdyZ7TCK&-|lQStgy|dSugPeli7r zVQ0mJljCZJTEr%Q3v;EZj5dRfbf(I(#VHiKI&s0q6-LhgFacvV18!hJwlX)F%KSV& z-y>oPXwdC?wN~4UYR1{gru{JUUQ-z-rI7Pz`s}edm7AQ*No}9LVaxi>Lwh;yzt|EF zZ^K}m1UrZA(Vt>o!n}-WoB~^6ymV0A$DzzH=2Zeu}qGVd^z`DPnhPpWOUOKQg1!>0Wt^I=n& zZ#HZ7IQ?duXo<(Sfw9>_)DR*FFEd9mFJx9fcgb?IXuGXmv96CbxSO}yBug+J+}LV! z*rb;-Z#0#wZMDi>R9FZ9)i&FuH6z}|qCCQUz*OcDt($Ey;zd;}%H*06_p>ND=JTd< zwMNKFgD0*f8Rj#0nI)EWC5fZN8IJ zYsPwqP5-ORk4@zsYVp}X-#yk{w9EMJnZ02}YHe@NTI1oAp6L7ImVl?$7q4(JjmR>i z%#qCM`)DLlU>`lqM?GN)#X}o)Wh$F+H*>bB%(vXx)Rk#9Bd%dl?qqH^m3hRosVmcK zM%>M!Jj#5~R6eV^(m%rz>(osr3KMCB&QzH}X7x>n_DF0xOAAxw+is>M8jo&ly-V1% zRR%R+HH$+}LVW`cj%@3CL%_*l_dN>`q==Gv0m{<1q7OQ<+y3>ygnJ9I4N)8Srfu4+Ag?V(qJxcY6pPD6U_CR+tk!akUW+KvVfy@qJu~Mfrp=z&GwaGBjn{hr z+$uq-!GeC?I4H9Mi4Jkn&1_~?3yN<9HwE3edFJ{QUE?ro6}_>NfzUtC5{id5u7EW{ zjbZ`KWlUh0K_48)c3S$$Zp-9(xCZvh1~%a^({Cypd3)^i-QW~yUrN`Z(0@I~V&E^8 zD9I{OJnY>OHsy1fBTeNV%6Zu#M2Gxfq$|njzn+CVgmFo}n&w*~@Y#~+m36d5rqKw8 za3$#$rjyOgs$1mb+Yafuu}pq|kK$PmQGe{{7l1 zeM0U3*NkvU|3LTtTk|(g=?{`idYtY7(CMST0ZLA32IT?#PNE*T|gX1NC3U$D(FI2K?k~u6S#308JnWnn4JJK?^{i+zPt?RnVEO(hfR6 z6lkCmbb%2-=q5xU5d-sS!x%eo04Hz(8K5t31$}ud=wMhuce#oOplffX5qNw18F+0d1fibPxmc8O0b4bb>A*QU}8dx)4`v0R4z7=to>Z zKjMlDpfhm=orx>xOk6={;))xfM{xx`iYtu(-HIzJK;PmD`W9Evx46;-(80KZ4#pL9 z1+AcCW2FV4zi}l(49q7wA6L-%xPs2dl_<~vdLUQOiL`<)krfHpfE_r16S#m36i^51 zfg5;0184+ZpaLK8g8*m(LC_3BAWRI*XA8!(f(U2>?Vtlhfd)E37Z?GAV+49QS0rEq z=;mBOH|L5Ips#ZUeVr@l>s&!!=Sn?5hvy19JXg@+xq=SQ6)!-a=L-5fSJ3CVf?l-; z<`aEID?xy+&=quruAnP)r3IirbOrsPE9ehhL4W8<2Z#c6imr45;W!}z3D|%gIDiwl zfD9B+2kLB1NpD4-7112^!12G9t+Km|VF2LaFof}k0M zKp3=uRuBPgpdEC8D9}JB5S9@lkbsRCm`^*#IDiwlfD9B+2kL6bT0kp^fHu$$IzSX?pc9CFrumfU34IF@cHjU`-~uvGKpm(DZr}k8pb>b1 z3Vgs10-y;5K{E(}FlYg-AOhMzJLmvWpb-P>vlC+koe+TpY`_j2zzJMH1`4PH^}r20 zpaC=jFHnIG_(1?PfgorGArJ;FpcOzma<*`G)vL{z&SGdZh4r`gQH~;%mZd z`Bzh~s;?Ffrw?m~i-$6YVuwnvWM4_VQhqu2a`I*I<@`&jm(-UExpYp;6%S?(#txQV z%)Xd-vHU{rh2#tR^Reek&t;!WJXd};_iXZ6@!9+{sb|z@3Qwn>)}AgN$Q+0rC_R;Z zD)Cf#e{O$rzqmjDWXg1(0O9fcW2wi~#|qhWR?8OmW%kAPl^)GLns~JQNbZs3BjO|Z zhf@!$4;LOvKcqcWd@%E1?7`9l*#{C2l<&{opS)k+8{1pDFMD6&zVe>jp5z{JPyXK2 zz3RP%-Ra%h?&3X}dt&#Lc4c=Zc9k=^Ofn;8@_I^F^}^lhyS2NEJB8ESA3)rZ-=5m8 zZZB+0Z_~CFw`R7+wwAVJw0COQ7Ss8@RG->c*pS|! zZ78nKtdFfPt;?=UtShh0txc{K*XGxx)~IU=x212>ZY!=9R_AX`-KySNxFvmyc1v+p zW>suesW;o3=q<0zox!~U^rf+-rJJ)iCvGk;$t_7P5trm|O5LR1RJbvHqjqC)ab|IB zap{Ka4T&4di*k#Si^N6w>r>aO*B7o!U#DGHTqrEeFGwv=7Zm2F=WFwe$xJeqEOlqQ z6W!%`xp~QX;=KIa)LeCLVNQCEHm5i{GdniBbZz$9#I@yXa@QoU(TBMwKdSZHcT5ei$nm8?=NF~%nA)bzF@#0irYJN&;iaMomMfwWuisI#& z%VU?9F3Vn)xU4)mH#s?3oSeTjb*Xx3VN!aMHmNuG-#3khkxe3V$`uN!R z(#6?}6Bm~+%3YMaNW3T?OU2Y!VO)BgHm-PK=EB&8rLozuiLvDiau*~o5HHA|pE_SX zzi?jqJng*V7~yl?3qbFPb(Gq(?TPksTdpnHCbs1xsfZdWw5D6N)?!PhCDu|3XTynb zIg|?}Lt-f3oN88^3&C_y3l`~qkoiC=pau&5v|sZVeHmZOS5mWTLM?l9-lSLb<{MLu zYGa`x-JmrTJsD5TQ*vkB33s_ZSD&oc>tb~!C95QqvYeBXvMA?WDVORhIMYteS#)F^ zF-OUswI}RlTh5lWiMG6yl2oZ6rbSIG(%$9OpGKDXsr^6qMeJ(?0qy@I^|JA#>e(Zq ze}Uz+2tQ47A)Tf{#??%+g^4?^2tt@?oOtOoraq`%>0WB#j=o+x`w|uLC*urH|H3MP z_-QJfe`%?lg&8alPWzOSKKQJ10_i%-tQj4xG*uecdMx31cw=j!K~kWrG2tpx`K-3qvYMgxvdJG{K4~iRHWTZ|^bFce zQZ)k}WIM^vDrdpcJ@|tnpVblI1^FvdaR}X93OzkX-6_!}1R*y@mDP9o1 z%ACo(mT6Rv)%?Z$QFpPflBjwNn<2B(5{t(+>c(m|<=dHCO=aGQZT%#lNs2{p&4^F4 zC`XuwO=TX@T15sUR?m=GRWstdEXtReADha2+ga;K?QM69B^KWd#z%V;ea?{a04Fiy zOvJ+1p=Ho3ohfeGypeXqRa#(gwM67|U~IvqZ2Gq{drjrjf4X@OFqo&xZhv*nP3E;uMhomP4Y0S>47Z1cc$E2osa)-|?PS-MqraIgLpu0eV~NDK1GXC4 zC2yk(U1~HwcWi`rteOfnP_4TRuudfn`cRg%fpT;ttvP^?d^ueNWEOl~&W%4|n z(eP?sVdgUbKo41Ybll|-*xEv*$^liMB?g}f{y|bR(03 zKF9PGUFCC}wgluez(2~p81TajF`xKw(f+jM+QR{Qt#hv3CK5yaXc>y zYiPtM7K;C+#-l#?w@UrkQf2adm$8A~AyVEPS7znUQ9rg?0`eK)dyK(QMpy?6i289B zdyK)w{cNRI=DMVd+g;M%QoH|(Hkb6@vt80|>i5r2?f&mv>y*0x;E?|9h*R2l4YkdW zaY_5>`u}tPm)i8dKyCWe?*C)D?td+{{r{fY`yZip|4#b%#e1F7tS0)~`%Y=Yubh&N z+W()W>;A{R=ajxi*Zr@czW?m>?-9jXJR)S;Tkv4F4VYKrYG`^3cRTfE~$q%yWvs~>}i0@8ez%{m#c7v53cmX z-T++H1aAq#TbtqP5WFo6*R;U3t#Dlgu5W`I+F@S@Oh@5H4Q}d$o4eqa5pb)}O>Pt6 zc8Q#+vn6WWVZ*4~?eGo1Q4yjy{K9n93jU2b@f2kvfw_cp>kUU;7h_xj-d ze)vEDKG*~w3c`n*;UgjVXc+Emf!S90SOh-a2A^n$PjvN!XM@k%;R_DWdouQYZYR3w~KVNPYz^ z_wrZKbT1!6+r3;suA51{~QhY@;A_eFaHIa@a1o!4PX9CG~&yD zg;sp|uhEPze+%vS^0(2DFMkIu`SN$slrJAgTfSUGW4`=7wC2lygXVnsZ_%DF{~a3i zC69MYSVB00owHCe?+6c{7-1rmw$+6efdWk{4pB#<^PA4efd-IC|Q!= zKilBH*x^qc@L!$q-(2vgGW>T1{zo1B&wBVXH~hH={#OJ1MI-!gFFc{bvJd{!5C10s zf7Jwk9fZGWhQAHL--SuOHU75+qki8C{}6$HY=eJlhbKE=f0T521r1NcPAGLj+X!e! z^S|ss`#<$p3SGzmkY%I*$O>`*s8dr|k1PP$jWht+gFFDa0f_)|BQgPGFH!+y6}bSi z56J+sAK3tM0OG%AQA%PW@H4&AyZ0#H;j}3xdk}^ax0Po8sH_3aH1DZQpw8Z@LuY}sL6hKSpZ(%1g{9fDa~+d z2*$%O(E_Kn!s!t>qYch%hgWvMtD^8~4bJL>*L1;a#S`Rg3C^*>xpp|u0lS?r>4NiR zxIlpm>)>_u@On2~~AWSvG1hZfRp5l@w5x0o{{0R z3Vf~(K3@-CaKjfp@L&VXHNuy?@MRUg;)93$@NfXW+5}$lZ?(d= zBk-Lzc(fhnJK(!f_?`ye?}Q%+%g7H!_>ly^U?cfrd~C<4FFN3tobVGD{IU$cqQI}# z!DIEX;D%rGz&~q%UvGqe?uFk_;a~XRH~sK01Msh!;9m#fx0>O%L-0Fc_}vzGycHHB z@Oy3WZ`$GCcEG=j!tZPF?>pf?n35U1KR_~r{Ex_HkpBtk4Dt_=&mjK@2@Ud(k@aA;CfZ1u`7u|3->~d;&QRav4bu@-LC)ApZ~29OPdi&q4k*5*_5< zAk#tqEm9ri-#Z1AKV_B%)y^(TcVq64q*3lp7#Revs?DDA%jd?SmdaYzV-{Cg=@9wHf+C&>x0@7TDAZgAv%=21D&+rB?)>M93Y;h>)X5iI6qqM97^;ijcdI6(Ns6T7*0jc@gqCNQ{ur zMP`IN3aJtDXyiu7V~`vnpNH%S`Fx~D$QK|#LLQ3*3Hd@~NXX-mA|c0+BOzaeBnkOq zWJ$>5ktQKeK%Rtr2@)mbiO7_YCz(d^z=H@yoeS5}%a5l=;%p zFDAcO{y6(_?Bn7W(qB-&kpC$8QTfB{hcU`kNPnPykbgf(nF`tWV(%5-O~0$Yo6jdH zQz3gacC`3Tn(`FlZNV$NWCt;o_j6vTItoys~Y7e zqz;RRbB7X#im#+!QD4bZZbJE`>`TXTshpV09ZXPGLgq#7#lj1z7sMBG&nGA=A@iK} zT;bUi= zZY-y>=~%khC-mhuBsP>N&p=yWSeIHSuFI`WtSzm{tkEdPAa$E~TW)n?b?Mg3ts3PR zq;3&!$*oFIhC!xR>n*HIt=zXFwxYN^y z#U<$_D&-XqfCO-9C1!=c7pN}S_ij&imRmvJjURs`%ofM;-f%HUmV*ZjOWej8|#3mHSr^l<~^A{&6V<3Cc zG0GMYW4UpOaV5$X&@L>DO^p@D<}OHFP&z+zzD9Whsq@71a$^!>N~1HQwb6x9sZrvn z+_{N!OXpl`OOz3y`3h=E z71f+K;Vm_08a2uWNHvHJIZwjV=T_Z$$^$6ZWhoP&sH7ED$x|Lc*_Cz0Tt&(PP@Q>4 z(ov=yfSA2#OWRb+07yz@F)PMc`~T#37S3y;_Wy9@_x~{0|8F~kb1N>>$sD7MlT#b0 z3EO%?%vCudwqeW06}`r#rYq>I>?t>?(EGPniOJ8ATF>VgXLZ;vYbg5QsLDCg9hS-S zaQqx8CU2Y~I`wqXCOVaV`_L22!=59(-4cV(1V2ZL291|kv&JOmROac=fu*Xob=+YI z$Y;Pf2bN-!U&FlBR6eV7q<7W~g|m`^u!nhvsr>oQk=|7^<~|nZAoF=s`E#5j-DwHP zHy}SpiZqr{EENAsjYoa(Znr^X)NvF_Bo}b4?e5xJMOVeo`>W64ou!y zb*HYz&$92>ZHd8W!q|6ssY?(+Si+1lM>4C`4Woa3w66?vY52XCP&~9zE5@=3Pi0(}ow&u5Nj8aY8|IX-2m?uzA*u^sJo65Fza<dI3!L+xjiKg@jDROZ{xT37gYLyi8^4%7_zHVg7G z^8-^E0r5l1nz&Fadra?t+7gRzwoY~wA_|Yvhz6!?D)ZeKe|6=N_b5O+&Xrr}JWAzy zf1&@GDp8Ee5fUDw3Cv-RVvc22jl#a|dW55771hFH!sdMRX5<0$u;#P5(ZnzW+CbC@GBzL|G?=kX_4P0{f^rH@1tw~{nK31Yt;Y$M3wFl z7>F?Ck3hf-}e>M3ex8Ym;Uk^Ho|#gE}a_<*3pBl5j25T&;fAYYMUK6 zfdV|h2ZEp#v;z%@QNjkCKmiRP074)F+JOc}0DGK}fd}|OD-gN~2XFxe)B_Ljf&d7C zHlP7pAK?OS-~~+}1R|gVNIGE$3TOm=&*`YQP2sbV}t`J zpdK^;9|(e05Cx7;2?aEO0B8YGAe|s&;09h00AbJuIsvT?dL3{B6$C&Cw1N(x0sA{xypcQlgv72xJ4^Tk}M1i!7P=E@8pcQC9>?7>J z1?oTp@PQx*g9s3GLI(A~0~&z}0w4%NpcS+O4M+zG2dD#H&in4}?J{kd6~} z-~w*o17RS1igBO;s2~C~U^_v$Ks{&#Drf>>&;{(?B(^2t1}bO*VIYqq+&~3QAPm|; z7qE2`GVlNu_(2eaK|AOIQXk;}NF%Y;gGS&3L4eE;8`3;%8bHp54G9`HjKCqupxbbJ}?B50qC6z)C`OnO=X5Tt_=XXmt zu9Phi%=evAM^uMFERb!G(Eapi6R zwprN;!00N&!b+VP0ajBP=296JQo2S6uzkv~YRWKS%CJ|;FiXm?JIXLJ()B=q4Utj^ z!y(lV0p>xf9|DYk)Ugp@*rO|g0P`JnYy?>3sAD6*)F#8CMjaagmNB{n2rzt6??!+z zONQl2hM7u+HA;rjNrq`jh8>AIJAwlEfL0(3#0Zqa4#+wnjS-xH2he~Z5CLL9C!hn; z1i=BgffhgoG@uoT0PR30Ap0++UjQz^4R`?!Xa&MR4Cn-;-b;}}Cw<6XKm&q68_*7P z09`;gAoUUKfD=#v4-f)uLj)(_2U>v;&;v+0f)9uRYTp|Cj1U2$K*#7+RQ}@xJK!Nu z3N^?fAPRH>vapV_3n)Mb;OZsx^beA%L4pl%04~4{v;aQ94+MZ95C+T-;{8kLyGUgCLW*>P5E)xW@eQq_ zqyd_r9(ZE?c>V$6fILL70d~Lv#DI1n*he+n?x(7hdkId!1GE9^B-LEJkBY>Na`6Ff zffDHfS^ytF8?aN}0F6K?3=fhV0onk^C<}EOA1>n~F^mVdwjTPB*Qh##h4lV){y#>4R=(1UujWoPY~Z05{+PS^zKL1605dXbeM3 zs1fA|GGGJjfCF#=K_E6v=$;_hCkYA=1Oz`-OcaO%9Y8101tb6+=mvTKv5z1DGGGJj zfCF#>EeGV^_>FQ&1-KL-%h_R zzFi{Ax%O81&Fq`{n-#L1C*P%%~sJ&i%J^i})dg-+c+0VVt>GxI0x}LnZdQah=)IGJki+88*o@lbRKff=zuX;y;tn9VD#l7jhB3arqw`;eT zZ_D1MldU~}Yx35yTe7$4w^VMmtCi?t6VjBm3CE`?D6`Ql`HaBB(JDmUbsAUdF`^|Wofd?m)2(1YHQ1D zvSgR9T$;Z$d1>{M0$Jv3>0&ya7SpBvzN1{{FD@@F%PiBDmB~u4FRfgZzbJW8mF)Bh zveW06B$red7Z#_;QeV6veSvsE>HG}Y>dUEYN>5eDTA%Ezo>w?8bzbe<;<@Q_#dAyN zWXNV;K0AB1es<-oJX!6lXBN&(ompE{B)h%1sI)M%P+M3g%e{U^WkG&HazT}B_o>rs zrxj02pC*#^K69#eYI%NkzCOQ_%qNq{YHxvT__b4tr=(92PbrZVUpu*cQuZYMqzc*b zlk=)47EVl^SUaJ3Liz;p8?N~m$*!O2(z?o>*-o7-`}vM!M>SrEr^vQnY)`j~?WI_T zto!9?HmXM}WZ_S?RU?H+DpCs57jja6HpdPHW=3A3w=Pv|Oftps-(q!o` z`7?gaUskhZ>#z9ozND|}Es(Xp)>3Rqw}@o%&v-OX*`0OkWb@A}Nu}y4xKd>GFFMms z(OGh2$nIaZXYIPZV#|}|zbY5xlw6aFWcwGTl9&-Su`Fci4L`Cz^T!dg|KIjK-ps>$QbJPE-MHyGl3lwUWGX)ni8ZuWln*x2Usm8TT%Vx&) zCYfuTO@Y2{(a4L47wGd8aGwCqWlS=1jr{ETXRhu#zurP;aGig^qK>QQ9T^m@WGa?2 z8ZuWmn<9Oqsm9BhmMx4MO)}Rwiy}SvW>by3nU;GP_nBnw&R#yUOmj!!&i*ZnLLLLJ z!xt!EivZ4LJejdkXKgIZrz+gAbKCU258k%u;<}9rT*zWx#<;{J^WvOM1-{c%;~J)A zGvj)b%r(xU0uQ}w(P%Bt7b)OA0i4U2WaJw8+4WD;HGu-1;hK2QqK>QQ*8~);WGa?2 z8ZuWmn<9O`sm9BhmMx4MO)}Rwiy}SvK~s&pnU;GP_nG8xa7~O_6!Kc(*ThQ{uvGx( zGWIg^Eb_DKpJbS3`qARO23|N!lmX3@thgx6q^0)8lfa~bC|@*MKB>z}5}kk#M} zcc<@K^l|;X4xwp~>A0HFkh#92ufq{O58&YUnrhs~v^>uEuu0|`8`j~!o$QeAIhpM4 zKBx4Wmu&neIi<0APU(`rcSu#T|L;7}DgBCU|BsUGznwncI^HRrMZW*PB-{TL}chdg=`Trm3c1kDH|8m74 zU72@Cza+o^w@uKV0r3AnEC}!XaN%#ak^TQNv;Dtssqks~N>)3;{(fOe*16dCicj(_ z73oiiQIM(w_CbON2mn!_1Ly`KLxdPZj-)uy1#|=Q2*EK<=$JqlV4EbkfEFMONd7dP z2e^9)D$oYB1GXUo*6ylUsH@t>$x?S@Y6FQ&=m!86hpAWzMyViR`Id?mTdHe<-~)nW zm{G$(>o_3Ebvq(-rKy*0=^zErTI1Rr80*h+_LZ2V%x zMvx{63Xt$qj^$p06Yv4mA_h8# z2<{v~oFK^Kmr(%%fr-oMTfj|T^;GW|AqqIh2`xicQv86!e-)h!bO9m%NPZT3A%t4{#5HJly z#S9Qt_ET%Zybl#qK2*&1P%#}t#dHi+>?dG4hKg0lDy-Hj49F@B$SMrTq@4hZu?mZ^ z3X8D{i?Ireu?mZ^3X8D{i?Ireu?mZ^3X3sSF98-~6&7O^7Go6_V-*%-6~OP|lx#&Rc z99@aB?eWFfk99h%7n(FqmFXZT#o(8WL+kMZe7Ty&sf zu8b-Ut`nT|>cNhQLAr?gGgKTS^)BKyAOF%R)VqkOAj}|frhO8N6EjKFaQ`wSB3+L# zo?9+B_tq~lCs`()`<#o}*?vm0t9}-ypQx}xD#x(z+{k?Z*)!Tmz>jl{tSV^7UO)pd zX{DY^OkJVgk6Qmj^?2>Q6yP}{;JC*=*}=ff2D{(8>6bU=MQ{VdJCjFCtUk4`p96jP#9Oo>u4B}&DV zD76#7lqgliwT0e_DP6X@PL+zx zuK4(s5Trw=ahYOzp%>E&y)dOCk(vO;vdy=Y{u$Ngp<}g!tjua+3=-Lv)c_S3 zJqQp2gBRfmf#4+HwyHEj=o%%o3(HWm1ji8d_>sPKf_=z0RFAZs4yijOi2VdRpa5P# z142NQz|uGM(>THf>OoW)umeuO3#dQ{hyYO*Hbxg-oMu_jLkPi+4#x$!ffgnS)c^R< z3AF+tAOggIu3^F)Kw@1KmDf~yY}11rGX$}Y?1&#K(}O(IgS^v&0@H&M(}TLF2Prha z#8R4`=|QovX=k-h4~q60tbFFc1aefDVYg1RLN4S^yOY z0AU~s#DPxs6kyz#x=60K=5QZ1t%rQa)SnJwbf|U$LO;O{F2YLGlOHFA86zzNnRp<#bsrm&P(<+F1Gf+3)M$uaFmlrfCojiFWsD8Wf?IL+0NPb%Vr0_}VliJ5c@p9j{?O)x*!%x!x{1^P<}l7 zxc+$Mu{?Pds6JYFwD8E_!`j1T@+P1^n0a9M{;~Te?@ip>e^2i2(Yq${{(L!?&FQ%c z`3*?kS>0FIm)cjmqj*R94)KoC-VAvUDBqsFUBA6@Tb}#}RBtWZn!2@iOOZSXh_{q( zo;WRj%?{~9>7B*;ECz9VXrz)`uPk0sx;%4v;j+QC zy=$tM7V5hSV5UL3KeJj}jhzHCtFkNgmFX4YisbStt^BVpEi6qftzA^4mH*;Jr3*7( zWA}jkdCBvt=N8UQom)Gncux8pk^BH;&eqN@pOrnUOkMyc$OAxXVeO0}t^co_K62X7 zsrspv`T6;UWGY$fEl%4Xpf;~KFFjA3m!>uUr4uqIXeX49&mONIUzwYqo19xcE=jBY z3&*C8tsPT5CVh-}Oma@Or_ht?$#(1A6+KU@{_}}sqS{sHO3}LiVrRNj>@0O;Xyt!7 zo{j7AN_(Ex{#Ot036Q0=|CLBSl8jWt1zP=I3l&4@P$t;hDg;Wj=3mpw{;Xg3S7_CL zQmy(5zLc-#Eqc>l(OYWC(AxhATKAuF*Oa1?RzzC)pK)ofvNP+{Y3+aBk#tn;1$&BC z{}*j(n`kS^8Cw5ema>vARm41b01$+~edNF9M(O?kKJ)v3ZjJDdldIVKzdpL0`c`@v zD^PDjuW(X;MgZio<$~q}S^y1*0C6VyR|r}=5S%1G96%Yq}y#yU_^dk&N0OAlKJW7CPFb(dfG`N@24ClC?CYU2p+6K03?wnFZ?(`GFajJTd)WJ&R1a}e zNShPE1>bz%TePXee7e&pzBhdIxQU*gorw5Yj2=3(H$hc^CtY@z?V+kLhG863)~$uZ zhcZ2!(KD+=5zY6xDVSa>>7P#3MvuEvfc@1!D6N>8n6%N|Mv0O7z4VV_t$&TY#QIht zx)@8}R0Q-*#{_#g#y5LOO^j6Zu(Nc$Tp3ZABI?4M3L+{{%IIx^(v@!XGo;b4oBSFoy3+M(!sv*tSPtbr65CuAcZooD~Z~@k0bZ>%xO>vN0eEfF z;G9W=$0ZFulQdxjhhu~g&<3;vU4V0f-~qgV9|!=x{o{CyNlT!N&K`f^GY*1B}qDIp%}l#wM; z8I`4zeTii>h`{LOBh(|gS@%lgIjn6tsTYbUfL&NEM4W&d@Bytr1aOR!Ekgym#tHUG z0vwLf{B{ETfJN*hIHZBhNEGOzcU$VJY0!o4Nykt*)^7`xj~@D}LrxGpfDgcm9nVsX z(j3mNor0oRzcZBqEad6Hsvyr0mB3Us>A}-<7FP9m%|(P2K2wokEs-|$TdXPyA1)$k zoPLWtoiVI~bwDUwqXMuXs2wYSJh=C~VpK{m9kL%BJ`GEws1K$4@_tHV>~P#z0;o>i zbFsWpoqu@H7YiMy5{U(d>Qr09IzqoGDy%y6o7y54NUAUUreecl$*EjnX`(h28`dWV zOuxq3B@Z=YQ{iJJQ?#2fl_c9F6+Tuoc@EG``XP4bHQH4xo#%X+ZvBTZCF79=J~U&_ zp-Y5Ve2jnt{(L>ZV%t!uN))e~EJ4CwZ3l^Y`(bZs_y_b^1hLh3R@D8VKaE)Nc0~fuc z8=WVTBM+?+!YzQE;58CX;XVZU5!BB5Eedk`mm>n5by-7)yB`k)M;rp#bPgC#Zgi@M zVS#z13B44ayeM7@?&@75IOk)8m`ZJbz2vM9V|bJ_{^%Dm`bCSk-HR69@CWSa^YBmN z^b@rBqyI&KN{%u{y&e6AhO~VL=#xF$8l}g&F^NucQ=?=VuaD8SP?6Gz^UD;7r(HGz z%M*{njo|zJ^sr3TF;(Oem1>&@uo2Y5MeaqAilD}UFCrB5m!=RYpeev9Hq#ZvKu!u#cSEAM1zAI0K<5_u%l zU(3E)c%?d0d%5^>`epIu{EHYXz+Q;?{rP7Lv_7Kvt>RNf@-J8^REKMimmkYMmU=Y( zi1>*9aPpxvz4zzu&)!$KH*=465B4i8k-tEVz4@2-W%ud(DtF}XNZwK1TiBc0Tf4nT z{sP6@OSffi({3x1$3Xp7@fQ8&4sogbtyBBwrvYD)wEf3-CzOpmFGr1GH5LW5U zzHohYOJPfDOYOSib!qYjSlXP~tZgoD%5Ks(RW{~lT#ex0P$mz7{QbW=SQspmhd_N` z^qR~y+BIeJ4ya#US(jgzTvsLkfT^o$R~D~KUn!D@z|0le73Isbm+O~TF3Vq*ysWym zKz;&iYl>^qYecs5VE&RM`3WqfQ|VfNu|G|o0!yngQc%7)d$E3TWmSGva#eL@fxHFQ zRuorY)S$FHvs_zVUY1>^lh45X(&WD&Mwv$S1!nt z=fLXuh4WMA*HXn)Iwht`eVIOuya#5_)6c7%n?E;sZuOkPIjM7MXBWwbpm=uatjt*& zjUHsr)X%Ie$}dVTsvaIiNS`6nNJ3_TwxE1^_H>ln4 zWjvLU=a8RW|ID@I*m9M_RXD>Wr5{-o@&p)_*w3QRFkWMlxx(30;*XnZypw4eW_-jX zbB(j9#NTMD@mZ$j4aS#E@~kWI;BPk7_Yu?a1IF)}zv9lLk!+}7xJap)%&rAHR(Il}7{a5Lj7#fyLQgFmg{#c3V8yIVqMRo-@~}mBo7FigkAK{TC8=SwM%yGT6N=f4Kw+> z7M(oVM$3r{2PohL#(9hj7#n5MWBAFXro%GXzz^B~vgqV#F!H&!t^t~_HpzUyKx;nh z`(mBHXER?Phdk787~@S?>B^7mItYGpVdJRe3*C z^Bm(-CYjfwjF_hWXblV72kt9s@%Jn`c?76M>~{AC1(@k!A>XVPf8U~$r@^R2vo=F^ z)^)BI_6VD2Xsr>dvjM8b&70W8(O}2BpB{x)uPMKV%uCl=q264(&@K#6>F(UMYSWE3 zX0F@R;7Z9I`ri#Sa}TZ7GB$F}Yr^uGn>uDKHFxk2EYWjy+(Rp(x0^C%$h@UmFAD5` zH+=`ZKeXuJi7+nqv+3DTpq+5Rm5i4%8n=l}{AB(~O8_+*dFIzTzxY@Y*RQ@mvgqUb zjV5vxi~VXw9;x}$nkONLovP_66ek%P4*ju31OGkmzTT#QM+9&l{b^HGn_2X?Fm5-=yiHge`%(2?f7VoGj;VQw@g9@R zudnI77xVi^*Vn~+wzKyKR8YO{er8dHukgn^t#?Tlg(5_q3ArOZ(5 zWGWlgoilfIeb!$bg;uXAqlV1O)LM;R<3YmQXBj0sN@L|HzucjT1`2ssWzD9MS^Rc} zznmca>eubkBeVx#c!yJZ^&F?Pko^Ds=xnES73~A~i?f{4y(c=P5cvQsEq6$l{Fhz& zqqm&W`mIjsAD7a+efsZQ=#*ag%puLa$SHk%p;Njb?38|Yty8*&)&Tq?&HcY4=#;!R zr}R9{|39Aof17;&EtQt0)S)sq77zUqaR{Xy$J9FD*KFI(R4a9tG?WzQZ_D-;z0UQv>1PUo};gVbO16 z++vb>0a_bxGiRB?p})51G8ZHsW8S9#GZhxXv&GM@f7V^%V*H|ULH>7qzzi6P9U!PX3MxHJC^*bk&JCGun+CQSALNZ46;!`H{DVayzQP~(EdK$?ai)p|H%D&j>-v5D9~(r^@9QP{ zg(ytX!(?7fQ_(RgcXUnT|5$YLH1O+qN}HkCd4x`D(>S{8SU5O&6j}{UM{3q2v`Ea^m=bjzAr;WSi4*jZuGTt{@3)LvvBUDTs!o z_l=0&sHY?A?Cb2HbI78DC&K6(Md5P_Fw@CG8nr|xv)|SGMt&W$KBnFzXpo=%#p`;w zdfp77&Tdj_$c>w!SMUl0i#Of4n=3=SbzS07=rXcnWYCbmS@V;QLZ`!&KSQ2X^Aiq{ zuT%EN3)487vb}zn0$vlqxr`?>Hm*AqCab#{wm-62baCBA#jRj5U(I-hNk(CQ?d^|* zpV7MiEcyMn{kcOLUgebL{EkEVgna*}S30DB`fs~*@1Hs(ZG}^Mak*1Ek=FkI!( z^ds6&-~y-gKj%B77s>zsaqFGZC-m;Wtn85feAFRrOE@JL?ExU<1mVAK-Ow7R_y6b1 zMk(X{zh~&5*+IR%*_#&8ZLC-xX1w1d^CGg|iI2uo>}aa-Nv7o$#^+2jzb#rjyRY_U zL7SPgzeWuXz7Y=y;9SODMxI0Cw}(j&QmUYGWB&|I&SlZYwHr-t6^r{?#;Z&+*Ea3Z zFxN_xXb0#;IoV*mT{x&T)wq{wd6e-%lgu^FrUu8`*tk=+*{#Kf1cPcGtA$M&V#gmWj`#LW;?G_z85&Q+`2NWO*Q*<)9QA;$v;0)c$-#H}2S$_zO zThwv&yct4~-K5Tt8#lvdFE|}Xq07jQkwHWLX3ekjD0DhZ`7`8MH9z4{mqi)M8Gro7 z^Fxw9pyw6bc)%1RGKiNB%O6cHWm9Qz=ecoHqs^fc7L_~+M*VGI3br#|Z<4u6>jO*E z0e`)zsy!_F`x*C|WT=|?&T|wKg}R%ne4MFyn(;}K%spvaUlq76z5gzuc>sU?Ck`n~;{f(A9n#bP>5%3xb4b7cA9iW; zAJJF=+5Y#@{}vhxc%H@pPN4sv(ip%B+5_;9$p_#T8VC3f*(u#e_WvOLe~s+_r_ui} zXbhmA{{JQU|Jw!oKaB%?cv>*mLGS z1?*v5z<4&Jaeo}*C-YC5`B|TZJ+yw;4Kvl(DHe5Hy-{CFSmbLNFEPoyeN4YQ8arDw znT6fkRN+89H^}8SlWY{`tY={-ElPR$7+1lu!f#T*CdLJfXEPdwI{mTZaG}yvm&3DN z%#V!oE$X;>UZ_yFmZ`Xe(U8AEp`O}Q;WbRj2F8p@MxkyI64PwRa?T~VXlnZw>twsr zENYG{Mn(873OIu?%Gkxo^Tp4uf7aV3I+IflB8&WV#`z|htDD|7 z*)&2LF66q9kor}(z@mz$)o37X!j}}VnQ<=TNsLAVxsjjDKgr01aZt)wgQX8=ShR8N zM#dJfxG!Y9z$7=$*jHY33!5tJXG%6QUSpEK;YGK|qLdepQKk!o-==`O882j9!T8l> zI#q$@Ywk>oHm=<$(={yajf@$S{0++VtfmTgFeQ1$+f6bQ?jc8R)r%Xo=No>gh4nyMOL(PtUAndEO$ zng`Ess`3e@rpWl5N#;F_^*yxyoOuB)uG(}<{W+7iDxtj_?#t!U3sqv^7XEgE?WjQU&6;=hvdGLy_Tex19~!6i*qWmxpv7`K>Y zsG4aUq4{*#3oW{M(cm(`blD08n5nQ3o-Ka%*D1)0EE;(VjDj@lGGylw8m$F+bkpo| zhn6 z>YQ9*IEjK&7Q>}Zkd`#5I$$T)E~*<4C&|sU2KW=?)+W?P=m5lif+t6C3=@1n2=Gr3 z;(%?E;OHgq$kBd+dyo(Zx}D z-_Ft?!3BhXcA$m)tdR2*!`X|EyvV3F@_DBwhDfQLBeX(&I}iuNQGx>q192cUPUrwS z0eOPp0^H-P1jX<+6edwk^pfkDz1%0!5INQ1uC1jUogRRKC=dgB0Q)E*1hfOeaY#TM zkR}LDz}Cmy1J=FR(1Gd(B=Q=ls(?cv$M+tf1!!ZEpCm^wz5pUX4 z=m0taZ4_ZZ2ha(~V*~|I0YBg!C)g$t2H4PS6u<|x1085U-9T4A!8S;610KK+gn>BF z0eEwSRv-w(fCM0*8r#MRc0ZN68}I;ez}|~6zyoxQQ*-SETF`JKKnI`$l0dD}lOWjp z2nwJAjvPTi6BYr_1R)G`17a^K2XOQeJb(%Wfj~b&9wbBnVTj%z%xi_0ir+*P=*L@AOf@jVvZmIEr1sY0}((No|amXf~d?0Di8)DfG|oB zffm3E#DI3dGfrp$qCgCgCkQsc1GE4kAPjT?f)#1i=Bc0zsf1hy!vT!A7v8){Af-5CPf%TR*`L_yG;*0un&W5Wx$y0zsey=mcCj zf&zqr2w)!}IDj@F3fRXG2KWIDXb0kedz|1QSW+8Ccm%Lb5bQtzXa!3}XyLK~p=69PaOhyh)I zFhsBe3g80*Km>>Zoq!IwCkZ|v0EB^dpbHTFNIBpJd_XG@24X-5Lmx>xAomlTK%$pC z3>%Lo-L#Pc<$b8WQHwl8yD78+T|iroAP>=|6GoXiNu(xIJwa4p%!HLP!!NSq(O?`C>@1FRRiD#aOz0-y!4&ScS_$j{MJ=I&Closzw}|| zL+!(IDO)OzRzApoko=(fe&PMp`?dFq@1@@p-z&YFc~^V4{7&{A{hi9&;@hRSGH+>b zmEX+1slQoyBmYL_K>k4TK=t*)>&4e!E$YR}NPZ+aQhmAb za_Z&UOU0McFNrUeUd+6xy;y!B`-1*L<@x;c$>*!j6`o5ySKD9QpWZL-Pd=M@Mti3G zboOce>B_gNPZgd@J(Ye^d@}un_(YPt<`srh5ed2wkdo%ZH_m=O;-lN}B zxjTP1{OlF(8m#--o2`fa+)c@ws(T81QhR3duwTjMv&n3As4$cos_iW9Oz#wTmUd)z zXgkW=v)lFUm2D$8q;C*!fVX|^`tsK7R()$_OMXjoOZB?Kb*bxWn~R&%o5jtgO_@#F zrt-$@Mtx&tLw-YYLv?*&eQJFzGd7qV)CVgA`GMp>_1eOU;fh7nXCO* zm)B+2>FX+2<*!O!RlTxsW$Mb>6~!ykSBT70zjpb=G>?2*-D`g(olhsz)&4?%s=v0n zxH`RBTwS^t9{kIzva9q}m6iFG$(6!4^v9RztDM)&i@$zW<;?t<$up~q3X4*UY72`C z(+kCgr86>TXlIlcWEbe<*FS%H^7QIyh0{`})lMy*nm$!LwKP97Uz=Y}W|Mld(wpy1 z_Et|RoRT`Fc5?CL^vUAMrIRuzX(yHEW#{ShDktVoOrBUhp>RU#gxc}NJJ>q3`jxYT zbB8XrDC9-Lm&*Mf1sJ1E{F^49xvB5!L$|9NM9)VYe@ed)g(-TN%!ibwqGM97*)SHJ zQ6I+Yx9H?);A4(c+6>LkBXpXFu_#WmTr!^>WT|PkL|-_VJ_@adrX#h^dTH+^4HWW0 zPHQ#|wU#2~hdC}B9^|~#5q7sltbulIIwoFv)z*p0(rns>MXPLswYz z@me^I38L`7=`+qW@o$=Z=BB=@_ZwF>h@Q8MKcruLE`akGPiJh@Z@7)sLuB$n(-_z` zQ{%YGqLHV-XdD?9{|$^=O!BN6$GWDf_OR&hWxUHIe}l$xbyJ0pG9@oCK4p?;+c<=S z*EH4lCe!h4#t%(0zl+(XS_34yuD{Yj#kCfNJO*7r%NB({BhFz|7<(9DksP9bmOtj= zjhwt)(BD6Baq5ywR$o4_?BbQnE?#o!z~Utr(&u9Qpx#gi8fXp+Qcj@tvOl9!7YTn( zoXg~s7>zD$1BD*(mpeR}q`_pPL5nu7-Dso>Sls00m?AyLB=gInK@WyW2-Ds8WSXj4 z%A&uRaivNA+S82ITh#FK;N|xh6mXs}L7XcQeHf~II9$Jrtp`PfI@m6oldCt0;*)dfp0nV|>S+CZaGWeMTur0X2vuZRolGD3_hYc?Hi>Z&$B z16^;?#r66K&3@9a>`q1)+ZVEL0{eMIhj_(*16J-D2{9_}HjJ;O~!e0(B(M6-FZ0vj=ZOdT{aeFbq>I2#_`1&&6 zcL$bUb%I7<1CxX>5M@%1#wpu?ZZbnUjS)=WB<MoCI}i3=_j-U2|yeoH~=@G05`g5VlsfTKE|>`1KVCd zjZ$m0l`$2(?lblW@4(K+I$+24#wrj20z=pcmo{#}xyC4TaC%U9dXSi#_CxRFv>YN@VO-?(@Ha*BOJxCg&(R^bY?R<0C#Zl1%R_9CcKY@9 zQfu%5@o_2`!~7uN@)3IJL_6RcM8N& z-~d{IARvtsWFP>v0$qSOLGS`TAO^Gp4uR~iPQaHSs6ZHq0G&V=;OZkNKmce3I)N_0 z(@$stqCgCA3=y1w3iyFA5COy-K>}334|D;-2o3=a=m0ta*BC(oLO>Xh#|bvTJ3;UP zAs`HN0G)tsl3)jXfC|KbcEFZ^r56YQt?aOuBnRLFLO>W0`v?-C0)C(iNU*R$gaL7& z18@!zTtE;A0i8KQ7vLNwxBwrZ0x_T+aE=pPKm=$59Fqhm&vq196}Oa19a^AOf@jT|fe`4H4{s4^V+NAPR^%f&};g z6^H{JfE&G=ijK_>Xg~mH1%f~bhyYR_!3H=07vKiGfFEcDf`f$E=rxoego53{(nI1Aupg&;hu|2#E>0XmewB&ka#x z?FFCYT+9yJ=}_$e5`f%G2m)as3UmP8eu4@FfH0s8Q7SyWYgv5t2a;Agq+bx+xO=n# zt|3Ag=mI>rU4(!xz&ngXpbPMf5~6^6oX`eH6F3BdfJdOtIsn80JNo@rpd0WH61o68 zI{E<62{*o-slcaE?O)6m-2opbKabs24(%(E9(E>WR+^pQS#l zeOml9{i*nA>66SS+9&0YvmfgpS3b&rl>DgrVd2BnhqY3%lrD*-(r9K>8!dm3{XqYq z@_zpP$GED^;PZF@+;X_^jFfw=5qxmpDR9>eolO@v_G?7+h2Y*`>g(K<(d35 z$!Drh7oJW%UHew?Tj_6!-zq(oc}jb#{ABh?{mIG``6rT3R11Yds!$s)4yT93;nL%o z$2GR|p8itKLz# zBXvh@Z*gyWuei5#d**iS_VR7n+w|Kix8`q6-deq-a7*fz+ReqA(>IGZmu|}3q}^2B zlij25sqD`0PVTPWShz8DV{KP)S9;e>d-_#(6n3O`)V3G5r?-pSOWQKrv~A@ZvNz~A zRIblopS-@hwXij{wYH_WCA~%5Qo1g4opxP$b9S@7xw0w0DY>b-v9K|5eQD*Q{6)!&suvb6OkG%8Qe2W=A}%Q{&MejzmoLa(pkGiqKYxDm z{A#L@N~LOj#lCc(*jG9)bDnly`P}Te`ni>J^5-Pash(XpJ9T#Ltm0Yevx;Y?&lJxr zEy^s?7L^xf7wQWuXXMXFo>5&;Sddy!IDPQ6-cyD7`ZrxomxjZo{j7Abi3GIie+M2 ztQ^fo^=P^+5vhdp;YuhUss!`FWU$&=Xic@&0>wZ&AO=cWM$@#iKkL{16*aFW)hcaQ zn)21W<~aamPu8P*D(<{H>8>gTC8g9{MOWG-x=PNBQ*)LbSx4SpvE^+^TU9Q|DY+&U zrHYsrlcFHhZrT5-PVfJ}fo1mmum4h^tK83y9Q|owNzRSA_p%$nM%OZShL*7lxQt!E z$-Yg+aJ*h5>! zuG2C$(w4FHv>XDkr8cDy+fd8cSzB%g;sEy8ma!|foB+Ck9zdiCV6p^Y^KIDA#WpX>v0dxYGX(sCcrkha;u{pYI0~`RhNtZo9 z3xJ)PWj}zq+j0m90}%kr9^`f)4kQ2_=mzEh!WcmWu!Fd41MC3y5|>?o0=NN84VS%u z4^Rn|LM*9}13)W)#T9ZJ5CyQMyBr5PfKC8QFJv9)2IO&q4X^`Fzy-Jg58wq)XB3|wwPzt*s_Wg52?3Si%Q z8T;1DZ2&f}m$7-hj4AnY0?+|0Uy+4A0(P~R?SKnV08HJNTL3SBg)Ool2m&FX4Tu5l zKnKtXV8*|!6DWnfxI&;=xbZa}2Tm2}M$Y=8s6PSbSF6Wl-xfl}y&>;o`KQw{*F0H$loVE}VB=}ISb z0G$A)aLPJ>d7QGGBiH~3-~?QN8}I-vfDcdsKcE3v7a<3M5D*5iOhS$lD1|Y|oj@0m z0J;GzqmU&)2JCy8JT0_F zjBYXn=QtrGte^@3f__3L&_+Z1)TI*I0Uc-)R#Kbv6XN3p+wjGtipCw~Rv?gAO{eq` zbikV=wQG@~hae`xlknmHVEcFuN zfY?v)0Bs|L9>6(D(0~pgh})AePDlXGNrKo%m97EyK|&kD5J^Ig&<;3<2`Uf;big@6 zu=V18)MBR(y2!~!lJj=^NtO{Hv6A(9QK)Tz3nd#yp$dLN2c+V?PiBx&hY+AwIsCiaFdx9~2{D4q%@o1c4aP1?YfHSVBJp zyg&d50c}7W=mdHIo1dTnUce6ofG`jRIshFI`w2F{4YUA$AP7W&4xkIr0bz)s04;zI zz<)?1pQJw#KPi2j`B?k7{89EJ{iDi<`45vHR!fCas#F^-j;2S&(b5N*53~=;?`PlF z->MvGa$iINy>A}o{+Jof>vJdDF zRPN8;pS-_%U*W#geYJaw_onX^?=9VvxktOFe0TP4{qD+L`MZ*LRr7^>DqqVLbLpIz zE8Us7Q@gXgFS}3QH+o0r4(*Qe-t1m|Z{_y}C38m9_b`$+gur zg*B-)wM&barY{vQEnSkiM7yM%&ZdQQsXx=N^_N#?SL>@Q7w0cdUR+&OSe05;TUlJ0 zUMa3Dt;npnR(j0@`>3K^%E;6 z>Pbgr6=E$?5TDa zx>MaXy{M;kQ7948kMPJ${`byr6SM!!z zvMqW`#gq3WJymzXop4u_ypmL^u7WG&syU0!v{Q7J92tk^DBH7kecF3}S`wv_m=QIx zEM(~ofAJSv&+n%B|6kPK|C#^4k$>hR0qip;<=lc>7`T|v4n-)N7?C?PWSJPjf7s0? zafre{QGl1xWs;3KIve@P{4?he@Q-GrZrn43!1`3eYy&06oY#c{mMh%AcoE}D#)e9A zDw&iFC473HdG5+Ci#D#^n7eW%i+d~MW|NHBIhdhLV=Csq+*i*~K6Il+A^*LRy+y+R zP{3V`OBh!$8rj>xPv)OFXRf~A#Rl4YfX!nuXKuGe7uRiMZViih6Jy3CH=5-%wV6Y* z;r#18O*QUhT5^ngO)}TW($4cnQ(mVu&Tpjg&`lPN{O7zpe?X|l;<{nGXKmu_~l3Y6V7z`-Dc6owHqb6jKzH^W4}q} z`LmX2v-L}dZnvo7X*4o+rf`S?zF@qNaTTMHu^s$m{z;oSV^bySS9Z+UQubPuapgw7 zu4hr-&Umv)Zj`U1X(@L!)wrK&d5iIYN#+`@EroYvjUBTc+}BiLi76Rl{I*G+^=$e> zcUtuEsxa#B1k7(2h8Y(zp2ygz{+zkGmr%ITo~dQh_w0{v6T{UTHAwz)NZl63O(vO_ z=htbO2lGu;4YBBNX54L(zrIt~yPE2`lg0fQ<9#N1_BD35McB%%f`Q{Bb9{Gs;a04wy@wJgZFG0AN z@dUMsJ1 zT6FTVG;%ptXro-d$+(d5JVv7=r#~sX*zzgLWaAA_AG0Xr2{1C5VbSkkyul8*iLx&z|9?I-g{E4lurIlA&|v zJ$sC5+_k}YI-fD0hYA**=4ynu#TZqinJyOc4XW`8i$b0NqZ-Ys4B5^U8m>TZ#BJUD zm$T>Egf?S)#(Ms&`{4Z}Z%E_@STuT zx`@^Q{K-!p($0?^lK58+>2dP=-$DONUpS=mx}DPRkl+6d`Tm=vx&L=fkRQQ*n*Tp8 z3akI}+0T2({%?cVYW~-^R%q?+XGdKL*lL*Qe-xHVMF)Bau7c1O1UI2zmSJ4jhcC5!ZNCa3H4NKURX$70hmaY7yuKBf^-2fCE{LxuAnE{Yv#$4i;AbjP@dGf{y1oZ%t?TknYBb^Q?xwh9cku0MsvR)NJ-&47r>Y|f|W}g4^{GaCy^d~2kjRoeTf1 z{#Q6~1su2n4qO2Tu7Cqq|2I6i0v=oe53aLZfd^M-7q0Gv4_Cm4s~5tFs~5wItGnRF z)eZP@bvGQj0*+k03Z7iO2CiJat{7}6A&M$OI^*RhRAWmW-aNSx9A3~#JY5IRbb;p^ z;OGi)Y!x`Z2E3@2DC%KOZh+YY^WtWh9+)#)VJaaqXXSx&5eiFRR0=LGBhrXLKx{01 zSv|O>0UMfN2Ag5J50QCmC3sskctG4xMH9?>nqfMW*^2%)ZvN5Zxcf){ zGH(CTzl!^R^!ITCkp2Pg0Mb9gEkOFmP2eY58S#7h;Ahp~A8NtRwb3+R*b30qnS`q|1N;<*}lejbsI zQDlyGz|>)m6)+0{+^?fgDur1FAPgrRkZ9wy3YdtB2)u4 zKrK)Q)B_DbBY=C2^s6)?4fTY408v5(qJ+|LPtXC}kECB;1hW_@0T4t~Ac&~U>h)#V zVgTiU8^B#m`i?4?)j$n^sH1ckAk+g5KqJruGy^RF?taqm*N8Oo67qopzyTm+sX)k5 z8gJ=?dy8Ne0|;SCgD#;ICZfvOlDuF7X8mIwkfjR&;TaRUkU5CTJm11*3DXa(>aT&MtU0@FXuhlvoZv{w?GfDQSeI3ktpn)K>`g;U+6$tDqnt>L;1GECTElvNsQbwi< zXaFL>(t(3e05||ApaTLZ1aLc>v!b8`whJf)$^ZjE{8)kbu>$wJ>8>i6)d1qj(!qpK zM@Z+j!c~tgxHXPWgrr?=$6L_k_P$PjQ(ojw>h)d>L< z0=O+gm?!BKgO!TGbN0S9<1LkA0jeAg(0C*Edf;{A_4sSS*F3K!UJbwMeKqk)_>}`M z2VOQ_j=vO4#{=}l5(mNuya$q5=lJ)YZSeV1(Wm@J%<&IAVLTDv7u@IBmv}tS`2E5AJw4F@!}ogA5du4V&Gxs?F^KN;?^Jij?g-pr+!4P$c)REJ#BJf* zytgHGgm-v%ByWw}da!4Hf#>GL_V9M^_T){Gn|wE=wneu2wxw>2-srzky)kw};0EJ{ zcsLmLgyW%LC=)HPY-{|w;1P2R!q<4ONp6m8_H9n}%<=bKow_P|mG7$5MnnrtZU}Gi zY)GtE*2mTb)~V~FL0>S{8SV6Us-4lbzO~6UVTuwMqnZ6Fno;0gm7sb32E_^VuT0Ub ze(#DTM+r#p>c%z#mWp(M5iqMc|_df#J(NG>0HS z@d2Zk`7TS*{DH)R-~wYoY`%ZKIzM`e?~>%a@I24F1kD{V=0@lE=csd{v;DKx*|AxH zo|ywNf530}<1}+%*L2_XXwE=jvcdEA)k)Eb{)y_u=taJZ zQWK&)Yd>FcaV*+E;F;So2r~0C!F<(D=q5s0v1(6GU7bMS*@NE6? zdETCx0%lCW@Yx4=mOzZ-0meoJMj4}GX9Uhr&xoBK;5h;^8lX8xK=npP_(!NCqNn;# zRZor541rFL0~i>l4vP&9q-XQ1CnE}AYDjd5FFiLPc|zm_AH@I+5B3gD4hr|o3`n#p ztuaraXI4P0InZpRqyI%4{f()HNQ18-m5%)vsq?0z|0Qa|HC~z#5Uk!?<>%P|zRFZZ zq{7GZ|Gn;HI{sg{XD)!8{U3IDUCEMgiMJ$K9HyB7Gm6xrSfRgAEsTkPP(_UA{YRZX zXUY+Acpb@tNP)K?nIGY~|KU7uUP23M9-93hR6QzIW4OKHt=9*U|9|*<{2QOw|7#mz z`v1*~Ze4dD#l;h+<(iFY;|fvVs{!-HlUZvwu3OTP{UTAQ`<^VaGK!o1B9VFJ#w^7V z3}v=(sX|@%+LD)YF8-wTGLY4l*V@!fday!$M{&E)rXjy%UaqWGS}2+M%#)a>Ftc6f za`arTykgzeeP5Hk-zF$CU|#1slars!yvSmsP*_;jUa0)gQCySldLXCf#jG=rImcpW z4?n}}BaOX6mXI@LwpsUXo0P0i8CtD@K5W*id?&|qDD$4#(YqhalDxcz?xEzDDc~UH zNzClcg_7Xvav#$M95gsV=Q*IhAIeE(b~c76s{^gZ9rCDuhoLO9?mH` zgN2qd7g=m6YWD|cMAI`d`V{Sc#3m|hU0$+pqw0J@0ncJy$jnx$nM?Mao7>lStXsEc zEqNw-&B%DvCMYvtR_*1S{FTfrEcQSz+3(4zww@KXGq1JSau~7K>Cs)X-s07zo36~dJno%9#i?OM`A&}KQ0Be#aqpQd z$;*}-Ldj27z!RCnm}bjmo8Lt(x2j`}oG{AcTzU_C)}|)a&4xRJ)1Js2Z?TW7;kuu* zY04@vOQ+NS8$_o9Wz^% z3VCjeDs5liSHC%66OoHelqhSi+y~R8q29UlXU{j`4)TNmHLuRFH@=L6ho9V z>FGPnvzViq*(((>7HLmhlYN52%Qi)s1G82abNXwUt1R|F&z4@vsdhCh>|kDRvC)PD zpWyInPR*xS=L^g?EVk@7d9n%2=TJX8WA9IAdG!vh|2KvHen>F@uN>~w{#ESMZYKYK z70mdmR;P9!t^If6-)a56iyYe0zZGb|zsjjy zMSlep2QV_8{QdOzBKiI=!1{l*_8->&`}Io>Z3o2wY^LXDDgNI%hEw}wG{qI9IDks0 zQ#g|Kc|Nlbz_djR3Wwx?p^fWecgEYrVD|Bt4wOe*mIJhl{zM_@WWA#!7e)E8+dCgk!I=`M`p{zos3^@`f|p z8ztG^XzQG&xTvbzxT>6V4`6j3p`5DpN!M1aAEcFQ{6ItC4#Xji)Kt!`uB}w_eu~-W zr`2PIxpvSiEQZ+TLOXa6Zc!^QFUMcz2}!s!-=>9!sF~5w`{>*F-o*5`BS)25I&q|0 zc5tRrvX8z^c{ql&WD4>by(N?mv{y(uqgaSk5lC?&<+9KyiHp-}b zNB@<&gS6t$4%cozQ%92v1eAVbxJHr67VelDr9#0QGbu#bbfrRmy@fl^4(?DCl@v>L_MJuauxcH8TPF>_}HzPJQ~OMZapqG$epJ?992FSie--IZHWT zE2D3=rE9uZHBr9u4^LG}22&00rh28=vaWqRj?sujc_SgpWzTrjt6aV62PG_^lxDWj z9#Fc63b}(SR<^OJz3<4cbIo|@E9dKITu4Q@hfwTW-fxa*Zd)3%emJ2*N~71HaGdFt zQ+gw)76xOa`PyHBmudTv`Q`5Kc3X4(R?*X3c*3+w|p9`bwbKzF(d} z?SLMPBH^UKEZRuKoW)n=A2$jbqvUuKsHJR__^Hh3vFINdUWU;#4Jl;x(=c3|beSkm zl%YCG?~;0;hH#?Uh4)cv=*}q3;NC+(x@swno@6MM*3V}kS2)^oeWr8L@6oo(ULEM! z=xn>GB!x#=9(R#GFHZVL@F5h^5&RaD5{;}tiEY8USJ8+ph4 zjb_S8uRYSHK^1=##X}FUmamkKk0o2F>(Gga*>y5I0osU~sEj@`RD9lZdT5>`s{d{6sK`%>dfYK0vllS!bCFRsU>F-f+v<`4xr#=hd`ibnFZ-=#m>s7zNpEr3oz zHw5iW={G9qrQ4wJ8}24Rqu&>9Ctv{Lb3zS(#m?PW-rSAl&D~hu+>PbU-B{k-jpfbV zSl--?<;~q#-rSAl&D~hu-0h(78*VIb?#A-wZY*!^#`5NFEN||{^5$+VZ|*K!M8NXq zZY*!^t{dT3+=BpwSaT!Jm%9Z(EG{=9aJdm<%bj+RV~(;L zvyt5`ozybCpgGqZ)-X4)hPi1{x2azB6evtYs`dRGzf$tmN zkAE-tJ$fR`Q#X zZ~DHON<gqnyQ3LG*H#Xk;y?D;tHjqo?T-$;HG`N;QC>ci-V{tp8m7$3yHo_as} zzW;so{nS^J??&DYe%Xj8-bub4dE57P>PzaEVqXk=(f5VaTk$u8Z+hPJzplO>doA#q z@fzmGcwUMh2p;gf5P8P;Ok{s*-`=+lync`(W%^z^{M^B(_wM)YE88>r!OnYA5%13A z9g#aCw}iHJ(o7LE{$qU8!S&&_-nHtg*pq)2@0%AZaQ}bX zL391T^ab13a$Z3BGG8?L7V`s(EiZymde%qCywcZxabVNfwHxWmx4hJc52de1zitzh z-^bNj_?ph9t6)|N-f}!w!QQYb${d(i!K_-QUBHUR?QDAUC}f?M;+i%tO&y1`N$Gm) zC}bTLS<^P%7#kJ)6)^|j_DpUJYRw}WGt~WsEMn5LWp7Ngf@PE2ov-KsLhRlTY9-PPhF+-;UJ6nHr^1XHGtFjiKxz$JVwoOsyK=wzZ zU%)CV)3meqN8H%lKCUC%eP{0+g`8O^Q_i%HyB{7r3R#Dxl%_qPeyDWEZDPF}u|~Oo zs&qed5c6ba_C`dI4Q|9fW_SFLO-pK<&36%}d?|CD#YTPhH4P^-(IV&UjxXmF-ONIF zFmJWkQq=AM%82Hg-O=@KPSJZ=Xdm-oi!F~0_MxPIuhUm-dc9k5h%%a5@te%En4_85 zT2W+n#jMjw=(YlW$eaFU4$QV}=k!-GS6J+UI!NBjskVU?Zf0(=*l5IoJ4oKosrdx! zyup0cVncJl(@DC%mQ(W}>l|XfZ?R>+8NfNk*KLBtrahpsJk2=Jrm=`e3M(mUymd~M{M#K`GSsL*>Hbt2Od1e8{1*|fUY1*jOzRoP9 zGdpL{g|1I>YA$7+YndA?wppbEpY^14e`?c}6=m)sCn)2otZSHOF)v`6wR>c&n4a3D zcp$x}Pt$d!^w{}bo1)BttX(M5B|PFhrfDB@?f&Kzr?!dyl$}oPc8UQ|M{@w4|A9jr zwZ*Bu_b-PwhvERFCOfpd{#l?6{=P$dVY5>^lm5OkgnarnPVMkTPHh$ab^XGj-F|{o zYoHhaPtKuv1N8URcOBY%iUaVI^-gU)tpTV~41h<*(3}981CU5Kv;{$0ACUb1!4}e| zSOBg6T)pT-`u+dW*UakW-~S^JwNK&M+VV$v*Y|SP4J}zmwX%x2(qf|*T%jDf&SG9D z>ojkr`};O2GiM4-aV8C#=r)0#u4JCb9L6*o{>X?aW{@B{RnIb!@H3m5R5u&_3{HC@ zbG*eq=0z0Ce^?rnUZuZ!)HrufvX%mzgFzYtJ$**BvX|c1{Eyt#z zLRtUHx;_b+Xdy<75pWg4~QO6GLt zJZ824Rl>YAiJFq`0aX!iVvF5Q0Xx_AaXXaLJZ6nww{F_T z)#d`hJ-bKuuWeGji`Sq`r{dki9L5~Q%vQXj-o?vur^|0_nlcY&@#eF_GUgJC-L5RA zfo>TeOJy$UIh4L? z{j6%H?M!R--G0tc9ZhOL`z`B`JH(I^TGW#+(4e(nF+INEMtky z%&RPR_Jhz-+{oGezcx*ob+e!i%1kQge&#UdnapejEw&Xj%NX_-o2bl$Sk%SV%~C`?fDOzsLX^M)9j+owCHh3RQ;oZ9e5o!T1Y96OexY zzxA3!n=rwted`SReuq>0BhCHaa=KG@&6nLDE{9fMOi)kHqQ|H{Xggfvk0dD-*W$dsQX`8YF3Wn_9iv^RF)bEWwxis z@PFHqmvV9pNAd-hhBIxsL-MYjNi)kB{vVr${DL{O)hKf)nJbtSHHPe=%xp(@Gtf7N z@IC{5ciF_GxVa0Q&Ph*Xjs+eJ?Fu-EIh>iTS_?ybNjY7u?W>N6wXfRc(yz^m9mR=HW=^o!vW%1q>m!sY zW6p}za*EDop(~h6Ew&ULSjBebIEp|IyyID);97i58_^3E_?UKN%j`mgN z6WukB>M)Or-T8LGbXCb6WFCF^DFqzF9LCJnlEVBcK`q&LDEtDOnp8I%auTP#kU8IC z%Q_ukLppMbUduvvGHFyCVxGdx){aFXgLZKYbli@8?2^K!C-u#ioRUr*dY4*kS*ZhT$-rf2)EGPdio21Nw*?X3-Kqqsx#m2=i__OT2Cw&1UYjo|> zoNAj`VF&Yii;ZqG;0qXKIVJC6nMarpT5P$DgMIhU4`I?#``o}Pd4-0nApOI}$f@-N zr~eA`Ig2ejsJ+AVKh%`l^sM~_KQ9(g=BzB_EyvYgXbv|&-4#OwJmumC(rGXe1WAnrY(0l`wrgs^_d!*hRlR{>Y^%_azD&a=PlX#VftEj zdfbxxnQiHVTAQTIg6xM7%eM%dwmbmYiHbt2Ov+ag+`sXmuwAjbocCsLSJ%8g5 z4(&4X|NpMUsf9jrXyp_KU=LjbICm<=_y1Rcwu)i^C?C*$`zvW(fOE*VFX+9mIkflb zxBmiK1K^iu(tZEc^gEx{0*K5d|3CdbS3tk>>F>SSw7vlS{fvJ9uczPtT{E59t@Ky- zCx`Zg->HqDzb_whXzdgOK%p1_g&*E}&Pnw9|LPCTobvjA2mY5|q<;ZL9Ol(DQdXL{Y}A$ro4}&a`Ep#Hx`$^Gmiw1o*erIY#(G)ynhbTFVoP4i$^8q-7g*}kv}NC*H?5B>``4*9 z4fz$he=VhC9#Ozy%u&p2t(BP)!24JGDsmql8T@jDO;hH?Jj2GmX^CvNv9+>nvOHQcjK{NWQ?*c&07;KfP&vWEn-ywrR+( z$WdfDB@e`|=f(ysBg< z*gl@7y1=F=b0GKRjFzeEOe-Geo*e4FFpIFqL zw1*yXYA4a$|F8eMK)d`yTAS~;4s9#V{jZzi(7r&v|H*YuEkVBjg_G!a{ND?-J815I z9bE%>j{N^;k^leO6CB#czZPi!zSpVk80^%B{-r>BgZ%%KX&%6LY2N>au@0^B&js4k zv&2SA~F0M;M6TRWM4|9|q4nML;hFS7pr?;2yPC|Pl4 zC-ZZ)T+Y1IVh?mY7@JdV87l;tt1Y%{`ePXnl&*0(wXWmz?_l0+v5(_qV!TaIb_+QG zt)Sl4z*6#^9M7T5d+7maLYCy^0CXiKuPPZ9u|2>pZEAL1WYd&+kV8;L%~W=#HIH)$ zQo1G{g|I2sTX?`H6O*zC$}!JgQd2h5NWCn3Q=_bR<*ewiLAwEE&<9bL%d#iOLF+ zwc1Iwx?KSWF^4m=?}~D69jdjDi9GXda#G%`*ioGLWab2mEz3x`us%YWGUl9Hw;-qJ zY!_m5+~f~0g`W)qY(C0jB`wYNe62Qh~+v$bSq zZrzGL_mG7)HK}ek?PC{NWYd%SX3d_-sZU{EWU*x-2UxR#oT77B=nCdii!DV5RG}3coLbBK4(&zq{a;AF{|{*H|3ZoZ@LT%re>?s5Zy^8wQ{yPcKmGpy zfbRWYPQU+k`u%@@xl?Pp%c(s>@&Bi!3bgOjegA6?((iw|25|AB;DWz+T9Zg38-o<0|=r|a{oz)PyZ`B+3bkxGLGSgA26z=O z!G1NCVAnTQfSY+G_G_?Kf_`l^xTOZX4hypDTkF8-z%<=_1pE^9pD|jjQdV3t`gF3}*x%*l?!SlS?)C4NfS>WI_dmdz z75Wdc?7jXY1N?D0c-RdlE5M&rfGz1OB2G{AC^Zt9tO)4d8DY!QVE4 zziS46kF_!MKX|}Dsw0S>YhWr5{8K*o=K}D59pGP_;9qs{Z&*@8|9c_$k0S7&#o)h6 zz<;~I|CEAVWni~KbkYqCc%iyMtpd!eB&N$zo?nGc1=XOV26WbfdL1b0!NLZxs1Yn~ z0!x}fR|{C`0n1uJLmf>l*Fbk3SdkA_7JyX_u-XaM=wPh?>k7g8BCw$tY%BqrTwrr4 z*ir_146wBvY;zN3F$Ps&)8I<*gevgFYH&ymcv3BRaveCd9vs#H4sQfcX#!7e21lr! zM6U*p%mYu$2Tv~m&v1aFoZy){c$NUqE(Fgh0?#c5&np4XcYzlmmcM>s893SiedXX7 zH#oL}D2p+!5}U?XffK61i)z4$wcw;WaB@93r2(AU2wvO-PHP6Iw}3M|puZKI*#^#1 zLd4lBI7b8L=7IC_!AlCj`3`V_6TDOhFB9OxLh$k;u)P>uR00NE;NntnNf}WVW2u2n z9p&IMH@Lh4yrL3ZQ3bB72Cu9ESJi^6>%cYj;MxYTvk?q7f$N&V^)28A54f=vyh=Gl zyjle}Y2fBO@S1$^+5&Kk1H8@&Zq>o-1sEy>!$sf?#o&!4L|Ke&E^N99QOou12u!Zu zY=F0vgSWcD9TnhhmEi4F;2qWA&KmH}T5wk#7^w&EY5?!XN+J3^P2j!F;C(IN{pw-j z0~)v+AOIn8a!? z`cJS-i~dty6v8~ID*qW4c+h|D0)J5o{;~}Gl>z>`9Q=(N{A~sJJFGLH{~qfg=zpjN z|A=J_^v`R-R2}%IdhpK;;Quy)e`x~$s*WK3O#}a)2mT`;{AU69F9-N=Iyi zA<^kpits`$2DK6}&qYi(hdaL%n+nQ6hXFdvLER0C3b3#eEUE&FtHF{Q&{YeT)`4a9 zpwR%9H-hdau%a2PYyqpVK#gAA3f8oNwaRE>9aa<4>ou?e3kK{DlK=`QJ*t8F|zDX5x+D8^#;4*Zr@jUW>fueJ$~7 z@Kxj0*em{5QZGkd_P(5;80yALv6w%WIuJSFJ&<@Y_@eRR=ogaDhoAR6AA8RKT(M4tbShdmF+9|}CAJ`{b>_h52&c(-SF{DHs& z>I2dHefKBt3*YCtZ^pf;dm{IE?@8PpyxX`tc9;LIR3sAdMiRS%yNq42JNbA&j-rEv8f;)^Iv0D${628TAOZ?`*&Fan3?Y`~Fo5DAFZi;UU zY*V*IZ}i=mydivp=Z1JV5LUy{kS~T_v*w|!K;j`VjKM%QyU^1yc-hhgX@j;v334+sbD1N4JJC3 z&gfd-+T@z>8qb>e>cDDsb##?)Rr1R4m7Xi(D+4RlmC+Tx70D~YS9q?7FApqNmq(ZR zmL)sF9iEQ((!kPPOT0@Gi-U`e#j$`tkXjU3`>Wt`g-}L0P@HEe~_{D*X)r+H3eN&TD!cz`R_D@bticIoMicbtoR3}C+ z@?Dgi5T4+f5FZ~Hua1w7^NmZ64UhGVjgJY8QO87mK3{Tlc(iA9{KCM6>V+dNNSq%$ z-#9;Zp8vcQMbG!1n>Z(Uj&V-xZ2#G*vm$4C&q|ybJkvNcHp)LLbw=b2?-_~HgQpv( z$4>K~mKqrudC(j1s@~`b--zU?;Zr@Q#!m^HqMi~R?i-#Q79Qpq79ScIst%2w>^nJm zQurj#N%0|pA?lFmiM|t)CxlP%oG@c>YEWd5cTl1&*k-iFTK%mlPsHQ(BwB(kMoX;O z-<)cSGh`&l<>7KqdE5vXsu3;ol_g8VrJmBbE8tRH(Gp)tXR%Qnqp1I>!bqXFFhMc@ z4H47*dWs_cdz}eK&|y%-e}6$LKa%gwPviyjjJ%lU*HUUk^{NTl#aC8uZyrYe{}Jim z|K|Pwz2g6O4w_9u}I>4T@ zHmB$VEc7IEkHsEv&*|>8>De3dDyqEq6mSspRA#n@EH+~i;ZDMA9)+MyP-ehv%Bh_E zBIaclTh{6Tn{r)F(XA|W7jvh@mZAe}%Jn%#A7r7YnNf>9;HK=_kW=qf*7yqZ9g98S zK_Jw<(IzPSj)$XhsLD0eTCGgM^e_=okxt^|hvjn!3&Ue+_!%?W=S>!zG)K315*oMf>F6m@vBO-km|tjRJZM0ua6go#7h z_AF=dV?jQ19s zuDxDwpc);k+{pC`+pBRpvW+0F&KnK+2;lbB{z_7xbr-|)>Lo1n~q+}R;`0gIf=H0^=bWH_hV zL{?bHoM*A2b{v75L)|ynWM!?k(p*{0m)%8AB~0C7o3*-Bepo(-918x?QGe-19u?B# z^o?0W%#*~kl)Fh}HFGj^Iy0*XpIewBS1-9Du&#YWi!DaMHk+W#fZ24HaPn6&udvwJ zo38%|lA-_HWYd(DA`gNOQX#7pP%vFgvyfNI56frNBt_h%LYn{AZ{X1&U7y>tNSXC{ zw(?vSI<@(~ru+UW z{{I$=0qCL_0FTfdfWbFAwO6W~+Bk~;|1rh>UqFAqu5fCb^PO5g#Q?Z-7R?u+c>phx z|Nlab?lYi!|L4%(&lRV(k^Yn!PVMd!rmr1N{{QxbtPFZSFk2bc>gNscl8+CW?=`?# zF5oK{aFq*q$^{(d0)BD7jTISc*F%9;sX9~0YA8a8@wl<@P-RG!v%cd0Cd0JyLPJlFybYytnZfcsj&doAF+7VupQxUNMR0LQf`2iyR>)&fpz0iU&iuUf!W z-IGsvtOXp_0{&_NceQ}GTEJN?;HwrbfCo@V5HuhUfR|dpNiE=`7ES;jY5@nefPY%R zJuTp!7I01r_@)J1(*mApVF2ZT8-P<ixzN2_v8~EX#t0{fIphu(E{FR0cW&; zFIvDAEm{B%&VZ;8PZGDGPX%1suu({$v4nvVb>Pz?m#s01wa#v;puV3l-1+IFSYWkelH{7H}a8 zc#s7g$b$XHE$|-;xQ_+A#{$k{0pGEJ>sY{ZEZ{K~a2U&+w!m*J*lp~A+gQMBEZ{U2 z@EHrZj0HT#0uEyVf3bkOSioB>;4BvGD{l3`Yz34<1UQNX{KNuoVv!FN01m(jz(XwH zAQtcs3%G{`yu$*{VF9PGfKOQFv=y#l0nf02V_3j1EGmFXpbCIbSimJL;1L#Z2n+aw z1>C^`-e3V|uz)XEv;gX1f(F13OrtUZUSJxP3Ge~as7!zdm_}s+{J%6R6X5-&QJDaz zZziAE0@p8%&ICAqX>=yQ?MtIG0Zv~Uoe6OH(&$Wp!#kecy7=6E&)DV8g>cr;L@;5fd7_;T>{*;J^6(9mWE#fe77|G65zR|;g6o2BuV0M9Iqw*>fQ1>CYU&Jy61rE!)3mn@C51UO`AoF%{= zOXDm7&R79otbi+)MqC0Mu{7cm;D)6UmjEX$jkpB3U}?l9zyV7mE&+bmp8ACQl}26y zoUb(U65x8Jk(U6+D~-GaxLrjRPz}@owLl$E4>SOcKoigmv;ZDJSwv6)4afuXfdaq* zH~}3HKp~+gpGDYG43q#apcE(r44@ov0~J6ePz6*2H9##;2h;;fCqV@?AP>j~3IGS- z1av?Eg+LKd43q#aLQg(Rv84t~(XWjE+;)U=F zUh=L-p7%YUdM---b@jQ}vw>%gXXE5y_dJt$I{dWv=|xW&PsPc@?s+n?KfK?&KS@4z z-xH~Q(S81XDtXxhj~kE29}7O_c`OkPN4?SH-U#{HQ+uL&{Cm_ru}2R-5+PrE>fz|a z{)g3vW8`f&9*RF0e9-e?g8c2?-N^?c5BMHP-5YcHjft|+AIQiZ^cO-5P-|oFVN#1wg zZK)m69sV6E``;tC_-;wv9KG339{AYyz;gZ~Eg zh8X$bjc_~^q;=U7m%!Z>r?BZxxhAs4wKs6{08~#gEKrc;?slEJ<}89wf9a-UL3jDcX4WJbgF-pB$XLcandSIw?lJdt+k!qTofIixT9$_fANT50CebPmYU_|2{P~I@Ui{9UCJL zzA+~53;I011o`m2qmvhwT^PS0c!7t!_~G-t=O@pLoaZAye)L@bx$3#Ga{}bakDnbp z+jDl}tT6fVlV?WG^qrX+6(w)JIx2QX;EY|T`%X`t7A0@KdRlB`V5BiJ?hSf9-o%LT z2rv2cBd7XKO`Q@w#ZO-S*zmw`V|aX6ko@|Iq2Zz4p~;iWPL7`xB)@)QNO*{MNbyL92jg2jt>eB@{oT&+~#ddwnkcgQ3%mtM^8NerQ+d%mf1XO-|A1y_aW$xV z*#F;NG41M8$p0TYWd6p7|9?=(^#AipB^0bF=RI7va?Jmwf?wr1>cxgg?nmaC#WZHh7nW?Ke0{WZ)hEw-#ydt3JBy}C1}+EuI&W^T3E zGR&jB5p#!s-j!49R!;u`<}Qmp@V1NC^m@15Ny=WTtV@~aGDkDbwmZ_T)8lx|9=P=` zo1n~q*>qDm`T5Mb7JGnA*L}B5&0f4H6>o(Cp35A~G>ezZ)snSm-eVJ#8IZ+;)O;41 z%QWo)7O(5xoNAY`!gA(Pi#?#8*?pf)%U+d_aZdryRlw0qvnp4~56kCJPfwvRcv*Jx z`)z_U1F|Y1GM`1}GEIAcRoVT3O-<(19K=pi9_QkL=dwMTX%=sz{IGn^6pz9PWhvfn zo1n~qEFPrhv&dYgX%Dn`58BjZPR-(-qwFKK9n1;Li%*_=ggtD@3~D6*~Fx{ zS+u#F^h)M3i=C}#M|l_e!#PDau+S~cZ5CUK+DGY(XpY2(jyeS_+??;jQWZK5(0a_4~Dd={F+G;LW-deizis)~Iwr{dMDatm{t#g>W#sMxNj zaw_g(l|9V+E%rc9NkiRFr}Y}GbwjosQ_IP&p!Fd!rh;x}JMD^V`dF#6NWnjvdN;QH zV&BxM)5j|0=H!7U)cs5rr8b)Sfhi*utOQygODNEkyFFif`UQt}wu}7w6#H)u{T-(J z{?`n1YX7F#f49*3e+?fvv}efge-{0{OR@jv(Eb01>E8b<>96ZkhqjC2|232UKSuZd zk0$^Bx4+`hmi^qJ{e^u0H`BfURrI_+kKzD)*`a;-6Nk2-)v5hPC7(a}{uTPWo8tdB zk?&tQtSYlk|LFNs>G%Je-!^l~zyBAR>;F;EUTgMYhXmD~P?oIQu(V^@`ctmJHnUFt z^K6znk+t7OA04WIf?2_Ar*-!_XxOqnXyQjPEy376alCH^RsSV3$NNWYn$YVpegwXg z7JsfE@xk=bHU$*S3T7_xsy@Ygi9X+t=uncIKxKv~Sj9B=s3S}4Qe2@?v?B6s-|R_a z+kLZUjh{Jt!{*Kos^}ITwc6X)ZwPEyv4jr0w07)<_6?V|4C&a^x$dNv%-X)8t`}^X zl9@CI7Rp7Rj}B!MO+#HrUANaGl&|0)RIoi=*)Q58kG2<_qG;PT6)2ww!W6E122zu*1+PAWBAh)25Fb zKVVkDoSs=6vfY^IAVj zXR;C~6tJAxPSX?DXIGjtYy3D?@**o{ukU_6i;~9Yj6ykwH7+2Qv0cN=R)glC-F`(! zpmW8VWovtMl9qfogHg7tlNy` zJA0j;cfZ+>*m*1fmeHa==14X!0D52<6K8a*sU2;P5XO)irG544_GRljI@$xPRxDrBv6Np730U^Nuf3x-$ql(g<@PBOS<1IYo{OP%5mnfjl zG;Lbvg_f)B+spgPMTI9?9h|Hsp7Ac_4G;MQ;KXQ;aPixTYEE4bbBXJ3R zwnPDSrfILvSq`(wEh1m(M`S*I)XYblI{WT z_oHk^`LG|oMWocE zfI8E(v*}??uoQX$Wr#GW(rFQ<#@ca)u~Nd zd+?9-w(dy&^FxU&z7=S3nyw1<#}OE$J20%W_vH{dyF0k87)? zg_=>!HbN%P`Fp8_T!f?>5&+S0_E!sj61a53M|Hlv9^195F+2*13>J4}I=2`j**hMf65}e&;l$V4wL8 zrGuW_$(63t8?{XbrsCZ;(%E8upWpM)W?|i+9h$0?^(5?|R{}l3`jJA~hzc>as}4>v z6OQ!yP|1NAir9mlfz&kWB*R$GMVsrJ%cvZKDb?L(Zq1y~#!NrVA3>i}7hNiAYZyN1 z9EWbbmrYeF&4I0iK9bpS z40=_W>BQP0Zdz;O<Xbz1dzSg>^r7vP`+^vX|?KuN;w0J$vc; z|MH;hW$gdU1tX|yq0P`*Xg73L3|fBb&x6rscw|UjxN%WO?-s;Y2h-T4p`TOb;E+KL z-_zu^hmP?J?gP}zB6OJ4XjjVg;yT)F8F8KHtR7Y^bnz%+88?gRO;0&KK|=?3O6yov zOK;RrF3oXHIZU5zI86J}Zp!~i*A{vw+nCMO!6WvJ8A=IK#u1_KPg@80BGM>#VaLz% zS?h;!YaSh?al{y${Tr6UN7)D}=#$i9*w_5LQx@-{I^>r$bahfKnVU;!b8Yn@Dk}z6 z-cAZ;J=D?W`f?<-#nr}%RM3lJdfzzcnx-$DJ&Rhf)uEAN22zJ`krUk?MW^dxQ5x z@AluFq{xt-U8$YP+l*U1+dVfXZb*d#AtU75>c1{|?V(KvH%8VST=V(LmgS!>2`wsH zxOe`cx#2m{*}+-inNfdgMsRvynlUXoH8RydB{C^IF-TDk{o`83e174<^LL%AP|QNQ z%i&D#nej9Hrw32-jP!ZEBjTq7Pe~4o3{!`;oaj9vIVjTRYYVg*t;v=o-FIL#sf|WM zlI}1_)u=U|YHyXVGUblCgXLkvYxv6orD0d3Bvu?QiWUZiNBAf%VBC?UXn;mO?gU7v zin8uk&%Wm+|Nn`fn5_x_f2;CWev!WL_Kkinpx|0?CH)A%1(b}P?E(rsMC2oq7f^WJ zFsP-)KJG^hS0_t&wua6$?QG6GGZ+VZ6mV%riX6%!BCq!^r;oPKnnk$Y4>mIqvSnQ# zlkd_OqQ=gg-Olqw$bUb5+7ZqZr8|*D)tqN^JxzpAlq7Q}^KNF=>*VAUEmh3RPI6+J zMk$zORJy)tQ-tts{Wxp>nE9E-md-vdNhSxOf=~;!Nc${u_8pac_qT2GGA*;R zH}ciz*O}XxH#4*P3&XRl}{H*5RF z9jn)_+br7^ndkjO>Hfr~*1KGHDJyBiN6aX5KQpV7g4N9H&{E7=woh$pQr#@u^PKhv z%=av|Y(#t6j=2%PYm@I?*z4IL@_Xh^<~_`;&XN$Who>(P_f^{O+2o|WS=v`Q@&93d z(P9si?NF4X)l2rfJKaCr`G9`F!jn;E!$cGCes0Vj9Rn8tk!@6S#|+?XX=E zsvu8Z&tbdoq42OxQf9$y-xv$L&3waR53qf^lQy;91-zcaDt^Y?$$XfZt$?L86~W@z z$v!6j#3n1VVHWan7Kt;zWU*zl9`Bgg_0yd4Ut`JdF%Ma6S!#Q)E;M&qAEsWcrfEAz z9>}|YW)rkmbC5RtO#yc@A7@HI`RVj?sEVdW(Buet`q#@7+SicrbDO%%jal2zu-5y` zcP;jRt+s!WQ~nT39%g=Ov1Q?py|%l4nN#prEbe{&yg z`zxE8Y%Oz)xPfo|Fx2(5Il}f{rYxTPv~1flj$7K(wmFWpzqaYhe3-2oXO(X--?!KU z94NYelT+;zR`?t9bBq07JkoakHfIjHS+$hw*}*hzSzG9zZozQZyfGQVoE2imfK$f@>iR`@gX z4;K4)5Ah>r$sbvN%&Gq`)~w}fu4I}vMyGnZ58xq}t_`Pk0AG2;sg0!=fbn6vHjCy0 ze0G~tTTO8Q|4nNEUiVL@*8OXzwzJl$mHva)2_*mj$rS(Z^)u=IfWJAlHypY)neGGl zUZqo;H(1wxO}_tY{@0=X>(5T@j-S$f0`&JP`Ts}#$*H}j>e|GlL;L0;N`D5e|3~)$ z%sqeH+>zw}zwc8^i|?JIG(~3c1{Ym!A0JA;XV43ZuSBQ1KJ^i0}wzl-~tSw z0;mS+fhM38$org-4+x+HZ~<wZXPyti{wLm@4 z05k!uK;CGA18@R`fD3Q~RX{aR3p4=DfVzm_1d4!CpaQ4^ng9==brK2y9Vh}Y|3w%8 zrngWKAwmPt0${cac}obGZz3?mL}0Rrz#I|sn-DNjL|}Rd1r{P;j*BP;FttTsYKy1@ zssPNd5KRE4RR~P0p#DP02Lw<8U~+|U162TK)d$#Eq)fFwtZ+9?1}FvIId$o-sM1!9K$gazL6t0a=b?8X!;08Y2*NnM;VrpLW0rPI0$1V{$dlh z^$xw*lg~^D#!U1@1YQ(<#a+yVT+BpU}H`vIYk zK#9T@Cy_%WT4N$A2!|+gM?>Toh=_bhI~1W6_%8=O6t;ke9P1Ea4twg8BOP*(Lk?~D zUk+#}u!x;FjzESz`5a(C!%Qqg4rAC8!O#p^n2A@&p$a)lVeSBhnb?GRWfaq_Cn8}_ zK94dop(w@I%YfVw2{{4d-BOq2sr?uE#@GH z7UZac98i$s26D(ijuyx<0y#3EEd(Hk`{RIq9H@`O?QzIF4u!`7?L51v@Zunv2B-%L z4iO3g1E>QuWlm;4Dy0{q2519{$_N!e1E7u|H~<$=0~9PGxB<13Py*Bf1tCH?&;aPW z2xWl#&^TIiuL`WHCW=OwjV)kHE7;nG&Fbf54%Uctf)2 zIUor7@IshnFi$sNR>C~H3T8D>1JnZb1pUGWn2kUSUiUnkuNJ+gz7~5m@TyAd=LKFd zUWvaPc-eS4_EO*_l~<#Ee+{K=6QvBK-wu4ZZja!554d;?D=3SD#0mKdhtYdp7k< z^cnv%Dy^g!c-nY6{#5WO53Qvae$xA7a(`sMk5+XeU)xG5A$Y$T>)TSt{yQgl7T^+dExH?WN z?|H6DYz%MoZcJ{7Z18PJt>vuUFT{)&*B#+(8KHR#nuMa8f)Wgg0uo(Vs&`6 zcXe`AWR-7K>dNSq{wvihW3&pNu`<3QxWcm{LF@2&uShPBEcY!>EsHMmFAH^eJCaKy zOMOdIOQK8sOVlN?#Q|E4FCGX6Jb}cbFs;XzY>%}2+EbTDX+=Ku^4P+_LStc^*5vbC zmbg^8G`3*T0%Jj(*5vcdPh1kd#Cu6{USytcUTSW1uAf%si*cO4`0OC9&6k)Jp5>jD zoEf3j`BMI<-|r92@Xkn1kI?FTscF$^{%Pv87_HA|TpXVooa&jHpcVSOQ<9S-lYO*G zUo>m1zsPvs_|&-QIR7|xTx@J$tU;^w1;=>CBz$3?m)7fxjP{LAT^PO4Pb>DtE(ly; zTo9*K`#k3-&I_OCJugY?_W90DofAFBe~wCC@W9!|+3~Z2XL)GtKKR3vqavexw0d9k z4F4JG8L`s?w0>XwH1d$2mKYfx=^dH$M!Y_6YD9E|e}p(M6-jr5R{Beo zN6Y=?YI%&-`ZJ7pS+LAgmY~)CyroH+jplQuN}?tH5|zC90b27fUKA|y6eSA7#~uIg z8sG0eJB|GRE7QOK;s0+t_!s`c-*@_lH!p4eZ_XSzxT33=B^Fy&_px8v?D|Vi!6p_N${cL5cvMld5 zV2QS5Yaz6FixU!-D4Es?AhfEpavr+1jRQLblU3ZJJ)9opw51 zro?on)7yJ*uh4ep_TG-n`};iyhXg@^kRA7r`FwIDe(~Zx?|Gm1ect!1IM4G4Z!JsP zbGdHu^n&@l*fduCwda3UNV7M$=JHOlvCj$b5{?V)?%AbFpJubU$o@`Vc}w_aS=t`L z$|+lG2=Ru6EWH(@VGW^2c@Fs-gq^~bLhF?c{*1S1F`G>BaCUke)~ILB9y@j9_`~Ac zpnUk$N{OZK*6Mngz7iXG^c$DD}y<8zP#Js3giYRSlzmE4Ad>>FqkFZC` z8Ipk8nu>+*Dd2ZVIt?1VGq&?U$$1ms8rwRAg~hFzIj2{VYb*1!D0)yK`-EGCJlc$3 z;x)hyb5I#nMi&fwN8u$2HolLHKAf01`{2nl;@!YFe(K~=W6=v_j*4d3&9XFng9zO( zyuB=KpTjFP?6KZsz>7e4B#u8gULkkB_vTz(g;=iQVw>&1h%^Fpfo`Fd9!1~jDyU*9 zS)z}^Q&8e$+1SoGYe@MLDr!9s*039m>nd*d-hkZV*--Fzb|5_2ke{A;S$alELDo{g~X-iNmGS5TfEh|gHrjJ@ZPet zeKk|LV=wO=kU_9nJ_$m{hGY=<@ACp&ZcgOa`ZXMn( z?qTqD^T@v8ZLtHx#*!0;x1uF>%dB4CDst}??k`JoXFQ3cYGtqMt*eY-dKB6T-$nD@ zX%_hwGUt31QtkfJlNHY!?72nBSRQ6+b=3Z$f6iZ}dizxIb!;)DkX^zx!cn|8eu-0s zlRiuX1XiTJ6$8@B{cQ`2V{JzyJT0KXh|Ya8+V|63Pa+KoQ?|I?K_%%ihgaR2}7e`fWW_y2}zz5j3e zELTKF;j4naqekz?vHkcsMm%|z5hoX&#ab#fWNXYC_I09Y!Lx=Gs-_Nt3O>8 zBJ2w6V@(bj*D7SE&=6ime{gBKq(9vi!ffGIe^yJ?R|~h4rD<<7fw$5t`%`l8d&|V} zy63T8VCCTn-q{Y@7c}K}FufH5?FLv~ z9FXdVgzL-Fwkx=$U6h;bgA2kIIk|f~w5+r%M8eI&>&w#CBa{T37uR#kqAqN*|j`Xt>gsSW(st)7FHT$wogY74J`RR7S!9}XYbs>gDzu+Y`~@<+3h5SFX-nqPTQzu^ z#J`fmHJK`wn2T$xh_R2Je+dCTWft@(R+?N!jQQHUn9BP|!iNS{xZ~}kw=-`lJ9DkEb@P>1u32LYj_$VZ9(SJEk9oQCL0LI^ zc1@|!I^)t)cYRrY*&%I>ajmiE;I3T@Q`>xdU4;s4l~~gZy}jgO`D7hmI?cpkH1{%Y zRvOIp6(Z~!?ZNyTWOx}doceC1o)J{2R(|FCYKRoZddI&^9v8= zAQ$WMq}JdW*WXY!eDkN^B~t<~iSjcnC&j43Rx#@8M+I zR3QRGEQ>wa{x5uMRY{TWr;lOyq@+9O7-9kJ+PP;~!5fsNi9J+BmObMxKuWtp zdW3Dla#`Jf?a|hJK@jos7v$U^SL)%TI&y7+Do|i-&p6;rtt3nUflox)qqP&{;^YQx&r(oAh_x@K6;r;(HO?hjVF?uE5|G)Lm(MWq4Ij9)^ee%sW$uRKs zethUHL@Uuo1c?r!ljtUTh!D|77(_pzOaUsP6Aq$|a1w69L(~(EL=(|Wc!?GwK(rC< zL!vw%)Gh&sYWxCsx@Kr|7}gpX(;T8TEIgXko>h#sPs=pzgwOgQj5 zvffIx6G6h^+Yh;fi|`N(c&|4SjCHRw*1hf{T8LJH5$^RM!Ql3KC(%vx5R7N9GnBn< z5Me?c0vN?!cMyzXuQQ6h?j{((US|M%y@6l=d!4cCb;hpOeMAex>z%Gg7?H`0#pN5@6hS-A}XN+E)>x`JLGg!LL zVCg!emg@{yt_KN*Dc2dHTxW!Gox#a<1}E1U%v)y&Z=KP*b;jz}8KzrjaBiJ(x%D8y zpxe6U0~lo+qXaPgHCo6p(a;URK+w<#z+lfhgFWjE_N+75v(8}8&=SB9&(IRU=*~K$ zJ40UpqdV&i?5s1Uv(9kNI>R~ZjO45{lC#br&N_oQ>kQ(oGg`CGXw5pKHS3JltTRxv z-bye~Gg`<{%{oIh>kQSbGfK10D9t*fH0zAgtTRfp&M3_~qcmgS00wBr=m8AStTRBf z&H&9i12pRl(5y2+v(CWGIs-H7jLEDA2*zaA8Iu{~4KOA%1|48bW}PvaG4cRoGNXlz z%B(XWv(A9bIs-E649KiAAhXVZ%sK-y>kP=OGZwSXSj;+OG3$)QtTPs~&REPkV=?QD z!K^a|v(6aII>RsP48N>1{IbsQ%R0j^>kPlFGyJm7@XLBH5hD5sgHWfeQN{<3VSt0E zBbL>tjg1c?r!ljtUTh+ZN@^brOTCi)5fI;yLLPB@4YxAjdl3Y>(KXMv#H;Q zw9X7oG~3)nrFIZ*YPOw9ReV4j(MNR708JNw9-^PwXL29+(ZizBHE~Obp{9%?hAkxh3;Ai=NQl_NFt@0Ko8-jj(tQI(NDN1 zfuL^FY*9#+odJ%9iAr@xo_Uif?Y z@20;S`EKDmneW8DQ_N*^@tm5=oll(i<4yn6Tj96z-%fu!^6kR6GT(}QtN2a6>#u$@ z_l?9i{NI@Vdg|-pujk)PzZrRR>T4rkQ@@t`YT~Q@uTH;_dL#Ts{`K_hk=F~aWnPQD zR(v)4YW!98)!ZwISNyL`XH(g5Hb0r3j7%0@&b%CZx%g7{rT9zgOS!KkzT*GN^p{g# z4u3iSrSz8~Un;zqc`^24@rCRQ@fXw=a$ih*(GL%4sV{`TkpF!8^O4UNK9~7i>~qD> zWx=}$&JS$HP%OzfHBC$gW2e?t94?&FD%`#(PYvDC-HAIpC<{n5xr3m?gR zB=(Ww)7huvPpePoKAiZl|HIQCN_{B&p?o@>j-(4_#*CT8r?OAQpHiR7J(+mY|K#)& zBTuMLp&J<2(PRC9cQ`uBJrKWPpMADy}K9xG9oXVX{ob;cZK9M>RK9N73 zJ{~zmUJ63!k`#}5w^?}?(V!}T$eShly@csFt>7$XOg(I0Gu_MLt?09^9_7`~f zKmESQ`=;(m-4nhie|P%s$lZmzGIz!9D&CpBGk&LfXYP)~9sWC}52g-=59SY~4@3?W z_Gk9T_80eM_r>?A`*QI_+#jDDiI1owxxIGTt&0m?mGIC{MOJ+-KOYw^A74a+7 zD{`Bon~RZbBpy*CxuL|6e`tDBYEyVqeq(xLWMg4NWf8oS7uknSE?&>D-tXGE2alh1L1*uf4V=? zUkGQyv2fAI8gWB4a(#(Df8TT{6$*#)z3JXaZ=omC6YD8+_zpC*mo%Gj4kK%evw& z)s=H5oPOtYU8*izmv^Kc5l2DK=rO&hWwp4bYB@Eb`qgPAg**J!k0-je;{N~7%kTeZ z#*~|~!*c)6)9P@tTgbEPaMFb%{BV+%=)*~#WrveALmy7^WILSX*>*U|)9rAQ=iA|= zeu3m^7h4H=_8m?-g**ulC)%gv~;)&?oc@TZ92&tFTSjE({7ggq^}JVYjeH*eeVP z`-DwVxb#kXg??c`*d`1LJB8iCUSXe59pkpTuukX_dV~$aCZSj87Y2lF!l20-x`d8% zOuK{)!fv5H!+fXED{S-OsyF4@&VO)kPQTst@LJBO9dz>l20jPy9pO2|uXGT_`xrx_ zJkuCDtTb$eXKu!E(8L3`sw&Nx1I}hm9G;6Oe=jmx0z@m(d43#j`RkiMf$AB)LHyx^ zZy;|6@-oPUGkwU~0srgu&0D1b4aO1WnjkjqEYI~IccnIk+zgza)8)G5aJ{@t6UtoC zIyuHhp~@X#J^n$gMA#?=R1hJ~p@gzJh@$J#-Yl1HSy( zQicoASQT21$Olr57lqcipym||oseSXorcb!EXU9hW!QtF5elL+eO4xsF|gLjwLYvx z_ZSTWF*~r%YImuNsMqrM4n?6k@R2U{)^kf4UQ}4w-gjDAJNnaJ-b>VIg}k6kb;Je{ z!3=(3h4er$4{NbL=^(xnRUBv>vIZep(k-`ugL#JUux3w-EGS+#GN!ESCI$!%2dQ-q z!b!M^dZLkNCVWH-(Mq%v9Yhz=Lxc!53Ft%};UYXl1JM{AM}35kXdzmOcA|smB6^4r zp^O0<;UJuZo2VxmiDtq_v=FUC*T^23kIx`hfVGFI$vsM-8`({-$OsM~83@k8KL&mO zZ*JaAnm{z5kWd2}WhW%c4j0+;?MiHaDV18(Rot#ikP&I8IA zBbhL=3wKRU{;(8bY!?1Q8PC*xipv8*kD~-aK1fUJe1{|`24innIUPRiC8Y@pS)~y! z%?S=KPRgj}as1;kg{^;C_V@v|i#q^vWpBo3MTh`w-jTeI4*tsLBd7pAk2wVCQn+Tej56n?@i)L=&pBht|(P2%(71Tpu`2nMi2aK*sD9(!P zVV5f}<3J4q0TdhvAQj}1wS0AuRrFvD0vU-;vA$A_dnAE52Qg)3%Ik1q^VLoiS{*{F zyHZ3wH*d$7xY#}(0zLS&kF53Bq=B&*Dy24}WqplU8^8dHuFDRI6}@Oi*(;k+);oYf z0$($3PDqW@?1AI>Fc2$ zx{wM~YRJKjv~zpd`O+l9Cqso$V+>4$qqOX*;`hV~X@UtYE0WgP+v*gLzvxoS%znjd zA60NlK@;CB9SrR7Cw9s6_bA>{fG1oVY;H!R3RKXF>@eM~cwa*v_TUAzivSm{lp8Oh zSMH}+)!&Kj`@4v~WCF3Ecrk%>`niPS^$NZ8=Vg@s3v7C+F41CcftXTKbL18`H0*UM*zflj>ydrNm4Am*}Y>{9^uv z^cN#vEPR0;8R&`d`=_H_KTdODX%r2MJrWGWd>=1-+h zMNSn?W=_UV7EfeP#80Rva>onE>^UN?KKd988n)HP$*DA!D09ld(?D)TDis;RAGTa~SoS4OX#-C}MrwoF|yc7<}q zB%T?}M$Cv2nHm}!QidisMK{fEG&dR>r#6gjP&Q1ikFK9xXRb5WO|2cn8&i{OqHAUc zO*|=>T0OQ}Sv|Qbx@vZ%xzboUwPI|AvSM-|IxyRB_8a|E;jyq1o;0GyY@gX@^i74v zLP}_|H`+VfWA+$5Q{7_->^s>N?V9a0JB`k%jxl(goeV~Uv+ZWP(LU8ShPT2dTcfSB z0W)9(rdr0}PwPDY?Ik!G)*;*A?EjFL$qPG-mEw3r#xc_ z)H&&nx@TRc%WzFO$6zcqSr@IFb(jvrF{O{;k>jKm)n-*wHPk6(Oi`4cAN^+jD!l*i zDc%3`{r?psmi<3g+lzUr_aLyc^d3Z{%6ky@I~V_mqOA()7Fy}@_aJOR_^csoa}`xwF}?0)@ENNG|?x6n#glXb~x1j^i&Dnjgc3;zh!tID5%%?i`~ z!fLNA@pV?b(0ZvC%a*+SePxAYyCv4!I4eZXM&Y`$bk$eCOw31xuQ*w+IT>Z|^IhCp zAqxGF#U8aT6z)(+kFZ&2g$Sm1>P3qQO=6Zt)$BLuKz%&fQQ&T8pBiZdF+UUM*}8 zHVOF-^I^rnxp4B-j!+i3GpYw^g`7c%`sfe>^5mQ_9H)j~^GS zuEXPpj`Q8%!O_uD-kS0qdG4kP;dXQF0b7fVZoFwsWs+S&+BaM(b_zoVAZP$1iVW}D zw`Xb0d1WqIMWAgjvJOJl;%1t$gUJCQ?FmogU&UfNO$k3Ue){yuQ#>BRn4)}lj#UV= zg*mORAnRTTQBqryM)z@-0MvV13)8pktL`!1>9aC(r$vK#IOih zD_mKY9#tMvc)YJvqEn7jqhifoX-hO*A<5Q_-MLN3*o1$I;um%atC(e)rOwgZv3loj zsSs&5!RlPU2-qMTEK67KoV;E--?_!MJ-1fKvb$$b6hPq^9&As{8u^nDsogs z`eL1!-ro7H>OWDcU-tC{;igsp3FcV!U%aiNe!H-(bK2(Ii32!wPWpt)>HL-@I)8U+ zW=l#+xV@s0cB9`bCGUDy^+szvHURrW-T zR|vNo^Ij=$-@B^+a+Rmd?XRexUE^Y3T<}NmtMGmhtr^K7;V6to&MI;li@f;-ClHB~ zFnacWIEXtuad_UkX~F5sU%uqh9&dJPJ@|Y1uVB01g!la$o!b6CaBKh6;MAVS-#^?_ zuRUAu)HdSpv7HTC^Y1yeFJ0}@B42ZAKZf7`z5kC>`#-nBPr#o#wPx7=Xa2;cZCdHn zrt$v&`?ou_|Ndd8_Q_YBS}*MXbHC}-hVl33IrtFBy0m|V-~Z>PoZ0~Xlp#%d^Z6Zr zd^PU>zfDsrEaLxf?4KlUU2eX8ph8Es&a5%sEE>5|C|gya@`!%PYodb{BJ4WsIm|ng z)e7km`i0gYoVE+wpC;}$Oc*)Zqkt>f`Q)NYqdTfdwFm!J)VNh4`-Pi?)ds(L(coLI z5+20aRIaKQUuE7|A=qw+rO}9p*&?+2RQ`E68lAhVB!c%d<%_LRJm$eQ5$O^7gqAI( z+-sC?#7hVK<6Yv-d-v|*s?yo=?iylvvp6WXj2_`iAys&vvh=pTSLwyg$mr;Or%oLo zJ$w4W@zEoR<7dW46Q{>VapyR3a{O?lO!z%Dgx8~NKp{QCMj-{C!gXfFV)EY6qloC6 zA)l*DoqS&nISnZ4!<{tckWIoPay7g3GK^R3PDMIaev^7{4Iz!F*o#|J3L*KdMZr<% zG;W2*ky^A!XX+HHuuNfd?=Q(P78T|#lXX+i)or*RTfFej?Lj<1s94N;sIy)<1RKt? z6DP*Y@9O71P(x4~>S~3k#mhT>dN4OyMUMS^jsw^%!{`xO=>#q)>BFmH!Km?-x z(`UJ^H2h;#gxI@MH;S&sJugRwY!)sf#PpVgSPu{uJwA9lQ6bHizWf>0_GMLhY$!eA z8Gb|zPbW^vC`!MSx%(<4q3N>Nhra=QOJQ#CY)JMBN0o;$v6oJ3H+tn&;Ok7(xAZ~T zp$ciXbgN&hr0yGpTg%ecgR(QY2UxV2ZnG2aArL0>%$dZ|aqA}KVcwkJUbOrkN_qS6 zvT|<~S@#I#0Cv<#Sq4$ZPQ^I3q=}`#elR7>pDqGAt zOSQXj{F}d`5QUT`=#dI(_O|u}}o|vG;oJ zn{)SkQ&>^ONP?XV{W2~B>R~A9z95%d!UA#E;K2Cr*VrHK5{vH zi9?}v!ha~SJ<8`p%CM>Y#Bd6zt^ zSn|eC9=7EniR~=9azln$|;^2KzS@`UrD#GzA3D}t~p zM=|TD|Msa0VYYBxq4na3yan267NOPzWi!mB`qHpLsY`q*rJS)g@G?xXf-!q3SRb`7yX^ zFp)fr!&V}Bru;eA=?ckqOO`)YC6uH*=C9PF^_U-m*a2%AzJ2ChOW@PAN)6f)WG5_5 z^s^-ioW$jetv#+@CD()2&q-cMS9_L^5uz6#9P)SW9vQ_2`=R4!lH-R44d1qgT?)h{nt;^}1Y%)zdR4 zo!Y@4yR<+54cPW?aBA)N`|>wk+ScPv?GHcc)DnN;)Qa^kEseh>*#E!rs8hS~6He{l z%tZ^>hPWLry}oiMG0 zCX>a)_R&%ub^(4`4RKkXA7fNvW!-{kztJ>Wr|$0tc)a)5ni0Q1jwt zp|*umi%ZzohS9~@hW%CY0b6yZy`uDKU1cm}R<19tiCUj*k2Oy$ZJCn2&`PV6&?xJe zfgJaI6BZhSY(uq%&)#jKe5QfL#2@OFZu=aiv2iF-1NnAe_^F*kgO*wBdKZdB!wYFi zP2D5+ZvWC>%7<8y&rRKIL}^)=XzW|m&bCVUP`WewpdIV9FY$I>e1xo5cR3h7Wv$ zkPk_UFo^33S=>|>UE-!#>EllAuoP)a#aDY-NScaiZyB`{hE*(zHP(^H z&8`huxum&}T<8EYDQR&#Q53y)l$W>CRx!J2R-SUFSO{`M-rGyfVT6rXE z$JdewA09Q@(%h!W0@5o(t;?7uYep@)s+{ZOh&QseW(R%YnM!o?Z${k)UMqB%S7?V( z(!^e9Dn1_{U`8QlQZ~kyMnzSOc4S6T8ER-~HIxx+cgNGlF;i<%42KWvKCT$n9V#}$ zqG3C0aUuenIwQTu_Q*FSU&X`S5mf2GH+Pg(%Yt&u!D6BYx1Eg*qosU9(G0Fv_zE!^ zCV!J4o~Y~qD9OYhbTKHaAqcs;WR>cWG#e9@lv(=Df+}l|+8K6=UBg_nHdm!CyQ+n< zlr6cM)e2h!^Ocnn^(^Fw$p~8;Aj811veYqA#>k{Ysgn&1u=JY&lW3ilj}+At6)|H- znRs9CW_&8hiSknx>f2LFo9F|VsBi&Ng$$7rL#{EuhI!B*<*<5%lZK0ASjk0<@*9sn z=n+O03CUqD7l#OvSS1B)6T4k0#<-<~n5{9(0y0EI$S`)d})GFU8P-;o3 zGt6eWA)};flQ~#Q;?P?8FGqI=_9YG9Wnlr6DTkk&U*fpFLOS3t1J*SHsGb@{V~?CZ#Ma(qo83_M&A$O68hG#pFvA15--i11-R- z-ipB~GcVOzPnwGI^ujkg#ZFs;EDbWSr6la$%0WhPL(f(zZfD?czPnL;LEYR4Lh;{P zjMLD15k4yMAzrIv%adE7-7CB+qUwqb) ziC;}SZ}F!ob1picDdSVtc5_~?yDZl#&P%J(5|vM@NkUC^tM;|!K&cQ`Xm;L;g*@HP zTe*<;t9w=LHT<2!-OQv$UON?~Afgghojf7I$JJ1(PT1Q|x#8;6?ip1R7v{#dTN_L{WYf<3-xZYOp5?TN_%N_M^mLKeifdq7Bmlh{CP zlu#E#bGI2IJ6WidkLJ=UvaDj1qj$Md&seZzG>dvIOGGw{&gNc^Y;@hp%4Zz-vmXemu zBMt1zZI|0;b}lLcUBG-#M$bQn*1b~Fl!h;jP(?;odGM{R1Dm?KP#>+oU}1|sYY^xf zKn*mqUXS9H;u`hhdZuodRb{2!$sO#{ zW=PpV(=)WoKeIy#_$KeQ24sF6TJVevK17N&ImgXEHM(puR2)Z_VSrZ}xb`WyB;YKs zQty%t97FfLvkkoGF46MR;LkThy;S$+3&9}MG9ZPeVyWE?m%V}5PO>(4Ulyuh#n$D7(_pz z`EFAJF2X~!5*exTz8dcR}WkaZ`=Mt;JNt}-9&ct&0(SnPo zMqU9}O@P|rIbvatZ$>ZR-of&dVqZjbC2_$OFB8{|j6jI!M0uBW-3H_8Qmwtn40d9; zg1tmPp^pJ_o%u`rQUkx#!2jAB7&4fyuUS4Ov)TA$?B&Eusjp0bsrW+S zi~cXfK2JXc#pkon7vUYUa4vH$cCPqb_PO|T>T|hg6VLjeo&I#{)8S9&Kb8JepGZ$cCJOgw?vLGHJeoZkKdK(h9Z4MVADJFcjfcnc zhtr26hYN=?hhm3{_hs)>?~5eDV?!U9x@YE2<>0yavQ}N2AIz>Uu1v4U^rww@pV}7=#e1{ewx2=lm|~ zG%vT7a>>_wVVB~qpW35%y+kX~Nw}50iq}tc5#0u05PB47Bn-ka0tAR2LQ4V-L@Uuv z^b_qS5GMTRfDXcYfhi(PxO^jU=s^UD5YavabQ1=lM}aOv838;*QxfnKZG_JkSG>(h zppEDuG(1`GHV}>H0UuF61!xxlC(%N<&3&kfXgvpX5ZWZ*Bp5Qm+et7Kf|tP#pf$jM z4j%n@Yq_A;mZez%6Ta6Lm#Xtw-nq&)bo%zdv6zfaU)54V>F!Rbf4RaN-g{YP3ATbe+S+l;b?$A)2Ou7NUdb zC0xqwSV6Q9T|^(@8Uh-L4nm1CFUhY&%Xy}VKEg2t)DwQfr(lBj5+NU;L;+(2s2c

P|pFONv6&NE~1g>!}xd&B24rX1B7b`XyW@DN@iL^NIi{DjxQBn=SVQ6NMp zV?Z+zAR0};N3;`Ngh4b;0)B!4KOhKTTn{g!d3ft)0Y=~OGH!-9fah}FpnVI<>GV~Z zw;kt8PevB9+U(~y3t8<;v$`fr4{a7oh3)4!3t8&yl2R*;(!-mDQo8*-XCbRS3Wt;S zzF{@hXJYSyXESMcE53L;i4f6Y?6r4@9wx1c9zxO^CRPyLQ9v01+(_}cA$HU7Bx;4v zHu<7YVWpF(Cjvx}=pn*{a~2r5fSu6o<4_U|JK|-;5if&{cv}cY62X)N7%;@k2q9iZ z1MxEQhnGP=aL5E0t^-GNJaLnUq|ywZu>&&{PvLOz1louu6EKK6Jd4Bebth(zX&+N? zQ(|>FaA6;A7x+{GeQU!PZ!>N)aF<{`$Lqouv=6&80ZA6m^^q&JdxNjQVq0||m zj&KuAL@Qw=u|w5UkxjEuMAPhiGw`rTBsVY3@-EHtEzR;T&1zYi6S|{SW zsa|z#ern^UO7epX^VrVvF3e*)s|Qw7rMYKkt-#KT6FC;869?crxmlL4+IeVz?%km& zz(Ix3pSyPe8b!Hq^J`Mh!O7D~^b!nB<7J>3c*g=56UNJMFkVJJ5#bA)G7d^bmSbsF zaA}rAOyN$nP}l$3m%hJj{Vz4}OAY)|1OFx(IQP-9j|@Gne0U~3x#V8A{607LnEKev zBa;s&ABsL$MC^hKr>9cql4GZaPAVs6j-`)9jujrrJP>=JIFX%*PpA{Q`xE#3@1H)J zIvPHjKaxI@8&8a94v!u3ADX@|bzk_td?KBQBno52(d=k^R2|KIAn^hJ2d3YjdVl!+ z`Fqp%M((92zu5bV_hj#h-$RdniM#!GPv4cgD|=`0j_e)rJJdUJ2NMT#2h;<({fYhl z{jq(%`0U>Ed(7P>G56D>q5(N1&_ zokSPWP4p1GL?5BznoQRTC*k5Hni+O8?IG%k2BMK@BAN*=;UoM+3lSh%i8i90=pcFt zbqJ^M>q+3h1Kc*Rre4LL=(|W z^buh~9RnPMi)bJki6)|j=p>v;z)yq-&pDu#2os(uz)y4&bu&OcfEN0h?jke>AM+9& z!~oIY16qk5LS-~AC(%rF5OrfffKZb_6VXZ3nLrECL%7cYKB9|oo(Eb9eFpFn-Gplv z@DsfNT4*q>DtB;_0d+(((ME)cMjy~axW|AtqMxXr0XhkF7Vr{5!ZCIyY9TrZHOa3; z58*xs_=yg}F$J^`>I~o~LPX>2oorzzKG3eapa-IlXfl8{qL*+*0YA}8)QNFX1EnL<>Pz&3Zc#B^+W^FNHh`6gqQFUexij45UoTT(M|-34x*FjBD#ql zqL&B}eS|@TiGD)40H}mU=!Ao)1JFVz(=NhI)Dw+F6X7RXi8dlgbP`=e579@2i3Y@F z!CnUVi2%_?bP(NyK@1Q&{O#kg05lNIgr5iyZA1rv7IrgD_xyT@=pzh5jRG2>6Lo}( za1$P)foLLHi4LNNFbHh~a1!-IGtok{6J10vp^gC#!b!M^dZH0P3!9nt5q_eD2oSAA zJJCUO5#2-&(MzaFKqGXbj&KnkqJd~4yo8?!5N$+|=p?jrfKE6FC*daQ0kp7@>1M)5 z1c-K`gXkjENx(rk2{%zsG!o5(kMI*MM1W`|+KCQAnF2JTj&Kw8L?h8m_=o_}PILfh zp*DlGPB@4kFX1Cvh*mp|hwXd_hRUPvM82q)npJVXQ0O!$ca(MALbZ3w6%+(bRmNHh`6gqQFU zexij45UoTT5hS!Ip0=4`2R?Ks;U?;dCc;Mqh;|}KbP$~cpVjFap%V_Gj&Kw8M5Cne z)Nc?CI>Mj7jNrY$g6BehwpZb3I`}yyszZdyl;k%jd z#=cwpjtLL%g zS$}qVGBp{V%)gv|Ir4JhrOZpQmx^D>ekJ}D^((nA(~JD{mr`E}e<}ZB`o+kLg%>g} z#9k;`NC&1pNV~@ zn8{}188wqTmpJD?H~n1dx$txOXVcF{o}H@kTkrJ8Qy&k1-1^10@X^diV;_aj`j5mv zqJAXzbmD3M(~}>Le^~u+?n8+W`9CzBPNl=?yqPv5X5p#KQ?aLtPiCKtKdC;Mdm{0K z|B30xQ;&xq&wnue!N>;-k7XWOx)?ebNY_d9pO9j2h#^5 z2MY%>2Vw_``?LGw`_=uqeTjYkebez&T#4sK5+nYR>Ak7F;l24i={=D>h25FmvE9X8 z*aN`FiQE0RPv4fhEqq&kXL@I3r|q3Tdu#mG*;_KV#BM1LXNTj%>Tqs*V!MC) z^tRNt@V5NT>6;@r7h;)MELMzWqw%O3&E1r^$$!)Ijj0>MH|B3h-w=Th|J3#2>+{#8 zuZvt)xHfZb?Aqcr*=yq0sMqAKPF(H3ditu=RpG1hThm)3TMJiau8dt-+>+fA-=c2G zU6HuL4{!eQ&Fbb{BoXmPriW5P;i3Gd^rpzB!p6+T*v8_9?1uOTbwh4_V!eO;^t#l# z@Vflk^xDYU!kWyQ*qS2z`bP!}t23)(tBb3$tKzHFRk@XkmHw5}D^e@MEAj*Bfyh9i zKhq!UFNU+>cvubRjD+Dgru$NT;l4aP{QE=Gy{X=CZ@wqp6X_{*XS#WhpY4iwsa?6w zM5n)Vx+B#Q?#Ktz!AP*so@tM@7u&LJ@iw(B2Veic*uB5;3&;Qae;@hg<{M!DfAT+B z_y6?&7mof9>)xL<=N_)%FM-av+r%xm<)XV)($$=f({EX$<#ZgLBH(mA2urUkiYK@_~)?c1N zMk||g(X7%G+poFSn#O)D1Dt9ao`a@0EFAJ_-&?Yw7rz>0FfvepIB+s{-8wHvX#m$9nR1{69ttrT+c zlNCbjw%R@871~t_=@GUIs|^;s&zbhA%BR#B;9$`RO zZJxlnu(`%MESI!crqR+q9)Z7Cs~P2!=5rP8u-oh$x!kd)f)A*E8M z_aP&oknk=JHVWxRxo^~={Th4$?#JKHKJC`VPdK$X_yBzRM=mXd&sTrlrQL80zWlCr zY2)`ewZcxf_W0dS&2_g+n|#EnZTYEF`@LUrYU8)Ur{C|mwcG#Jt^LkHw|32+xV7(` zb!)4?=hj~QW4G46&8?$-Ws#;qMox;5pzQ;YR(8MzVn|KI*=tKH)N zf9k)>m#w(ssaQ-nyD&Y<=$%`)jE+9MRn}Wa@VPJ6(8FO=)r3Y<433+~n z^ay>zWn|-Kv!vb4*r=r5xtEp|Q>T0eMGaw-uuoV`OaS|Lz!oza+jU@g-=5fkopeIglgYHxGyNyxS>PH`Kp( z-+|%nWpZDwA@^mJ?NLaNuv=J7?&Zv_*Orx7r+gi<)(V@10U=%MUn(SD$&K&s%W>m7 z_j(P{--PH^g=`WAgv*HL#gQc%+t@qL8_P;jmA6oImCz&f3YU?>tG`QiaLEDb;#X^k z{sBa9R7j7|C#)vAbjqziB`4!S5^a+=d&BK04Ha4>7(Kl*{`6-I7g3m&VA-jau zUBq#GU$o#MV+*{6<1S*?zR|t=Mi1=Rxqoz9Y}c;Q(L={iA3|_i7B5{KeY1w--$&7I zh4cu!gv&@)5H)j&Y?$|M~Swd zlGK!u{U>g{3Ge?uJ&T6g%g|ospNFgm<}_BGH+Ovl7JCD*+0$%)JS`>1ek#27pddWm zz~4*rdU|{*t-=~w_`=7V25)Kf5J*#6_>h6)82X8;ryH-b@+BWZ{J^FQ2I1n^=4Hs1 z!j=aenudpH8Xlr)c!;LqA)1DVXc``(X?TdH;USuahiDoeqG@=Drr{x)hKFbx9-?V@ zh^FBonudpH8Xlr)c!;LqA)1DVXc``(X?TdH;USuahiDp(Z2_8whiDoeqG@=Drr{x) zhKFbx9-?V@h^FBonudpH8Xlr)c!;LqAsT;&X#5?b@pp*E-ys@*hiLpAqVac##@`{@ zeTQiG9irWLNQZH6h<4v0+I@#;_Z_0$cZhc1AtMRU?mI-g?-1?2L$v!2(e67$yYCR~ zzC*P84$o^TCvh=8gd4=I$Y-^2z z@Z~3d{WilF5e$p*jh}Q!NS8?U;FFkt;;Yf}U&gxZ#hOwy5BGfaoz{gq%UlE6HS*J{ zmDcLb=*!ET+Vif{78|Tn=0cIhHKMaLQeQ(G^fk1G_r4;#$!0o%qF$&C*a&wm*^Gwl z>lWLoi=eXYmuzDjtXq4kR8F(?Hkz%s(QLhqX6rC%hhwhhB(!UJbfASg{6fKxL^E7A ziu$b;v|kT$G_0>QbZ>gb+E~Sc>4CAHUoCd;$+Fe7fp4E*ZJEGZGUhXB*G^-2h^@yM zTXy%fb8py;3=ECPq0M{C{5G}$J*s+!TSz}?NFSsjeUOIqK^oErX-FTWA$^dB^g$ZZ z2WdGUq~&~&mh(Yc&If5ZAEf1cke2g7TFwV)IUl6ue2|v&L0ZlSX*nNUu$;#nE%_~l zDri9;qy>GD7W6?{&TXeW|ej5wsrzqOZCuNs)yE6z9v}qmk#IXIBlmww4Dmkb}D3B#W%lM z>JcsD12lto!L(gY6g)O$#06=6>3i8Oh#F}izlkRCoA{D$pXI5QJK%yV$`v@I(K=of zxnLhZuOQmUqtAeYU8A);+@PUn(yDn^Z8V$jTQHl)NNl#IF9sIQ5m-MC1f1x&Jiv^6 z0pk>3$fcQl&tk)PR8UcfR`LyHr&g;%8p`+3Lcd{At0;>m`#m(-@1e~8CVIN4#UE zaiy9px%pTSbjg~QY+VPTjgVDpcWG!ZA)nVR=%k7^tY2J9X-xy#5z{K#QLE-l)>Jto zL`9bC54)L_MMQzi7pbY<%TYFlzCt&PdjJi|cr0$pztK?0Ii$v@TzWtkH@bWP%NqX9 z#?JTerhbz8N&YwTKaBoL@dugjr@tHdZs9xU&!^wYd}|iACXqKS>yqi$Gq1&7E54d} zC6+BtX6ftiEBO~^KY!sfQ_r4z#`xIz59iXEC)Fp)Z7#Bp#vUm?oO$Tn+1S~_>1;Bd zwEgMjju(!_A5b62O%#q~j-Ht55zy9ejxY$ z#QXj4pT0MBZ}{H)`=;+n-5tIweP`s(!X24AVs{h|W)H>>ss}UsWBZHyvisuu)P1>l zBJPh*kEBMzBl*4Qy^+0zJ()eRJ;mMG-SOS(?%eJ9+opG>c7$(@-4Yp&Z;x$@-wf{q zH-&G?-N=i3GDdhk_J`JTO_cgFVZ!5fNv1JKs^k84N` zKt>EV6_iSL3#&=xP!CyBw-1l(8{QT>Fg$u-_^tzG&;AaNBZm2*#M$w~gQEw=A30n8 z^zZGTR5ZtKUac33&MM=|BTHVhvtFMSDGObmo2rn(Rb1?sr#jG0Lm@rFK4G;kU#6nx zrfW#;g}jXl3F{lMPk0$pckU?-@Vv&^8Ec1n`!_43+O4Ri&(qLna)~}m2aSE>$>WJb z<0r;X%FbTecYmuw6kEZ?R%;(R_4f+t5%vj}>7e;X)=XO3L3y4#-(8ttgZ&5YpEzS2 zdGO?+vlFLI8mCSh4<$}dBwbNBBN*^32)s#Nmy`fm6oei8E4%J!?_-dTcmuNE?>!S{sf1 z0{AV657kQwun#OtOgQF#r-tNpka?v-dW5Tl)g*^-XCA6LD=O_r-u~SR;dW!*dktUw zX@#gt4R1gX-=~ls;VR)W{WQ1L=%?s^>Ao>oKAFp>+wWDh&~EX2uZ+3huMkzKj4Ppr zLEIlv8RTkVHD%yHfq&)Gt?X1bYWfbzScXXqq}2!Vz&-& zAKft=8yPLz$0)!$$r0lw}!^vEscFUb69jRuTCw4sn5VVkg8*PHOZN6Gwa@6G%7?ixN& zChP70P$A2fU26|IiOxQ(pb6y*-&f(g4tvHQ-g$QXgo4NKr5XHZ6=LkI?90?6sHtBe zJ;JcCT9@WuCv|ReYA-+O)UNnLr}mv*w|4cnT-uMniQoJ2_tT%bwD;pZfFE94ukFRV z0Qvvjr5*V-r}lS$=h7a)-yGikfB))w?H_;O)E@j(m-er(yR>uPcWR@p0qvi^>(rh+ zet7(_ao?lH$?=DABXWG= zzSD`*kMgGF6xJrr^1kHEqqqw>F@HysI6iUq(M#UEl;(K(jmu@?jMFB-JaOU&e2<9yLaxo8{@zK_5*wI=KjbCTUI*6 z{B?~6JPy%o6cUCP;GnQt0}O@#sx)9^$KE}|72;=Wh)+Z0I)(HI*9xnNf9L(bSg6r} zk3#fTh4cuo5b~|H(_-jDRn9NwI%S;+4+61$yKUu<#PCl0ft`Ez%$WMpHhCMuZj8BMb?v>7pIKg_a(w-F$H8uI=;kG5%$b@-F^O4XK|N zsia3CL&A3>wY;zYrH0fmL(&$7grNl3C9Ecu4^P)x)9$vN2S#`9p$+i?h)vdq~DsB;zQFtP(t2uvjwo(oe*%hD}Vl^cIpaS+H8LOR!jCM&T#I z+7W)eheW(15-*f=37zOT^wftN866Qu8%ZbEHI8 z2_7a`EH!)OtYYWyhE0ns{RF8PFQ^K32o_5V-h@YumvhEzLAq(0Icx5;*|W}EwRpwy z%g0+siQn%*cm~4#5~&LM1d9pBIt%`ZyX4GSGsSAl&`+>`*n`;rhQJ9DsS36W788p* z0{#sUo0}8n2dG_tED&lYVsEEeGs8<4<;CpWQ6Pqg_-D?1euZ4UFOkrQ2ipaQ$y@aK zB6$-z&gC>W`(5Pgo;7FsS-xdRmw55LiZA7ta2|_K^Bwvkyjq{Gzhl?mrLS7N$Txk? zEZ>O-9_U-Rd>P)DFAXnSC1N=W)7mk7jAK@PouhcYo-HU0vvBrlnM=F>R3Jt#aV}Gq z;j1kD0p&bKuuZU2a3!X;SK`67;4f;6vKg;ja^<3)RamcBa>+70C-n5-Hhb6)p=|zxO*wg2h4RI1c4hw6cIA(-1^D?-T*_5f*%aHk zcIA#MVH5CUyK>_v4&@)eawsd$awvZ|)1ica=um#V#-S|n*p=<~IFxTJvMYbN$gV7b z?fMSROtT;MSZB2QGw6U_`|OulmrbWDvK^veY9JeO8@XR)Yh(qdJ^=&a4|J` zufeCTtVK;gC>HA~iIzw#5piFDB5|yPvKJFZy8@w22u((-EJL$W-{Ur?#>lwM_{}f+ zZyCl1khX?<53HfT`!)1;zs7-|GmvCxed2#ku{ak?@dynuh?kofL~o(f{OB#*^WgCN zkz#Ix%q`8ikMGFSYRW~d<%nq=_e@wvKmF^tk3zR7<8>%+!)(GlU1YT|-{!$w{wokg z^mgvR5WSsl|D(6t@qNx{vOX|Qs+@5fhiIJJ21MiZ%HKlWIIEtXzNxv;tJT$=1~mw3 znC24CIO*8`0&bYlqN|M3)?@>s6}pduYdm)?F6HJ5Gq{IB7s_g!Xgw;fh8}F8*xXg- z7iNYs3#9F#aR~KTBMQX89W0ODGG-|4!g&<@^Jx|>Tqntqs zYr|e`DO{wFe%))>eyEfU^~C|Dg5%sh0>^O-k!}{bP|&L<;nx_HBh~AsIky-B+zx6w6wy-=wY`tyTUSq;ep4QaO;@ zxVUPXa%bQmH+5;}rY_n5O9Srk(#{=T+POUl6qR{Lpr*58_G+dEe~5y6hX}1?T@#qb zB!)Gbeu_A$CTggb!{$XqRmq&zH02bT$L`p}39g}I$ZG>DrsDTN5&08pU8hJDNSssO z8nppGYrRBml-P!C;J2_niH185)_A=@E8&O&^+X#{wUIxGHbUJBG!nLLKpoLeIIv4d zM;+mi<|97BOUT$3q@$MTAgUGsUP8jQARRSCGofq;s<7P$qya62y&rHB<=F0{qk&Mi z1GPje;eczhjs`;V0ghfkBfLaels^f%52zzLh{}GTk*L@PXha)f?>ZaN6OBaKR6rx7 z1^h;|6KXHuAAq z3-5ILV6TrI+=ND@If*`|ag3#nENy6HM{RIK; z%HG+MyN2*?35#7Es=QKDOnBZ0P1QEue~vIPT|LVB>=Gq(&MF zz;uIoVWQZBaBYJ)nF$|!StX8Z81qHG7-!x(rwWIBxKtc7qN_#Nc;{2O=$-iO&;NAb zXT3F!3IuqE5UV1*X<*bf2=ZB?ZbpWh24|?6SLP*p@Kd`6mB#8*aSP^P#{mF$F(b{6 zZA>$)S&iQ={1$U&-lNT8EfR$jHnqlObyi6OC6psZpG877e*5!RD)?z;wn!Q)aY~mZ zh6d)+td@boY&g}L9VdQI$P3eOrKLt(j3{4Rc4mTk9=bJ18;2}&2aI@WS!k3*1Af+P z5-ii&3B?8235`&90A8YOcC@fx<4>Y&8!*N< zTdJ>}3MdNz2jM1K2wyKOt|mFL9k%F5Wq3-`>LEjGA>^%qhiE0-+kiHrY&+oGI73`3 z+9Kyvc?-vKY&_A%o+-WzJka|S|4$E$pgXH(a-`BpM z`d;LF{_mx~8~bkHyP2=!UkAU=rW5HB@_&{7GWKQQ%gh(?FM?lW zKTmuf`dt1z`C0fg?X%RUkx%`fray^&68I$Zas1=p$Jvh(AB8>&f0+G1{N0JX` z9*jR2d@zfBC$jfs?uy?PyeoTW;?B^W@}0?eIIhK08zUS28`F2h?g-qGxjlY+@b>I& ziQ7WA$+snM4d1HWnz|)&i~pANhS-L{hRpi-`r!KP&54^sH_JCCZwlX}-ITg9a-;vo z^bN5a0yku?k6$0WK6_naFZY$`zAAjBc4g{{$Q7}*y=xY%>RvImH@h?~_F&|W5b?#q z#o0^z7pE5)Ru17{IJ-btHk`*j6vOjUb0Ty6bJDY8vjel`+%6549U5lDrv;~FgW2OV zM~9Ed9-0mWvEKoACQM-m19@E97x8JnWJjze(2{A6H)q{(>^GRV5=cAZErCm(oA z)w^m%&#Ix`l>M`aJo8PN1nY@$5{V5Ez_EhG4c}?!XcJ zMf2wvugLzlNc3iPDTugPB2~dAL46wsp|72f5o_rzJ&oHq%Y?H`wg2g4b!f{AW z^6;-YcNGzB)*;2oLY%cUi+qpf!;L!JT_k$54yzD-i$tn|&4N9Wp0|8-;#-t05-X(h zhN(oj_Y;4e1=pID=z^&IB(hC#oM5kTUVKr(HBwX+BGKb6T5|ElL-#tlh(NRM>V!bD zO(Mq$78eN15-BfmsBWhek!V&KrN}}`VSa}A9nFUsRaRCcdb7$J5Pb_w{aIyXvmm_< z(E)V9pIK$-b0zn^bBz2{6p7xq5!B0dIjm` zb)mF4ADjNo9QDsUaawTbQN&h6oY?@|AgEm;y@F6m#dlo;Xz(avi*nfw8bGTo%Oooo zFJEC@tdMrw_aL+#B7E@HLZM`bAal4%_+cH8P26g@HgoyHRaf*{S7!>vMt3`kh&7A0 z1EQMoz|5j0n*{Zu9h_HVgg*1cxo3Ag1Q&|o&lAKA7-1KAMBYiea_%JUvzi%9>h%& z;z;ar0eS^{u&lRYh%RqTj82|C8w=Be#Ywwsiik6-aWX_SNMwy*y`U~^*`VCnqqNpq zv|`1wu@t1V+gU`EIXWK>A#D;_FW4$b8^={cO!+FKZs*97 z-05eWj2sPBTUrr$W^EkkMXM4p+$6NEgnK_Z(3*+7;Kxw6ek3Y!RXXEqf}3z2p=>_Om3LLk{7kxhal z7s!IO2#oG_7ZGTd=qV6#vP5Ec6A(L{fW=DGSZ!vT8KOL+J3V`lb~@s2lSoz2ElBN* z<#_lh_=`fz8nXy&X9Z=Kp4lhQoi}?XR3}!7`-jmb8uuV@21JdMNL6sGU@>(N-W819 zBy^!C&YBGiUnrLw8?nt{5)IMbJ&2wOp&p4;1>J(fE`1yYgYx{P)@~1WM z6FA?lIR9o-UifQ;a-7?){KsD^l%-?s%D?LE$}RYR(4Q-m+N3va6oUKs) z?y@U4;YrK8!=^}4S^DKKkLo-L&;LLCg`P@2|92YC|3;lO@1dOLp=|0U5_T-2oXBCy zNvgDzQ@%oWx9maCIf&LHk*Z*wV6k?G3ZWn>V2dir3)Z$w<`Dj}sZOXwr%XHh%2@Q~34*;bvm? zRpvSh;xEkHLS$&XM5==Ig2gh&Jw)`(&76hY1?O0Dw`@7`7hY*m{@dx>gYZir_5g`g z1sep53CBz)s;kJ)K6wuGlrbpf9n`K^v=TbX3s+gh@AmIO{ACbaCy}b4CdixjPo#P556t>Y-$jX5d zsS0X>dUggsbaOu>=!ly6$>(f5q*|KCuKfzcn#tIA8QZ@=LSe?%AWMfxq$;QhvZgK` zVghb#^hATcli_AJm&5TrBB-awlDVDZ_aORm2%RjEs-Rm?7roj{r}-(SA!E@z8*?mZX9P>i6QC^K2IZPrO z1rHG{)+n2BL&7a-P^0WwwtNW`oCmkft^)C9a`d(t5W=PinhCRh4sM&+;7OtsOAZ4C zBFqTP9A1OG&6UW51kVsGmcvf$8HQcMiscX)U9o7@>J`fdXLV9RI?QzGS)C=M&K5LN zX#E^fRwoyTFeA{j3cELCa=r9T&?(p=SS+hf{RIcIy8O~bJ(q`9tz14twx$%wG}EAG zYrK$fn4p;&>*wHX@p-cN=yK?=(oPa`W*3!)j9dTEEryqN*s#(T2sz7&N*nFya`>>) zB0|o(qS8h+x*RdAsB49gn~I7W>F5&Od1Qecv-I^xi8AR%)X3F>Rf78q7Mt+m?RfN3 z{h7!xwV6J1KBnC#!H$16c0q?J|4~N`?wXhnn3JFJV-~ILT`>W>`dM$?;-@}|;MW<@ zm+$F0$k%0=KkPcHASY(d^k#16tMHTVxq9(dw6K|Tm@1c;7G9x0sqQ?wK!h2YSy*?X zu;xi*mEit@!xfg{OlLHOWsKChaZEQ}GLvF{K7DYda_Vt5|L=$}zvQ zDPR89rYyk!-{IMR{ZTeW-r!IkInt(d{1d+YZ?-8jUbiVfgYW-d{8#XQ!;N;uewahK z75@JZ7-v&nT4h&4V_`e+XPdGT|EsREDYyQ~uGD^QS6+~9%A~Yi`C7tW0~_)DkN=Um zy@#W;y3NmOTPoRFB<3tB}l1iRjNuE+g zo?1;#t0AX5$Z>zi1`DYy-_~eAUjNZ5?FV zM}F-mzuQTEkHe?q`!e|hh5TU|`J;03-zvx-+sL2T$)7sNf5&S<$?>yF@;|D`?bT$a zhWxpc{LfnQ7cTO@G!nMi;4krFQF8pMf&8_b{EdhFZ6o@(<0RnTd5MPvZjG_x|5WH&j*Lmt{l9_A$v zZz7LqCXZ|(k7^~4ZX=IrCy(tQkCPXG$1CL2GBQ|B!lVs6(MFzRCr@^er>NwqmE^Q4 za(Xp+S`B%+lblgYp5Y>AYM_~oS#=ERt|vncw$74_uG26B~~T!^8Oa`fmZTCnngGsY9}A= zARm!7f}3QrPazX!{rNC8To!W`Rxkw0~`4rJNco5{75A~t|ULHB0sGrKdT`>camS!l3%(&GaFxN z4BA#lrt8VC8_4gv$?ti{?>CY^@RC1lB7f9O{#y(A<5uz~ZRAhe$$#%4f950qL)r#z zm&uGm{=AI*&vNn?736=}$p5yJzjTnlQpsOelE0}Ue_Kudu7>=*ll((1XlCP&E(Yz; z$ZQ??r+V_w4dh?k@!jNk=8AR*{v}WK|7W?IdezNv8`m^5L%4804b;jzg;_ z>l(;2TR|M+lwq`vp2zL$A7_OAck)H~sKc31lIyqM z9J|?na|(Lo@=b{wgEwZNMee^Lb$$4H`TE3l!Rs>LjD6Gp%~UKLlVgc!Fq*kGcCG)~ z)HUI2#p~6}l>WW&Fy(m1*dUYgZ)KhUg#v^1$WkHIX&in&j%x>g=lc zs=%uB%E(G>WpYJmMK%(T1S08PsW-7axID8gw#>gQwKTj`UYfWp2rv4vOZ}Ioz7d8m z{lt>slFZ`RV*ldQCE-itOA;3cFU~;g+`lMwQTU>b3j+(&7e+4BE=-0))If)a{d7;H zN9#$#zkc@o`1yhJ)9|jZotHc}bZ+*X_&I@d(q~7Yp`JV|bXN9E-A^@EmzgVs>zLCKQ3E{bYBjJ3A{5Kl|yKk(t`eB)sfrXT)a&W~5J#oZfd@ z@U+bI*mVE&)U@z4d0OJs;HjBYVyE~|Nu3-%Sw1;&Qt+hAiLn#?C#FsapCF%*2nK_h zsj;d4sj1_`$IHie9hW{fa;$c2@|e&u*`wn}2aZl36`_azBSS}KkBA=;I3j&`JNkiav;$a?8+PxJH&rT>frFf^1+FT!HJoJ zVh8yTN*x$JP(CmLt@_M_*aZKC)cEjtd3<93;QpEYV*B~`>xSR|_}IYM^q2^|{wF&_ zomqbzKL1Va`%p)=J>DK@Pq#(dw6`HNl$RYOOj6zy8_E zcx9k6twvN$O*%r3tUYcI*weO%O|vB{LKWHaczK{aT^1?R%92V*$;xp#Ag9sAFRh$# z(kWQ~pYY$JzYG2U)*XKlKlHaMyN)S%t75)o*@rJ~jx7+OrzP)zLGOd@k%lp!`jlk?vv<8e#R{99DDMTi^u!$uXojD%NH)0;PW4g_f+~1yjGv! z+iyRgUmU(@!o=fxmS4UMr-k7Id_SCa$z{tg#CETmkBd>Q?!5@E z=|$v-Z~TO#eOEIRMiCxYkUulO!xte{fG?7Yt$6mX%D8+iY9d{muck9jII%ldNlP!ZR1$yeMJ4HR zSt`khudtGW1-UbGyYDLLgpwsJl`bq=Nz9I=l1?lTQdmikqe^VjbE1;?y;UN6(9#xR zk+|S5+8{MVH%W$h2YkT7`)h7#c8Tt-UM$q~oB|K}^tFS{8KCFv>zN^u?!9>$M>#YxfmU2P`KeT|EMWP9(fp#&kwH<&U;XEBC?|gU(&n07iU^~ z+DQeuH%nvqO62l5)w<+?*^hF~4;mU~-gwmL(I=NEhYI4ogR0WpZ~`S~k#S0iGN>lK zLiqEsWXJSuYm{nU%+6B_#F!VEz4}Eoj|PcU1#1O$w~LpUC!3#9yJU|-?J79?)H8x- z1-h&b)u!!1(5n#9A(5(}CP=l(6{wwpzbKU#pl~;LHrgYG`SIg*6SWBw1C~{XozwRq z^BqXDNgoQC{60}4Ib^Xv6#PZ$&JO-u&F(-yWu_LRxupTSM^9Hz7j`IFv|^dB6TYcB z(F@?p3Y%Z7TI4&%u%zpm17}Ug!3a$3_yFhoT=Ues4t3V35ai1>yzxCJtz0Dzj^B@8 zC!8xTKOen>`fY>Vra_{ zjgE7AiIVgVin_7>u@T^3uAF$xkTau1ITs0?roxp+!!5K?3l=eF?3I|pB}aW#i#41V zv2$jD2p-~}**`xynRGXIPm{S6Gn@i%a$F$C#*#Rr8a5CBd#xO z+OrCZ&n(V;-?Y0+lr-9=9V$`ID4X`|y%IB$roC%Ui6T~E(78e?Tt&yN2mg%b#2#V{ z1#?T5!uzO=G3EcF`rKG=Yz)?g?3`C1#Js}nrQa33^rxbi^7}-I9IluCV?@1l(*G;H z)aprbPc)ue3oY;MKJ@WhQh2ezC=-ytAfGnSKg=0NRu* zR@)T!$u{M=>tP%4pS8+qbFgPXr%kE+d5!XT$flg=wWLB}*CkaI@>Yl7(>Ov=3~9oV4dg&PhCG zRQ>rSOJP{r$xxl3krmoSD7Q{&&0_2OEGft`$UNxZsc^yBblO4{y$>mG)L0O z`bau?UyY>3h&p-Dh}u(7+-C9b`w?|PiIPSZ~gT6653qK~~(_Vw6njKNa|jlth2 zs0OoI_Wc-qX^E0XI|g4?qMT8V!Ati_%!tO|WhIIj-59*QWGSNk-YQ>^z7?blhcehkkj}E5u^6dZ`;k=MQN`p zEpa0vzJ)h#4}q3;xAN-wHl=&1P5CXJ`ES58zYm{pUTRb3ooiG6_zmdr!xmuNm3Yoy zZ&T(xWm7)C+^bx2ChP+)u_+JDw<(8RjQs)U*_2Bc*%Zg2@F}p$rW}dq|F0f{J;9$m z%KzfI|DLc->B8ry3v9|Ic=nfi5#Qs#`SCR9|DXD6v+nS@^(^T-8$%*sOm9f{Whxvb z*9b?;@GV)<2ltjLA<^4qIpH8|K6tiN1*YO#4IN#UM*%xgMbr}RKEO+~5*>up50n!s zQA5bv8AiB?Ho`|#O`R)M!{xY07hP!Py=yy==1TZzh3{(TB;gRb4k0z`-~@UaoVZRC zL7m+^sTmGw;ourM8iU{Nj_orL=!bV#IMhX;AHUsW2xSLQLD-3EqL$Ez2JsWcQDbb4 zAg4GnVxYDBO33IsK& zK)x=W_|?|di&J}1Vfh;OBPf5Cf*w_4Z7ntgLS^HO>&e&mR?MxV!MvbU>}2)`Xy@#@+?idKI;sYhbSKSyC1K&vM@i zJsBOnv!q%&lGcB!Xic?~YT9dBg_Iin%;&(1%WLy}(u+%7mZxohnUBqb zfP9wixLnJ}=EBc9%hfgTJ#1;9n~eSwNB?+gfOqG3E_*F3B8(80%4|naQzwwmMfna? zrW2@o0-n1!i0v8l%-7>Q`zE+#&W%#KhkYMTZnncicXMk$;8<|3nKGt|BT(F#PeoI{ z1_m5P!a2kt$7bio!oQKj;ZJn+jqt=a=$(uxMs+Kk8FMQPRaA2s{4wJvonCYFxnFn| zuM~&cyJtw=T=S^hI74dG3#%gE2Me#%PiWfH39T+frVr<33#?L9{Axsj8f~%yLK|4X zViyhJnHz=9!85nTh3@`8=WAWxEC83C;_RD2SJgbdSL8}hTO)$qc?q`enUWpbbwGr^ zT@IbJqY;P_P;syZ4&PBYaQ=*2Lv25X82xOzXo)52YtY#=t@6;q$wRXx4^4lrVJ1aP_N%Z)qD??>pj$x_fS9GLq&5BwZuKt=k`$1+C$xD4;7Y$$}t4Z zmprNqXat5%w2XZPJPm}3Ed@LtqLZk^<^rCY1!v-7!cSE7@+VQYk?03%i8i7NdkuKn z2=8`4Oc=Q3Mb4i-O0=~LyP065Lap)6I>Z($g;&&}=1?=}hB%-1U-(HkcbU+qB#2hQ zNtGBGjD3AXmD6<5zQJ(wFIt{n<)Yo;8d@act|M;k`6{RNp_j&lUJpT=Jugl0yfmNl z(u&PX(=;#5#Jscs^U{*bOJgiA?WVjPM1>1zCOQdE7eG52FO6WlG*^KPfVLZ6nqPQn zK;cz3@*6>80xvBAywutEQkmXM{dF&u(!EqGhoJeA*MW-ldWdmEJu1@cK=paugr87R zk>2VBXW~46pzvv;>7{w4mo|-F+9P^t-{++v9nuY`5;Ey0>@Hv|QMLe} z@sO8hK3*EDcxi6prQL{^Ru^8HOn7PB;HA#Kms^9?XAyfp6c(i+1{3jwqsB(I!Fu3^DCIjdmENTk#Qv^*ryf#MX;-y7`8NTtO;78dH6CZ{?lt1);C;dU}gTM!w zZ^yqK{C4*J#QUN5<@b}Ra7s(1`Xl}R{`7mX_X4n9h`$?rH~fzFPU`K*+y1xHuwDqf zm3cG%W)Kz(i8n%T$ZsTH55tBb^;+aL|7+=2W3Xb#yb^yU_)7NW#LJC74#T1$ z^;G03|5NEFW3Xw+Y>96PZpl88fK`M1MDp?Q85kG7cV!eUh%2LHe-g>cov42ryVeG;kJqym?cFxqZx?#(ZoEM&#nG=TvLm2i8 znOR$BBu`JlN+CTheQNrY46G8gll&)UgTATh;}gdvj}0FiJ0^Z~@~G628CV-+4@(^y zIW#^cI7OSBniQGjpOg;xyLu1qKgf09f(cvqm-g!(+Xp)Vxijex`!#>c7xDRh>5f=O zpd$lYfna;KEzuTgliM;aTfOPVj7Rol8xjqv`ea?WPJ=B#MDuHDSIiZFH9&^*#F}t* zuqv(w)vO}{-GAAUw1@4QJq7K5zb#!6s|ZwNp#L8%&z2?1LS-^60K$rfBqN#|D?Z(AA??7UtX`D)Tw_+=Ift*|Jr(OiIPV9+WLwT0qyo5dg~wf2 zmncGi13#Q@gJqBDUDuQ>We=~dEkbr)TOh>fIFk8-bT?jy+F<=h-A#U$Za)UKOL7P6;xHH(VZuJt8LVOECGZLkR0 zxuHNv;aFRVQPzf?xj5GH`$WOv#@dnSHUxV1wI12N8Eeh4w=})7J&(P{7(7_N?3RLR zFso(XkHNQ=C~34~@NFf^8QmCsd&yEpF$UjJqL5LJ!5jBV%!tO|c!?rLHwNEXvXoJb z!FQD`WHe*&-6cyI`53(Go|1*^Nw;CLo@G=19c%t;vG!kw&le7}Dbv>2l>fxq|J7Lgci&)Bp4kjv zf`9fXKb#H!eizyl=Oml5C1O)fz}o*$vG%_z3R{3atpE2((w`q_UvwJQ|G#ft|KD+* z^ex{RBEy{*PW`h90h2aX|>E zZwr386)s=td$=}399M;@*Z|SG$Sy2k4GePk&XHRDy$BzJbr7-Lu{gD}3wxlms>Fu5 z*uI_1X3fZeUmR{=Ok5%4#>iYF<2v#+_`U)EL%2+AEsikDg~p;;+s4z74Ly-!UtwG) zb_T{u3)_p(h7dx=bWhKn$++2S#6lkmqY6o`9fy;#39%8e2SIIBQ%{#_2P|G9Qf`RM zg&~VLA)pGmz`8WIz2&-~u4Xbg#a=`#c6}cx&$WX}C)hriU&7%dMjV{qpZEfF4r436&>^lS&-wH8*W8yT;F5Ynx3N+_+(~8Ta{6#5Rhmob z!<|&M$21v<_v|rU#)%bsOq+3H^&Zn_oY<1DiA|`m4Pu>?{T91p=c=o5Tdt`TKdBP^ zrlO#qh?e5Qfu?$bj!H53S(d%&gw#Vnq8|GF^w2@1rs2lMbhjFly2aVC!kY-#~0bw;zXLBAVWK~d>-x#X5SmQw~Dh}4-&XNyC zU=6R}2!T6-h(bevCnp4F)FFV1JVPz@GZp5!IMvS7ggCT`sBDaT9g}99!$k0uyv|h> ze{K?YPrbA{cr&Du%rqlQWoX8OSNZ8|*Gqr7Ui!E7)}e7@aT}1)2E9(ghKA^^Bk1SO zOYd}ECz>Qy?}0`xpjM!9dfjN@UI{JK+kh61g;t;n&D859=rT9I>g{qdCdNqzcUZ$l zOm;@1@Ol|7+}q5n%61sqe3NRLYMN_&C_d3{SP~c_SR5z|1!rlZu&kkN+s~2I_JS+) z3;fP8dRgYnv!NH-6|6trzbv;no}r%wLH@ooq17mbC2&#a&q|_sT z_i(FNPanh%43co#cuVFK{PtVpsX)Mf1@U+pPrg9v@KekGbZ?s}srTzThoV#((U4Rz zl|+H-a|{*pf-$1-pVDg*Z7NskC`ecD8B&!PmeBT!X#?>By&;M=U(q#Jf}8tusYfZ4 z3Xy7~QH$7FLG@kdO5+w4mMIbZJnXlH{gdjT;#GH+x^=^Ka2k~ z_>=Sx!{67w@BeQ4>-bmU&qJSuKaG46_}KrE|HJGD$!{m#kE8_{_1mBk53cV3} z-T#{ZmF!E27ZY1!&!wL6Kb_tZcp|Vll}K&!Kb&|l`9SLa^nK}X#qX8xN!=B{Gae6b z^xu)VEpTfJ`U9z(`<}>djz89w$n?eG6*9Xiu_?4k-jsYK{c!Bz0K7uR9|}H{eK7H0 z2!0`x4}>4k5MKnIA=CH8?hD+P`Bt31A@51wow_THxDy+*&{Rm@65Ei3mq-7Nq3g3k z>p;6^>Q%jK`&YYGrdC8&_*bMOG5BN5^u~LW%frjH<*8*6cw|g3jV%o<&0H3TPsZ$} ziAzJ5%9keLl~MafYDr{?e~G*}37?GVMbU*_;l2x8=S9!nF~4ta_iU+qD|{p-PTx4K z|DB9qurKW@?#SRG^A|D()C@~>BP9B@?jCF?m;SQ}M&>m=u zwZ>cg%>i$)G3-e;$QHeUWUW-yZHtx#$}&n^3Bn5?yy~rfwEc8E|G)BE^Zf=sr=BTI z{Cc(spxWTcQT4#mV8+MiYYbsR~Rr+98>4IIQ2X>VX*j4&pSLuFTrHY$MEk>0} zSt@<5t8}@ZOQ*aIAqqji>nh!@tMt0A(&@TNpX(}JuB-I8uF~PUN`LDr-L0$iwyx6I zx=JNFm3opYJ*}&Bw64<6x=J_eD!r_$RIyX3MX6FVOr?i)l@8Wb`d3%!UR|Ykb(LP# zRjT5t)V9o}lbU2|Cqcz4RVEaojG$9>l|I!~8$l&Lm3o>gboBJykkTSLr`prTcW1vkaA!X|)Z=rL&zOR2@`(1l8Wu zPGSr}uj#6U$%D%IiOOlXT1J!;R5nzpPpVQ;PIVAeE>kOsDx#XGAvm{DIfWNK(pAp6 z)jFb{Xdv8#hiD|cKrWq4454D9O5Ihpm1rZ{i4MX?_zCJhs#I@Psl2C3U4Tp|L>W;| zR1h}8PB;jas3fY0YNCd4619Yj(1<#s9>}G$fgx^!x|b@|YgI4NL^KmEL@Uuov=beK zyZ}%LsvD~1L(E#Mq>1GI> zo2!ikU7M@)Y_8I=xk^P*mAb$x)g9G#g35xbkDyMUD)j;~p%7(6IZ;7y607oAO?40| zQAtqyRIMgz2q#fXxCo8l+&7m_KI*BQxvG3XQ$0i@;U$`gW}<~?CEAE~qJyBva#bOy z^Qx8;6@-nj6AnTpDhc{2SF4E{f?BdF6`@sXeX4X#uGSItKrWpP3~>`4qLJ_t)SgzU zDyp^+^h>VNExAgsD*S zil`=P2q#fXxCo7?19IuCXGjC#Cir-zHWFTmb6L^V-EIEh-qMQA`SoplVUCmIMh z;UO9cFVRFa6D>q5(MGfr)K15}4Db`3#27+`PP3{IWkfkqLD&d8L8W$;b_*&Mx78}5 zny4Y1KrWrN3~><}QAgAh4TPJZcDzah2$dS(Y7;@lYPE%ECEAE~qJ!`eexj2YLyRS; zV~^VdKs|EY9ssImVaGL;Jghtd6)Z)i&0&o)^ zqLJ_tO++)nHxal!0DO~x+XK)+_y|AINsJ-J64Ew6CKRHKCF18VH&ppf>_kx<_vWnuunig=i((h<2ib@Da3Lz}yX>uD&`J z$fZ->ju3??Bg%;i!baE$2SMWpbXS0?{^+g%b?H@e!p(X2g4bNHrCyD^>W5GL*eiio zGB3yBRUc1CFNI!;z8H8hlZ?Zwes*hOYiO&yH3`4^+6$@YN2ZM~J(=7RhJXFk6OkwU zPoy7@!NY!Lb9{4fbM~iO zOqIPiac}5e`QGF`;d``uQg=u0_QUJG1fToiJGDDg@krbculuo$fsL6v;&%k$cRz7^ z=yv(`00NZpf}rtPib^3Qh6&O~IS8HzsZj-6-Ffydivp z1`qs^>;2cKuZvw5fDiuoH;ZY!OV=c?4qvTZomv-J=Ups zg$!@};kDY@)a8-O{qV;hTN7B5Ssh;;gh&3ws?e(F%D~FZiuj5kJn|Ye)$8-GE3u2gG;lQB`ynHCSR7kG<>NB-~5qp_`i`}A}vWS4lmZ=n?G`i z|C02@v5Ny2XBNd51s7#6N?a7WNWLh!FuYJ(n1YXf|ApyrEF1`D;H5vfAlsAZ3H3xT z2waeXm;T`S+4BW`frI6HGz{H!2+^(W2@ohhH0gui}m zerjH1o_}6?t~56ZfBo8=)a=M?|Lk-q77Bzi-SO@qeD)`1g=WdKk~72b+MhZja)$qm z^o$t%_GeCypB_9tds^bO&}q@>f$5oP@oB+n*;5mzhEA1FO`Z}yMT7VL$jSbb(N)mx336|FP*~V#frI$-s|) z@aXJOiK9YC$?)VKK2kd}bwuO{KeX#(hX)SN92P$;2ygz0Lqmr~rv#>CCdVfS;mtoW zDKtr*l!QlrEs*Mpbosl|@aZ2oBy({5;NZd8iHV7!iSoqcLE(cm`1Ow*=sz%hfOJ4| zLU@7(zy6W&{_*MkWBUj8&+Hf9FSuWJTw+{koIEZ$Hau1vn}UCT{}?`J2RbwG@E`PN zeF`lVgzt))YL_B^^+AX=0 z@b#}jyFXIzuTR6HcOm{c}Q=__Z6sqn5rQAUWM)c5+#jRh3$b7<%~{+?ZJ|zj6#L& zp^}AA#i-EE!D_N$Q6}B>aLH1bl|l_Ri^+yn$Ri~R(Y5gk4IPS_Y;4*qF%ErTFc}@n zWMgMvfe7<#)6T&M)hL^EFsMrWeyCtEWvPkM#OO66@+%ggqxl)r=gckeFE(g%0e#bf zA+``OcOCFeIsC}U6JYZ6e~+hjQytgz9dnTH;DZkyZU9>o?zwEq%2mD|41qK71xa7H zVpR`V(Uk_e1H1K!`?UfQX2Q&&<_siuzC@~m69tP6HP{Xe|3Zy#@z zC~36qawO3*aAEt(S%Gv#Pfr!HPF%vE05{Xm=CkpO;`>;Ho?0Tml4Q875 zefxN~L`kDZ|dJEQPOCe`iCXT8D&%dXs^VKsHuNk zqKMHo^-oHcGV-Rr>(i2j@L8$wt&+9ZS{w6cB}-ve3ZKXZJS(AZ8WWh$3xpK*+HUmJ z^%AKHP88hxUOPEIa_st|APr`k_IT(_g|0C=kT0=+Oe?T$MgMFx7rl#S(|d( z=?-N)Z2#Yf-~aQ^u_=FFVpHzMet#3Muqofcet+jaX;Xf9szX@;9{|sEP)>YWra<70MGwj2|WKx_0q~i zpXiwh{r~%{`v2Q6l=>Dd6lvC6y8S;aM?y{&tfbwD_yuRT!UCiLr*t@hR@#15e;k%(_3+NQ&(7OYwg$V7;y|%D?;`< zVg5(!6=Btdu=`;ELwgq3Wr-`xx^xEsqq@i|Es*TAjG-G}YdY+`7t+5uMXYn`7S#>} zHB|#};moA##{DfD5n9=|fM*-w1yQ--oO?_S&Y<}lWzna+FnVKA;b5Saks5iS`3)k6 znIn$2BXWNokLGNKM7Yv-q10kWl=<)ipmrzz8^vJC6*Z=ttLZgWi?eEtL=8IV=+ZYk zfCym)4m&3Ju|SCkGkcNyN}STs+WVDuchSpr#458LsRtysA$qTI?BvjsE z$z>xB56orbz+6g(Kx-~raLT}9b>#)t3=&w4gGMe@92}U-W*mf7uU-h!4&4{MCVE6n zaG<3caO?Xebco+B%h|;S$U2;~zZ0j!;8c%MkHL?iHWyHhRL}*+Br(kB-n>>+7Tw~hiHSpwXkY1}Zi#nX%R>vcohY;ezQNIUAYYVSyz>$u&-mus{ zM7Tr{!!`#a1UCB#X(J$Syijr=4W@JZI*dv64G46i{AlGW20489JD)&v_3P%K!eV%f zuo<_GqB2@_unre%BRP8vL>*dAQKBCR>u+{l1j7{xMl^^PeN#h-=EjK}8b+HY1!+3I z9v7p#?KuZyA!@QhQ3KLckKiU}*8&t34U*|01)g8@`=Br#wRbN-c@wq0Kpo*Gv@YD5 z)??VBQSKxRV3Sy;`D|4i}d zE-r_>CTnc9!^LJj(UG633>F&~Ho6SwEy#LV{c!OYzsv<66IE;z95D7+E|5tFJkyK` zk}^COD;A1I2mRL^YnLeC(qKx&BF^?j8%gjAzCvVQ<_H_`yFv6*VM{KOGr(TnIrUtrb_-iD#|tAJbQeMCHVhUjH$$mpZp5$&KMsbM zDp`W#4BaDy?i+%qiK!vv3TF_!f15e8lGY6T;%%3MQY1}$A`$Qt6*;{UHJl=t4$ z)oa05v#%sx3BBTfDg9y$)-L{JdTVTJU~A_2`18T%yS|8glK3e7o#gxB_qG1idy#ki z@5J5+yzYBBp4|Ri@)_yL$P-f^izj>!hwk5gPw$=E??~S+-IBg3c2nTS%nj-5W7o^q zCBGSrX0J7O4bZMiT^YI3YVna;6_5uY2Jn++vG+3rNQHY;&PY)1O@%xPPvWll}ORw8>+ z5c>&af?3!@$j4`n4IHZ-lRheTWcY~W;qk*Vho+{)CdVg50*S8JA?bsY6C(#@50GKE z5ZymHE;L3S6Y~fBiH=Z5xLs=xwq{}bpKhY90c{Mpa{#RhxMx7NHtcj&_1h!%Ohvpr zRTfhMcmptY&M*Hq3(x;Q{hj3%#n!O&Kv$0laC8~||L9zeH=E%coYmmu2~L1BfRMN! z*TKsecEG~6bO_=oZN2?@hV^geiFQj>Vqz>}^5Q3F@P?Z@xHuE>>JR0$Mcte=4eREt zS$A_L1ax9kE<0xCV)SwDfNQD^7|iHZ4evQbU>yS8O+-5}hA6`pWbSIhMYxG3qQ(bk zL?gB_bGHyaLdL#iZW~ca)DrcCBMMX#HQND=@Dgo=v;(Lh>WN08mGBXY3vT;tL={m> zIHm&CghsfDcA}Fg?*<%1RJjR?+++v#g z45w)$jsY=Q{H|H!a&*smJHmMA_-_mV#sJ@us%=ZW2M--4Na9& zFcTA}H1rzI*qE#lKaS+8t9Hj;U0zpQdTt_a3~n{WB^913M~fzkLwv8eQRod%?^1ld zTNsJExV(`^;whfLB2#N4w_0)O!(XUk=80)3UD#HlMvdNL#9D=eekb7~>IpZ|NR)Ts zeK=?88^rr={moO(S*m4{N@r1MhZWY$mGGRFYeenaEcLZF5tS8BQLcK;nQ=~fYjNqt zFH%P$iS2|<%b1JjB$n?en%}&{Vi#8xmyApD4cYn_k&|pIE_u%v+lxys(k2JxTq!Pp zq){|4fXli#nzr${nai8jHAg={?_l@CTNs?1p&#fIFr~Mf2gO>B(HSZb)aW3ph+3ka zsOdUS%;d}k0*)91Uhn5bI&o$_HfKdzxa)4Q(;R)68j2T4SgN7){L}zP#x-vRDz^c( zMDy13;S4S(qpbgYysT3ZJ(mme-Z^Eia16SMxg@;gYU{Jy&e;GhR}Z?PJU_e8ofQvv za$VmAd?MzJi?=$w;x!7heA@+5D<{#$?`r&R!)BA_;q4bljmAO3dGg~L9J_dkuNi>^87)Os9(mu0JK!WL8|oN!t_3^s@?m=m*s*|Q=2V=YN_;`g|G zQf)|iM`8Ay2pn&@#)IDz^4GW^&OK1dIC?D^M+Z6M=;>x09n_4YSDA5i4>OMbUB=N1 zihiE7@w>tAX1`8+9r{}SI++fqwRCD*WSf6m`m5Mifv+-O#=i`Hnf)U1Md%Cpi{$6w z&$Z7}pG7|Nf0q6<_G#eL%qQ_rf}dnRPJA5tSpGQqQTQY6qtu6y4>KRcKL~!1{dOi5 zPX$xi{zQMMU+z!77k*EBFZFKZUH`l3cVh1Z-pRZje>?bg_N~NQp||9>l5d9J)ZR?J z5qZP^M*8*G>w(uZuf<;rzLtG8@oMN*`PJkr;a9X*QZGkd_P?BdDfUv}rOb=*7lSWm zlZj*~DJPR#!&|kjsTU$I_+LmrAA3IVeCE0MbHV4b&nBJ?Ju5$(d?x&i_Dt&O$kXua z_f+huz*Ctg<4*>k%x+0+32l+LB%cUBp*@j$Jo32z@$}}{=D_C6WAVp=k7XZCJQ{jb zel(c~C$vPWFY-wI!Qg|*`@{FAzZHYOzWCkYySlzBf32mpZK*HQU!*_RKFfTP{8;`- z{!shC|84*K>HZA%fJ|cd$JASqH)C(aUeCVjd$}8FPQ2iMKEG#U=;_Rs;N#iNiOr$S z^5*1Yu}71A{!Kd`=)ZTzoxVG|Z;9U2b^Z2e_qzVe`Ch=kD!no$d_ZWC=+Yfa`WAJ= zli!YWrL$afGoeU#a8~k+$c)Ts@za8*Wv9ocZ9QrGRM)Y=qqiNtV2V6B-Zk~$9R~&v z(8hO<=_=U$Z*+bHV(x%D(-3b6He~A)^`UyJ*FUjaU~STwtn2HjLk|*Ix~E8gB?js_vt!loZ;4Shc4nGe$$o z4@#CoJ&a+t2(k#-{lfwwMvf#?{X0}9Ne@V*DmYPa@3p6H6frvOsedn7$|$s_epa%O(P&ToN6At~qCI5{4cki= z!mNyR0LqjsW#j|UuAi4IgjuOF$1D9aY8^|hL(G4cEQMJaW`7)uklnv15Mrjy97|_o z6kRKks^CPyy&X#fJyu2e|0+m>nWlX|mi~8%l14k0{<1_lqjS{qtCFR#ffNp<7Vjq3 z%K3GPLiF20p{+zwtFhngm6$@u1VdQ`?fPwrBJ|tBaQfrc^7>uLQuZ*GT7>NWeSwg| zUONZwY&aSvXDK^fUN!U?5vk2M!j{+fu1JGOy zJr77E-n4@g1^0dcnoL2)gz}#SX)x2Y4+kJKTh`C7pSLM9XF8N$!><22=>50j^L5zw z&x3vcAF$uwdg%O*!G3>lVZXl+Z2Z5N?obw=4V``H|8F|NrW~;rHvZ80UkaW7ikoc8 zgRt{&JjJ2Bh`s-2VDG0OK3`pkIOf=t-@@+yX6XIKCcz}Fsrr80!)|Eqqlr&K)u`~EC`7^U?;C6?A`2hsm6QO@WF(SMaJWfX(x z&Ju-;auD6MS7Jsqi0&>?#OMZ5sX=dj<}0R=cF0wD8$Yb+oMq~>OD*MW(sElYy6p%bBP&Z5!nR)c7-_sR z(H+cMnm|>_QrOlDhf>QEv1RVFtGYxX`fZ``IkM;zam`+dDKtbL>WO%_vp|I24)VQr zKKkob5(x+Y;Gu%WdM*5Y;@?R8sO0>8TB@$LAT4Iv_I>Yll_+Vny;mzy&Zs@R)s-kn zZ;*u@xM+i{-zzbNU3jPlxvQZ>5&Ar(u>V?LtXiiK?vkZ&lql@L788GqklmgFA%%VG zO!TK)B~leURB-S6R?a=8rEfJBq{U3zzVBP!5+#kcZ#9)DXViVGxkN#u>{~5+C1yl@ ztF=TCqw8C3B}*B3-`dq)vJg%t3U7_pVM5&J&8|B1=jX8bzXUe_GCm)H&Hv$7+mtUK zvMCqC?*CuUz;^#Lhf;-i0FT4&|AeD#%1>bLzv6zIQn}uy^ugx8;bVuAgs;ET;OprrbaI<=)v93#8xu!II|gv!zaXrUD95S>I>FJL27qMB$S%A!CyVI%BBB~e8DU}eLw}#K)8uU!b`LetwcM~L39#QKTt-L6AnTps)-t+j&KuRqJ`)nIth6@P)3v! zcA|=?AzVZq(LlI~R-%pQAbdpQwmDL56Hzr48wa;z3tgc}o^KlRwn0I*!9mr7gX#tc zc?JhH4-V=W98|OMyux%f_8MEg=acF-tsL?}_1jFM??tv-`vC{EB8|*$ zGIYE){C01AgT!`;UXG|CZdICBODt6ji~>>*t-w-w#_qt;20tZaDm{`pavn^iC1FL zBThULF}4yract3hB$4QC$96=IB+hWi>|rOSdUFWwhm?NAxZh0@7SU}aA_I|;1V zDPv_#I;99Kn<-;qOv(`i%PgTk1+d1YjO8t5tZXS)0<1tOHv+*;h`AXic*? z4a+=!7?t#pj8zk5ESM-`4MZ8sAIezyP{tyLGS)AYv2>x#bP!m6kY4`;mi3ddqMwXq z`edxoCu8|NdKw5Tz`A%cmb#O%%AJgb>tw81Cu6xf87t4pSaeRtdUG8EdZ5Ymo@ih(Q_4j>%YYOvaL7GFA(t<0i1|7o8vk7WuDquPYJ8*(ZPz{2FVQ=~U^tc6B z0pCT)Kmm220WgONJ8%LS)PbsQf@79bc>_1_fLc%w#1LTv4j?oWZcqbifwh&8fEV~d zC1KcGrh^{mKm`Z^dxCI+Y7hi)LX#G;JV5-GV8SR+x! z@`&_|5m<4MY77D^3CdU=P{zuDG8P4-W24gui{sJDk-)-sGS;-CVOlzD4igUG0&Y+XD!U1mp=X*0GEhJe)B$UVkboUnnh6}2;GDTY=AvN*nuBZ zf=0m7{oZsOgcHc12GoLj4Z6`=wlxzDARMMTzSQQFT-^aZ^e zAvn72Q651*Kod6=>rJMaewyu`hrd9#@o7IFa$iOzv;UIfW5wx>8jeu)=Qy$ucaW>v zPr2y}IwE>!$o=auKO+Q{e_tqqt@r_zyhp)=hX?PNPM zPsN^6p2|KMe^M=Lz4gA=224H>ejtA!bs%z}kV>bbDK?eaAKS0&&)y%uU#0uFllO)1 z%kN9=i|i}xP4A8FW%p+8joquh8o9M_OZt}RE$l6sWGty9vx#^@P2_G)-W`j>)V>c={W^ah!px%(XK6!ok`uy(H?#S-Kb?NJ(*Rj`Su8m!*T${ZnevNuf zZdYk8M}BXXEj>8qakkJHj3Lt5a7;t}bj#Z;NhYw`I1* zwklh*TjE>PEjd~%KD;@?Nwk_VKw&ku&mbunoXlZUqa!GheezA7{`=a!s=puGeW?^ihvM?Ks zN7ZPqHQ5?&%`ZqTh%6|~PtT9eXXj@wi(RH%mYo-$*WA0tAbUw>ZfveHH#;XjN1ciK^R&Ww>GPuJvFByZjh(BU8<`qEr+JEda`(hT;Y3roDL)}KA$#`z zv)acujbp|h9^H9n#~IC|+#|ai52-O#QL~|VNDbv0l0#hkZ@@A8?yx&Ar{suSaHZ)! zL)MjX#+-^X>xes4N6wzKhwXV=$`-K|q_h;3SScgML`BTf9sa5{CnSZiKzI6EB9=l$ zx*}S^R%G}Xukcwe&Z%6EO|oH@VXVKi{CpAh|9`9Z`XBxOp~P>rYyaLps|M3;CTN&3 z4!y@#tB_C(*a z;cxP6G#RPfCeINj;}lyWsmM$J^*??8NRwd(KYjnvQHBuuj_GH~6|}Plm@Boj1ltoB z*xy-lCUa)ut^UrE#gX~5BMWD@U9@EWthOfl-!{ADqPg>1+Gd@wEapi+*0Owb+ro7_ zcWvLccz4G-S|+0SMeEgDHm%uBU(Q~)X3L_Eby!D3U#6{ObHs?Y9rWd**p|r7o!d99 z-nDZbt-gU@+p)9v@6py69Cz>OdWNA$^dcJm)Ah_DMWTC+O8+IC4E~=`I{1F?QH?ek zYb~>mS;NqCUivQ~QPPl@V?~ee^~M=vGEVU&XzT#%jiW!WC2_`@jI)Cpl(wAIiS1_a z-*}dkgd1lvT=5le><#O;UvK=7!Wg^5`s&v^dX^ys4if+LSA07?*RL@#Qev<@LGx6v z_&M_TjfcLv4 zL5@x}1Sw{<<9Tfj<+AsgwOU@o_5=o=Dz9}9GOtY>Twa^_m(FW?qQhd3NOTiR6WzIn z;?s+B_!HfELyA;hqMK$iR=J68y2&`@Cb}6Wk&p`C~$TH@Pi3_y{>`l}=mC!bQqa5^wOliQZ-;~)Itg7K61wRmfe>d|u_*!x z*nk~40QyEG^yf+FAklYq7CQGN^p;5I;gfuX81-W_04hNhs0K9v-6|5g0wwgVNazog z(7__1Q&2)Li-ev*i6g`qkIf2T0RpfB5lFxW&@m&SGf{F8;#L`(ZbIMHtqLCT059+X zKL~(IPz7oTad!}#wV)2vg9gAR2o9hdNJ7`8BoN|lR&0tu0yba=4&VgnG?LKKDWT^` zLT{(!CB&4E)OR)I$KwG|3DChLp;J^sFO!6xQK^m)AFIb^17P+OEI=oe!~^t1N$5S5 z&>bbA3ssT`@dX<;?Z5$?zy)NW5aJsiY9o8SNsDgZhOC3I{{ zB4PCl61Hu?4jcfTh!Q%!CG;dp=mp6HWlCjUf=@( zLOiDun^mA1)PNwU1$CevpjT8v-@VjGh!>8)ChI0RLf_d7c|1}9EI7Ehvg?R5sJkA^@Sik`uQ~(PQfEA!KnqEhQ zoe&>!VABa)Kn8B001xm2A3!HIy^aXOehc0OQ$;)?0UNLb2XF$6 zvyd?UN5WtW34?$nFCn)0u;~W@PzkC)HK+kWfbkg;#tlgrq#2Ud{xDd(bPH{^mL_HhsVk0-zF9fof0# zf&e2#=;cf_5aM>Wn>IPXg9=~)0PX za<3*|4ZoUy#a%KNoBC4j#pH|V=})~7Io8{sc`o)Gdi-P0D$i!0i9e%0lY2V(bhx+Y zzoS#_%sv%=N_{H#Wb(=Illdo7Peh(5Jf40$@_6B~^kdP-*vB%DMjvG##awO5$Fh&a zA5kC4J{*5oeK_|}@}WZy#vW82%pQy%R1fAJK#za+K>UDuAeTy}!m0fJ)c(l+!u{#{ zqxZA-r|*m2$KIFO7u%=o%kGWuRrluZW$w+~6TOGMCv$h~ZsqRmUGclryR_Ne@66qi zyaRK*r*4njUbroNTlBWVt?65%x3V`d>Bp0bZWd3E^e{I=A#$hN}P^w#KB zc57x!Y>Tobb5-}|)aJKR+`yGcvORsxGrCts*Tj< zgQ;L7Sg1+YL~GcZOm(bUsm@fzs+6j1WxP_Y%mtExaG>3<_%ptkPw{2Faj)vdT>W8B zUP&ooCGSqTBkqEnmZLID^Y_JEiYx1kJ5^`y*a(0_wwO(^Wu>^JN;xqphQ*vUX$@QR zLQ04T1xwlzwXl{hN|37y`yT&iFe<{-tU8HT>4=<)9WpmIc z-U(bl1{lE0dw>`CfFEF7B#)83JO)Sd7~abVK`p2Q^#G$Ld5rtzF?5p0;9qLvT*B}y z;6Vkj00CfNB`*SuuH(|SfCD_J02UwsD-Z!jc+wu)uA3795=13ahz7GMP;kO=G{w(Y0v|v_4<7)Ppc>SG zAgBd(pdK^;ww*vb507>p9_>6l+Ie_1^YCcq;nB>)qnU?CGY^ku9v;m+w1;Tu;nC2; zy8#+_cr@_vK7jTe9_>3k+IM)g@9=2f;nBXsqkV@*`woxx9UkpFJlc17wD0gLU^)m6 z@Sp-%fB>vO1QM_TJ8%FOL3=1;+YJ=p0bbw(eh>g?*Ws%`4G4l-PzUNk13hNgQ;nAwYqg97Ts}7G=9oj=Lw$ZG^qdA91 za}Hk#(451gIfqAc4v*#>9?dyCT61``=J3pZf(0DlK?Se?0a$?qY`_j2zzJMH1`6;1 zFYp0BL3?E4S+dBuz&+Rr~npV1tO4u4cLJLIDreuzzxub!+U@i z_(1?vf+~Xcuo~MnAP8zf9jFHlAOx7h1PeG&0W3fORv-ci*nk~4fD^cY8z=xxH@p}4 zfFA@vC8z?`1nprBwrfEhs0R%IjW#?QZFn@=@MyH*EdY%+JQ{6yG}-WIvfuXLz*F@Mxdm(LTeY zeTGN-43G919_=$c+Glt)&+urT;n6(9qj`o$^9+yX86M3uJep^CG|%v8p5f6v!=rhI zNAnDi<{2K%Gdx;nc(l$?jwjGMLpfgCL$uFOmM73IL&=puy9^~)0_`$9+GQxi5@?s9 zVZHbnt8FQmA-5xLf-0>mfn`b->p}Fo%f{upS}U=7sblz|u}sY0%AHJd+@T zz`CE1K{Zf;wUel5qFW*p4h(PSEp+TH31_35ws}0jX(j7&qEM@Vh>{JUP#HJj2MwV5 zFyTBx)PhD(jgsY2vUMm~0VP|3LiGV}h)S%wnP>#A1Ytv=dNsOfs{vS1vQiVut`%j6 zLJa|Hf{;523kp>LRv>~9P!8jdtv;PgC)43{zBAPs=`1{zek%GD`&8!1*pteW z*(c&ps88e`Pd*-gJpWjV=36g3nm*}TK1cJfhab*AlzJ%gP~pM!gV6`s2Qvp_2bF`_ z2jUMf4`dF+4jiHJ`%Q+c`OJN>`;_~#`{Mi5eYw5Kz2Uw2dsFvD?k(Jt?&pd=e@E($ z$Q^~-)3--&XK&Bk7Q0QkEqiPHR`u50Ey-KLx8#$lWF%Qgq!ZBuo5_hE^=MzRlRaec2|6tx+}Lcxih>o zzazCHvZJs)y*;{}-JXfZ;z~T*5vSGQa#y!stz4bm7T>0B%WX|=4R6hFNo|R2DO{Dl zDoW$`Gn-?Zu~J-ole#IlF}X3kF~1?TA+n*cKD|DwjpuJ(S6G`~8(qt;&8&&hT5{Rd z@zv_;Tr3$2$MWr|_Q(m>_sW&oE8 zLF@uW8;h@=pPQMamF~J`#Am28a?_L3!_)KAQqv-avH97l@u}+6+&Rf}!n6`zYD#2E zVRCwMbTT_RGbuJnnbbKkI+2~23CF@pINKC&Qk!xUk`uxc@@J>cj+|XMD}7eFq>mCj>!RLb4`XD)Bv;N=iVhl3S$^x)^`%W)MSYA zlK4E+QOZc-mzfSyP72{%jYqmmgndsua7oS9rPV$vsNErdjbPbRUiFskoD2z!PQ5Tho?R&_ihcn(m6J&S%2VI zEu=p%xwl%HTv{zHG!&~|%)?(TEgDj!@~Wl9CS#RbEiEw_r`&33smVAdtEFWo!tK~+mDOok}0T3Ts3N*UGCD$_yAsg^D`9i@zF=?c?9%BhyFG#zE|)lyHJ=^!{1 zmtKqY)_tWl?Bo-_H_%t5a{)e1>j0cX>jC607r3ivJphr`14z?)02BWxa9^Rd09Mn- zZ@w&WdtVZ`DcAXF02JLPfHeT<^HVej;53>8@Y^&8V0;SA6-f60JoYP^=a0t!fAv;@ zYx|tQ{rYK|Q;_v@%~65-SDN>47mfRuG5;T3^WQylhIJWT|F`sx|L^1e|8~=5h9`z* zL@NDP`hGzxvf}mD(U>8K{yX~ng)Q{%;4NmW_I?4|6Bu}^_Y2<{)cXZmPiipl7w}`l za-XL*@igw;oP&Ee>2tYnAWGj2tTq&yUWmj0ZeY!jB9-@UV6Dkm<-QwOXEIK??*`VJ zj8mM8-8e&QZ_X*6M|hR=Hdt&h9R;sa<1OF4@9MRav?RzzlR=7aY>aOK2E2`ZlgV(! zH#WxmJ^Q_lee;mQNP4O&e(w8v`zn(mif?RA)zTO)d3v^(jxxZzfs!Ccw;F=zhp%Vq ztF=tsp=D}pPhjBCGc_&QFqlk@ANz1Jb#cvr-qeljw*gXjX{O$0C^Wqghd)zaJ)}tG zW$F%-vC7TVag%Y%&D7gX#wjmT?=T&uj7+`LbP&AJHD>D4N~dJjrk-7mCkiT3S;aQ>Z_;j=x##@W2W9tdHIXX4lPq- zdnyC_%hVH?35mh>35DAt3oo8GchTa(Wb7t-Z>|6Muw?F~`UE_bqmOM5Ze}I=js9m> zx!zEodif5262Dd`*iRBj;{-x^ctvy~ zbpTse2;5IL3fwJp|9=gAy#7VH=bz>Pke7P7mzU5swFBfQ3*7ZP1zI-*n35nzZ!-kZ zpHuyf`YuZL-(s%O(m%GRGVoOC|LCBaRGQk3tt2zJ^nd)v&87ciIlhm4Z+>1ay(&1? zQ&akW{&qvz>SaCrRlyxYid0@zaHq*wLA3W`aS)yuZ{Inn=Ar4N{lQ%su1ilG0gN)MWhQ_N*_9+dtY zIF~(WGF&m28E0Va_pReYLkeTOD(LgA)^l)S6!dBk)SBmm=E?UDpg z8suZ9gCLg~Gk@u!l%$!SM@>h;p%~w5mmEq-kfV2A|7%fA%kt%k=lT#|9vkzR!K!P7xcg`wz|r*i^EB_@mDC3CbDH<>PFe@Bfj)lm zT@Sa9`u@+PF#w;XzW>W<48ZTH@BaYx{g3#yzhWsrIk&|fYhGnO-I3@7~h_k zR5m3+j=o?BqQCt0%I0ROU=A_~t+K&(69fCJY(_Jq6YmUE*~}m00tLr^&Ripl-ljgd zcJ$IZ127Rf%D6XEy)>jq#<$3)UZLP+ld;Ne zD|y9aoO0VrUNsq~STh>a?|?1FubB*2tW=C|miv9%|N4-^7~d`T^|t@$8-@_Z*ZeK? z3V)rsReQ~2yNQ9Pdd=qs`GpS$V$|2n$oZU#_&Y zGmrhcWVaHln0j@Q_CNzIirPC#DZ{Wd4GT@SOYooq2*3&?U;}pG0GPOiX4WO#zyrL% z4=OFc`U;zTK0ue~S2JFBAT)+c-zz+hT5>$a|fK^?kIuHUXXavk* zf(0DlK?Se?0a$?uBwzz}-~dkG0y1y|1$clD1V9z20d*h**lvOYJg5K`AOI^6fdp*8 z4jjM0w3^$0H_32pc>SGAgBd(pdK`U5KuuQV420Vr+^0)zyhp51UBFR zP9OsXcz_QCKozJ4H6RFTK^Olht0Tna?tcNUN9b}0GJg@)(Sb+#6UB|NfC|`lq5@cf9XNm! zctAA}ItT^S18G0u11gZZ2n7Uz2oIaY-SL?Pmy&Gy;~^7pE5)Q30I52SUKrOwg6{rD0Pz$_=XEUNV00WgIz0so0x)2OC!p0GJ zm_0(9qd1aI6`}$NcyO!;$J_CM12};T$iM?6LOjccO*b|tE7-_E=hdrNsM`)2G-<;~2;V}>~av%T~B$F+I=V>BaR z`qk*Gg;!FqL|!SpoPIg_GW&AorPxc#OW7CWFRCx*UP!(Wej)#S>iNj?h3C@GMW0JN z8-6zbOzN4)Gli$qPe-3-pU$LXX(gTQjML2ixu=p(g`dhlnR+tvWZ{YQ6VWHwCo+%6 z9#?~UK9-kZB8c~AJB{N1U$BX<|>O5YW|i@hszXY5Yp&g>oWJJdUJ zw=-qV1DL!id{h3$)QyoF3pb>1h~AL6K74(CcWQTJcj3D9boV8Iu2rthUK77Y zy(YISxhuRYzcaNn($D<-A!j;&T!XJhf08q2jO+r#bo zwp3fBt#D=f%IHZm{4=XEE8ABpE3+%&E7TRa<;msY<@sf)WszltrRk;7rR>tolGqYu zNp^93vAQ_7D7h%SD8DeZFtV@^O-G~AL~FP;zaX_BvY;?OJwH01ou9cZcA0Wnc3ym* zIxlx=^3w37`AbrlL@p`JP0x+aW#?w*#O5e-vKPlMRxi$7l)NZ>QNAVB5@{*SPS1|c zX8WAwKh+#*E?khlAbJ6NLFW9}`O5j(nemzG%-oFRjPQ*7^wjjo^uo0CwCFT;TIRf1 zpELazrlhAtr?68plVg*W$=ONqN$RBB#N@>A#C$jvj)V(M>85BC+s|zOk@1Cb>2c9< z?6}O>*jQz3c1(PXYMAlg%=~}J`fz=|E>#z)E7YcIqqS^pCKwAU!E8;uMy<(JC#%EN z`KnY^q^eMvu8dZ)m6<>+paio1xL@_>d`Vx}m-nW;5pThh_C!6bC!@p^MajD3Zq=QW zlX6(jyHc)*tKdvKqfXYDal{;oBWsV_ReR2sw1sVXDJ4auf|wSgA}eOBF{@(D3UNUd za+aheY{^%oDk2pHKFvpYmd|i8PT{hwKL7t`f4}FyS5g1}*M3#J{zw16+Wrgei{4(f z&zNi^$>6D;e>5FsfKKz0AV)uM z2%7C|xQKRx<=5DQ-8QV<^JXJIEF9+MqJkZ>QdNcE1+2n;^FqEiX!o%P0{KX+f zDzDx7OD1EL+wS~jlX1#zcm9gWIOVoG_onf$nhaNF8vojm!VD^nf8At=^3wP>Oh+jr zjsKJBAmya-!=|GQK8^R}Ob5ZC81GEzZy47%O-I3@407_qZyACZYovRr{`oGmSF4e* z-Ne9C)kuFBY>hO~?1g%b^w&9k;kOM1s~7a}S4{srq)6peOy4mXtK5p|yC&n5TQPml zWE_(f)4!MuS7ycZuR{tmsEX;|Ook}0V)}Q}QOc;8{=;;Taw?|(G##akis}2NgAA%- z(kqAZKX+{txK&qD-~LvC+fQ=CREzMT61mEV@^zdObpR4>vVz*;&j9ZpRwsngO?rHPewS~{?_PD=;Y)@kX$ z;yNuI{1J#XcIdY>vD8jWhoFfScUn3Enpk*;{#wxvY-8=6mJTewLw|wRerf4&Xkrnb zmJYur*5YaDsMo}jJQT4LVr3qRsOf2gQ_{3+IyGfYMboS4*R0g6 z)(mRaX*Otb9r*hdnu4aNY14FQIyGIIZcVRdKr_@4!(Z4BtD4r5K}~Bjw(B(61h$=; zisp#Jc!W6uSxrup*R0UAXbPHEO;JJe-nqEzxre8ClS*cm2 zS*=;48Pu%RtkbO5Y|wNzucQ5!H5E;-reCvCvsyE#S*O{c$+qKnc}DR1G;4jo@R_w>NRnx8+)Z`E2aY0ko^t)+^tGIPG{=1?q{bMTWAvx5vmXTfb zGzu=xI$L{Ormti#@PW!h>lo2x)4o+r+cMWhNTKzNYzI!F_?KN=?~nO9+wu2YbBb~3 zD_LlwKP3T2Q}LS}+BYq&^vxg`0XRB6N~cqB14e4x+MqAtR-V-=R&p9%#La zAJZQ6GVP4?l(s2#t!AuJ?^9`Uuc1SCuVtj-lZioG^vxT!pRDPmUwT2?tffu4qKgoK z0=%FW)N5bj+4qA=AhZ%9uz{+M)%0^f>?B;Esi6M z1_}t!Zp$9*`*`gyVC)qAx#EFf43&&AR8%wsw|_pqS3IuzPWsy-{&p3p0k!yxTq{ul zIGixraIj)=V?3CQp_8H00V49<};I7i0d92tXiWDL%cF*t`_v;+p{$QYa>V{nd)!8vqF5g42! zV{nd)!8tMp=g1hGBV%w59T9=SIWh+4P%#h~oFij!j*P)MG6v_!7@Q+x0FI0SI5Gy{ z$QXblV*n2A3xNSRG6vwt7=S|uLtp@oi~%?@2H?zTkht5?318`&vz@fq+FaSr!02~cV)A0ffyrD!#VBn36fj9I#6Bu|SW8e*) z!~_Q3P`V*7@J7~>t$zM$=cSf`UHU`XS$g6_+BtjTLnUXh%{5$SvL2#%!fWUCi4SRK z`H2r{=lqEe4fPdJtZ}s0LGcgkFAeQgapFVTYvja-v{%fD50$=tPQQ%)s$WJO533L7 z9!fqGeklK7>cPl^g@fsX(Sz*4%mc9pln1g0;s?|Nxl}S0{)?_kcziTM{D#c+vFnxV zv%BNFPacPG@>+!I_FOy}565Hujz5TBrCycWoZKAVoZpn%6xmeRnBExO$ZpJRh;2|d zWY@>ntLx+I(rXKA(ra?G=3sHWf!dyHOVV_V(JMn&99h-1GQLt>nOl)u5nhpBo?0GR zURai17G1_J%Pfs8RhD)yPA!fsE-XqfiY{UoWfsO3DhspGcvOw%T9ajsEXdA@&r#>( zE-qZu)e>(}TXM6Lv$M0}v(#C+3k#8SBpL}dcU{na0dqm;`OW8d&rHk=(b|FSGng5j z)0?MvPfJV-P3tYUI#q5JH_*`c$$&T2o4IjeJg^Z4#@iE*KEU1QtFGGjZ(G>_?~ zbpk`9yUuJslR2~VjOH`CMH ztqIueO?X4zE>F9M@pLN9O1C@V4!OJJcA1eoUCpj;XTlkBb~)M|jHA=uZ11)uY$02h z)J~JSbc)Slw>4o6S-XUGx=Xp!(roFjNK}L>y7+dU;XAozuA5D;A-0QYXBcMng719w z3QIG?{D!`ue|^mV-)*}6WbjSyJ$chX&`2}j!VJBAVE<)03JztEOBwvY5TsbJG^~Q* zX_IB{qfc)$_mh&g-K2S{-h=NAuJ>TzwG4{A2OrJF4F20tYCu=Y+X7Ce}L5kfR#ts2Dga5`k z;jst3x#y=Q!xg(Zj5mh%d&m3#4JnLdD7wDxc<=d{$q>bEj#Ew8QF8Zb&;K(WWq`hc zk|0NaZU~|uzMiX7TCP5zn}i^}wqc6m#`Qb2)<}hGNr;arkp}VMvk6%hkUy z8LQk}{Y#T^%FWfkG8w15T>Wd)QOd~GzcC#IZx4;Rx_59%aY2ug6#ZM%QE({66kSs7 zlni(5`JKri#cIcxpa-mWes3~dvDz^v>wc@9KMX01aeAe`s-2^MG=wnb>VuS-zr;MK zh9f~74B=PiiLZdx0F$zuaw?WT8A?vP-$3{H(-?rCtQ5H0Hq*WS^!dF_0vDzG|9?#L z{@+A%0C;H*fPcTn%Uw%j02CSn@cI;5M}Wove2?b+-?3QWoNH;_Kbiw@CVk{+-v13x z)BXQ(FZb0}n*Sf`|Iz2)Z>#?Lm2~}oW^eyLuKyd4luib~Fp2&ri)H-9S7BrCi*c}L zP}wtVvnB%-v!?NiV8E=&nG9FVn#TI3->k_GDU7kg=__mYRG17=e6wz>Zc2w`mb{Pd zv6zm6n$uXz^wykiMW(2x6=N9;S5vBJ+q=0bqLy1N*B0sIf0`cyJ9XSkYh* zbGho-zxRj#5|g=(IbK{nRzq>=#WzrPFXlm3FWus2JqPGBZI{FmO~xtaL1S+3KiAML zvf4jA*9`V}iYb83gwlVB0aJj@WVm7q81%%{_92Ba&b!xV3UHVVQA`2G+}U3WaGH*S z6ktr5eW!pPm+2t54lpLn(nBeIi%xyX+P`wow4DqN#h5co4y7c>QMVz8es=0j50BCr z`yTTcDKXfdqIs%pmLF_38`R9ydN%v0PED;C%1`;=aOM)D&H3Ttc>NI8NxeSyvYc-LnF@>?=U&6=u5@RV-FKk)7Wa0d_)&=wC z&RWs7C~{fL_H{dVZQm9e-G;fAcW%0R+pO4@Ev4`1>I^%g@7O>oub7IA@928xH!cl^ zeeEsTdXuq=`N8S zg|5|U?!T*O?mvM(cha^0Oqv7mJG<%no#p`ifUf-?rjKP-ANLEo?%zw-{b$nWEUo)@ zC0+mjb|2#~@eBc;X@#RjI7WhFZE&0&j(5PbobYUn?-M7;u*nU>3Y_SH zle}=U4^F`#K=GUaoLULbt%B!OlloyytHDFlgK$PIoLL9YuZI^jz~&H)U^t<8VI!P1 z0?uY>SfSX$!Hal!aRr=XfpZ0Ti4|Td!g&(B%m(M%;R1|K6kDAz>VgYpxX29`D{zSi zF7?7?KDgWuR|H7?FjiLLp;cAz@@jZR4ZJc4+c5r7Y_Ef{dbqj)t_i`lDqPnH*N=c3 zM#7Dw;3l@6+|0qNc(|nkZneN|0=(J^J21dfj7xC44eqeRoesFm39oU%Yh`$y8}3#} z{V=Zg;GrA5@J1iJ2?I98Jpp)gB}`PoWHr2{2HqNkx7EVi>);*r@XiK!R|wv%!h10C zQ@nQs+&dEPV-Az|vG9Hl?&o2u0v@oy2LyP~3Lg~VLlS%#LrBF(?C@g_Qa_AGop|Um z7kpfXPq^We3Vg}~JH0UNgHQY6GXeN)C48<5K9Aw4;tMtK#UOmC7QS2uU#W+$Ho(_H z@O2fw(FhNXfSHl-;~3#8zRAJ2c=&b&e8&PmA;5R7@I8^#595;(9{L9x{FEJj+5z8p z!q2#17skzsSvUNw0zc=0|LBFE_rWjt;THq&OBiA+ez^*Mr5b*<27WCFzs|NVW5jQ8 z@Sk{i7^88;oCSVUfZwvhZ;SAsCHNg1{H`5-&jJ6%N$Q93uNccK{+kT{-3|Xkf&b}& z-}l09AI$sVe+A$VD&c=)2(b7+)$oTk@PC8wN44HA@73~erO3mp%PlFpjZv18fXhbJ4QK+jymY9hpq-FhoD=9N+a|z`$;bg zeH`@jFi-(2EwD;})mF0iI07{oK`jO)SZjlIc3AI#4Ne$xK~;v0Za4x%uEmiaILZsp z@WC_vaC88Usf1%OE?XQ|4ae8Ovx4yKS~#H&Hr2y$1Dwcok&{?BnS)b!cn*eki&HJ| zTmhbECH2FYCgP##5}aX!Gwtwv2fV-un_Vy>!wcPTmI7yEz_{4rg%|nY#eO&^0OwZ1 zORC_d)o@-7yetUk*TMyLu(cjW8{onaT*MqE7h^2CxP*gCdAO_sF1NrH0;wOyN-G{( zCBn-kc!dpKX@_kN*zSZe7hEmFHEy^Tqus@I9=P5MH~8R2Kim|6n=9c}Rd7o++*$*- z1>x1Tu%iyfF>GGk-T-&7-Q-RV?&9G!74TXMyiS0-t)zY!*Nb@Q1_|D1gE!gX9t^`5 zZ+60j3npcFiyPjmz}r0Vb}zic2k-R5y8`g;N_bBdycgs7#l1CfUl86`3-7Ok`|Dw< z0Uij!2UK{FWtLOL!NG@k_;3Y$1UCkV9}`IZFdntyp~pn{xCEcD!6)tTDF^Iy!n6xM zEyHKr@L2^u=Yh}Tb_0>tRv};X!Q549Ugw70={d3?+K)S7@xG_p??tJrzH4k8+_jmKjVO1xDP_iy5MJJ_&GQH zM+JV~1Ha&fU-ZE*;g$*U%K`Y6O8C_(__b>I^&0q%ApECVco=tAh`D1FB;J*l@ei;9Xdo#p;6XCy0@IP$uKke}Q4%qF4c^CXI8UDZx{~Nb- zi2vh(KlH-?^}!$c;g19GCzbH0Rq+3+;m>N|{|myO*TN&XD?}{R!(TMOUxwhXSh`0< z{51!E!^7WJz~5Qm?*&pnj6YcM&>uzkCkYQ`skDPqI&@pNKq>e?0lPO7j%P9%CO%KN@*7|FPu9)Q@E!i9NzT zl72YyaGvfCP#K za%=vUuqCew*XB7bx8X7%Rmp4c9CPx_|FO&vEXH)d!a!ou|_nu#z+qyLrN z8JdT%aBb?^@U=Obg;2RBvn#r*Kywg=cjk7)cPKkD+oRhH@f3~z&vh^z>8m4G=eH%d zsoSz!V_Vs+=`E2h`KyvN`aiolwwc|Wrm_F|jmeGb#w?BeXE&tRN7m=pCD*CzvTI{& z_pb@l=>Is)IGBk=V}nG(&5ll=896h5M)C~xjMhP|>dDfafUJ^sN8EXu5m1%0 zu9%B;rJWIH2h9bTu}AF%TZ(1^%t>)ckuo$7V8NQQhOIf81yB((mZ+sba{z`ba(tXu zXa>M2S71|Yn9b2E`)dPrJMnj0=z8oJi z{|vPOUBW;~vsSaemLRmSjXS9&Xz7Bvvkgr^(?i9!A%yEa*b#<3(f4flT7Hhl8fh}t z;0yMHQHBu4f_;{Xw3>mEW|bxib{(@-|6%>J-e=m@a#`!*6*LlR*1ScnEwk|LV(EQw z#sJ}-r$7Re)52kUA_EZ)oz8}T)Jlr~gIf%`sjX%C@g3;pUp)7J^JHJ#@Rt9%NoYmIYf6y(f_tZ>(=br zzD{4Ru;iQ=Z#r6x*>ciN1p|&BILlAzFF*e02bQ|wMzZMw-g<|?%rLyBfR|6Oz^txK;$sbAEvzV1xZ!BB%5 ztF!@A$oVG26<^!Ns;%D?a>0ezN!G(q(#%wrM z%Z979Y>4fN3>=PZh_xO|vf(Vlj_5l!T-ngQRL{G!hZO0=Y{=eh;U0cn;9O6N+)Fg) z-z=K*ubamE@1{BbY=08CC;m;~Cj6A<^1Dai+UVn#U#33%m#DA)V3erlU;iDnCgAflcHj#l_aycGPo=T{U!uPMmH$n11ybMtJ@irkIe~kN#{G{wAab87 z(3k@n1Msshfm_ola!ixJd4BNrr7^nx|IzP@Pb9|wpTYdP_(kH>nY+bgxs;o^FESaY z+{}Hk$vEaR_naX`D>HM?H66@U=Dx&axH2>Mr9%ocsLVajWQg)I_hqJ|3_f%B%r_kb zBl1o)L3hcp=AH$nqu@|ZF+q1pkPli7L5!8qTFPPqb3Z9D*q*349F-7Of+(qkqJ|yO zcWk&SAqv&|=6~UkBAr+XF#{y_MJ8jFo7fkdj8kr6Ut%(jxx~J7NYTnn?8{6CGnLqv zn+#WGVqY<&FoR0$D@}$dFR`yO9i@!Ke!1x&Qh=Bh3$z99F95)YeSUOQ8B}g=sPz2b=2x1MJlh3 zT4OR+xpmZ9lX1$eqt=;>W3G-`Z#tT(zK{(j!xgIyW5ZFuEjb&96vo(KRML{ueylBE zlgSXy3o5vm&!_ACJp%XbqXM`7X9Cx=SKuC^kFj49xUN^|`u#DH`zGDzzlFy9Tj_I} z?)RUug2w)Dr2F~l+TTIf{!h@gf75qq{{J7+bv|AH|KfImyW{gTp8q+4d*GnRolW=s ze`yU}-!BrlqpJn((TM^#X}iGvBVGG1%hB8c-2#_P2wXLNF#B2Nk7LK*wA#|j-2J;^ zenS4)#B8JHI=GGr(bo&<^G;?LrM_*$^nb}MWZOzkuw)oq{lM=tN zj(&dx{cmF~qQ9_>y6xuEO_E#b@zM0yBHG@gsi{u=gdjrLgo`@BZ$YsSyx@AtJ=r;0h9eyi9?Tr7`M|BW#W ze*Pxj^4-$Lbq?GQ7AJ{L=RTW@(G(qiU(`kwLm zDLxBrbPv*eDg!(hOXzuN(Mqa?Y1Ou8Q7O}^1-+$?QYt<>#^Xn+miLSs{{o)Z#q?Ls z(Bk8HEdEV>FHhXVS+swx^po?M1@v2UXkQmF%jmaJD#mgy=iEYEl;tKm(l+{tX=l`o zWBXKkMxC#fO7U4ALwl<~XMbDI${OZsI`{O~)!*(j^w;qUIXTDtrC%|}^XjS2{~h#- zx}Gvr8@;xWDHip9-B+pipMy`XH~PvV#xfdxLQYv#68#F(Ip)M%*GjJu)O>3w_ZI7? z{xc=MU);m-CzQk(ruem8LvzG zfA4zyTJocG{cqggV*AXF-uKW$eb@fCdu93Iwa9#!&&cWP{=v75eVEUKezkb~3TiCn zlD}*#nZ8fQ^Hg7LUVm%X{QVsdGGB~ZheOOv`e@SH0oPHsN1N@{$67pEv`30Rb8`E! zo=cBkF^8y~H$=UAxGpWWDHK~!LUb1d9!Klw4DEZPsdesn>&lp8?F*}DUy9e(7o6g6 zOdHhSz+T{-)7x$IV=kTn`uVVmuKKT_pF}wvKN9`S9dp8QocI^EQyJ=g1;yVzUS7pg z4KX+hJ(6BJAqM;3M5Xazx0if)ukk-mTgizftoPRpuE*u%=Q2ch*d0I9{<=$l;vie9 zCJv#c>d#a9r(3H|Uz(jRfzu`M;g`VW^TbcArR)Dmz2pD&`sAbE|6gq9UrfEm#eVXz z_O4c4$HqiT*4{viiiqh7NkK*&EUxVuV zHn`VU={5R?Jp!UMZyH;rjs5S(uj#Mo?E^n`-DoEN4gY9~lgqyN$lv4W3B4?aJI4*z zvlc#fULAj>^!;p|zJC4i-?^WTaJmFem%!-~7+MK*T0j4zb#(pz>fhY;zp*x*ctZO? zvERkqd!X6c)$E_+egoq%7~43E-#_^nht`^)|NUZpk1{*my0G)uyP*Ewr|G4pfB)oX z1=kJwIN!gv)(8FQPCh42w?^pii}f-(eFn_k%*@h48Vj;x~|9=xWG_xI>!_fdV8Pi{TY z_jsUZ_jGH@(5`V#|Muw;I9&pLm%#t6KYHeRn*VRnAB*3|{C}gmexZF)oa)9nn@;Ic zoFx-O_G~seGeU9EWaEOLB};LZ2D!>~ke$>mYFzKL^iWEs7wg$#I!cTN9~fs!D>;e)etPP;_NQ8| z4bZDZVz50?bLhEtVw+*Ln41kdqVL%7=i0=OB9)hGlO|)8n`>_|8K>M_d#lMf=5pcQxYrQEm}{#j%L>fRTCT{&(J*oH0S?a3k9x`<^lY4l;;17 z(R_ie6tkUT(r2cFV}AMLt2`U1|9|=)ihKUIGyY$1U0qB$4D$jSdtr^=pL9Zd@}v*( z{(+PGnv8ul`aYN2#y#*c4exjWJzj(|_yz`Lc6xlk(8mYprK+C=eVv(qJL3oRqdoZ? zIz67CSSH7Nj`TCaOfLI-J!AeJ?w-(JLw`-@hq2Bxp6kW0i}NNN@8>P8WBSSue-Gmo zjL-IP)enFE@eKNr9MAp5M^2A#D1Ur|UY2?e_^6!~$7`{{zta0Y8%~dhIMr3=>F=E` zfx(x6@6j=ljdcD0-P70qhU+c-;I@AAluO9WIKlz;N>-u76Z)@UT->Mu#nO#9IBmE31xBbER`=`&a;;Jxxonfcj zD~@0D>*t&CTIQp8KACOL(2r$s`RC8szG3XA7|M(j`cdl7=tm`k{N>v`^pZLL{1+cN z-3BuJZ6JDC>u2F`)kDK|7M0&dq94&fXV2+2lfhpT|2_TWH^2X%-`iwqXTI>KlB0Gn zXF|~>+5=UGmoO~}TQz;+Yd|fi1NEQ*u-ya)cu)Z>Kma0;fDPDz12};T$iNLezzcl9 z4+5YPRDo(x1A?Fy)Pn|~0)|;iI|O(j04orI1Z=<#9KZ==;06lt059-?0H_32pc>SG zAgBd(pdK`U5NHG=0P7|=z=H~40RpfB5lFxW?7#_JKn8B001xm2AMk?!s03A@8q|Ow zr~~z&0fc}G8o>xK5{v?DJHY`SQ~(PQfE7r<2JFBAoWKQS;06lt059-?0H_32pc>SG zAgBd(pq`*JumRg4pn?%#Bw!8`EZ_hSDu4wDzzRel0XuL2CvX87xWWHt?@ZvEIM4h) zGm=J!C5=Y%A^FspkU&Bb59B^Q;RqxIEN;kQPrv~Z4vQ-s36YXOZo=dyrXd>VSHn0cZr8fH1)H5IDdBSOFV> zQpn@l4mbcO-~uWDH{b!hfB^UaKM(*afhwRHr~!gN2&e_>fO?<-Xad+{1P-tOR=@`E zfE{oUD1}a3yMPM719$-e@Bt#=2LeDPPz6*2H9!!k1?qr$paEzEnt(7M0W7nG5(iiS zE5HMGzyUY`7lBe(fonJ50la_!_y7^`1C>A(Pz}@oZ0tJviVF9U>*xkx?;%t%*Hcvo zDt&}TAlO52A1BlS5)h=Le#wjx>U#**y>lqZ#|Z(zAD&BZX(dR2Cq{7YCHQkVMpumh zf1KcGX`^4;2to&;3E*P{Z#Thu1or@64}m{M2>T)=yoFE?ux*42AlOY92iT7gM4$nv zJW61C2w}i}oWQouqqhLI4ni=8F1li3ggU^!mmmNkKmzRD1Zzu#3eRn$7mJPZK0W4X z_R+NkH@IBMdOaxAAmBjBR-;fEAE63p0zy3m&v8OM&0@yZ!6>tG=zz0+UH9!N<1V{kWMQ{Rczzfi$p3WTk zQ2kK+F!e$71L=eG`|2Uhp_`CAEnRm2z zly|akC*F>{&Ay#{OMOdxEA?jdP3g__q4**B(9t*A-eBKI9#jvC2U7>42c!e(*W<6t zuV?ma`<4CK*AlNqUSnTNzN)?|zM4uz6H+4G9q*RAGp}f`D6eE+PP`m>nSD9=lKPVP zQtHL%i_(kf7ve9-FJzwAo>!jF?n~^8>|^&OpHrU`pG!R(eO7ul{Y?BB`I*eq+SAI@ z*{2duMV?}xNaQ30ZLy?ErhmsGf4~h?_9*905J&@iV-!1RX?9z5AyR!Eu z?vLEh-k-cry-&O^b#L@u>E3ia9+%^pm=;rF*?SWAMDAhlN$ym4iaS$xx82R&oxDrE zOS~(!Bf3M{k=`EPE^p6l)3$}TrMJen%3CvcYIiDkX164^M7FS7lAG1d;^x$*=q71X zdSiT}yfL#u+n{X7MibFUl#M34)Go0rwLZF@S)W{|t`pa#)<)M#Ytw7uYveVVJG48L zJF>SYZjao~-kw~ot`=9PRz+7ytI{juE9I4$+qB!1+p?XB&PeC671|1AMRs{&d1N`e zJb9~nt9WZljjEEG?ud8D9hr8mU1`tWlDH*u3wulQX7y(A=G0Bmo1~l4H^y(2Z#=pz zx=dP@UK(F2FU>5`mMBZIixZ0@i`m7=Md~7PQEFjyp|mi)Aih9ekeRQ|SLSEuCFVuu zvGbACSDc%g6P+W?N#78^LB1g~Tbr%S&R(CmK5{*Keeyc>I`O*H ztmrIhR(fW9raUuqt#++)ZFWX%hCCxPU7M~<&rVBBi%esuC8w%W#i^-lqSr{*q?NcL zE16cURcXy$owz!3HG6gPD)lPys??RyE2S&bS9Dw6|qV$FF3*`$l7ibqK7i6a-rbMQ&Q<9TgCuik^9FbW$ z*`l_HEvfUP=S%0O&x@ZYpO-mTJ6Ab3J1H?KGKrm(JV!l8JSTN_^la(u^u+i?d17XQ zHX%GAeOCM|`K-*D+L_9k+3|_-k@4*Kv31E>wN|W6g`y!Tln%y&axhb))hIRD z>O^&+fE>v9HNWD|iU~0yvSQMw`b1w!hzgRB_Qt)kH{;Pf ziYMz%xFc@XovctR#EO(F>XKY(XWS_}GY-w6II{MHJz{6=NnYheK4pvABwN}Vx60Ox zMYAZDESKOS9LptHl@-|(6QvRUk_UeHv)jr4zpHos|0f&&Khv;#|4b%7kEPFpo!XuD z!_1DHPk*%c^BXBw#(DMr^9A+UJbixB82_L5ha1nJF`j6I-MEb7_ROQ~7=D?ltfUZ)C8K#wG@5m$%b@mBF1W=z4H%D?HCzKQFs~AEo{} zF_d?56O&&}^Xc<{qfHEaf&)vi9RE1Z8u_FnB#dqRld1uq4*&GYpY>3!;?vgR^*rd> zX|PTos{MYF{^L@gK{@_qvn{YZ&)q-`GVqDaCtbXq>FnDrw*UF$pV(*3zgzCp#)*@9 zT^^{X3vH7*J$tI2vffWEOyST^cg+7<;9nfO94mpb5;!eN;MWIkUVjJq|No}Y{~uPF zNj)98^sz1E|Bu?I*{6AHy^?pFce1z3E75N*?@sSddcDj0D&2qBJCm+BZ!O)?=y#X* z6}pG_jiakBuPb+dC%tR3cOQL{BTiyjj`Qb!@X~wPcai(O@1~z+8J^N2@1xIlQCc|q zen{*4evidI&0{(FclLfceV3P6#I(`JUEcAO+cjm>_oFPEI~Fk=l>ZWwtv@aL z2EL1u|56oYe}0KyLLaWoCf8Rih5q(`}E9a znLSokmW5oF1ITiHv01J+o#n<{mRV}7*M~?e72UiY)GDEsOcZhl3fTjRq!o+TgH@&_ z*5xER_AX?UE>l_8tzGGprC8mFrK4|_}v|UEvR=9>@0U&Ln7+wP;RCmpP-_N!KCcn%N2x5j zn~qaHx`QUmvnp4f9+bs{wJ3|?G&^z-q8y+alwTH=$jGxE-!h_&VjapX7p@28Qj4$a zwjMQC&zKnMStwU7_G9^nUWyj%e_T{j0m{=&rk-{FLHm%QXPx0?rT6NLJuhRc&-eXu z2Ca+)@<*uV6laxCbNuvBP;*SQe{b%&@I9!nV!6+ysm$k6pL;G<^ju=kR-y=svr;Gm zmO`6M7C~dK2&!{MU?F{UL-E!Ml11~9g>Ezo+i?`W0LjH$El6%OFS$M^*`Jf#*fNK) z*V4!ZW0r^MUzhhTmVOv3b?xkuH$p>|ecppqzcBc5QHNWjJ9O38g~*Qv@_N|PvXr^l z)4G7MW0*9P-nSnEr@r^n_j>8C&fI{AzIQSS?lQaw9c+3ZN3II{c>4Q3l09%hg&~x) z;Cp*hfEW5;prwPc(-@6DHaVC4nY{_1zq#8wm_{49hFm0;@|$lqlr1TjO&XD5T$anf zh29mQoab_j+|b~Lz9D#Y7Q^S#O)1cge(o=xy~`N;%-lE+8H?n`ei)^Z*2ulVbz~Vc zF65)~j?mrw*Ezd8n2Lj5CncbZhKV!1lvq94xevMN4b60q9t(XD4Jf_ia`$<CJ2Ij{^R9h~AG!8ZrFQM}HKC`{POe#Nc5$d;XdIC;8XvuQLCT{zc~J+Rx*E zn>iN!nfTYKpRzxR{xJIk@%yRoMZcT*cKqAYx1--szLxoF{Hy6y;>*gHGhdRwsC+K- zQT(I$d(n5rca!h1Z;A&yUSeNj_hp~bo|2zR?v3otKAw6+eT02P-5sUKmgK$iJ?Wj% zoyzv^&B+as4N;0TNv@S|&vvr6CRFy8%(D2h%%aqMb$)7YW_EnGHdC7>Pt#hHS4OT> zFV!esA|DOfeB2 z1D~*YZ}1rW)_5!T}Y^oT2?1s>{Yo&Ig@3Oa``A5Yf*H1ko5dRgc`^8UXMZBvcC z9^=zSe8B1clx0fcnE(H@aBPkxVypzlN?^ninE$tb@$0p8{@)LK$N#zW|62be_qpB^ zhxV8}KcUofWF9vur_^&~_L`Jq?i?A-q_iyz@?|`;%f;Yd`=S|}*Dar;uIU~U4 zm=u)Hmhspw{b-cV<(oHj4khkM)8bTS&7ebNbaCn$Wz(h&t8d-BsdL)KO$E7o%A~jz zxj1;^=`zEf#PW1mVvOg@40RIAiDyiTDD42RXH82{Y39Lrq)fqKiG>GvJ!cS-(;5W* z0IxV5A;UAjBsv*fUzQ`L7@->sKe18{m6<&Bp)&gn3DOfd`iIIqUzVgI50&X{*)N!s zRjLAh(WIPG6)*)2<$jubYe2D2DX$W#9u@w?PNEWDHYq5t5{rcZd&7_# zJ#{15k-Wxb^~C32V@^u5lWCvUxqQw1uFmDS+uMi_nUs^)xJE0|D`$wl;hQGq?Bn-&H=Xf!6ejvuxk`i@C)c|B+}DZ}+xOTm#JE6UId>lR-R}+!i z-V*zYAv1dBMzRR`*c@X|zJknn1yhi;0!e>bmLy|e-a}8zqf2UAzh?FFZ3VLa%%rTm z{W13EhaWe5)uf!f{V`gEk;V;QD@&TOD?h@x;p--am1q$Dyeu)r7=(|%VGx0Of*-xT zwo&Wkna#QOit82z9Im}iU?#-=#WM8Jd2n;>+`6fA!@6+u)N{^h4(|wW>Rj8kM%~mI zzG4%#+jZoi2)8e|Dy%nYYQ^od=FFcybs;H&Y17;0O`obPm_DI*j!SRN6NhX2`Wq&+ zF9@HRYv^GphW6es#3+Bx+yyh|&0S1M*^pBo!zql7o77FKm$xrhH*UJ3UwK@WQzR27 zULL;tlgi5S_3JinqC)y4Gjs|bNT2>KHy^pjISA_L}4 z!xQrL<;L8X+)OoW*m~2e-192eST%F?V^TgT6X_MkW?*9b6F5qh{R%l>D|3cW&xTxf z7UaU@=QgM4HJINtXcJw#jK0DAR#}otGnjv2QdV&WvtzN|-T1aiIei9m63r3(*&d!- z@*ST0=XZFn`&ZMrD=+1_|3~Bg)j#67|NRG^d-4IEJL~H__oV|oclHid6Q?}>f6oscV^(pPSI+0g#1J^YSRa?!kTrj34|NFoce^ysFoNRT1UM^$xYIJtUJbAqu zSq%qjI<1)Ze=?f%^p7@&1{!Qt3s+{0)%DJtp3aw&UK+Z7{;byAPjXd@vHls? zDYP^CN{^BEGsN@wG+6ZFSIG=z(e*Z)uYG#y6jwL%@5+~XzwItYXO8Ju^tIOY?Rkuz zoxVpgouff3d}rr+do!q?zK;5QbEyBmmip2CD|$w%>Ba2WiRbr+Rm1ghRsWu#`8sUu zhmKCoE_X!q*S~sUPZy2nMd#0M0Ko~x;XedAf@zC(n#YRv*Rb@XnSmA^U2hKaz{5~^=TV-EA%iZ6UqC<_o z%I*E0s;6_h^;m~`a-WViIQsp;)Bl;5*M}S1>pdTUFvhVG7%PFX5*RCi)3*fn{Ppv{ ziPHH0@W=TyVvYzNTzJga<;Due{^d|}NW+hVjk8PnSp$S{D>N3_M6&{`$=|yrD=$q9V%14SB1Krn^-)lziUr#2l%kcjG!8u)?Td2I8Qj1g#m6ubQ z(xLqO!>2(nnSpctg*n$p5hwTT57krs{rT7jKa;663$-9OA2r+zrnxzzk!p=z?=j<1 zI5Ret=Ed5mcFbYsQo3eR>gFuCGIhpGvmg=byv+|bx_KQ%K##u^RH zYqm8H*0QDgd{4KhY_w-1Ywe-hsST*82qgDXKT)nV=NJ~?RNC%jXrJlWw==+qa_~wdNMWx zb^4CD#!@y`0;f+2?2ausw1LL|wZo48bt_by2Y>jPfT8_Kr#k-sWHtj8Bq0t|r&6nry(X>rhNY z*C!JNd+O#oj6JLT-u@eN{k_s!nem%Of5rpP@^p^d!c5*!^|v(rbL!?;PTm%V>c@XN z>)olGeHp8RsGs^wHr9{jcUsTe4SlC^eKcVlZRls@45yEa(YT-87+RwS9bH{K*s_o2 zeAORDyC`;s?BtsE(_71pGg__Pj(LT_t6?$s`BfN zH2$ya8~^9~#Ko-l)%)P1*E)=S7~}85^=U?@ReZ9&@ z7QhPF03NUd4!{YxfC|73cmOXT5c<;T!yOUu0|B5Cr~;~i8XyRSfLfpqs0SK=MxY4@ z0}{{-Fnb9szyTJ(3fKT1umcXj3Alg?z)k2&rw4bufB^Ua5%2>6pc1G8s(~6H2!w!I zpbn@98h}Qi31E&ASbzg8fEBO-JYWYLfD>>56@Z)2pHAHI0s`OzM8FROfJ&eWs0M0) zAP@p-fjXcbXaE|4CLjzjJp>lu01IFRYyc0~0SDj&TtEe(FP(1O@c>>x0DOQ5_<;aW z2~+{qKn)NCLO?B02h;-%KqJruu*V1-U;(Uv4d4Mg-~gO}3#b6xguZloaK{S>fDaG> zKM(*afhwRHr~!gN2&e_>fO?<-Xat&oFdzXevxE{0SO62%|c z2k-&{-~&X!4+MZppbDr4YJeaR0&0OepdM%d8i6K&2@_a=11x|QumL<^2ONMCZ~+yB z{&eDw2k-&{-~&X!4+MZppbDr4YJeaR0&0OepdM%d8i6Jt46v;P4zK`Lzy|Pu9dH0n zzy(wg`qPO!9>5C-fDaG>KM(*afhwRHr~!gN2&e_>fO?<-Xat&oFu=AEIKTo}0UN*r zcEABR0T)m~=uao^cmOXT06stj{6GMx1gd~)pauv6A)pqh1L}bWpb=;S!hi%YT?7{3 z01IFRYyc0~0SDkD^rh2T@PHj~5c<;T#2pt<0k{DV-~|N02Z(?l2mqBp6;KV-06`!G)B<%t zJ_i90T!0&oK!zzYa~4-f%A5CAHHDxeyu0fImX zs0HePdY}Pl1e$;_AOXx#0t;|}1+W4(fG6~&(~dh1zzMj33cw9`052c_K0pNgKme!& zs(@;s1_%NnpcbeD>VXEJ5ny@7h=}`I&=8fb*^`Lk#bs%~`I*@)n{<{2nX1}&y*`Iwa@ml0H_O;}z>Z{_bsYEm( zCDPsTZn-=2iuQ`~O7`W%%aNC3FUc=uUesPxUd+Cbcp>rv`$F=0^?C96)V}CGX2zUFt4zSL*)g{nGvE`{MV>_hs(Y?p5y1#uM>KoQ)@AYD|o!?up(b z-ILzQ>`dOR-Ywppx+{8@bXR&ue22Uvvt8S+Y|m~>Y>RATwcc!<* zx5!&Eo3+i#=Io}#rpTt)MtNgqgSJ80kc}pyktiEYcBx%rS89E9y|g~PF1}7)mszW= zRn}(LB-TXMuxpZcsCS5Wq;8MiF5RA9&8$wYQdfzqQY)h?rIqR1;ewnSNyU7T1PSahXi&6`t3#El=S|**Gug(|e zr{+cHN%PW?ctnn5+O#&MEju?cH!_!<| zUF5phEO}ODrZ!WVnY}h~ZRA?^+T;v%hBzZNJvv>Qo}Lz;CQr*u)ut*_v)3f9iCn{8 zlT=hiR8p*IZ2%)PD-5oS2#roghs} zpA|n#J}YykcBXP>c6?%dWIQ`Qd4_t1ct&bmbeuFU-5hV0n=_IoDN;6^2uH%PCb=oo zs5L5$*@i?zq=9Wn)~oemeX1^6C)K5EXp1{PuwGWGH%VSxU&_B zibzGwCA%_C&8axEj)WuPU>!-jY8UM(KFUjc+7`FTwv1J?D%PweVTo8+OOjJLkxQ{r zR$|knU2ZwCw_!8+|0ngH{|DdlXL@@#r*&kr!oD3BoZH$#c zj6mM^qkrFUD^Umj9VMlEvc~okD0LSKy(~{w3s0?Ib8tO4)e#hhZA`B@LwUnC{oc-V zFnVA0CvfsL(x*CJqR>Y^l(y1Sd1_*9PTzVm+Fny*PGJem)d*dq>a81*`=cHIeY({O zJLA=5*By zpM3npsn8LpvVIw(Cyc-A(G

#OT+nu}BQeJdOQ)_Df*pl|A7twpM1=@A7$VqCzp|v2 z*nWR#Qdo)Y_eW)kDW?6N_$!klu=nXU(mDfvVs-}qdK*+hL;A64DJt!->Kq`1iSeWX zd6I(W+ArjHKQRc=Kc%ap9i)DEraPyKaNWXy!>J-VM;wbI>6q^sv*t{1$Kl*_7fqix zd#*B#&H$f{dovc!ncCjc4o%dbj1xaKBtuWu=qruCE=y8rO5<-#$|_Z9{LG{rb4ue_ zS<*^W8X1$qN>mzuTb7ujl*Zqg6j7Se__=8*#Vd`Ee_;?}R2r|6icp#TIi-PXnE{7W z8tA|5DX#xA`4shE^#07`e1B$gVSncD4Vl$5Kl-ZaAIg$cnrix`Nm-?;reB$qV@@^w zV_DKlR87A&DXc`*^qaE86s4N}$)t$VRMS73mQuWGI`J>2g`jKZ(luHBbwJl_^1#29 z`rGH%@!b4dchE`|tDI z*1zL9-+er{|0_Iq*{eKvbK1lGPYcgI*~N2b_V66j!7&TAxp&`bYi0KJ#{cKW|E>R; z%Tn(s?zri4#KWo>SURzS&S$O|^Fn@?H3-o^rFT9Lkk#OsZ{_R=u3H#zI6G2&=M!cG zvU>CSuZCpk$r^nP|8HeUDow-xyGdE4YWV*!DaV|K|7}^)O4RWGX<8W0x}d6B_!ILn z_}4yPU88K;v|;tFn>Te%+qemD>8*$VWl~(;pcpm%uoGPWU6vT*=+(;LALh{ta`HbW zMdS^Nap*eS0QrASOM#9u>iPm5RWLw4@qea;z@QivVPRGZG~tPlO-n&m+=caw88Fr_ z5c2T}gAn~wy1M-~)z~QWU80l0wVdN{>K5Jhmy7GRPx*wp?RqzUO1>LErLY_SJ45F6 z!Wexe&s66Nwz;=_OOsTZl4niIDpkpICgqq@@|Losm8j&cCWV#QjklF0#;Dwf)VjP$ z5v6tG?WU!a(2aMP7E)9pVy{fAB zrLezVAmn#$gAn~wx&cX((cqci<_rj~TNrRS15$i{9rgpVdh_ZrBtuWu=&N#XS&~Xq z<$_6BrK)nDNjc_JxmcF85>>h1w6N0p>w3K}<@Li8G}iwcp8N4X@!W>Tc#i)z&%O9I z&sE*!;EvqLbJyL$bH7-|bNAfNbG7vP0geA7m-5^{()j;w8vhHwD{R?>RsueuCSRyn3W)U;iK;KdO4a*%E|i!j4MH$H;|vOv>3vPJuNP+BM*3ft8c&DMQnY8OUL*H-9 z4PlB#J5RsoSAgQexCC^Pq2%0q4fqAm-Mfq81?c~~f5vmu_Ve61Pm0{v=J8y|tvvU?5uSTm<+&Dm{bmQx zt)z7T46OtB(OFBM+)n=gM|$J`$Nc}aDQ2%PywqLY%z9b|?q33{fgKq0Z7c7^YiIK3 z6A$)}ow{AyPVPm+(EATBUO@Ld>NR9?E+RzVj|S&qhUw{@%JaxhpBixb`%(M7$NKXc z?VZ?uAJ2QZ_yfIeDl}cSlF`p*9qx?5&q6$co@4##j#g_t_3;XN%KM*H{?1tZLMJUX zfezJmYJc>=>H3uWQ<#66#^2Erhkm+a@eU<)l*isWRsv%sFjfL%B`~TbV14Q3&+nk| z|K48z|JeB7{POp}GpeGlUQrSQM!u6u)BrkISN$cJ$mBN~Sd|4aiK{O z`S^chWPV|!dEqu;7nzo#lIzYGnqLq!Um)b;iw#2bN}xxiStxSlYmAlXWN^@z^=ZR7>ZIa+R+bDyRQwEA!?VK zlv8Sm+7%|{me;wVGyH3bJBcYE@vG3WR(--5|thns_otKVz2?OHygJYNkn9rP``lCgqfB ztFALC$DFOYzAR}a+N#;6g_*KdH<%PxqOF=!mYAY!)m)PzO0!jMrlpi%t0Ja_lwzyq znU+$#tvWH^v=C&)xGK2N?B+Jh)J@;euRo=80Pehn=R|sa`(~b-v6j{WT)}g9-NkdB z|KqvtpYYt|UsJsP!xZ~Z|9|@po_q8V#qj@m75A;hw1?kHis7f%=WpY=i!b82p3OX` z{s+(f`ww_-_s@B*@qRj2fcF2t?oa7l0owon>15@g`2X(L-%{?jwK5TF|M))~`)w}4 zz5T@nrppKqLKv9$;Z{yBGzif@rH^Nw)J5oFTtr$%N1T%5$vO?cEwD}_RCH7x{L zF^*^pvr@3z^@-)Cr64QDZbCs;3WcmNEd*IH+S$UaT!2QDw+SD28l>p$OEp=5&=wS*4oO)h6YXYEExADaV{Sy~CumRk`zDjpnqs(dKJyf1^FI#x^)n!E`7xKh)xFAQ*s;y>oA!P0-nC480(OK=c%y{xrT>9 z7TN}0M=%!?nPZFf!PZ7Y(dk8ba_ewbla>3;mjc`aH2#-p{QqSd|1YNT|1bZS=kBAk z02=5lfW!aDbJx=N|7W!RexJD&@1t7!ahq4EDqH2%M25zl>(_Wxf?=K$F0 zbw8a0cqN?!_#N8+zk|*J{I7dy-vIi5##iW!zy!@5v{mKy|DW<|?ed+rR%V;6fBfIf z{5JR8+evqHlAg-{MXw4>tb)3L75d&7Ft7zmWRs~<&?S{-xi*`WRjTFMVp2}2mg`QF za?Dw-ttO?FX1TVRmQsS{+HP71dd^16RcM3@hZ;LfOF>qQ2CH`vkW(}T?dL9&Lh?q~ zXs$*y!gre#mp8&j(>1IS-dUCy<4|xYBmD6_1`)ct(k+*ttkt)eK+baE`f>&w&T>s* zro{fcxN!{*uvg|?JA2mr1w~r0fu9%^OSVYg?F%+5w-e5QJ0(sx7S18Y4CShq^U2Mc zuFy*{9r3axm1a8bH7To9({Z0kIi;G8`%TI*XF7J7l(vOIzKnw&7foBanD)L3Tc8bh zn-rAK7ParfpT5nT2DXm^aSxalhq+Os9T`#iK4?;0i6fwg$`WHVDMKmW6AzmdQQ8RT z5z|si7y&(M5Te&0-HudIt@?p_!DE*Wkvj zIZvX&pD-yX-=8&_iV;=nlP1L#=Wbe}kM*A_OAHJ};Ad9u?VU76r~Uta@Dk6hp?&|X z^#3{9`|mv3`|qD!mE1#g_TRYMdG08k{kL=*?eX_tv_~NQ_diGD`+wlMD;}WF?&i5w zU*owGuk+l2`>VLAH17W?o%^?z#{G`@JooCYB!l(<{2}fAw>rafY@Fxz#dz-AqZB*P z!!fDTL~Os0jz)x-~k80@e?O5T|fok20VZl z5C9+GCpdl)z-1*+1ylnyKoAH4wFEt>zo^5VdZ3Zu$Ts0J46tnk4zK`Lzy|Pu9dH0n zpn~8y;l`y0@B#wh14O_N1b|AQ3aAEZfDpl6SLR)8ls>g>3508YRKQ~++k0|*4i89rQ!fFB3|l|VJYaZU{`gFpzV1?qr$paEzk z=t(`N33tK(8>7!(%n_XyzzWy^9GE>Oz)&adLnKumU!K2kd|YZ~`u%0&oK!zzg^Yj@v|B`hfsY z2~+{qKn)NCLO?B02Q&~I8yj)i1cU(zV2<{ubR$c@I61%qSOFWr0}g^C=ES87r~ur6 z2k-&{-~&X!4+MZJg5$AjT-E?VAOzF`bwEAP05k$j4}k?N1jqAMqW=7!x8Xhy*Z~LN z1YAG`;08Q^7Z3oE;CRE2%K%UbQ~}jM4G;uEKrK)QG!PsgG~$vyM&JMoUo0^kEgzz+m~DuUyi)wrwyfaDbKI_^Az-JYWYLfRmu7^`|b}sQ}!7m*Dt&0hc~N1pGh%s06BjYM=%P0<{Fk zzt-Wh9%uj>fhHgfNI)~dgqKoM0S>Sd9KW;Sk_YU718@@br2fu@I~9N%@Bm&w0DOR- zU=Ml%xUK}MfNG!y2m&FX7N`U2fd-%vXaXdHqkbIN$h8o|HgFtIblL$2-~?Pi1>h$1 zrZzavOTRcK3ApbAM8FROfGUDxN;NKPfFKY8YJobS9%uj>fhK@$rO#c>5uFym3fKT1 zumcXj3Alg?zzui+f#A5oN7U1LgNXZnAOKVXRX{aR0|bE(Pz%%n^*{sAL~z_3#wF81 zU;z%W09L>T@PHj~08YRKQ~++k0|*4iIv*}Yf}YZKe%uKFl|U6x4b%WZAOzF`^#sR` z23$4*O+Xls0H%w;0vuogtbh%$6C4jZaOnhGKn36iJb)Jv03RR{^prm6$DK-oXB;PsR4pO2&e_>fO?>j;P`SAF2ex3m%srQzzWy^JHhdF2QHm}3#b6xfS2I- zj(|%aAOe0M08|21Ks8VU1POXlzf()UIDTA*`}IHr&S6J4>fPwO z;=8GLqVGuWq~DIeEx(<4%lB65&FGubo9RQ*L(-x28}T>fH!=scgUZ3|fy9Bxf$Zyv z*CVg9uP67b`^EjK*P^dUuccp&zbe0)NyHO!qN7{vPQ4O+MS3Oua{Oia<;+XkOY%#Z z7qu6a7qc%UUWmNFzL0!geO`P%wNKqA?n^xveNK8V{cQYM`Ps}f+A~L=jy^3uoq8(z zl=M{k$@r7q&s63c`An`!t0rr8!?#OO-cXF4yOWc*ZKYG7(fBL@o zebRmDd*k=Y_h#Z+T#k3d#8~Q{=snUs>7DVN($3V~>fP+!$-C6M#Jf^EqC2D=>Fx3D z^7hO&ZJV+!yEVR5-kP~nyHmL{yCtzDvL&`z-kjN_ZBjO6HfkG{joA%}4UrA(hGbNY ziqTY8v`g$tt&gsk)~DCS*U9TLYqhn?+Uy!_jj|?tN8*m2+vB&(w`W#stL4?1RoW_L zRd!`!Wn?A0GI?9%Hukn;r`joYrdC8(h$~Xdqsyh`>09Hs%D1M~xGJle4qr#AJ=!j{ zr*DbhBHxm^S-V-jIdhYClX6q`#>9=08`&F^%hYA!vgA^Askk(?B)UXel3pBNEHBP1 z(iSO;x)zEHQwyRCqy_2u@%i%n%sg$LGA|oRM3hLjEzuTfW80E*)w$x_)ST!XX-@iv z=nc{h>Dlqw^6bp@+Vw}Ti(V&Pm!1`$CCy6DjL(#3X0Fw)Rj$p>NX&@LU}q$!N2asW zlhf2`;gyiC1JyexHT^it{4^d<32JoP;BywthTbER|Blj4))NttuBbB>-J zJzF|EJyD$~PE1XRPLL*~&x)TVpOraNJ5xC`J3cX98J|5PaYp0}_Kf5>b(}aZ)f{b> zn$uELlB9H)2`8J>Cb22i7;Tgq(+$xEsUck-ub1mHby}TLm#x)mmD+455sHM^P%@|n z#bB~Vtr2Td)zNCHx~(c(nW&6ZvX#kz8W00Xzv>tLDKRQaV%it?$-a!B35t;QYF@>g z^&~tI59>*~Rk!F)RYWVgT@e@SN;*}i=uA1H4#|w@6Rg20y(&zcreN=WQ;rlpK9gI(aK{&=53i2fM$8SEg&wZU!5kP&+$9V2*wWUEh>+(Vo!4Pn0{4-8ZK_Ze07uK1Zneb8JpJ&;7iil=V^{ z{dw*e%92#tJok$xWtBS5{gO#JrOtD|Y*J3i^W3kP6qNT=8t1u3IMb%vv@lbPFcT)l z87uu5jrlmm38-r?wF<7sg76OB1 z45=y1N`Wmoalo_`WW~6=q97{;LOwod5TZXx-C)&`c{I9jKQ7+o zI)B!(=_OdJ-nUOE`i#`VW2s=1N({w0sSSF=P;h!dj%0)K+B)Ci(+iu44Szo2A(L|Q z+S+J=dgbU5OGrTPdc`+Q%E>EH<2i^Uoj>|kS<;NBA&#K3-!?4_D%a6e%MwG4xbSCam3`Qxh`h=+8lOTvSE#a&n3e)PXS6*9dah7N(zFn$?2}oa z0&RNYJ=0P~us#JsK7QXIM1PLD%5J1*dz5J+IvHGFlHg|5wr4e|8JcJwa>#$NweI{qa*gw}96E|AyB7$7t<; z^=mwLM6Kqor?dZlL1+KP+UT4>dS$v<=8Hf2vKlA<|LcYRe`YDuq%F!N(sC63f0vD3 zEIeQb9DoyW0TqB7@Bm&w0DOQ51b|AQ3aAEZfFKY8YJobS9%uj>fhHgfFg*kgumD!T zMxYe(xV8fhzzMj33cw9`052c_KEMwIfJ&eWs0M0)AP@p-fjXcbXaJf3_85T!EPxfT z0X$#_90W?C6W1=F0`LG{KmdGz2q5Ibf=~+!LM3qma{2(_>v(!zpB z3kxDGEQqwQAkxBuNDB)hEoe{2C6qY80$2eaumcXj3AhN9!U|lw0T18>1i%M~fFGy? zs(@;s1_%NnpcbeD>VXEJ5n#du7T^F2Uh!73ca`%03RR%2(hpP zfJ&emr~!gN2&e_>fO?=2Xad3j+e+X73t$Co01r3-C*T4q05{+Pynq1s2$VuUt^+_N zPz6*2H9!yu0kuFKP!BW$O+Xl6+X#rKuppkof_Msx4M04F#SS2z!h(1T3*sp(2&b?h zoWg=|3Jbz1EC{EtAe_R2a0&~;DJX>qsIVZQ!h(Pb3j!)E2&k|ioWg=|3Jbz1EC{Et zAdJF-FbWI8C@d1dbP*6nVL=#$1z{8xE5HMYqOc%}!h$FY3!*42h@!9{io${@3Janr zEC`~oAc(?(APNhDC@ct~pcEpE!h$FY3!*42h@!9{io${@3JanrEQq48Ad13*=m|?0 zU}FRhumD!T2JnC#Z~#ug1ylfTzyk|)0zxE6z2{Ph7zqn|jKBdFzzWy^95PBM|H%xQ`R+00{^(vq_$h zP~Sta?wvzrbDR(W{NcIumR5oUcwz+SUV=Y|V|3LB@W%;`mNxpejUaRongBjV@OBfd zM{p1D^$_@Dgs?9{!dnRS0NX~W0D|3wae(~@K?E9r%A*9PhY$wr#|dofJbDXY>mUSk z=%OnoMyLbqdkF#%0wloRO|Z5^sPNo2da>9j@6%(RW*=Q!aD&U0tk;7=4FV37Y&8m% z@e!(kCLq*9@Ej-91I<7PC2K*+HlSpAl&lqnS_uTgRAQl4LNnlv5nL$LKn};~stK^8 zWSuQ2yEc>^3N;MaV+5g_U_+tufE{oEVL^q5fBJZ&8B;Quw7T-?26@5#3EB$8tP5I5tA?=WIsOOE2H^etm2crk2 zgXshD1M-2)>)Pwe>)HK@{gM6b{^V=wYvOCESEH{=ucmW;{7kpjt#oH!NxTwyg?%OY zvih?4a_Xh%OVUf}7vnF=FJ@lQUQk}hKA(6#@;v)|a!6mk@=W&W#M6K<`V>apl!(qrjIv+c=S)LX<`Qa49$mTpep6u(KnDRZNCWBA6NW$|V5 zvdmI#sj@V?B(Ws2gk6$ctS%N8rxryQNsH18;|t}5nFZPcWkGg+Vt!;kJ3l#3ohQyq zMWPWVl5A7k#J1Gj=v--TdQNw z$1j&J&s?Tmrd*c2G;wL*}7fTnXFN$9zUzE8}yHL3>dqLuY$OY^L z$tmg-aZ2~($YgeMQdVVAPPIf^q?Yvg@$=>LGv{gNDd%O+O`ID!mpwN*Nu4B4N}Uru zM>;2ccKmGl?94=MqB1c%AvQstkU2{`OF1ihX5!4qne3U#@#=VSeCmwo8PXZ)aq)5T zxJPmf1);0%ho1CYDf&Fg3+K9OxMI~ zXzK;ig<-wk#T9R zuq*A1J7s6ap*a*s)}F9O?5sV>tGvjkY*CwJOIzbs*_yFv7R8d~5?q91xg@KyBAa5O zG{Rpz{_3mlwY4(8wDSUHOu@3lj2I8W&UDWVrcfU@Mq{*=07qiqO@7&KQ=9;gjwbWzn#=<#MY5N_# z@#G;my2}oJ%$#3y(2d?;n{a!7)D2zb=DT~X$yW>op%=_Z)}-{UX#TV;Nk*@whn}=Y z-}I(!{hHOwx8WJ~=IYN(%F5d=i(VV@uev8zFWmw;Uo|NwZ@Y}vWF!yi*UFM+bXtz! zA^o~ZVI>-qKQBv6F~;QMZx}@APgig2<8y8O%v@W?wakFSwe^Y2#Mq%>oMXc@^%-dY zL+OOkZ|S58hHdKKG?as0E~DSnzg3o`(wh2Tn3Pp&Q~$O}Ip&)Bcgm7hVpIRFNns^6 z^`5fCP?IeD8M5E_aoQk4|AgMuC(yS%!%QSP8C*}!ak!=qv;Id#nsvE1XlX>VjyIkf zv#$HK`?e`BwDaFHl#E_dqu=lw!v7zblr?1IcRz09y1&D77ro1K_3wz> z7s&5FkM{oi#ZTy50NVFoc!cL(`zFs_`X>4MAM$bExrFCdZsocE`5~PHKU?rh|1%d)r z`w3X6Ct#VKfQ4`Zmaz#~m?mIhnSfPd0+xIUSg0jnft3&@7*gx$q5JiK=Qyqahi@4p z1OP5f@B+0!Wh=qcLEvKq321D&k#f*_qw$MdnF885|z1J~=v&->T^z^seCGTW9nak^Wt5f9CaDA#y7@cjhu~X}z8in!5lx?%-oMPI zEx}_1D`4wxW9(9Iak=Ohp`KYlYZ!Cybuo*m{sVP@#YeCLBH#xkz|%pf1-Kr974QKf zP!BW!)?)-45CAHHI)Lq1OpOn40)8L>)B_EGt&6||ejosZ0SWNzB{Tqy03whCL?8(W zB@z%yBp?n*Km-pZgMf${N(P~VAzf1q)Bs$VU;#t`K_o&5s0G+o0tZw8ZlDUN2G}+N zqB8`5D+pUAY?*7#Djov1=3RlL?DnlAq0R*0C4~Uoc98J@B*Ca0{rL#{MrIs z)dF1A0({Q`e9r>>$CMcY+{6Oh!~(p*0=&Tj9K8Y@y#kiC3w{6#)rCd?tIh?iIv22L zT&M=Hz*`6bSd}ecowa~<)&kZ^lO7~sl`}ma0#+82o+n^&uz(f5ltBX4>SBXpBd=2&Beh>%&))s;d za04Eo5~u`dOTP;BKqC+aJjV&H@JuS5ZbArptqyRawL4qp zP>lopKrO(u5t_OP;$DK21PX3)+ESs+r)-n+R1kV*G4@H`ak)f!&m6{iSMEJE9oI4T$=*Y`Uz+I`0j_R=A!Q_30Jyvb9{|5MX$JzF z-_+(vS_ps#T<`#Jg9~tj3*H|53cw*Q*p3t66&HK}T;l><tthY{c| zr_U1LGZz|sHxOC~@SY1zM+p|n2Bn4I1>jL983ef1g&@!jxWiO%@UjcORsvk@0$lA> z#R>4Y3qhb3XaJf3_~5Cs;~v0u6YPKoXad-y1P9;-1Rw-($8Zk_05t%d_`)~2_OJK2m@Rj!3H1{K#+g{#RCWk3J@9rL`p0~@9Co@O1Bg&EN;l$y{VfJwHU3Jhd1=?H6TiG`gZ${o^ z-%K7-4~d6TZ$#ga-bf#eACwPf4rm9IlkQZYC6q+AJJB8KX1kNGsIQ2xq+X7`EWMn5 zDL(9O1<`%dzVvhP=j7)y&uY&q&t{)VJQI0_eJ1&|I^vE6;@;Hb(Z{97(|h83NS9F)OD}8_be);~)ecFA>ec5{x_eSnz z?@h+lxE9OYqurz2liiuv8QGb*J92mYF8Qv^4sD0BBfCAZJ+htMp4_Hx6St+dMz=~^ z(|5-2l<&-J(Y7dCvYXk>dQ5|FLn<1LO3`#zyi4xNtk>2n>$B?;>muveb;-5rT5)Y^ zO>~X4CVfZz4*8DE?b_|i?b+3d)sfZg>f|bQRm;lEZQ56Y}(@nQBVNG**nm6oQL#FxlRGK;mv%Hr&z#G=R| zc2RPnI_!Q0|DV0{j&I`3_Wl%WG-F#Hjf*UIjT5p-0OK(@1yU?ZLV$n;gpg{Bl7xg1 zD?oaPlm;QqN+%7A^p28EZ)khVuC=>&d$G3nMO*LPyLjL88+jZtAlvhZ{oMWIb;4KU zv81DE&(WFZoZktB_#$%|_*0Xogip~TV1)?5*45@2~CkwbyXf zgOvkXpI7&$)tG9inS*Em3{eh1ur#YAl#s$JNjWTQa>^ZX>+W=$pS{`D#pxsQKkEOj`TsHIA^wZ;J_y^*$!`^9&Ed_-Z!;QmcysbQMVX;niTOVV zy*WAjT}BhmCbhrEY-Qq;+WWq5Gh%JLb)R)I?T`n!DMW?CvSG5&eO64Vyfd*W73((Z zcvC8e@Gh%;N@dL3tUs{r7;8rz`rE8OEXvYEZnM%s9hpx35u>ex-ew(R82d4!9kyX? zs3>a=hp`N!F^9w0Pl_@#p<(Q&j3%57V?SfI;$Rs2xy^`u7;B>)@+>#a9LBKR!GVQ_ zF-#YIG{Nbjj)_he;faT6x@g>i%o^DaDkT03+rF~)-Ju`Zep!?yXCvFM7;QNn*?!Gv zhizp0O;Oeyj%>eWH0E$*`(06H=(5fKIrtZ}-!qzUHnRPJ*~-L6w&6cA8*!3#xR==q zHf0QDmHgWFtj&mZ9Ifw~1|8eCxelVjVc9TQXpqKt%^yzeyQVcpkM~{k&<@duRFULQ zwtZ*q%R@hC|G6kj6B)F-M`!*2!f0!pL0gzcb^J8{KZWN1_kN{HxSi_%CsFiHL?`u`@X|9@jMX$Vm5 z|M!1JJp!rr-~Act3rKbUH{YWPEu{bdHtGMbFeKrReUfnFpd?gN4glB1b4NTG{lqP< zE^cY*$NB%Q1AjKp`3Dm4_0K;TP2_x-T{)$YKFj|yTfx9@mrg05&+<=ZBk*B% z?~=bMdG2L+AF~x~ie0!XZ&UJ&>>IWju}&Auhs~f<=xwf(sBl>BFj>flA<+2I1Otuf z6Ad)*#Q(EE!-_oimt+|k=Kf{ddDhN6^iC`{uyS1M$nkMzX(CRH-gsoIc=OS@t#O># z0Zu|-w8Q2k#GK z43{z+aZ>M8#%u+fGQoPMa+?vm13H#Y(=TzynGOic1_u^$KnSA#FtH%Y@;~DRQHR$3 z6dgp3>5x3OooVgdL+_9(in8R)A*qbEoH`^gqa8Mfq!ne&p+l-IsJ39QBwR)De<|Ys0ggK*Gx*4@l>h(D^1S^2p|iN( zW^?`jpdL0aYHmlZ3o2r=1Q{{e4HYq2hK!i3Ku1h2tp&^cU^(=}WKTU<0Yx#{%#W45 zNRX8^)D6g$P!*G_AS)(U>tGGnNAy8iOs<8rnCut9I*5zO^)9dh8e?)JM8@PMsEodk!`RE#O zvJadB4KjHuM9AbesF2Cikk>1>Be7RDQ1l>oK#5GA4kB0^RXMoY1FnId znY9^fRjj%I>SpqV8hBA9xULGk7)jFdB{krBXq?HHqO3&T0F^WOvO2J@9*i`Amp6hN zo4`$wJCirJfL8>-E0Jw2U&ZYqUd@Bo2;j9McwGs2y$jqTfj79ps0_v+fF|Dv1vL34 zNTA6#BW>H-j9Z|ECf|xAZh0%}UF243Y663-F0BH9()yIYVvE1;3uJ}CcoYczQGR>-xR>NMDXnr z@EsTUt^~g42H%IYn*4zReh6_jc@Napj$%S;GgQj zKR1AXX$1d@8UgulC=!tW-U9x20Q?^v{6{PJzg&PCQ~i?%_X*&z2>z>t==O6i{KBKV zoh+cxKo(JHAeZDdxbwTv;7*p%;ZAm=#homp$DM38xsyxLxWApkb&U{fpD zd>Gimw-WD7^5kRu;IXL9kdH%g zhI~9q;^di);4E~_lTSd~Jo!ZQ&67_GfG6`^#4Z60is0-La1JUvDgKtDZsAsXt*iz>j=&Axhz(N|Aif`)o>cO@7?sffH3wIcE| z)auF0ec&0j;0ix@W*xW^o%Q6i&{|JE8@=`9bI@E*KDQY>uLV3m0QPXbM9LKp1o_uKqxIqOk zL;pRw4-NR_NF{hV3SH!l)!?QYa5IVyP+Lz$ahR0A6c0;=2xw_~h%G z!7XUTC*KeNqdFKvH$M4BwBwU+LO(wFW>hj-n{f*o^U1fOGoQRw0=JnB`fii4yj=lr zM~goB4piXCccMw3d>0CFXYw9i$3|jD)4@@Q{MyV)F(fP zR(Xyqrr%e!=)K7jFUH#w`6quFP5p9npX-4)-pClOBYi3DjEW_HG?3t@_s3;D+rj|Hg* zVeC=;(bOYh>Oh!yIQVd8M~pK1QxAn7;vY&-K7Zzc*aP|l-S=nji{EEZ@4?8u8fg`V zsPkYvZp735k$#Q(4uN=>AM&Z!580izHwua4q zgTY%fx5OxKKSkPv{LKl<+Rsq0LH))QN1$VIzl=7$*V%7Mi{4z{qz+P(jrW54sFg-k3nNodShgxwlPT^2D6cP#Gt%= zt}j73`x)vjsBcJ7#y)>(f;tOkC|_T{Bt`0j{KbiNLFz0RyGXw%bzzwL3MMFDKeINr zR;R9l;WhoM4eBTuS*5K?P@aCKH`c3DN5L@Z4JOVHQa`~MsST#i4WG-On>Z(UPKLAw z^|MpdOOQV+u`)>6`Q9^=l$oDBBTgEFY3d`WEl-ldV3xWF8cWlpFQ`#YeyBUUB)-HT zb-~DDZE^DS5NQj>sefR4VPxUJg5ZLT**!2dKRlnGpP=4>nNwn?=#+&Yrp|$hxk1Xo zk5S*i)a)>2;3ueSV5TcZ`S&T(668;ACmq4aiQ0)t>KK@v6(<$J^vnqL3rv!RVD`8; zbqh?Bf}nP6@|e&uS<(+Qs9RuUhDPdvq3K!b6}X3#19>CS9&FD{i%rwbE`fYoVrp<| zhI$0*q!}2V%uh}n9VErT*ikz52n-*|ADJM%z|0Y`BlIJ>sXJi&aD$WrBh(u(*%~69 zz_@NuXTS)l1SVTTE!pOHvtf1y)S8lwp~fur1vDDc^^tmw^Z|$bG13N1QAa?&HbKgO znVMLQUX!X0Q%Ar=Rj?{k8LQN(A7EJHwS+fF-2h{%uBIx&qzIVs1U-G!2QXO{D$7zG zfI(V-5$Xe<ZKh7Q=x{x=6>Lg{d9X(j&6`HfGqSJ2X2g1dHH~}%-Lt=zJCUexSe|aO&|Un= z+~nwE1@7W6TOM3IH@I}}{<39rmM$kbvt{$b?7V6>CFxo^MS zu2R*e%Gpk@ymLZlw#Ib7y_M0N!~5-r6=h~3_uKa!ZZlyYNKU4~<07uh97wR-$$^Ci zlBwL(=p7RuNKT!%d|6MSp~M;+&@<&4m5ZnoSqdR&I`YX<>Of2Nt@t z;G9yC+Xot;b8%0^OUxMR^n07E5!xsd)F7tn)WfY|6RI`@&V}Ij?dHF z|1**>_l*i6(@ENYR0B}KFKFsw3DX3ICf?g$F{C&`xy#U+yNm zy)^$%kJqSQ@@#W;ap{ryf5iWR{=b?Z-`rWzeaG5%nzd|Hlr-ayT71htsj2!#U2jZ>)WF=pD}SMOkv@aAq>va_VqqG1_tJa86*f z!{%^KEXtZghjS9MF(!v|GNU<%4yUUqGZS(+K}HkK9L{WJD-&@z=9@={=P(-?FKsxl zq-1z5vlVQL{kCSF@60o@Z=TJF-Pg<~|MCoXn(1q>Je>o_@--h#)Yq7a!~bEv#_~PW zbG~Q#e!k}v+rF~)-J$nArxs<&neUm;Xv?YZIgQbdQ{S_I(GHvMSy+@chrVYKvoR*$ zb2_6rhrVZVQD!FOdzLVoaOQiunXNeRJt1ZzPJGW&W-Al-J;TeGjbKykGiv!EXx^0C z@N#A=*c8=rh`Gl?^LA(0j99O-LbiqEG~eVFnQj!z(>ZV~H(E%-;DC9%8L0pK4|k)M zTb+?}t26dpxd1xJe5ju~rgJID`JahBN?X zNJ9B0x)<nDuHI8teb$cgh{9%AZr99`A_1b_!U6H`y?cyPeT6qB&2;$LYnp@WLJ|l{0bl) zcoOn@Cm}O;64GiXAscoQ(pD!SZ*&s!KPMrza}x40Cn1A!64D%LqY20woP;dDNl4C{ zgd{anLVCP?jD)mF$TgdUM6pRo>6%mvNP7uY0Pj7Uo&q!gd^U#+#{MVp=VXMkE-?yg`ef=p2)MB#EP4m zDt#X}fSB-$&}9QwD(2HmawnHS!`FNWujB3MebFhygFnaVG{VSMinB5IXPkNT6m+|o zjJ6)5Z$$#lH2NvI(a(GvGy?I^nK=5s`}f13_s40vg&sR_+28|>K6U>-8DlKax^U zoqI0+9dwV4I0AGQX+x_LwSMd;qTfgxI-gV={Oz#+(YfSEG&w0N_-1$-`ji}5)_%sw zVWLB{W8{od=)huxs3#ldE+B7Z`mB*pTSYJGYywJq34TECBlv(8pe#zL0a^f0KYj&T zfU@0$I-qor;0J^u{0dY9W!ws`vl3_oT;v}+tAJL(+e>HxT;wD>D}iP}8X~y+&ZOr7 z75#)7pam!+huB#MxCgNWDC7&tB%uW;=T_1O0!jh|wCw3@22dr}iR!gZl%CPH5m3+7 ziQ1}8ltFc(gsBr%NS!Df>O`?mCn|M1Q6|!f3XD$FK6Ik2p%e89ov144L>WLQGWI)> zJ>Q8$_f90KcOtjE6B*&1NayZE=5;4BqC1h!+=;~F&PKqq7fS$|^w4f1ph-_Bn)Gy{ zNlz!5^mL+0PbZr6bfQU5r>|=z*Cuom(2S$42|$rvn-nEf11N%OL+Mf*>W^+X%GPPC!nL>qcdw4u#J z8#+w1p`An_&0N+I@18M-in@|CuWr|VSM?h7j;ffNf0C9kT%0B}Idj{(4 z43wT3{15@PT?Pua3{+tmD5o+|5M`j6$#4hGB0~TwbPSZy7^s0UP_1I1q{Kj}hk*(W z0~HkpY8DI>92lqyFp#rvAmQFXYP^A7B}VC9LM?z^B?dZ_7-&agpc9FKCL{*>j~Hk@ zVxa4YfrcXndW{%pGeY~GfaW3w`idB6DPo|Th=E2T26~7XXc%Ikr;fIZz6cdK#u&RW z;Gyl#479bGfr`T!s0Nu)2cV7046EZv?u!&X9c@7re9IEZb6rORKbFadRZO8ZyG$pL z`s4^23i(+I59l@MPvY7C`RGT| zfF31P^hwB2h&~Y+GoOwoCZ5CgTZI-W9(*s{;c4*D*A{wH^B*_P)4IQ?e{>d~|D;Te3 zUX8yRd^MX)BtuC)ncN-Ttx?57VQth&-Y{@}Ja`K#zs4 z<*)7Au5VA@7Q4;3Ewe4YEx0YaHL*2B^$-*3WT3@T(MVK}rl~H%xFNG8z9qONdp$ZD z@Yg4=3sZGO>e|S)`nBn6VpJcIxjKGz@apVU3969buS#ASzEZm~MKu!o73s~f&Bo>o zRY?RlWj7`^hBoq4ClS6}8>_K0O`#}{_ZH|7n_?(6cNw0lgAQa#! z=Re${wWOLO%{pcM$C`|$Ok=z;NO}K>hEN0FkgN|==6|X#Qm5CY{awCnO`;}L!`CD! z=U=N%RYj`wsx)Q&8x*|7SDWVY~Z(4zo3; z^yG6H&E;;$(+$V`pTZ)B=M`nfp5%1U?4$D;O-xV@#C-SYa1XN;-1@cWIOWZt=BGII zG8@5NYgICU{mb3{qv4W zzL7P|MzAUNyZ-r`G9zzO)-qecrg-x&M~<4qlB}u3nOU}ZM)qA`Gh)5Unp;>*7xshP z5~9LkdAiB5<`yQH4rcWHd-9FvqgaU2iRUAon5G7b$UnZ&wr{L`bqMDUObgNBi;A-3 z%qg#9wB^((U(9I7sZ+j$(GHtaUe9RlA`X|neM)}h($Af|Sh*%v228k3Ce4)&Wm z-elW1*1kIQ!~f=@EIAwguVA$0bojrL(T>yM|0+g14u^m1!Z`Tj;2$L6qPu7gp8nnU zkt7`bk|b1oMH8N*dH*>y?>|KI{#Vnye<{uTKSkPqCzA$X`d5;$j^_P&`gcF&{!ga4 zfAw>k@I1}=&!xHlA1|lZ(Avz;7>{WFWN!*1D8v}^I6Id$dG zAGe2WeeMa*?KJd&u;$<&8rm~H2*>y!yW)dpicbRq=F(nTDyKWB zzFI&E5GsLYpst<3cM-|}KOpoHG@!h1q!07~JIYt^FM)!8DUB9BhD1aG;!K9q8mZla4%42e|qP+8#m+;29*8aCG=9fo7mI zKxphDDBT1IQ2L-1>GMPh4M6Dt0qS@@6@Unx4+?TVh@ts}03GBCpb3D`l@H2PKB!0e zpl{@ZDv=M8LOv+y_^ND)qY?{cYb-)c92H@;xG7@ z68nK2eT}z|4(#Z}dISCD3-l9sj`n;xQ0gUA_7VbsyPr^nBg7378ixoCI5;jGoC+M0 z1{?@C4g`nYuL9)(+Htkrgpxi2R3d%l*vk;(^LYcbYgz!PdikKd<%0;5uLk=}*h^>) z&|Z<(Z4idTPd$(pPA-0b-X>D4Xml;nab|FKeB_RDaor&p9?mILGM=oHNUIWd?3veF~SNF%)j z`8E@OMdhB;uv=)S&})#*@H9P+%=6=o&G{vPo>WSkHaf{jrpkM1d$y0vOksvy&m{+# zTTFki#otF#!#;Ks0v$Gg8Q=rl{RA)20H`$X_-g@mkl+Ja05=_9zYk~uTwX#w&>pcZK1R&aiqE(X63m;_YOdF7V} z2{nKYD0G$h%X`nH=K%qrlr9?DK!VT@(CFo_02+Z(x`zCXK_eO8TJ*>2EcE z4V*j22d`JwvehgO>(LTi4=l=+20f){8pm-f<9nfGk$D}swI zZ@&gK0seLZ*F`7=Y5~5N;04P12sMNe7k$7f(=x{2lxX4C)r|2szQ6G6O8Tf<`{%iG@J0#sKuJHa8|#2(Kpi5~0i`(0 z{D6Q{trjQPVL%zqvesTYUCMD<`GJytf){60Gf<8*O62J9YCsd91PBdX1i70~4M0%Y zUmhjY1Ihpa60&}Xz543`d58eTP(L4_BkKVg0jNRxA>ZhS#G)S}fPP5#`Jub#hs>P6 z63_v^myWDEK&S#*fby;bcKqnBuA{%vjw4h8`hmxN^r>ah!f#VM#^1yPkNfC*s(p0a zNBv7Z{pN4!CvY4cm@+`|60}}I3n29qDscb=Z($IgQzR*&N(;W!0wh$?W1 z$^x`sp^=r|3CgXxk$jeVn^Tk<4;-O z3Fe0{@Hcat3jEFXkpp|uAI3g3KFoX&{~-85_Wi{BsrR^dyWY;em3S*e`h&?g!*6PD zrrwB<0%7{~*z3mYnNP+^gE0GA;4A=F+?B_l~anI;`VV|V72_$$FzvM(oI zPQApv*!6t$**#B3p4OjEKjnQg^+ex?mt|b*QKwGU29yMA*I3KHQB2ZSBI|VNoz2Cm3CF?%E*;EsSU=iFs{gKj&BZ<-e6)= zXcNCFxiL(NgQ?3Sm+P0OBQeq(%=E?kf_>S`5|@Q8<1b5Y2yf6xc`$ORerbArY`sC+ zgYip(mt-$aTpS|x!Q{H|I&EF*q6p~^rZ0?LXk3`NAWjN|*|mwap|$+lBxw+8Ym%#y zy^$XMJpSzTisZ7vCE>-9)AiGn3&RVwg{cLR1^R+CX#^(bbEo#s)8?h-M&{~s)1(S$ z%*o7-&koMc1{1+hkPjxi!d)6E14d5PPfni{JIOdHb7K6&;ECB25~L5vpOBmto~6x7 z&CDF%b=<%)TxaieZF;IB(xG>xjhJB=nf5p-0cNKqriG^Q(~@oBHmxl+H8NG7nkF?s zV@hUnd~$Gd_UOdXp`-bulShS*(nt|7a-@D_`V+BF7^DdpKO%TUc2Z(eXc9jud3gA6 z?eG*S1L}vRTVt(8YlgG|gL>gifl%Y_dT(7{?O;uNb$?~BGOH!D5Gns9ykEvI+XZ)UXP z^p5&1jCLH}Q8%qbhi_%Hb_Iv+vQMa%QesUh*E4$dVmKHvw3X3NZnJ3U$p0A?b6UH4 z^W|#~W^Nm^Ii}gw+ZfF`oL${slo`99I@pLld^@8FXS1t!Fk5jjyLzY1h;;^8&S@o` zRZnwgo6ZT#$8lgG=hV)%M=zYHbLtp%PKBy>Emz=BD$}W7>RFD297}F#Tt78>DNX2O zjXvACm$HAZ!d~kx+flTR>Y?{qcNb;Jnb+!PwB^)m#To55^;-8Z+R6D5y9DSMe&k+8 zL%FZ&c84|YSM~cC%{ffVy}u|k_E_qm1N#GvCY+_^KFDkZ1H0Wrjf88aHmNmwkMlT0 zI)K+~kc3*&0o+YGfI-p${LZ72&_}%hW%~ChX#jS-Ky&u%8U;7y0wgXX9f0E`;oH>z z@1nm;!vFkD68ayIgjVVU_zv{}TuT3b@fk_D?nz1b+Slua^)&zQqWS*^X#U?I4Ztsx z_TL4h{m0ScpQn8DuXnn-xE^m_{J-aK<|j7yOLX`l=KX`9*&h1k=dR|*vpblrjN@MO zjO=^ZX2d!$mU}&yoaxit`9y`o@+^~u+$&nH6lKPK)AFG1{7FU=Id^V%wE2!CFF|$qDP}8hBzAXYcjxAtM~9zgHUgh$zfYOJ zDS7T{_!(v^*c5vKOx~vC8QJ%&&4}G6_L3jGhYOoN5zEJMU?HD~kaL3d9PK?FJe|{&C%Yw;!Lg?Hg-fjpt@^19I*gm9;;)=tvh6t5*&F zV7`BJ_<2Sa#iFd)d%%n{D!;^R45P9=nj1IB zdYRE&ZdA5=oPwkBD@B>1>oor-deBjMH=~K%sBHHy`9oR$sGMZBf}zarUh;;rd?T+i z8^NeNmV?O~Fo$1bwla=`$uqL=lQtvPakL_p)pTrkachVQhvnl;jx{QOG;tx^|GZJz z8nq89g!{T}Us?O^(2UZQqhr2*bodQMJL8Sg%E=VdQyswOk17Q(=>R@Y`hW9C2k^&K z2XNgi>H%=ABs@)Z0LOoiVt3O2TYVep`BM$Rk3X*o*PKcD{ufHZE2RH-+65H%cS^zy znFq7=g@n+Ta+0ZRq}rh?mgaPG~vv9 zyw7aKf%o`;*@zSG@gcL7iF=RXJEwP5C}}Ef?z}mR@>@{u-#HGOV{Tz|_|vv6wYGdbH+DI$8lua!%78aug12KF4S$=bY^BV!Y7i^F>*+ zM;qgWHeX;g=FnSwu_!YW@fQF3lFbCp6Z}{g^Ll!h?Hs6>G)xw{n2+M{-@$XQ4stES zkZC_U{AJtcus+wJztp}`lqF}E+DDAGoL*{QWwgU~seP>|YYs29K}KT^FST@0W+rl} z?fbgT1kQf^SeM!cdY8Fe#Jtq7+`)l`E;abgM<(buovF02`AsVxw6YnG!ls#993B3K zZOg4aap*7ZZx&_A*~R@|jJBL!+}~of!*+3hyC`c8FYfO!8k^|FjdO4!KVRG;3FrPu z68`Xe(&E2U66&e`fA@=$@WujyR?*2Y`o?nc@nk8q%3(lA+Q+;#932g5Fmnf9Z@KeT-g z>vJ9YQSe7aS#mZC{+Q90(@}7U(GJ@vm?_Gd!%^@jjK(H93Yu>p9sX%iW+pUh{EX3r zvr*&c%vL5oYV7-k&4_)}*i1WQId_#gYGAp80}G8B__p@K1i!60Yq5H0zO7l`-mDzo z{BLi+wCxFN&m8)3>sLitayD-Ln$eciaqBmXcG$+P-xg)f;kflXMq>`gt=|`AhAztd zpM!tf`2(W~XXDl%nXOEG+#24?Y{bbu^DMI!Y|0oZJ$W;(|N4{7h;ihSX zpGd+TH%da_Q*?iUdj7S=WZ{dH`@foU|G9QaIA!T?V*RdOE?AvEfpj(((9AK3Lr0)_ z(NaG>h;;yDheSyCiA_K=&;kSi^lK5hJp>*Q01-e_A<+d$0D9|*3Q!7^0ci6gdI0n^ z5mmqoXaJOsM5qOdXvrt~fLg#0)B$K$BsKtz0A!IwNDGP(yAdG>C!&*|SOT~J32+1G z4kV)0kyr|p0gzM@AxkJiC`W{toTven02SOruA5TX(x<|smFNQ4-lh~9}}1JDSdgO7*?Od{G$i2*<-&>08? zD-kM?A{2^5sQ8I!x+uB;2|()~5uKYv1tXE`zJziM}%mdh=z?~6;KVJ zZIFnrPa+yziGH9CfM}Ko;YksqNFsy-MM(CDP`wj%0)4{6uq?C_Tz~|)0U1CyA`vaK z#4?~9K$l2S1-t-yX^E9U6@d1Uq7SGA`~cb+iD*eBqUV;_2s8mu^b(%9utfCu5`91|00l7- zDx4x@qC`k3icm5Vn}8M|0C2qo9zYW&Q3Of=7XS$|`h*bj6rnUFLXA;`7?KD*K@oaH zq6a_+P0hv57T+ z4}jL2=m#L}CDsEFei9+&C^iEvKmg$T2?BslZej`G0^EQMC_pJt29yI81p0(3mc4)m zpyQT^PHG}L!ihD24}kKV2%%OH{Z7ROpb=;S(4$L4?=>+1=m0-R5CBNK(nwEm0qB(~ z%76lt0%ZXDw$UI@r~p&~eL^VRi4cYrp>9TFJpp=LVhvCW_<=g09%uj>fhM3CfK;9s z0Cb=g;P(=si7ARe34r#kG`sn(5p=J19d<> z&;T?7d~^Z5MOpdo1@uh7JxHkG7Sd+~s=b6}z&}VR-%Dr!bimIoqAlafO|JV1Db&9Jp^u$5CGhJ34GU5dJ5p`CHPJB(GnLWGyv{? zf(q0DI^Z54l(dIv=aswYL3Gi!&x?9my|gT1g<$U43J-RwACR$Ueb}j-mrw(=0Cj@| z&t5_!&^Gf;zF z&JPlFK;BCbx@g~30#Yxb&O{$A@liq}AY&hUfqI}7kOv4J>KHdKTG==_mmYjA^gwS+ zI2>^8B~%0TKntJ)CEPrEJ>UTmw*YIZy%6p`OR>KIFaU_B`ADEdOlsnea2(GpP|RyVz64Q<*2@ zPX?dNK9P7L^aTGza#whlwkws0B=kgjAU0qOWOl}P26tv3PdpxaoPRv|SoksRvDBlH zNA*Y3kHj7^9?3i$e>nJXc1L1IXa~O|`B3;F?V;3zkq7k$(+|WRFdoRtcEwweWRo|MvHFm3UYvz{tEx}u|Hz#fm z-OS&dyeWK>c2nxc$c_4q=~ygg#4^!%G#Jg^khmdq1AjwuOL&X6C3Ssw!ESPatJ7D- zt}?F5Tp7PIcxCpA#1)|{_$!i|!<)6usZEhh`lj^8*hXVx=JNRE!OOFeL?jg9BgwvS zpVpVUEOHrFqypa1n)sUFn(XSt>d}a+-cxdVXxaF+X!^{M6v7*;AsY7^h_B z#pea*W#=a5hUW5flXJpzv^lBSk=gp}bTAe)f|;&(SFkI4a^mFB$^6O5lfoxyC#6n| zoT#6eKB4yn?S#~<$Si$UdS+~sH9I9S zB{YSflAIi#tW8cG9XVP*I(<~^DC4Nik?|t~he)|^tR8u>ZNHVrWi^_j>|zg>rS{s zZr+`g!jdMXToIS=&LETu~6aBlQ- zYFLBVPC;y^AhuHw+bM|c6vTE4Vmk$~or2g-L2RcWwo?$>DTwV9#CA#m(1BLqFo16- z2!IHb04_iR+yFv8MFC2IGN2sr5Jo>|1=gs57eM@{R035%HBbZifLZ`Spn@P!sRs}Q zDhL7<1c6F3&;kSizKb9LB7jIxK_sY10OCLeaiD@YP(d81AP!Uz2P%jIKmMFpgP>4B zP^cg%R1g#@2nrPhg$jZ~1wo;Lpin_js30g*5ELp13Kax}3W7qV89-#H1OTp=zyksx z0*DM1M1~3?L&XgsE>sW~Du@de#Dxmt!qLx(_)w_;5F{!H5)}lA3W7uhL85{nQ9+QX zAV^dYBq|6J6$FV2f<&bOK%}T3QdAHrDu@)70H6b09|4h~A^?aKl@h=ONPruV0R=#? zIQluuu%;aF02P1=cmWNl1gd~)pawwXsMG>}0Fk4D$WcM$s5Ami03t_)ixLnyDu^5v z5hwv%fCRV!gpUfsM+M=dg5YuVb0UaT5JV~nA{7-tB&i^hR1irjh$Iz6k_sY81(BqJ zNK!#0sUVV65J@VCBo#!GN)v!^Qb9PW1OUFDAOIqOa8hvr65s}8KmkgDGQ!876Kgy` z1)u_60O6%l2~+_HFO?d=2h;)xFO@o=9%uj%V=9O-6~vfI3lIQwfFC3XfCwPQR9t`r zxB(eZfKtNf=PbjTa=-&1;8aw=3ur(kfN)c(25JBwPz(5hIsh@J(f}alRGI+9oC;!2 zB>?C^E5Pq12!IHb04_iR+<;6N{hSKclmcZyIp6^*00f|l7tnx8pbDr4Y5*Tl3;2OL zpdLUBsx$&kKr_$+@FX3s2!IHb0O+-?NC3K8D`*I>D1_0^S&B7Kp;yqfMezU?fC_j4 z4X6arN?xf3Y5?fgD`@kgK($;!XAh+wXaE|4CZHK;0r&s`z39nX5lR3E-;=i@xB;{V zA#X(}C5(Q~GOR(E8Ygc>s0SK=MgVgA z2vD3S|3#<(RKN>p02;HC-y&24HGmI5mjd!z1jy2p-y$>sjX)F7 z44|ny`7MGDaJ>XHHz4Ol5DBB76AfX=i4oBHgq#>b1{9zaC15^Mi;04g$Ua17CfNB5@9~87gQfdJ|PzTfl4L~E%1T+I^1EH8L zlC1BaXb_;Z0$h~90|FodC4dW%05>25=ovxYjesr!N;%*GDgYJm0vb>WQ~}jM4d4UN zWq`aIp$@1A8h}Qii7>i9o3W+^2mm_J3UK`dw4zYZtVuz00tMZD6c-=?Zot}LeDCgk z(_2u{KKiQhY9<*^29w#{iQS>y{O;r{;a9X*QZGkd)?ZG)6nn{dDf43d#o&wC7ZNXo zUf^FyJ|BKwdp`ACqV_Rlxd~0xP z_SVF$p7Xf+@Rl( z-oh2BkRKi6-hh5tdP8i3u_1G5{LGUv~yAuyf45lPc92D)0U-{MwaSJ)1g?% z2xYqC-NEkclEjkG5`IZ?ad@$|ICVM{`O}MHi;P8?h4F>Kh1ms(1)&Ae(~Q$H^W*b_ z^RuTWP7R&PpPD=+e2R8TYF=cXJ}*5tHrJS&nG>HAoRgiMm>rtU&rSxzK`of-igf8+ z>61Cz{eajB#tE5O@maxH*_nx%p_%;5T(luO7vN~L?Ri~;VReDvrGFE9+X0*5#)Uw`$H{|8L zNj0o$YN{ea-KNr>n8)yB%H!q1@@!e6EL0XPHA*u|TnQ>!IU$E+UQW8hZq1#NB9bnp zT``y8%9O-Qf+bloA%;X=ObTH^6HTDgCFJ4JzhdCA z5|aMOoIZi4|T&(X-s@fsdxwt`Ku%Qoe0N}iE@|FRh|_a(tf zB)g7sW7cptn2BUq?%=>eiDby-eRqPnywe>?DgAqLd9B>uQKgQ&GYPGA@Y9-m;H*7$ z=u_MHqAWQ}Z4(%6IZbV&c?E2^YZ7V6tn#0sK7o#zUxxG?RX6Pc#|2cSWuba_? zv)o>p*@}bQUWM6+lic1?W-AlV?Hw*-HsVANqnz0aHf3UZ82|Fvj990n;aFb9 zY>X*Qxth_O!!+fZqRdPvP1(n2VuESPBiC&$vlR?d6Z|&sXEx&G+k73f6>Q4HzReHU zGaJFC*a!9ez$8!QXt;sd3O1#}ass)>XkK8FXXIavHY3)nEZ4D>oW>LmR7^ISgzJFB zknJa0&EdbEo~84apRsgtPxq2Vr_DL5XIb#{d3ff?+16w;X?=w8yhLt1<@dK49Z?#B zO8TaCmu;96UcdfhTmNdd*|J`2ZQeH8u*n>#m~1dvX!EK#{Ab_1xyzPw?PpnA*J871 zeS$HzuKtgr@NAn~IN__3@Wm6|!Wz>18z#NK9i;a+ogTk>4%PCL?w^Zv03IhDfNB4b zgin1}5|;m(bOA{7FZu;Z@R1h4U0Y@0DANA>^aWH)K-z!*y;c(LJwpmf59$EXisRumnr{$E%N{A@%K+x?!4F4#ho)U|Bv`z@5<@_ z(+=$6SdK)%wqNW=;x;-4Q#epD*=VxRkvRB?wqnU?b3Z=#!@A9+^%2H66wI5~YO`hE zyzR7MbsVUe^qa)yt>rGYo@_l@eW7~ho!-6tEb1dSXVJ3md2{gR+%>fCuyM@YL58m6 z?ljF|xq|~?4l=~HpD6ApJZj!g7^7j`DQ7I6)6-7>jnS)Mnc2w7>R2#tdpPTf5*UeVMg?y&O+^ z?I>nzOy4h$W;EyU`{m@K%uM9_<-RF46V}LJ`Nz9y)Y#1Ro8t(UJ2|k>I5L%+8hvcS zv1Ibj|wp;t+&<`YSjFxg2w|yWfEEzwI(T>wdwVlyU zu6dPx5E-}X)L=B1yWH$!Nx`bqj-t%iYiSQwb-Hi5&4m4OyN52Wt=zrl<%Z=B4lH!J z!EL`d!OP8=0Grj0z@}Wfdd=F^>+^L>owf1X&yCNp?Fwtx9Qv!TvnWgUt8Z*&(_0_6N)mU^7}TN#B2q3KkSpgd3QeyuFDG6_nmAr zVr{GMBQgjMHD!apyi`2R%e@pnDN^Z%5D z6+a;DzTZ-;f4e03>EDZAl7!jMOTw{ldxdY32Ee7H0Wkb`>gPxG|84Z|GgSZoh0m(O zTGIX>rnvv^zes}qGf8-x;{Fi*`#Ht_*HY{sO{#)MJpiBDL$=!80v8aub5cup-skG# zw)t{5Tg>>sKd1i}Tt1J!Wc_=>JZqZR67aNsAC-ifm3KXL*$$m`C=b2=2o`0@ng5v0 zXv?Ypn8RqtssEVEXot;z%qz;8L;rCKvoR+BaVn!ZhyG)JQD!FOKTcyb;mm(5V74-@ z|M=LcFJv|{-W+mX^3d=iW-Hhf`*cH|E6g*p?{u3HyDNN%+}|_Y4$~E4xq}18a)n=+ zpeuBiq4e(wP3*45`h7HGDc|)hw(Tlw*ByG-v!p0X&RkD7qb;YdC&XySsq0zFXot=9 zEGx>IL)WvM*%*`SIfK!hL)WvSC^HjsJ!dkSaOQeeGFx%rdd^}t;>7iw&1_}ju4nih zW+T`X`$TtsK$$nwJ$x>+6>N%X`NP~}f$8*p=h=){ud)KlN62Ts$vtX%Q7m_G;8@EXnkpHB1tzoPm78)^Q(i5}l1?Z4$SX^#GC()Rx!>IXo108ji% z5@t~zz&9xFzwq;tu#aN@ufJX?TuO8QZkqewwOkTTAPvCpPM3tsNdr*)Guep8#5Y!MA{JM}Znt$}{tyoh^l#f}Q0 zVmnVi9E9{#$l|F`#8aVkr$XdTg?OC`-8vPLbt**UREWc=Pzz8Y6rgf}v*-^1iuhI3 z@2e=?S5bhkqV`@z*}d9ANfs)q(Nz?ptEePbQADnyeq2R0xQaq>6*b^0%Dz>UZmX!8 zwtZUEL8~Z%R#DBYqL5idZL*58WEB<3DoTJ=)bgq*<5f|ItD*!~MfI(UT3Qulw6sA4 z6wj(Cd{t3%s-l8aMe(SLDo_;#pekxPRg`h6sLWIYKr4V!NR{s*piq%EjcUgB-?ykg zR8e}UqMA@e0ilZ8K^2vNDvAJA)c@IDg+e^rDpcCpR+*)A`e)T|a%)w6`*P0RG4kR@`h`w0g0SZ_ylbdpi}@~<^s8FlOHbWivC~{ri(htB zJY)VM^wCR7fHJ@XsDKaf1NA^7;O-}Qfl8nOXaZUQbq}Eyr~}kNf)DTmEr1Si+!^#% zfC7{O9>52*06O6E65N0S)B~-+;efB5!1oeFzyqj&1~dRoKntJ)WqkxON~i$5fFGy_ zgnmK^AOU_r*o}2S1>glLfkvPi2mt&b!2`I4umq?;El>wE04>}Kx}Lm*QoslJfqGyP zAoLPS012o9Mxb_xz;iSVihv4eKm*VOxB~^ zHQ)nufbS!SKnqYBC6ohxpdM%h+yev!C<8nIq+M0$tg4VsRiT-ED4MEJ zDpes;szRSsg<_}*B~TU8Fe+4GRA{`Ye1JyDG5}&NstVKt5L!{2O|;WeX&0d!fNaRf zb#GmB&<{}?0SJMp&;U^(|3L?k0M!l^f*C4AFI4DVsF1Kwp<1Crh(d)1g$nrz6?zXU zgd0?7Hqe0~KyN{X)B;^|1ZXDE1`(i?phD$9g}?xvegr55sICCP4QK@0r>(;JCZGk- z0aU@OTo(Z~>a?K*6r0mAC7^Viu1W$5#Z{DjtEl)^QS5DdcT`>5R-vrgwhDFAwpA#c zwyi=@v~3ltqiw5D{%l)?I%wM}6hzxrp~%^`3f0cGRVaJ5t&#>$bdZuX7g8$ zTS6yJS2rC1fX{!A+%p>T-y>kYsJicT^F1p1%wLsu`aoLVD@WFskXoO6e#MU5ljs*U zKw5qDm4a{>y~f>FA>=+p7rlYI|J>Yu*;&z7QEIN|hZez3U&SQz*MRqQI;r}}Ct}@v zb6v~cMRa=YUCO!R6}q{`OTW+ww~VZ{pJTnF^+)}{ReaY0&k_z?B_6n{vrItBE1318RTfOk@`n&0OV(%F5WZsUy9eg|V zR{YK0H`-qhe$xBeP;&R~=queX2VUCy!k*{*pX+_L{Tc4*!6yfv=-btm@D2<;zWcH0 zqsF6|N3=&$52ts;cElg*eNcNa_(1ml#QmZBWA}C6%ipWrGt|HP?(p5(-Ko3McMjaq zcY7Bp85*}`w#7-KK-)TW%kG<_H+A0_i0!>$&zAn{d#`K1mb+%~s(~v*SMpaTuLxhE zU6I-x*{p9)Z;EX)Hf1)(HwHImFW(c1MD$3yFV<)DWiE?f7Q8IGA+aH}f!~n4G<>Oc zX=;6By}mwuN$e8ilFY^Ni-Q+u*Cp14*6}0S0z((XF9=?cU7J`NTFb9Zt_iQv)}&TP zR_m+Nt75B+Rhe)+91LfB6TP8czBkzu?$LTu=SR-h&rhEhJI^>Tb8h_H;JMjz66b`@ z;m=8)9X?w-J9Sp%Ed8wX%GgR{W#-KInZYx&D-tV0EBF=3Gs0(RXQY-#mg~#Y%VNun zWtpY%rNO1yP$Cox@u6gQxLfN^Er~4Am!ucR78{E*r^inZo}OKlSQJ{sFG?;9FVq&M z7DN{43(}{>iqsc~oot+(IVpZp@TBaCi4#L7@+T%w2p6e281B$IQbxqkjdVNT4t;@~ zwm@u3_vDzVEf_zt_Y>_$aFYfP8))s*y8_;pp{Cu9(T48&Kwa9OuLroNCQ_r@?oLZF$&fOxxGU(&mLy6-C45Oz42znW5+Z^wr1=GGE1|{j`ZAzYzeH&~>tXEl65s%Y_{UEoKsBl>BFgey##Kdyj zjGli_uJQckSNE-@nTGi^b70U+f-TiD&@*@ACOjo@G?uKX25V|!zo~}HY`ezVRfm46 zp|2=Q6P#)oIjbU!ww(Ip%NgxB^~oCeuNPza zcGyP$7^Afbj{erwH}>No^#EM; z2TAzHosw`5{X60#NqFx?Nl3h_2`A9p|F>xFeI`F+*vfwe-ZWhqxt`T z(%k=j^zTTT|NnsI|DSkW6HcP}|L@Se|3;es_t4|B%cy2xwIuv-sU%#vN)oC&sK;PL z5>BH0|G^>B7>LsRKmA+%+WQM0baiq6@PC~D-_pOI{@;zv`^$kJyNTHdT(aGd<-6qk z5b0)SE7%mf`^t04`9^MGG?H`4cIP#&OTLxST+Sui9a%w_ytODZ_UQ6pE_vTJn+fX* zvZ9zL$!k5tJxx?NEYCDq$d7e!9nsVI9#T{oU+BQ-2`)W#(P_(;|3@TNwY9Y!H7iiC zS~^#ev%;!_9#?r`^qJ#TOxxqADS<1(J?qzP+!W{`&%1Fy$9kLXSXsyJ&^y-cMOkv@ zSZ`;v<!Dz>+W4)8n4x3}Wi_zK@rpSyvtSY6uYo%Pz=-G?WU?lpzo6%5ivuNbV z{~0akGz;AhX0D&v9B$#-ebcxDdYsXm!x-zHqRiOc)WHVy;d>cPIE%6FW47WT#=75T z#5#j4-}Eech^t_N&K(mJw--g7-zlqF}L>mf#4PCeHSMmtVD*TalbO1I#O0oPMRIg7O0LOn>623+n0Iug6g@KilFq7^DeEV2Q z=(|!9c+vv6=Wq1-2PEO$pHof2Et2rtnCCE zw)IuvMY@Xb;a(yt9F~tYS?H_6G;UgSVv}+0JsmyEPCI)ZTMWB#-8E}_DAMaGQuxRE z(qMf_*e_~)%C>8)T{WKX&3UQ33Ki_rXkl@zry1?!yp-MZ7FND{hS5&Wd5G4Tk$a4) zG^wm|HpLD6ZRA3HwkT_MDXwvR$8*fa;5+ON*z$|v^}$V>E?>85^QN^lahtbo&oi3K z`3}1qE_fH~g`&*R#hU+faLJq(8BOGThdo-%PbISD39}Q|vb|^D-pzjO^QOGh!V_YfyfLj_odPw>cs@49zYvu0PLY0fR)=MVK3zXeD;k>s)D6F0;>JLpK<`E z(c@QUkiP#W(*LL0|J%MH2@OA$gx7AAgoX64J-NUBf8-Z^f7s#b;ubc19RIg+IsJcy z>#-D=aQco!A)jL04^Hm@ewxuv&TZQRknv)x&oEnqC$+~PaS{}fKs z|6EaK?6Jtf=6Lpf-e$u3VAeqQI(^tR+#5uN!*Zv|LIWLC#qStT1?A&`?%$y*{{Ps! z6Zj_T^nc)UB$Jukle#8^9B=4L8cs0D=cf;sqjVn(r0Fp`F=C=JoBA{ zN{bKrVEo0JO|5MDk#E<&G^$7=Y1imw8aST6tTEQm?b@N+jjw2oQ*XQRRgH1VhgNO7 zG31qmuZ=29ZG&;hL+ibo5VeQaTXZ;WW8PK|EzD14;82GaK0~}X(nIUNr>uVzW&B^S z*%y_4bL5Y`-cd!W@7OD7j8*Tk_YIA4>OJBn|21QD|FCA?RQA=8Z=ioP zsz~)U&_C7~tKJ6sCmQ3_+d%(RV;pS_bl<3=)!9H7H3zGsf$lwUIpAj+!wodho|kpp z)BETg|0i_5{zt0or+WZCq+Ea3SLt4W7wCNdD>C=gWde6Po&W#nM5+b2M&JZG|KIgJ zfjgSc|36FT{tM{;KYw1}ZlQYsuK6!J=b`ccU#9c^vnlugQyTYw!)FCfdP3kruUNTH zMrkZT%K!hepY8{s`hOeh|N9x{cOUHj(?j|W=H7wxf3->LK94!07*}U?G!&OQLXV$@ zA1IGrW5VcMX5a=M5C#lG<7)B13@pG2T%ZwzfM6#KM9m*|VYwSLgQI}lK{!AJC_v~X z48RFoAPgeF&_{^C4LpGBppmzDU<4-M0&WljVIX!A5^w=GV7dsFs99SZmfL{`cmcDQ zV1XG}fFA^a*h@&j4+6m0N0@*cct8Xwz{1clT2{~i{6HTe1mFZN5CB2Iw-P#{W^FB4 zZUtW81G+Xs59~k&VGsf4PQn75zy%sX2#6^{0v_N6`ffr1KF|R4d$A1IfeZp52#mdi ziKtmy50-m@u8+_I2XF#E2!JNQ^b-;=0w-{R2vC3&p>e#7zy}(Dsf92D2XKNQXar&_ zApsBY0$m58Cu-K#i{(C`>%?yW8?b{QXarJ&>F{=9AQqQ=3CLW37c_JM)DK5mbUgBQ65FLDoF z#774GE#2Tnw!w?+gBJw`FA5G`B(w~QXc)Z6I(U(7@FLIPMc%=SB7+wxgBOXdgVswL zyvRLxk!SECW$+@VW6+JRPr!Iz_P#boDv#Uipjm3<+ZerK zHClJ8W0CpjTWanJeJhP6r&wnVj2vg8Z>giELFUXrXu%v%FeG1PusRb%quO;^{p#Pc z(Kpo96Fy*TBOJg3{2&aNPC^ePUlNcN1p7_YxAY0((Cprq0FCvgOx9?xo@Sye;%E-T0TyJ@~EeIK={95C%=a-bo|* zxqughK@+fd(&&C3j5=uPq8ERUb&C38MA~Q=#XSS>1P^U04MRy-XjD0y6Et77W zdW3glox>mkc&v>Gd>{n8y@UdqfWD6~0uPPZsBfk>Re2mj2JaZIgZ_Sb??^OjlR@Q# z`9IVD?1BH^_dws1nI~gUW}b*W5#P=3&Seu>Ih*fJb}QY5$J38TA1^+Zc`Wu==F!-r zrAM-l#2-mNoO>woko-`7S8|uKtMFj@!RUj<2Qm-D9w^ zQ%b6^HN7=+L+pmq_3ZVzE$o)ub;WCYu1Q_pwmGt?f8*W_UF$oNEuGA|-ZkB;JFjfL z!oI3+MbGlovbLp>CH;xL9bN4mm$xip7WQ7&eQD<YLv)FEzI<9%<{Jv-kY2 z*&XM#oXeckdv^C(oikf!*w5^X^|Yo=Z#yk=YX8Z5PwG0cV|vR8%<;M7635BM<)!jPsUh%nPX!EO&Cy!Q+E=){M zj7}_0$V`Y$D2>mKkB?`^=f)*y9KYh2%$V4i(oxx?;zzMZ<(d=Ca&x{Z*`zcTl(Z66 zijhnt7Ab|Z;dq!0=R%2)9LhH)8tv@_}~Ix>!!qa7ael#yamNz96Ikri`>gh4js zg|1=7|MSVtQy-@D|0jb7S64qCU#cFUj_wPXnW-ixO?Ve@0}t>5A7}u65CB17Y-wY7 za~omlA)4Ca49`a9(yxHVy@aoyXaIf?071|QLLdwxKmkpl88G&F^!ETdH{J_;G|(*{ z03pD35)`Uoqq0XuMXoK3;I2p!M^ z0T_S?Bwz$4Ufd-)KCGwSX)I4zyBdKjPx$ggSDxt06QMjYlqX_&B9$k` z^2Ai0SjrPyc_No5&ho@vo_NcXhVmp(o-~#x;qruQQCCS@2@AkIsecL*>G26OsjojLE zOY1GYH+S6Je^crv`%T?9w%oWk-Inf4b*7k9*Vf3^o*P+>iz1797PcMKxpeO(ZI|?2+<7r`ao0tWi+V0>y|8zF$Nc_z zsd@H!-E&*!?u{qoO1#jPZi}`RFUVXFyPz~DJ10Jeos&C1alU+hes*%UGP`hI`n>3Q z#d9;~#?CFBlRYPX4tq{+R$`VsD}Q$KY~}32S?RN)XBB5=X2xcgW@Kl?XRtGJXC}^+ z&&;2ZJVQC75KG6Rv0`hcHP%`>J$rimboTVzX^GS1)AFY#PgPFsIi>ZK-jh2{?msDY zQuL(aiJ22)CzhsXr^lzW({m>zPLNN?AD=v4IlgdQ`nc$E#c7#ov1z5L*{SiV?9|+p zMAdlw>6U0qadKvIY;x(??6L7<*<*9ZB#x1f$xlj7QYICSP9GgTx;Qa2F*dO@Av+;H zft`>WpBOKX&yP!vQ^pm>rpHD{dA=VF76X|;EKu@i{c%6*&ov|(mFv+I8F=rJ|S-V`9mWHN*|9AtxjRS;*^?dPQH*rFBtVklY@&omFiCjco`mNxNqFd< zgoiOnc=Dd)CB%RFFxvq9AOL~@$wvw4MhTB@lJK0q%9{QY&vBBP03PNf;mLgxp6Ddu z@qLm&7#bu4=0zX@BQOCoumGekB_t~)JPJy}bN?hKA$nYxbpsFZ0v~7qeh>gbfZV2p zY^KE8FJr`JjvQFmhGw3=k#s;01YiInK*Cc(ic`XKs3bgeP_hzYiw(1OAOi<*0%SiW z?i!ZWfYJP=XBqp>7B6;bjK;>BLf`alEl17uMpmRk&=xN@3Ui81`gl^E`X%0gfy&#XNpO9fTV;6 zi%EEjq!c8?-Hn(HfiQ>w1uz{13-Gu}36CL@@XSd`4+J0*l{M{=u*3*Vzzi$^>0Aj3 zTnP^_lVsokPT&G~Zl&ZU#83M$+W`C^0FdgHkldBRg!qLBW);u`ngJ5M5>mU8ju5}D z$E*MhKqM-w`gNpxB_wzyJT*-+11lkZ--cN`kbwgr?JFVCE4hIO_z3am4Vd+V00;u4 zek?1 zzyXjimXINq+`t3yOg6~}@F+IP4}yfjZ*0VT2!ufdD4+=-hb-Y)Z4w7~fah^adLRHB zF|b$t5j&Q+2yu)XvmW3Dek?pXfY~5u1R)Rx5ugC3hhPB*c%TD%AOHgpfdq`e1e}C; zmK)CU!Sg~e9wwy-P>9Of#@Sx_;YA!N@jwRzEL>o~tOz7v1ZF}^STJh^Hed%1LR{g* ztP6PX{gqzK`hXwbuM1!{2pT~c3pYkEs{po-@buHdmwhl7fUh-@l{J1NMBhjeEPtD2 z7BJ!`Ia1PL_FX+@4VcY~m^EVdb7uH?3l`Wg`z1SO9hm*93%=)pyAo=FC_RYBNmv6%9{Vyf+aTm@DFy(IxzcZ z7c6<;U%Xh{fZ4zMF&o6}2e#G)j3HpL(}dbL{6pXbZbEc=FzW>k_}=TsYydRk`#=b@ zVW8mqFw;h}EZ_;TS%+CYFyQ-fA~~?ufpHR+o3Q+7GiEKohVLiaF)ITnzMtyCtQ&ao z{RuwIHh=)WKRJlm5N1ycV>SYq4uT`ZGkMJFF?*H)&XVA{COF#y=h$GI8(!pvmo&i3 zbe-g4fvl|fQW1-m8{tYbyuu1s+u>RV>~z8P9=Op5H?dvh)q1$a0B?|B$^>t;z?*IG zRvB)0kaW1y?CoyMdNF%v1MCXGyMtKFb<^y9JSpih`=9|nB*8~a@G%SQwvm-h*zLxm zXT0#a2KWNImwbtbJvvenF#DL9 zceJ}mS#0I;{9}p7*vGPz#V$UQenfdB|8U}A_TlV9v4@KE9KD_g;}4c7haG*OaDVcC znKIb%`%3p_59F{*cW3X8-CfFLGqFsmE87+8D&3W(Om^wc?47YYOLU%}-Y0E1YWC{v z=Gf-arU*T;FL4!nRc>QqqkQ0;Ke1k3pHC)|ax&kU=#)G2>yqn~b@{c)waVJUn)DiF zO<{FMRrAe1-l}*Jh5C}o?n(+rYtKgO)rfu zEiTC{i7hED&Mb~CE+w++Gy5VPh4wT(gQs|T=JMF(rA66A@kQ*S+`_~{dEwB{>q}o8 zy|{Q$=Azg|ofj$>7UrktN9PykWrlcGU+#j$1@Z;?ImtQ7oWl9(^P}e%W~XOIXBW@Q zoVR!2Iep1dc|XYx#x75cSf!E(``SqFhnuQxl*9J9%QjxM zey#fKup>Uy;bBMB`fbg=s_eTXe}CNXMir^P`{RDEF;>0z$NfQLoObtK3jaBIm*cUo_&AU90Z$EJCyHGV}<=ga};b!O}%^d(>trj3j1eGkjimg=|=O^ zb-u}bM(sv1Kb3)p>qdV((r$Fx{{!7iWAw_E*4V;pVW>ORfUG>zr8Ut_p(Pe(^`_1Dm6SxiIu_nHQNeWdU7 zLwBf$9IAuW7^2+M)pn-UZEDph8v8iSQP8H=4hT{;{$h0yUULw154D2|S8vJ`hVr-r zA98e>q6ES^?sXdTzwL5?``sFW+jgqJMXndP9F6&Z<{t#^hcw>*2KwJXWBxx%WBw<; z3q?Qe7PlPzRrGg{O#fT#^Wm|}-h zWjM_Nk3%VdcsyzW#1l{qAWrwd6HyKzo`iY;@#F@0iXWaDfTsoF>5Z^81Y==%1{)#I zfOtMi1jIS05fCpxkw9fL+E6SY z#!)RG&PBO^I1lv#;(Qbgh!>(_K)lEeFIEc&EfkCpyh4Ci8sKUXu2IVg z)*3Ot4)p|;&FDm3fta+w^;Wn6r3K79-q`Vg&I4R3nHFq8vfog?a?> zArvHt52GSMd;}#4;-jcZ5FbNPg7`S962xwlC5YJo+^tq8Jb~&2@kx{?h)uVeA?`z2gt#Ad5e7el$_SA~X@tn3HbSI3Wk?;WBSbyQBSZo95u%|1il~qfr2sUd zP(n1JPC_)JP(rkzQbM#wpiLnMw!?34!XlaJA{{Jra?r&?w+?#r&?`Wn0XB%xFTsEj z22HTh3_}(ew!(-FDt6c;!)6CO$_dA~;8-^t=YiufN?2d?(QH9oku0j~3tmCfi3U{Nv%*EhlqA-FLNuZqA;3f#>0kymr@ z8XjJ&gV*Wd76D#wfH#P6s{~U>4SGQkd@8o@?%jZ0PhaMdm7=rA$VUH-XDPvDDc51xQpp0A7bId9DIa_kLuuK zdib~iyA3ca!rc;l!U&%gTsKdBb(e2QZzm;VkA-&N~(K8^YvajyXB z`VILRl<|n4mEh;pYM%cxVgB=KP0trl(<6S-3csY5_Iw$oJ>pkn_*Dn|niIa~f?s!& zmCfi?i+&0y`Vqh3gWptZf4+s!*wFrr%ZG&A*d)hkYmeso1BApG<$U=M(Wyl-|y~9eum-R`ML{Ce)S_-mzuDh}egQcvbU%|Yu+#TU~rDlg_=NW8$lkbOS(eDS&TbINo1 zXA{q|&t}zngY?tN)A>D#J?x(BQ?aLtRTT%>-M!f)-8G-L9r{{rF7-*O5DZXg-V0s9qBt1sx?ULWOrt7kKJCRyXF=Vj-{<`&~=y0;+T zmS|(!vUF!baZZ{l2=a7a0egOSc8ux=(&zP@8>c%8GUr68dLT*n6Xed0pIxHbf#_L< znaP>*%pBcIP&zYnX7tPg-AN#yk&DG+CAyCw+FGEx0r~V+su@Vr9R&GP5~r}IWKWKr zTs$d#l0x+Yi4)lqv(sbKi&QP3(ES666sSf(rf~t{<4RN^5FOhw zh8>eVDt1({Io+(#r~rv3wkfN`lwu?uQ6hP&4Pe9BP%KnbD+BVuM34<;>F$7{KkZj& zM1X!@#uugg0+L?Yo1?J+O74t1>Mqbo0J1CRj5|v-4nWjVkdv}3=j?H+2FTc=wt_WD zwE#J)1xT3{bDr)7U`<(Lj79)ROA6HiB*r=NSU-$JFKX_c<%6zMlRS$UN|0AjL`2X$9Mh2H$Y9Fjob;+eF8@x}i>0$_i z;F3%2b2X|jxl~;&-zR8}f=#Kt?q9Vj)j{Y|g!)zQwYKu6)L!E3B5sq0KrMjeR-UE~^`H{^ z(ZJivtT9%-$peeVIQ1qEtQzBJOCHcjo9b8Pcp2$?Vx`)O)#l^}4*l|b7Jql(HL`1t zf|1YY|Kjx=0@CY>jQ`%epN1A{2(4vRU z;>|y0*zVw<+_AT2-&FS1k#GKeql#2t^WUH`R=v%?Ut^qloBx2uINF;3pvGwRHUEv8 zqtwy-hcpMl=W(&pQk18u>Yl9nQ-4@<6l_Xut3U90Ts@c(c%UbXXbe*B$!gpDVV};W zXbe~G$!gpGA$zi>QH7~JE34|s?3WGfxR07^LR4PVO7s6^YV03mzN$9=m_M0;LpA?X znW?EcY zzoi?f?^FMz$g#&BJK^NWFlQqdRn9VoJsmmlo8#*||CkinlxSbQY6CrKojR-y6F&7d zKX)nR|KHyta5qu@KSa;|d+SPpn@7+7`y-A0zx8(l=iNc$`rk&i0bdfh?>{4O?|eb# zE}{JY`^yFHF3SIpr~Lohl>eW9p}_rVslcVE2Ed2>|4jlngK7YNuv_5X&CA@SR0HrA z%KhI-H2~vj%A_d&f2Z<(H|78T6fU3tt8Wnd0w&B}s?K7#@|h{4i6*=mSb!DSfeakL z30wf9oAVgmoc97BXaIf?06`D}VGsdq7r_A@U}SV2W1-UsX@m$QU<4QuokmF_tOTv0 z4fA#&0|#&d7jOd)@B$z3g8&GEMi2sF5CIBcdkGHk0An4{&}0P0I^Z$X0gs^$cno#G zn*fG7pyA30luz&|o1isB-2{zaMxbhfN6`e2nh6@tj6kgf4H-qCQi4aJ1dloi9%T|V z&KZFs2_7X9G)fhL0tvM~f=77-kLm~-ONu~k1dpN!9yJj>N+NhvMDQqxprNV=lta*% zQv|9Ycoack4Ka@*2p-iBJc=K9)IRViec(~~z@zYiN8JOBibbI6fk)8;kD3P>bdX@F z`Jv(12p;Hw9tgkyL?8hpFaa~L0voUc890EGpfz-1-VHp!3w)pf1V9ipf)EG;HbQWK z2Rfh!0x$p(7=a0xfdyEB4cLJU9KZ=&zyrJlt)UO|4ZsfqAP5>k2!ufdD4+?jEd&R6 zpaXg!00WSK5tx7(Sb!DSfD9bK30%MpJitp}4Kd#U0w4$)K?sCF1So)MC0M`%9nb>- z7=Q>QfZ74x1kAt!Y`_j=-~dkG0&aj(0p1II1g&8M=KUZD8bJtzK?Ep(=^$9Z0Uqdp z9tc1L5-MCj z4|G5e1YiKj%+p|zgb|nkvhvgo5H^5hJoN>H12};TxPb?Ffe#=Bk9~;wAVBV&dIKU1 zka*`6&;*z+f(0Dlfez?_0GvI98~8v7gh2!-fbAtXzylo+fB_)+%S*rr%ml5W1@l&b zlrL`wNcB?NO}KyuAi>M~fFA@v5Hx}?hyVq!eFRdD)Rqzf&~^t43y}@ zK#2;lqzDP4B|234Xf6Z<44Ejl&=`rKHp13Hgn^JEtlfmJ2g`uHmk|1hh@A#Xa9_&=cPPjoBH1radej*5(Km+zH zk3HLnJu6_(>abH?z!{-E*3e2c0c(mdVy8M)`e-f;4A`?$3-(yOWqnu%B!Dsgc|7-lZ&Ww2jpodt0ehS6Aw=K+A>hU?XL|_+i2VfD zO8d?Mgbt!XrIY5^6cGd>_OTuKK@$+W2@8$aIy2=6sw3EX!Wep40Y?FSKj8v?5C#g+ zF*L}n2rR$>+`tEdAOxC$&Q3_c0_?y6JfHzI0tK*bgbo;i8Q6gfctIlw0|hXhgapjM z3h+N~-AkEr<@LgA>DQv_-TARsORr>KiNC_q{rQQUoXhtldlb4yKmBs_<>E`3mtrrK zUc_Dc?29?dn#(Wb)%)}dlsAt)S9~_}Z0yTJ^Oh4arW^X-Lo%0mVY$)sPbrm?%Iz& zQhYe`aO~mILs`nCvk&EVC3eZX@{~(g9xObNrn~oxlueJ_U%D?#_wTd!bW};cglC>??_T!y|6RAGrF^QdxkRWr5)KF@g3}r z+--^5rT)mG!K{@vPP05>-n+i9kDa&3=XVS5BDV0sd z)w}ryFN~N_uRmJ{mD+Hv#_pXom_Qae{@Z8b!K&p z^6%Lz<5#lkz5VhP`BlkP%BsT3^vdYU;)=|Q*oxBf?DF_>c6n}D>$1|)?9%vBc4=-& zVu`#YPq}zyaUqdTL=#2I#>YBJ?b-HtJ4^Za#O3nk`9;Y^3T5Qe3!@8*3o;8L3wke0 zQ%=5kY39<{rKL-M$z7bdSf&XI7)jyz@h6}ezf+oSd(<@#f`k~M3MTUpBXCoHlhZ%$IizhFw6qNbuT zV~mV?{J+iL`sw$x`c~%O1NHya`Tvt~1z_L`+)*_bl9~s;Kl0bg$BZgceb>szYK&Fy zweoQqS{CX+<`{oSdAg-%bQNt9HoxDX-iFz z$~&lX;ru;%SM6bXNr}Pybk(6QoVPG7sTCu=a6aY0h4VA#&Tl_w&b*mtUO0CqU371o zJM&ESdC!&0)XmN98-~49UHRquuT;0sN2v|vR&m=cRgZkHHDy$h>g%?djrQEu34lf2dSkX5xR`%cmv1r2*` z4^>s#SsmnL%|V90G5F)2@D$BahUufKQtuy~S`(ylAXNIOZ>W9Lx70og^CvTKs6GnG z-7D(vqYhKzS?PI3)E`uSdGy`E|9jokX*Dlo<%K=+-PGx$id0`W)v7U8z1>tyW1Nw7 zQ;|w7#lAB%#yM;^CE5h8`%ZzIPXB-PYXZ0UMS3*1D?|9@esz;$d8xYGLqcO(7Z zaJRrcU!?khG>t8g61a7H1y0{h`TsVC>HhV5V|VLY871;@{eLr49{=yaM>I4n10V6v z)VLGMr((5T=rBW8&Cnc7(~wm&HHItq*R>t#kp1;pqY6{onI5vgK3ijma(`XhlMdBi z&(a(Pom_31)DZpkIhuo@zpgEks@{~Uu5{nInxkM-YVTdC+LWpwADvedq_)5Q4)xA= zGv6g82J_QZhw86!PC3F`Fgo!Kk9qEnn4N!wn?Zra2f|<=WG=Vb7xC8pD-a z<=P%+$X0posKU_ETK#qCL2Tz~3{h^CYx|e#rmXq|XTIhrXv%84m#U_$I>?2ZgP>JD zTnAItVD7s}bCh8^n5rNjU0f5S@;X+|qP|bB?QZ4=YO9R-=?pwvtNgW*j=nebe_^Xk zw@|2;{ic>L`%OKlmA<5AUsd+qk#40g)flJVR{AoHakRD43q}>K&Q^M%=3tsy=|vjD z)!9m4KB_Qu+*W@bx|MF%7^1#bxTWI{h2u(jhvY%T)V+4vqcyE2{n9O11y?zYE+GH1^+dzZAHyQQiMC z`v08I%G@vJ3fv8g>HMFjuhQ6mZBc>yZKuFp+b?jIUONBpWtew9ob>M}^sUSi<>T}J zrp~{rt6KiZ{L!+Sol@D1N(cF4I;^HKeWb)-KB_uY2RVV6klLYkkY~=0QCjPun@G-? zGaEOSoOR)xGwJrh`fea>U$u7isUAv?GIYidGN{zc_j{u%w1 z+ZZURwx|wuERSdK-=XgZ8+<4u*1(arwq`Xdt99g$v~{D3RNs--sWDc)M_N*29BoJ1 z`cXxz^GMsEF<6~P+Qw0Z8Of3M(N#4eYLB#E&|jIs{8~NIFdt>$P)8bi&4)(TYt}dF zind;}a*{~Hu%I?1THT9os@d?$jyUqi_U2JVs_)poT4StwkL_zT#?f|cUpuO3bspQ- zX$)59vAtzfVdxmF{yJnYy6<|8A?iCtyg_r6k)I;&-&zx-vhkG<1iz&n@(=?h)fUyE znyHb0AV4dHSOXsjQZ=hlS*;`AXrxCKslGWKvzLBM;SO&YljbI&yDOu z*_66cuSe!XS>;1orGU5kL)wm-9Z}gaN4~wieN>U^Yj1aIj8$)Ydxyq2+S=PYM-{Ek z_VzA~!Rl;pyG9j;j>+n;Lw`uiXbe$bvvs%TC?jvS_T8g7NIlo_@6{Xyn{t?Po~mr? z{`+czR9?qQ3*1ky?K=#VR9jSsYJo@oc@qsVVh!|Z_t&gOWwnlc`}e@8BGuRaJ*Y8O zz3tyFjd8TKe-Di+TAl6R!uUaLD48M@JQ=w({hVC5Mk` z3{h@wYs*fCDsFjPa}=~uwRI;$6t{G14ua;kwjr$El&Y3+UsiJzY)WlmW7Vcq1^H-q zO_18=_I-K_EoJ_uHn*6MGH|Ho79V&&F|rT5^*x{YzvlyQ|4*aZ z|8G(4|M{Cl?l&~{-;K)zu92p1E~T*mr_t}zd4KAg^!q=j-@lQ5|1>7FJL+ep`Va|1?XwK8k5mF>EnMX(Gs7r^<2i3u}-l*YgIn}k(ma| z30gXdkV+5D+4mBrj@eAG5x7zW(?yu<=MybNsCNz%4A|pL(Az=;+6a~g#&OW!@1zxf znpR)2W(MMLv;pcSa4l_&_etv(>ke#U?N99;^BL1F`nNY!uc4ck2ANJm0xqEMBCMbR z81@nt;0AmzAp#3Lk2?O%Z0`0ZbQR z1s=fk5N6;9re2}}@O}6exPh6uhzUADBM|I_3p4|{gNOj3mvDkGF!T{_z;#^A1dYH2 zLO|@qw}9y)Y`_DUy@VO~f!K>VVC*B@AObARCA7LgA0eC|0QgqI0=z)iM%Y0Zm^%q4 zXar)4@Bn=`;RE`;gdGHcv6t`wT_529e$WJ@e!>YNK#E*Se+8IY2nPrPv6b)uT?gR> zx=z9dfS%=NMz|a6i}6&|8Mb(Ew00vYT2$Y9y%X6KHXRy|0atc33%TTBcAF z(uwASe&(RXfk;~$qgSj(>u&2V^5Ipa5e(VFeE00Ra#OtR1aCFaj%Z0uS(mMwM2YQvlya z7(k?D9wX5PQ0t2pyxF>?yeZ{f(!|WduIr=@DX#8bzH=5MJ3$!uQiQ8@Y5BDs_(j_L zQ>+34S1pR3y8W?JT#=vVw!Akx@yh8^@r;`Az4{SleQdh@#}hQGOou+yk&eisOL z&ZV8+GKVpBV&iFb{`2*pJ@B7B@Si>KpFQxOJ#a+#K>yXs)rHOJ&C$)pO_@!xP5F(< zjmpNthRpid`cg99$#xdj_R(_%V^@~0$X=0Im7}K#$}95AlgpLm1$v%fbXjp}W@&6` zX-RfTdUvh70f4+2_;eJNYir#i|v{ASbOR6EInC}y*#%lu}EH&Ul?0Zx-@%f z{8E;lD44jUcwy$k+B)b^qccaxjxJ5i(zE~AiMa`h z3G#$IJ^fD^Ul^Aj7adom=l{jVmd0eq#OWD;xuX(C$w%dzlk^n8LQ}da+Ei3B^c=ua zBpZoG*hr3^1Sp5|p=3x273f)j(Z*sh6O08*fovciU;{aS!Y|YF0Fw<$L&2A(X95*uJi>8bzW-1x8#<-C+ z=A?uq(~|&`q9PUyX+zXd(5LkYovh2#GXNF7z@@n;SESDqAI#Iw-J@@1emQXdkMaMG zN*$E{e|A(?MCfv2_1B?ubRZx)(J^8F{X5-%FZ<)N{|x z%bKHLQ--_erkwBF-%}H$@|LWm9sfaZ)AtxCskW#Nbsc=P$PnHL5TpN;|%- zF+_c7$4_XEf;MV|X~$1$4pL9r@l%?kU{gkxcHH-l<{;RV+BUs9gIayJ=DV7sU{gl+ zDBzDiT@$3X=lFp7jA_h=YR`fBDGVH{=a|S$Ox-?A2DS14t^euUANSU5X=TfgeCL!O zRiyelr_X4NRd46?S&ebDbxxlfRkS)gr~lFzY@{jCfe%NYA5|DS=&HXCd7iQV3pF7s z|Dy6Sa3B4Z9SoFIqpCw4%v26R{~h-B$LeDl!3H+B7=Q5P@pFrdNy+b+wc`s5vey7N-qnt<2G5%E<+s|2Mak@Bbg>uIR66+%a`F3-668%t)GrkG@_LqPAJU!%*pY zG9=ZhkyK$t4%IB6kAHZCefBlDw!E?@j(kH@7*(YD8lrD#j8$(#^i7R%>S>5R z?litNs%W(h(J%-1w>1W<^Wgr@sKSio;NJILjUnp0w)j2GQE)C&TmD*A%~>_-+Wzm? z1gUMO^wcUn%s@#ssyb9VRmaDdn!7cBP_rJD^*Zvc#t%moslHa@M;c?*+iLt+V;pU* z#!p5St z7&ug`floKjkMPsY|F*jxe^Ik1DtqS0w_Cp)RiygbtzT)3Rd2iXYmITVwOhX#RkS+W zt>0=4R%g5QyHSN1QM>hfjUno5xBj3x%E;TTeSg#(q@GObpEO6orqtf-Q}w}3y$z?* z)*dwd$>jofHI4u0r0I)m1n%5Z1@7l`?!W0r0w?}~#`?cq;HG_r#`=Fw;PyUi=N4Q_ zXXTA=Uo>jcWh5 zQ|-T>YX4uM+W)ht_Wwsz`~S0U8@H9t`+c2s{-0u*?GtW({TY2LvvzFN`F~sW_<#HV zT(gHN+fun`W~ScaT?R_3QPrXPk2*ee*4(q%U$Y*S^*ZvccWG3S>TA8<*BGnb*849S z<7jKW|2nE@b++Dr(;Q4w^7QW-!<9RW+E#qXdp7?usxWjkR(~Dxa`?V~Y79|d^7I4E zQP9GUFnRhf%|Yr(p8i{N6l}`KlBXYiSQDi3I#$|SE4{W$8Ch*_F+YWYL$$Z~y#C1% zeqR6Ie$(bhHG8JAr;dCNuy0h6>gxgaYm8NI4?s6|s9#M3Z>W*(J#9SzJE~}P_5hs5 zV0C_e=SLN$w&g$MZS*>gA?o}5uGbu;j?eFc<{hu47j#2F)YDlWT4t*lx)EJ_^ z6A_o@C}>|tcp~D~9HgET5s&65*p%81sj91}8a!s7S91_-N^O5MRIlgL90i*)vMSE~ z4K+b3Z%IylYy->q=xrKO6;&HmH!>?J#InjSSEeZsga0;0|gB*P*nA+4i(hN;JFE{N(3-E5H8q);%yb^u&W}Sz4lFxp+anVrYAZ6Z{lOvDrn1vNUK_i* z9%EF8+WrykbY_3!5J4-uAV9ld8Ux3wPE{Rx7ffO%Rd&HadwpOR9K7t{?GFvHDwXa3 zcvbA`N;Ihswf)1t{;B=pVIl@;vpqC81m1Dbt%?tKs~PnviPdj`%5wnQS1)PbxN6O^ z_N9r93H-vq%NrRo7~X6W6QTet(?r_U`H1RjW*vo6|IR_dWCs6zd^EM!98S!Br6yh_ zzR2LrO3y?nQb5(E>Q^ntTU8wk^C?5hOB+J*@UA}iJzn)DX7)D?6ID^8LKg%5s%x0V zw3S0e9eC3WL>>6lZ%J&qdjdbrg!XgutCNU1T*7^eN;^*F>D9DEp!8DbqcwNaCpF|;pOW+G`<=Nnar zdY_f+p31ARe%bOR>#kb+ahuKTA6pZw61@B-lbEp-#;s~ob*T;&Oi+)Za;?VWLf-I9>)?RXwVk)h>5=&3l-h>6*f5ikpWHH?byMidLOwWyX~y1|{FDb>U@p?#oB879`T6h&d6M>V2~ zuBH7DZy!^tf!^KJxhz??bXjL&#j>l`ZdkQq?Xsnj+PKFK6L&I2Y-XTGwMliTxRz9a z`Uy4e>eY#j%i5Q84jFm!Fp*m*W`uzr)v#(gvf8Xv-h`N@j42=ELu9o(Jxth^VZuh$ z4Tf$8hE<2!VAFvOrmbDEZv8b?@9GG<;P^#YIki(~_D6?_JVlKOEev$24i#BU;q8Q7 zy?WJ^^db4+x6_niVojyL?`5Dx)uW28^-ymoquLs+S=_$ls`c$_5?9won>tLiX%wf4 zfi_h|68 zZWFnE%MILi`rjuQxaYqua3_v2a4)?^|7JdY|8tr)8@SKSH5|77f5yMw`}1=&{$FIG zdZ3qAvuz=BjN?*u-q1y(W2MTAn?(9Xl7JDIfEieT71)3s$iM-dzy;jE1H8Zo8h{@J zKoB&75D0?^Pyo|Iuz&+R&;dPhU_AvaF#r)rzz9sh3@pG3Y`_j=-~dkG0&d^|Uf=@_ zgxKuIYybp7BM5;ohyVpJy#xz5z!Q}fZPsCl9tgkyL?8hpFaa~L04uNoJCK0`IDree zfd_bj4>SNj2!J4H1R)Rx5ugCJkKl;PdLG4Ni4N$201Q9`5-!3%G#? zc!3YFy#xn%paXg!00R(#1dPB0%)kPyzy|C<1`gmP4y>mOOV~bw13b_HJrIBah(H2H zU;<`f0ajoGb|3=>Z~_-_0}t>5A7J|l4)8z+^gsXx;=p=}SRw%1TNqP9^eIR3&8;% z=ztywzyL%b0V6O0Gq3!3%G#?cmdl=aKwT2>Ken*f(;oCtjCd&%c&@O?j>GYWmflR}!ztujF&doRTZ_ zq$hCm&ZHFFclhtmo0hqw=HqN0N^yj}#tGKOB9y_)zAd*h8gV*n-^K@%-ylOOPOpYo?$b&u0)sImA@-_ zmvUF(&h(wpJBxQ@?ugw{+L_%M-^uRG-JZBzzCFJqxkK4exGjBK&-TQ2d3%0aa+|WP zaBKS3=&i+DGPlHTDczjCIes&HbMB_ZP4Z3o8sft20-}t}boPZjNteH|I7b zHp!dvS0%4ft}1LyZ|vES*dTAnuTQR5))$iLWHedq%yh;&OY5@h;_KLTxwVP4^4k2G z$(kjoXP+!=9_OOKG=B>mrSc9&c(34o;e`LDz;2D6KOGjC>RXWq`v z+Y#O2-@)&QZ4Yi&w#T=Hwz;<@wuZNQwkEekw)nQBHb*!6H}jjDHYGPkHu^TEHbgi0 zH}D%`{-9s+$6G=z?v}**@OsbsWOJn1*PL1xUFToNuZyh>u2t5?*M!!%*Th$cR-ans zU&XJAtqiVIR>oI^R=8IrmWP*nmM51*mid;YmPVKQm-0(vOM*+3CGo|f#qPxkU)bmI zCA|@^&zoB0T9jBAUg%kvTo75{TacO`o$sH|&yQUiyi~a~J})%SJufjgJl8WfIVUp5 zHzzeaI@>>+pB-<1TtC ze2i;nwZa5?m;}r8uC8P4ZJrEToSQ}HToUKvz-q=(jOm2hndMXy+GDKk+;_Oc`pjWo z7P0e4;5ZI+F^*+yCo3OvYuQx0T2Gp3XL8BZ*V*ODDE!ha!Y?JUV>xgX;}}K=KfoQd z$mU3R9o4h;T?Y;Z+bzNec$PFji|qMKHaLm{$1p;6cLv$rgOa@Ee0 ztYb{~cu;==!e)>J4h0XknV#D9HOqS~at)ms&$jS5$;loqiHt>z=^iZ=sF>BzGlwJl zybgA6&>#Ez(j>)rJ;6&!spdeLv5FA|JY_hi5w_1Rx{!W!M*{e?$9Gr)x`yt>}%U~HML${-5rMl^!Pu}H>Owo#U)w9 zuO`7Y94IqZGiDG^&uIG!gZN&7=a*&?*v#?^${bkDm_cB_{9Y5xkl$rl#J7;h8V-~h zs~Izh@0VYQH|2ME7J-{cR4WI{jAe|tes>KpXNjISsf+1#mt7rQ0o^~X^>~7n2 zptHSgS7XCQ-&!NOvB5>9zF|{f<@kPHAs8pjg@^q}o9(Xy%eG-ENJ3pB3}tZH7ns+mfwH#_Io zWDyml6OZCRnX!aXt3Ca1K6zXoO`~A-VsrE6jmwrc9yz>!_k^Rp0xzt!2s9FqS${`4 z7yD#G#QR5abp(=+iU8C;3!?- z#*6}2G9jB7*PFt)%nnlz)A|;LHZdx&1hcO?_g~vaGnH7HbYYt^3hQP9?q)o03I}MG z(qYOSnoQG1xx=)J!1BW#2ZLQ&PkP`yZq6w7J|^k}qv`ZLK`LbPrgExCNtrrzsyWsO z|8gol_rK90*y$aBlXVWE@ke$cPHOMKlNC*0&@f|F}bVlGXui_?|;}?#m8gBK^Jk zU57BM!y&}|4&e%)T{w4^)*nzEH2>crEd2Oq&9Bh-{~!AJe;(x`$9vvLCN){TWrsqf z@0=HXP1>kQrB5n1N>5b|6V=Z|ZxZRXvm11ZI-JyKZGWTeSpIjM}F-T(lQ|Mjlm!`)#^%=+`dV zXG*x*b0~%MeD-LP?Q?-9kpeq~N|8SLv-LfgV)|}4rMFk2s(sZ3^~O`QwyErJ3imy) zo?E{MLr+Hr*aYnmo<4dL;iRANoQq;w z^q*iaZAXdYIqh@Ii7u^T`rzGql=+$UXE)z&1Bl>n<`bE z;I>mh+kBi$JR{6Uug+H5D&9q}n+UFNbMrY~Sh>_$Dd5+fjccXf+v${)mX+QUKj8(+ z@)(?9-zb}@pyliF@NfO;sp$$_ZXNK;`HQz&YuH_R=Ah z!p-c*vjoI)Xl7Jo%8PFtPj$pO1}CMB?5+GA2+%K7b_6>TG5Y4kCp+4u6%b{{>7~S9}Bm#%4&qa|=LwoeACj68(mPJlWjCLw5p4Ai=3o`*uEo|(hPl{0S)kc4+7ah-}wFR4iCKVffRq^T4Qg73>;6)YZVU(O(cX3pN(3XOsO5KjFu)paE4+v=jz z>_r@XIU(Vvq*=5B`eBqXM5#nK{jtqU9HUYuwL+-8gT5on8j*E@g;(mOr1mDMr`YHK z_5&uHVj+(G%B4EJExK@yY7I5Tw9ELNv4f&+E~VJx6wo$JJcV(HO(nRDA2CUYq0Kk} z-P1+-;-V<8HcZ0_w37%AxSBYXG-6aUmrDD3HvPOf6H7hYfp0hWoSkdk%~3PP{dFAM z$;4_p(ZA!vOMfc;>6_QdYvPRv#fENfpH21l{KAbLssdVhfwu`R59tfbs& zC0M7mHZQ(V=~}-UIb`DlJZ8oh5cw7f#)z>WLKCLFOE4 zF%+%3c$RDzg~w=_vOydP@X{as=4RTXr3XU2Uf#t)zeH1p>5EprDt)p$C`+N!OJDnL zkfxfh&M@8EUF;B}Z>iNfiejfQs*V1Ix@KM+uHrmi>depw(xL5Ekw*!6XMglz-td!K z5#a)i&4%;II0t>|33D2!#QA6^Z7jqIUJ7z9oJC?Wx*{p;a$y%XYJ&CD;v0@-r*--C z0Hsz%&`W>xLzUw-u`2yaZNwgIU!hpDib;~_y2?vGlejxn&ernaefBW4Ln*f{cTI45 zTj?}pa}iu$`?a95`@n-YZ*%_6=A1)0AVD_n+?FRjYwhDs;LIg=71kzSblyyTN%hP# zAMbhJZ!728ZK_ke#qn(Pt5Yj?@~UG#C;a|RCH9?PE#@h8eACmf{blS^&pzcnN~v}( z*mM8i{?mWWy@FTf4m585@M2&^EPiL+H=JL(|1ZBdU--)lHLrWQGt!l>{Nvk?zxB`6 z#cpb7AL%}O(`T<;|K5$i5C6Q@tA2gqTcy|iZu-8`(`U9F|7Gm&KYZ`~uU+p7pPYQ^ zOC9gepM30^$q(jzV|n}dG zfqJ!fslOM0^WQ6f?%r9N@3OrqEPe0n>5miNTuK$Pg$u8YkK5h4nCEtI?t4m4trebX z{6@9py~9iTD|L@jBlMbK9IFqi`8+L7;uLKyP1MRtcJf3#1$rLie|=Hj?Bo4GHAC;i*2H2zQO^Z(iNf9}svxnbAZVzG*_eFVd< z<)JW7@6@u_P>AC>#2g`06D(VnO_kLmddz$ztzm1cMVcX9Gi-U;xmy@lo5G*Ku(d6t zz>Q2ufN_T@JWRvZ_Kd>zGXbXkoopa%8HE*iOEcO9k`;lPazmX=o;pEZR8 zRGsj!+*+YzwUmqrffjmk4G*h(-XJzttP8CfMV@A2UT38G)Njk_8>9BI-s)91Xpvz2 z#HhNfD1ztK5=U_ePhxu+wj3TxSY@g1Wma zqrfdp$WF#9OyObH-Q5|59bf{UW_;Wf9)Y?$Epy#%%b2d`SX$m?JZ%bpqPn{$qsY%O zF<)i;vMFq|zt*~&vHjg^5oJ_Ms>Bpr$!#WL_BKZ$gfC|t=3}aT7GZ{PtpazmQy*u% z$rSzs6?lI}fzL4^pJ#mA6gKJa7V>&{wk8Lzv;7Eyf*a1C25gl8S*Z7jT#5h@*Czo*?I&ycSb z;dSincQYP0g+D5)5H@uNgc@Z@Of1o#QMBHb2&Mgp|z zbUQo!!;BGA_!Cs8BN+uonUMcx{H`fH0@Z22-T}R3tdA$I$(XJmu(bS!@u#M+wK^4z z$`P))PZsR;4)*+i`V?9Na6ZigxJMS=p=bXq@*Khs>A8Q~wGQEr^zQ#{zpx8qCXl~? zqYhzyr9=1*`2g7cj$KI2qICprlZ9W?`~TOK(fR@O_re&vFmr}Oc>ET64T^jKe6iRe ztQQ=@PhxgqZCDomm!AJ0a?7jvGNDJkcx@Uv#zd@ACI^&B9_A2%=_V@C%rg4NCMvC6wQkj>jdZM5r_}S;Wsy`) zhb|(63nYO~M$B-<8hDmXr5Q@9%q>~z+Yng1YSSF-W_4FRe|;7?ILylqmKhbsPHIE6 z?nEC+Bm>5rjZDzGRn3i4Jk#b(FiE>1i!?ku@Ulk;GNZznNm{-k&9}`nZMI3&jafut z2H9fMoHB)lyEA00fZMEP%(t!S=$<_$SvO^oMMh1s%78MXlQC0aDOzEX4ttbolBZ^o zhi7SX*%LLH(aAU%dA@DBJl{5xyl@tIqv+U58sQ>;pp!9^JiRhf{+dj3Zq6ddMaR~Y zbqR7nCu1f#h8}&}ddiM|XH@=Mvd9}vhpwV^gdh(rX4ICOIY8h0Y-%o-tLAa*76;ZY zYYwdQZJUYR`ek-&7D;HhRkEisHVqho*A=e%$YuG#%$LVm&e?2 z-H}Bso_Z|fK$)?KF_TzD6YJa7D-@~I>&u;4Odl+mW|byVs10b zr=in5wBa~i;9Xe+PNYLuk@*S&K_??DbBDOS^u5o<1Xgov*Eg@QDt4_^vv+3^Jc-V{ zoC9S>Cu1hTCAwgP+{Q%8Dx&))*3SBPMbD;`s`^<(`U_@Ib-(hnRA+E@1He;&SK>FzAVx) zAN6t$lo=JqOwz|0(s7d?SiZHO@6VEmOGx~cw7M)30Twet?I>)^#u{4}sol^4?#O+& z?!G!WkwrY7P%UFmGGxXgMs(fgq-i)xsOvUItKZc1*gwabVR|CRHfyKU=qyfS5HJwhpf&*nnCu4xR-N>G0V^?nx7uc-Hf@Zt>Nc&V4 zX}Iw%=Rld!$%u@3xLFoqcn~hB6_hd0tlpd1?ERiuR&_p@MJmp`oSk20bTVd=O7A2v zsro&QWFm2TgLpEFINSnP($dMuB&aZIDn(uDv#Dq$sJ?90Owm0G!B#*os7uoEcQUV zuT&_RmaknkYlf!eEG=Q5ADh2?u2~Y69dZbXbq-<62Q)69>=3&DX%{YD?GPfrvJ2xr zXBXa_=n!W9-65RbE(z0q;Sj#C(jlyEbO`_cutV5MbN_!&^ZlP`RF2N&ij)Eg9`x!xEz6U%MnGg+iBCy6WQT7h&>Vboe7R{JTg zXHy~lQp!3Fll2?P>?Y3)k7v&G8MB&Z%$hrGx@Y!u Kr#DTX?U^}e&J0h}%-M9a zp&wYU;m5P2Y$b_ZOidP21}co1QZ~a#8QpLOpDyH1zr>%&lBCsi=t2&pH)V;%jOp4? zjITVb4TZJ_Dl4PRj8AG{r*ba_T^-Xt!XMch_8b}R?Vj0$51jl_^a%ci1kR&pB* zd5uQEwQymdvC+k+bg>vhnm41LZZ?AyE}nS&%8Plre)Sm0rI! zi858oi_fN!Wmqp^dMIP22MY9T$W%9}(6XUtO#gOu(0g>WM8D~MMD_f0X#^RW!uYks zG>Xk<;Q&2u8mQeSZ)H?T0$Zu&3|wO#Z(MvniyRCfX{~LdHkiz3;S6$U`Um9D541~* zyZAyH5ytWdFe{B?Z&=hZj%7?YK$cZ30NqV9h1$Dljr5)+Jpx$Cch(FSyA!fTjl1|_ z8p#!$NHTfW6&uG`$2gWTz2sUl2KGosE_+uLVKbL{GOb>GDUE2R7+tiM0Q@M+ruOdF zn(K=%r#Zb*Js_rr^@3!^YDTTO?q3h}*KpBJwQSlD*c70Pc~$eWr4XyD@|83KjY32( zcMR+0)-jG|#A~?lYhc;v(L7YCPcYkfth1}_;JkUhj=ih8+B$+=hdcU|;;UIiqu*I+ z>UUPKaC*^f3Zpi+t>02C>c!X6NHa9MfTUG%pv+jwh-Y)is%2BL>OGBJw)g^TS8eRC zSM~g7vxxK285eP&%vj8bCoj7PcpQTJZW9;qEnT`{*~X3Qmp8h`bztT0wvKjME+eoj z*x5B-n@PxWK5k*-kqIu7@$ABBOLC0lX%7l5x$F6QgmbZfd`}DusCYS^C(Y2N)!Xwi z%lVBT7}{Mz5pE77voo=nF;jNw^>K4{tr>dVBG5>{NM+~^%lWMtT0s%j)XhYOK!q_~ zb-|51msJds|WU{F_+>p`WCCXfD-m;|4NNZ*#cV(80vmIm z3*{Y4l8hvdP?j&eJFN3-GkRTYGMG8bc*jlPg6)XYuf+E(0*u2Aovx#ZF&ro}mM~&U zz(6)W)Ti=3^{J;enJdcs7NJHWKB3kwGcxr#%lWODYNm+s97xOW5S@(LbL@dD3T4Wu zD7_Wpw^JR$eT8Pm<3ZXJ!=3+%#I=gUG{zFqj{w`8I9F&dxK`~UaT`~R2Z+J#ep zlLXJ-?829SZWmU*>k$5nYye09k|Ugd+acWYoI`NUvJ3AXw+rh}+J%q5Lhtv#X%`B~ z9`JA{%_;Z;?W5=aje;zk^vJ?LPRYUzAJOywvku{x^(Xn$H2$x;L~D8R{C|x4Czk83 z31-EA-l7;oQJ+xpMs2$A!LZIh=<3Q{{DMUQ%OjzjZZPP|VeB!Lv5c{v5zCz5#%$Tt zTpA71#Pa}M_?=zBjxH<{(|6+e7cKG(`I^F9?Cj$iE$3!mwc_a6LvsSDWjFdeF7&3g z8p~ZclTpq@CSh_~IYN&J78r2uVca6Y_=%ypO%ySe11lKo8PjP_>eXDZV=vPiIm}?` z(0Ym&zGRVS$Tu_xN#mIeBPHg~!E5fz8Rbl55+)go~+Kb9opT$#(mWy&5*9?t)88GY}#3jQf$OQUo>UOa2J$G96t+zXOgzm)VR_yDR zq#Ieu+=>~kj8#SbZ;BVbF)RT__t#pd`gec7X*s`D_uDCA9=C((9^n$UFhe@sUtzii; zx{L#B+T3OQw&na*O(Wszr^{Eb;|P(C`|9prEuxL2jFj%q z|C>dCHE$S(u4jW$viVS$hDb!sipO+h`~aUYLaAOdA2;_K2^_*mK<~%VAaX+QSfF2| zx$b<&k~|~1ne%^$bFqKct5my)n9V}(xt_J0-^h*8fCVXH9lPn%nsF2^V@y}HXu#(8 z6fNrwG`fQAt_7~1VL_kf3xlIxU0H_D2}{z9q-M_g5E`iO4okq`8>oM`oZqV3ofNU2 ze0brq0ZSOu=@t!CuWn5ZR3nYDT$2`?SBkQz~Gyt z|FoRns@q)@;UNP!bPJX+X3{M^iZeG!eQRw~AMO2@MYxfe5z-!a@xLtsjNBQWrF|4J zl_tsIdIakk({+}zchEny$TQ??8FI0+k7qPeV*a$YGU+?$-_Iy#B9kyVtsKEDlp5Rq zZv&|3e_)Yd{KRO__EW@E?kb{84`QG{FkQVsd)C}jFZA|os2#HOU9cZo5^E%WgzAxc z;YY&~kgbJl>M;@gkLCQNO12r=hOxStnXGB00ScEfYT8zAvI#L7_qWvBg{Oa%EBI*M z|A+V3h5h*sL8`S2cmKd4OrmlBzf{|WOWv1-@5nS)zsfHB`@6ExDcObZ{e?a&?80AZ z-2aH(F3c{s3-_JO6{hCcg?}xz3&n5d2`|y}|M?%=h3_}mg^ru;f6P{ zHn2G{m z19AWdAOX2RK2QJ@0ZyP8C`=GN1y0yEGAQ(nNSjLkbawdo&U5 z(L@)(wGspXp3y`&MH3x>4CDcDfF>3JWk3Z0hh`$Ym5Fvh0&;ULyQ@i8cT(y+j89Z(brCd5Q4dCBki&2#;N2F@aJDcU>af zb&2rQMb{WX0ZIV)(GuZDON0w8F$aM6ED?^gMEJ}S;Vw&rrz{bkvP3w^5=#L1#}eTh zON3V}5e~6L_`(w53rmFiD-rImM0mau;q*#`zbg^0u0(jb5=#k`!g7Q$ftIc)0vub> zbwq#@E4q#d@LxsO5dp5N=sF_6Q59WB1h}UX;hBoA4+5N0(e*)qKPnNfsOSnHz^9Z5 zH&P-zNQrPBCBko%2$xYJTt3CIQVfkMCu6a%F|8BhUK0@VacA$N+x0$>B|fCG?$Tp%AP z1Qehcr~+yL{xm@Z9Doeu0R=!2pa3O68Q?raC{?HUcnNNxKqbg02*nH^QK%lUpCd?3Eod?c zMXiKUfL$dNo+8*zBMxw$CD=bAxSW0x-bAPc_!dGQP3?ETw6yShnSU5tbRpcp6vDuG&{9vBVSoCFyt z0GvQEP!3c9b$}b-TL?BF7sv;kKq*iG)B&RaH^8+MWFQ|X1gNN&ai=XF{XB0ZUyr=* zdp#A4#{4lp7CRk0t(=a3HuPEdXA`f5U-P_{d^Pf_@72^R(O3Mh@UO&P4!*3s9DgbF zlKZ8^i{TeNFP?d!{XmFMHng`RUimv}b(tmoO}Gm&R}&!nD?KJ9;+e>(P5 z@G0e~cr+AsM-!*Qr#z>UPez{fJ(+qU`h@=p{)yNp^z0Y=RPa;h9*92Rf8e7?B;txB zPJ~Z*P9*P--0!Pmz0-du ze`o9ydiRUn7`#!rF@8hK4g3wU>x0)T*T=65UFW_oac%fo&$Y>8kz=l7iKF48o}q?NgatE@gL!j#JYpsN_V^~)aC9RXK<&o zGad{D-N8g_xYg5|3`7FHKo2;He-1w< zHaj?5nH`@Mn&qCAm>HhwnVFmsncV_hxf#qf=x4;yLeY@RB)6sDqbI| zch@KC!gZdyWNoC@SDUJd*7$4qnpkzPTB(j#g{s_DiOO)Lr!rX)sqj^#%A@7}a=tuP z7A#ZJc>eP%yb^N;or*JF6e@BTB?`lZp2B27q`+5@%8%yz^ZEQ(UNBF|i|2-N-MI-l zEPLdn6p?&V$`N(=9lRrE584%bJSUXn&Pmw9HjgbSMns>O5~6}%;Ds0;7g=mC- z_SNg>y-wr*Inzwz|Ff5Kze?ia5y!bW^m0>+i6Ab>OpGx4*Fb0(V4}(DI=Xu~SFcy@4iNT=st3vSC7!yjrae}{9 zz~2>v=Ssj-Dfs&`@DCU%N`J&qQTh|SgG+zLh*A0rhK$l*;UHZ48^(>&-{BhE$i_e5 zAzb<=T!c&KUEl>bc#-#B#yM&@fj%T&1O*#N9dM$}4(2#Oy97F9P|5|#kt;DbAIvKN z^9#X(BCya27Ac^!7*tBY;!>~#!&<2n<65Z<16!%Q60E@ZR;t7RSE|AYSE`2Ra6KP2 zH5l(owHWY9br|tV^)7If8+2jhE4eZBl^O(aG)BPE7z}}>u^0nOOE5T=nlL(+JPJ6i7@S@L&cHBPnu&3;G^-q(T>;L) zcv+f@0kbr(nrLL>QVgG^`4~M*3*cg0T8KfkvvZXb-;988erFHpWGltyK`a-Y;BX7y?1UD$)#$s?&3Aniw z+=79*w6z@EhVi+y9d5^^9T=t?*|-e;$EC~RfLyww7Q7NJ$fW?^PHYvxpa|~7z+T#w z1MbH7UTSlIdoawG_R8QsjP|AddEiy~;ME1-0gU~ngGJyWCwN!^+l#?a3D^OHfYezA zc9nzO72pw=2c&D@n_M~yD}i)O0IwB^MmDaqA?o@Z@CG}0Bg_cWO%kZWnjnR9!JG5I zTk^qMVOfxl7lOCJz#!f31n*G5JBz`)O2E5eZ;aSq=#+bBRSxscJR{_*@D2d@1+>%p1~+<={&d;LGr4F1-R{hx96UhWHw6 z9@1w8@H9*xQp^Uvo&&yN2j6snZ%N?WFoj6(h>?xY6(Z{MFq23h zIKeL{;1`R*GbLcW6#Np5CeoM7!LPt}B7GHZ&ZV#MXNg}Iz;B4)H*Mg*nCIg5N6w|HBFXrvm<0G5Fsl;D@E)_xX={v+)DiY@{EG z;E!zJ|Kx!GYX?7afJq7bu?&8k3;rYz{AoV;vjXt{3c;TjfxmEqzf{0q6@$Mn0e@2p z{QC*f#>tV z3kBfCLZYLVE5aAv2?`1*7K64DFsBr>mw}FQP=XanlCjpFlnY~$lm}nwQa)@-Qb7(_ z2zTjH5&We~v?@PQA%|&nG`Ow zf$Mas7A7gF4$jl1`f_j-+^0(}7^oyS9H>hTuv1B+VW^VEz=ygt7WOJ>91K>{c(_rQ z8ezARCcu%pG!f=2X%bwiOOxSCU77-C>e5trQ!uBQ2f>(8EHcVjB908mQOPDkd9@UL(Tnf9GG~W&`fO$+>D1nP$C6m0lpby3} zX)&y2(h_)BmzEZS%V0H=mOH@}FrG;(i@{YT;ObIv4Qy!A+H!DR1=w5(uCD@H_*SA{ z05^!>MjN;(2iy$Po3sVCH)*Q`Zi5L<+MWyUfF;hz#%1}4x*T>n>54+|$|5iT`<&FO zfI*n)q@5+;u2OJ!8Q2DUowTO{+zYdvv=4SWX@50%70h?i)v(`52e=c&gD~SshhWE( z4vSzr%z08M2kd}VPwI4lT`=xR-7jBH$2gsAIb|C4S| zz#Cx(lx`{kRagV1FwB9{&E?=NunJ1I!Yn8quL5s_bx^v!2D}3%Lg`K(ybG2>>249c z2L?mw-W>2g*bSxoVK|gdNMJ+;AAkW-`cxkHAnb_J$pY{pm=mRki@-;m;G+uoX&4uc zY&=$isLzywkC%Z@l!H%JfTt?KC=8L(Q`O+put!SI)Pm2#EGa!FfX~A^DZO9=U(5kt zvV$+fU@5&Kfv>`DDZQ2peir6S>2y9AgB4SHy%2l@#!Tr=C-@d@n$p|F;5#sFO7E6} z@4><;yBk_9Zb>;OK*)&q8Bd0y56J*g)KI=?o4_~)X}`pAkAe#ZSw{OKUsFrrVL zCHsXEjh*tJN|E)#^JLn9}1Zh2Z9gq4@4urNRq4-?i2C*gZK0INAL69 zm%KN8ubV6t!F%|7qIdhqP7%J#eOLU>b9Y4U@Z6EOJ#@Qrd+avmty!ZFparf!Pdnsk+R6UFu5R1mW25H;Cz05^itoYNwOoj=f&p+=kjx- zb9{4>v%|C9WJ3tf;%7x?`pAM1p5dMmpB^OpL3G+#PspQ??ZDrZx+HRmhb#x7smj#Y z6hGMwB9lFn6O%$@HHc00PfSgSkj)^`7;01+W8?kfQ)DsljB6!pL3E67OmcLXYz6U# zU<2O}B}+ll6?VB@ak3NeqoVb``XpHi+;#EVU@c!8t?|_)tHaf9vJjlBjF5F8Q4y+8 zDq>_CNR>s(JY|W}P^nTHEAf}4iX+9I;)D`X6tW8VovETok*6qL7%b!qqht|i&sWGA z;Ll6tMshu53kb=I9FzQH35Ym6j)Xl#c7RxpKPP32kQE>yhD1e-kqsclM|cmPpiBI+ z)bT}c(ER^vn|OA?o7eyEKhX~}L+G6!ea6t>X1bZCj#{R={jX&ng)y&U#3q7#G%Nwx zCW4Tj^l5}i%lVlG3C2VaEM(Kf;guPgL%4)7-LxA_bz9e?TugP-rsDR@bTesEd&8>F zEL=ACtb$+YDuQ&^HeU%8Vt9nUp<*xo&mk%UkcuDc4ZMB^+4BSkE~8xo`hxk!Q%)GUQ@sZ)7x5V*b?Hik=vn zla}t~l%HpmGl@xc)eE$6qkAsGG;`mM_MKMx zOG^rj6pc{jP%r#ySON@>(^e&F)1i+-PkKA{Ys>ku3!91 zZ}g~;P1$WU=73YXwa^IbuiH;>U4OmHd;q;T+4JU~HeY;#%e}xwlTlrZToYNFIB^1* z?p;AP0a!n_=WJ*P`^U}G-)k7^?*GzgKt8AXE{IehRrDF z8!7DJK$)?GF;h7Yp$R=_5pE=Aq_lTFWf6d!VKZ`fD}~oH2UjvOT%yp989#xllqg^PBuci#QrdU|Q!Y51chX+}~rXMG6oH2i5; z0tVmF`?KZzR^8rC5$icnW-MV$r`r*Ir{OP_q!~#aG2Q-kSONy$DE-ZHeyeWppa>81 z`6@G(FlN&25E`YwTZ9{l87b{u{D&@JoRKa4(`b|)pzkFdC^Hr_qF)!}`j5Y`)(1leW^3=b6)_Z8%!*r(DP)_7olJ=0KUT zo)JsdbaHJJ+h?Q22Fg_|BDirGEmpH+?Z%d6OEw0UuV;$&a9(4&|HX@Gq#El`JwvCh z=Rk>33#XG>L75?`T#;S4i`D=vxzQm!_anQo;BmX~Lz@2|_@P6%Nb~=nsId#;=Vak& zdiQ@Zy$kUCd$O>C-UWE!uk=|-?+5&sL%7Oe7i4-D;K$v?!p$`Q-(6-Go*W|y3uyiS z|DbmO+GzbhTZvt`{kslfykHl;rr3q*c&_k1&Hdj_?*MQoa=33Uc=5qEY5ecgpZ~M* z|Cv8BO+hoLX{#1*-n6VoHQ1$>2U`V;zNV|(&(gjI4wM;3F=o&Vs=>fg&9#rm5?r*U z6Z-<~Yv4ecaTMdQ#Cjk{&#jO}>`P26D0AQ_#$kyy<@O@Y4rQA)w?_4Qo%Ysqpv0(! zGl)g?8(7JZqi5EZMykBQ0% zPX7kJ!s!%7UhQdw8hL%24sGB-nX#TRgHSbnv(hV-W}2|gTCRrFGql&ufihz~<8Y*! zYSVcsi_|ZZyao=G8AmaulS)ll`f@diy(p&ufv3x?5WFcd;m=v@uN1L`HKsoiuVhK>u`UraU<_ zN}0mWKa0^EPA5h093oE#gU5EV4v(H4C8MCZOoW%w98M>Q)}o?L3{!? zwU$&HxfsC`t{aw!A(e3bFhvZlghyGVSWEav6w$$fGGiHIx)Sbfp@&kwLn~dECB;S# zMxu0$+#8?2SV-^gPt6k&2kHI(1$H5i{x%=T6MlEKUAX5`yD)+NI;7%s z}Jlp>CBpv+jon67k3pi4NY5}s^HwULVvEa54` z5;3F_o;pksLo4A+EK;l`{4-X!EMyYioy;UI;OnA?*{w|K#@gapaV1w)tBmX^ceAIn&;jPnaEGO!DqF(5%& z55kO2Dg{dz)2S5GN|rN~?(E*Pr>%o&Ru3|3WRHUPlQ)mauAPUw5ADvb?M0SE8i^iJ zZF`3$WIs)jXrn^4YFo2hBA3vnUZB2ViP%Yn3BOBL%cWMJOofm!tnKT~c40T!0WMxa zZ6{{e^{f#VsC|;*2YS&S&1#fvZC8Qs!z7lo^W{1Jpuxu-6of|~E# zdwSE2J<+tnJ8CdncwaxV_loNCn#meV>WtK8*1%9Mp7U!hB8 zH6xMSG!g@JwI3o{HWgCEHbRQt)hI+ z=RldUo-y4#4@`laNE4(w+vpMdt^?Ww?_k&d!-pvEePXo+5Yn_;*!hiF5>ih|n8|@M zqmwbfddK}IwnFXXM7sHKS4Z2Pfbq%HZj!kvi%d63TgrhlV+CV?-Iv*Oazk7ARAB?0 z$^}}eX4CwFwnLr!kMw!$-^3pK)7+5W-KOXH=Qn3bOamoj83)RYm5fNtVQPyl8@&9% z?Ow~_&aPf@=1B;8YWnOqCud8RXVl()=zsBJ^i8^1b;z8UzM9geKJ*T= zO^La%)sh$^al^Y3(#;asW|3m()VT7;QZ|=!pv+joi1w~~fExj-1C_w~?mh)zDUeK= z-fl^bk-U-3^bU&@Yo^ChcDHb#%vi;!l{1@9W&8l2@WiApMmZn0WZPWp11@X5%%q0P zED1CcJhE!I+#=R74-cth+9ek`2lnsQRO|{YZNp808sc81r_EZsF>U{RAWPORrA(dRK$+3Wm@aF$ zK^-yK^3XNn3c=Yd* zFrDTBJolj_RFEIQyZ&1e%2zssdmomB2`gya|C}UTy4)_jI93*x)A;`cjsK_2Am4!> z%fh53TAZ5aPobAM&w zUd0EX@56@<95c^oJKvf`!;9#YS8<@sSjd=8!x*&FNQ88Gt+k4?I9A!@+2Mjg;=#Nbl8GfPUBQR=ScK$($NvZZjQ zl+s*AN&yP3-;k~+p7e>=WcBteu#2pLT>&l1bjb}^@)velQf%ZPa~t2u!Sj5&xr|5* zs-51y+-(uTY9zsE;FpsMZsb6jv79lTQqZ5FS;sw@ANV5H6sBLwX5}DiND6ARq~6HQ z2r6igMTAvBD@Zje2a?-hVkKib1)=}B%cP*4$7tf~0N0_WB5kjw1|f1tO4@75fsvyT zRMI|+2&x}+&8O^q6|!uDHoW8`iG6?T7b7r1hV)-@oT-*pszy z*J;Uxk*my#YA1_I2j}Yd_=~(8&_5CkW$0bIE{g=Ko;Hw%ZsS0iv5qmFo?yW5?60Rx z^;OrEUSm!ALdbZMA_1gl$JC&Z#e~>4PCLe+R$pymiCeeEVSLX{~qd5Uj&n*_bG#_BX zQAPL~%>nr9&+>(nv+Tlej^_$@kqzMUKgk!ilMUeE(fPs*ngej;$9Y1@G`kRV=Lzqe z$`z_UlIi__o}1=6{^Ywktz7wR(vGpIS8(;w&FowK*{#N+q8yk1(N<2b0&>W^w_E~@ z0t#G&GN2A{cnJzn2jsR8DuJAKLLpEFa4Nn6^+3@nLM`ApLnsA=vjitl3*>)9C08{{+imyNo z;5b2$02#;y@_>Ax04M|$pcp6tDuF5>|1_ZhC^UF=V*LpzDL+26!()07SqBz$J!k2jCDxmH-*Z1@eG=pa3WYN&)z_ zkm1Bab^$^Q0Zu5WjUW^P@FgLa1Mm_d!y|;uw-Vs%L57nDSpsr_d;pFdWG4Uz4stO7 z_YE?YAj3_8Tndx}@JrB>PBAE0b`FR;D&dXS2Ud9^p zbcGPG!aP-a0@jz8vAjH0e?ks`_2jAg6R>nVReu7OiSJ1#R*09eC_Ghp0+xQKT1mh% z?=seRm$9(Bj1}EwEafg^@pc)jwo|PnV1;(NO%SjeJJm{p2w>rLs+9yRuP$R`Rm?R2V(1gxA+6_S8;)2UVxuwJ^1h0=S{iIvi2ERil_g>)GUq{~3aAA{a`Y(M2|ekQ5t9cL07ZZTlmKNw1yBXl0D_BP1MGkV zagxfij>Hr~yPT!4AkkK2QWGKnYL=Q~*_ko^%Q=6k`MIfCS_M`9LAy1d4%D zpd6?KssW*$U<2%c1mptwKp{|ab}2c?C=}W z;H&(r@ClfDIYR5`r(TM_53dph-0^eO*S{8O=LkXF=>p9-CFpGrI#rZx4GPeh*ZJ&}4mN~`MgkHfs0-tW0Td0&K9*iYRXz1M#)e{YP|*jMg}-yOQ! zeRqOZ+4tO)yfbpA@6Oa6(L4Ni@OQ*+57Juu@!LYTxo=Ax=Z?p24bocs@moT-xNk|^ z9H!Owli^6%7fz{BT5q3MV>bnFQf`XViu>*x6E}o!@Z6BRK61V9`qXvN>-^WLx*tH_ zvDDG%Q9rG_AG;=ajdD%=NQhS6PjrX7J>AK!2(7)J>Wp^!JNeF7N3cWbh=)QUH(P%{ zb~t!gIUGL}q80cP2g3(F2a^XPv<83b>gd(}tNE*Av zb+1j(3jLln$<>k7K3b(ey2`(bUlm&!q;>k^D?%&WD-z4YpV0qbc)n+T^3n*c+n<^j zo#&s&&x_H@{mR_7U8ZjLitnP-y-B&~*3o#I*1< z&$Of`;_-P>O;K9KpKpp?61+sYBu?x2yQe0mgr|6>Bxxmo-{jP!=p_Fnp4RdYPE;nw zCxj-rX*K_Fqo*-BJ~G}%>-k5=`N#3&Vq=42m9gRuimIYU0%)THilW6|VABC25U+ zUuCKyTH&wYX_fzAxl$f43zfNPo&RvDr!-j-De=)t|IuQ9F<%^0g0$9u+!=DZor$6_ zt@fWRj1>9`Qw7lie*s?*%Ma3;|M9#~o;xp*8>UtNlX67%$tfvH>;Cgn%n@`bjySFS z@3tp$!a1ItB(44Lv!%qS=ofif{XZxuLYxorZnpma51SU=`yM_2CucjXbBpKyb>6?Q zFqu0hAfTD;E*!I1Sq!VoC$;1BNH~A3MFL9&!Fc8ypfqmdK$)?CG2MhNnih{K>zL4G zF`6QZY&5WvBFHAkm~wjlx-98vr4(Gwfik1Qm@XZdVm(t!2TVZ&qy^EY^x$j1G+m!1 zO*<(yVGfiTOBvIp2@mErXlc5pgI<*B_ox?o(f3fwOiw)myMi?5k42EN3eyoyb9GEg zyl{gh!A1r$SC=8p5xCJJ!dhQ;kv5KVpv+jwm`*2nLU&~!ounx)T`zj6nRSDx!RqHG zOX7{pjG%s0iwLWJc9Ujq=RldUnlYVzin(HSXCM7&PqzoC(7J}S{g(Q}o_Y_m4uvfl zFfufPI=a~+!m6V-($3u+C^ObGrqdB7RMTX7)77KtAahOXJ;tId{A?)ty2X+iBXc9D zuUjo5toqtRn!1MrWyW&Gbo$cg<(Tx<&&1wmpG7~Jt~I@N>U$46Zb`k7n-NsdZ59z$ z1??r(oZvv2v6?ZRf^gAY-KRpKPGnM&w%?*CL=IV5w_9>zyK#fw#cxS%T-h&PjR5kSi_jET=2N@Mr*mCN@gq@957({46-t( zEu(uZnKLpwf@O5?utW^4jPA3@u$Ix)R5~|vpv+jwn68Y_`{{dk57NB$^aX^yrbfop zO4DW47+8N`x86%cC%flMpNTQ|TQXo|XynS_{0WN)tBwwkcJAUpnX#5JosKa7ukYO* zTF6|HjU&?P3O^s5z9N>)7?~SEeLY|iVb#|m($otaC^ObErqdUuX57~2y4QL-8C&I^ zLk7I|v-O7byFNQio6+3AjsBD+lSZaLu^vwuGZHR5I2;i(iflrH)&uzU6@|i`v>xE+ ze@M^p=i7xxYUmmM8oQ97=l*~Eus}Gm$}UWyXaAR176^Z%XaAQxpD%oyp8Xg8EKhiu zp8fyN_wt47=-L1KCHcZudiMY6@8$`!>Dm8nN}lk0uPj`pN`mB~_y1Ln`^pb~d-8o6 z|GVc%E|Ff4-27k{uX~{D?AHf*CA0`Peav*ubBf1&W)txG?N_}A9x|8{W z>#09DY`{8%9V1bX9I?Os6JHZtFKh zf|@edGF??TsIR&ZGeng=X~~e0!I4whDT@TF%DPEe5e}3Y>lo9i4852ERhDTKt}Dzu zVG>jL2caq#GphDATSP4xGBP-FDtpQz!K$(&q^y%1C^Nbl)2R$M?|uV5qm~UqZKzdN z)eW+y4Wz!OEtxYiJ96rK#v;M0K9v-A83)RYMU2`E)c$W}W3ioSn1On@|Fa7%k}g8s zTG8HXf;ZVA&Oe(aL19YDE)J9#OBmB72uq7CG!le@u#5|}L}7;|VTjV651148T$aQg zr(|vCK$%ftOqV!3U+K|SzsjX0ja4SI#`;`e=bz7#pxY=ZK@KF}iA3_9NKBU?EKJ!) zTWJyn<@8IK7HQVj3t19(Cne*jH8cr zjG8plv9F!Gi8Djd=Sp_eQote4?kq@;&9P-d)QOs6VzDY~tyLir3>`weyB z0E@~HHEgxLY{`?6#}QQ9D;5z}wcSk$`z8m%Au4Pp3 z%!>n?82)S1sDn$2^|~C9NOo{WC!?hom04p>;NyXEf7|c9YDQ1 zU-9Sig+I~w zzx)pc!W%UH|HxAyTu<-+SJ4`Pjm{z({|np)$5y`kIhy}}$6P91V>`W(I}&VW-}2g< zxn&{8(!#NY?!rfT+PHFxDyjtBKtt0;uBfb?P~O^R9J{jcdUk9@|ES9TQJC55xJ&;D zX80D#AGLBtc|d7Pkj@Ne^gDcpeG9jEjed9jLtxy9r8fp$Zo*b5HF&cc8B}Qh;M=Ofx0Omi0luvod|Ng6wrcQg)x1C> z&;+yqtw1{<#r`zp=~R36glcEq0HMOGUi*_r`A&<1pn zzP1}YjGxd&J5<96en8nn+6Q=uN}F0A9b{AZ{uFG^;hQqf3iC|~oB3N|FHXqc04=z- z0YUluOaMX8@e3OE%$974LL;X3&Ou8b;2{ob3R%8-X=oMM-i1_DfX?02W}Zk76!}|% zgaXk%LIDAQc`0;`r@fFO&z=SO-Rb;S+i17&t6j9I=~UTml=(c+KS18~`Qp>Gn_3=* z_NLi*G?+upU_P*suC!4U{G#pwng*91SPCsl!_Yj`5<(L&Wt6~nV;ATFw1IP}+yZ`} z1Ly&iA%YEX0XonEbO618I!s`I2DAgcfHF$30uI0fGy&~E0I=>RxBwsE9GDMV2tL3M zbO1eox`<#0+(0AX2RZ?Hh+qTUfDdQ`dH^LxumTRi3;2O9Kpi2p06l8GMk1)j=$BL0csC$di_o(w&idm{Nn_zC%m)Z>xI^~ckX zMIQ@1mU%S(Xzp*&X_h^j-R0fjfhDWN%O09=bhzo6JW( zq;ARHtlu1or(zKr=^)<}-k!WMcSEu;x({Dd#qjFD>ddM*AB_-PnO%`s5n7R3o?ISYE-&9R6dwu>Wd{?3 zp~2j;7~)7fu)(t;+F+4%U+teG<0e1lH?`fOXN#Z7e_AEFHT<+ zy(n7@FICpYGGudzA$}W z^t|+f%>4NL;QZ{liE~5e=H?~mh3Coh^tpRykDe1dJ9u_>R$^9YR_?6iS>dzfvr=b9 z&eYFLhoYfCC^HZr2o7Y=NSqNmBX@f8^ziBO>8Y8KnflDV6BuQXIw5jG;`q?wmg+?;BPH0e!gU(^@yWg6p+!N#nf z&_jC8oAidgNiD3&n(o=_8g<4TiGICrF(kuU- zFF*C;59s@Uu<-tm@BeKB`T73}zF=<%og+psf$?4c9{QPYN+9Fx;xy|W!q=2H#NMHN zr)SM>wTfP%Nq4M$?4F`G1u+b9>d{kF(0f#fLe%>{Qu=iXWSs4sW_rVc^nOuq`Z_hP z*c4vq!km_OpDB!#DEM_#Fz*sB1aeV@e&EvnxV$4?>GViQQo+L^C8X9!ef^ zF*zrSw}m*wOuL`5>s<+CoZXyenFc3{C#qx`%6qMh!#OoF52w^E1K$x+ZYWX541D*X zqL^F;eo}}-%)kU?-JKH1I6FAaG7z5*$Zfm)LrN7Fn937MJ{^^0NSBe$I!gC}5QQk+ zP7>`&31plBPBZD?p>SJu>1vj`ynHxKkPwGHmW&??X*AMYM;SjWL?O!fC<&OBK*rh2 zX(nT<)Eaxfx{S4+G4d+bc+wa0qeQFvN;bD3M2PksQy z-*hXk1vI}u`2alT)RhxxEWmeYEWo$sdX=>_4&aVC9_0{P7jXU^Zsk`r4#2nCt&Gw* zfL}c4Qf{7QReESFz@g7-N}ARHSVn#T!wCLaK4k5{?!^N*eUA^iWb#smG~{l9tO zuY9{OJG{y0osR^a4c$L>R#M!BH{q`cQE;mWM$bcvY<^J!8K;-i%qbB|I9$a&gyD%O zJRs5dB^;%4UN$Sh*lelfWj8%PD1Ry~`BAxU1wD=rmb~W%%ccO{|J51^d5b3mWD*$Q zG)oAo^nGIq*|ci&)^%G3iwjLuPg%uj6H99GXZef-`9(U$PwdxfB=&8dSdd9z6Q@~X zF;l_SV~MR&-wHX0kdh=}ms?z?9Q=BXM7_fk1u_Xdl+!FxXjL9BOH@VnRL?~utK!s& zC;K3B^BXl1{wYfA^%BT9+c?b<4&SgvV+k*$q{26>kfme6B?+v^)AC75_J6a6xu53d zf=mLtIL*w(3l`0jTT;ZvY^s?*W1gLKHGe3oW%{>jnEpPQdy@n*&MBN`rgumku`9<+ zuP8G$G%psEvSd^y0R^($m-gE=lJOay43J6S;hbj4=#hE~!-)*{@d+oTYF#NyPSr+& z=T&)<_S8ty=O`H?6393Y~z57Z|A&+JKUfa=RyE^LK05{1t99$RzMkPBWWP z*6u8`xuW`*C!*ri@>Ep>PbQh)tC7sF@??Tc0$VxFl8M3Vk+Ni>sFHm5KPt~d74}yMJbr>IPOnU1#VM1?vLDn)^0z3NpO-+!+0ALzUf>hQ z-I7t03WgaA*N@ly70#i=8UEt9!B*UvYCo;h06$!n|C!R3@xTv-lo~0o*~9?ssfkEs>P9+wx}^ab;c4IbrO>JPYJ zy{7!0`U32)d6ec;HRS?_OWAOpM|ppaQ~A;19!0srtsHxzTe)(pOL_err*hyA4#o1I zrt~j%D`#aq%C-@g;-@tLF^>C)ZNGl_v-JM|`;zy6I;GvvmMF_XxPmdL$$~tFSjH;emsG-x! zi&E8!TB|rsI(z?3(8bWHj@kROgNkBu*}GSWL(JaqQkH&E0vTr?r&;!*>3w)Cd&^sh zDjlpxz!(- z`f%y+*tf?ry0Vr`AhT;+R6WD1R?h?)Kq%INP( zAmg0IX_o0|OkW+#^zzDz$AMy%tKOK7cZJZHR#fbX+_%PiIQSny2}7CsW$6BWLKLFd z|H{P%nFRK8nu$GCni_j=Ozg_aG7-URT_uQKwQ_x2;d6p2hDsk>_!)i-i21>LwetTalNk0qIm#LdCjZ*fWG~2KGmw6{p&_0OY;D3$2@>j z8~Hqdzx%RR*+Jj`cUZj2;q?9g@CL8)MH>IV=S)pmN8kP#ef!VFbmiUwt8ygX|92@; z-}cXJ`y9Rh|L3V>8U5k=zkew2|4-i&j5c&;FD zjoNc?BL7KHz)+-)BLA-tg(&h~685(eNb4>U59Kry8J#U3j)`1ZdQCf9s-9YqSmNDx3DBf+%Wv*VOaK0dQ)ynko<^G4Dg`rIy<(4}00v~4RT=>^`5cma2 z{4)t;oYOeXj!_1om^9$&ELe>fc|g2{@T2u%d*5>@`Yy@w&-LuL`;tI@MA71|bTgz#Ap~ zzew)CNFd`pmeWjnbklry>{eY_(kIYOQ{$q7@DqPRn}qgbm7&II-`1uQrn_KY04Qi$KUUKN}R?3bW=aTZ;$dRcTpcebce2ZXdHm@Rj=|i`Tsxokyq)b z^#J;T52f6#Z@V&hWzBq>?7gtkU+-i7mdr2S>KRA#u?x=GY$?_G+?w~Mxl}w zGpF+L3u&l0tzbS4TQ26XVY~25g)YPugBv%j!l)hm7{ZN7{fiOjCyFhd#G+IKZw(Fp zK&gL20vTsFrAW*wDl5~2{5`x9yQB?)Al0ZudJ zP}fE(l-s&`^{P#SReQ)PiyEC)XlKhGu`AEachOfA#A3@@<=MGeNUo9m`YC##<)EUN z+{24sh(pY^|E2u;rUWw1LpjZI4PDr~Dsrt@j%(&z*{L;iuXuL#9IV|--6|yCkfV;d z*mh7+OfDDOg*e1q{4?d>+Y-n)`#8;V5v>+Y%~5`zE3`z_`_d|_RAnDpwLr4k2AeI_sA``#XgwMCtxQqP-`9jPo!~GwIOdOH*?Q(iO{TZTZU2EmVQR^G>OR z#q(;**d?UVNOK)!>=vRBW&9fn_&Et=oKrc?WQ2QPqC&=e>tB5C8UOAno^2{+@dqpJ z0OnnZJwkeo^nYwg`0Wj!uYaQyTU}; z557ff0Fn>D8n>oc>D|9?zDM~Sz5D-i2hI6E&#Ls&`+wlCn)2Zst8yvz0j&MAN3l~M zK=5j}@-2G*SKoCh|2WI5EdMT3{z2dWe;R01woxCz${}5m$PeI*Cp-R}ruqMmnn@ZM zf4gT(!~F~SUK5S1;8Q-|;Cb5fm}fivzk_BT-9eN0Cg{i<&ttU5Xln}n7vNzE9i2l* z!!#}Zixd{1DV=d99g}6HQI;hK{phjg!A*NEla8T?ZWz13Ll+!B&JVUy_>>pvl0dmF zMttO~aUxk$YJ)5-l};b$Cp~n{409VB5L{|vBON$xoZnOTTqXs~f6q?A$9rBLOR)o| z7j&bkiHAvDg{Ci_LrRkNW2aehTJb6iCCZ7snKE{UjSe-AmtO^qbULpjqYFPW-i3mo zcB*v;_XFdo);xKu%r$mS{>MslSebkR`Q_szk4?-X^OEg5=pPVr&oQyYRk6hQp>dMw zKX@z6bJKJ1KU$irmV-}tt=zSeg<{n+PmgONhD@MEpsCp{+o}0|j51_9&7wZtLvy(E zX18&amOt1|`Q`AONGD98pa8Wf`B~82<$;JO%p33g4Db?7^R5-HrK|GSc!uXnJ$6F7 zZI;_u6~jXNU1Q5((64s#m|hsWs+W#+Jws;fAOnoq{+)Ey(S8ci(DH1j{}tYx=OdC4 zkjS4t7EuEo^cxWcc9o^Aj2f>>nwlNuMzm0V-ysY7$6<_3b7 zG~xzQ5LUm*3*n#;AAW&uC;Vz{(IT32-ZQNrvP|<^_`IV8c`u=BcoF?J&M(|9ahjs= z{P59PQ@TcG<8s`(c3_bXAzQqAXG>E$0g2E&OsD1N-EX4nniI5(8*n@QiyH*LA?MSy zXBP6Bc^niBsdo_b)9u@0=SXe`#rOh0Q{6X5a_^wbhKUI}i_%Kh6l3b36OQo3&X(L< zRen+T$k~#=osKy?3Z3krVsryt9H7({5~uAxTk7kfGc;%j11UNqunB=vD6o|--d;T3 zO2-dtrsMgay@3}5n%dvE&Ozb5ehP1)>!#6fDy3JuDD=oq3Z;VjG+BczDOjW9!p41P zOHM{t!XiGIx)JQBklyCKbR}}?Pzp@sbA(PFt0q`u$GD)4E;!NeJx6jv-zv%Xk;r{M zIzg*U1O@eaC6Fiz;Bus#<-gRpbxf4=B~5!_25 zhcE;ea?uFrqGR1Xi|B{LJY`62NuIS(aBrKJs>yT@nh*!Yibeo>m7LZvJX@O9M5i@Z zjonGXM|u$~#6D$cwseS#0;sv5+@nQ{O0%d7SKLJzhl)TY)v(!4KQ~q1dk#uFN*S%- zU<9?((ZjkZIU1T(db%rDsfm(vh(yo>l#Cn7f3^dG0bEUr)TQzm|SA@Ji<8=u3f@k}v4br=N>I8+;ZkLj<1AJcU&tu>M2p zvB+b|N5YT99}Yf@)g97_Xd-oAsE9W%&vYsoNsAWp7E`l8#5?@mMex z*dDwwetqJ)`1_V1py@9B7tKQJWa(wFe;)$o)Z}&zMWqNY8_o`rD1Cd#=d8iGW44YG(;E^rh3Gx7Oh66AZbC z%!AEY8a8!o&ThnJ6E^2HW79fBn-|!KjA8R)CwQqFT&jV~yhOwNWsNu#@ex@wHdnS_ zvlW|Hv|+OYn^$#WQy!ts^$L+SU~||CZnA@09N^V1@LCVJ%?sYp2ySlzW6eb7$L1}q z*lfqVVu||ZpVKdnQJ}ZwBpI5;b zZQ!d6eBBAY=>}68__hwd>jU3w20!iHP5f3PxTgvHP7C{DoIIQ#D#z&~2S|FwgEae#kwf&b?L z4|s{TE~ybaN)y=70$N)^dpqdpATrrYn{I{38nEfLVAF<8pBhJpP~aJm~jUIS0m!IOO8DNRJyg3XzJ zY_?%@pdFj?0BxS75Lp8@&#_?BhRwNlY&x(x--%5(HWzxZ>BZ*aM)3S5@WK}G;#Tld zc@c4`3NEvNLpE?ZBO2zfbmGuzH+ZE6UZsQUeBg#=aM%xSY6G{(!^Epq@LCJF%?94U z!0k>j<_2%pz*}|jb{}|WGq}SK-qQx&CyfwC6!3ut@F6R>(+)oB03UaOPkO+oyx^`z z@R=r}k&NeBaOj0r@TGR}6?v5SnhL&Q0Y`1%TMT^134YQIeo6!1*TD~b;Afk`-G1=% zZQvJuyNN$;27e;&A^ubae`W!*Ht^>R{7)zNOE>r{4g8G`{>}&fPcxYFgMX0s5&xtT zjb!}UfaDzu_;L$pGtPcz}gU8AJ#1m9vAsyW_G#olh z2ha9_v*iKeTopXm0xqzD3mF)8f=k@s1sZsf4qoB|FKY%bmlhER6)@5OuCRiu?BEp+ zaE%LG>jBq$!Htbzvbl;58QTIvaRB18;PKH@S&MGU6Hz-J*lH`M^7*5#n76 zcy|MMuNA!C4kjGngD&u45BP`|e5?_Cq6z$jyo>m>3MMu1bsc=u2d0|Ax8*&=cUAB` z3;1ap_!$O%=mbCK2Gbh&1s(j75B#VZ{HmX5B;)JyUOMzm75ugZ%-F#1GVuFO@P}^j z#~Sz(9sH>e{8=-Y^@BfG_7VTH0sN&E{FNR2jT_vjfxp+mKl;G`Z3h412kAT2AT{PH zc)&)q^(c1whdFS>;>4yKn|2L!=%C9-ETp2x(~Lu2KiDXHiA^flVgXxiU^@dlonW^c z?A5?N9X!Mb9@Y#_^@B$$y~Jq^;4xOP-wsZ9fXBPQ6FuNbUhtGg@U$lI^cHYH9w45n zg0n2(IW}+(1Lrxx`EH_-jPo=cTBL)Eec<`c;DvthVr3EW(gtv;6D>KZnc8f*um=@;Po!>Mh|$C4&LkoZ*2x|_k(vz!^9m5 zcuxa(pOt7NW5kX_4>-VwT;NU*_-GUOR13JP6?{hCMSM;LU$B5L*}zvA_?i=Z!wrsV z;9ENQjt~4~Gx#Y#_`WD-Qk04*rV+{8tzFZyK0w1pmWFWcEF@`9~-CXAk%{jmUIt?)QQJXd&8ql{V~H zIzXEw4N>zf6Pb!lR|7V!*rauFX_H~I(Sc1DHk;kp)Ues=#bygOd)mOhPVmrfV!{62 z!+U6lN&R&ENSVkKpaJ{GSg>gYY=9dFsbMCb?8SjbY@XH(p5X^WtvK9{%~>7T%s=V( z&XRgV`#!ttv!T!CK1_TV{4n!D{DZ&;>CZ$z6ZlN#{pkCF_cNc4emd~!MW4#Omv}Gu zUiOpmPX<4kc{l!U;N8qS(RTvxq~DIdt-qamEBsbA6;B0HnbGK|KAL(n@}~S|@{Q0N z+1KN*2VP(FTJF`vtHD<@uS8$bUrD_jemVD2;-%nAnHQrk>My2V2)~efKJk3;`OI_C z=k(`N&xW7PJ(HkS`7+69QctFK?R`4_bb!|5i##PimHb4A-oxTg2A)hm5uvsCl8=WT z&psBXmH5(+Mjn+PP0~7i*`4v7ft_hug-?Ds`B3Pg;Rp2xQxAk`{k=pYn8=JoY4yF- z{o(s__a*KN-j}&Idar(O>YngDIa-A;cz0$8d0g*E-4(tocW2_x;GLN}q&t$d8ejId z#BIUbvbRQW)o)GR622vObK>UU%^7;T)8naFIF`F9aZ~W7%=YMZeS7N0Fs;y+xFL8$ z=KARMyS9aBg}(T8f$P%OM(Euyc}?h=?A7tB1N06U*(z^MZV7G4ZjNsbY))^AY?3!6 zqoHVaI6fR0PH&8ClsEQo$gGd9*Vm`kh1ccQCe{YmX0D1}rPG^Ycunrg#FfD-Ggm~f z(630X4zJFwO3?a#nU&F%`pVRbFs<*GSiU9y|iw_0{)5{{Xx?l40(B;{s zaa!9ieOcr(`LZOf?3cYHeo5exG_C6=U!1rocv0rU=!N=)0~ch^kDni)RsAAM!9{FS0;hkenZ)HT~k}2F^{-i_nUG$+>&xMCa&p zQnSOebLS+^37(TVJ9@T$c4}6bR`*Ms6+A0*W|Y?UONGLr+(3d>_RE|RJwrbuMeF+I zW+r9^XAYevpO!o|bZYjL_$h%?(kDkwmQPNd6h28lDLErNBX?r*#L$Vk6A~wcPRJgg zI6ioM_PF?Qf#cHCBh%&S$zUir+^_eijtw81J0@{V@R-ce(WCXFQ`5rJKsnMzW)a2oz!?TCQ4+|WYJ~VQud}#k6nJLjJI<4v#?#l%dfgr8v z7wy%1Q$69HTz8^7*q!N$cIjQI&Twb0BheA;$h1e>_4ZU-xJ_FWRU#rt~na?U(Qdy;&`;1+|PPP93Bfchntlr(OG;31`rm zaYP*fN18>M&eD9nzmzRvlWj?B$eOjpEdfiqA<`f>q|~q~t4SrKWNG!kfSjS%`uoE_ z{`W7C|NlpY@BgL#|D}`4i*6k?d?f>d--Y3a@v&Vy$mD|OI<<}bPwb;LhARD^EJ@#% zK*o6#rD05W^6setI7` z8ShM#@5B2SCXH{|p+(R?+zsAk?4uPeq> zJ%4NaSso^cV~AD9JU;xOqL^GBPZi=2^Y{Se?uQb{IHz%%IR1q>ds_6QU4BRuxHlL;@M-p`2zS!`C}1id;Se{oXXBLy1Z8Tk{p^&EXb0(Q4dIA~T6xndas==uEe2T}Fc zu-!*i-zR~LvyIctcB~|`DQ|o6)><_crNPzGQw&G3nl|wS1#2Xzg_3fW1TxNMPO}8L zC3kFIK0(G%wkla-1Qiof9Q9>{@eyvN%1^IhsGm&SAc2gN7G$MuGeb2=!x}!w>7sO1 zOf3dhGqxC7VeWA?%xxv(R!Sh_Y~(aE*C9D#p@Obx{;F7thN`5fmne#W3j2<)VP7X% zcC!RBP9LY4eNM?4Tb8#kUva7!m=CBXV`-ijMmW;o#&K%l2{nxGA+w*9K*rg`X=Xgu zM4=lP;w!8TUd8%C2$^rJ*g)r-w-M*C^J zY4(y>&q^TUY~eJM%p-ZQP)>osX!1>VdaeH1_{a8vDQYJGx?{IRKv{ z-~UHw-M`~8{(nG~PTBh2iZ9ap|J$e2b0PiV{lA^2_`n};{!6l~IDtZGslzQm%(6+` z77m;wsB5VGu``fTQ0OW+S%`wCj$mY9fU@ox31pn@oMsu=C^g37Wf_Qfx6RcWmO>`x z!zWt)g*U+o)PYlk^cm@`qlBjlQHT=uk$5jiAmi-jG?Ng|iMN+YSiBvWHz37x%%m)y zQMi?h1#{fC@xW<9B8^1XQOB7=6rzq(NWs@7ka6~Mn(2t;m+9@dq%A2bFkY)tdRDoX z#X4R*$3)ACKPeqJT}ZW|LLG%YLx@5Y_7IZvH3?*#)Nw%DX2N1I0=Id}#6!T&# zo>?w%@xE95t%AUlulNH(q74!1sB1`wLe%weQZX%ojML9)rYoKuX-IlWfu;9*b15mX zpk8q)X}Y#pNGoncWupy+TT`Lmw3kO;{UznVnL=`nt7qUCKlVP@pH6z9&gw1cvz92CHLit|F}eI*AjBc&?=h6K5ea0Rt(=3>u(VNHW1MXK8^fZO)X%bLbJ1|nw&0-ubGtf9#VcEhOmi3cOmq;La!VsG{2dNWlV-?HLNij=8NAkMr z#+8JW*;jJBVB*kNr@*2bCLTv-T`Yl&vxO52fL=*m=fYnModRUySy!%Fv6iO0+OoCf zO`7Nbbcgce*O_wUeuwhq`Br5Gt@$_a30?UGjr+fa#{F-<#H+N^8UXLnxc_%%c$G!7 zt;+A{{r|w9JjxUF{{O=HnsV0hR%O8oP5CvA{kJUkD9_OQ|K}x-GKly8eHQ7XCx5>1 zOXUB5eJKC_&kY+|CLR6ErF;|a_h-lQ<{svy9qxO17HE*yU)1mz8zce-)9a0KK#rDz>lAK0QmAVxbia{fFD2OZv0Kyf-gUVEB~0C zejI^cKjUuw?bw2EKjW_b(gdc!wFbBfFT8}6Tq;7 zF*_C7VHje-8UPDm1u)=%*#QhXU=9ES510$U-~;9XFaUvh0SrQ5jQ|EBuqFV55m*c0 z2U>wPpdFBR6BIxN8UPDm1#E;dJMB2a00-a%T!0(!02<&0bf6LN0Zl+N&;s}YjDw(6 z2M8Do!4v@FAy@-|F%irPU|a;V0~i~@900~gFc*L^63jywvlHVbm>1B2M!*L&0nI=Q z;0Ia(jGW0oPY~( z10FyFFeZcP0LEo7AJ7Ce11*3bz!(kIMi{db<26_ZfH50P0WfZZH2@g9!K?rVZZJE5 z!5hp0U;qbm0T{%=JOBoAFfV|?9IO$*fDXpTb2MWMgE|-=)6t484D4WhTt^4CFt~&9 zu^lRHjoFET9*mFkuwn~?Js2PB!LWq^AB>OpaA6CBJ{TYKpT*Z~GO04LxA+<*tr054(8 zP8~-Y0Uyu=Gy^SwA7}+I@`SYm(g;BY6hH+U01IFRY=9kLfCF#>F2D_V01fa0I?xFC zfF_`sFlJ{9j`#r#S7B`chOAKAPmo6m3ZMcFfCaDuHoy)rzyUY`7vKgwfChL09cTo6 zKoigmv;cmf6~HhTYGO<5?7$IuH$eeZpaHM|R=@_>0R}h#C*T6yfCtb3FQ5aB07lfX zCIF*qSPLNUAt-vfAJzh3ln*t91dQ~drjUTqKGYNv zFyd#-PCJfZ^ba+O1dITpCXs+qK-44>FcOHGL;^+wQIkl(h#+bb2^bYbO(Fp!gO~!S zKm%X_tbh%$0}OBgPQV4Y0S}-7UO*>|+1ZFAKA;J}03&K;2^eI=8UPG5Vpafyji_}c zV89Wzt^^D^VlDs!kEnGeVDJ&Ot^^D~qSlpwK}giP5-<>nT33R!h#&(Pki=A=0k8m8 z!kC>l9I*ooZ~#ug1-JnZpaEV$2O0q%U_5Z+xqIk6?|bP_Mn4(g{`J9kv+pF{3B8kh zJNb6_?butvx3Z~3DwN8NCP%}gGWW38-%P&|eIxKjhJ5UUuV-INycQxq`{b+PSLIhz zuSCexKK*j^<-p6Cm!y|cFGk4IKK(-Ug}@7$=i}sSpM5UzT@|k(eG!-xR$mKpy!L`Qt}! z)Nf4R5WOKl9{KU>gV$%bCCDp3cU|(j@OAQaDe}wLuT5VQy(Vx?hCK6wS7)~-wuZLm zwj{TNx5PFFH)l5`Hib6jqRD7DDo0bpkzt*@^D$~Wvmw4AxFNefu|Bjuw=PLO`trKe z+Q?dcZJNCF16O6%NNZA8My}MaOp}*>;0ivrdv%ul^h2w1E0Zh3D`oQ3kF3yFq?bpR z^YPx1U?e+~AbHHLV?(0j^i=&GJi!AE|X9i|wPK%!wJS}@_f;{?jrzB4apCX@lB+^0WrTKNQIICVRuZv7TU0mi+uf-MOx0SGY?iPya}#-kI)*b_B@RKi(c} z&$cDnLT$O$WNWxpZcX_kew};#2U;@Jubyg(H0e!gU(^>MkN z>`iGAP1n+%DEIo0yMykmE8z;ca?YeP?2I{rjx0;C5X;$<_OM;H!}DLarL9qGz?vc7 z|DYw?kZ1@s*3?~QtH>+M7?vX z2Ul<0v_7(BaPt=0y+YKx>N#UwR8_98Fnvi4(@!F!S4kk_?BX0G?N?A&rSKPn{+CFD zOIAcS)UdqTDFwr;1y$I6ehs@%CX26ruWjCU%Pm}}7&UnSe7_6_sO-#4xI+EQ=q1D6QtG151Fwp=UGT)*_6m@P6L zk)>-(^tx2|eNnHOq|}WP$T$z-G^s`7TMx?I(2e&Nh<)!K~qrb4XCgv1z$ ztCv_yh2Iy&I-O*SOCaMsjMGdk%xb;G5KC-8#*@qB+}eT-Zmy8*av@1Z66+<|GU4|{ z$wDO7pae3`M$SRrtPC0_8~?`Oxl12K=58oB#0$6hvEwAgy5-ZhE=O$}JILF|!tv6U zZ%{DNFnN3l)=A5&RxyPdDn(ki95xr4)}e!nU~3@)lBV=8mXBa-Nd)^NLIlS7Mx%Eo z{YFFr8K;laYzPY6k7x5CDAiRijz=h!xp>q}=jDQxhShb`dBs6RFbSPk3K57ppT%_s znFRVc&A!$bbcW|set3sanu`IYIv0AXs?(y+R2ICphb4S9zfdy937IqWSniBX0l^A4!s%V)!R5WhDj*oVsNGK#Y@eUUn|&cq@!-iuREv+CZfC{vB|&t zx~%Tjd593ZnNja67i(HDd zN0sKKpFQ~_`u@M7^!tBonG{Gb$y?cfDfMdx?DUW71=;~+fZzc-0NW6u1?UFUVS*d* z15ymTKnLF%r7aJj0bW1{8i6LD1@HrHKs(R@sCx+wfCaDuHoy)rzyUY`7vKgwfChL0 z9cTo6Koigmv;cmf6=(z6fexS(=mNTd9-tQp0DXY8k01jIpaKnm1+W4(zz#S77vKhT zpb2OO{6HJf4s-%NKmc$`mr=3+9q<9oKr7Gz^a4`=wVz-GoPY<=0Uyu|v;rMK7tjs# z0KI@bKu`b`umCo|4luw8xPd0173c(d0c8=v3OE1{&bH~<&m0la_?Gy*=L31|UY0ckfu0W5$WZ~!jA19$-+ z&;qmq${qsNp->wD3xEYAR2zU5C{zYu?FrQhxBxfc0W`o1Gy+(sgQ_IK3fKWG?V-8= ztl2?Tjes>osBRIkP6t&D0@lw^ZGZ!C0a$WF^#WK-Lv03RX(`14SO61C4+WXabr6KcEZ{8UQO`2ONMK@B%)d z1@Hs#fl}cEMTMF`4LPL)XaFpL9dH0H0Ip6{vI$LqAAswU3Wp^sbp&`Qsc=qG;g_Vs zB}s)h61C89MN;8~MCFbEw<8tKMk@S^sN4}$zyiRHNQLu|3cn#0E<;rA2yhgl(nf%z z5EVIsAAqBf3LhaA?m;R%f>byIsc;5T;S8k04@iXzkP7b~6^=jDx)b2;Ll(l;k=^4Z$*X6iV8;+749i2oKjS{qEPWAz}-ZJ zlZgt~5*1!0DjZ5w_>!n_BcYN@P!E!c+t2Q}*iWth+a zz}G{y0}j9icmOZZ2s8mL0NgfIcxqumCoI0ZzaTXn+p*fM&oCz|n%rKS3EK zG!V!_E4J-`18@NzzzZ}2O+X6(PYEiZ1UN@fDJ8%;f=Vd?&Jk2f32=^}Qc8ex1eH<( zoFh~?M^Gsxz&V0SDFMzA)It;B9HGKFLWN%hwbl7t-b34Pg`nn{00#(alnHQmpr)7r zCkJYU32<#t;nkqRp@CXg0^Ar>crd7TzyY`b58wqFfhGVR2`Zcss8|x1h^DXVI;tTfC?i4ZUa;p32+ur;U}QNML>mjfC|R| zYMTjg3{c@1pu#agg=2sU#{dcJS@&TZy-N-^!%osbDHQnivg@=4b};FwL2ldL#0N{zm%sD9xIec`g20 z@U<+>oYzY;=fz(MzLI@8@p6df&P%=&eo3ChH+_lb(2MNSccq_>(mZ;Zr{YfqpUQqB zK{M&)o=iR&eo}riMRV!tPoy7@J|1{HL$m1xAImd>~8n>V*=yk>p5tM5dYbBKPa}r|*m27ofTI;`avc z-EHz+U%o4KXXH-(&h#D8I|6rPZjav{;pEl6|jC9Vry zm%BE0ZSdOcH3^z^FL!nF>hRU_)hU{HPv4r}65SHmlA)RR#{a%Qv_apHrWyDG>oe=( z>w@dDGzVX3ZSJb%RpF~-%-6m~Uz5HvdS!s-;fr4pydt|gu{uOE@g-M;W;wR*B6=}tOLTBVoPtweN^69CW zk(v6;^l8!40;gq8jh`B%`TG*5gigtwoIE+qXYh-hq@R?Y5uFj3kvTDbV(`Q)pTjSA zeDe74@$&Jh<08lDG>cz!dSH4c7!L-6+5SX-s6TgXlIHT0k4+sDIYvJwO|$t0j?PSr zPYX`V9+fyM#OL!1A1Qy#Z~ijP?icCNd(z#}?f}j27w-yoWjhm{A)4VY*%9uLJ5uct zn&U6s7Htc(Wm@B{!Pcxl;Sc$9Ey0ptz~}o5da~|>JLJx}lCH2zcBPyVr|wMiS^qLD&Vnp!PuN5DoGob! z)4YEvYs9Ks)0QaB{FiBnHv}89YC;XEIVGut6I8pg^yeAi36S_{YSu^*=8gLq(D<)M~6m1k8R z>a0A}Q+cSb@{paDov|dy+atg76?!df(+X=(sot|C^%-uMjW)>#jnFnikYeYMFDIal z5PC;wQ7L7VU;*ra6KLEshkVay2`knO^Z_lTKWhct(q-fu3G@La4H?_5di>nAWn7QRdvH_DB=G=-{1K9XkI)pUX_;VI-ejyU$7E7_jI z>RZ$zG}4adAsBg#{Vx0t{Yt@(DY&W^$LMzoRZo%VJPW}_)sg>_14q1o(@Td9BfPYu zwcvT_f-tyYz{4~p;^kd(# zm!J&O!F;8((5BXo5EnxFVhfQ#T4{?iw_#+Vq}lfoyg(b!2iU!fC~ZJ1V8?Gb0iAw> zt{U*yVSjTqJW`4;z4Zm+R=YHDJbTl3L<>{Jtp9{?cv|!g1Zh&(SuLsZZ1>f?D zxGE3n{i|?SC_T$Iv{bTSmAHJ$yGCc@ho@8HlTVq&dp=5DK4+bjv$T^BaUq+%Xv1V$ zr;T4ktAufDdIqQ}HIMMS)eVIjVWkBGEn$i%uck~zr=;XJpd|Tm1y&l%r>UFjBJJ`; z=t$!}R80lGcrWd0J%mE-=)z|HCg?%+%oiyyZL&t731|UY zfp(x1=mvU$jy;4PAOKkCHI4kpsRT9vt)sXV;^s-LaPLXr()P>5i{-#}nfvJ|B->y3@3~B*b63BY9UB4OL5b zdU{Jj`bu}?e5Co>*-*Npg}u*vpC5Q`_}N|0>`6+={#`>)k36;e6Z@X* zeR9zgvByUr+xw{Z(Sb*XckX(4&qLBf{SOX3Fp}6!>mCF~GWW;t58j`pl@CJq)xA3%UgICUte>>gd+^mf)7q=J2LSRFBHTDO#~0LA@oZb?LPuR}HP{zcO$|bah~L zcvX^mK|-`1L2`L`xx73@YZB;@^iXstFccn?2UD~rLB97RvQ%GMeRMT&3quzs zE(l$aI6riLZb@=Um{uf6EsiYK7l*>RMcIXkh3WI6=fxKU7i3FDF$Csi=Emoy=0xTs zW`}4M0`zF0Hv>HxNgA;b4+TS!0ev8F#=e=!ncUoR~QwbNsI3hNlk%z5RQS89h2SZP8J^NA8=t`|uGyu0TK37*UY! z)BC8qht>;7_e6UFJ(=z}tr(E)N_2&~a-B(9GeGW4bwoP!jx?6*Zq@yJ zn@5{szD13_`aW$p9~%&K8)E_@j(!%hM{RLykY@i+SVERuL$V>v=l_qWx|&v^NBT%~xGJys6BqlFv!ZkCysWMg=v>!`*SAqr8A`J}_J1Tsz^=b*Gz+90hkPB#9H!8MUw<}TQ<;z~?By;2;7QVf6! zC=a16gHu;wo|!U@rVcJ#w~_*mpjj5r+PHzVEpu+)Dj01fqLwbbRXuO>&h5OE7mCQ$ z!tWdDGuo*z$#I1QGEP6IS#3cP3Fm9e=E#;cn^&)?oZ=JJr5H%!tk}3=CG;r|$Tv_t zthCl#BiL)$KfWHAk;r@u1|mVa3zA$bL?KGDn8a8kfsC`2)2!COwetKzttlp3aPi|s zq8M5#3JOax#6*?r1e1*<)KQgfLKLDZ7myxTOCaOy;DlrU7HY19znD+*#V#Pn{w4G9maj7|%^xoX#fsC_>6N8r4P!z&n43jQVVL4~bDrytBDuNy*Atgf4luLXz z?%u&MNmi{}wSE<*z^YW`M!{qw33XIuyAXwuPD7Q8NspT)ka4zhnyG>+M3a4&qyos!8Z`lVH4&m^$hc6QU6HxrCH?UIH0s8>g8*a3hYD=|e+f#uJDK z7ZjS-o1aUN8sOT+2(y4jR`NPmEMSGX2$6<-r8p25l4m5hehMDA`Jkeh+{|>h2yuwH zbSdS}%M!>qyEx5q3By2lROZt7MVaRmPN~eTi4^Mz=GU!4LXCviF~4p*s3<0vU$+Z! zi1~FH<<#{O$T-_L&GHMi>f*BeT3ux&gpy{52bZ)vB|$tJc}qO4m*2fg?^1UNW*f<< zpZfdn6rvE7SxTDRB7x)~O6=k^QwAk@Wu-FXmt?L^NlC^NpQsRmD^xOU9p~TsPIoCs z(R}|~ZgeW%1y<#Cn)C0APk5A}bFIpLn)9#wZ*Ju?C(|5%KXNKh(7b>DHN&agHp8l9 z&T%RmXzstyoZwV0rn&!KYH%uZ8m!8LOPoqS`TyVcmP6^IIRLlCY3%^rs(i|8RiqfL zC-6bW_BDF{Z#=X3{@*q5XKrDk3A{^C+{l4CX6gGA@CPvz^l{Q!zn5 zEo)PfB~>5DD#A+&e3ko0{x>S0LGBi8H_}o^dF~OS5ak&pVQ!N^#@WqjCJ*KxxT1RurgMyl#4)O|t}qEJI5(eo0>IB6|i+BOpkvj)&A1r_C_#v@5S z{S$vMDb=gwE>}2Q`ABlVkVqrZ_0#dd$U#Lhxm#R9h(pY)2<6Pn6395GaGK>+htz?I z<*Vn_L`wE#A5SKmYYzy?HIiS)Tzl}KqL^H+JtV{-=Gt<~uRA1=arSVUh`D*g{a#qQf!3;GESY-OgGF+eUhPD#iA(r24ifYyYui| zjP>l+Y=~^3p3stq+x?H#FzX63=voP6oXwnOW?{KE>R-&qUv)%yX%Ib{kV(_lNAgpO z@J^NdMfq+tBe2BY1CI;#8upK$Q|qZWX9M-PioNnGjW19oiU+w-C<{*E<-+)1@h7Vp_gWmv_-}?eLTN^z8pcjo3C( zJSR#Z*~IFYpregXtX^2Tjvkv!)>SD{c2|vfw^59zNg(5F z;>0vy5$QT3g~q?UZ?TJ}0Yh(CA?A{8G0n*uamOjvjS|Q>TRHRdI7Ey%jeq&9{M4^G z)_Ig~Hif=TA++ShLI~luR=!g_BbaO?Vf?B)sovgag(!>!8a3-?(qpRxGR_W8GgZ(D z&Q}r@yVT5t8S8Varp;KOi9F8K13&9%W zWaD3>(2R9yS1mLb{po;Bd4S&ifACGGvU#Re*?pQ*ne`2u@{PM~%B4rylwUh+$_>A^ zD(y$o`}+}A#m?yc{aU7Ys2||ui`>c&=>6Zl)1|z8wpBTY`T#EaqeuAzt^YSd@BgpT z-2Zdv{r~2OOX;CC09NdFDiW;$aPN!_?|hx!|BpT^-{9l>f5+}WbIZ%WNt9%ikPeev zdO?uTko05c5*b%$uwN9SFa$RW@vW3ITP2Wjc5s^IQlSu!rEaVk3Wd1xglgK1U2P)I zOM>l2TIwjz%R&^QJhziDS4be^Y~w_0zqQK!1-*z1sI?a!kpywXV3G#?W8z^hO3Bm8 z{#R<)dIwp#Q34rf7pIx6g^3Cgs~B??d&N^qY!-tm?0&U|-8;zQdnAx?c5s?Kp`ZwE z%s-)QGCogK`*?;A%;hJP6hR6sE@8|25BQXph1*OofAlH2O_$`tf!Bo87^$mcp?qD4 zLM)VblT=$Ika2c!jwcwOOmh`qfR=yHF%#?>qe0^*mMpEji&YMCM zqB{4GE(r-_oV}c8>R^4y8-?P8dr#F5vSnqec$S$?IAd~!Yg9;^k=8oOmlC27<-3=J zyHNreXD{b?@=^B$gc&P4MPY=7#N@1T`j8-WH+|wYr~Fx=#WbXD27L z+DNVt!e0!Nlx`-i;N(%>GKo4>o>8h1g^u5N;c}DK>m4CQMhfdF+Pgv&h786N#|X)F zwFENGPR{W}qj_n$Xk#U;YV(Cum!DxSnt7@Eq+q>~nmP*fo)Cp7P=cg+Py!iefYVGM ztXD{DEti)n^D0U6+iq58WjTyb`=j)SoYZ(mOVo@MJ14NYMdzNo2odR*(4iYPjDNq z=;h5HELcQ4#XHP4boTPcV{%%>X=S&T-DCX$pQ~Z(^JHaA0vV@|)67<=NN!-o_{vnY z++jL`oONtBtL-Y*IkO|RI73fji3EG`2e_ouWtvKlYf8je$<+t?i-~Dr!vifGH@_yQ(Ttx5wPtd#nNm&1nx?Fw# z^Xt$z=>7lXS;hDNw*LJ4|I`u#t7*5Pw8+uUrd6w}iAeRa@VdUchKMhae78y<C0LsFe4W@}Of(l8&u<80;}&)z~k z+qz-xhK<)$tP+8w7(u3zo7nn=8n(W{wFQ|3Hgk?=Yr%=zD6C~QEnh&4plY@nVWowm z5KA3x>zo&SX>OOW^*yr%<3=IuzHm2T_b^vvys!x zYJ3KmlefCsjS9tqAFpO>Ma?S}_sccR{4^IAWD@A*gqhXeQ0$VOd-UVsuJR6%KWdmr zduI0t^Jl~TAJwq;1F~_c1TxMhPBVMqL47*OT8vOE3B`~SyUXuj#m4t5HH`a^%o>(J z#@WJYW*io*HO2xMZBsS#jIe@%g?6hHw zCezjys+NYAXj?23=0<<5hS6UjbJs{9<80wHGa5RhwS`eeTU1SFBh1X$v3gc^XZU&z zTfaEkrB6;CxZUw_`#Do?D%fa+G_60}%lCVr!aiC-b()=MDcY~?gF5&ri} z3MLkt$!dZYL#rBF46d;Fn>8%{8reE1fsE6~35%;e))pSPsSzDU8K`Wy#sUmGskz-Y z*qhIWZDk$|->P9*zY4Enka0G0j<-Am4Sb;$7xLYJP%$_dEIxdVg^*?F)G$UyMcwePLDFY+i2s4b=Q^JeBj%H%|;sP_yV~{h(dgU43Z!>Ng(5F;WU#4H8#R!!Gou{ zG{sOso?^fRCCUi)8|kT|MBfpj5G9(L}6ogeXLbjw4xakw97yp4iT5CJ}B{)N4ak2*sh8-fA+HpCL$99ymd{zAvQ3NLwA{ z`hgIIDA$Q3(M=M_IGZ@l zr1}5WpOb(8=MnE-CjBOG8Q;Xj%V)>auoH!%;h{aaXP-TrM%$86t&mDcSU%*t&4P80ZDOwMfo9#&hoe;;!++kb%d z*6lyURL%Au$>5JMW3&BVRPZO5xY_=%Sase0Q_SCN|2G@>Gfd-b-^;)(W^=axJJw#e z{~VJ#+yBE2{wHR3Hj?oR4TpY-d7kb6g$3B{zru9S_FrQOcKdHI>$Cm0&EW4a`Lq4M zu?)NYe=rBMeIFKLx92bwwEg#3irxMP%m{7&V*~gnObl)RUo6LN|1;)?w*SQr{uR?i z+yCYO|Bl(B?f>Tj_hZs%`vDL556m5H>!NoU+L1Abv|VWgRZJyqZ)gH7m{GcrjxK8p z4%slj^#8}+o5wj(=lTD2bkbG1DwU(tCv<_Ff)d30fGEf*bO2Al?tpj$9YjS$?Z_#3 z5K%|GARZv%K^(_Xcbp+R=N_}$nLTE9jvX@RUb9Pfc6auealh}^C#g>Lr&H-hGr!+I z>pbR3r|MJn`Mh7BPkmCU`n=z7ML~jgg=J`0Tu9NbxRIk>@gU~3;uZZwp9E?MK&|*2 zK-~cb5RF<1Hi97q469(13yiqIW)Iln1zUY!n+CS~!48D2Rz?ND(Lt~?1R7y*OcOXZ z0-k~7?aDZWv^LEckL>Nr1O&KNCL({kG6_+xmC4B9uAGTr*UA(JI2AFkm9vn=T{#<} zua#*k7)1nZWx5+Y2Z6Aa8D8*Q#KTt3)4=l)7F)SM2QNf)Y~`XLcyS241fjB(OPj#U zBH&EK%~ob1ue%aMVt3_o1kqNm5N8o*Be%OU2NAVRGp z$Zchj3%tq=E=K%qWr-K;@_}&#<5rgX!DWcatt=0KS0gmHa!m-lHVj_Z1YVCo-O3F} z_^zx#yl!Qs*hO50u-(dyGT4pi-Aa!GOdyE2vbqsmgIM0mO)9t+A-zpAZgykSEePUn-AQsfjj&}(~O-uHth<4 zyMy2(A#hI^+}i{`8UY_esBz_Sq=;9ZK*VunpRkXZ7QrVaaK8*b)c`*20H1M!pKAo4 zRlox(_?!!T-VMIs0blfjFZsZO8hFSLW_0l70QgD}d^H5V7ABfz9B#sjd9z1V68U@2TJyT;Tg|@QWVs126cY z5Bx|2|G*D^Ne4d;fL{)RUkQOH!eFim{KE+NRRl{{zJ|Q=%GVJy-8ADHh@Gx{6T#D! zZy|cR@<#}tuKY3Lrz?Mg0P4!0B7(Z|ZG=!){tPkHl|M%ib)_Fs)RjEKs4L&`fPaBN z>dIdtlDhI&2&Jz4wIBSh4t@{O)Rn&pg5O6_b>#4?gf8HSnMO;IDM>p9A2(1i@1wuowpa zwF&%n1pGJQ6!G6h@INH*H!}F24d8z{!2foF|I-NmRsnyff}gm+|8)}^M+qK$5WS$} z17!_t@PiJWShi!7Gk{HvK~M>SDpJ!cE<}P?+%o7vKzPOL0DXuHuV{^+AK~E@T?GS( z60Zc^UW=yfPL^>yr^rGQP43$?laK5g=dbM!I{Y2XXS11QOmWs}U|=SK-94}e*A&p(R(8TFQM=qt0nQuuP}%f^>;A16K*KhAt9 z_NBrfr2gReNAZt}AErNyewhCt`GNjH_KWc^7T-_5AALXng(T%R$i5eUulV^iWj4sa zn|xP)H=B)TiN6G+?$Cv#Wyp@V#f-U&%k&icQkQSJeqku z_Ilw+>WFb9cQ|oaJe+wg_FCc9)T_p;xmOaeh_7TQ#$7U_Qx1dpq2j^x!6;=gNWP@M zlzlNy`3ur7L|@21pQP*s+2`WV6%V8-cR~Ky~ycvK1JQL;Td~!kDS__ z-W}bYrz{2fuI$eE&f<>rj_8j3_T+Y*G8DwO6(3GN9DO*SN>YA;Y+t;u_)wa%6XYLE zKBzyKrQ8I4TMf!fkhovGKSNmw^7ke0)9=e}j&CkfPJ-yY`FoQ0=#-Hles^(GnqukY z?@HdK-<91M-&jnhlhI_pSLn@bh;1mWPpvm7vR-1HxGr;NjIt1xanDRI-jHPJQs)k(@ckWIuB#hx_f9msblyLF1X z7r(K%D!nSYDo;5F^p)8a@fF1z(l6@#~7$c3zviCUK2;O@`v`6_%%# z8_RRc5)^kYvoyA}5KqMo$}*7X61y@>Vw7Vbwb)pkyDC8$1~Q9ciwX-<3y&{|FDO!O zf$04FyyQHcG7H2h24DKhC`I8*&e7*&XU8e4K>CX475U4Plv5xZi^qzy(v(pkKQlQ~ zpE>KY!lkK84ay~uxJ0}pb8(C^38XGEC?;Qm@(5%uh+R-PKSfyta_1$^6VJ<>8#}i! zBQ?XAk)sR(;yIb={n2Dpk7lREDR)5n?C9C~vyzlKAUicawKyeBc?0riCePH*%ubF^ zE>22MicZQ;Oit7%W+%ia6vwB>N5}V!6USxFh@DXwn;L73&5cQn5yxbVm{I6Vbs7}a zFELsiof#FQn0~1aqa)Xzpoo5%wpd%CHAV6KaxJHt)07<`A4x{^NTw;)R0yZS24x0F zgv3xL7^A!Zselp4=?TgTknzX-1uaE60dl^CPxNIdBS5c5r)&UmchQx0MO}F{sp@K0 ziBl$kbYrwJ?@Ur2fUF}<5dhPa1t2dcDgIxUasU*?G)4c*(vn- zc&z_#75E{9vo}c(nS{n#yy~ zAx~_qyGHm(>u)$KOsneg)TS)d_qi%~p)O!TfvNyDGY&6Q<>_B_p{)D4r+?O6BNXZf zoE4^3brkA{Tot@f7m_%;1W;vcXS5Tlyz+F&qtfbP4SpV4b!2@C(SF2PWLj89(f*dJ zf){Nj6Ae@aFvMsl8XlOI-coF-@s7gW$BioXdWl}xl&;9>QjDYFDIEf(#*S%5eoH7&I;42Itul7Tot@fSCTmU1(0Gc6I&VWgu=_j zdoAP4wAX%=nI$;E_%UV{8=-K2&sk+!Sx4difvbWSZZ3)SgaA^=WF{O~OE_|Bp$pV{ zaoUZt$`v={w!$1~)*>Sm?H@UdObhEM+COns@S@Eli9RQQ6kM4&iqTFq#FyG;8EsaZ z?MIxo)G(vYT6BaW{))5Ew78BU{xeqvFXAE+ZkGU3OlD#$qn(JA_y4pM?WWsqzPZL- z+TaqLc!PJ2P_BRBY%y)Cqg({@GfYPJoe}G{{IK%-~Xjhj*HqgomxfaQtReXX1TO4Jy5WNPUPN7_Ej2;H5-8%24RiHcuUh7sc91`O~X=< z;826G;=?KfmQ+||z{-mtwSsbDwNi7(`o^;6mU^VpHmP?7we9FY^RfP;sYY9|&||Wt ztyo7A8QM6k6B%PEhBYDX;alVDp<;VTQI?i+pi%Ap-BpH7!wDKOZj2b2jG)5|IlM=yS^+Qn8|zPMbQpGX-%by56WDGkCy? zFzq;lE8IfcrdUoGq0i$g=Xc{=m5(BQbXPuN-HxwDUtxicwG*)Z$5-Wo!aAQ;OJ@m` zUy`n7Y@yP7XbhFE3z{-8d*T21kFIkWa{*W!+mD)mGtAw$93#Hywbg@;wIIuuvYULQLOKBOb1D2jx z)yA38!h~_&uSM|lvwO?QH|C^ zd07Iqf0{*>20FZBunr#DWVH!vSu8d==?ruPe_|hPw)RnoKI_Aq9>PdCNRuaK1Ka{s zW^UyK=36$83|tW|+BT7!Rz0-MFz+BLhd0q?N=k}pXyEW>+BSnb+(+A{4jzksY+|!I z<_Wr(gR}v60oE^(rbATi;7tM*n`r4ri9Q?F^Ehb3ce;m@Zh0eR&J#RpsMoesa*~_m(fec z(zn8pGd1H(Xfn=$yH9qBn8FQ=Yz6IsEtF)H&N9%lvf{0$)(R~Kt6*SPm79YORE8?h zlBxwsAKdKF4YB2Zxs49H_$VE=2RqAEwor>&aAhOIG15}fr8(%F&m= zzImkLXh!M#6@^&F?{at24=C2V?9RkNd1x;R3Ut4OJ9#vOWyUp2urk4EbhD++qU@#R z1ls5=Y8&oBm}+eHDdoY{r_q3|S&RW+jWrXmM`+^=Dvs^Y z;Q$R%8nWzw7TQNYA87bffmi8#bXNsw+0Mv``AG0iw=pzCY`51srt24}pJ#tsEM!hb zf0X-v^82apMZZ`4%TzwvpZnAJA1A(5{JQbAcrNjk%ty&D8edG%YLw{bjdzV~_MP0@ zxwq19rjMm*g-PZ};kDwc;;Xrrv$T#Rbuji)^hNQ7+;gb|`m_0G(oYxm(^89l;uHGg z`eOxJ_fgng+*RBe-4WfMOXd6W52YSVKak#yjonA?n*B%E-Wrc&QH!uUYVMM z+=H3R6S4fv^ks=l6PH9UE?$_tKs-N-H4Nvb&oQFLv@ESr$kMum*u?mR`1ryZ#j(XP zMOtqV?TEI;T4OEwNP*T86oP45Lr@H)b=|LPd2iGccV}EVHK`blafjFtB^R_ef3@hh z{q+8SetG>r-v68N|4YvT`bzoO;J}3q<#*lx%01>Nm8~oah|`0chXjz4Z4pC^c8_m( z_l?ap+&4B?ci-4NQumEtb1gS5In4(&wZ!>1t_oh9r6kBU0i?8BL`u6wv=gV=iizq1 zRbDU-5y`r%_LD5Li$D2y&I;42Ituk4Tot@f%a~B0DuB(5!wXe;LR?)a>wfORpLN#= zh58L=g=tkCh5Apf3SOw?B+f1YR2kbD?S!&hF;QJC3>~W~oM8O!5sLO-oJFREbrkKt zxhiA~xmJ({4+kPQ{(I)~q9QO*T!aqbdzt73Lr^ zM^A#3=o3K7^FoX;+NpvFIX#upQ?k@{?38wM>XNN?B*2k&P#nGsQHmj%vBMDtNVSCWRgrK$S7bXs1>=R-HN7th2xK zS%*1#-Q9O?nldQb2Texnx-Hwwp-F7+gWO!>O=D{7vyMe9-!vp^N$IyM+5{0wzg<7^ ze5xwU>c}p)sxz6nvszb_4y)M>)j|q=qH~s* zmesL80-vgi)9Q~PR|Vf6w^2`|1yE&dVYKTH+~Lx4OY`zDWv|*NxCG1s)%s|nIh2?;bdR>rW^ z-l|$*oLUQUdhxqQqFD=PkZE8YHEZRn;5AE(u)y;jCPuFzu2lgO*3zzhCH6d z^jmp?UF#QH8`oshggUCy&Q-yyvXPYN6F^FXMvO4psZ!+^n~gH&TsK6W%8rqYn+~q| zra5&~XcSikuh3mgAy5^-2;&G8GJj~;C{)?aU0;5QIx5u3RlzH?iB#Dx zfGT4fqn$!Fzu0V4!f>ew!YMU)=Sb8tI8#j1>ZsNjt_ohQ`$(r90!V53h(Sg>wJ;A+ zFf>dyrCW=tGj?egrw-;JJ58$IV~pimZdy`Dan9hX;KkWOf;=LClsk|ZVYCwm(-Aoh z4Zb<6DiB6WRgui;=(L0y$5~-oRY#%5b5-y{-Oq#qRRN4JjzFlg^NZbmQe`(cn#_yv zw1k?#Sz%iBnT6^c_;o&!tAZD5D~a=%0IG~_jCMj{av~?8%7`+}t}&|2BAj3wdcU*Y zC2gSJ|3}w(q$}z7f8U)Rse^w1uQ^7)*JG%Ib%RN#%{r>-ue*6D)wO8t++QYa5sK@6 zx9>aj`+w`ap}+qtv*>Ac;3Q66Q|-^(fz(aqd)>)g6?_LiL|wN_09D2?qg@B$_cQrI zSLREb=cT2|V2E!Q=1lu%e^qDAGr9Jg_S8|LDO?r2M13UAUSxnEiNF>{JBjdR}(T+_HJc)1=Xah?!B${tJXV6>A9KQ_sGt1`MOhSwNjl|ofUS!L&G zNf+hpGVQFRbkn&icYfc}t0Q5>=hMY-Fn3^9_;8yz4tnxz6QmF>R}(T<39B@N(^9 za)FdOmB|H;K(5N%Wh0lh0Cy3Z7vO2ibv|c{XMh>jFsGNr~-@cG6)P+Sbyvk9mmY zHz-9Es5Q)muaU zp1nfnkoS(Vfd5fTpit?i^^;3JWer%4wqD?0J30jXkJ(YF<9C;Gb?_bZ7JNlRx|>nO9>r|hiDI5SPN>(^N`KV=Q4(^<2)I{40d zoVw;c0aO{!V6^M3cA>rRsZwW|6A0@B_F==_>o-+@$zfBrTBn&sYj;|uzA9H)j5FDk zpne^9`KPR5_>P-3@ciHkt`5HAo}e!KKmaLoE^#8GUB`6_oqdPQt1Pg=DZRbeDJ?q7 zDP4c5CjI*&r?h_x<@USZC(T>vlzuVUDY-xLO0Uy1fd1WHX&pTS$b8cyT}ICUHh#k+ zY4i+WiNhoP6aDrNZTCu9`u+d&KlDfs({KOxa~^3KtpV6Cc%*6g{ZCU=D6{Ara&;UOW0D?dmXabsn7N8Ai2gH2@ z31|SEfC9Jx58wm*KmZ5T-)mVgGp2{ZyK-~v2=572=C&;qmp;&Flu zGy*E%2E2d<=s*w%14wTmBd>vsga$G)8OTUsAR~8yjHCrJvK7ckQ$Q_5h5{L>31s9X zkdcKzM*0C6c?V=99FUP|Kt_rI8My^yBo&a6O+ZE(0U7xNWDkIh0WvZL$Vd?&BR7DI zYydLS0LX~{FC+ZFEYgY;SppgW2ha#8fD7;dJ_5DSkG}&z2xtNjuwQNk5Sw2{P<|QF z_+^CQml1zoM&Nzf3n0|Kj2Qbeg6qqOtuG^}zKodqGJ@&Lh@~$hh`x*%`ZA*C%Ltk; zBU-+UVEHnlFC#j>>;n)LpIV53_%b5l%LsulBlf*4b`fO20W<mKy+s zj+PNKT1K#F8BwBTgomcFLO?)h8Y={ZfR+*aSw_TW8KIixAP@$`eu4}*2-Lzx{H+3R zzzb-A4g`TP5CO!K1Q~DujerWc0WY8dIuHcHKm?FZ5gGs|pa5P#19Tt=gn|2-HF!{?>sY5C$TE&`Xej2EYj@fC~`&7SPdd&+!FR9BAw(goTBIJO&8) z38R4KeuC!|p$#yAW?>PX+fQikCp7F^OxjQ^9_nX8pmPZ(W`Y5D`v~ejLV)2U{WS`3 zo+2pIy69sULF*xm2Aq8a-yuT7acl$p{RHPpLZ?4Yl}{tI17a7!4KyDjj0GBx6Lg>h z2%R7Z{e(`S@f1OvwG^F2aP$zG8G7k2p^wl8H0~p4Knq|1jfV&g)8Zta$3g$d4zhht zpLdL({+6*pV#@lw5VaXlpllOF75s!SFdAs-CwNa0+JP}Z3zU_iYzLHeLfHn08Uliy zq*%)=!Wh8UM{q&ZAj3)eYc$XZWz}iWt_#{h)J~wWkDwhQI3TJMXap3X6VUsy?IgAV zD&PVPnApKg?4rLsKnv6sj}sIi0E_~{kX-C17=Ut$Ak8A}0)VrJ(8AD5e~EpBc0hr~ zexMZ?11N_GUW%GBr!UanKb!t(8cqMui3w)_j#GpX&GyyF@2VekV7oh=g0Up2)gn$Up0gMI=K;pD(_fc{l#9NYU~WSv{LOo;+?)y!_NV(RT`Or{9jfU3@F^R{SmT ztt>^&*Wb(?OCB?hSt1 ze{#RDKT9$7Po*>IX%tgGy)U+}_(bN3I7QXZKAw17e?0eClH%&;A5A?PeYCJQO_BAB zdop|Cd&E82M-q?dkK}eIcN-L6Kea2mtFSY@Ge!~iGdtot#2wk~35v0w+m_sBY|B5K zqA2@?R5}$)75g$2XJ72gK9qP!e<(+h_KgSg5A-~sKaks+q-gv3`&0Kv?=NggZ;5Rw z-q&|u^uEI8^yU~v+|S$_zgN6BdryL5?&t1K-fi5S-;|=L`-QvGcg5~1Zp={JeQ{%! z+_&{)t~c3h^yWA8Y|uC4)+Z_YetunQU36XH&NRi}FW!;4BYuZ?N0uV+>$m4_OWtPO zmZuo}(OV0*q;HAcQoK2HbNptJ{K03fE#8#5DSnf9Q+7>ajSlbd)yC?4B9(|H3KWe$ z)>G`xbjQ0zipQV0QNJ;_D!Iy_i2SLQ(UpZ2=@p$T`fo^4O#Z_4>FZI-uVk_(Il`S~e|)L)pFo)?=}oSUIo{U<3_ zf9%TQoXni~9Fd~+CuZxjb5|shkF2g;+Wkqlo>PS@BuotnADL#q7^rmb}ck zEKhO!qnDnzBzcK(N&e#0#ZijfpS~z|QSrjeg>j1ApS>V)fqp^m{3J#1&!3k%FM3|# z+%(1SFV4u!h|dsbWGRBbe$Juk@#*69Y&1bp{BzTi(~N2Pvr`nuzi?Litk_w_sTqpo zFHX%)NlekFy{`vM)d$hgK zmZs?b#nwz~yj5(?wj^5gmRxhP*`OHzsYsN(^3xRMzZlMh<6$wJ4b2J_gPCAFCr7DG|C}S~FdX@Y6h;0o$Z0ty7o`lv{uiaJm=JX_CnV{)#U(%g zZtySZ{r}VREARi!`2UqB(Ia_~WPNhYm9O?N$y)p~JW!g=J&G|O&D8IK(wt9O!|)H3 zNdEGAhAX)`_y^WnV=YDfJ15JbL*G=<2Weum(P4l@r_-=ZNIw&iED&rVNyKZU~TKgV1pZl3h&4%kL zTs9->u8}=quhC@-IAcxY>(^xqKV=Q4(`AdeI`}SonmX%40aO{sGun08C}C9JbLN$0 zJ`U$5JDV%argXI{%`7_H)mHOK`&FFbrV#b(zQv!ihSTZ3C0reR_dP=$_ptz~jFTDd zx^Ijyrth%ziZhiSNf(x`Jewn`b>qmt;mWVk?IzDIP6Shw`gLXeQ`T@gUAdI2gYU`% z)QJZLP-SdlwChU5{xADj(HB$cd#CD^H?X(VMWq+NQ|N6l@|Tpq(n=eLeP>**XOi`` z@iNXT)5?+b&6**vjTHg^Gn)*B$~OqhxoUXvo+H^_5kQr(mC;T-1Q*{{xem*3c{OLDX>px}yoRfW7xHU)WA;2 zL9-@XOK2Wpu2nMUO{+?kub>Ye_ek*vozh*u@=BfuoKou)P5S)(PU+jX`=pzr4thpUDcHA6yX1yE(|WV90%tHz$MTq&GrRi~XHGkH~U zEu}^_4Gk}Fg0tLIqRs-Z=BnWZewCzsMF3UCW=1=KF`rY~umOLS8uuLRQGxB3Bj)oF z%;uGc1l8^})^N6&w$@p~o49It311`ejtHR2*v@DtA!hSODr3|llkNDll&SL7XwK%J zS zOZ*SZQ`*vI>u|e+YpB`q+IpN;tdBdnDonG?SRZeZ3cUiTGPW?|W zN`WexRCW&4WgXXO(}+6ivYxAg*X3=d3#bZU3*(4%sZ269G&Y+zNywbIs=0QISnt6}%$v zk`|i;P-Sdmv{M9b@+(b6D)WS`D%K)4BgWKq=yRPg;MsQ`))RCyn0Zl&<)ySNh>br}UGICf%PT-~W?7 zX?!pJ{_mkx<~#3Q{@1kr|CvRW_5Y{3h2PGa%M2RRKZo-FvBVrmSAiTN2Wde0d17@!rD4>7cJpxC?(}!?eWuRP3R*?fa1SW(7ZqZ zXaeLuYy$#-<0QcV8Yrcf<^uviLl>c~hamM5yoU&5PZAnW%@efIKzytUIKM(*M`v{GI3b+9;paD7%0wO>Q&<049x<_*WjX)TP04;!cf*=D< zKn2`@7tjD52muj5?8i1B2#6;M4L~EH0&c(yXg~l60}((xMUVjppa5>b3uu521c4?% z5>`?jfC9Jx51;`7AOti4;xvK`H~|%K15JQ9iy#9Ipb=03H{b(wAjCfIqrc$AqQQ%W z)Fr@yMT75(2G12zmjKTd4W26+oK`gWt7!07A&Cj_Qqkb0qQOf=gO`d1FBJ`5DjK|0 zGrJ})0MT3`$1}_!To&YZu4PGjwI00TNGzbasQX$z1@KGVz3Gh+T;G?3! zM}@Q}z(+-cj|$1T3UU(Qqe7Yz;G;sC65ykv!AFIJCBR38geAa7MT2{aCiw|)N}(%- z-~v2=4}docT?>Q|&;-C6MT0kr25%G%-Y6QpQ8aj?Xz)hS;Ekfe8%2XRiUw~K4gMb* z{694Ke`xUk(BS`}!T&=OdkOIWpzDYL{|`+C+<+I*0Qi4s@c+=lKm>sQhX(%-4gMb* zygxK2pa3qw1NZtMyKm&9j z2*4LagD;2%Ul0wxAR2r@=t?8N7es?Ehz4H}4Za{6JV7*gf@tsrp^K3KPY?~BAR0VD zG_OAsYNbsGkY&3(?>gqQNgjgI|aSzYq<6AsYNb zH28&3?-Jk_LcL3XUkLRs0bU{0y99WJQ124p6{5i_L=&fx?*qQAD%!$FM1zlrrUUR1 zp^KLQ9}&8E3Gfl2iP13Xz(4ODVzY`5gJ7V_>RyhBEWY2BfwLH#vTElA~g00@D$OcP69kdGc~G>sA9E26<-~<%F1$Y3xpAZDX{qqFe-XRqllA#@`+#<4@L?_+e zd57LRIw%9`XeZD_C!hi>$r~L%4tKcb{UrXS8_ib#a=}|lg4#xZ217UmDb^@;npu>J zjqRT;IFP;7RlZA(kehc!}b zg%{E<#9k;qpLst1y!d?fxx{n&bGZY_1IB^;v#DpJ&lWzH{#?&9`ZKwwlTRB@=buVF z6@99(KfOP;zxZV4$@r7vli744t*3MQlKYH(`6p6OM4u=;o_;*`c=55!WAVqt$Fh(1 z?Tu1SxAdOap5h~!N8*o&k7RczcI&%yyOO(%UHP4o@-jKLKzae*h@_OU?{B^18qSqC!OJ~ww|@=D{%{G8OB=$yjr^z7K|;uV=I;#Y`Q zWG_!#u3w&uC1XY`KPxpWI;$`X+s|qi;cOdUCokJs(X) zqtU{&^t9Nt;@O$A<7bO!XU|HUrJt3Xnw)A(%}+^9iB2h;nLaaiW^r<6a(uElIXfva zNuQLPn4D-#%uh&7h)yVsPmhm{FOJKMi;ok>WzR^Qp`Vc(n;dJ5&5ucqiH<24X(MJ7 zJ2Rc}PO&pPIx$)wog0-LWsJ&qq&lJH22BsOKkiLf5dg_0p7ln+YdXY3}77p_q?UKJ!x=YJPdW zz-F!rW*EVIQvM!2nb|6UD&uHIyQee}A<}oN^%<7cz7ak9tg6!Br=QiH_T9&sVVYG( zrM7TY@Jf9^8f_Lpl`+C-rxc!lQg*P?15Wb=vW-IK?kZ3DwqWte#v*czXQNeVOjU{vqZf)-3J=vR#TjH8SVzqs=BnT|`A<0>kKJ|3+dP*L>5QIx4iCtAbbP%cRYA0aO_~80{3oTRzH?WgS(f zbv4J7S!fugDl=8J@4FqGDW++4RBI1$YzxxG` z^jmuGKl2Ba`;XrHJGOYGm+8I#cR%n*n<)O@(JxZ20E+*&>p$Gm85I9-8RY;tMe+a6 zq#OX>qWFLEGLLkK;{W|J?UuGv{J)QTJ<<(`|98kC{ATRxd%s8T|5smSdH>(nEsRQ) z;{SyXt)P%A<(4+l2elaxP7ox(0VseA@Blu*4+McGpc#<*2{OBZ9>53qfdCK&L}4Y>0XP6B z&Xlf+j19Tt=P;O{JjR4X#f&)+h7vKTBfDh0BKcE8vAP9tjFc1NxS%e0_2`GRI z@B)4y2s8l^pc!ZZ#2$hK$Up<&02IIlcmN-u10f&+v;x9Df($r-MnDDJfEUmJ9S8zV zKnu_Yh=&L=-~bfB4R`?!@B=|01cZSmAObW4tw1{<9VavZ4!{X0fD7;dKEMwIfDq6G zM1W?X1!x7t69fs6fd;?mVPGCqvBeE| z0S(ZBAP@#3Knu_YNXH2cfD=#v7vKSWfFB3|A)pCp23mnOKs-T^02yci9DoyO1QbH0 zo!H_6+<*u00zNf z3b+9;paD7%1j2ySOK1R`gn@P{*x~{_fDiBk0U!j3`v@}N02%=ma06aI19Tt=gaPRg zp#g9JPM{G`02OcnZomV00UzK80)&BfhOngxkopM?fD=#v7vKSWfFB3|A)pCp2BedO z2EYj@fD7;dKEMwIfDq6Gh^GiL-~bu{6>tG=!azGc*y02HKmZ510KK!_<;ZrA`G;%30s;0v4y3h8$5s)@BtbS091l9)rCL(_;ZGiKg0O*!Y2HQSNt?Y2rWPx zL7CZ(Kk?pQ?ZoGSe@mZw-WT7`ej)J%@eA4a67T8nYEN`e;gR$su}6x#GrQxv#ogImiCy}x+|J}qV`qMcaGG%d`FHbuTcTSE z_oeTP-B;Y4*&N?2ZqDADxL3b7cTe&j)UA!@KWBf+(#_X!ZDt%RMWpbslGQUEg_wzk9-p`BIWUo$KtzVs6o?LD$&o4_Y zi!LiHO)rftEygqPc)YJG+ErMRUJ_eUT%1`PUo0-pUX{2?zbdyVxyV?QUzl1LU07I< zUJzSQoS&H=pD)hO&P&YG=jG-m=NfbKSEjCvURjuvo)eo>oSm5+pDoVLUXi#$zan>e z@^a(yd@L1<#tO62vtqM~Gcz;eGsT(N%MzFAm*p-^UTR#Lza(`@^pe8G>5F3*7ca_O z6u(HkD0^YzLjA(r1<4DH3-afu&X1m7I4^x(?7ZT+nRDakisxo$BxdL{a_1z^G0w?P zPfd?bFGSPPShP4TGc7(%oR&R1akhST?yTfl###BPsj1Pag(>MNu_?tfGiS!n6wk~~ zPE6J(=O!g58I$r8Q=c*ZUuslzRG}l?5$hh>Ww*P(rGyJ zj+7(nC^V!SVhu$(BgbV?&PoYMmvUlKG{ijptpB&KDKGsEz5oAudHp~9|J(aY{{N*{ z=%1vyM=a(empVShd6KKbd@^FbrT->-iUX3;;P`)`4%a%RRC4S(TsNL)L6q{s}LS!S!JlA5?^GfQcrVcm}b>c zsb{zfM382atVYCwk4~@G`QP=}cdtuDooH*EA%FHwZfevu3H?66o zK+kbi@B)3C2?VMF7-1ZdKL}0)Tot@Pe@3G0 z5I~i&jnPgZJY>JaI)Y3?Z7#2YnPuo@RvAg=IffDIMa~k_vO0?O5?2K;RzJz~kN~QT zVMaT#;HQ4QDHbjl+xN+(omEFtY1c5)9OT+<+EGVo4sliR(&R~$Z33t=wlLaBgC!hm zO=--j##Ww60ZyXI7#fjG8O{dNraH>>GFJsJ(|4FmpeleZj3biCyi9CmsubX48ayYN zYc_0WrB^r`Oq=Q`)2mz+yi9*V((DpIm9c}-PA0rqPg+M)MTrs2OZ)X!eV54u zssh-;I3k(M3&mEZN`abl)3BrI7-xfN(`T0H_&{)gH@PZ!nZ8HT>=Hngv4fFhnz5uo z%G0}l?_!Vi2EF_L#UhWijeP(AWUpJgmDT_}>+(wH(i(u|e2?U#H2@3dd8A*`yZ^Iy zxurj)cmL91k96={r&RcvTY8Yz0G#-#TUteH0FI5Jm;tl~AeHn;qi7Aln&WOspfvy& zy#K=szfbS~or^`Yje;;MAq1lH*k=d1&@*2zmv4$sVtzwTc-41OY8r<@j!XyHwz2e4 zlTQ#_C+1^^;X9A*aMMTf$Rf1&!&lybt3KO<$O4)~F#yPKkbuYl8UhMvhzmf@jO5T% z_Wx(aOTPc?Pq_7$y#Coo1OXtAGt;Y|ZG)3Pd0PH|@0}0NFXnQl!EH>dIP1gBjQ7}w z+n5H2F%8~k(on!-z8gO|PrFMW!2 zfxpO0UxSxE1*o8VU3lqJjGSS-^x4Vbo3B-T^Vzm`IP$0I=DKvlEuEkuopihGI8X{H zK%oQ%e-g#M57QsSK8SxY@xK1P!LkWv*{XruyUBNrck|g)HkvIQPalsRkG~_nlYKkE z)(q@>Ge+wLGRNY_#ADev5^v~l0Pm1#hsa*@txw%?2g0^eMfG4a=WoTzb&;bx~=eV`r+8a{#33n*=O|SA4)wG zeW>tY`oY+P#RoDE#2*kJ$Zkz+)wkyEPu_3bpWl+Ix>8`;J%zi|cgOB7Zpv(mZxT0U z?@HXI-<8{#+-PjfCsWC2ve29EjrA5cWH!V%h#Ru&6YKT$xpm2P#=88SsXMzylqE2+ zR$rUDDS4A|Q+`cqO>|9Rb$WGdbup1i^!6A%`R-JAw7YO)`o`Fe#Z{SA@m1og?8?MS z|H|BoE-ue3k1rROXO|_G>C19UlS_@I`FJWGjTgGoU9qm>lFX9$ z5^+g(abmH)ICoX@D&wmBqST`3qQb)T!q~#%g3N;W0&ziheqz2pKQ}Kq&zP5=o0=P) zTlkFG0SlL;FNs}Jyf|}l{9^Iq>_v%-^ow#ACNDHD%wLeYAbLUJ{Pg*;^NZ(Y&WoQX zo|ip0ajt%DZbov3F(ZFY>YV5~h3V<(vFXKVCK`{5(d@LuG<{m`?Bvksr)1AeoT;Cgo1C0%OwLbAO^Qw`OiWLVO)O5xOo&eqCuGMb#_QvA zz-L%cz3(B+(zlu}}pe)3Xs*Ej+c7ovP=n7L1jDVV=R0?pyRCd%5C(E_mw4{#WyvtR= zi}SZk98eX&7RC{YQ}!gSHDb)`h7+f9WDRjX&$ZmNq>kde$5p|L^J5ZZn*gee9gKG3 zVD`CX@W?Ukukn_qq6H^XX#|;Ps3FuBI4ex6>L}FvTot@f1(N6i0aO_yjCMj{na0(o zP^HVu_MM-(n-j;}Ttk*Ga&0zksG}?&a8>ZK{DcHa382c@#%L!C)*d8GSt|2~tu)pm zoIKWDH6;3wYrknv9VPmRtAdy4r%WPH6~H#e5lK|Ja%?5C7U3ka?y4ctA8_qA?Wv#?g#+5@8A5y1}E!oI`A78a&lheP296xjyD>F>R}(Twms@;N|)S z3H5*gs*DjvJGrXNMYcDKrAcSVi%@fOjZyR!uFa+mb(G}qA(kSNEs-?XQW68#}p1uxOxF^ND`0NWTxBvIw^u$9PK#C9&?-VYDH zm;Nf(e$$>hO7u0Z3SOeWCs}p~pvpL!(N3ZobCIn~gXbcf(PYkOHRbv`XNzfD9p(B4 zR|PNEuSlqQ0;n>28M}pz!dmkD=l<(+2#&rfLif_On})9D#YP%6NYIBrODmox2`2{L z>VI>Xru;KCqDuf(MxD{FDXO6MT~KNYI;3>}>iQR_^w5_Tsh!pUbbZ?+{fgfGPxW}D zKc;v8F1JTILht^6J>M{Qik6B|N5j$+6VuCYUY#gy*KfP^!xu;<@f*i{U15;pG>xB z_p%LlZ(Ossdm_^VjkL&vkETRay!^}gTf<0HBykoCpvo9vEDi2%uCs(bm*DEV2w$|_ zt0_RqO+&kEU{ASW1D{#qLd%cj-~G`r4f|Ktcc3bOK}NgmOjsIzX(>CCP0Ns-t+cD$ zw91AdZTsV4+V*SKHc%D7Afw&5Dz^Y(K>$_8X2x#e zCc6AK4(U*&u3IE@&tAK6?ake{*>)?pzuZc0>yW1Y=`cX^NVOswirZuPvU<;#N>j!DQ(SG2T+FmIzsO6Q-L$v<$VOsm&)WQ`4s4@l_ z?OKZqY>ufll(x|ryUHzGLVucqGN+=UGiU!WZTuf<-5LQ@86%8#ZNxoy+}g&A z-~Ht2?10YTNv%yh#6tX_^sJaC}-c+(q8Kf_E*ESS7Pl2RRL^a99etIoo(OV zfdaM0!eD*>dYJag)W+KcP-X03v}-ROq*fij!?t;d&e$;M+8e6%cZX@an_B(00IG~( zM!U9S{O&QYz21#$soQO4;L^^r#-+)QHbqNmttWPOuivm~{oQxoS^7*L=&oeafGO63 zTQ;rTxQ-R0{S=V6eCIpli{^X780sMt-xENUv4zpjP+SC0Sq&{ITf^8vom0i&b&2~{ zudT1ie>059elqr`0IG};Mmv-7y|u$?a@DtG1D3IuY1F@FZq9)npQ4XZ6FRhXvPqV? z;*;-lHkvlq@n`N2xGKzBXY-Y#P6ECqfGT4fqn(WSdV0btBL>DWQkq3-%Xu0jsD_|F z^53ZTl^##l?xv{g{^@kot}(JWG1(BbExFW%^tmeccq zn}6k#Wbz3Zy~rm`xmc5~c+My7`XjgWUBxX;p#N{1>yp0t4Yw3=x}{qjZt1JDT~hdG zF6mnG0XX^-m-I>2C9Te>(l<`1($swvvZh}W#GhWg{YUis|2s=c>;LilzxnuYm{@cz z&`MX0+={JTasE^aE1`^VKr@ zsz!I>`Y?;t?$Xn^M$8l1h$a|Q*=#1 zD}`!{dK#m&rmR2XY&JEhqpUyYs^Dd9CPBX-fGT4LV=Y-fXO-2w2y4n(DO6k55s%f% z32nyfFF31B73wJLFS#msVOvPj4+T(VG#KrKMeyZ}RaonkSySA>1#1g@8sm0YiT{qX z-_)ay68}9{1uteU#q<689cuZdc`xa>r>t%Z??Nj{s+!d)ABls z`Hx%`yqFy%V^#oF#tue1F>UA9nu411>u{o;#yG|NYAfqMaWX;LS}0GM)xCjAk; z|Nn8uCvBzo{|_J1q|tc)e@YbYC|*9}Z{hzRxA^}bzfpLnb2)2+-anVzrYL=?i!zEH z@jd7>=x=L&Wp`JX(D*X#RDB11V=KEPV;Mk|ZIis!lscw*g8Ip$TZ{CHR4MK%q6Rqk}*P;NFLiKnI{6Cqw{e zKOq2&0+f^Z2q?lebUvUN5d8!V7!A042+e@dPw)b*fOL}J-ghl(BeVgHCkSDnp`Q=} zq>}^hcRPmAF+oeu3qhqM3i&%mIe?r-Xk3o4T3 z#!-Yew9tmIt9Pjo_5#iQiv_ipP7!BSU}SAYzFk(fLs%jhoq%f^{QjtU)JRH=Yxu^} z-*i$MZu1a{f)$s$Mo@@_Td$mo7#f53$~&_#;*N&3ghl zt%nQ~jIVii7V6S@wMX81(G$3(#NWKT@aLPbk9&3#wIeh402;;ABrBRE6ksKJQWn`@y zk^G^hG62+SqtI*s6{|6T9m5?ubnphI-6-e}(hyCv;mchdWigR3VY1~yL9&E14-Z^7 z$Wt&5Eu`G$0~?X3;4I5ANK$Zi`7ayfOBgcMREi@N{SlJiAVUw*jZx)W3fUHF9EiEtHGn4#uD zgX;)EF>{)!-cQJBK`HD9`T+SX&Z($@R1#Bp1(8eQJj*f2BT=JOLmMz~LSLmOKecu2 z;NC^%4eJ;})(y)TLc)t7V+a{9tYZk-E-YgRi7rOaRNVdGZl!W7fV>=IEt~mEsyrY) zRO~W~G)T`evtnepi&`_-NQFvR#YAe4^D9RnH_6z_l`hf=#@p1b(mv~%boy*L6Y`Tx z7+kl5N?676(r1fUNDWd$EQ=cE<=9K(&9d31q2XCegkT3Cb`jit1m`}24+sPPlZ1Al z;S|9+txE{D(2tX#tB24I{6F^I1k8yl>*KDayHnMjq*9&Uo2EN}ECNDsU+E|)t`K(x zr6b}B*a2KX#EuIpZbSt^P>36DD8YRv?(0ZqbQWhLvpPGO)p_UD`Og2QZ&z}=tCEJi z&+~oH^S$pgKj})PZk_))B~+RM>q9-CiVU3RC{Jfrk~0%TLF11p#c~I)bAj)0qRbIchw2(yX-dt z`|0Z4+^b1N=ZO+KvGlWLiG2xQT=j#{58_{hzQ}%__&of%{CV^6Zww$oz$n%PXnK(KZ$)3{3P>n{NvEa*^d$*g+G!%N`4sm z(EKpB{z z@_ptyb8Tu(dUg7qz}>;SXxE23vv*`~@BTo3Z`WJ$TXHJ>X6B8|>w(vTuZCU;y==Y| zcroxo^4X59!DoU`XJ{9TEM2|(5!#*Nq2PnTguKzWVf)&Nt2^%s$HS}SJIy=H+cURj zS7vWXP!5UYipUKUV?Eczmq|;yFW(uBc1JG@E!cWV$AzorNL{gWqvynC#b$=ij-T0a z+Qe|rNwE`r$8MTB@yJx?jKg;x+jo`0IN?7QpfgA@LL1y#68WfcA!p$JjEqQ!S4G0;448In$u)tuQXh-GFE~t6d_i^IFdgtfjVO= zqg^G~wDXQLv$=M@*qrR{`F+2z0!N=$1TDBWWt3YLiV)=sKQk$qwtkN5u)(>FyTR60^1p#gtuwu9fh~r`C`KFp1<=ZrXb?O z(dVlKUARtVl-?y2Axb}iWsq~?W8Z#&O6Fq*v=QLg5CA~!B>JND8v=p<4W+I z%Ol8jp$M@OCXxK_NTANx#%Nawh+TLv|7Dw7&55Vpp(|ybcM>Xr zVLNEEe8q=!0zkt=g1(B-f)oQXjs6+NCSc+Wx)mCBGXgZkW(?a!80w>&X$OV_itiLU zuba?8$=r+pFbt4)5EMWKDu7C$3UC1$paa!F4d4bmfC2b`I-m(?1C*Tv6{r9zfhxcS zXn+n>12upfXabsn7N7$N02LB41OP5T1F8Wx-~kN41ZsggpaEzCnt>Le6=(z60U5am zRG0$qRpBe{1*#51?R2 z5D7yT5D@WVAmYV9#EXH57XuM51|nVzM7)s46AAG33;8(#5ijJ^1Vp@0X#_;P7>IZ= z5b;6}4*?M`bRGc_F9srBsI)WTjRZuz7>IZ=5bAG3i-Cw20}(FIZ=5bAG3i-Cw20}(IuJdh(I;>AG3i-Cw20}(GqE}(@~S1ve({S#p+2EtMd zgr!h3fUp$y34&0_X9BoC7n-v^6{d@gxT3-3;d&DnJ9O z0XN_Ud_XNw2PpK0H7bBAKm)1)H{b<)KrK)QGyqBmp#rD^G@u%A173nPhr~ql;dm`j z2Q&c6L_!5n2~+_tKm&B38mIx>04Bx^ObHv9IW#aSZD79Bz?`swsY7a=2$++Q-wwq zfVn;LCIaRK4KINCJ);)D+@OIeYC{DuC2nB8)xZq3Q3GH`+%N#lQX77t9>A2VQ8+)x zw8i|UfvIH!6VnFfiwzy925JD45~|Y;5d1(r&-~(!bI-miN zwh|Pe0;mEspc-%kUV@;l565ePI-miNw-Z#L0ziBMJxv4zInXmiKzI)|Mzptk4d4Y# z0CV>SV#KH-2?*b!{qPADK;nMU+im4hr&ZlmBK?z zqryW>vBE=4zrsUI&B8-W+rmRk>B2)y_rgQ0777osIw?HFYN+rKt1sbD3Bql9I{dW! zbaG2%i@7EBRP?F9Q_&|opYT1tbMw|mdmfqbaK}UG2V)NgAIv1;iBKZDDX}TMN#2y) z7};oUOg*sb{?Pr|4T%lm4f2NM`p9~7ed@mGeS!PZ>tgGI>oRNOYeQ?Z_a^QQ-z(pn zToYMiu1T$qt`5+=aO|GoJ(;_=-W9payek!t#sl&6s@SUFs?447J3};EoVX)=hkQr! z_Q>t#?WxMk#E^?Q|zYTO_>$(6`>W`8xuE%ZFZ+G1+UA*;;~RH+mq-C_sBiTYa`d1*QS<7mj{;bT9#NAUM4R~ zULCpGygIcsx-_sfy(G3IxFmB`{HoAZ*((!QhOd;bOkNSW!n`7NdGzwY<>|$-#lgjy zMe#+UMZSfpXfzs#rn_U^!S2ju@ykM&WfvqCgcryQlJg_;&H1T$(RqP+=}Tjm1~1KA z62ByLN%rEz#o>$Pi<1{cE}D2@=7RVIp$oEe6LZ6J<+;i8Bj=mvr{+ZG1m>jAi=7ud zFB6GJLXm7&qAT1bcO_>>W}CB9=SI&BoSQx;c24k|%&hpV(5&pt#LVzad1mtL$l2!E zsk5SI1rzcJipDv%CJS}pXd0OOD^VC#det>8=H6uDBFe5!Z zHa$2!b5i`I&`H@76DNjGlut~a5IMm-A$5H8_`vb$<6_4JkINhzKQ?r1c3NUuc$z#d zc}(OO^O)4p(W3)Lr>DlI2B&7G#HWO&WRFT56+TKnDtTn&Nb|^4C>jcc(w(u+U}t7> zd~#@V_K3t0;UnZDl7~kQHxEx87CkI*So+Y|p}|8lhr|yF9g;mbad7xx`QYS1k%P>G zQU^v43>=s~Aja|nMD~mC8`_s=14vHnnJ{CYj`6$3CdP)x%43szNA@=NPK}9<35-dP zj*SkE&WwtW3XRH+OpFYVlt(7_itJ_Xl^PKp5g3sk9vdDUo*5P&78;ff{C{P>KjJc7 zsj6sIpekJ1QL#%&DB<4y|L=PBu8IuJ|3A{(|Ho1!zW*O>(N?fq3dT1|oujQ523+_6 z%pQ;F(5OW36nTwMggBjuxf#DeziB z1};k(mG%ooh)N&Cd>qsza5$r#(wG|AmanwswmHj7^6=cL&WaDhzXzvzogfGosEnG| z3q^>UAIvldbqO5K=%o2``I;9t&n0*`ZvYB*#NU%G3aks3+NLxJl5mO2sCuJNgsA!< zr1TC6)EP%H+Ns_ywfDS{ue#;wmh~lhyLEcmJl?uwsrokw;&8FbsDHCigsA^vr2GdG zs57=R+Uf7mraMl+T5Wo<$=5-(>7`G1w+J$DS<0w%t5Aff^x>rOClaVL4rjDex=5Su zsJ8V`pb;*n_#oT#(ls9<2*L#_qvmZw5u)ZtFwH?-0*5m?Y3|UbJ8E9o{1?-_WH0A! zO6jT(6(r#j?Xl_|eK7^?LJ^|slS%0v5~wqdVzg7;p-pd^?oytodH)9wH55PV{ zOyy&m_kU-pPl?bz08@TsDjAyh|IUG?aw+8jIJ?1A{zdEmcP;iQx6{1;6^l&8Pk8{U zzUxySqIv(dTYbv@SpPpmmDZg%HT4VX|KD`775~rs|CZ{5dY2Td^+7yo)*Y1kF6j^| zg;&xZ*E`j2@3=!iC_=3Fqo~H;l0coYnbEG^vEj&u{CD{r%5-46r8qXU&7I)w6NYGqy3>sf$RRNAuOiOQER3)=ADP55kiNr}GFw z1TIP$b>2%TLezOG(;3tyu#M44=Yn1?dvc3;vUQTP&Lw-Zb-_|SdZZu&m!*tKj}nRy zl|Gu({YV0J#sH(8(io@g*UPo+F49t4Cps%W2+y`IS*qrv1wpt#Wz>9(P=u)Yv848U z5~wq_GTLd5xbA{@zueR8*t_MYIO|-pXY?!l(HKOI3TEAO)AEjB1Y;iV)R4o~aG$64=h@q;|phyY&=1 zdUgJ3&T5zJ+4+|&RquTSF}OHo)O&(ZgsArkr15toP-h&@Xs0*&vHiy1^DQsp;rXXJ z>ploC&%bD?%1;zz;WCv``JhmQsQh%&{5=WO8Cx0cl(%WS9ec64$G=!VreqK2mn&7{ zNrC`ekTPn#uTX@j@eES;BMHjQ|kYJf00jFME(B-C;OBdivRZ|4P^`Z|2wLse;noi z>o2MQf6*yc|DUh_=eL>rZx3qO=AGeK%T_Z}td>iDqVg|U>Qi-qPzk(J_PCx&p5Bpx z1BD{EfPANflc{dMBY`^OaK^rR=BM}SUF4nNs5zdje3AYS-WjEj#T_Kb!euI>@&^k= za4EU+r;+CONTANx%xI@P#$*=ej~e8LH67m3xf4ibBo8fl_R1lV&>=+(I-N{eD}g#= z8>5{;7zSCEZxH;Ws8QBQ_J-Lt%nqg1P-kpqv@;Fw_rAo37#_QLK~cl_ zDfVVjOO(3`T9^D(K;Ilz8Bv5B;W3)2_-ZVeokSiBnym)Rg zORSUZO=0I0u_aW*mJ7*>XC+W)Y+$sr#VdL9vT$9t2pe46c~kDw!n>zqRy-ho?DHRm z4*sqwIMdoh9Lef%VXG~ho&WS4S;X3l$j+A~P-kpmw6nHWs_j|VS92&9FA!&ob7weM zJ#Z7Shjt%T#O`@y@skp$Gd3~W*^O3%{JZz954$nn>{QSAoNN}7))mxY>9viE<^2ZE ztKV;@2zGM2%lN}Zul&3s@)r2)hi|x*3uqi*;faP~ z&^SQbI74}b;sCz8(yM%Vi=q7SE3eY=fm=D_UbnL0g&O6%kGK`@RJStYS2fDz&w7-H zYduPc`u}@JP33*`|GV8%>dRM0{fhek2cBy6{~Npi#iZ%`#Wiqq%T2JU(BlNPx%zut zp>%J({q5t0BE$+^NLBfa1nP_}jCK`@_t%{T6^d5CemI=B^aDjM?m=5#5TTpjnx7z8 z%dIb?peG7Nh=ML6DW8`>opC6mouCa;!vH@Bii^tI^P<8QJRL>6HCL>Subw2>&2=cF zw9|zmL}?e3s4q&O&N!6ONm?t1WqzCP?63TpEh_Ec+jU#NogrAxl_;aQVW9|7+{;PU z*CkMA9L8uTZj02?^GHEMkl$iE3tV{SU|RPg{%h5ojSrtJXuvfoqs*rWMTjzAMFKw~ zfjVOgqn*qHx3~7gn!LRoXcT!5+S`J0%>4HDRKZ$qeHjHkO(;SXbO}lMyaeiuLmBM^ zwQp~oMdj^nQDFz$-r7ogx?nfgp^Va=Arv7>yOczIQ37?wp^Q$_4&2^4OUs|yqS6k& zy|oqhOu=%lL>a|BODIAV_iB>$bqUlNhcViT>)hTt3!LBH78Q9g{%h5oO?!K`paIvU zj55y@iV$U9P6B^d0(Hg~Mmw3&-dYhhXic5dtyyOjd5snG-I8;yp~QiQs=l2iNWrBk zquS>PMTlx&OFI8h0(HirjCN|HF@B-nkBH)m!=ZC$6;ZvoGnYg6a|KbjNM+Q0wortq zdk-o8eF@YVhcY_pZbjPUe3(DWPMvaVZ^|ON@20o&d&p}|YzAk!{eA!KT5c-eP=Eic zS*CI$&HFEX)u%L4zu$kHPuWWI{x3XcD5p^T|IC{V@GkYB&JGvr1(zCBM6 zhznN6I+!CAA=bh5r2gj;s51^>w5tP*-r z3Pp(O-$=UuPy%(v4n`;Stwp(oFP>sv&)b9lE6=yCUvi6cksuBitBm?zEEFN?zk-zi znFQ*LBN*-UA0iFu`CtI=w`?!H-7i`XyZsbccT;jrTq4NCWh-M%Tq+bH*2K+J2cJuz z&Nzh8t|si-e&?QCuKg+6huh7cUub;_dd$wP&pbg8E>IaYpDz?4YJLl;{iOuzj2(=2 znme`q&bnJ2j-uM{w$~3*{RM(FT&gmvf0|#L$uF4(@-Q5>{aJf)~DD<5q@n;gKGY(_y6?)p870Rz^?*HfWeabQ#3pj0At@2kI z1Nh=gQ&~uB0M2;XRQ^t50KaTBl^$9HaMl&I%0Fog;76aE$`v#QF!Nbc`I^Q6eruY_ z4KxNY$5*RJGzKtl(UyyTL;L@?otf+ZvzuDgC5=CM7W*eQDxTVtyVa3(^oNdJi*=dI z(y?{1t^(MT_1K7@3uK}>9vF-t|v9WFd*xgt+0c>%s`vL58tV^p1 z*z8zW0PJ|IR{+@dSg!)G_pz=4*Z{fjKC5vAyCLgt09zvKUI6plRRBkQ#Qc1YIi z0Bn=2%bN(;D_K_oY?!QLi)0;JBv5z3karLiKm{s*N}vjG0UDqK)j$p420VZlFaRH50=0l2r~~SO2A~mW0_2?p z1yF$spc1Ge^xdZmM>IeOs(~874R`=AU;sYA1Zn|4PzTfl4L~Cx?;j?>==LsRn8QH{b!hfC2ab6Q~9JKpjvI zGysi&+(}RX6{r9zfhxcSXn+n>12upf@Bm)G0DOQ+=)2Ea9PtBnKt0d^Gy?Jrf&!>O z1yBi80WLrTbf6lj0o;HG@B#+l15BV6@B?)~JVSHn0cZr8fM%ctXa$AE#L?0 zfO?<-Xat&oW}pRV1%?1^z)+wakh=*ApaK;@C86&=t8l~xXn+n>12upf@Bm)G0DOQ6 z)B^kmH-2|_z36)}^+NQ8zzgZ;W6uYl&pa1@F7#aX*~GKqXM454n%ElN zDsN3b6M4pbCiQgm>A=(JEwL@ZEt#j{PlYHydg96Olk$_vCn8Unlqo&>c;NB$W71>E z&5_OK=G3FnM+1+hABjB@d?fR5{Nd2U*@qGjg&&e1N;s7h!VmP^AG|-aA-*BBA-g`YKD=IDpS&+}pLt(uU36VwU3zV7ZE$Vo-uS(t zd$Vg2Yr<>fHObYH)#mEdJ<)pt_oVNZ?oRH}ZvH(t2XD^Y6u&8SQ+7pSMR9tRT_3zYb6xzp&~@2ZA{LIxv1CuA$LvX68@)DgZF;%1Jb6vz8uOae zvgoqFvh>xltAkf(md2NcmS&eEmV}qcOOjVbt}?GmT^YSHaAo?6*cHJmGMC3M4_%&J zoLC%Q+_NaSD6=rWFtjimO+>>{IhyQ_ber9&%c7SBE=wiJucXCp#-KD?Ce{m7E!wY0gZY z9X&g6cKWQ?S;4b1XU5MAotZr&aYpzI`HbZ0k<-o7Q>R5w3!IidRXR0!N~CXB|8zJO z4u&%`;xj@sveOgO!_(#I$&(@{nJ1-AjGh=cF?~Ypgy0F8>u90XTRWnnSHUhe|A!0Qh1U)DH)6e&0uO`bYfs) zdO~bMa6)FE_&%Y1vf~ru!{g=g$#Ic!=D5_@=-9y6^xo3m$uW^J=9tvz=;*-c^r+aV z;Hb>V_{h-6>|Tkz!h6YkB}YU?m?Kidqr(Hk)5BuJg2OU_cpwzWb|gB&9X;*A_RP@u z(9qCqTcR!8CbuPrM246{QmxU}Kx?`s))H*VG{>7m&Do|zQ@BZPN;XCs&Bjziv?0)t zrnPR#x=5W_m-0vb0e`wSRvWC%m~k^?W_<}?*eBCc{fJ>2DR0yp@TNU6PtcQb$K4@! zwkA;%uIZ@`R%i6M9@4W~LJMoMmULNr{iiEqmBGqPMZ6+ZkyR6FSe4bJ5>ZSgB}e6e zoTk?0IM34Yzoq&A%F|^uHc~qcKh*cm|FZ*m=)uH#vS4rrLub~|jne>6;h9ASd5RCQ z?dCAg6~Y({ACuYRVIGpHcTvKXLJ?d*9?P(b6#i5Kb;esL?_7$ z&nzN&>Emj==#t0Qt`ZdC3YAgxB|;IR=y8(!dlINKj%2hGeW*0F=k)^7E$`*lI|<+a z>>}b1#^3o3lq~;JK^v}B8RfrPC_0#c_uyoydsj9 z?(Y~!9z@v4GC>QjO&R6BMkqp*`yLWHErB}Y2u3@(F?sT0f!vn==4>y`*K_9|nI31gCc1dB)ai=ZntPmhSgxZU!+)euJO|*QShe-zXFz z%Ds++PD`N9ID*km?qcn{v*d;Egrc$!#@7ca{0c!8u2LC=zey-U6#hPv{4)vE8AmWW z3GdX-I}2a%q@Bjwj1N=Z8P!BW!jX)F70t^9^t%M4o z5~u<+pc-%kUcd*`0(C$G&VZZ;+DTA=3ZM$mfNH=EcmW?!3)BG(KocNK=g_SIm4FM-ff~RA7=Q`*fqI}3Xa2s8t&fYL#z0IC2Ds0Q4C7w`eKKt0d|v;t};p$gCeH(&rJ z;0Nk~MxYr`W)LcXDnJ9O0XN_Ud_XNw2Q&apKntLB6DoizKm)1)H{b<)KrK)QGyqLN z3m~r|s6Zv)0(77T@Bjv20)C(#Xat&pRzTTGr~s+}4X6g(fEVxqwLl%v05kzDKr0|` zCn$glAR|0^CjlAZ$vX+i2v6QgKt^~K8R5x03CIXf-bp}4coiAp$wdjs2(Ka|yo!wQ zDl)>W$Ox|@BfN@?@G3IGtH=niA|t$tjPNQl!mG##uOcJ7ij43oGQz9K2(Ka|ys81! zfE(}vKA;w;0~Fu6^bMd2(12>d4R`?`fQ;}eGQz7305Zap6B3XSo}7??jPT@y1Z0FK zCnO*Tyowy~DssT9%0xm1Pzh84Esl48R2ZKs}&z6DoizKm)1)H{b<) zKrK)Q$g2n{PzksI9jGBt3+=(b4FI7{svoEa5X+<@jEP!k0>YS7gfXcIV^R^uq#}$- zMHrKcFeYlc2?%3S5y7M)cu7Uvl8R6z@+SfUl*pe52umV=A|M!v{E2`NB=RQ$0*}a_ z*c~F^NJXrXiZCM;5k@M4id4iCsR$)f5k;gTfJjB`kczM&6%j)!f`wGX38@GXQV|`b zA}~m;1`rsex&beMFd%YC0)l_k1^^*Hsv^y%!huSl3eW*Jfi(2u-#(xgr~?`R1niJ& z6Dj~i=#Xm@ssT6P1$+QvaLBa@4S?K1P=QLo1?WHx-~kN41pGif&!3Ag|q zr~y2H0U#JfMI4HX5EQyY#Gj}LJyGRu0s>A{#G0rGGf@#)q9Uk7^#BHdP!biPB;@S` zKTr=e0*DqsEFuL5zL_?jzdKV2Q|(F1Z=1X*iaF$K}|9NVHzqTG*kp|00|Xg5#-zighh~t z6A%`mA|is^oPan86(JC62Y^Ti6;Tb;oDvYtKpG;RK}9@+ickg>0Sqc)7pN^IAZ$TJ zu!4%{1ad|KA`!?V35Y}>wjUXZOuNDcqaUe{7mxc$kXQ2sV&hhfi3B$VowF1$~+l=vg670 z6R{_PPh=jCKOTBK`&iyhUE2;>&@#oT^GJizAhPy#LQT#C)yL}NnabgHh67jd3w! z;=tncqF9mn{jLS(g4F!z{J{M5yx6?pyv(KXOGB4tFG*YyzC^wxd2!@o^WxM+(Tf5X zr7w(K7`!lZLHvTy1=+cYx#79;+~oP4=V#|6=7i_SbCTyp&NI(TMWT^FB;6J33U*~? z$7hFTXU|QX8$MS)H+fFv9P^yitmv%3tn|#-%;3z-*{ja(C}EC2c53j{%qj6xLZ@U; zPMjP*Sw1-#j)cu{YDRQMU`Bd+Yber)L2?6kzR@HBZ^@|egm<}s-)9P&5<>r8{Gt!OqO&_~g*!>=B70!biwQBoB`qZXTXGEP7bru=Js^LxYEA z4v8NUIwX5=;^6SX^1;c2A_tiVr4Ec97&tI}K0m4v3}zC&&|$`$YCJ_eqV9jt`7akBf~9j?0XVj}48@ z?w!~>ytllEbN+HivOUsnwx@G24)62sg+L$@)mWS)Zzl)&=U){+K`L&(y|iL$z5mVTMiFO!^`| z)0Z-$M!-mWW8R=Q6y{xGr%hqn*T9=JRBM#26 zQTV%sB1GXIA;~|KK%H?2qn+?rH@>-`QOPwZ&hy~>oFZbE?&JJ|B@2CzpaNH=j6$y# ziV%faHf9Ic9MDo&oJpZC4i@sJ+gez1=(bow@h@wA6a(_<(b;c2l zcA{g(yMG*CzU{?)J^$Py;t$5(^DkSn{PzjkaIMNH|9YVaQT``M_zxveXB@(4C%;{L z?mXd|YYWOa&&@Abvd|j@6}T#86#9Ol2vO*#NaD{VP-pC5v=iE?J$Dw{`aND$@WJ@^ zpe27m(1Yu<$C7XATYkS$C_;L~X+EnhLx&IqnrV^m_|E(AJl$U7k|H1Q3WiqY* z-}h~wvV+$DznAbSbFltj^0D>*pHv1$)(I&kc%gSw zwM{}T@LJj9il#g64Zu$bMTiysG@1B43Dg-!Fxpjgv3H1bWf%4bidOhwp0RvCD!FNU zP|${JRYv(A5{eMzPm=I!B~WKwq8^a*nDP);xI+!^$`&P&Ee{b6g#NZxam z=i^S9k{&K%)HX6_g9Pe~LmBOi!stm)fl=_2;)YpgIT&Z>Lr&&BQpCLH$gmX>s51^> zv@;Ly{fi3B>HhjM-eom>0;59tqSLn;GqlK}t(2O(I5z9CO?Co#0@CV|Kg8iroEcbl(q1pw3v& zXm|G>$Q-j~bcMeKT=*#+tn*vx2W z7i#62e7o?3+h$CIZMhTd?HkyyI%c1oFM^G2PZY83EwX2&1nP`!jCQu=C-R##8<{!# z(hUy$^av;A+sHn$DzSv5gijW+$@FaT$^)S$jgx$X7 zWB7XB&#JsO;M=DKTexjy{1NqxPz3ixzKHZQ5^A*s>WuY_c53_rN-^;zr zym9Y3`qzVA#XHSA$=gEz*1em(>*$PXI<}ntu69k4Wu;b@B}B0v_-Nms{u$>=qk7Nk zJp)m&`{aEC5wH`iZ@4F(E44n}cL7A+4i(Gmy%HjD^RHyk-+5O;_-=b)*@)g9nOAlV z{XNPm+q(&uVJ$#vWqqiHC)%zU;Q;*C0 z4g#siTi-$Scwec7LLrE}Bk!9CAP-pIL=1PUSQ>)3N92760o;38-$6WLv#1xsxanYb zzISnh@llu@Y%?hmpi?%I`&l)D*ze|U^3HYrK0+{fYvI|5jBj2>RSHiYSYQOoPt3o4 z`a5XdKH}8JiY6maeZRc#AV__G>pO_d?<=)XUO@?8Anz&d)e*t@`G;-HN4)-Fd8Qy%|8UC`1pALKGy$>x`Nkv8KhJn9PzYELGS(N2 zuqhks3<|D9f9G8Zixl=MEE{VS@}6Wo#U9O;j99BN z#OBtpW}~2>LQ$~bqpeUztoO)&WU?p!Tp8=ecp7Lha#Lgo8Kay?X|JVi6!d(QElA!n^xDqKNO_FYhG8 zoCgY3K*;&%yi*V`-tXZ<#Q3Kkx|4=~j z5nO-?=(`9_z)+x0IzjRWfJz^s8jxuzg5Lyu9n&R$eJ7y}kY^BTdI(jk2wtEb@a-fF z0V;M8swU2m{LM26)m?-kz_3k(mWg4>KLXHa5L&hpIskJ!p%Lf+)E$K39VbhEqm!U? z5j3D4XazdDXGpF|-j%&Zt35L$(@$lXt$@6h&;Sep>UR*@0Cgw9ODi$(UDg#@M{oL- z-p%|Gq@@{c^fUbbmsBd7q!T~Qd=mUP^HKbx&_~%16CZ{@ls`;<5cwebe&GG|d$IR| z?`7VNzZ-ft`%dDW@H_H5$+shKn{TJyioO+iE1im^f~m~*`1a8D?3;- zVZM=iJ^Fg!_4I48*MhHQUX8yRdNun>;+60#@+--gBQKjT2VU~Al{2wz-OmJ`Nk1Lj z5`UtL?PM8w*nBwkQ1qcpBAy5(vYR3s&5fxCq7S4uWY)*mht_A-Mc2yrCf7vPm}`>v zr0$Bx(|2a>$lRX1EqQC`mh?@D6`32d*JrPzTk8og&n(Ma9bXz>61ggJrFn&Ud1hfI z8t;x@7FiIPZ_YC>OUnkeH;0Hje$t8D>z#|*F49Z6+Sz1R`iV6>9Nzor$$bR zoSdB=J1I%)D^kbBk4;QV9Fv)vogz<>k4lF!v{E8^xO|v-sCh_=_B%`;5ZFJsUvS?{ zFiWc&Qsd*}GJ9u7hel;-XF_>Ia#$*m>M+{_Lj!H;)(q`5$afbE)@SPCb)mXsZKT$$ zO_>2-&7xy|x1@PPrLrY;doA7wb>8?_q0u?Q<+c)xN;y_S*Nc8dduN zwzt=Qh()Q|kFdeL_9fP)YCpyn_u5aeL{s{IA4 zTeV#tA~z$8wXWJ<4e)PR@~Zva1pk4Rui8KT;J>f{R{Odh{5RIYYX8#+{s+rpwf~i+ z*^>5+0)DH4|Ha~1SG!b+KV+j;SzSS+hmR)bYFpbIN!HO&Lk7R?77IV1o)aV%e?MR0%d?^{v+8 z0$Z^NR~w>(ZCHz|4Xpv&u_RaP@PGlV%+-b&;BYL^)kc`$UbWyzKRBum99<8NX#n?b z1jl0Wt~O2q$E)Bz72pIc<<%xu5xE&bEbP@LY2dy(xL-B6e+_tm8$1xJeYJzU;K2rX zhz~pzYk#%FYQe*?1Xw$w4xEgYz*=Vm7-|HMlskz>VO_8`MFpo~d9ZeLC3p;032W0_ z;ISHboDLpe4W3W~p6CWo@_^H^eps7f5V;v)tR~h@Ho;S{s8~DI51v*Bo?Z{0fhES; znT_CC@(kkH3OExBjjjYY}fEQpL%VQgSRQ*?N}eJ-BAJFiDlB-swyHkBaTJW+FcrWH`Y#T_f&(cv4mP% z;|A}=N@{Jb7hH!0)!KbNa6LLR+6MH%wENM))gGt=H=;ACZE64$=u>MCVv~ODA!!rw zVHtcx0UuSt&FE=rk5z(?SAkEsz$Z2EDIMHW4L)51KH~HWsrH%-zK;Hy_J#_+SpjaZ1XJkhX>Yl}x3Roidq)S~ zMWcAcKL~ceJ!v@-SrR~J; z$>8S-_=O67zXJS0CHTWC@JBB2OAY+74*sMX{AmsNGdK8i54h6{W(@EbKJb?&_^Vp* z*M9Ifb>MI7!LJ&?-!+22$KrDB4_IBU{SnK{wLi%_h<{eVzo_7@3L-ZnTZuz|#aeUi zZ!Ylf8u$+#{AV@zuNv@cH~4Q4_&;9oKL+@}KJXh8{I(YSub=4Zkm~SzZ2yJr$rA>)17;3iKf%K(8Gg zCf2rVwa5&h`H>PptHVNft=D?LhbCc(J-s-<{jkWMUL4>7SY%Hx4)7qX zwWk*ccnA^)(2D~+45244Zk*{lE}>nBdvgTGM4mf zry!w#b}BLoXs2O)zjk^Jcm|gFYiDAezjhYV3TS6zxxY5k2hKuf0qq>D{nyS#ZUJpJ zk_%{E$S$Bo8o=|AUqG9K1OwXn$S|PIMT!CK0_+o@U5F$D+C|tdK)ZM-cnR_hXqRH| z0Bv3XoIea)FdV#0?jm+8L~ce@#i4~rJD@G91Q#RWfOfeHyaFi)v@4NwK)VV_2ec)~ zI-o5@+5zoq54a482efMpa5+*BXxAe5fYwtB#*lqLyRHtr9{C5f8<2oNyAc@(v=vA} zpxuNV1lr9=LZID(ECkw0q#@95MIHj}HY6g@Zbv2p?GCw{c&7rcQiS>v1lnpOB+%9%BY}2rHMq70T;~Sw^MLEU;08AR*Fpd3SSxLMv-8c&8?iS6)Gv#? zF2A05EkwPt*sEKqN0xm#{&Mi;^h?o~%$JfchF{FS5Pu;^xeB7Rw?Xo`Fl8!;)6NFz zZP9J!wq!C)nF``tgIm+jL@7@}=hGR=Q4rXYdMfgi{8Zw}(32V3&mchg2_lcnk0%}r zJ(k%V+Z>?$1d&JOM-z{PC_6#y;Q;mTB9xmT@!$^1OJLF-2H{Ov%1RKV9Soumm=7fH z57Yhy@eRQZ>Ge_Cy&!pC_`dAAIPG1KUK?F&u1(U;1zFm;Ah@QBb}dNU6S^mJcZ~Kd zNKq~V`K|=*Sddv2TNPN9qWucwI}>+=sCO88b}2A#N>cuTEbUPcyfIDL2Ta85=Nl2?bX&Qi{S;L`Mx=n|7M4ur4D(w+oC$~O?b!lWGu!jx?wzBowx5kwc6 zi;@e&lx-j$4Mx-5Qg`CA&}A9QGZ3JC2qN?4`H6WU+Jzu?X@GJJL}(9!#KobDGZ)2Z z2ZGdvkqhMu6SV(8W^Qb5U~cOC$oZ@01m~nFw}5$GG7^qtDYHPZD?K|p+nk-GT?ew1 zSs-{$n)VzpDX&0yX7=p(*+JTIAbOU0R`Sd+}AUiHj`v#;bPk=c#NxKGQ$Hd13 z$D}DwfH^ujDm*GnSptG1yQm+Y7!ewg86Knj0I6Y-Ve+s9We3P~#5w{UDcUC>OW6T} zv`av=&7|A_VcH`g-WsIL08!c@AlbZ=b_WPFr6?zW+?Z$xHDu~z^#R%$AW|pSCHx`U z7a&#}p#FP=b_GcILcWXgKYo*p1c42?4Kz9|JmO8f5iVccjn^% zS=G9~X$j8(zT+WApdF9?woJhEbsgEgpO>ka07Q7A$T*7$FA27BTgxcl%R&*NeBUSG)=Qwy*vRN4 z-?fFYRyOkSD4#v@J?kPi0=^Dit3 zuVC#|e*5=^U=g>ljH10M6d{WCW0Gr~1nP{9jCP_8(Eiy7$J;-9@k;VLw12kpZ5M3g zww6)8lu(2y-%m)m^%AHvHZnTNC$xVy^6@9zUcM6Io2`r3w1002)^TggDB#;d5u$)U zCFv3ps57=Q+6idW{@I9_A9HFiWJ!KlRLXY*JGtFul=5An2vN$NB;vCYs5AN*?W9Ee zcW3TZvXn)H5BLhnePs6&#?}X|)dbe!0a{6br#a6RJ6P+RTWNvAv-8`=_XKOX^<@)?}RkoE(?ZmvTarTtJSLX`FwB&k?*Hi%eai6^_aA=BQ2tEu{{LKQD0kDE|3`l3RgR>6|IfbJ ztNe@B{5SvBqr5=-{(t!{#s1UU|3^l6lp|^F|Jm2m=d|{}`4{v##s7b~ojynWf4588 z=Rbci|4jY=$IgrjOE6cQO~qcgsA85NXe%pP-kppbkcKGPEXbXFu?|Fc&v~2z&ovrl-kaGS1^~G zUq(g0Clnzn`g_uHn*{2Nt&DbxqB+0M@=(j-0afk$iM;2YYL!%~wx0`zb0Ny8?H583 zqPBlx-U{jxSkGvuEf!g>%x}YOMz30p!Pt@$?FdTjnlcKVj&wfPq+RpFlq=5sm9sPIpPB1DD%M%q3lfjVP7qn*P2+E$xE zom@L$Kb%v7$MQ>*s^!lFL%HE))bi&-5u%oVCl$9zpw8ILXs6|XZL5u**6&n%O-u69 z!K%7bFqunGMpZLH5u&R9AU(HApw8IL=%i}Dw$(;e>yforwFFPizf7s#`U}BmE3R5_Bu1optuLSeC9J{ITKF?Gt z6TUT+PpJR@gIR{MnAZKr4mFgaG!C%;eO~3e)c^n9*M`zfd;eX1hM_dkIKW;97|L7J z|NqfFUgZkv|6g;rp|nu`zp;PyDj!h)|HnJL%2nw9_qe1#kMhWWq5l7x-uVCg`G2W` z{vZ3NpbC3?%)b`Q6KnV1RIe{epw3v&Xji*v*H`D>oHXWX-@oG@+Px`lpBB3TQC3u` z56y1`o4E$NS)~KX`dgt0QP%$vIzW@ zU_Do(i~|2oC_)tYKP2s|5~wpaGdc;J;C^eh5(5gnbl?r)OPedUk=H7+R3HAmU_aNR zj1vDrC_^S$A zBDY;Zw|b=n>WqzycDIeOG1pT`kZudD{kI^k81u2b`qB4d%P4I5&tDv$Sp3Th+hju zh$7NTBZ?6Obw)p0>0GyvO6q&{VJe>yZ|0hX{)|~gi zF6#f^Hq)B_=kfn@`OWhG_MrMGMiJG=A7`8Dvp(Jf-?uJeTAg<74v0etnmc+hAOPPF^_o0`^OKOx{m` zZ{#AT`N^mUXcr!s2DUQVnFcReVZEP=m}j+=b|#keezr=nGg2vHWCIztK>~F~Kck(I zd3{b4J>S0W=A+)`Up{Z~IKG*4!F!;D3dEOl!KKz^^6T$gRWOa4>g@gVsUJFzwhPZS zoqb;2gK^Ue2}R*p@4#@yZWXaex>#B&&6SkCtFwRf79kAIRtiP%@9+n#k*elF3Dg-I z8SN?v518PEHkHIZut-IfY@z+rgb(R?>W(ao%-`L{5Z7Suk=#`Z9wl9{j9cnlKi#x{ z+CuuD_$XD<;8mr>ih)GEvk=un8KQbaNVkm=s53S*+Np=`(2a%7t*wIG)g4tV$;@Vf_g7tG5IwlU9Lz~*O+N3e)n z=&TxlbVcvWHRM7o>lKO+Me88B)=8kw*vM!n8d_OeHOhYx=8UubHRvo}$$n?MYRV97 zmoM(XA0JFYs)BLtx$w0;4qRd zA%Qw$E2Eu&Ha!v>5z+iv8rXI1O7cVNGB#5B1v|Ojdn~1|uXkQ26d_8v7m4_w1nP{< zjCNAuJ#usIQSM&6@cfG}xWIk{JpTl|jTbNM|1SRV1J%k^)c;>~yH^=c{r~BI^eBI% ze!uTy>hDwh|BuH|9RIOZ%H7kv%7kfE%4wTD%3mq||4#bf6Q_BVW2pcCE1Lh;pYtdq zPVp+oZlm!6>id7&<5kvU{(q}3eLZ9B8(HfA-!RMS|MU3&%NF-b@zhZ`?~~UQ&z{|D z60>DY!B2vEL1r$yb4_;BFYAR;N57v0s)YZi(okEyKL{Fx62yueNmclm1nP`!jCK`? zxyQS#HaWkpY+L61lWZ!qq{pH}NgD-&xd7#pv`HvIlynS<`Md<`jDAKtN%7l&Rutkj zN6`lK6JS6gb066?E4Cdyn^|%clh?K|-?f=^{I*%JmRs+v=b(N!vUHzAAw_ zVAV1_x2mW;+Y(;Fx8QwpFm3>rh5%hX_T8(vBrjUzR|fv60b9T3S(< z^Hu(uvhi2`ak+e!U$0cZZ4)f#N|aIDp+XU&xZ_CHHziPKY-O|)7r!@XMWN-l+~NTR z&iO7s#ZKhG`!By@sWP_<8gNa@D07EUgedbqB=Cz8s590x+R5A-S!cDkHskcUhQWSt zd3V}eVF?B9!DfkHK(Lu>P)1pY2}OvqP9Q;Fmq4AdnbA(x-pD%3d-0C3k=AN=?d2W3 z=jIA5)o+Ij)^jz=DDViO2vOjPB<-sbs53S*ItfgXbveJ~PpOT-z2RQ02JD)K!TPUN zWT_JGCD_mPD5Jz9g(5_WgCuTB0(HhVMmvdnBkL?5wrnn;4KAlITLqUY_9#IKu1p!l zrp-Lr|M9_JQS5z5<`*SUXRK$m6T4qKY}2vMwZpqHHsSCCtzeX=gFRC=?eG}EX0AaQ zW!+mSLX>qs67+Qm)ES!@?PMLW9k!9yYKQIR-Mx0Wn7|!;pyAuGg7sXDq5@BuUZEWQ zXG8fV_5c5Jf}z|-^Z(a9=~LQi9H710r@Th<|8IO{C^KpP|H5MorGn!BrK5ey{nYn= z=wUkZ}CH243nj8|D5s8SyG8Oo6zbY4e=RJHR$?_a6^zwn&?{eL#`RML>> zIKe!za`&fdeN_T=#%4yR%I)_Ku&G?@9bjL%yZa6(R=s3p@7&&a!G5ks(dsQ-;(df7 zM2Qa|aZ?hgGqy3>No@NLu#vg&ceuUOgMW_rJD_y2CkRS#Wy&b_M4<>#?1M?>rzB8k zY-F?(8(no;8E*X!wjKY-HP85X(7$J_xF~$R)c0vnFq9i!MlB}^MTlA+LMm>PK%KFb z(N0TrA8BPc|M6l8X8Y5{I>k;?2dCXVRreK4<`R@q)%}DbL{$$ZJ-14r&e+Q6q$;gm zv^@4pQbqMYiY_aQL4A@FBr{5D5I_i2t|mx9!843Ab~n#JENVh6kyRq zE5i%Dm0LZawrFTe)3+qAbZvtrgJIEsO}L$5u&;w()A??)ENVecIq}u%{`Bbo@?1XV4GlhuXW-cd9Zbv zQgxmzh`>cDqt2Z|5u(mVk-|?)pw8ILXs7dlZLUqn!D@5uI}Ihaxuy3ILV~&6{5@8* zlXvL9IZ`M>RCEey`J4pmjBSi|irTihSJh8;u{{9a{>H0x(HOwYSw7`!>id85ilN*` zF#w5mhH?ar0ZjketNfAr{(t(Xp{%6&|JA1%EdGD;eunZBivR!HU0!7sjRCAk_>|!k z12A0jDbhqm`jb|-{%@6C()4rlI{Ld#m7d#v3^U2MbyhADYj5IKO5w`WQY(~qcN$Ah zAE&IgkLRVOb#0#|8CLSz%C6Z`ZC;XIG25|DpO4JTGLCFpqpS?hD*frNraYd7dF+w5 zYiQoLYUuBF>syUGyCnC3xmYW@B2u7nXQaTc0nenLZ4Sk6FaHj3p8bdrD5EXhU5Q~Qz(Be$SCulf}4^1jcI zM{r19CDci?r8cV)sypd{5i72i4tC^y2U+6+)_0KU&{LRI8d(hM^1e|)r8Kb=?$%wp z=~(@6WP9zqxhfnA_xqII%tDI2T70^(rT706O!B;VOzF}B@vRW z=0c7o%9brrfQqXu11_>HTe9FTSHivRu3&qe$ASQpUiR{>d!>V^`L< zGZU>Ps%rr*niiSd0z^!zwEz$9*4ASkXwo{}G_k&QVtm88)+xBD5gnxT4!b&N3--DC zXfsbPD@Hh+qpvbg;rbi5mOYBKHBZ({^ZM&jGE&K6wbEPILnp6VqG|QP2I+oXuoza< zU)wL+s4k%vE63oN_0MFO{7e{wGdy|SE}B#yT!8M^1&5J6ol^&gVImvaijCfYoEXbl zpulTyIn~H0eEpk`nI6!ipNOGU{RgPYFLS*+@mdh^a?R3{9;YptrER&0R+F8Wje+o@ z4X@JhNtKKBL?_-DDlgC`&(iQn173P~4?Ca!KR|Dz$%$2UppuQPL!{7KZ6KNE)o&nS zVA7^Gv4>9HLQa}izlHpCzita*u)nbWP0T)~a`QqoaQUQNS6xvXs_8&o8b2en-eA^d z8w{h~`W5yHuis>0JbA4JTd9q?TeM&|&8x31Ke@I>nk`Sx$3c_ocm6)QU$^sj(HpR> z>F0#5L6z%q(w@7=I%&_{bYV9=jlJ0$d^es&qGzc^-Sl&XZSp#rJ(U;hX!hpL4bwV2 zlh@H~Ip^ecG+P8Co!VTrkA=0Jn10`fF;457Dh4mD+bdxxRodO_9~Gj>_1h0aq1Lrl z46aJAXxgLDKA`owF{Wz$P85Ts*6l-8?N-Ut*E&*O!>?M(SPz)%R8jPgZN3 z5-rtam+zw8Kz(kt2MEJAaw6WR-1rdg6vBvr?HBQpy6o;R#fj+V0Uguo9mWYfrn3r+=Kce=y5h1SKfyx}?xKk__9kHgPT&JQrwINu5k0vYkLzPc12%f= zJwT90t4$f2P;g+_$tnZx>ugeL(hcz zcGKi8Xa9O?5VcPe*xHrPn8>!edJp@Dm@5D1!9fa3#2ei#S8^i32u%$06j|5`T)+>a zrwD-(40Hea3*Y}|r9aL7Y5Y&iKg#_m@gx36`TrjKuciNz`s3ms@qd*6L-h~kKP(he z#o`Y#KZyOH^!@DjIwC0<*)Ex;XlgKNRzpDWADV@j=z=5C0`$)(IeHD`;T)k zBQ4{8V#~=G1f>7j~s~DtE}Y6}D%$<+kQ-NvWCP%us>GQ!L$3+LEIY6!RO)*Jswp*6|5> zP+n75RirTy^D9!zQ_JGlCay^=<*$~nlCLaXk-wb3Ouj_DXz&95g8cboONxt1G+tqO zVeXv#g2Mdl*@=0Hxyqc_?AWYQU%9ue#G*>icvre3){zSh1~^~dt9Ztxv@_<++Hzn1doS!kp^7PSf+fQ=To;P9e6=b_Qq6YELrL^N>q* zRo9|uW4hPqR-sS#8p`$8IVds}W~+3kJm1?Q;l}g5ty7*+3qJFluhoU1h0?~Hm+4la z&v^wU`~e3=rkB|&XZ&{K;mUdS7JYQ$%c9DxR_D%V&|)i3Fw@q$TvtV{%56+>g>Du4 z6jxGyCpaiFgUnVb;wq4%wQnb;ND^&y>NIE6GS4i}mAcAmm2YF7*XdTF&+|G;@~a#a znL*}Mc~-yqWv{{Jy~msFypbQNX!DF;PnC$m+e zxVEP5o8MZETYe6xEz&C48MV~f)66v6HM)vxL9{X3LES3!*$z^wA8}A*`kAe=#dW~d zYrrb6%NF1GYBO8qIph84%zuQD&{b5ccpI}^t6POW%LJwPF$YCvnAs{zeE(Q?4VV^L z%T}r_&??gzwNdR!X4*p6>8h+n(8g5P>sFypbuHz2f`cM6%$zFK>NQ}s*JF!TTE9T6 zRAz`((xn8fUv=%}ebKRg@g+AAHl;~$16qylbt6cHjZrwFt^>uF9V(S-bmG6vN zZT%C?G~tc9>T7YdG2u((T@_%s&e?iy(|Ll)l!t-?f|0j!G!XRA(uyU zu`O$#ky~%i8NEVgwneF8)l253NVT@RXr1Z|UM2NUGxaNls#eYQCS9eq5ZajQ&AL_SbKOjde#SwO8DX}{wdH=j zMYd?M^})1hzdrM`XG6N`YjLzO;bGk>^a_MP?_nRl+zPp-PM0U8R1pT~}7E z>{D;MGwNyOR^2MJ?V!DZZl@sjb5LXkn62W#2ojsCaj+eD%Sg1jEo0FZXc5hAx^ipv zXk#=xbgR%uvx7o;oP#3M$7~gigL9-uw3gCh*UZ`qo7Xay%4e{;P@2?a}2nR)Gh}kM8H|I{L>RZqhQPn;ow2Z5^$c!V~sjH7xzcxm; zOScMrWOqgj2xn9Of9rQSg)$xY&-ut9 ze3Op*e`0eAS-STB2g@D8?R5PA@nd#j4ITf#`5l|^&wpVPo|$bHo_NG9%$r4H{{2`I zzDvjczxR)lu$`{|PbDP5MdtuI`>Fr`6FfIG@aA9s3myMoKU{bGpZ*CeTlL6nk1ld; z6SQ%w?$xbAi$;6H9;Ge$6bD6S2eZ{yZT@m-wPkB9eTuDHztD_d4*PVq(rVep;P&fQ zp${%ak-f-4kr`mN3Jx!aJFEK<>X2lLcPVYI?meniXC&;IW}Mrdx=Lx4Y-4VB=~ki7 zZ4V{(3I|1I2eVafXmAfs!fsyjxd6t-@{0@E+YN^cn7@ z^j_ki$P6)CWr)v67|sEEOs#dbdIzh`Ka=)%2A=@#)m2TaY8%tLPqzwvdiyB1*ElFL zyO^!g^Km}b^=u`*T6<}oVEr;POR@eDGj4|mbk)?V-Nq#E*R4XIe}YyOR=oje{byi`go@R_(BL zg0)sP(-i9;G2?ca)>Tuhb{mt-=vJXm@_x#2go7e8$V8HRXu9qn8)|7e?GN{iB+)={ z_PBD=C^i(UJ8Lv)HocCkXFRLRN45QF-3ge_ADpI~4^Rmo z9QKY{JhiW_8b2G;yMBD0e@RaCobQPp1N zEu*R}qH9sL8Iz*YPp)rSkLv28)vb+jJ*HcQKCTBTsG}SdnLW%_apCNJW&F#D9Yn2u zEhC%!EtD>{$unmh-Q&7?Y4vPlbcc1T&`0+Wg?5O8A~Vcv6&=24#%aq*JEdkHm2?Z} z;;Ot#w+>ATYVt(Z!nDGk>EDM}I|PM}|Cb-3e*5Y8zvKH3;n(Q+{~r!JgeU3vfBg6C z!raGg!nf$y|IhDo3HQ-=|6`vyh0Eyo{~PwZgny#%{zKIF|JUjG|BpQ`Aw|dkuOytp zMRfeXb=XP2|EF^X`!9R&r*!DGoF>J*!}wsW0)QjFf7>Ss;2sjHD4(bY$*UmGJks#}FVvPUSa zqZ|~O5$05p?XN{v+mTEWS^Yw~S4RD;Ns%?qsNV-arK^)x$2P`xOt%VsY=3r9GpogI1?D#`LUi75bPSqks-`P-I4!tzv4qPn#mD z+K#IsuKHP%T36-mt65~v>FT4^uZ@vCuUmyavd1Z`qZ|~O5$05pHQlF85m{~j)DT(y ztVxkI&Zuu`FX-x|)v=ASy{KD-KDNUY*wY*onF_O2Y*X&jrigCxPOBk4{p>S{@VKsi zT7BCX;Y+$z=p%fR!rR3`kr`yRiV#2b!37l6T~_65#+Dz+E3@e>Ks$D?Oo-Nh2VU2r zK7V^fojeZlj*EVRC|`n+0**0U!A7R&r@k1 z=Ag)oFk6)wJ8?Shm{|A3f!nm@M!fgpavQXfiN{Zz<*81oohYiW!)w#j;YBL_D;yM= zoy=BsKzpI1^ocUCIyAjXsBw|Hk2w=F*>yzP&Y-Ryc*@G;y1IPvx~?u--P*V-7}Kpn zYjxVO$Z-nlEe?vz9%ie!aFkBNJ5E%0Vw2AxGHi4#)-*P4W|Qb9&#I3vr>mP**EYuY zhHe%5_+Dc1L6L(!%rlCQz2P>y2y1f6+G0)P(`Gh_Z}P1A_}Pa%JKh?|Hn`7|5xh&?|IsRv> zPpe#a<|cO2eDWr4X}Ve{3*8Z|Km;~m2M*u_E+7FnkbwvIKmZ8igb|p571)3SxPTjY zfDZ%!cbX7@5txA$*nk7LfE###4+!p?=@GyTtiT2wzy;jE1AHI=geYMIW?%(2-~cY* z1|Hx80U-1fMqmPFU;$Pj0voUc2XF!xa03tU0bzhJ0yD4z8*l&@a03tUfdJqK2?H| z0<1s;Hed%1-~=w<1|Hx80U(SMMqmb3U;_@|0&d^|J`eyQAe_qffD5BFk5&bHP0f2tgs8JK>!HOC+fo`y=wnPoH*_Mp2NThQoQS@~M07tVqKhyw2++S6HAlh>(03j+N5TPI z0A1%%b0mBq0MLCNHAe!S{84ix&_NzGN5TPIzzsaW2Ld1j_+i2TOuzy}UE#bpCr%)m59EeM06u1qCY1Q-B5|>4@yK&P1L*z8F+vf_(2eG zV?(w5pg?!14HITy1vcOSF5m_p-~$1`ogf5Y1ZH3bHsAm*;07Mx0|CIFBn-d^Ouzy} zU}>@5tx7(Sbzv@0DZ-YPT&R}-~)aT1R>A? zx`4n9)AIom-&5|Dux_(2GC zfG*GtqJTd|n1KlFzzJNy4bX3%h@OK*^y)iNPISF1MnNy&PZK6!0XEfeT2$4P@W}Uf=_MVxpV@ObLPz2!jsL3AzB+Pw+qh z24DmxUBh|^GH&{D^P&K520;jfK__9oq6;@8Ad34F ze=GNfKjS~ke_j1L|MmQ*>ZkIjg-_H^3*pgTx2?2l@Ba_vQBs@1@>T-YdSFc{lcM>7DF5 z@psB^=iW}doqj9!R_V>`oAEcxZ{*%cyurVb^%R~So;DPzUgGq1;9FTIw1E&f{h z)!eIzSNT`-uc)ucuM}QRy{x=ke2IH0e_TB-A1}O^dQo|?_(JA|*bAlSv(Lw$FF%)i zF7X`yT>e@0S^3$*GpT2kXNpf}o{l|T%4W0iZ24I3SmIdvsn}DcquHbJqva#HBZ(vY zk^GbDlk$^=CsI!+PZSSl4#y6c9?w1=rykdGk0l=CAIm?gJ}N(2IFvf194bD-J(7P| zeOP|D@KEX@<)Pw(nFnJJmNMB)JX22R(h2m=_JI0;{6OJg>Y#G4cz@>p*!`sg*#q$d z<@<8?CGJb#8@so3PxhYpJ>|P|cPH-V@6O+)-X-5vxHEO9a%XXWW`AsdXM2JVLZmfq(!U!7m2u98<3u1j5~TvuF~Ss7bdT9I85Ur}D3Tb@|XFV8Pi zm&wZt*QTyjt}R}Zxh8f^X=!$8d};aW+|`Mz`K$9+saMHY6|PKOsa#o%XX3GVX&^fg zA1GguyCQJ~Pkq^`m&=zIE=ygeTvog^b7}0-(k0nT;+K>!&Rv|in7=rGk$RDQQQ^YW zh02A+3o;kPE-0O!JwJYa`MlhDiSzjL@=Meu@{+>h)M90EaZzSbY*8tejm2Z-{#<{e zpYP9~tDY;LTUeM{s4Og=lQ}1LPH91QL3}}Zer|qZK0iNywtBXFc41y>o-(gEH#0Xj zw=^d^CqAbq>O-UHMM6Q|>Huq&k$2VmK3yg-fAqC>|;YbHPNA59R}E zKn@iADZk<``ZB(lujI{os9&;dF@7w85(APTraRzfrV zp$0>Uzz$r%4P@X2KHvvI5CUP)0lGjp=m84o1^h5!0487oBCrD|kbn%lzz>2TOi+fM zxE%pKKu8isU!GnZd-u}?7#t>Kms!G03Yy!00@B&&2T3_3s;h=6Vo1-*bv5&|#)BQOIi5P=;yfD=eS243I?A}){6`Ur#z!P0Vi%`$l1_hws1A|CCV;ek-Q*^5vm`@Yd z{z1A+T~^bMf#?C|G~pT}j3+P+xW@_eDI)4l(8~LXF2D~Gb`TmP`hevGA%h6;og}z% zA_^?034UNLEdor#M2L~3TU?sx1eRlj1j0Z8mNCNEpP=v@Ci-JAQQeoOoxN_lZNLP9 zCF^n`)DW;D*#JW2+=L(WfbclsJWX_gUJypI1|%CnvSuV}M5sRCjZ$La0iqYU(u576 zdKstaRu8ZsS+O744I(>)8U>a#A&n6xglYyBU?OamgY0R>fzuqqDHEe8lA zZT21{D_<%Clp{kO$Y;&od=kQi7+EcxA-*C1+2)}4LU$Cu#OSV9?32>R*^lENm-D%N zBG2dZC)5)%9qFgOrhKjV)y!98UoCwl`<3`t${*oapZ_TTq57fxVc~<+2g(P<_cQOu z-aq-?;CuXg`FGWK<#!A3q~1~9DZZU~JN9Kq&_4+RCqA;pz>fblgY#~rF1qO zPnRFaJ&<^Se;|KQJt$M}?1T67_va6&2jl~V`%?EQ_Z9EWRFC_k_Z08W+#S2SbXWGS z_+8~Yb9W~0Sr9Ig_@jc~KE|o~}seDpR%E`j+)NXEf zepDTmN2#y(UCOTF&dko(&e9#(JK}egZ_nMHxShW}zeC+2?aqOSDA$G&bEvYTamg45j=Gf-artGHprt-$z#>7T`V}66WLEccf zK6SlveQ|weeQbScU3Oi3U3qP8ZDK9IHlI)va$;;SF~|?**Qjf#|M}Ia)ynGPs?4g` zs?v4Y>*CjySLRkGR`S#*y}CkPQCOZ@t}HJu%Pfm6D_xttHhyjSn)EMu{6BoDd}-m5 z)FsL##fvi+$1W~il)Wf^QTf8$g^3IK3-cGK7swYB&QG1MoL@XIb6)Jc(vs|w_>%JC z+~UMyesO-$z@l<27fZzWSiWEFm-`Fnrp{H)EiTL~j4dpklRYPXPI*CYL1F>FAU|K7 zFV8QWojO}NyErd1FE+0T#=CpM=vJ3Bi*yF4p5D=~|ol|M^8OFpa6m+Djc zioKcMSZ_(mDsiP8%|#PYKAP`Qd*q%%cdA?IE=DquSftdI?TUAmJ9C|hPQEkWp?1g} zg>WjYgo~j}C>AOOv%z?<9LNO{0X~rTtA5#E@TGi;ujtKqW8RV{>xp~Ha!yXjyqtHd zZrNRsQj#JST^U!*RdQyXac9|)b0i$RBX3vjvb|tS*%Vt*%!o0uWX)RR*0LpMNmzJG z-mIEsbHS7{DW;+^V~iO~hO8lOC<{3uA@D+;S9zH)a49;}Kl~>@`mKMX>;Fe?sT}{a z{{K(@l${HxT+IIYTe_*K^lLrt#KoE&6jp{5a5W;F?~enx$4@9OHL)v=ASy{B76CA3;>uTfy{ zaZqF`%vQ1CBG*Usv1!*$O&eWp!KU%mW;cmYKeIl@_jPsD>fFW{KhUj0ALHvRMksPn zVV+Tp+N*Qg7;6hQjj=YnNsRiL^)Y^^tD{!uHpcjoZWa0%$0)iJ9Hg&S$yv-+F-EvZ z`nhJUu~y47*eg!D^m^ho&#o1%JztYZ(K7W5)W`Z2U7fWI+8FCsb*s?F`UXWg#zB!8 zVYZ63>AsPEvrl`+Y2vIb)U;JrW;Kbgenx$4U(?k|t798uJE2>JKDIY0u=hA9G8Ja4 z*jnxzXA~V;(G>C3W;cmYKeIl@ysnN~o!c1W$GTPMV|fFW{e_gigudz(2iKO{KE7bfLW_0;dkjb06)A=67HaW03KcG63(K20Qy%*!VjqbzrSAQ5)RRC z0N%LPC0s$j0l0&H17M}!0Qi4Otvxi|#EpwJ+03mLs^8SVt;;~mq#c{OdS2lF)vZDw^G6i$2@Z=uO6%4;e|7`Sxx+_e|7{FI{mh=U??7PD21EsyMKwVdX~j8;`!xM`e|7ikh{vjys7 z{eiB|S_W;5^@qAu=wtni0v+R^$n0UZinZzQ;VUojY2V?s#hON`&1@3l1-?(lS`uKj0f_smHBD0U#D!!&4>ubBOX(Oy(v}ug>3p9zcadv&2MO|IBy0-$CaAevOX*{}&zqr|I~A-?!X?OydChzbOeH z)A9djzbgsr==lHEf=e(`9{}8dTiDdq^X$**_R&Yf zMOSw%i#EplUv;a{$NQTU>>&<{%m}kpy!d!KqCc9b95qc7YGomMp-k?@rZRa_Y?VoM zF@663O;d;8qS7DbpvY91t?Gc!nhlptVCOcYdejzds7r0ur25n**VpO4O;e|DP;Kt! zpvdfGwyG0)=DAhdF1z<@U&A%&hOqLHuYQrHJ1?B3sP%4I{hZj)N75JnT~`aOR&8v+ zf1+E3z5#!eB09)Hkr`pO3JMK)mlo8H(fS-(G~me#H4Urso#zbV`jM_KTHV?h*PrTE zp^xiZ6x72U6q!BDR&n7Y+g>fMN?2@<##%>mNyq4>_b)O+@_p$>ZSD5l zT{}h>>{9QpE5#T8zpfNosiw|)7nNa@i#B9Um-f?tv>KGFx;6jeORhnsPXJL)&}vxu zo35@wy}P!C&;L@l2JIo*w)`8)a0LfNW`H?F&3gy8Pg_{~o5omB=W;{W?Vu4y)twDn zGsd>&*4?9f_o<`%7DR`J?itxzm+0qzHBD*$mdde=gCaA;9O8D-3+^7R6x!c3MrEPW ztWxi}Wn^^!&Q|5YER=<&~xDqxzd^iuMmIDkyR=%p77noyKNVjcWDoeLH8|l16vem*;P% zDbHyt!%_~4%mA}hdC;uS=7y*|GiXLA$oNq875w?%O;eCE72z5Vip(IhRYCABw}2I- zp#@pjScC^&vkL#<6ovJ_EehXsh{E}QYZc!68>?{5e6#T5v(3WIw_Aljoo5y9UTzk? z6S51vn{2}G(6Rqt9&!o~)3N`@vz)>jI`)6)n+_pL*8ptU>Y(rcox<NJ|Nm^at!v4Xx6R*A6UjeP81HgWWcD%<$$r}H=>DZU zxQ_IT6bZeE@&6FUI^Hp=?is{K!_B|wpbUS_Lm z+c|rBZl&5ScC)CTRx5;7y<*_>G{yJ{t$L7yBD0&>su%$-kiM*1j9LIwl&CTBy0Vq0 zDce6&sUGB@$n-FW*vE>-y$D96-pUQFp@Z7$er?Z4ZDed}r%0$Wi|$a5!1Q^GdNi&r zQaO~}Jvu@k$uOTSi-mAFTlWI2tHD1`Q-gn@vOmm0kr`mNssZ*pJ1RB6xqv3MVDDM~ z0rmK&Y3lJ)s=UZS`d)&w#G-le9)bHkhGEFi6l?u3$gCaA+tQ52H9TCO60L7%u zyI0+}WAFAIBihGwHc@*|oIGzXeW0oTbo#|V>q@1Sa_Y~8TPeCxZd=3WLL-O&u#UQR z_Ak0sXo+hd+kQq>zKVk)Gt6vNalGHouU5RSU9%)=FNfNk`c3fDX-e{MRE8BC6q#Mj zRvn9DD7f>eBy_yfum!YZAZjJkY=D2&l}RgO8#lnubgR&BfPbe7U&%p{8Dh4oHa@A& zt5my|GJO!M-y79t)W`pC)0E@qEPg0*(8nC&_RuG0cBG*d9Dmud*g4!#-EmLdD{>M0 z^v;ft7DRD46xAIM{kyI#TG^(K{Y;LBe*PubF!SS~&vk3i;?Z7MpHqe#I4CkBOyoI2 ziR%8b9p9CdXZ0fl`({_$qtrfGH+;^B;+#+A^938W@rAB{T7jnyc`xmi@1-JE zKCev_GhNxaU?rGV{fO`j-72)jwG6(X+HdBd$c!>uWf0;**!fRnFtT%G*9hJRDsN{~ z#ZXQkE>rK22lB&yqs*1ggz4RT@!ydbK7hcoEPqm^&! z=+EdK&Zt|3K6;)ido2e=rjI$q-APq$JW9YxCOU%KpzhqE9T(^u9^1b*`M_+NrXT_p zVFL$6W`sFJr~me}_$WksgpGT4?88CDlzW7`steJP$5eX+v#x+zfv4UWXS7GK=vJZM z7zV2SX6mE^8NevBRR+~P!bAqs>=Ei?n0k+3)fH1Kb{mtR{)5@S*_A&NYWqeL)qXh# zMP`sWL@i;I8=6?UdV`JEN@u8+k4`%6h)+M&kD7Jw#FNfI)}HCV{k>J#Pvial@P3mHl1nXdc)^^i^2FxM>nWR6+5?K@WC z)FG>IKOOu3^-@t7dfO`eoR0gqZxe;z*=rMi`k+HNuh$_QFNlICWfeM;bo_sU=YHoK zuZF%b4RhbE9{*QLvzEImMLQw-7d*X`Tbi<5?Kzz4!00;0e=NQl4*Bp`zT2!SpT1${smCQQHu!XN?^ z&Tf3I4RgT$&en=S37vRVUmYhm*ucasWiT0)KWy?9V5(WR#spG4iE+% zfJciGfB_hR37CNkV5|rUV?{_9D?-9p5fa9VkT6z+gs~zdj1?hatOyBXMbNIA+LjTR zfEkFu0bIZhJirG60AoeaE|)L@Gq3_1Z~zx@0}t?l0N|s90hoXVh` zVSq3KGq3_1Z~zx@0}t?l0N@7+126##5P>vIxPb@wKmcHX2Z>J-24DgfAObsZ0tvW* zZG7U@sBKt3sifqp4tmkn`EiI&a_F^#!0ruNzTSe-u{(% z=~dn@oC7PVi2*+lhUw*F1sKF&BAm*y=saIHDKOSBsjt35l?Mg}2RX}eR|k8schMb* z8zwBk34EaE6v3Y+q9^I??YOItEpHrWZ-#_~Tiw(bpJW&#tiZ(>Si^~xw^twCl)6A) znlNE$C+JQt$8#QL&)G4)il%_T0KNG-``6P8i^?Tdc83uZkw=-VzyZ{DjO)v6o86v&ZAdvoFS9EWeO@A@M?eUyAW(%g^MVNj$?plYd%$ zT7Fs^H-SHve@cByeky*{edN>=Cl03{k3C*`Ec;meu`>0Qc>0l(4U(|mK@&QKg#XO?^JinI}3ND?ojS1-k!NVc6(_@ zc1L_i`L^6`iQD+w^0%tD%C{D_r?xBGizAs|a=ZfcSy}F7thU{8#}kOFuO3muzXJLoWwc&Ir#nMe@;drsGp> z{X4aSh5)Ga|1Xcz_R2lzk$@B;(}ZJ_o-SbzxZzzHNE126D{Ai$sv)LsY-+8|-5 z1_?toNEoU?!cYwohH9Wsc?361V5kPk2+Y6=Y`_6rKn7mm2SI?L8YB$WAYrHm2}3nV z7^*?SPz@4>YLGBggM^_PBn;I+r@RP$j4%KbumBO*ffGnT243I?L4cteBm=-u4Uz?j zzz#4_gM@(^Bn;FbVW0*H12st8NkRZ-U=*M3| zKmHQ>@s~^h{rF2FKtKKxy6~6Kg};O@{3Z0>FQM;#34QlV=(}G+-~AGLt(VYiy@U?y zC3ILXp~HGQg+`#KdI>$%OX#UyLQnO&y&?Lom(Xv$gnsMk<$=Y31&E+$_!c@b2KvA( z5KIzb&gC~U;!d< z0tv{#2ZA6Bgwuo(SbzxZzy)OB1pyEOoj`DJrH27C5P==IfE#!TU1|N89s(Vp3mBq= z8CZc0IDiYtzy|^#1Ui7wPZ)t2h`<3{Kn7mm2O+=>5CSj)3lM=FxCmWoWlZ;i00;qo zkT3uX5P==IfDF9A54a>@0487oB5(i~a04$0fDjPUgb`SP2pqr#+`vodN*lm*evB{z zGZ29tIDrJbzz>3eA192!3`AfDPT&S!;0GbVpCXLF46MKgoInCH@PQ!U>CzcpX^k{V zG6NCVfeW~S2lxryqd0fNB%yJVsd18}agwcZlB02we|#Bdqi;(D*J1ikaJ|d(9{MK$ z4}EuH9$UpZ6Ex$U+6Tu;=J-ujib{*@=Qq zy6Np4sIMihyfUw=`D7nf@CFK4dtxd9#=Zd%6TPI_PI$3frcL1*nNMd+nF)bQ!665BDAGaYcfPNC2W zSU^cv(nSkWNsiNM54e(S>T$Y9Cx7V6rq}5fRi4Tw(}OPyfzD&qs(#t05>Eb-PvD|K z9ZUyV5tCHFJ}PwOq>PtlgzbZCI1{#evU)aY$_@8_^`@9n5U1H_27LbXN2lJ)z88Nl z^_KEhvE}Fknb+i3$6oHIBjVU`{)PPW>htAi%TJ%o9y>PtRR2-#$oLauhZBeS!}-V6 z$K}ThkEI?Pc(i;dcPMd)Ka_t&eMEkw@Nnv3<>BH(nTKKzl^)DK7=N&w$z>85K9f(Y zX*peZAoYOqK=EMaVC-P&{_Oq3O~wQ`ld%BPsaUF%%qHW>^6uR3#BTl!#{(FnF#!4P z`4M$Q9w}@~ZBw=tw`R7+ww7+m-V(p1tmf2&%B%TdbyyxQ45fyYq2kS%n`1YZZpz*i zzo~rV$s1BPC^rRNg2DRwMfUXxpsSi`T$uU1#fs|%}AtCUs6>oV8Ht}Cs~u8glN zugI-Ptl(GVm#fR=<%MObWy-SRwV7*U*OsoyUK78jyfn8ov6Nq$zgoRozPfN#>MG@` z;+2^zV^@~q*?2r&9>@(O2Ka&e73vl86@|-Fmn)YSFUwpOyR39+_R{#JD0Pu?QSrjeg|Q1u7i2GpUr;_jcYfl0{`~xT>Ur{cg(aya%97&Z%;MPM z(xU95_%AsIKzwd_PHs+O4nHS9Tb(V>F3d{JQf3v;%A6HDtJIh6i}#g#bG?aPzBjL^ zimVi(m1F))PpqfZo$Zcymm|4IBEm=VUH|tT|KI$?x5J!yfO~#><@g`{|0`qv#Lfg% zf4O9fR?Z8|uAUyyuA7+pQj9aX7SR4B*D&*I0Uf$ERI9>i*Ls-gDvuQ$6qzArtBbj- zS6$(9baoA;b~!h$HlF5ck7}k)U3s+fwJ%fGmt4clGnI5}&}V94nL?3+A?8$9)WvXZ z;g`A*f5|n>JX4Qu4f;&2l;au>ip&VJ)h}sr75pW&U(!x$tP|Zn&9KFK zbtThE+P-vsUvdpIPuH(ogFamvj+>)z*;u-;o84}eZuJKeiso z*Fl-C;h@M2F)<)M;X%|VgrWe#!pxqsvD+VKm$+1$`jeE<60 ziT!K#Ev>u2y7F7vi8*!G_kZ3!O(6ob`sExHnIR?$v5l_p*ZpHZf$pb5Y#Z4=vSxsh0kRA?-%mA};<$2@vuJ}Qlo31>M53L(qdeyr1YnN|X z+E@2;^e>{i)oH7r`UQs{yW>B8a`n?ZP2uUM@bs_J@P460afjn(SN=?>eWVLhMdou* zWCoa(>NH+ePSv6Rs5*6>HsC3%t-Lo{dHz-_>!8*2aZqG>nAnu)i$V7>w(aQt=<0}u=OjnxaDDGD)I44?} zIlJ;_LakZOrmAh=pvd$wr>fw^^%aaYtKfoYGIrVIm*U)HGB$5g#pmh@rWLeJ75`%1 zmwNsr{mwK-!8Y&Uf+~RktI?jVTLWg{pBC*L3U!o&BGbp5D%!R6(JnfZXeshVjgc>^ zMqVk`bUxl~7v?Oa-|suk!opWY;fD^hu&T={{P5o`!l>OW7(X-%FZ_vFxWHx>zWXz? zaM91K!l#?8LicT=aQIqLm`m6Fe|xrBIQ!e8@ZDK-tv~($``;9W+s-lzX8M2Uo1$Rr zqkaN=%|b{Jh0heTu%7<^CMOEFM5+Hj`v27LCqLoM!`xH#-~ab7<9-~wh7~_Rmz2?2 z^#q-gO;%3Ej@`&PJ@gfw6GNsuIc}J98UThucVY~5Cx$-KqoNu6HYpPYjwTB3gV&L^o7heoLBCso+-A|UC9XybXwY!boe39=beB2F0KhZ@Ah}{4~yo(svUBsyEB1UZ&F<`rhVcJEE zz%F70b`gWGix_fUlrey9l1?PkR{@nOoTMLJn8yhZ=mFv>f_KyDbvH*pB zVkP7>6*x?rQtARu+MbddctHSoXuBH@xccb7%6b1Fo~HvuKonSMrKTi(i9_G=(DxT% ztXVn69!TG6uxb3*wbZ78A9x38Kwx~SalHD22bmU^0w4@r<3tn-RelfAOE<+JWiEz+ zm0E`w87KOHg&Kw^0WSyu_i5Y(PL3L^1OgxgIzSib24?|ll&}LA2(!Csx+MW0=mz#N z!UKAN8LtO7@PQEM0_G&WJVf9C5(xHh!%Kna>tDqgsSzBn{>Vf+HOv{EVHTE5x9vU< z0v#X%6wn8R(}WpV0S3LdW2k#OhPt<7lzThIwzp$!dpm};w_`ASI|j42V=#L=hL5*n z_;@=;j<;jHc)JB)sCYXDh_}0e7hpViJH~^zV<>og6kq^&JH~#uW5jnmMtrwpuy;F# zc(-GSce@w3P7!Y41tHJ@B0vHBX~GDszy_Q^23`;V9iR*JfIh%+x1dIZNPA4X9k_rO z_(2GCfo`CHS%4cR48Q_J-~evm0e%n$ogl)Xm!aJ>PFR5xxPcdVX!DpV*H-(nr8+@3 z;1Iq6h`<3nzz;e>H;4{Wy@X-H3hY1zKF|RofJ+hvAOZ)FPZ2)Q3A%xBnlJ%7Z~-3( zf(VEL2QraB0E9sg=mk8gZUi>q1YQsT-N-~l{R60fCu_$&sI?JQa)JQp0fu3$4){Sg zFeV8n@Sh@jfEmS-KnN(njly(*K48MyT_6a0P!1c)5v5zEE>;eOZqi=&pfkem_F_&q zyUEd#rXF^a$IU3aDd48UZn_4Sb4Ge!vboM@_if3g>^}RVn)Y?wbYJS`Xiw>+_fEQw zUto(#cq4V4q&HG`KfRH1v>&omc7!3?y*WEU7j}eJ+R-^3zFMm#@u$n#TsD#Av-xA{G5MJCRPku$XzXa|NcKqlNcqX! zlZhw!C-YCJPoxejhl`JA9?#Pi^tne9kMfV^52=UbL)ujZxrY)D@elD2@|i?B_dxkz z{NUjIxdVv<{DJ&^>V5Kkg?m%?D)$!e$=nmWr*wDr?)cs1yK;9W?&9yt->Kdy-&xq7 z+OO;{?o;*^_h$CS_LlZ!_r&*VL& zMUcBOaU*|Y{s#31`G&%l)D~q+adT#KY;$Q-c2j&)d1G#4Vk5sXzd_v~Zzx=!x?Z`y zxIVK!w!XA3yDq-2yf(Ksv6f$(PpAnwQ5Z}ODucx}nKiLBrPbNh@zv#3xmAf({HpwQ z>UHvUg_Wt5%F5!3%!=5G((>%``110y+_J>7?6v#pWgEM(3QKm7A46OFc_ItI(I~%k;*2OA3AmP>$xJi6|e<_ozK`PoX>2t#lV7 znMf>B>dJP-yULxp&O|5QneR|Ll(6;{H- zy{cFC7Cb4B;wj3RhTj9^on=SPk#JOg1%O`wl&o26+*-EeEC~y5$(vQPY%Z8mCdE`V zW{fdo$&fX~4P_xGBm`c_^D0l5ZE>EToq0 zF4W4>kg(4=eDL@~RQ)!z=!~BrIQC0E!CBlycweprHp*)O%aJ~!QChS)s~gdNY(+K6%CWSOmXxuzrw_KL zS+LVQv>{w)vvAM!NkYv6KGP@RYb~@E@|iw~gW~IN8nlOkX2Di+4$}pMV%?R6?1OA? zawX@Z>??~H=r^#z$_W7DiIrSvVut0^N=|%>)>3Ke+HX_2^mSZdVj;u8bzHdmXqwS6 zF~c-QzkgMz8Q|i~1@xjyy569fmGc`mn%UFEt>;7=yL?ljWe&5K7WM;l!iAQ^#hN%H zLN7rv5qLoan3K2*6wrN)u$?4Az|L*r76ySKN_apA5C#Yb2moP_kU#`Bd_4Ed35zC}yDa zV=_>HbC~D=0&R>~7cib8yr2_UX*Vi6$H7KsIcd7KCU<0(Q0 z0d5nmBTC314EO=U4*Y;0BwU~i*pfsCFr^7EFpLpCpa927!aGjzrwBI)fhe$?CS(u+ zmgr_$5fJ-{Ffa`eULXwP7Kj3Sk}#(U4-k&w7U%}{aiSC0P7^_3a&MsmMTrnF_Tw(_ zfo@8{wmOmAMdxgEz$xDXv!P3W1wkl2Nt9w zY6~k)NJaG0T4_bp^UTCI0zFAuyl>K^4tjbgJ`o&ub~-C3rl$L*=2!E7mB6nO z_*DYGO5n^B7(N<1!atck96u~S9)Gm>2>);@Gx@g|XL=4LvoE%vO$~tBmr;9EE#~zq# zpzHt3)#HD5{r|vE*k-O?F*83}+32&Y+g`g2qg@w{EcjB-e+Czhd~wc~Uc(}~G{sP@ zclA%YGWJR`xd;=gm!>R?R_1CMRqoX;O_@s z<0UJLCtoFWuC5|l#oD#8`@hulpUK9Ked#sKaASY5=u59*F*PUpfld9tiRQEzQ>)Es zakR2XtLAhzHKZ5^MW%<@s!MWQZb+RbO!P&{8WUacTX$L9=S!wp<9u4zA`Xg7FSAuI z^tfP_dT6Niv|m{zUC&#;&hw^O=K@;WVh)N-AG6h^!?+fZI)tcP7|t#gW-Hw`Lc=}O zul4+C)_M-DZwUuQrk`24kaJ&Uv(#kcfQ8vGF50LPLu|E`VJ7O=d%-m8T}*4-z(JAe zV^%InW)~RN*2-17cfSaiB(Gk*hJMz!e9h{HD}ig5V9tx)xqHX9=nxj^>)XD6^b$N* zb@zUuu3TCU4}C?esIB4ii*#$iEd0~1+gn0)Udus|>1LwlN$Pl6_b+Yb ztmyK3XmIWFRci(tYMtD(W7qEFyy!l5 z2}*8qZwmPLe2z4`+R-*PeE<4Iym;$qR+{H|&YT(P%z4h|1akWvpWn6N-|!K4(Xv$S zL+Y->9Cnwl)UyM*eIJ_%qf!S?h8$R_Gfft9_WCRJ464qHC6Ei238GS?Lu9y9-hFfU z;?UA_7M-*3!lHVOc9Y;Xt)kH}Y-5^b^2+dX_^LJHrtyfvNB+_{Fz(qV3&sbG#x#v0 z-Xeiq&?|_zq1$YF^x)FCk>V!VX5*59>*NHXEXMnN+1{X2@dz8 zp}O!#!{h=_n%W8sADwG5Y&bIfQ5t;?bjY-SDgQ8z(HshCg#>azpWtwTQQM>%&gXRp z2Lu*qoX{A+U;F1Fh~(!$<4KKy!l>t&yb9%CAE&5~&L7kMkKw1ykp(6TQvPAo>s+eQ zYb1~h`UHoo*JXwEI%SmgI%$ylo^lfEyRfpZ=dk^8oJrpO*TcN z{QrHF|9?LH|3tPb43JHhMRM8oqNG;F%542+e7 zH&=kWs=(W7z&q-|yBffIly>5MC1BhNKES|-?BK%=aE}LkLL>4r6!-d2^rQGp1&Y-u zzEBIk1nn~RC5V@?uRy(weHHR$>}$|3W8biVX(*VnZ*lNDrQmmwF=@o`11OrYA3@TL z{TP~N>=0%qu%A{CIi$_lFQ9G4eg$ze_8X|1vES+7Cyhj|9HQc3mB>o~3t+>>KQk2V zDE^-V{F@s*g1l??DH3=&vafBrf(%~DCnq2in^}>H%@|U8ITEs&NbKdvbLGg*&ik&@ z;t%vk4GF&-ncB>Uv|o-?SdOG^R*9@_R*gJhj@)flhiqVuG+B-`Zl)uTn>8Ulm?N8; zjYpC&M+z-RVmCV(ncZv>vW7YGyV+^T9p*@{9J>ZHLfA$K#Bm73QKJN-kcgv333fvkjv6Jn z-3eajBGOzBD&DA}=mpAva%{Z00^C&v-d2sxNK2k<-qeM^Za`5joWy zsqO3)WL9$|By(iBvwcW&XGx@5b0oX7w~%nnk*rJ!{`C4iB)+o`kb%vS{?0x|9yUiJ zGo}2~>l9Mq+2_l^FP4K}ss#VNhG;ncwR&ti*g)h;FBSh&C31%1k2s1@l;Wj${S!C% zGY>XsfETZS=?8yXfep}(;#GM4Nj><-25it#{Bt9UO~5!n-b)+*rVx1vibt&Ary9}L zXfMMHM>*(H4iIZpBF7A;yyuPeR&2p^C#G{0G3kkobD)T+PwYfDikJY!PWGbcL-CYy z6fqf!O|C?-8pWx#;2HJcS?VF;919qNxFDMkbwRce6AIY5m{Gu%BHf)PeNgcNB)xN_ zj?<}1uP?$J19l0r;OSJQ;^oMNr&G1x^~*8&fUT4d6PuAFPbVl9S0PoNPE!KI>$RAV zz}A;y17;<#Ymq@urzrsw6xe3WP+(CXHuzEOsz4Db>l{-S*tS}52QuyH1f}8)0Tgur zlNeYGvl!UTn8v_%S-{(^M9xsWi=$XdFzWnXC${&x!TUYW1p=;5fjqb=W0=`NAZgR@Jo&0 zS1?hHrL9Dc85nda2fvHS1RN7F*bgwJz;OKsNZ;p}o56m9$r&tzxdt3lG}zBEV!y ze_+A_T@|SKDW)yZwSj;+9=0YGvpkpu6B+2TKt+b>40LfIVA@CC?6LM4-}^MM=vU|S8?834C65{)o+lpLT< zJyvih18;$xCc71Sn(Ph;YO=e$;JuL4WW5#O1CY^V57mN?KuD843MEbUxI*O6(_~Ls zP=u-`dm6Hu>{;k)vKJw&$zF!CCVSOODxB;)kl|$C zg$^hC0fac&kD$cKegY{@mVp*0`#Iz{*)O5L$$kR?PWC$}aI#P2z-nq=1a`OtMW}JI zKS7R@{TX_k?0+H1$^HsOPWE>0}lNbut^2I+-0( zoy-BPPUf-^>0F|sW=9daoy-T}PUeSlC#!;VC#!*WC#!>aCksHmlQlxVlZ}IZCmRm| zPj(U%JlRA@c(PL*L=GWOHrb6L1U%VPD0s3nAmPcTLBo^HfQToX1r<*=2Qr>?;RP2$ z$kPa6v4dW4sCu$<-6%ralbsK7Pj&&+Jy{s?o@@p5J=rA?_+*zs;gekfiBEPFG(K4~ zL_S#rDxYk%Mxosj)x-O&AH+aUbOc0l=) zU9S;2^gr26J`|z*$##k#^yBEM{bSF^sgEKbX&)s&41bvYApSw{gY^5+_qF$v??v8| z-%Gw5emDD0{GH%C>9?bAYi}pt3crb1yg@@t7#Lo`Pq_KN;W>g5Q{5Jdep~Ri^sP~v1(4ho-j%&2eoK(F z1*11>Hz#+7Nm(!+JJ1vD(S@p@c2nZU@Qw0~i5tQWpIU$Fn#eW1q|}d@0KxU?b%X3b#_%^RamGAh9a4k zcuS}y(;ROOl9r%!b#i5RrMxn6Rp_ehm5D1uS7u3_KS=ri(aSZ`<_}Z$fBe$WrI}0O zLYW^rg2?^XFG{b7uFzL3r@a3}I7FKK(dF9mVKa6x*0jI;w&^P=w5zT7`YSUBGBGcq)$+N{}*hK#Wexr|Koc8EXw(@jHLnbs!uUv zN&fZl_jhprWvVo~;m-3-7IOCb$1>*A4X{}f$OXNE!wq*f6byG3+&RvP_0S#plVBnj z-;re_SYJSPXG*?Iav?W7TIfS~1Ru^L>laBN7xW2YTxY1&ucy(t z&e(=WC3@r=|Ai*E3^#{w{Kqn&wZdcp#_=%j0iRDHFPA_r=n+KVLye9?CFF8azU>k;vQ;nbW_3LXnzKY z7;iHqmnQU$Zk`kL%ajuP~W1Ob>rxMm-+->6NDa!!#boVY!TgsFgr2=o1`uC_(Hi zAIen$yy!oD4b#Udl%p#HV)uRL?&$V^41+PBUTw0Fv)5l)ms2$bB#;aG1V>$2Q?S2$ zWi^{j8K#d{WwnfH|Hn{SMfY@>0mxy8cI96BNm`sdZT`euSAf!(>n=Ir)qKtYW5-CfqR8ftB zxw1o)D;i3aw`t7(!r4~k*RNTXTTihnO|z`ZN7q}GD`@Qh4N)*l2w^O|9`-&%I5d1ij#5xUb9)1dGA`4pIWWT)_1JRD_?Xd=TIKNn`^id zCjGzPPqiw|e`3lJ8v9?{!Ihten9`y%<&eabRflW}^#9)YW$Fwo_5bh5kN>0pAL#ju z2xiE0x<_cG7M#8NSppq`V+^g!WXv#bga!ivVZd;s@VPiN& z(zUtx$aR}68v8TCTTd33OQ0<15FBH8TTI3b<3@NevrHH;+$el54sWhBR~)&u8#cB! zw?{fUsc9C7L+y0Pb%6{*owEB+%t?Db+Limn=XN}phIwsb+OH4%rI`$ z1a<{J{Q-;$%}@j;v~{(%by1xd>9zTKD2#f$$q~bh5%o3X$ZQFe z1s#H8jCzO3m|@(A8fIn+1BM%g&&5%nCY>gtHpGvYY!Ko0seug& zG$^ct8%%B)MvXeyNNz2aKv~csIL11-(PYdpZqxzHoGT0%ZWKNj*TF2hD=og62CIYS zuJs!_M_&;)nS3)W8x^sMd^=kLWkHAF7%QU3WXv#bR0PaS7X}PB3ZIKBVv;mTRD{TJ zk5FS6ecUmVD~2H>?ly8|t^~@04#6?Tz0+jOFmA*RGqZ&O!;Qk{;<$q}3#;$$7ves~ zgMPEgAH$jv{ATheAc3-=LvW12-(oUm7&n54nR;QsaHH_KICxsCK?L90hO2$?PnTUL zd&b_3;M&RFMG`0rIt0fU+^r^KhH)b}n7L3GFx)77E)H%1Ef0Ys8(D+zuVF6e^qoG; zUkfjFx0zft95Cu5N-jnuP!@CujV zrV9gx8->rs6=8f&wqs=*Oc|W;_a9r8d+Gllzs8ka|7BIaIkQx0{gG99yR=kU@YnFlGI>=pMo!xpLJvt;%n8n{q?is<<;&<>`Y~WpaS}|B@SR9@BfeX%66Zrnv6;?j!8FFlP-a>phNJOjtT8De|w?VWXv#b921yn5C#l43ZILQ ziC6N9lXuJJjkI3L#@3=Pc-&;r*qssG7BVB5h0nzSo+q6r z0;G;+$M*KkBX+<>|9$96DElfmo2#&E@cAJbD#*J!$fr-L^;YQ(e zakVtiIe@RERdna&+Rh8w=mOi<2^W*WPcFQuK5VjX?Ar)+J6RtmfwG`OaEzfoVlrkJ zH$sJ(Mq$8kqwu*nRHKP+qHgFpZJ2o5Rdf#TG1)ZsXasmY*__ z#XX-s9>{GP-~Sg;GIk%M-CrPqqj>c6zbAL4|MZDKZj*WU#zDK8c05%AWkDv0gEnYp z3?_T`4c-j6WBsJbkYPA?!0ckTZoz&Z`%A?K%qm%>+#Nr>EC0RqR3P^eBbtFmykhr3 z!Cbjsl$)hZ)G1gk(U*1MqsQ5!(^qQq`H|Hfn=!S#yR}&^JjZk93(xVrf!q!Z`^N5! z+PsD8af$@Wf=qA>wV5y(G7KBF2@?*nbHjzg=i=Ig-VR;X@uqxLJ{`z?!U$!c1-IDu zWWijyE+5L^Rq5_&qP5%dRY}X|ZD^x@{0No#jLCzXKmCJ0yC}wx1j>R;a153CtjUmJ z*r-gHaEqNAE)+f&SLUEi^SNP-c*XAL2X|k$r&RaV;J%-ig=y`a={wGW;#dK53*_^4MC7Q&GW@tiL{7lcSoVp1N{u2 za6Wx)h(GtqJ-}k_3U}m%5uCY)+*lxiT+lCw?1yf0$n?OlS-!NhR z=C(B(ux8$@rq*rk9Rrqcd(q^H;aRRBm@M_ZY^5a=aWOPEgc6b=Dv@9WZ_Nk$QXu!a z@wuly8a00}g}F@vxnPwb7Rhd-Yp&_hgQYxINzE6uHLs0q*w}5XFDle=#K^$5t_iek zozTd@J6hK?LOo+~$L8+#<_QJbL4DhhaMp>`vw}4mPwKzK^&EXUkaNNazzAsgIzs*^ zR%tZXkwwBkVHCT~SJEpc8##;p83nymJxe5z3pNSnzLGW=Z#JHLYNVQ;naEY93*6e~ zwVOLOMY@{lwAs+MuD^LK5}WCKqOB8FbZy_*I;)XnZs-$KW7t*RwO0eV{TkutUiG^c zC#M!mAQx;DL}Oh|-!Y~~PqkFtgQW*oN7|0bvrc?qpkuEEayuW&vHQuTb0m-pjuRZp zv0ACNXSU&3=do0paILv>pmVQ};M{}c)+`C+f)#?fjLG6wPoud#l>AJ;wZ(XD|3M^G znR#M_H>V*pnU35~mN8}CkGb*^t^Mcvm@6+YwJN`icgBQJptdf40x>_7F z7u^h5*dvO8$KCXT<`9EVV%|G@$_wrl)87-A{?48*2cHqM;Ge}Tc=lW+_r&7x3#^lz$^c1AbeN^6!Lnz<&o&{zM1}{Js(8KgfrOhlP$nRz>-b zCE%Z+B*6a13jWy!{sn>p?0-4J>s z^bOdlwcu$&=3p{p4pz z$EKA+)ZuCe%FRx&#RW#(;3~*G&@@YMjZk@LEkk*&(0W)`j`Dh;_^_b@$D4LH&WX)q^1LfM<^+3$gL@!7 z!5)R?1bYmk6Gj-1JF)2r7x<(be98mvg%AZxc)_QI9>p`zqhQZMkb*tu2cNG1U#J9M z6zUW&L7jrVTm!x$L@Hi|NCkThDi!SY25?^h+^>VlM(_=(o%p5{48WG*Z~)qa)Y1qfS(r{7hmwA{6(R3@ozqq zzf=x>*$;lD0{r(%@T*nee^i5CgANA!dM)^kI`CjUn1&bz`(^Lq?h2LDq5 zzpH}ZD*?Z60e@fxe`q5bVf=_;(|>XB$B@xrKPd$dIlzn){HY84nNZgFxd-K6Kw5+S z(hL5o4E(hZ{7pIdTcNh`y9$*58*&@$lPd7{)!-j$z{9m*whsJbJ@}^v@P7i}pLOsr zjo|+_f&VuS{HwH=_%|8+J9IgWF#e%p(~%PJs0IAgO0+dfHoTA-sBloVgC(V)#Q|EK zpv?s`H^@DpT?0$KphKvAIDII)gyx6akFuu%)Ud=1^Hzan)u68iEUyLqbznt3SlIwp zNe774GFYP!^KmrRs@POl0@ho=1}hk_fjR>lp(MhZ?BKXk@B|2ou<=gtM4>A(!Hx1s z9`IxhoahB7m4T=Dz*Eb?)BND%3NQ$<5jLd?oLUW@UIU&{3!aG;o!D9R;IsyCdH|fE zgJ(AqjWA|PhiKC*8Jw+vb5w9{2^g|~^Q_=}8@Pah3pu#R4lXVQmpH(4oZz`G@H{uT z)B~Qcfy=z$1!drJ9~dqNFZ6>eD!_{>!HcWFON92xr8OvDRtsKU2VPMRUfDo2!ni7c zO)GWq>PE0xK1^&;z=#U2Dgjqpz%^E|)dsF*;5rVjw}Tr>!D}4gwN7xO3*6)e+dSZA z4Q%&<(K4{Z2X>Z&U4F2;0^9-x6}Ghs+*S>4uK{<|g4fj%jWDjS$EF(^z#9YLO*+`q z2*#Sgo#VipG1Sd&k-=RGc&iHDCVulb(o^Hj(%#R`{cPqlvCrtANqrpoSpGQiQRt)0 zhp`X$e-Qp4`+ofW;QQ(KqVH)#ss#k!OurF*Lwh5c3@5YuVd(>(~m_T(`fC$@T1v1@jXFWIWYQ&_DJ&KFs&OH z-yPiD(x(&KaO>~{V3)NK)3FEDXy=+?}x*e-on>XyhY@-2y*LpNu3#&+sEQ?W=) zjwO0RJ(-(gH|aN}Zj1<}fY1%?*K4$XVEDT1jyS0Vq_;=6Yul6C!nAf^d~0xPdP|g6 z4or53yR&(ffM}=InIy&gY&0GXM$v*Vm`kMQEkK#M;o>OlyqR2~3ebK=10{>h!AUDs5FV5{_g^8z9({ZjLr< z&B?37S7%A%KDaV{RrD&2RtF3Zq74wZG)1cd%9kWA4qcoPx&Wyakrnca#D$>?GvQcR zr}Y3M%jM;X3qrISU~HMbES1*<2rbQ=7dvnNx#4rOvfdQG8Kw zQF>u?p|&u&AiN+uKR!P=KTVnd+Pq{a9Lmm(&kfE^&xy{_=FFX)nH8I*&q~dV%#>#) z&JLZOnGu_z&qz&=OqZu8riG?uXyrfstkjv2Gvza(29P;DcDjCgYHEa508C6d7>our zS^+RTIeS|Cv>>hj7d=%wHF-*yRsf7o3QkH-j84=hCQlBN7C@X<08CGaPS7SKPYmUi z0G6MS9Ty)L9G9lG0JWxMUI!qkrvuS|Mr#3v8?yEB`XH?Y7!@i2VOj?;UK6ZIS4U|T zz+}}SS^-e6OjSfG-U~gfrx9cW91eX}C0NkK2RxG>>wPCrO7dYm3{0wzM@$YXByN0zjNr08Fb!f9GvKdz4fEe{W&`f9@*jlvTO@KRWpNi;6TJ{d_J|?$FB@Qg^fnIhD}G zrV~n9KCyv&OJxpo}+8e(X%I=Edu)WTm{gp=jhaP^yxXe^c+2Ujt)IX zf1Z{ZC!jaa(V6Gy#B=oF>5H3y9(qA?oHqjU zAp&~lTm{fC=jfJm^vXFp0h=zw$dze#3{fZjK$j1kcH<~o3$H*W%jA|SfmLKcvt z)16ZVM3-Ag19Eh@NqCGP)B(}W=ICYfK83(OKV8_2o;Iy^Pe4DL3&lY6vW09Q?^g{( z51TZ}2TFn|MgpcHTb zPQV4Y0S}-N`uy}_OBvt;$^k!60aOB2Ks8VUpbyN^1?K1h^9CRQNG${zPyqCOc?nTFn|MgpcHTbPC}obE^KiF9zX-UKpEfz$^k!60aOB2Ks8VU zpa)A|0EBt~-B? zC;aETA&W72O59?paYFS6EF^t_7Y@30aTy_Kwp$w34MOru!R8} zumh!l18@Q^zzui+4e$bGfDb4K{6GbO{wIBn5zzajuQ5U`PzTfl4S;ljAOi}Z0wsV2 zKv%QhPi$cT2kby8-~gO}3vdG-Km)u$8Q=rT0Y6Xypo2+YXoPA2y-QvT)B*KC0}udo zpb?M`5oACCR6?JhCD>vCtN{9xoB=2h;-%KmgEzMnFDX;HN?_xC)d27QhPF00wZt4wM28zzMhjH{by@zzdWC zKA;@%0~G*zhxA=Ws0PqALU&E|lDW5Cqjwf+{E% zqM$yMpbW}|FlYrzPzUYvQ;39CV>6UOxeyAiLkVi3ya9k>DA$2Tpa~cUoB-qo+;a1y zTi*4&n|deuj!p`EvA2V7XWojx6(SA3#GBzad)^4Xkx9mrA?j5p_J{Y&`;+@3)USpP zpZ__LvBv(F@+36mmU^6ALa+S4iOXX}YHY4Qd4W~iqfdMf*5;>qxnJx>Im$WTu^ z^mz8M#AD&dWa?{29@QRA?TPNuska?_BuLtP@rOgy-%jif@0NEbNu5u7DD`0ULH)t> z1JVOY>T_$P&KHgA@ig_igQU+Fzb|xO_TI$3VN&Qz-V?b;qn>y4ZvF1`U9r1@cV$SY zFLY=2j>H||J9=&p-ku?yzR+#iTNAg2ZkLOZhC6WhbvW$KMbwrSf^LbETu zCAKBFCDR@64pEOh(G~9M=?r#eI^rE6>X9d+(CtgMN7}Xa)aK}BeRG=n<-s;6_k}iP zHzqcQH_986*G8_@sBa#bWxJ}>)MLch0zQ33)9qN50aK& ze0gYj_JYI(;XXCL)cMi#_4Ct9V@re7Z;$8o{KDt3z_1{DDv-1-3!t>;L$xtMug;H~)b9L&&OLLO5BeS*Hsaa9##iwV+W(H?w z&W=+*K06~ZBRoT%k))nHl>MU9^l548%LmWO^lAHr&*&j#zs%J5)X>!Il!VasO9ms< zqfbqalDc2|v>5g2Gol4x^ z#)QUSe0*qp_JqU<;S=N&lH(%dv~elw-|J23##m#pF_TyNO9aA!o`zsUhI;s+`fOdI zE?g%Ir9Z7URTHhzsh1zC4pwKX;#HxlY-OS{Tq##3sjsh*;$PIS`_q)UnxwwICKUhl zvNZMfgWil5*FvQEm+*u=vM1?|km_H`6{Y2H)6N*_{$(6-N63*aO;EqThkE@P9_JyR zWeMu{%PeV&*fd*;dj7gKZHZZemP|>!Bvg`B6KYtMsrMgIG$kcR<(&Rs5g=AV;F1GznoH|@|!PTDQJ0J#KK3N};jQ|r)PT-bVyUL;5G;$gBp zO9HuIo#0SfeRTYh50)3o8YyKYI3U^QjS)O~gnXDSfn2a&a41jwlE3E^!;{S;ADe-` zyg7m|dxS3_m%w_#QTakCdn2`zfxf&of-jGe{izbj1$~0Z%-kYHB-5h@i^^3}(y*A= zDw26Fp=Gev$n2)b_EoKe z*ghZIVIyz-oj}guP}ZLyyHg~P3swliIuhSZj~?VO(MnRyB+@vD?PcNvdBg9HVE8Fv z7~~RICYUqaZL%x%VA()F40mtbC@Omy6^iTny%CJ=B}1o6AQ!9@9ICEyL8>$Ay2!G* zrr#gIc7m)1C6EjH1&69>B!r@QQB4lYSO_oSR)->d>{xg#Hr;KZ|Je!2v5!3M#h>b*j$z$GWw#`~f-c_ONRFke0z!I$UA zi!&vV3)Tq^bsTUZo?to-CQp`a9?Xr8M{wf>a$uSSazURU+}JV5w-T;4l+@q6qpP)J zQ{M@25xv;ZhS}xCr^07Ou>T@io*{u;uu5>KLxRf=szF?KhI7JvR(y5@H(nBMfLsDA z1&4AY{}VyDaV%aO7{QB|$?{ne$OS6|hiVhJ3evOyG=t%s7;u`VM)2TOvK^E_E?6Z9 z5AZX^^bi@;4demTF(dsc;{#V5#E0@1Z9=;^cvZnB7t16S`gN^l6}*o z2Nwx6#;qM2x>^S{e<}WgkLB%uK9JkTQ1)LZ%V$a;7pxS7{fM+N_tAceABw1d5)T^G z`h`?0W)HqFf(QG__6!N+f&syy>c3K|>^ZHt{__`xfrnwRi^CU3@Fq!qoGpP|P!}BP zcvMMMJy`eDd_0QW5tTBSKmRs@KW~sHb0m-pHV6)Nd~p4qT6BDhyy-hkgL(9&5j=X2 ze3>PIT+k~Bk5&)zs|kyFjw6p&N7}{36BQ9zwXt>K#@0P+{Ur00&cq zNs04a{lC74j`BZDE*LKT(@`F1F)ngnGnp_)`Jp(NAeTU&V6Mp)|J24eev|7D7UdPv z1Dr6MDPJTlz|i?j`SDCz6L2O|zA}+3(@VMX%5Rx+(#cGDi8E#5Z*0m-G#8+0JyRav z%9L7~3-Hhu%60oUrrdHdQ=Hv4CH@7QQhSk2dFBC|astf*c)f#i{y)c*-6^Ix5=^UDe1IhtqFQEjm09L>TFn|Mg zpcHTbPQV3t059MJ{D5+hPy$#12G{`y-~v2=7w`dopb}6H5lR3nzyLeo09=3v@B%)- z56FiJDqsO@00-?{icmOZp1E`Zjp9K^T zp#-o346p+Zzy){!FW>|GfE*yGfCaDt94G~xfE&<&GN2r&0F=3e62J;Dzz#S77vKTB zfDiBk@^XR-SO6Qqfl|N$xBw5}1$=-Xs08E|f(lpw8^D25zzMhk58wrSfFGy?Zc0#3jMcmNIX0p)-nr~oQ~DxeyW4-ynW1xf%5UBPzLyba-agJ1ZsdfAONV72@K$X z9Vi7HfD6!oGQbD;fhwR5ke3q_Km|$w3t$86fCF#>Zomupff}F=2mr`gQjxQyB3(&E zrjm+GB^8-UY5AYw z?@^J}qauw*MFtODJqbwEp$jJgnK^W&Bp~}nMb3?iBpVg^HRK`kYE&fBsK}vFWhp{c z3RnOuU;{W%3OE2K-~!x$2had7PzLyba=;H%0F^)$Pz}@owSY94AOi}Z0wo0U(1NlR zumKFQ@2@b#w_y9kE3>9jg1mvZtNJ&wp z7D5SN1(0fjql~f}@B)6I5~u+h03DFq2^PQxAlXB80Z8be%OU}39I79v0Fb<)B6&ka z-iC@)2o&tf*Z>A_00|A$>V=0$X`psbKuQC(dx8f*HUqVG0&*Crp%ak9 zpjH9MVNj97Kuw-d2h;<|VNj(51Q{p+Y=9j=P6Ayl31tAX4(P&2K$?MC2OznC8azQK zP#q$@K$Q*=WIzFsQJ^B3Kt&#biWCC16hI0AofQOR52#+i4;5C9qh^)LYg z{3^!wRgCD<2|>WvS3r zFn&%=o`CUlYVrh(pHq`3VEmk#JOSh9)Z_^mH&-!au41%Y#Xz}=fpS$25HL`#VxU~b zK)H&6auoyRDhA3`43w)F9#=6au3{*hJj4*Vih*wx!`vzcw^fX5t2%(uY!#!~Dn_&E zWFshm3X}jgfB|;E321;9@BtM-4NwOJfN{WhKxrXZ0S1%;Za^czLzF9lYM>UV2LeDN zFb+Ui_87D{0D?55AmvDK1vmOS~9*KpZvI(&O+9X@$ylJe`d zSgHqW@uexlK6q2+#`uk)8?!fHH9q-<`6metf^BO{2W~=q8<3=8J6%Qs#a9+R(MxYZBLl zDfd3PA+kZ+kXj$5?ECb(*t+1l%-T5R-)CDBtzof3-`q9X)d^amPhOo|6`?HrR3sYF zBk7hH<>6zEzEE@a>I7xt%d}2kWTmz;MY;I;Rp~2ZR|c=lT+w?)fL7{@T^_tVb6Nbd z5UtghxHNpJd})$$^0iA+7e_DF#cF-Qi!v+XD?%%>7bY$Y(~5n`a3rizW`1Yv9>t1 zD7r|eJpCB0-j`VrUl5{9{lxt6e0hFyUW9V>v3{Q(O3#f^wti+#d`@Uic6M$BzvQgQ zERAyZqcioH>9b>J2PtbmJ|i?EJ3TQyOnLiBTE|bDmO3j+nfvK8V`m1>%$yMyEBPf( z51%fdo}}!3ZE9*tbc#MD9gGEow3=Uha)@&H6Q_kwlTS;Y8lf!y6s_r}pOT&wqdfl1 z#Q4O}#O%ol%H)^-$uWPK^7!f0WkxOP9sUf|TbU_lCS#EkUdO$y(AA z@o1hDt@o$9)2^5+=*rNFe<5eqk#K|^GG+WnO109IJxc5TrFo18d4|PVh_e0@wy;gM zC9M(4`%hV-7TuCAiBaZ%Mvbc>HLD~j_g_|$azxhTloX|V7eD*eH47Xx{(nh6{~zQ3 zO$Yv*yQ@LB(gxmn8TL-v*G+duj5{U&^vxG?CVz+d8zvJuH~Ui&K1(-Trb{3f^a|!~ zz7!Ac;(lRZxci0XdxZy0<_&j_V}xmw33G%8D7G^tkPG?+hq{S|@kQLjANpRQImB<8 z>>K_Z#}L0|GGPueMZry#KrUD*I8=zZPl$s!L!67|0RPiu-SFl(2KZf*33Gt|MnTPzKrZML%mr9{9^xkG`22ae zdeA%fB#hMAHEZB)^`qZ2Ibk?;9OL}H$%Hx1FHwZ^C6Eg?2o4n|MoiA?i*s{ZYksg~ zn2>{mjhg&m1h2kK{>+s?F6b8=%B#F6l^8W40ir>jS=!pRu510QCR*eovI&)tyB;6? zp~(}&v*8axyA+W+=)a6T^*?%Yf=ebFM}8E@y=8p=J4H#SP8{UbzCv-%7UY6H!J(o> zTch+d5$(1?W5p=Z+@fKk{|e;H8(tV*4Ik+-4HNy?WFlv<|I6*G6zB{IY4XAFY51Bn!Zcs(1|2E> zmC1w=tr2FL0z8`}ybvbn7aT53@x3a3IONWY0bve)Ui{kRgyGb2jPo}p6XrO-MX{YF zfn2a!aHuPQkr^K#m@BT;WPtglGGf^U*&{kWJIV% zHg!ch*0pvO2t^8g#*?sz{MG39f!yxK=bj|Pwc(@f62D2-6Nzr)!*_)X1JsR&{aTQYzllI@WS2BfExs+SZWr{w-s(fZT zy=OYTXPQ+BZ)3{u&$24(*D=LH&o`}QO3fmx5-07yztg&ZkDP8*$}VEcep>r)3XS`J zV+!d3{?Vp<5+waUnJIR9zU#0}nJ}63|9TXuWsUzAP8$E8T{!=L|0UAAmKCD@+=nia z7DjCgYzth~GzG!#TH;b%ce-?XZFk-1x{;o*cRfvixs(2KJ^ihkwoGxg(<>0~YjQnB zCA)2bQ_cOScRw%7isH>Z@NATgf_Saq;q}UN>70Cp)U&gs_!b-PP=jTz#GSb)}h)R+L_&TCLM<* zbR^OCmdNywDgtYd^&=RvE^VSc-09lmdV$(ATKFWvGtokG6^?z=X+Uo@n)GpM`lD$1 zj9TtZE^4^v6&>MGe7YK+mZ{mES9D-U@o5*e+M87wH~icj09ao$u;ZFAO$O@7F| z6*LYXn(EGawD_GiYO2K-g3;_nMN8f3L`&UShrNuxUJ87v5_^%*P}c9pTr|+9@|R)L<+cC9I;0QOo-GG2k~+L(^t`IkeZYq(sHYDsrjyn=${Kd#L%etNl~Rch`0#;I#?gci==6cb)asq;=wd0Q z>guSWs$b-a(*+V=>wD-~Ax;{_9?%GL4?2whdi<*f{#672s)2viz`ttX|MxX;@D?ah zKzl;ok=%~_lSF5@Gu|F*k5N7ebRiO?1A$zS)XM0}C}ngcFV-k`BOFdrmPU4I_?#>$ zFCgbao12;g-GuNod0KRG=9K*>_nfGom>Qo`ButPxL8dNPou+&QC<~@2yCCI=I8rRa zBRExbDjip!7@Qi zSsZM+AIu;>RcgL;eQWh5e^LQ`#9I|@#eBS%K?<`DTYO#(^CjaVj_TLr1u8=SQj zSOuvy*jMd%Mdxgx=E>2cCaZ=Q!`E{=O}P%xKXZ#x=t8SV?LpK{?t*vZQ6E2)e8gjXeiw!x$Lr7>VI~8Ht43hIppa%tAQ$ur4i{K$F0jILHW!%r zq$Taa0kIjb9Ix1p+Q(>Mw9W2FsmXx3@_tFxHb(-vpigkP%4^6~Ug25WS9#{s)?u=4 zcyrw9&pAc|qpiQAt}z-I^=a!i889E9U(=zPE`eOIOmHaGGknj|tYcC=8{w?=n9Le( z9IqpDL^ByM$MqYEXr=^m!7{<&;;IpGjeOF2O_mK${`t_17>0fRdc9S-=yjX&r#h>0 z{S7vyhMqsDwJMj>{~!L&rtGM(DpmCV$q#JGtZJ+B#XD@unkuWJ(*LI`t;+Z>+mtU> zSd}&O|987>%AI~%8*r^nx%C%JX^YJY(Bk*#{aMWCR6?vvMRgj z|5O_P|N3&P5;$b1zJwxu<%DzXZtDLxMrGl*=>PZR^8a&R9Y@Q?SYx9-i;nnA28;?c zF5$nWW-vzrxnP;#aE+l}G=@=Kgvw3E4QKxO_K>eW{}>I7w)&1%jM2cTFG7_j1LouN z-*jZ=N+1`k5*$k249s2FyWzLgCGq zKrUD%I9!mFl-d_$;dP1nHT^-Fe^b<$+%ViaUU43+9ixHKHpe4%CIjY*{5@6SA_?Sz zRf5A+WS>MPwU)wj+FX(5-xu{JPYlnFTU|Dc(ZFcy@@Qa;21b2q>m~!{gO#Pj6p}zL zSS>iz!9pS?B`D@w{UDu#{&qj0|JG>o!tm;N9jGHsCIjX$|40EYkU%b2EjV15Cl`iU zcy{C0Zhx5O(|erB5yP?L73t9v#%N%)P4dWilL2#8{)sAau>^9#YQf>EvQKxmo$9Xe z{4T0W^9g>U$rr=7<5rs!#%N%)wR!ZUF&Y^434XH4fcbF!nGRG)0=Zz7;82GP-`$i^ zo;$%wn%CTo=x_J~&hLpPCk&^K*Ks;B$z;GBws|1IO@}z<&M}K;sV)DcA z>v#ov^wcpL7;S?*a+=A2xhDUY>Tt0Ha=|LW;cAi+x%=A7F`eC$O|BTO9kS@C zxzoj!ljuIcW1lc(2KE2HPksMw^#79&nQ}Mv{U_4@XYORmJnH{{d^uCDqQ3v%sqg0;>gwIyh*HlluVfn2ac z5OaGr&;Y#Y(F3*NGih$mhPF1!dFa~S-nw?fHZiK2FJt@~V{J z<3Q8xntb4`+g7)>cXh3gbmc~r#mj=B)*~}VFkWIq?-JyKHGT5}6xvRS)pEl6kj31+cqQTJBcqiRIr8gE1ht3+oD=Yc4L;|^>U$B`*R=UYE(?ck{ z(vRX5-Tj)+%>|wW#jtE=?yr*qBBuen$lq_8ZSuwNZTKc|EIABE=9o+v0T?a7MuEm8 zkPB7`VnvX)L1ug5N96`u5u~koZDhm7?vB=?f#_Vst2eiGwQlR06u_u7-rBn6q`p)R zF&35kVE;C}v2Als47fR$sW4z}>|9eEMqI;J)v;wLgiJQfb;YTcR?wnUs4K8ZFgGr` z!FaRr+*2df^en`<=!UkgwaqkLe^aEZxwDI2t{bA(&gonv-nBx!X;PrEU3|8&u=&m# z!ACp!b)f`u!A3ze-@#;>>a0BELSSdKvO?_kqk{fj8 zEnE#|6mBdY!3__YUL=8BuugEOUnN*4Vv5n9*)Z_H{G4w=^N$#=W(MK-)k=ZxTzSGWXn39J_!l}q%UI^cliD``ZR&K<#}a&qHx z3FLxhg7}TmMqjC>hgeqzGD!WajF^+0@R!0X;&~(3_mkx-C6Ei!aiDU}esKmJ^ae0- zyKtG8f-m%3o>l&jg3SY?30TN|3~Y3Un*oyx@wtD#YR+=K45) z1W&5ShbtwJ3;G1%$xy2*VQGi{)rE>`L;R_*E|!hpK{eT4DS=$DLU5=ff@>??;=vIa z#tGxEg??Nxf*&>H!72&lf>nY;9TWWap`UuWV={~<;-D1O$?_3=sUt7Wlt3<6Etsp5 z;i3^`nDqbK73m-6 z-ndPp`TxJ{l>5Cryjq%;x>&p}Z@;WyQni?8E%jU`xm`d#;NDB91#AZhK0rB0@Bp;{ zW~;j~f!B=*=Wa~Gbz{!B8xv{WnD*_)WLS5}WP%g$0Rg}@mrxJ5S_n0OwVhA~s67NX zPzP9h2~MC2upT7%0n1^67ia*So+~7GHNXReasV0wZcMj!LoL9Ksnc%E`zH?wn8EMH zlx8<3-McXl*^PPgZp-Ov=$a7cICkXv&3ZgbG z*lqhTR z6mPN?Z(_xpc=4vv;!Oj!C;n z_f=7oOA+sI&LuSgQWD7Rpg*9dymK!4JAX?2we(=0&ISnyh)ryApN@vH$uhUk#tAN6 zyi1|}w(W%c4*CARy_}HWOTDLWFUBT&zoy5eyr-_>P38SE9>%+>iZ@|}2ph?92w$+| zgBwc;xGeyb?Wwv6ko0y#(%a3bM%{M60XP8{-~lwi4^#@E&Z~fGpcbeD8UP(o4-hOs zDc}HHfCtckGN2sr1C@Z~Fu@8izz#S858wrSKsitWQ~}k1j8>78sG(d zKuv%kPbR2<1zM8JkLqH#v(pHTE|Y zsSw{2CwN2CuUTE)2jy%?Kpbi$BCa_&50 z;_LyOKoyC#+rs&FY28aL3M+ch8A`zF9rPVUzycF)EGyxz0kDpQ8|z5WHzpk-4^Rfw z_7bGM1Ql@6&N&xuX;h@cL#V~Z+)1kRpI~7ZNzc%UUw)v)I7zXrgqv2X7u##wFU0Q( z0@e@VcZ!XE_-4V|uxN$58ZOv{VfusZC8%`JF0u55yCiUdRN_(~OF^4#^vY==*hq?l zUNgL|?!~2yyW(O~`C+Q;YFF;>74*Vge`p2H{oKW@fnK=F_tG9n8$x`*PcPgRKqXKG zR0B0YEx->DN&zR}0z7~hC4nRoSf)9=LI3BD71 zJNS0yt@vA+H{)-H-psy{cq9CV{6;t_CzJal`?dY4ebIgTzVz#{*MqNTUW>mLdM*2E z;??l0@~g>LBClw#q+X7`tiPOoDfUwErOb=*7eg;*Ur4+VenEaA`F!Mg?fKMm(dYE% z($B`84L+NBCjLz5ndsB{)8T}i2<{C(B|jB@Qhri@B0XUJfz+Pp9(_;r5&ey3~&74t+;@du)4fduE%yExk3i zHMljiCB7xJCEK0o4tLAl$*xG3)|KjvcIut!j#x*qBNL5BL(yov-k#nZ+Z^1SX^Xe* zeI)!y;^FpuT+s*h2h$J49tb{=xj%k?=>BXx5f8`Zc(OOrtM#Vti{6*GH+-*rZ}OhZ z-TUwAxiffYoPmyJ3>3M+Y{Tv+vV-aZINx- zw$#?>R()%FOKeMUOQt*C9qP_@CAz|0a#yl5(y4W(I-(tVM>-md2BVpF%vjHEPHYZu zmNzHcBEzhR5ZkbPePG?;)&pyLSGTN+M_O7YH%nKCR|c*MUm3`+WDvPbyDW04c4_F6 z?8S+T!xtwm3SSgkk+`ruJa@V0f~aG6||^hUgzH>E{2T}yjno}ee=j=MwdtSjLP zyJT0=8F6aPlq2fU9qH0oX|Ob7kK04`EKl$-mwA$A^lL0-i`sNs+8VP4tr<()60&4V z5+&ghxg@DZR837OQAJnMa!d}=H-fkFxh^mD|GixW{r{HL(i5Zsh)2!Aiwim#qm-xG zLszSI`YDWS76i7;0$`9bI|dCYLmtp1Bjq@BskDmrG(gR7Fwv{QKL7u*cPHR!T<8Ay zXGRESKmta90PRTLw}^O2oY;x*7RNi@mn72ImK`UKBfKPW;v|sO*+up}CW{kiHQCcN zt?8O{73uAA+umN&?cVnG_L^?@w!M~r@Atq+a3lm)^#A{!=l4{8_<+WU_nb3l1~@bG z9(o?${b;Zvd&B5G<0@N-qulsh4W7azxq! zqb}h`Fsu=Nq+D44S=$BUH{nAVAPFBb92;J{V3;U;5aTf6gQnwaSVg1s3GN8KK=||wV2Ch$5MyxRgJrZYLE64z8PRegtHY0s zamnyO4E%);+7P*fq-Qyi8-^blgQ4Mr7;Ow6!~md$@}*i^GN1M6Gr0?+fOhIp3MHF7 zz>=e8KAvL?u7Q>xp!{l?B^WexASY$+(=c9_|1=B%I_R4cds_CjXi?oDF)$Q3ftDj{ z;6godW_XJ*EiW#{1t)h|kFYXhD6Tc{zcHLQxxbVcXq=3caFj)p{RIa3@?Q|+j*~Ml zhk?E+c`t`?%SOJI7`WsMigCmI*TpDiUqLZ&m|su~KIRk@!=iZw#gJtF3u2TsTTl#3 z<`)zLr;U2EV63t^uO1lhZ0v6qjLBjZWU7sk&ZfMlV_?(4o=%JTzJNi;F?mnNU}!Dh zN*JKbe;UR-YxDa820up)5(5LEXVUWAzJLL@S$T0W5ISA2bpGfVt#Int`m^c2FD^aK zsS*7~FQ7kWj+S^yZ`~krs>z5O4kosXz#h~`sOjDK7bI0X97enc_*q>y!RSc!0U*@bXwt_I6j^3Z!IWP!)cHWC& zkl4?!Ta0`A`%8l%dVlV^#fW$Q%V3b&pWi_+&fk*L#;i~n=;sTC!Sei9!(jG+LScM9 zr%*U}kXI;-%;&!h2GhAhVdT7puPzP-wDeaOM=4se+dMrT8(#l^;%EZhFY}UDr@9yIFZaDlizOPe+w+NH+V&NFh`2Nt9^qS*yS3}i+7sTPE@!5VuFPGoP zaExle{s#xC_=4i_Q2uTh2dnxDYNS`rFDQ;UO&2{YTUH!^$}cMp zk=5!ggQHUU@0U2vMVo;BE{o%9wV7(;fL2{zD`HrmM!ybF_EV&Zz7y}VtS{;#{PbVQ zZ=TtjFw$R@_xBj~r@?)ss-}TQwnw2P>GWo)uw{?o)iQae`@}aB937a6;{@vS^f$=4 zTI?@yC}HORvlSbv#ZLS<_T%IaBR^FCDg9|IsrID56ZlT>+x~B9-wb>s`bp?x|JMUw z^L;h=75|shiP*8o7n5Ize-xt;u;}L!AH?3*-b=lcrujF0Z~5O$9gV*ceLeD8^wq#C zzL#m_>P78v;06Elf#=e(bcE>`=t~iaBq-fU2)a8lG z(mRruMz;sH`8q>egIfZdgPOlXYY$u^UL4sJ+(@%Ku1l;9tVypHSI1};$LMlxiMS-T zIDJ84o;FXM7i`mJi?d_1VrNIE`KKkP`da-o>tSe8Xq+}m92INvH6>`iLVs=_lSeC#)2Oy;gn{cK+! zol9|{02QW_i8Cs$rSrom(e0 zwYTr@+>?6_&gvp1YNoO*rVnQ*5%e+(opOS6aL&SRwpGhHZ=Ua4ng5&A)Ow9Sw=nCA6lN?d3{(VI z!$e`Ors8lv;p~M}?N{%nq>ZJO=FHsEY$#HiajY~@p$~WHMi8aZXx1j~hn@F_bIi1z zJ4-9e)ZDUcEK-&U6!}7W`$bt`6SL52@(7;rd4sGb{*7YWNhyC; zYolziiixrfcFI3yQpKKXi3j&ec~=>fG6RMdz-)b1_lV!0E~^;mW0# zbLdMlPHU2_b}odzz3A^}XRxY6MSxCbp{gT0=DFFbXQrLXIhQr_epYhjJGheRB^|-a zYg`Dv@~u?ib@cHam4}VYLX}6KT+&y0Zbr-g^F~YU4gTD#b53q9QdB<`uS0+evzl3` zs5l2(FRDJxkXQHZT*35$j$qv{EA)%`PhQD|(EmdJSa1%tW>A0%)5%23ZYhv7n|&=UWR{v|8Kv7lRHRYo(%gNIE7CZc6YzGgS!%hE z@&>$bmcIR-S-R{jqttU)k*=6wl)itfBF+4&B0cd-Me6;YBJHMY0Dk#%Sz1SV0KXhi zq=^wly1!eIgeFDWKEeAdCmsKPKKJ!>Kmis|32ZVXtCZGTds022k0tavb zH;`5k24Do0zy?&{050GLLI)uM126&^m_Y@w0u?xb3%G&MMM%H^j6eovPywvK395ky zh=+(WP!3E$0TxgRY(NDL-~w(S9wo{^IWPeQSU@GP0Tnoa3kb&u2^fJ4%%B3OJ%j^z zK`ncPvs!CGJrIu(WuP3GfC4PQ4yu3?xPcecf_l&hEI0|a5>x>vs0JQT3&a&f87K!P zpa2WO?G4M0<7vPI6wuf~XL$NR3m6UDI3?E$YC%0{1nzFa3rvRy1z12OumQs{!U$ww z29>}Ds(=%?ffv+)27)WC*h9+=zyuUf32Z-~iPGS6UC2iz|pSU;+xT04q>|1Gs?DMU;VZU;+xL09IfJ z4p0p|KnfEEU;+xL09IfJ4p0rmLxh3gN^8V&1z12OumJ~f0XGnP2m>$z1z12OumcBh z0S^$569$5hIB=0XaFKc7qRN4bYy%gm0~a|5E^-fCB+^k@uBe8Ai;M#oDFYW-1}?G= zTx1`(sA}LM*T6*r9nI&8Dh*szK5&s~;3D(DMHK@V)wT_YST}G{OV2!^98*JPE>Uow zm`8g!V6)GsUVnn9ZCgO6sRQLW9v!`ao^o^{br%{wrXEgs=|4;dvPV*z@hsB{dX~9c z6UuRrHFK$hO267Xptd_(w*LQ=jty93J-SFJzX1nP*T;@)xnKBYzRwR`M6IEhm2w+m7-Vv8^h9 z5!=S{7qKlae-YdM@)!O8xqhgXh5mJv-}>RB(KiBb1Yg%)Q(yDFdgA3{M?yz@NBl3P zUW~q&I2=0cJDhwW@`C?`)br8j1J9?Qi#->7PJ6aBCLHQ{`p{EdPqsZ_fBg8PM;{44 zyyBsz2T$C8EZW`OabN4b!aY5A9lEpYj<$pL+mGLR^p^0={+m-bMQ;k+l#awAnRECt z+gjqr(2c$ulQ%?e@ZXTSK6-t}0rf!Qy3lpL>yp<-uJvD=+8^B?*q^>8c1`da@tXM6 z+STgSiK{|a`L0Uti|q67OYM#B4eU+tiP21L;-2{K@M)d_FJ2bkq3uw2BrXkI>bo?# z{m{1HHgQ|LQ|nYa6I(-DeOr@TB3t}hQk$cj1Dn%YObcqF7VpqH)Q&`ZsNL6|yd-jo z|B}?j(Tf8Yr!P9TDYVJADY-GS(Z4aZA-W;3A-z7fKDb_7A76*F=o4#0Ykg~zYa(m> zYf`JDs{^akt75BytHf3DmD);mK=AGHscdfewfiu(om_O(j{qa_4UQGZ#>Z%5)G>+Cq0zq4$x)F}{!yuxXiK0a z-5hHUHjB-1pXO72iKbAKuPNCWY4kUy8lp72Ub;S3AFLPa<8@k{T9>E|)%xgYd!)u+ zlk!Hr0dLw9^8`JjC+^nVsyk5~s`gbUT@jbxmHNMa{{O>2pS#jU$N!(re*eeuf8U`$ zu)&W)$7s5^krI96Wa#l8eK1DU2Uaroxq~sZBzw+5hzp_rjXoH2E*p%2iU6ybg$83V z(2GN7Ti9SsfuYU;!!d=bznd$YUe*z;{vIv_U;SBB<@I#_AgT|mnL|~7USIVKjCJNz ze~?2T14sM!az)gOJc6yTj|;)K!g*BlWdc-~9wu60u+jd!5$}>l<%SsXzKScFUepn+ z{ncCuzV_#{+CxQvHOxY_$0-Ro@Xn5Pl(-oTQU7bW!s&$_!TRs#Lh$u(qdKn_pu((S z4psk!dG#Nm?ciFjn0m2CuqCeJLhvmyhuR=0K!vF?3r(;}X$FxpERanKmNP7!$wQ^> z9k*B8y}fhq`0;(26xk$?IcJ6R9^i_k7jfuX?-evUTV}f;>NUvRhm8XMWujtH=1rjY z`e6mp(=+me{)11Ic>@^vGd$z5}&rR}|&3#%7n=(TwoxyeZC{Th0u!z4vm3&>b+*kIgRe=*uRr<0PcTN zk*aAPz&(DmWT*N6_8wCtwbe-Z|3%@}srz54rtkm%x=&<<$M^r1qq+0{o$ThCO|PWB zi(f(=Vz~enrh_?D=b(?D)H$+~f#h}ve}3o4`)w-XWu)|1bj-?<(0E zJTS}vQw8+JGJPFn?!$vj`1>FiK>rJUtu3SVHBEpD)5*kID>UIRrn2szBqKNXa^BAB zAuh09kdaz9Cm-el@HJabb($+ch3RAtRWr&2i<)KU`N^*t^}+sZ#a+4kt4FwU=;a!z ziuOJ_%mAf!!jq420r-|&L2bBFfC|&e9I7SH&a`CTrk&Gt*tTwbz0z^}QLw9ckc+6t^W=wKGgu8t2PG@UnPSMU2ElC!4# zc=7CR>uD~oUXGDkH7B3p0`L`EMU|N=K!xdG4pp&nxf28DbwR#I=G5~LR}8&aBUR7d z*f0Z>+67NO%LU*Yay2#KN&zZN2Xm-~q={0fhkUk8`#G*udMQV&U7sIjfKuDF_l02w zD0$O9%mv_A+*(>?GXt<^4`K<z+O?Uo8qVS1TE)sfzK`l_VAkM}LePJhrv8~lJ}x$o#lxMJzW9I1NuzC6qTrS{H~ zuW$kQhFwohstHhGdYMBtEL}6x*Jk>*-?w1Mh8?7_bKm7(<%+5oeZ(63wP6M*wXu6& zA7+4(cLi^70r<7Kk=Elm0#uka%tC83o8LdX^5_ko+ZPmg%RkB$LNC-vt*4W5E&yN4 zO;o?-0#uka%%N&YC*JqhlG_{P*0QgM<}A$JAH2zxOfTtYtoq;RJAcRPigb#;^IuEf z{k?SmKF$BPj&84hXqFb!{C~ftx&KyOt4M#Kx&N-5N%H~F{cAM;-x9jLyIqmi(ENXY zqPhRBxJs5P=>EZ5P101F|L;?p|1U(hAMa75{WSldhi=_B$yhBKE0r(ZVnO5a$%36vQ z3Tv2!RwzEnv}IRl?nK4Ai*{VmwX?k```?*g^1kqVi7TF7+>u&?C%?=E z;OoDI>bypP3bU43sQ#F?lrG+89h&M-Z(ap=iTXwO#aiGiTmkh0k5~(Ql?%YPz*g1* zkWQ;7YnX*v06iek*8)SmCzRR%U*pQBmv_V(;Okrfz5%vTrI!d$VY-<(pQ+G%!DrC< zOnLJK=Nv1}WS+>*9XzQiGgUA`W!XH|_51>eN_@mfYEvzg;BgUJBq;PcY}S9$qce4^H(I2qdv%cA{`Cg%E`>DYM5m zCi;9A-MF8yOwW?3&u31C=?f#AN^)WJuqL6Lo>eYfPXTPq%;O67xL}wt^@qMNB0JK} z>LZ-`v_K$Ppa_CNxRLHEm@?DCM4+vM)W;B}vkxiIR@!gvZ4&z`6h8GmE)M<+Khv0^ za1F)Dv>sb9G~xdL&Q{}}3cUOo+0_!Em-h+K%WPs6ZZAp|)z@A${qnvodzC<6n!f)pkj>Js===XXw^{lHefOXD7e)F7efPhKZa%v0`K4K^qA`FtzW+Z! z=M2zy|EY6i=~MddAEKL`ZrTYm9sj310>Ak~%tP1zFTRGYjcj2lVP+)L8!gA$h56y^ z;!65Ou>w0#ffKkuHE;tD@PZm3(zU#b1j>K`lmjC$0R@;r1*imePz9X81>C>`YCs*3 zgbsQ=AOj1q0u@vN2f&1UiVL`b2h@OCP!F0wSt}s}1(<;aQ~)bbfde=}HSmIZAg&-J zPzDU39GHL^V8$w?64*c$s0Ov59yEa#AaxK1U<5KSg9=~;c2EVJpc;5U4X6VRK&S^mE>I2JzyoSP9cTd3F~R_hKn7+|0V;tFsK5bSzyoSP9cTbe zKs-(ufdVX`5?Fy9IDi{?K^|3hbZ?U?w@G8n}tR{h$|1YCs*R2Ti~Sgl<9v z22c)+zyvBlC9nbqa01Nnr(jw?1=IQ|b)X(J0pSo)2Fig6$Up&RU;!0GUpXtW#0qS{ z4ypj=p`vYwa03tUf*Mc@>Oehc0F6L6Mu@-wOu!5(fgLzNHSmI3P!AeG6Yzm%qOY97 zaatk*2^fG8$iNINpaN6^8>j-+zzw{h4m5#gPb5JE#IK;03jy0W^bAK%~ov zXv3o%3i|t>0ZUB43@U&XIDiwlKs9g!5AXsS(V#G(4%CB2fa$=L7BC8kO@su>fB}>P zBQOCOSb!C%z)AF#(~TuHpdK^=A7}xiz-S=05)vo_24Dg*FoQ~2( z=akcmC75lP-Z+UW-~cXwnM7$*Cor`oZR!N3wxq3`XaJbsQt^QnFbasr2nm#da$o`q z!0eYw1;Ff=v=1OufY~n<%zjCG0|K*O_O16CEU5+cKR3@o4mSb-flKsE4y z8X%k?L{J9GfrC;K$c}1Q?Ix9aJgjemP0g?wSH;tx(ZkUaNqxtL2*TmN_ z2VeS?=qrI&(l5te4!$hD96zERQI8~E3ccieDfwdLMgNPb!_mWm!|4}dF9cr*_szeT zem3@O@LBQMcub3_vBaU!A>X0oGm&Tf&!nD?J{@>E{Z#C!;8WsL@h7z>)h82Agr4v{ zk$hZuJpP#WnEF`aQOwJid?fOS|B=+g(T4*Mryq(v6nsd0DE^@Kp!#6qfzSiK2a@+k z?)TrHibkV>Xu3Pr9qbO@=f5v?Z}i^4z3F>m_XO_|?}^{7-L2kDnbhy{-IcsELUY=s z?ugzIxFdZqb})EQJQ%-SyIs9Kaa-s%-)+fTgx)#ZV27ryCHdf`Y%CyF7TgczOIX?K1VU#E#GoA7y!u zTmw;s?^Hp%D~EWFcu63!z=tNQp=;u1IyFPV#|Wd z#AWfN+ER6CVo7L;Z%J}-WU+s7YEg7iU{U(Q*oDCh#S7yLwT0@!#08-Xd>14aL>BlL zq~=HG2j-{e#pVSm8-0APHdmdSm=l`go0AMg0{%d%E!q}nOP?P*KX|@)e*8S`JoUW9 z?9goA?BuM-EdQ+3xzTe2=cdnzofAAqJSRR=o2kxBoEVLL*{}Qf{%jZfuBTm0F<%l{0 zj&xP5Dp(~}#Z^sJ)r37{_t}%Sh|Olx7M~?)j+p)C zloC|}N?MM|L0OdJCe5Up62_3xXH1qy%KhajL(~v3q|0Ju!7{NdE@_e~CB%^E6O;6{ z{;R(~wZu!u|8LHI|HtwF(QSWXU-+{_THp6&zW($1|0Nob!Jth4*omDzb`L#vA`CjD z6+ZQYf?>*7m|NKh&|Rb~;IWN~A)4KE<9@>W$k|GE1RwvK9SQm&7e)`OkDMK3FAd8D zSivk9COdML36nQ+_M-xU^pUeW*^5J2fEFeKo!-dVKXY;Pme5DeZl>3!>paL3e!~6F z$+p*z3%tBOa&|Ypuup(qW)rh;du2w>GVRqja+diuGjf*gbw4Q(SMPQGaqTRkd+4~? zUdMHZ@Ts2`43p_~_p;V|h?IrN zuv~yLvtS5zwKPKH^|qfC2%`742kC_?1Sm5t%+v2}|5_l9hYh4k0@`a5GxNBPJ>EkX zmFyd2qJ&xj|MpzDZ}*nYc3fmmv*hl$a#y>yckk{UoA>Qy*UV))MDKAfvR)D|>#~h3 z&ID%eV;qYZN9#)L@7Q?6Hd`|tix{`GbMK{B=3F)_oJw(l^uN@5{KHg5uK-<453}(4 zqSIGcm+0&5OWX5$`p*l*(|dY#R_s6rdNRFZ7WxIGz{|le`ZNU(k zF8(Z4Mih>avhW;fVWLXghUnr8a=Z9{a3S=NdKW*;UKW-MP-Yekk?rCO^1Jx&3Ix%+ z_)GM{6#|r*7Ut=9@&7CkNAKcjuZaSbn03sN=;FWUBI_m5yEtNwXVDs&na7zfzHLAk z#{oqgR35irN9WGG{rG=zarjRDGR5%<(8csH3$LzBCtuLt$rt2z@)HH(>7Beko}EQ< z3>`1q$#Z&O_*A+;2>m30qf{BU02O96vt2;r4V)N=(qhp+I)7pbP34rGxTS9=5kC2c zBEjCIFlPx+VXDkRsZo%2#@(NGW>Y(TsU3$S!LwV(=bUoT`$sOSUW%bl1vt&jGJhIY zkkiXu@MkWD-u?7-^%gbUd;uy<53^A7A+t=wfXp%lTk$VkaJ?`i+KT@@tRSbADCU2L z72@;~#r$(pUZMr`srP z@1pbn={EJ$52n`8_y6DS7gtah48GOgVXX!g0XmsOCB~s| z5jm-W_-5QG7bvnhx(Emv93GcExK}CR0W(jr5Ci~&*Bs6Ct z=p#>h{E@7a$i?96^d8mYECDLaI_6L*W|{|0F+;oRrGvfUos^0c-~$SMt^gHgJu`C= z{tmsg`hD0XxWZ#`5k8$@wWodWmF-*UtiH@uEL4I_I}h@4MZlTAJ4-G>d65!) z#7Y1a0eYBN4TDWbiMMO&2bATc{VHwe4m#frXP^(c28=}t@C8-?s0h%@ER>8P+XO7* zLa8M%6)C|NSqY#bKo7IfCF9v9pi9QNCdiDz4b}6frJY+Yr+Gp5?%TbqZ#5JygHognUt(o|iU4bwndz1GaNB_p&X!^6zCDy~aTgLy zWz#NFS14QtbCEK9h2owiK!sV&#K-)7)E3+i+ZgNUWB$G^TWC7Fz9txSZ`5nyLhD5t zdY5}T@4hE1xDa}I^>>l4vf4pKfL>-hZRxuP`KFGJ-YB#$-_^cN+p%+>e(6V{-ED6r z7hNyS2v*R_h2SgrHC92W2++mEC;y!^ohd{&i37>Um91D(tMYd1}Xw{Gc%Xp z3_QSyNw9rF`-QvOS<=?NmMGj?tBb_%VeuiI5kq>I*zfHdIFfpT+~eLt_9d{@o<~C*}X!{hmqs{Q_CKjBdYi$#LZKIq5t@Qo>gi&h#!pLnCYqYhx>k& zXcjm(W@hQa^Y!P@!lstj@^Y)P^aOeZc8TKKS4^atMj=atd(YWe3mJ1!C`@5HXlbT3wja5|#A-V;{2~=zAdtEtoXK9~kKWYYV@g zk^Xy%wSRq^@$}r+x6^{AAzt52HLUIbdmAd;|ErUFgT1es`Q4&?ux??eKTz|ZC(`pA zeD}c#|K>_BZ54c9!8z%TI4!w%y;~0hqgq8elv| zI6+wt;Q-=s!U}4EiKaLhZ)+mlpb;o-gab5!iWNi+Fm(}j;096{zXIV9p@IgW93!fM zp@*;@$FHCPl%F7Mpca%jZJ=nt*h*9bsg1CMCibX<9@PW6i*SL)Fn;YOY@im%J%k6C zP7qEY**DTtKpl`;2{Whyb->U@*g-u|ItUMF0_9zV4S0bR#;>3r)b%Xu?>2pt*yeN@ z;lwgww9vXj7+nsm9jgU3+ZXe?mV^FdbPX_d5mi9!Cd|ME#AEmsQ~|MvFaisx0=1w_ zSR;(K11}f_D(r*{)B~xNFaaCz0%Hf^1X34a1vS7JCX{YM1+~C*lyCt<4`By&z$mPx z7X^7AL;ms0KU&})E%1*P_(u!;qXqsyYk@=82d@{ej~~!J|T@<`XyePg&+oWzvYz%GmZA@;6Z18VLt&gq`tWU3ttqZOb*TvUrYt^-h zHK8@WHObYH)&A9~RZ&WMkzN^F8C)r@j0d%#8ceJRt?;c#E{`ntFHbFtE( z2PbJ0wei7m!LizCttHqTY)Uo+>bq)uH3?799d;g7gLb-#ppvc}umlxNP8rkXX+w;z z1rUVS8g5)#N5}u0uFHJ?&*cCA6YB%nqrNpo#!LQ*jh8@0fDO!&#!Kj^3^#gJc<`vU zNHKoEiUAb?I+>Y4&0Tz-4p#^jVLG2?rM7E(XYsMS-a0P0UYMZ=)~{fxdzuEEvsOkY zOP2{(>|n*pv~q9#Fe7NfHNwEjDY6l?Yf$m*dTih#=xw5p-2ad@AXEhCW)>g+++AWD zHgfUx@{C*?HVrdE>22uaBJgeaBi4pc5uk@z!WeF;jo8c;Krhh9HDb#!Bb45Vqqqos zBmOgMM5qYR!z^JOI=>MM?n-(`a|O@~G;)nNW|$F5Z^W@&1ile}%o-6Y0<32i+AH&8 z>G>^L@R&yLIIa|WsYb3P#}6|?=`A^di@>+!PgqMrMSu;=LM=JqctEL5Igu-dUaXO8 z%1OhFPREWCYB;fkRbYvh{pjA2G7y(wF{2z*oi zjGFH(0V>QICaz}KG03?vNS;S0WU+JPxn^82*jZ`4elEOToRMq7Glv=#(y};M7m)+Cx{V?b)`2j)v>UzXv~;eHvE)y+A`Z;udzM%hmy(8Z#Fc zZn<*TR#YVWp>8@Cg0EwW)e$NJtY;QFYYcA#bmAO4Ypm2t&frR*muLhlc@`IfujJ2J zC7~if4>NPw!@#oxv!~LpDsd&A%>~yBGlKP-$%WwS_e)kks0h%(#MzJg2Dz*wJDbn4 zeLMTlyd1QDo;;^W++VS{P!V7?v(Q6Cw`2YR`ImiExZ4nxynNwa2bR=+o*leV`G8rhq0xCcyumKfR z0Vi;QYTyAipcd4F2G9t6pan?Ox@86+12eF+5|zLXs(=$z0}rSnsD!n6EUqBRKshi0 z1z12OumU?!K^1TS7jOeFr~&n$5i|j@gOETOC)GC1+W4eP(c-N0vB)t52yikpaGN}C(3~dD8Nck3GH~S z0tavc7w~`@Pz&lo184+3Af6y3U;yR72xMRe7ElSSzy?&{08UU1+`t2BKpm(jsDzDp z+ys1}1qi}siVVtu5y*g&ol{Uy32eX)R8R#PKoe*NN)urQ6`&H>fE`o;2XKLE-~nDx zOHc{x@VEgqfo4!n$Lq_CKmis|0j$6V?7#tBpc;697u0|{&;S~N4>W@oFd7IQgb2!j z0h9w1PzWla8ILPKC9ncJr~(e)0@c6`yr34;gGS&3EnqY-bP;CY0&d_1wV)m}g0gO+ z94Np7Y`_h?1eLJ-5Ir^l1z12OumLBi2DP9GGy}si!U$ww29>}Ds(=%?ffv+)1|aqj z5-@;rU;+xL1U8@&RKhAeb^;f0122$H5C&iZ3b23*U2dD-fAg&&zAS}Rhh-d+( zql60Tf%6z4^bk$Jbb=7uR?<^Ic?aQPbkQRrOw)_-~*;ZgrPM^jaN}lcV*>N z_xa(H#uZwi=Bp*a;VC1l}H^@&r)_nt>NBTZWdcN6Q+~vIaD& z6F8cv#k_4qGq8pUGaA*wI8Kimfe9_Ew4&`+pzYA8O~4c;Y=?+)G^!DpfDD>|+Jj}s zu?#4{41B0!J*(mhdQ<_tXl?N*A%iN=092)XY_NJ@e?Ux{>bag^5w1`~=|yHJ}mrfPt>BruSK*5>x>f@PInd z09t^-PAH%f*g+Mj23}APd_Y`57=Rg606TC3H>d}Vzz2jbLID-P3UDj49(yPBj_;l1 z+mW~ZZ>Qdhz7=>Y{buaVAeZYe`9|ao{~M{-qpt^EPrnv>ElAn^;;(A2s;?$q3BBTb zCHZpXW&g{mBhe#)BRwy5yrjOAcro;%@5SWd$YKBC)CBLi^r+iN(pNu@|e=_w%^ohU| z>BnP_2Ok$tBj=y+K>U8~{u9wyv^ARQj&=vS)Az;h3*IN*7r$4#SG_lJPv{=sJ;}Qx zcl+;7-4(qna98@y*qy;U#XIA7Xm_Z0Bo2lS`VJ;h*~Op##1H$?GE5`L9b|8@)DgZF+xrzkh$~n&>rwYtmQ8t`1%;ULC(myGp$( zu`jgGw=cOjve&;iwI{kKuqVAcwmZ06+#L^TAvKif3U&Fql2>+ohTMNR65ZCB-WuB) z+$wI3Z_&1>TN0Z?n|+&;T14|}sg7tzpd;NLYY(=I?eR;rOVmpe7l$tPU7Wlqa*_X{ z)TZdBrcFH?BOCo2QyZci0vponW9x(K#r5%Z+B$VzVr^)xZ*6i-WQ~7KYISsVV0C&` zY*lcTxGKIf*$r&?4WWB+Il!O7y}_#|zTIw>(RG|@LPIUzE^ zKOr?fIzBKyJudti^Z#`;s11qwP`$4{Sr@7E*QIKswSn4nO{^wZBi6*dnpgEEJRy(I zlXOSies`)mS{;Ss z=swmZ_^HbeJRysw^rC;cQv#k`!Uf=a*k4%XpdvsAvv}psEZ(raOS#y3Sw^aIy~~Cf zpwtN^PcG*I@U8dXto5KGKnJsU>rE}8^;U4P^|Fju>jj4ypw!muT{+AEQ(5Q6+jh=R zINQ0WVp;ZM)haH4{&f9q;;(G=Kt+HKCRWdt!XEv}`h8g6a{DGx9%{=yxw=T~zp>a* z5ulSdSOPY zcD?I|8KBgje{usCfN#G4Wz7c_0Xmr_G+!w@j*VP!y)Yxze4B)&)UmHW+kCh1@U9h?7-NqVK;C@rGfZ)o1XopcU>h3;RjrTGAVVv@d9W0aQv zm~sSuVv=@yjgm^Yqcs2Dw2x^S&HuNXZh!fjNqUIp0QA!R)9;uh_dZ#AaGEUnrx~SJ zSIN?aQ;pKsn<*y%PQB(fx5c{(sCQIn36F8|nN1hu4d&y7>M-x;xDt z50av(w}WdVz0E%3N}za|mC&mVGeD`^$jQxI0Ddh~US0aY3>Bt>S$r+`?_mme;VoQj zy(}ZvdRvDXpw!mu?Hp!+lJ_v%xB&d>k=W{iiU7ULLZ^^s)1YOtb99yV)nYqW0=+~d zwUSO=$_3!7NXIOw2SSDEWtLjS{=H4XZ*ILixDx0k8mTJwUN+1CrS`*y1}WfodXd2h{hbw?>*0rqnx&`UH@E9vC5TmZg`7FI>52++$cwTk^4bK#GO*KsA# zOEgkd>^(5d0HyZBlh<fN%YoC|1xjQXSVl$&c>@|zt`Qw1=I^L zQtRZ@&0GM!MmAO>s0gr@S*S*oxR?I*)u{i|hW@g{xPNhqNm@YP`@dgrlJ?Sfeh1y& zr0@H!lVs_;^qqef-F`PgmhPhO{R-W`MBn!>pxdwMJO7rmWl5s@7=7n&I7^m3qVN3Y z%#fvjb{VB>=;o%|LzMS#nv>=TaL_dXEwXf?ie8hx`&ZKatEy32Ot=nj?U2 zLJu9^ja|2`iN60g+?ezIzb*IpfA1|^!|Dw^Vr%YJE`Z*&`k1MmtvRR&u!dP^&E@yS z{x=r9YPK)l#s$<1Fj6%-c{>+?uaS#t;T535tY&5|SQ>PmmavVRr)7PAbxs{D63tC< zd;(OMDznf`BbfZmLrnZYQ&{CrW|7lk_i>^0&_lPFUY*QN zOfQ~LVEuP%WFo2Py(|GE1mVX0)Jx&aiNAlnbSY9?9z5&&A-YQ%hBtE{@p@)YR zL+{Nr7N7f5pf^9l#nAsm@6C0z;_C&dFe$k>Jsx5P6YB5nYxZ=uZ|&T&lg-M>cY#xn z771BT0U89TFzcC_!*qk5OGP>G2c5G7b;-OjoO-NC%m#|)7NEkcW)3k!3Fbb_o1r8p z*yBZlHBy)w0V+%{v(Pz@^i>ygfb#Q^0%a&M^gsSKg8SJxoyD8 zd$LHZW{Tn!pu+SpvGNMcbb{Rl&KSx$r81{#PZbH*LV;=os4%_ELWgv-P07z|k`wRg zBJoDC>On<-9%iBAJK4P<9il8yy=RJq8$%)L1gJ1;nM2H3g0CF|=Pb#o;GrTB$Fhh} z5nwHIh#5){ao`LkIT2$;B95mh^_1Tg5n(kGA7=~9M}kc+Z$6U#V7LKl&bX0@cAMK!xdL4lx4>wr+j~61-scGwt(SJU#xQE zW@axn@GT}Y(ex1Wj0jDe^*5TAibS45FsOehE9ts_>8D1id!k8dpxYaNGfL;v9DqH4HA-7QF-m`uXh0oN%L-jC*>!jsp8{uLxx9j<+U8grPuPC7Wfvfz?R>}CD`&i zR`{+BzGsK;BjdmP0j|iFKZi@QDbOSn>7 z{xUAqmcLRDzl!U%<*zl8dNsa|tGDHkeejcJ_>C6$%~9}Mqv5y3R`NR%{B9ZSF~B6Q z_m)4!1>f@bOz@v%_ga{{t}mp%fG_4;_|O?vAAB1e?!W9`QLHrxcnQWrk8(< zE6C;lz$N7J?~q7d{!d&XCfFoHp8}h4@w?n&fukzm=t?-oO6t`ZYr~>( zb~s*z6RO}u2b|=DlW_sPJf#|*f$QkyRuA;!a(em98aNeK)yvcB;B;JEFVARzXW<%q z`Rpb*(+AHHyUBAUII9fKHo)_64ZeK75w@9NK!$U0S-w2i4CmqMe0hEaTu@2s)wsZl zMGI~4LOWcf!o^i^i32Wm!euVFyc({+CH`{I16Sfoe|c36TwM#-)WNm&a9smjFB~E_ zh;X9>Hy~!nHr-4IlKthrICN8u&;pe6$WeRu3OTEBg#1rs@cYOIA^)Hp{t#&)G}T zrjR~D{<#W&Q3ZdAToUrHobcC3DWO;6->R|b-`(&xNHZb-)(igw*(T)Q)x!To(h2$Z zViWma5SLCIT|5geAj`S4r z{~|wye9{hkk)}dEg*+9eQGx@%h{#tVOD@RLR>%f79+x9~g>3Ya*?NpJA(w?L*Fr^X zCCx}|AzR8|1@c?SmF3WiG#9cBc`jtT3{|ANkgJgILUvf76KOAGS0$`Q_6yl9MONQ+8!e%7PkXuAJN`j-y;25ON(5o@F9E-*o z;drFekSEA+BC=}8lgw~3l55CQkX=JQqY}0v#fI!hjt%)tJDiGC8}hU&I2{=`>;mk!XWZ{$SbSiDx~?4 zSBr3s1lJ5cz`d3yF`kkHn8+pAURK^R z%>P*O(a@vnqwz%TWic?#5f;&%t{PE(cw|6R#DLwBl_qu}_#2<0b8+^*d&-X5du1gTpixB6~P z+@jqg-V(bxaC7RW$W6YR5)myTMq=SWICW#>M&FHz8?+n58)DZ7uJ58u`0?w4*QF^R zf&bd%{?LAPfBc#tWh01Q?Y}yCRfuvC#P`@yRomLV#lIy@RIb!(Tn|*Z6I`!N?GrN zo6;MjlxrZlA+$l=5T{H7>2*z%Wk6diu8pk;P>zAfYTxR_DvdG>#8w7Yrh<{6kMi7W zE5sGCz>?JB$l{}mf{W4@Mk%X6a$#tpx-d>T1=5sLz`r0l zKQv#Zi~_-V>ABIl{<+CHp*iZDcpymG1fp&Jw&eLC$|cZtUW)Pv_+}?&X|u#xv2z2I zMIdsH@0`R;jdBRY&JLWNIx9jM1QIi}8RCo>Cp-}uBhZJanRHa0LeH6}8~ zH)h4?^r+}4|EOe3s6}mwHwT;3zNpXdOE!g?)TVf2urb{bZSXfFDMx@>AFm76r71&z zzcyJDs!=IFz;RE6aswpXnp<4o38&^1oiRtik*bPR`6w%ZriyCJ9-y26 z5u4AJuxgYMAXXWu?5a>J;+CK#O}PO4lnWrFs7hQ8QYL_?$!|&;LzD*~ULK@u|53^U zkSq(8sg(6UD5b@y=ogc;iT~O6)W^+q{Qugp$ToPK|35~^9RDA57F0YdJ0gFi$Uw;% zG(<95fC_UIv(P{Z9hRVfL(O@b6Z+*Mq5TxpBS3}eW)6|dUZ4Z)`Ez;ZM0=%3v@(J4Vd8nLBgBy;>yPR2B{@0`xFT7{Sh&r!yzqYem9MqYw=ORG9V5LZ@F) z3RxV?8EjV0oS3f{i8-C3H40E+HZTjtr0cioUp6K;2WL*uH;M$E!Gc0XfDO!&g3@Uw zxf5CB1U*_L=-Dg~R0QZ`Vr63dm;1rA6*zRhvVY2j{!qPfE|ea6=waE@nWW;)VMZu9 zXY;AIxCnX!=)=ALmPP4)p7fp4;NS(8CUfF5QEJJ`XS>~mZ=J^aWu z*@wf7Pw?>^~^&1PX0||@OJx%i>a4k}9g&4Vp`^qpQl-_V(o`01Ye^7)uly%3bT$`=!6xT#{nle;e-`#ii4b5eawZ_i!g$<`h*L?*J=*c zXOsXHW<9gec`?~N>R>ZBMf~HcIQ3nxsF`asS9HI_6LJZ~WaTEuCnT{)2MVt6J#$|If3>|MC5QYEz6+kQ3^=MM7OjK|BIfm~LjFRZl4i z@%5ihmmB;Hww@x<7EzoU;s3CACg5#d*PVawfdqI-0>mS@uYjo4mTf|^gsW463 zw5g=||L=Q`1TO)CQZV0q^G&EvKk_YjXSw$+xbNI^NFmuSIokGP{b*XjfNB!L0_(D6 zd{Cc8IUaRD|p6On6Lio6a`GySI2*FiUKA*d-1Oo0cvBcK{GUIq>v0q zvN1~JFXKaoe0EaL_8*p!bQNR-HBv}6NtTji58oAJD=TRCBZ??Tbfwz;L{1T)dhKdh z(WQ|>vPp6hwv0dD|3(qzh^~|^$N&2&3YcskKJmAT0M%L7z)igxDI}XDC*iE|C;X2T zQI6<}IqUCEQNU!Kb^Py7QNW~6_>{ukr_ zkGkB(-5pVg}MI=@&7Nrgz*C80BFGPx1Yv3)c*S$)clK^ z9z)kX#xwZ-Kl2l}p$!|_lGY<)D&qgE9J>eyML<8X` zOrntp5KX{{p3Pj-LbMVL_7;rw77X=L^r`OZ_!Hxi4dV501U!KR1wvLoA3}d zgdl2(I-;KN582nKKq#%~LTZwp3m3kGis#%>FSZVN_k3kGfr#%&A6YYT>J3r1@T25Sq(Y72&H zkLbyWZNY$T!FX-KaBab8ZNXq|!B}mg0a{mdNL$iFd|zpAX_jV zTQD43FdADh7+WwFTQC$`FcMoZ5L++~TQCe;FbZ2}hXI{12p3UBR1n81jhja(BTnuunig=i((h<2ib(2fE+VGu5&il`>sgomgh1W`-W5%q+Z z@DUA!pD>9=B0w||%|r_@qGv1Dv=QwDBdSFw!FXz65H5nj)Pk|pf}zyHLokq9FpgR< zj9M^?S}=%OFos$%gjz6yS}=fGFn(Gvd|EJiS}=H8Fm_rnW?C?0S}!Gg_~eZ zv|vcIU_`WFK(t^yv|u>2U^KK~FtlJSv|uPS?mYklp#|fh1;d~Pqo4(Ypao-~aqj^b z0WBB+Eg1hS82&66{VW*#EEx1G81pO`@+=tfEEw=C81FoyC&Qivqn-tWo&{r`1w)<% zBc25Vo(1Eb1;d>Mqn!nVodsi^1w)+$Bb@~UorSg<&=f)UPw0nUQ) z&4S_0g3--_QO$xu&4Mw_f+5X<5zT@D%_Dj;u30dwSumo(xWF&6OZbQe!cUk) zBf*M^qKRlGT8LIcKL{9vi>M;12{+*(Y6t<0=vm7(bwoYkC458!;U`R@kq8h?L^IJs zv=VJZJE0#248lcJ5!Hm7@DMeGAZm#^qMq;)KB9r}10#BxT+>Jdh$f<$XdzmOHlm%- zj{pYYBC3dL!cBOH8bT1YL>*C2cnKfTK==uhXe0te6VXhx5Us$7o^4#CYa1Y+a1m8R zHQ^>aL=7Q`TB44qC%lA@XdwKANi-4xqKRlGT8LIc^8-3z5H6yMs3zQm2N=<_hHC^- zOVkndgqQFU4TPUCiAEwoG!et{*&Bhl_!;<`|7)4gQkRYKhZx)e;h+xedeS1N1>0hh^-HQIrm}m!^nsE4^kgQKhQr& zzaM+wM0|bxz0iBvceQuZ@5J6Q5nmsFJM?z;t;AblMA#?ajJ%ouQtC@l#Mr0bh`nLH zkwKh&D3v{!I2b;dL!^D=_55q8*P^ctzZ!luhe-R#EBTjGFGpY25o;fN$$TmEV*JGr zqU{qegkQ)#pL{-oc>B~BqhHj&n0_wyocUbl+4!@eXS2^(^#RSNGs$=|gsA((f$)Lc zQ^}_yh`Ucc8GTZJGW|phk@uO$!Bzf{6UouIR4eo#CCi9myRL zMC7O9(YPK@551^eySzW4D`#&5z#}x-Gj| z+nl~NcB_fl{P?EOrtHSV#xSDulY@~-)&(5CC45T`QTmaa^Eah#ir%CnPCs^|d1K~= z_zfXM>L;!bU!S`!d0hmt`l)N9*Xq}%5wCAvles#6b?EBsRoYc)#Os@DGFQg03|*N; z#C|xMTb*1TS)E^%S`}TTuS&0stuzs}A72q#kzJlx9!A`L@`}h6`O8y?-5*x!0qRTA zi(`w;#Ti8JhZbcQCKiSl<}OQK7P%~cY3kDGr8*+`V-YiwSrA_kLJYrlN&4d0#pcDC zi{gml&t90gFnnR|f+XVj^XI3|kDjlepGG9Vd0yt+__?8TvxwynpOc%PoFAE=pO=~! zoi}`T`0U)=0>4sQ?iHQHWFXYR56W*{lSD&np)aUC`i2EN#)PGJSMMUIlQi%K4Yto*W z$Mj?n`5$s;s}t4X>KtPKBUO1<$`y6#i2jcmrjgO(dPv6q|IKCXxoP>7KpDc2jvuWTs~UU>-9(6Rtp+?q9nnAp zh*qNO5H6JkhvWeoaJX8}LSNGNo|IvrHfnXq_qOjvx!81MvDVN_=&P4#4O6sbT0_&} zLF+L4@VQ#wKIpd}PI}Qd2ii`%CWMST4m z{|_9s`Q&sB!GeyGdeU7dr)AmWH4ocOvJYOP&-x%8ay$o$uWxmlaAbdY`9=BJIq>xB z_$!1X82sUJ+D>x+>VBtf9epM~e&EnDt@?G}Qr}W~t&t*|uqrV1;0i6E9|n4luExwv zq7Jo$1NDRts70rN$?Pt&r!@?tFL7JLZ z^bwl2juru;AEOv?-+tSPbz>KOV;2Ks7n{c}azMA>P#nuGSnL_Q7#h1cZR{ckatl7| z8oS6b+=8tf$SqjpKyJYz$8ZZ4Igneh$bsB~MLC8$>J1Ly7Hs7xZsDSJ>2q9Hec0;0 zwkK=GE_%l<`o}H?#x6FZvsU9afs0Es`)w!DLul-ZEIEHhz_Eg(1rjPA&7dyJOVTkokR~|90jV0I>JXZ5v@cw5hUuJcC@r_7`xaqc9Dbs z(x2AOy<-=rj9t_n=UY2hja}q8e!-zQj$g3If%}5Rma&UHPCHsh7EW7Oi!E%6PT3Z{ zY=J7e*Gsezy@YFkrW4IX4^cG)c!}mCKri8@iyDYFB1HHdGc6f1few41wb(ayE8k;C zL#(ZQQ&F(UcM%1Py^dYh&b5wR)?(1v+9hoZIg8zLaf-9pBNsL2v%PXrcNT+k(Qp<+ za?!VXnO23ndaZ9h?t+#Vd$eVmXPPgBi+B>3@Au?G1a9Z@=?vYxc4(3O40aja0qc9P zz7^@pG|yu=VpJX<0iBxZJ2aq~{{9$3E^#08SU1Wx+#bE1L>F(SHMmiF>xsG}fPo!r zvWpeP(`^`AYiJ7&0hi($P=Gj_)Ks41bvWAo)S+{pkDIce8IN-#Yl_ zCto^*+z3Yw9(`SV-Tzwf)&5r&yuA9Qfft8f2)&SfKJk3``5f{eM824RF7;d#IS|s% z#-25w%{&uF7KHfI!^r~&4nFnClZT!-{P>YC9DPiC%>QWck^YAlJhb{j{lPS{8<-Dd z?vLLex<8Bj2I2d1iDV*@$PcH6qr>`e`rg>RCUP9a_lNdp?@8Pfz9+XYxi7LWe|HL* z4)nXzcg5~X?>)5V@SR8QIJ#Tg?cWvL*}r2!eD%=4_MvUVTMukGc>5=}9ol^O)+3va zZqzpV2ZI~>*DqMNIyNw14rGv>Ahb4nOX8Ot`AA$9zACpSxhAqEe`V^*=#~1F>1Zr! zB40s#b!c^VRbo{b84HptBP;VOQY)g!SrA#CzWm5C|FR4+6@->%mn4>im*kMEAhI~W zD77fMNJqAU*g|t*=Cb%@q06$DCN2$Mnu{bO5o9b#Er>4A7o;zVA!kA6;`qg(i?hgE z5WXmPVX|<%133%Q=f=)Wo|B%Rm={K_g5=rhxv@FsoDA|5gu>bWM1QznKPz)a{EW~U zS!5^(&(58mJUw>Wz>I;Z1EC|m13d%n15NlgEuun4CV*H?+!J^A7a0S{>Iq~3(6p`o z>~+%-|9`{%*7yIy`Tuqt#?O>62`6l#QgIl^|K$_~Og1#;#J?&6oC}H*8-5EyJf>=- zkZhNnY@o;ZV4{Ch&y=CPljqJYVI?D)T*qJX&?%WJzF2V1`pW+KaL&*h?>JK{eS z0nR6!CK*6u^lGG#?2s(gB!x8})((v=)?xSJUnl|{1uE4hC;n3rpjs4zEmJg7NOnk0 z+M>~LA}2oTm?F?opi&kcKYoe=CfmzSoKOU)E?Wm@P18sr*&#V;myJI$F-=hZIAwJl z1uEt;{S*aE)@8?yQxq`i6Vs&#P}^h!TBAoJ@q!I(mn_vLW1{>p?{<8=ZIvR=kzc7M zIZ>?$Pz@S{5h0BflI@a{HE8^4=~m=9@+)P~aU>@l(}^c5V6uJeM2#Xq_1H%EYN|#G z$#%)fdTjhzDHM5*{EB(3_7nw7)?>%(PEo+5&&qm5fZ8OtqA_|kQb=}4mTHp1+hvJz zU0y|?qd=wF)Z>?eQ*MWUlY#Z2-m0#uW3lZ`|Q zjqH#tWzyJ2DthfS6@iWd6|<;O5ujSM1y)SeNFmuRX~o~ioSmKD!}c8YD+gm6V(YdH zu3fix*WgaIJjL;VBGb`fVxx9yo3*>NK}~n0S-*#?H2&MU`L02(upd5~6cNs6oQKb? zFldHG3dx{kDYM!z-LnljnH;kQw+wC_+_r1HWzC9MM~wDO zJK#X&$7!%@cWmA@L4&m_G94W%XjYpd!co*|upkyht>;@Y#OKGqnXVU-i zc15hC#wl3#AKR*p`}cc{;KiuLhq?dDkOScR`>fpmzqrC2mimNd654f@&EY$jYWU8eFnb&f5VRd=lB09 z+P~TkE`IuSC~i?(BaU|H)kq=PBUviNgPqexrg+#jxMS<)ZLwX08`R6fiOw=YcR*a9 zMheL(lBI;&RT(I>oZzl9f_F=6NuiOgl4~*iytzmMH#^tB+RfXxp|sYny+eZ=H}9bX z?VD7$BF&LLahF@K?b7yQcB^{ztJe5$J;jX5IMJiXP}}bgSkbAGLb5}$ltuP^%C=~5 z&-%fkUAu0L71Z=Q(OX8~62Y1=q>yZuq`;jpO8FVKs~fG|IW)L_=dK-_w{6-vYTU74 z8Ch3A$_$OHm28xxtZkSato#fM#Nr_-<=SoAcip;U`<-iLO)LtYX|I_zD*8mIjOf)6 ziYfF`G}$Qso2;Fw&kNx5wHwk+o}9 zFS=~aRaY*%VNqXUm+Vu-IpQbol6&y<#(!#;)Uig_3XXqls&afsJL}?Jt?hw1{gPhE zMoG(UyPch#-@_;>IgDyNYq#OlE}A#y*t9b8_CnrVjr2-3OHR;C!>v{`St7UZlE0OS z#W@ zmu=s@ZP&~ozk&s46}q8c(a_O&VmF-37rkR)MTBFPpaaI(KSxo{QMQ8i&s9V?7CH8R6P7R3NUvm@B<<%HLgk0ahlkIE z{dd~m2a9z4(M_{ui_hXQ>_^+P6=fXdDroOKMTBF4WAE?4((5(SE7>hMsZKv?*|<(W zx(R1{nNB}n(a_Pjf=)O`5urNa_hA0j8tIknmYk^5U*dH7QA;Ou!f2D@hUU06W zouh399dMo^LUq8O!1S<2dL;vrbif8&{FI+z=cc-0ki}H(yyjbnwyf0-I0FU8&MzbJ z2at7^MtUVpt?!2}BYmdFSc&m~Pkthd6&MfrV0Nvs6uAI@{V!{b>n_0WzYxZC=ev#1 zXVn_f>+!w)=QYOS?|O{if7oN(Gz0Ykzf)r@`C^T6XgAish2;$%W1tFo{i@tX@}DuD zaKGF5=u?kz>9>$40CWGhM%=~;%>94pfX6UbV?V#H9iD#ErkRNU-}q3$gZka1m3zr7owi<569(ZTs)%aBO?ZeJLJ+k?J>er72$Kj9%|t8FPIM8*YM_d6 z6E#FFQBO1wO+*XPMsyNgL=T}209AyW5QLX#AR37lqK)VzdWjIB4*}JLho~idgr8_6 znur#nm1rkAh%Si(_^X=;652t)MN|_WqJ|JeEm23*6JEkcG!TBGk!T`Xh*qMFXeT;| zPNIwGCVGfoLOTTLL>1v7Y6&mlCjvwZ(N1&{-9#@DBtpa#LOTNJgh5mhZlZ>$CF+QJ z!b>y|jYJF4O0*MQM39(5xQ+rILJ;+YpJ*hSiFTrs=pm*MQwbf9F*p~1D#An567__S z2oOy~Gtok{5^Y2~fw%5BJkdpT6TL);=p&{QdJr%O7g0r26K=vo)DU%qk1&ZQqLt_% zx`|#QMD!6;iD`t6NLQR-fQzUiJVXsqOLz&BXe645R)V=hT-`*Fm`Y41i~+z+Fy)7f zi9TG+?BQZk4;NE;xY`J&>u_}uOw!>B5>tq&ggyiqgo~&q+=PdyAp}uJ)DvF9M>G(A z!Xz4r0MSIW5KOv(lL_b|m}SEiBtihL(E0)VZ4gz2oA3}dL@iNIFr9|WM=+Cy%Osdd z!xbQ!h-RXNVDbzX^Jcg@3Fghf84NIQ2F_qWCk(AiA;2J9L^a_dnCrsDG#4(Wxo|PV z1M};V8X@R5-z5daCr%)kZ?5;OdNre8fYb$Cc?!u5iVwkfQByoa#a%^ zqK2p?>IpB=K$t`$(L}TmtpqbZxR~q#XDYyi4mdRdLDUgm!cPQ zn2*856bv}|fI0vgdigigEV%pxGc356T*1{sv=U6I;L;ZWE`m7}T+E^1sv&9#=1Fk* z2_{BxH4)5-;9@!i7c(Kamw$~84qVJ|;9^n(R}%mYnase& zJO(&hfhvO83viAC%vs=K&H|jC05cWfd<2>aCM3Xp4PXue7t;^8stGs2qysMI8*nk- zfQzXHT+A}yY9yFZz{O+&I9&kd5x}hv@DR)%fYU{4$ZP>FCJMmm0x(AaP8Wdb0dThi zm=6Gb6JP=W7w7(?g94oP@8XPq7w7rAIIG{q3H|7s0O#_%IE~-M8T>BJ;CEFM9)eT$ zU7W3t`xL;5`Yz7VcX4Ju?o$A#;KPTUfA8Y_dl#qPyEyCK#aZ_*PPlh*uDy$M?OmK^ z@8S%57w6TxIGY|_8Q>gx7w6EsIDH-+8Q_e07bnZ3BLkcw@8T4B^k#rl{k+~l9&55 z`DyUeY&ww+r*o*27x^Uraq8pf$NIuc3Bc?4Wrt^LqUC5US@TUJJjLdo}rL1oiV$uS8$bUrE0lLj}Fe zOYxUNFJ)g$poU)Vh2#s77xK@iP(|-Z$td#d(}}0UPv=lgFOtk3NF9hC&{0n>_LTWl z=E?YzAym{$JQ054P>Ff{`lIPbVvm@ptQUVc^lVYV#>!t6H z-EZE1@V@AM`h98C*E18D;rMW9IExB<;d^uYllvq4^Y^6giQc2%lin9YoxRN6@w-EJ zXYWd&(q3+Fa&KgBe$Vip@SYrM?M3d)-;uf_dWVi`d$HZ-?#!X0(JOuYm;juYxB3HP>D~!C4F=3X7lC@ zYVn0`%HEi`F??h0h66VQCo#wWayr%`eo@$W0#tjW+L%OD3V=}K()Ty zCCN)7m*g)_T^zkwzc_tS>>?92`{EadF3et#xFC$GeaZ79=jYE$ofoxZ;LUS0=fqLD zFFQXmKRiD-FNxZH`Lk1JN6*$76F=9So0$`z6Pl9^C&J-yu0PoyK@GpuS<$ofv(l*I zXP&7>$wyAlpO!i;dYb-A&iU6-*Duy<_GWtGJt0)~OLT|3b6v@<2x|MKI-{L>XSySX z>VBE_czdWliwb|?wp?qnHPV`INwq{<^pYJK&6F8M zrN6X4<~RMBhB#{dWqk=>*q8GrQSC2ZpQ?}6>!|n_t265|wei{zYW^ieSmbJwsE(cY zq&!iN?n%32sQZ_xj#r1OvsDRH{>!v+(}E z*8cv__y4_qtNtIyD>y1Lq>Ud7#CzpoOtD%!gfbc|rJ=s=x}eV*M{y!;t)Y4BnkUCDRz#@&`xz`bT_e4cEs~}D$JaD?$16kQZG+&+0*fwD#5v+C zXwd>igldteR?{xfNUvm@BrT%jlpi@3-2;n8;|hk&aNh~Mu}D$VQMXA=~d5+_7Wx zhQWe<(T{ib&gz1;KenWd8Z)FCq*o)mBqyiFdc2xn7h8Y3qK31&P>rQ!)R+m;S8JqK zvP*IzHO?OC8|$`gUw`|~Roe>GuwLFe8)gT04DQ^%d&m000+o(0Q&e(PoVXwGDza1C zJ}w%@Ix8GG1!u+OiWs#Y%!17~YNS`PPqLKdJS!q2mTyD@Fq~=krdt`$#0$ul&D#cp zBe6!oJGO7$fW^hw@hWS_nX`g--&3I96=n204VpzX(kt03SxP?yZx8ns)o-j07Zhl) zyo?63A$yHRdL{cLsR64%C_lrFhvXB6byFz_u8}uRIK(=SM(;VnwWY&uR+Q2245=UK z)yOH5mVV=(w-6;cdY zloe4D8=<9hhddc=SC!GWA9}9UNU!8f$x^;Vo$28fwl7O6D?NHDx~?vx>l|o#i$;1S zr%O`TQup{}&=u$B9<=?=otqgsUl4k7W%01{nW$!6_=%b0!VjW~o{ruVU&u}>{NhSQ zgmcn4xAwWx6{J@qr%RrkD+*poU+cuFj}7Q9?}{~wo{rv?bH$0P6cMT`&Vl&>jr2-3 zO41eEw4yk$*gr^}Xc8)n$a7i^I2Qq*t<8(h@TMl87%sP5`PR=bAEd&Vz(D zjr2;QNHhMXoD#8&NHJ3o%UEF1wPhrokK?v#q*t;uds z8tIj6mn`KvCq!BK7C?DLetz`(Ze!nTZle*k0pEYZZ7jMO`T7wDaQ@@9#-Ab%;H)py z8u$Nht?|b{t~Jj2u`r&msWqBs))>1zwTACb)Df63jGrL}U@QK+ce{I{quti5tpDy9jccG}0>>kfgK{5s{h)EiOX@ z>3Z9y8_P(!7{_nbNUvmzWU1!H_d(gO(A=t^o5~2f1R~ls(ks~}S;~2K{V40nL=|;& z8Bq%$B&3mENfds?-xO8sTyaE=-fBkOcl;Jblp}iL3+Bm1FrHYe2yxCF=k5`K_ER;| zE7>hcdrCwwBCF202*v`V1{8UY{E3Y^nH%DXm?AD5TodMVlS+gbvg&6+h+%;>8x&EF=n7ghsEAOlSqM9( zYNS`PTXIr;ZuCK=z@&|eJV$;7P1>Z0P)%ASO(MM-*)2J#K3CMFTNQbZ{0f@1SrMU{ zv>0YIX{1*&AW4%-1o+8&gnZZ^ZJQIfm65Up$8Xd~ucRqSDJ2HXF_@){B%ipwjEto? zdO#zQgHy^QEg9pV*sM@+>uXqnAzR7_S%yP)X{1-OS+bNN&SRlHHa;rn_*O-ZBX{DK zKbc|i6WbIKYRg{^Bf2%xE7>Ah%3scXn_pWwEM8#Cc14gQxPrC}DI!!`u7DNo8tIj6 zlcX&r2E^r+b98WG)S46VGNP7Cw~=0r?2@FYV&6&aO3?OrgEM?sAZ|w)aVw-a(yNhO zl9LnX3=FHBNQ}@WgIK3^m}7^Z2t0 z_Dt1CuVkNODXTEPg@4W%kun0v!`ctVca)L38uEe~>6Pr2EG5-W%V77E0;vTO?<^xR z3R$fh>6L7eq{L#6t8X$M-6N z9YrSYFem#W<-}cz7;3;Dr^Bp)WoK%nSF%sClzn46jPfFdhqXG)@w*kNjusU*Zl5BC z8t}(4?rNAdRU^HUeUdb;#AvTP8;XwhYKNS-{uB35lbFPe=TJ?IQ*8{|A<8Umsd5 z{p&ikjM-xQkdAe!la5u_HS_QynXli-$rnhWpfYJExhcRLfG`j8g2dMT2nBaJ)`z=ZWo>EB@|U~RxhJ+C9@>ul^Gv%KRV zE%+c(sE-yV@cS>J$%rsUeU)^CV+h#ECoEPnN@ZlQoB-b%c3UagAKG2 z#u30nv>uSDoBKw0g+ff1FAEOvqxO=T0Dm+M{x5xmCcjLK|4Zo50iRUwhYd+4xs`5e zg)fjfmu9@^v$EB9VwE2|SRU%-4ovD_EB80i8uhX%tOWVmg3Gl!YtNoTS7>!_+WWO2 z8ZO{Je1+zzfZi-j#jtM{=)0J{dHio(9qh!vw2w^G$4`k;a1 zTP_J=71Q(EdJe!PP|!DD99vIHGbhRpt(| zI0IyNLYqJv;ubw)E!7V$FK~qml?q(b;EFfw?$UwdU!Sfc!yBzz{KrPWi1c_GUq!!&r7Rw~l zxY$S)rugCDCLDqFN&3*)oW|_Ly7o5gjZS7KtAITA4)Zt zL^VF%;3jGgqn3&w{7|65By{Xdf%|bF_*!b>!n$@hQG0YDO!dvNR%?q;GJt6I13{wZ z01zO2+A^eLM@s2BF#woE2cbiWYF_bR4|*(`lGkedz=%2?-#U8Vg2i|Xa1g$m0#tc> zyjCi3KX$3I^LD!qQRHEu6W8&&M)(8?;elTN5>_|>YKMTX1Auu15JO9`fd~-+m|WL3 zghc0^MAfjo($29D?-{$;V-*K+wpK5Ymqcf=V_?i;2v)jzGlEqH{NZhZuHFtpKMJ^s zTKU&uoMF~UX=rc_O0b|AtxtNe!mK0wM3WzABRUDs0icfX5pJ}kSp&D5_&TkbjYJEf z`4?***8E_(5#BCPv&Qzili|E+7@5YMU3k;wwFAk~Wy8pw*gU?~*lV=%N7WHXm3Ql3 z;a48`l?Q(1fnRyxS04C((E|tWirf|5o4;e?`4`dcscq41`nL4e*j96E22~aPw+C5Z|C=Elrmd@wYa-H_N2-jG|LTpwAVUzb`JU6+id2V$rr5L=tNIeN2x zbNZ&(P3BFR8{;>IZp_}0xFLK)?0WP1%yo%t!`J4nNnR7VCVzG6>gd(_)#=__Jaq%V(MZeDJpQb2x5WJ!LpzBs)o zE9)R8FO6Ipj)WFOE@92XG-f}<&Nt7`oEJYYac=nB+&Rf}BIo4ir{+iJ>+_laKPzWB zB*Llw_*uy_6KAAP&zzQ+6`qxwnVcD!8J(fe2u;sU%g73a`6-bpkx(=k?~U}B-ACIF zH+?cPk09(zc(a%>kQS&2fXaZe>U34qh~q1N!)t$WcsAbuzh!^_m+}9>pUKW+XXYy! zbH*L)A;bM;21%~P@W^Qz>6M%%S!!qop=9_sVJKOF?0d_|z7A4nX{1+jrevuB8U%*n zpL|DCB8sg*Gy)doPpKIWH$dna8tIjsE=keF#?(iL6APoZioSeLD1seDCLVD+srS_P zDIzROM@QRkl(vyxjhrrda<&zHd3e7f*ioc%wjFyw5i!;_UE2(M9*{)hVf^ivq-}$U zh*W-t5x_fqIl2tyi6G4pVu_cB*RGL4!)p;*ZLOUhw4(232W5mUgQ@VBOr#R{#UAs;Cf<(q*=?jv+ST}($))n=IwYIn~WCX)RzIa$s)KR>G zzIa3tq59%>X*nr0vR<-OpGVf=;Sl=8X2zF~=@Xl`!3VR@7nW^XTM$@&?9npvw?O6{ z8i`!XU_i2zd?pCI#FAgUYeKPcy%QSoinDX=_|Ev4qMf5{1smWCiU_pxN%IMEanEgyRvCy&^B)yBc0V+g*6Dj0C_JN zO`2SAIXRwGGcgiEh=$3+J zpi+FKDtaG#QPI%RxPtBQk|IKFhdW^Sy&8!u|IiuG2_`(`vIpY7{xv|z*i1`24Z>TleZ>upr zKhJIa=eu>ri--gGmnF5v_DwZL{W)&q*2T3(HR1p^{YV&pUsYo~fEa+ke5TgegBXB6 zc)Hfuf*62*PNH@IV*gw5`;|{TM(_~g|20FK{)5@?pMmfHKX`OB{=YN$Z&G3F`~9(3 z6bCuRIA0R(M6*4mkwUUvvQ$Gdlk6>Hdou!cik)0eXXj?SNoQ{v+_q`gt zt%n0=Yr&~_{8dGH$CygAt{nmM+9`?Hg0GX?v`uJ&F+a>-j(?V&++sJv>xvNPLrx>? zf%~7+NFmuSIZ-2Q7<)FAY6SaaE87Ux=`~SP98^qjOsZg0q)ti1NjAkBiV(Fa_M#E) z(?}uNE;&(CM8}>F8=1Pk$kolh_;YjdOB|-_7I{qmlA^Dpf93ps>`g_4>XN(Qj7Kz5 zNVZE(v0qmQtDH5IaXy-ab_H zLVwpik5JInf38fMf5LvFIMy@}5Qt$ri~{7V#UxZrdXJj4av~ z&bES6)xM*Reuq2dRyzKkVv}QI1^e#%iU_su?w4*Og+{hWPR4EaSzFX?&bC6gS?em{ zwht7W92+a>wht8%s@v{`t3J?3A=xQe%5BVyuy1T{lXvQ(zO%cWwS(3>|LBxNoa7z+V?~JCM8mR)NTHFPl9Op7yZ4rE zqA@#^Xrh9BPP&OcQA~48tzZ+SPf5f{Hqobw5VeUCXqHzsQb=}6PSix(#-2s;iDII& z$l9UsGE{K-aHD!XDt+F3MKQ)Pu5yiX>@!7#>aY8xzeu5xosyIBm)#pn`)kY&s=o?0 zPTpT%Rg7_rtDwI=S461(x*tB;qme?=FImc8d<)3RAnYOI$H}a<@XSQdH}ZkS(&CT* zS{OSpCh*n|>Wxb=Cb0Xj>J9%*ZsW@s3;6!8d5x_%xQ$xW1vu*)UgP&L7Vz^WUgJ58 z17sF^jenZvH7=Z2XZ$(F0Qxr68HX?i;CIy-A0YmJDaHXF4A&dMsN49>e#HMDt~37r zuI!(kiTMA^A1jFeU$9bp=g3u385ioKEQ)&;GC~&-iyb}&rM`*iMZ}8BbsiT{mQ~;wVOD0f+@xX?2fzJ8%#gn{Dsv1VA$Lt9Tv9tVQT!(vAwQTD_7n z%J0aSb%amiA4TEwGOp8u%?&bW(q{#vdp;RNj4%VQqtMC<;^y&|N{#p9qeE8As~x>v zgZ*2r$mlt8ckame^J&<1pB<^~#!k&vj67A4F|+pPjo~$#=S2iR^D_pV#AynQAC*%k z5U|-dv_=a!5vpzdS7~AnCL4sjo!$;evaIOD>IOvDj;vs=Tk(#Z&cH}eD-yK^VYdjy zAHqL5@xjLfSV8Xe8rsC`lKHmjYj zXMZY)751n4_-Cg)K$U-`c9s{8i;%0hvBkJ z1>EOGx-8EdJ_GJD&`#DAfnJ0XH?mhbUDoM_8iINcdsP`WO*6( zZh76sMYa(ITaDd~Rh>2c0298~!fdB^FrRvJ^+C+Yu~tG~_Lcqiyag7a=^Sm z*rD~t&`PbjW9Ul6w4*y%=Ln{>$mZ$7>K1krtFf@u%S7_R>hT7=3a>*w%*~NL8*v=7 zx1Uyre&4_*nuhb7A{iFVUMGC-SO@fPbUgGXHp}@16YL&GaU&>*r;`W}VFbEH^w5r}yk+AhU9#{0if&~4|-?!&Gojt*)U z)Z^3aGSa%S$FQ#&Bl~->|BN>5-%1mQq%3wE8tYtR)z1X*nG%Pe{6YMbY0amiTiKqf zoI1#v*L?H_cnfXLy>LB-mY5DBPZJrF4x3xC%e0;&xCBm<#}LpQlWd%QutzU8_BJ1c z-`UTn!9Gi3pJlJ?MdHvZE!2(qJs}hGdqOSP8z+3h>;xRA4*N{&!9LRh*k@W7_JIwf zb1$lotip6WZ0hs&1Fbv;^u<4(61-ojNA%%{b9-^bxh?qE+zx!A&$@_@%!+{APV6;r z3ig_3;JEWTvDXaiVkLcModwwEoIdPxjtBdk(}sPT#~-N?d(8-9uNfVXH=`YUwW~*J z!9KG>*k@J`_L=3yVgqg#>=kye^%(~@Td0IgOR}7x;^W7hJ1)C1=5_IEs|vL49=?GaIg7}!o*--| z`VOtdwcoyGjGU0HC({?gYwJFyh{se6_CP#%U`Jj94E&YE6#(rq@)4$yKfV6Ipf+{% z6vB>$mk*p?wp3wXEV09c$DYKY{1AB-8w-|?9N&BL$5#*0$m7Z@E(}&THk|zNOC8Eb zIXp#p_n~9uMZxw{-O0--btoqHpT=2&Jf-cs1)7uY=hCR}SO8#I6SSI^#5UQ)_ynIz zMlbN@Wc4b22$mDT2_t8>jG#=D>&3k_|Aegx>k4Wb4fwJ-kM z$@;;rA#CgQAHG~px#Q!^$b&sDH1c3g*x1!ZbP>J86hhao(7LJ!K{#h6I#Q{|E9!ac z#4g$%);(N3Pt{$Ex0<|MjO==Hjmo*m6>RF_9pL|di#gx9Pv-Z*-;MsR{=4b##lB~L zFZ12_cSGNeenuPkbK!s+KlC&U_U9aQL0{TUsjo zy7qGVMeRA(rAR#$eM)~S^+fdX_@nwm=?7yEhVF~+kKJS5li3&F7uuJ-J8^gT?%Z8T z%ty%YP3?{D4eiO^nYc52XKr_LcVu^d*GOfEcz!4~6dlTKOKyv7%Wuux9=| z=J@8&=IpHryXr$~Lv%x8U3i^7kY1a(x&M03D_F25e`Rb{WMzIuXhn8;_KL(6>1DBH zxh2UZp+)_dh8AQmiC+}DC~{%;{KWaJix4}at<(LH9h zrv2wHUi{8kc>n*e_V<6r|91_KdH?^lKC6L>2fFLp0~jQEPEtrVNtPNaVKfW2IYT8S z-Uwk3Wzw&N#^=K=eEIYBGTJ`~?Vr|2A=xTfO8W*>dv>(9N85{!_l#^T91ycss^ehl zo2~-wkAFka-m#{FBVoU$h;YtEC$iun=^#>QWUJ(49AuCE6?f3c#zF^KD^JEjzpiNS zSW`g<{e~h!bDLTZ#y^Q67aC z9?(c3iK6!Sdm>+~9`S|UHH-Sf+E&nKt!8q3Q7XvnkfN@meg!>}QADU7c?|YHtC2#o zQ?ist_}+1F#3Od^kgv6hx}{(T+c(a8MZ9+$>!OK5gubQN;Mi0-Hy!`>DTz4Aw^zTd z2vOVO3uuLxG*U=*N>0=kw~w@i-8)OSMZpf`+M;~W*6%2mIF?ngMZR-NB2KbJ{)-|+ zZIQ>(77uHrknEJ4s70+Fp zLL-G_r{qMQVR)x?SFyWdY0nhwP|`CKg>e0@qP$~F1^x416%nd`o`h#MYow4gB}@4S z*)xaxNBlGH{j=pZCydLwaE_gr^Lu5~c?yc$r;$RkO|q0aED$q#P z9G(BBsOzX-!3O$$MTFWw2jGj3G*U>mNlxSu2HcG4z$H9l_g-bD4xf#zEu#;zMJDS6 zClPS-2a0KqsTK6zVMT=My(Ij0t40dRM#)m%L;A&n?mhm=-|}kVR33P%@EJE-MxCdj z$goBV$#%(7>M+=xbxAC-b_Xt{)yU?84nF3SR&&nM{Oj$g?Bm~8v~{#U_4eufVYRXK zr?tjkAFDC$#=HN6zu`45!d!qSe^G0k_>UUn6}q*39PpHLs_@ZIEQ?MSpU_ExhdhCMr*ahpc3)W*7tj8`m zelA##U9=Lc$1YfpU9cXzU_ExhdhCMr*ahpc3)W*7tj8``k6o}HyI?(b!Fue1_1FdL zu?yB?7p%uFSdU$>9=l*YcENh=g7w%1>#+;gV;8K)E?AFUupYZ$J$Au*?4pKXJ$Au* z?1J^!1?#a3)?*i}$1YfpU9cXzU_ExhdhCMr*ahpc3)W*7tj8``k6o}HyI?(b!Fue1 z_1FdLu?yB?7p%uFSdU$>9=p)-UO~8sD#Ams9=l*YcENh=g7w%1>#+;gV;8K)E?AFU zupYZ$J$Au*?4pxkJ$Au*?4p<8YYWjwOeORnU=XawE~bskLhlDyk6pNkD#Ams9=l*YcENh=!X#LaT{ID_ z$1YfpU9cXzU_Ev*m0&$~VGICng7w%1>#+;gV;8K)E?AFUv=OYwF1iTTV;4bU3Ne+? zhXB@N7cQcja1*S@E?AFUupYZ$J$Au*?1J^!1?#aRR~*24?1Hc71?#bk0Kt0fqJ>~R zb|GJ*vmU!(J$Au*>>@^OA+)?&x03v>{y#g4NU=pk5(U4#hMVi!{h{SaUfE~1+75Uj;6 zSc_e-7CUnC0j$L?Sc_e-7Q0|AcAVV+Yq1MfV#g^CbQ9WPz(u$TR$>>d#4cEgU9b|n zU?q0JO6(#)v=FSsE?9|OuoAn_307hk)dVZCBMl(HO6-D_*l{KUjRY&P<8%gE307hs zxel@-yI@6j!Fue1_1FdLu?yB?7p%uFSdU$>9=l*YcENh=g7w%1>#+;gV;8K)E?AFU zupT?kRDku^acTmr$Bt7IU_ExhdhCMr*ahpcqfCtFjALWf!c< zE?AXauqwM?Rd&Iu?1EL<1*@_PR%I8g$}U)yU9c*?3-zMmtU-fEC(t5&^8xj*|#r zg?8Nk09I(nsROV=yI_TO!3yo@xBx4(3sz_stk5o4p-JNhiZ3hjaw+661L3sz_s ztk5nz1S_-)R%jQj&@Nb^U9dvCV1@P(Jz1$;uu{8Vop!-G?SggM1?#j6)@c{4(=J%2 zU9e8OV4ZfsI_-jW+6C*hqk{vi(=J%2U9e6&Iyk^O?SggM(ZK=MX&0>1j$RJ1PP>q? zYpm0bt`4wHyI`Gm!8+|Dda_=-kilCF(GslIj(Y~cYVGK=0IRhNzKR!o%`W&Z6nz$G zBie~hf-iXmU*O_q0-Gnv_=!8MIh-$)3)DVK`I}B(?0i7@i7g0r26K=vo)DVKGCF+QJ!b|vw2EtF6 zz=)oWToWLgh-RXNXeHW+cA|smB)W)hqKD`uf<%azLi7<+iD|@iVg{jO)EgZPa1m8R zHQ^>aL=7Q`T3|%aISRHUS8r z<_zXzMSI}SvrYcl%sC7kbPePw$K8}6NH=Oa0%#Si(j(u7Ga_YnAhxreZ zA4ERLzn^+P`o8{t`n}kD=6jiUmM(T~|8~PjRR4iqtG6&-aLkF|3CteS~o_j6%TI99-tEpF`uj;R+Ux~e9zLI%4 z{&MK$>`U59=@(-!nlENvh`$heA^Uvd`SA0(FDAbj`C|UL)N|42^ykvg#-25w%{&u- zCiG19X}){SC6mcWGJha-AbMc`e`rg>R=DnHy@%^Fw*?SWAgzw4iOYV#8%io>4J9_uvJ?T4Rcba!*?ug$Jx+A+gu{*pww=20TvMawcwKKX?-qS6_}1{P zxlPGUkxluHsg2Q%!-L_$+=k?a$cFs-)cWXpeSLaeY@N9-6N|?}vFt!%AUu#;n_L@N zo4+M>OY|1~mh{cBo6VauH^pxX-ITpiyD@#kzzyaNnd{@%hpx|Fm$)u`UGCcCwUKM{ z*QBnAUZY==zB+cbd3ENh_*J2+vTG7+!fSF@Ca;WKnUAKT(dh8%@ao*E|*A= zGNXendfEBjh`DjH+xRvobWlh`N{c_`T2RN zdC__Ly!6?zv(2+JbK`SEbF*_2bHa0S;bb@x&iAMKqy2h+`mESl=2@9D<7bA>%$|`r zBYZ|~Hs6ltPfwj5JzYONeOl}^^R&#Y_^i;Z?99Z>@XXwdTRFE=HL%zF7yDijUrp>!}7G=rJmcyFjT+mq-C_vE^h-I4BmSE?)8 zrFW$}W1VJarX$`F>d3Yy+QaR+wq#qRE#I1IjkfBo>6TcF*^+6FH;0wxIg62HY6It4LJm~M0|N~${Y3S-gJGe-mK5m#p^gDt<-|&X7VQ+a)JA zIAf2cl^UEG**t!5rf{rn)~L3}|47l+(f-s2XT~|?j};NBL!N~b-qT1S*(6Da6w4*Y z(1>d=T4fJJ6$y6c=8 zf)E>U3~MN>!f3O3ANDI(N{c>!*CKqG}@tK>w^U`~gTtX(DAr)akwafbEY ztGG*kpy=!9UqP4rwIV`w$%}Bt?HVa08zoD*gf9l>S}u{HT}8S^VaS)=U&p@s`e7N3 zUV<(!Xrz#Amn@|b-wkXU(_>31X7^b~zrv(!qusgi@*A8eG20Qv3dgDnHeF5;p*G#i z(ov+)$acv|ILhv@r5shbx#093dmc>MQGcUY;aF8cNBwt2gzBhQ;GEkuQb-0QOF4?U zF6=&z$C%=mWNQPQBj3Qu+%q*;7B;YPZjGNYbWWz(>|^;mjBdi{21^3=dGwS zzK{3*Q~$Bncx%bCL1gSr2oZmKs{;r;)k8|#gKnIE7m#IPO{fH&X}l`{?{pqILTJ}XGMsknA1vcqGdkS zNFmuRIZ-Rc$DZ3VjBw&}+u5by;#YW5b93SI=Y-=VKU3^+?5kY69QzkVgzB=lq{~R5 zk=>G$ahcs89e+&Fv7KF1mlYgg(k}Z~#U97L3cBpy6cMV+-iDiA)<_}QAz8|0d_ZPs zb-}Yl(IwY7vnF#bs!|Md46UH=sudBc?>>aTUeQP)*(q7dcbpctb!@*Y zK6+H}z%YJDtzhFxxy!BC;@DO}cX<>Ms=K}{-9-wG?3A30yX;O<+FfIIP)|>L<4L)z zMzO`Q?U!~}zw?d%7$U9Zk8|l%-SrV%v{fU8WI&ScDmFJ51IS%}P;Gnzx&MCh-|CIW zFb?p|->Wxn#5llxFMEw%i~%fu$!p}UcN_Z=|Ns0RpD_pV|9^n*|Nn4@&v+2A|G)lL zy>T7J0G@oa-Z&j&05`h4#?KM=Khy9U-$vfQ0gM6Mcf@OSuV(%~U3+rsjcez+7ibqe zIr{y-V}VuwZ+Jd>x;1qIepjyyBOB0Eyb>&v^Od<{;lN;R83%m~*L4(y4#~-R zYV_fB z4rM-q+dgw1!ug;+ZohGl>18@xgJPp&bLHH4+Bge2KB&!Sit(mvLOS zixt)5>M~<0$J)!-@i{E`TqA{Kmt-kBnzSZ4bTsBBGJ!evS>ae!@aDeM7mZV#j@+S` z>6l%?9?_|YPmNS1O96DeId;+o>$ zZ>>{#WF%nhg{Q#!W5F`2{Th^dL?eY{w`3{R_=4OjI9hNem`FqWQZk}wnQKXb=Ep;d z=8h#5Y_}} z#&(PWeC-Q$##I;t*m{>w=Kt^8>oabAq~7>BzW-0zL+#RTu-fXs90F|6SVrhko*(XS)|@3!f_Z{@?#^QeFG~ zbf4mNrxhyLuu~Ngj<=jw$G?Hb{Fz1y$redA>;^>AD?h_LArIk%+%Sl`S55$tl9;D( zTR~H<+`fyS!9CwP6J~}-$1w}GZ5iAuD`m&lZ5h03d-0v5gy7oIPi@=2izPyEZ2Nh_ z-lKda_-TrJ9CuZ)1*R(^9G^NZ@SCy)NTHD}l9Ouz`@AXI0@k+w+bzJTC>b(lH>kYq z6<*wCDDH9GRlydRsfbWp;G6LJZ5k;g1Cpg$z==h*`Z=%uMct1L@I7xwt9I`i+O=cM z*xjr$8vPb@c~m2XWQSxajW~A4Cx}sv?3+y~#q3kCpl{eZ?ik#;dkfw=?B2L>a7U5( z0;ef@J9bpCu})V+sEu_9PI*Ejg=B~1M6S7cjB6%3W!RYGP8-EF=+7nHGh5N!v896U zIYSYlx+eq2ysnW#vRAT{dpJV3Ym9sBo+C$o%5)z&N@w?>f)P5!UshL|C^g}kib;-% zmGj#1vrb9GNe=S#D?-$!`4$@GOByL8dnG4onmuEh#_qWjH%-A#Wt(QSD^JusVZ|)R z%nCNooKq5UlFc($5u!HFx6v@qYNU|tm7J(~I3hCcnk$Es%AGmfso?56{wQo@Yp`_O z4fAZp4#%#_wa2k}iU`$Jzb#!w3XSZQoV=^-PCBux3U(^)s)DXw!d3GXI~=N%bu@@P+RuDNY{}f8tPT)FckK(Sgww}D}E>P@p?5v>cE>uLQuKOzq-b(VmZ?gpya- z(F}+q`^&Ezjt<(NeNz~_@%{hRC%ne_hyz&nINsm?LKp-1{{O;b^~OBT19-IFs6i~i zTbKv%`*(Vc&DXjOH^u_y&i5LJ@%_K)cj}BZVgUaA{yJk*pD?O04)CMAY21hJ|Lc#M zhK6|nXCHg$XYZ-J$UF5jTHZzz4wl9<2dvGx1bIBvUdWc zs+$N|lDkbvmMyu+ge4cbgoGqYmaRfi#gZ+{fGx|m+z3~>6Yg>q+!8xYNV~ffhj4lq zQty&nPDn17mBs5)TK2~uC?JIDf1oFN@nb}ooULsE=d_H(OIS>^a9lT&0pop0hs_cb52}2TI(81 zIm1y#Z-K^#mr*&Lrkv}NluPRpKD6OtmSW#W`8Y! zj5EktO3U>^ef+bd*X7dvW3};WRUXkaeH#WZjFnp-sOGQ5qB1Z);nwwTShM+>!kD&t zC;GDz5sm6!WYUeUtMaM;$l{|)Vv=3#^Gu1D%Xo;FF~|fk$T^uZ)>_hdWo(ExP8q8) z3t!PAUQxW=^!G+rX-~6~Wn3bnv5e0*=|j zj#b7RM{mcaM+Zi<XRyIETHBmKItv81NhbN+|n&H4)FGGY3=_NHtF}Y7GUUK73n%! z3*ex!fZu;bk?tg0fZcQbQag;LnF4=xjS2BQ3@MYxnZnfv8|_=Uz#r+Sa$H}Z5YqkE8xO*oQ$uHejFb^eRJhlg(g&zkU63}4XjIt+K^ zeVQ|P*U+%1_jbB_A7%Pcx=e1lDYELenmgvCP)YZyJU@<(VTb4+??zq{jE%^NNj$hw zB~4?aV@<@Vq=G&Y?L}{7xKI#95=ci=Nf=dflpY+(!mm3#t}=txhJ7gWd$aw+S}ElK zzD08-OZO@j#d~1*E~o%-rCiVz$NyM#@9|;|{q=x7e}1j?VXa_wjhx;=P5!NL{V!*b=_65X6r6 zjcQ!%4&O8)F1E<`pnQx;U}t<|64*+9WD?kV-jD=#*4L82F7zXlsO;$BQc=1_|JS?$ zy1ROW7VO6F(Z#{u_5KlA#9sHFf;ia9-=m6yZSTD!;=*$QTK@~A40yGL|7@ynXsZ+t zXC!)>Na`6Xs2!-bqyOU%6-sLv93iwnM}It<{$Rp?3V#I4;A_DJ|MPn&b>xD(ccwg1 zGdHJ<^x*qo9=tSE>TcTM-k#hk^OA;pgz0eUKyK!#Ht-s^h;GcCwNvOt5_$*aQm-lS zns6GtKU6|w%KI2`;ap*^Rfv-I^!!4L&?TP2#wTe_UsO2O+P6YD77ipTOFt>$zu|az znwUWe^Jh301HK*R!XHKD4&D&=aMjXveie=&rpuI(N@_-wcF>Dw?F;-`6{S2C{xzn; zrGg7pR;}^ytAI*lZY%JufQpL;Bl+XzH-U2kWT;T1;9DW6*FQKWm@?urJRJlJvEjKP zxRVr04V~W*eh)_85I!7&TI-~XZ6j_6M-Y|f76(rd=8VFX!pQr=6U1;v;YML(M&Xyi zkWu)V7?DwUYZ!S$c%0BO3Qr9qGYYp2v*3xMQr8XKH`I&}2L2$Z81*L)+*nj9)7|L-KxedO$M5ei zJj9Ftbd;9_mtYUCy?gi#8Ve8gqq~7+tjr_J1qb!!%zMWA(@FSI=YrH7SS;8`OFQs7 z<}HN2LHHHV0C`tmqTn*coY_zI(*hNv%wzIHIhqv5pij1=wUP6O|ek@`$!*n zveILRUu>j{bK#pu!8yD<@a$crz2V^nXKE#`K10{=X`|L+xWj3+(Jc$-O^MdieP{X* zV;`l5mO#Re$d=eaG5i$6S1N`?F{Y3BcK>JKpBnh52L4~xK*w9TH{nqu|9a~6?5l}a zBd>_B#P$XErCyA@7=AwgT;kc}GvR0QDf&0K|H%W7#U6|9%{+W4*?Dirp1|(DTLST+ zo6>fBZND^gcPuE<}Ox-4`_ZdvH!TqM#Zc8M3JFM#I-(pJ%umTCTR+R5`yvULh)Bn$KZ4Z>e}fob;t%SI# zXK)MGixp$6HQF$+HpSSxZDlXraeZ|Aie3z78tc@RCTVo(%BZlbOi7p(_5-dkkO^P| z=fo7IRg{tnD_k#Dn0l=+>`UY36HwUICTVo(%BZkUn36Cn?1!YJHw2Jz)^e6o7)(yC z8h%b;-9brhX%|UVd~KsT2SFz%T%8VgkCXKuQKsJ)K*rg^St{$8P`PnL)(Z__^acV6 z3UP|dyl{Q8<=$hGOqaBb+cR40<8}uVX?=Rc(H~-3 z6Gf!Sz6P!}391WTz5+XZohb>kE)Q~Df=mG0IVY}5t=8%)8n-Fv5l7dh;ck=F`pLFV;mrFB{r|eS z+W%LxNM&bOAFQpt9qtfN97CVr@P=`e_H$C#8v@8U1DvIlRwvZ)t=WdPqJN-`t-BGi zMz4B>54{mJk6xZUEjo@g-Z02`WTQz&UFMHn_o#+xdja;Dk}%i3UvM>oOaKF%6IY|w z^2Sl4G1lm6)MC(Mb@FPAnPk*uE~6UzO-Y#5_)AjVHUVUu4VW<2^S|cj&gY0IMV$) z$@K#PWSjxcQqtiiQ^NFe93cxYk>X0AszHrWcs71~;g4)L39l=ojJ4+mQxfLd^B-Kl zAQQj<=VbI-cyEmU38`wY5UZ4a)fi>f?~Nwmb!C)MzdKAxnDzTx(&?`Rka14sET!LO zp*j9(Q|r`frrr}BOUb6Fnx^&91ngz2HdkYX9(~lI43+yPlV)^Hl~4Icb{+C7d{_BqmwH zx0n(!m+rqQREw!eOXk~q5-fGf?uA7ftrh~(s z@m;1Q%%uw<&5VbsM4`y}EZT@k>D(2dMsrU)q0_O}dcm z|4)2Hkv^dQ|8=wnKxCgH{ek-b`S1Cpd#V4Q{4T8#_?1WMqW=G$Rc>iI_5Y(Q-O~I0 zPU$il1K1SyN`4vxIIhzx2?r$M=4Y*IP9gjM=!0tipDVVjSNNT>g8#JAfXKo)|2d`K zMghkrJGj{aZeie7CwRRJ+~x+id%zpK;Eg_ThabF20e4n_H&=r3DlkzE-ckeJS_|$H z2Z^^y;BFbb-2&cW1@E+hd+gv{4)AUU-s1%Cb%FP}!2u7L^b&P3?)Tx;1Ag#91$?Li ze7F*Pqzc?y4L(`}K2{4pUI#u=4?Zal5ucL4r)6-^0;a6sGdA#9JNTRfe4c?XIKdZP z;7e|Bp9g%|3%=q5U-g5pDd6iB;2V|T{wgqCP1MDBvj(T$ss-P!1K+6!-xUuMKPiEq zlEL>Z;QLna(>CxkcJQ+f@N*3Oyc0a&0yA##3m))`Uhqpk@XLPiD+>5872v;Cg8x

S`GO1TJRfn;0L0xN^pEr0%^lZV%9>`#rV*QQ{S?I-?oF_ae&`tAQ=h}zwZKn z;0Ax_0e|ELf9wN);s<}KfIq7M4_1P?D)8sk;4f;xU)F-Z5@jgKZYD9V=EGQ*7W=J2=e&PG{f@Cpgmu9^(d&^?=8D!Q*}434U;v z0(Mk@p-Q4I#_TGbIv!fcu^(TRRu<>iMkjU z*WlFBT5wq%cu75YX#;p!BY1fexV#y>q6NIN6}&0{UL6EKAr26`C9p>ZqZV+560Q)MzSQSwhqrV!bHr0TeYr!pb z;MRKZ`UY@YBe=Z@yrCJqu?5`G3f>d|cM1oHH;Z6g0uwTLiv_&Z3huIjx7oqn4)Asc z-r)rAbb))^;9VZ@ZZCL`54_h8-lu>A6=1TGsEcub6;3@+4L(={K2!@nTn9c<5AJOM zA8iC5YXTo{2A^mFpKJx63V=@s!NE2#B@7Xt5y59A@HrWL-U7a01z)s*FWJF;4)A3L zzTyO5b%C$B!PhRVp$+dl9+e(<{r_`M47`<37is=yysgFmVPe_RXx zqz?RPJ@~T*@L(gDYXX1X4E~}8{ADZns{r`xAo!a$@Za0P|Cj>)b}IP0Y2fdtga0WC zz4YRc!2goLLl!V^CF)}Q(S}ohvV;Ha0RPOu|8atUae;qzgMagY|LX<+?gRhf2M;UY zkqYpmN}_$5P=$b44N5hjTnk$2Kx;i{YXI$yprZ+7&7f2C6I~MMmO+mN^jblm4fNYV z#X;2Mm{!4Xs?rHoxxi{SSmOa}yc##e4vV#!^Q5WN4hEq$O;4&9@i5tAs1779@ zFZY4V{ooY}cx456RV8>e|K^`YhiS`&!OwSoKKHrA=YpThd^Y-7@w2JVgg=w}bmG(d z-;cbXe=qr7=)LTxVxLkzmHuSpllga(?}pyZz7u;#c_;mLFiUnrP<8VxGQyQ_}1JliCcoVWD?PYm`KIL z@!ZXcn}auJc1CxKJ5x7>Z|d8j>`31jxiNo3@`lh2+3m6I%J%fO$hQ3T$?HScXSc?- zDqGWAB3tsClbb`Evzua@luhaW2-%eP2!s1HJLThHR77o>hS7ZZ=yHYn^_fIHLxG&qCw~0(^IE~Ps^Q}I5l``=9K6u z;wh<lf5<{tua7S)dVpecg z=7i`8;t8qa!^h{2OB@$GE^}=3Sn=4@G2vr!GZQm|Gcz-yGsGFG>EY?QX^CmUXr0t20&6DzPe68LrG#Br1Xx86~QSO3EMh=X?oY z(3kN>y`nee348k7iaYI!xbn`VGvv&&7*kl9o&_ShQus2@n!FB=s(rgDa?I9dc05Z-t&Qg*#2o3R>@e?i*Lv#(1T4t;PAj(DfdZB6P)+QP+2wk}&H! zPx{>a~Iy&h|ZUTvwvRt%%HVZ&_v;k(Dl>>nwc4+i+oZ8WFLS zy38%fsIL1=vgopvQC$P3B+TmiZ&J}40?0TUI7_KZcYmvy_Rzu{tu~Ch;s@3X>h)sf zsOLvaOPK93jG9WC#L&emqo(dRC1KXopSh+$CV&l`6W5eh5lU)GyOoTyW=+w^fzU62jI)-rl%}x8=d9r;7U~RE7nD>JT_hbD3_|f2hN^P-p>cBe z7s}U70?0V)IZNeEA=9G^igH(C%Pu|hrY+}jS~FW6X{`G2I9dHGW%4ZnWSlLWrLu|@ zM+Pq?nj*(*poOIz#Z|9xZNk;>5tB%|h-IvPdre80tKZ+a)<7nJEu53n+IWo>nkm&_ z3)d#BwMR`N=^~a@u>RISM6K58 zRvra=pF-s;Y3(!C8{=`4yt@45Q|XZ>jw*=>*?G`Bs@5BQ(v*m~-2TqX4P*k?&N;bq z(`x&OayxvcL)!ZZn>3f^{ug?D($8t$-*-CM_LKep4^H(+C%o^J2L6Ld$I}{s)!W>X zOf~?gU+PlAzT%c%ruqM$e#tF`zU`DgpndLG%C1lYVLApjUEZ|Gxu* zaA3-%`%k0!{}+w(|0Lx0a1R$1Q}WuN;*?wXocu064}UwKfxnZ_y5G&`+wbKw?E`#r z{eC``{xF|J-^-`ZAH(!Hqh5opjpYXiT{z=bgXL=bC@SXPJM(=a+wm`DMl@mVb_kWhVIP zZ+<0#zp;Y9wS&KRg8$_P^Iq^zRp8&m4&o7+NRzx)1SCF->0%wsZ4V=~NNGE84G%w94~TQbW40n>R5^K~o$U?z@X@{M7> zjbU0%)BV(QFnz`_W5zH^#^fP_4Zz$L!*mtH)D**P6vG4*!<-YtG!w(j67$34kjC^dd}|GR&AV%#<=rlrqedGE9>)%#t!pk}}MZGE9*&%#bonkg@=P=}{&Q5F~=0 z)r(}D;gh2)Z1{<}QHH5ehM7@@iBX1mQRW6PE6Th8=0q8$L>Xp8874#-=0h2#Ls>O| zSx{C-aBRW!C&TO~!{jI9bD!J!tmlobIKihocVfDeNdTYhOz>&WTQSY4XZKb<&$%1( zoQzL!-iZlLhWSl~=}pGxHSfi|Cd0HQ!>lIb^Oz4{9+UA2%!e_7$@t9WqnNp5n7Cw^ zw`7>MWSF&Nn6zYVfG|W50ST}W9M5B>lJP0ZmoP=iFhj{OLCM?%J-@GEf|Bu>$^Dp_ zWPC32EzCtSJ_-3QCLtN0eS8nIkBm<{eg@NyjL$cI9`lVXNN{|i4L>o7VxP7UvnULc zD2&gZEavkj=kpnp3o&Ctt$~1<5=Vqjjx6O9BA4>1kjwcb$Q6A0WpJGp++YX$7})OuH+#UXK5&}?-cSkds0Md7fVVb*x3z$` zTl$E1*}!`o;C)Uo=>Z?~fe$O--b(PXYVe6#@F^iq9F)LkEZ}oiBC`{8DPCkazt07} z;>J}ke!lL*PX#~I75G_&pKn*=XFYzt*93k>93Xy91`pVX`fb0+41upWjRB7#@Kv87 z@O8xy_@L4d7^*e|KCCeY>I{MJG#CQkYc>RaXx(4P+d-!x@GG|=@Ee~Y@LR zs*QnKL%>yM3^W)5-bQ0U8XA^odWF>xsCF0vbxuQ|!EFdMc@2RU#SjSA83HpJ41r^s z4T0muLxmj7k_~~7)etz*VF=7~8UiP~4S`d=hQR55L*UE`L!h(D5SU+M2%KGK2%J-I z3^W=7i<^vr7DM2IfFZD?%@F8nHwFZ3wixGMUelL~#(-=HTxu}}Y=*#cyD{K21g>@) z0^MFiAnG>+R#q4Sy_Lp5wIOg#ts!u2vmwyeY6$cP4S~%fHXPK1yIwW~wp$H>8|{X` zO-@4~?luH&@frfV{D#2p3Pa$IDnnpTjUjM%ogr{6 zZ@V!db`->ZTrvi%hQQNyLm5$u#Y?qXx9Mj~dWkLTW&J7pVd5 zm81r=H_o)Hx6{rTZH=!EPUx)}z)832f747w?2DG=N|Gmyn^?h>i-Jy4c zcRJqgd28U!1L;Hi1N*z)h`+x7wS%wvU+sLQ@8!XLLoW$0b-dW~!oc$fo;&nx;MuNc z;;H?E2cPyo-T74ClY>tTJuW=n@mSBJ1A7lVa_HdzSsBD1-2cGA`~CNKCi?~k?;E;T zxVPh;p1TL`IM?ug&MfA_)L{I_-P>brIDmZ5}@=!o~+Jh1b?O^0>_c68ks zzhVFOgWLSuI_Fe4je(6_8{+HtuRD01|GLg=`_>L#Gqgrn z)3LgzcVN|lm4{XYR%D{ls2EN4M0)bwsqS!h{u9Yhgg=qHI&t;>tD;wlSEa5DUzxii zaYgWo%<|}Rae3C(jR` zpFb~gUg*5+;>6-0pWhEI%A6ZJS2;IxPV^k*ob%$d5;`S&a^mFB$=Q<< zCk0Q+%!|zn&dbh?%?;8_e_~E(PVU6yiD8=SPtA_Z7H6kvzF!GtI$|Bcj?Apsticl^ zG~b^-K6<=zeCD_q&G=`JO&l9KHg`;t=KS+BlQTmzvojJiLNjvHlQip}pO%^ynI=w4 zPmNAhre>xbYEQLC+C`fAkG3gonP4m!q`Ch@AQZ^8CR&57nU-ja*pg}vH|LrXO~IyY zW2`aQm}!VMhz+UwaD88$QkSlc)aGlFHKCeJb+lTnPF01ga+Qh7U}dHvTA@^=N1gpo zdml781}uOLZ~#ug4R`?`pa2y>6;K1z0S$oEL9hTe zzz#6L3Ah0-pa7LXHBbi#odgN60Cs=@F2D_V0Uw|Ml|T(p2Z&t+8L$HkZ~<<>3-|y9 zs06A3p^qQ~R=^H0zzui-KcE1WKow8})B#eQU;*p^1KfZYz_JZl0kB*{t^zP7Bx5W{ z#!!%qksuiZK{CdHWDEnz7zL6s2qa?+NX8J5j1eFiBS10+fMg5+$r%5UG5jNA^hd_v zkBqS&8Dl>(hJIuW{ZI|W*pG~%9~mP*G6sHRjQhwK_K`8_BV*7<#+Z+cAs-n-Ju-%R zWQ_F480nEQ&?8#_8-P(B8G}4B#&~25@yHnAkuks{V}M7-_>PS69jc@RjPA%7+>tT1 zBV%ZXDk-|QP7LkH7}=3Aup?twhiVT2gE~}k2pH0lF`^@5Ku5+vj*M{}8N)a-MscVf z5io`$V+@BX6Tt>x1cxdU0pmARj|dpOp?XBH#0eO>kugX@B}PD>SVoVS?u@T#C;G%x zM+xW=%jgix=n%{35Xxb~50cUUk85U3L_z~hI|G(@lrEJ2wODuIf?MHHoz5ClAN0vjMya2%vxEr9J1 z!O_u0!7hTYhtLYx;soy?!LlFc0RIrdc90P8M=0?QLK7f%5nMpsAfX+w?)9*uU5bg&9V;Yt_!+@QUicJPVfy9tWc^AumcW&dKPGuICl`|00uaL zAVh5DB6iU)H&734i~9)8=8>^$_Yg`skM!Co};L=-3Z5 z0BwL{kl^WCN@}iPae9q34V_KDYg*|*cPC5%tcM6yKm*VU1Obb%kZuBafC``*r~{gS z7N8xl_z4W~0DhnXr~&GMW*`WNT?7l@1l)ihr~+z%W}p=a0zw~w0dBwx$n||B;3Rbr zulRpn3xU_LdwJ;9+$%}4qtCybdO7m4_;Q*o>6Lw%mtrpkU&@j#edxv93&|J4FXW$3 zJs){qd_MhL^f`s>>0{3ZpUpm#cqa5rE|pA$Q~ANvV8>wY>At6fWL2MdD)dzD$>ft^ zva3%$5qUy&uapmz0?S>wFEK9cap+|FjlY7H^^N*w+i98}cl72Y)u<~%`q1Z#g zhq4bQ$i_bRK=Og`1Nr+?WMwbjpH4=TN-{%s_Q8SdeTn-*_vOgaK74Qfp42^&dqlFe zkKV1^ow+M^SCFjj6MOu7GIz%A6z)vl(RoMy_SEeWvbaz0j_y`=XKss;&3$%PVpnKa z?$#t(-REyf-4eM)yd_O`_evrYkHv%WELq-%ZqDsY?hNnD-;}y3a+65AwnxeSK67L2 z#^8-JyQdEL;pJ=Y#u8(-^Ro4F=N7WmmU zi8Y}$xz$Os!O!=mdLz9DS0z`4SLIixRz_BeE7L2YWQm`N#-hP!wg)@I=em=;zm6T^ z#ZRQKj$W-?ogsVt;8ocx6IX_=Ja9#fdhOZeiRGc?xyzH(Z^!QOk;}x((qxyfT$;Hg zc1iG(ELrA$brFm~Yb4HA;_Oqw=oUZofgQsQ5 zZa;Kt?v&&y;ZyP_r%sNXES{V`DN45cdY?W)*890R$vNRU`4dxQzb~Gcp4~Y+A4-KH zAu*Khh;}HvPam9>Jt1*I=!D$yNwVY5AD22Va-4Wvnk@O1V>8FZjtL%gOwD` zDMhybqLdb+q9SI581?Yy4!A65*l7Pht^aSd|LhG8ik2X**(w$L(-* z3zLAl2h>=$BTt!ZE_54=GTM$jeN;(I$aaL3s@aYVniAmyDg=Ec!#~JghLqBB+N=Y%#{c-0c_`-oD#LV zI=&JO5l2^|A;N^M&z?0&s7qW%B|c|L!mPw2q_|B2$T;gcODPdXnFaqEcrd6o_a*Be zzf1~)+34a8uq?wL8LdX2A18w!QP$oOK*ky1ER{iQ>2|}2rlMwWJY!5_tm5)DUY&5^ zzF-ne7qpCp`=TicbKwdu=niC@0nW+lPOI5tmvKp>OjUR4JtnNXmrR1`f|gNt`%Fog zbtjV6G6Kjrr*f9k9kyb7q;$O-Vc=Kvay3>jZgQ#BK>fv8FwHEAIoTKN%O_k*)h+67JYKSsnRlaGGQ6iZSs#m&;?Ejy=%PVz~{r}~AywabR+oS=q{eSElpEUP!oAe>={rBV5K50AI{|`Ro zk{X-`VDs8p;0u6mpsR?Jk=XgZ;nXE_~@{H9cqAI)&385_z7` z|F7><*Z=dJOt!qWW<73s>+!}aZ#7QY%lnh2!q5xnW0yB+Q0w}C%9Mn;yd6}=J7||3 zlsDMKSxVO1j*l_r7jh(Oe#>p(B3_eJf<;X19&RHt6BbPuAC#Wwv z8b8n4lYnR4ya&Dh7}V~jRtT%@A61dwsIaF$Y6@hVHLx}c(!Yz&1s#Y!q%Gd^g# z#~SwfoJk~I#4>8_^QI)sT61%)flL5fI47<(t=5dGwL+X?trf0KSZfDNBIzQQQEM4f z5@xM=NK>~9AmeQ0ETuJkyj?z`OQ8>4m8@u51k#sjiFA?Q978KS{DpC{?WGKVQUDoe z8)vC(<4Y`Flk}^cFPg;D#VupOf60`Dx!`?VgCG;YHqOau zuu$d4)?gvt=o&0spRfkMY!Xiww~QM6iYW=R2K}V9FA5;7b|g;cETzF#p*8+wsXE9< zQpSAp7%G|`S<_|lXxJ!mxnA{{)J1^Pk+GiV|6-C|*G2i%d*ok_Dv3#ssQjBL5px+T zybM7mfYUiASB6^c)r)09O+k-5W*M4pJlQh*s!4WT7iBENuN_qqlPtrpn-VdXVFi`j zX9SROPUjq}4DTz|4*5XNMBAYrdGu$R_IA-DP58m~4U@FG^dG;}R_R@_4@^mz6VPId?jYFvRtP=^;0Am^1<*J^XaS@_LKE4pnv#$^$hvc6st!tq zJ5G2B-rX0O1fp1Z1Gbzf$nk0`)*6AO#3kzz#6L1$Y2I zPzh86wLm=&7DV0QeTK_bePFR*-)TRa2i*Q8Q~-dpi{J*lfFGy;s(>1x4rm5ifgs@R zBlv*|pbBULn)|32T7V!R3=qVD6|`rtT4OBq+gAZp@n0zQYM>nup;vE54@KX@GivXm z@@)oueS`|28VL4LObNHB1gZfAx2OcB01|Gdbo2=JJGHWNcF|u30Fm-#-=k?mLME+% z4QM`i30?CBc?JR$@QK2u^ml>fg0Bq_I|voLt^<}1`Xf8wMW(6%JMz;ESdf(#Kq(Z8 zes}Nw;rgzh@)w_~C_YtHe5$7Sl%>#|^xNBtPdSQD2{5TvTaW&SQt>HE@hMyJDM#@s zU-2oW_*7-_sn(7w1$)vf@uKl|UP&cJ+Gaa>SQM7w;-fquQ^3bM37&%5lUhBnbS**5 z7kNxO1$?%G@`leBpK=tRYA5Sh`=j3D_^qV)Qfe+8%LF!?ha2gquda(IU*Wxj%pbCqqvwXFPS`qX=#mW(_Zs@0^;!{{lVv2>8 zC8kqYXJR_lgtB=~%cj&v;x>?xE^~6Rn&_u508~VLB6eMe-5AlnRg=du0nA= zr#(*sv~EC4P(S6RKezAGs*QjC4FgLAo0nf_*7N#sixvnOlwSrth$O%d5TZ@iccxUr)r8%S%#=W zt4}^Z{q)oU;z2?a)ozDY96|c+^V8Z7YQ)|>-l@D4t0+w0UW6u~6=(xQS|8%G01WT} zRe;_*_~-GT8u&lfz#Hk;qpvHkXI_hu2LyfXM(*Y0%h`R2eW881mqITIFAhCF_*~z! zozM7F2cO>mRQ$=VCjyTjdi22Ffk%2C?s!OeaOnO)+EYMXLy^5VLB0xd_ayHL-;=*P zOuh&jsmtG_J%mH^<0#L3U?iXJ}{iCgrB^jy$cKIJEu1wt?$= zwsve0HV^d=#xi}ezRbqh#^i?ZhS>Vfb$;?g5W6;bZFX&9ZI=8Hgsw@@8i?rXj$UEa z(2BumUr#6PM=)}IL!Q<(3@i^XAALPTYFXdX;L_N|!HXl2K-Zxq2QG|}KY_mUgXd?@ z6VHn*78i#W3Fi(i96Y;kLFasb_~2Rl&y1hZb$Z~mL#G@#dElg;c^z{F@&FJ$Q8_U) zJ2pEwI~z)bLZMtolKcSVXQgIEW+k-s0~x+2K!kh%q>qUnqa2f&86z(M#vK6?(?Zj7 zQ1fN)E`In^9#7Ret# zu5o`E)(RwjJ>CwF;2v@&$O}M@_5ld9q@%~)VaxH=|9MNw60wMuv>c`V|1(ld3QAcq zK^_2T=55cUN~{)bon4V$?&c){KG1cp+-X&P<$Kns8T0iEHw^&wLd zdNb9{>Z@oF=OY1RoXwo226U>0>iCC6BV=Rj;*J3`j5&{R5@6c%e`|Ez+Et{j{@&Fz z_8DDYLUGz@bvtMC05vX__J^%qrNiikK*s5%>^KUmCRKe>02${L&Qc0%5}HcyJvsrs zX+wp&`bL@IH;m|$vI}F06ZETaIPfSUeYeN&)Bgh1B z3g=|?Sg7*j>9G*AlpYH)CalMwnuOGaE~6fQW=g`W$7a&qmj#e<&g3km$Dk05KU=y! z>XYE(DO0O*dUQ>rx;4WXtAK{T)AhLHx5y(0O&ZWOQa&Xg$sJV^lbkjGxhWBINw)Bk z1epNN^W%#(&i5!j(R5SmKiy`2l$044UUZ&M%#H z71{aI8h{@jwlP%Fsn64 zs{En=GR{`cQfjRgYDZn&I!*^w{gBeT`=(Bn>Fbf+SfdYT;8ixk?*HN6jw5v&$@?P# zWSrADOG(`#w8Y;n{REki@Y-`h*TE=59%FrNmP08=erHmOuB0;7w%?nQFxR$ru6K|L z;55$3>RoGY6VkgeZgKNPZ%5U;7H_ymjM~=UTNb_lr%5TglFF#}KbVp*>wOC8dY1q) z&H!gAy<_i$D@LjBe)Hk~8YkmZDa%g?Amg0QSt{c&Io>`>#gIq@rndH*tEMuAHO-Y!`d>U6B$OLdY=VVoNyZb(^-VT-m#6lln~& z>R!5Wi?+doc7YVqyREMuufL^QRP}^W`u{d%P0#As()SA6gg&8PP(R@GoC$G@fd7yx z&S?u1|7=P^kFI}dok()85LYsU0*RS0W-Q2s%{9!fn zDro{*SVDi&ZTK659uEJ{IGLQoGYK*QY~n1HNvxhcPs`-Utc;e?;TVua%PWnEb#K_% z*S&Uq-?|ao*8F9hjLxOZT_%8xvw{;D?H77=)$2#vpVt{bkupkag?jt97VA+zujT4u zJ(^KoG3D{6mM0sryTk!h^~{@s*@E|1;-PbTrt z6hOvV!3ia76t?P-^&_t`4WxvPTYLNa*RJaArY{=EsD}|zOZXq-Bzy`_7-Rxi!Kv1a zsGgvH98P#;bltiYQ7UgOVLfa}`0zLhpGt{cD}ao%mJAt}5YS1rG_NZy|H-@2_u2}cm*O}D$x>Nd>C+*S_`v12V z*rdfxPU*F;F{$xbCiOq&l)katDP2qb|8IVZN$Y40z=OAYq!5h(EZ^;+eE?j1AAlLl z6zR*f24Mfiiu8WeCtVh@Nh>>jl0ahs53KOm=9B$@=rP0V<6y6F{QMPMAZ%*BFs{lr zt(pR?2B-z<0Bm^9BmldfGYf#N&lwCR1hc9n)DIP!C}5bk+!PJ3Bp}*iD_m%#K`v5dr}ARcF{&opegT z=IRWat1~Nr9oCs0fGHlsUh51Ncnlk^GZ@}6?7Ggp0JdIdegONgvkCy4u(K+l8mIwk zfjXd`;F#WkpN#}vq0^girWp|81QCz`8L$9Wzy@GgGDNrJF7|BrWd}@d_P8rW_}XLK#~yd82uFM5Oq0Of zD^}na_qE3zEmkAQ{q5D_7o6@5=ac*1YrttZ;A7nXUNe5d2_NG=_yYJ91h^l*cKi|! z5kx=&WWWMg0UKZk8~_8HfD3Q~9>5Fu06(Ar6+k6WMHtR!HO|xkwLl$E4>SOcKoigm zv;eI@00;tYKszu6me1IQN z2*dfTz?n**3aAEZfLfpqs0SK=MxY632H+Tj-VcNTfE5n(ejs3B1HB&z@RC9A2Le_$ z(EEXa1r79mAYdH>y&uR2;tV%_!gU6{APDfEK`)3xMrXj82E8Z<@TfsA3Ig0}(2Ifq z-x~CyAi%)}YXIP7gEawgwZU3|RzT<>h=2shfCYg24Q2!EfCFHF6L0};04_P07w`do zg09dR3eHpj@YKPo0J!U5H9##;2h;;_;lUaK`0-%PKno!D5hOqcEPxfT0d~LvFu)18 z0IaBB9smm|m=D1E2?pmMtb#C{&q|!B0;+);pccU53VN9mL;&7Fm<(6|D_{fcfCFHF z6L0};zyo*zAK(YzJA}b^2&)9(K!jeVgc_h0r~~Q=!})B$nMME}Mp!c-4iF?j1}uOT zumN_!0WiP`xBxfc0bt?Jd;kplnF7F`pH%`d<7d?Xe3P(Rpbn@98h}QC+xBZ;Of%rO zgtY+Teu4zZfCaDuSS`iufCFHF6L0};zyo*zAK(WRpaQ4_s(@;s2B-z#429JL;sJsL z$bbc~5{C6@!x=l^02tr|T!0(!0A9cc_yGl|04jkhpc<$FY619Cq1QD54pmqqfR(9C z93n`73|IgwU<2%c17L*Vd^&N)1-JnZ;01huA5ee_pc1G8s(~6nFBn0Hf3o9~xp$NA zhTqM(FH*&8hUk|^Y ze=YS|1&E`*X=;GMvm0qy{1b;z0Vo=zYq4nR{dR2Jg+@ zlei~zPwwvIsP^oGcSPm-7 z61_#aC6kCHf{AQA5f8<4Hz#in-<;nW*qOa4aZ~7~+>Yc9*t4f@jNB;Rn7$!;gK|S= zdu)4fdv;r5TWDME`sDTD>+@SvTO(V=t?4b%Ey|Y6=Gf-JO_5FFrgVR_U+hoEqA`Wr zzX$uW8xtEt8*>|A1)pD^S|3?2u1~Lvu2a@!u8Un4ye@lf;@Z%)xiLHgh`s4m(N)T- z%*xox;L7ZZ#EQ_0Tr?RCNAo?Yo=A__lkSdo50D?f{MD(eBUg)8r^%O}a#iNa*pY%S00WD|i}Q<8iz17}Md@>++_zusoZvaxg^7isg}JknXRH4GA`8R? z>G{$5%KS_?77m89or%s+XYMTjS(!6qX9myAo{=~sbVly<y5S^{e&V*v2U?|&>=m>S>W+i8Z zXXQ^wmGtuGAH||SZ}RaMn-ZLoZBMj^+H-Bmws2cMmAEO+`^(hEYJ;`engsd#%T@cy3qZ6= zsmfHw$lqVKB2f{l$SFxBtmOSEf5b2P)4r%r@nyU*Z_u0dBs?Kc&Yg6J-Fa8a6>-If z?fvtPlq2F09cg=%JpW~EFogx75B-)R zdUkML8^Myy$!LG0>+1~C)J_3pob{a0*D6ZN^e>K$-lL?iRng7Sv6N-HKDwq%kw#aO zY|6hbPkGh!k;RmZF1W6yFe#`?02yZ`C)Bis>aXcv+$G?@?(Qv{dKdLZ$$$Y7v;wh? zlhQeq#(V)}oRyqoq!e#8rqq4Ord~3cSh=n{x?#gcb%LUh`bV~LQa_*4Z4p3P21%qP zkVK@uk>-0$|Ke@||IuLchVIqTwd=O@_ZE^mVmBqFCp~t_MJbsLqdXAo0{(+cn|ry! zHFY{nspwhM3$BZ@pAbOCS;aYqKykWe5U6+{xgac6Yb`@)|1_SfDM8h`evRh$M$8r& z9|FvjdtI9H>d0wIWu%U*!X>1g6F5Db^_QSBnm;wrrj#kq^|K@A@H*Q&TjXu_I zI8~?!hh1YPFA7&s^0PP@XFVs9M`bYmKA(PxBn=QJq6A zq<+M0N?p&**eagP6zWGFQxbZX^*VSJ2^bVW##zrfhJb=nETBOouPHq}{ql))*k?+@ zEYb>IW*`&5dQP>(Mt^NknT5?oR;tYWrquP^luy8q6jKsr0auYwK>=i(^_*h}h%z$^ zXehG^Q+j&(}r6~!sNY{`ss|1j7Hgc8{342{$W)Nw^Mr{HYkF(i@NvmO*ha=Eq z5zoV=Vg3rD$92aHJOPKN_BYKeJOYJ}s!HU#hJWLT!aBz7V^I zOCro44lpekPJY$ajkFX~l!gmOI8trOgPtd~aL(i@o?XN~A;A9=bw#VkxEQCIXrYfM zb4-9=RbN&g)tJ)J|8NffVHK8y_>o3a z{`CBg{W#fHs>V{S6Uk_Z{%JL}$#j2Ry}JA{lKeOUWSlcN$B>^=9&VKSE88T0A^9WC zrsVbPlu5k9EvEaM#k-LNYZgGp>Epyhr(0OBN7j#V`ZA?Y{_gJX3(sGC_O|x+BGVK- z=6J_1yiR-ed2P}!4%?+$J#=(CrCtB9N=$ORD|I#H*TV<0z{gzES;}>@6 zThG{}b^SK!RnaXijM=0e18%9hkL>@uMB#JURZVA8|9{t`>T?bK{}w@A|F2e#BdsRw z>Dnw)=^P0h)%~|?m771<3!09jYKyA5kedI)LDT*9$a>}8LFL{qfQ-}2sh0h9dSv|= zw+Xg*C6zu3U#kN%wjCGPZfve?rWExYluKjnM|J;+Yix??{<`qG#%>~A9V>v0)6WTw zt)amR(?1MW#9K&X=Pq2bboqs<=Ag3f?gbZJvSiu9i@S|Bbw{R}64x_RCgpuJ&2)b~ zyXvb%6mBN5=5y*-#yG|c*R4cXK`AcdY=H(i5!0l4d=@ia)w$eRRh4(f$o&B{pN#+D*|F z>v~TO%sx33>fj84^Hk2BIWquT!BxGh1BJI2@~w68xt;oQ6I2$>;g|##+(XB_;kMs_xj2|PAJ4@OlXT!?PYiXQlmKFQjP?;n9@d2!T6H8PYRYE`dX)`u5?!)#Y3fAN z{mq(sj&!tA02yaJXE#06M>GG&{J^C`_reWZ)_2p;+={iE@!0D&y_(FIOAHwF(p?sB zny=o&sFcHV#>w>al-(5q$T%B0v0h^{+1Z=^@rFwy9ZSh@c;#kp4BkzK#4Bl3b7Tn@ zMJSPPSRk+5yo}x(^!`9%+6!*(IJth2@_Um2GR`TS=x{_wv35r*j0xQrMz^o%?e34R z-PB8KO%^WF+#2BNW6J&*G4;yYMLSs-2X54FgS8u$^>06}yL)@DapWd`c-}bjyhM`h z58CBPruN8@dP9pHI6RB7-AaU;lqPfh64KNq!I$P3pUEFD7;Rh zG;$gId*=)VOUH>}*!-`~4o<@Tk~btmu@6gp(naIyM^n8d4l?FYWPEZQ^lFkec8M@-QCyE^A9NA9hH+GzPHm%P#30TK9jc#V7rV?EOzz>XyFw zN2|0^vPpl;+NJwNn>3sLKM=4>Jp%Rr>HjVJKD&FNtw;Ei(f)t`a^Y(U)&3vbxG#(c zvFW;uZQNxWfSt}|2jB$UfCumben0`R=evx(+GT9~E@Q)Xxdx~MuxGyvX8>{&fSuE2 zxCM{}+Q?bPR@5>a1jsUgE!AZk-~h1Kv+O2N=Dhgr2e28uTmfK5co}=l%e6oqP!BW! zO+Yh%P1@yFAP8VXdU*3-|#As06Bk8la9qIfOF-8BPRb zI1!MAAp)ET$Z#Sc!-;?lCjv5@2*_|EAj64(3?~9IoCwHpA|S(wfD9)BGMos=A^;}> zvK6oa4!{X`06$OxQ~}jMEl>|M03vxDpd89{kgb3nZ~#ug4R`<_pa2y>6#(}IGTax) za9<$9eSr-31v1 z5h#Zq{PqEUpaQ4@YJggx9uPYTGGGO4fCF#>9>5P&098OWPz%%pLKi^-EPxfT0S>?k zcmO|80aOtvhc);u_7Nn&0@wft-~?QN2k-$EKs8Vc)B|FiAOlvw1~>pG-~v2=52ygD zfm%QsB*=gjumcXjNuV6M@!Jdd0R^Z4s(>1x9*~C!R=^H804LxEd_V5G2B;%Y4kcj~{WV|(?0^Gs0&c(q_y7f{0%`%#Pmlo%U;`Wg z16%<70#HRJ_yKrlpxR8R1hBq|sx$%Xn`EqSlBEuU1+Wn)hj#qNk|r6enPeLvlpmt?G5lCfw>#?AaxS3;D~A@0V|ATEH09_7)Bcc23nJkSA4 z9_WBY4|Kq?2RdNk106&GR;^Sl{2;3bi+ZrC2P}f1D0cPWP!F)Pr;`EoAa<&Mt{&{_ z0Y>x`1s3#lfJHeSU`|d4*pkx$hU9dR)Pt-ZU`b9VVMa~|*pSl!2IO>r2{|2LKTZc2 zkJCZ591p@=oIeKs9noJ|Kr$8HXT&s>mV$yDFmBqI>73h4zRnX11zuU z06S|sz{r{ou&|~BY^>=318X|Kx|$9!t)>I)s_6jBYC6EInhvn3rUMMB>0nb2FrlUp z?5F7f<7qm;a+(e>o2CQIrRe}OX*$3>nhr3FrUOi$>7d#@2Vv|?A(%GP0d~!FfMqis zVB1UwSU1xF_RVytRS)&*p;0|FsfQNzARXc{E$YFh9_;FYsRx&O`2W~@@4z^Y`|N*q zak$$22e6A250pfSRJ&slNr?p@)f;gnL5dPZ0xW8lbM|JG;07ERLf6{_}e^Yyu1qhh?hWPE+|6kQW;`Pbb zGOwjxn|gKh)!tW)SI0h?{^Yq=oL3^RjEp8mPmlDBoPBxVW%cs#C+tt0`gro=XFk^V zv2!1FJ{tMx$VU<%IsH=4OJ_ek@L`2{@9htr`e5>dXFkyPfphP7-XD4Y$cu>=PruOf z!r9C~MrDSF?cr1JOTO>Sd;8vd?mf~jOpspp2DwVyrpO!ApC zPxn22?kVS~$WtRvCZ0U~M9&jvA0K#JJwANWK6z>=IdsP9bI!fXc~|6JBabB>JN?d{ zcb+Fr}9oduEb2{CVKHE3Yr}~ER#^%)B$-B?o)pysq zJDoctcaGeVzT=9NUoI5Zy4oesFz!{lvPVb=~VGQ<+pM zHI*Dq_9l(w*tO|vqXj+w2d;`=HF4$8mEBiPuFb4Xt({skx~6xHv1aUw^cB%7#xEbd zJbwAa>Y>%$t0ynZT$Z|Q>eA6mdoML+=I`%WWvm+OPIpJU#}k8zcw%DZ(8}(WlNV<$ zPF*~;Vsu6C3S-6C^7QiP^6`rXFN$9@v218r_p-^QnWd?vQ%gpdB$iAr&MZzXek;BH zqxN{mU`M=TqJ5}6(mvic*cNY_XdP4B^JsH#v(Y@(lx~VPjW-T9#v3OZ zh8nsXChIfxsrsq9(YoF`qizg+|IgKo*7VjGHDj@KEE*e+4o2hAiO5i-J2F|FsZLc- zRgG5lRvA@emFdc8<#@$lMZ997e5ky;e6lQ4mMS|F9twAdC#{T?vZg|#q27=Y8Vja_ z(cpOLU}?N`A}|!_4osG0N>U|L=BU|g8s?ahHloJ38pIjq57&S0r`O@{|A*b@|F!u0 zzma@Xseye;CGE!@r6LBJ9frv%by_JqhPPbktFIz>Nft3p<@`oK8MX>Esu}l$_zY#^ zpLY6>^v@uW!q3KE=o?Mulf;WNM0kV;kr=j28rY$O3?tH3Cil4)+vc22-?l!@2hblgg8iAzwxnv+PH z?QMoruQXGKNh*klKB(!{PO7wre#y~|g-yuEW(avPJI6GWScv^nGmcI#eym^_)n+ac z53e|F5ffVa@PRL)0uC0^NVss68VLkkAB{91mt>g67r3MjCuf>nStM%!QrlQBX^M8=5-b%5w3Yj<`wV^P0Bj1QVxE$Lg93QHZ#CC^K?A~4|3SU<58j=#3fC{ zh^r90>2;idg9USQH9I}RDZn`doK98CeBl*C8N&GpG?4=~wbVD{bFNv(8_&P5}xfx2>$;NsvioFx7_=J5mo3y~nvSDOu^%j#n%jE07=5lkkbdF0$!?gq#PI;V=l7#6Pra zIGbP!Bo$Mn+K>@+(F4?VHkS@_?y&=o5{Ew$K~P(vOdXdTay_n9Nx2kAGc>rhI0yR3 znJI0F5O0NB5tee2I@Tr9&FmK1oP;E|r5mPICa&&?v+SA660<@K&Bxi0A$`tOC*idK zG~;Y0t}vr;3xS0#KDW;3ryNIBdQOr;)lDfG*gE8>BvQd3E-c4}z3|Wt5wuhe1%n|6 z|7a*Tb(p^mZxTOj?a*h!FV2!wxPjt!NrLA&amnoRB)yhI1Uz$*OtziL8!3=Qz|dJb z*dk$ji4lnC)L!+>SilIICFOe2K%JH(5pZ1u_G)LlOD?2t^lej8q9Lv=l#syI$ygvM z9wRMfJJgN@!bygeL&!y$9?v`#aNwsqY0F~92xc{7e9~R1laS^HL`7`s(Itfrb?MyZ z0$-9rh+`@HO@gj9L$q6KNIpra8>HyTk+uW%}`v~m1o2e*~2ky@9*(HZC@N%gEG;ntF^gDhBHZe-JsSQ{}m*Bb710vAF?=~5tJ zsf1@#_1-a%BMh8O6#Af7^&Ii&b|YTbIy~pE zYyQidHwBaGc+T^G$>}#F6(JVt5OiF}Dy3Jjjy|a`@1D)sEGro8poP&TVU@dmAA+v6 zxPfvba}Rslc4KXBNQfIIZ4q+pJj1f}sgo$)Y$WLyXUrtlHGn#5L`GiG(9RIZb2gs8 zQaC|8ql^-)z-HcaE%H*hj3&j5oNW;ApeO+pm`+o{3~^9|SBF>=uFKgWvWZUMuJ$Sh zX>kH@uz=0>OqOC5;u1!{!9rXh8MI7ignoy}x*17tGp@4b6bQ@FWRd`XP=HH1Y(*5d z-DtfMQ8XaQrR(e@JvPBDpIYF8}()QY6t>xzrB6C3bdChIQ%nI_49=FRm=PMPO`_k+#TirB^B zXdhSUyH-gAB%t7h~nta>7A$ zK-o4HLyFA0b>j6D4TlEN!FF3bY_N!ASzH&y(pKs;?WTE-ES04*v6bP_=WvUel>vnv zhM;LXq5#6lj_t&r!v@*=1jtFAvE=*l-cl#jS}6o7ynV==;A|n)41;|P;Urrxna;r0 zhp|m@S_hBok~tn+8{J?M_N2Tr2OQL%!(1J=p~^PiYGv@5F~`xeq>8_QC|Ybs^et!- ze%?OVilsp$D9$mku(jVblWx8yPRa$&i%9BtCX}d@!@7mjg$9Dcm=sHOvt%Gj%GwUImHL(=y;CS<8)8kbUd{PBcBpPWuTYT7b-XF_}H;ItvkPIquT}e8UxnvzqVxEeP$M*h_6x-BcsB%;K&l66p&a&raWbE+6u&6H9^bui~PA}MKrB)3Rid`AbL2>|h~oNXnEgm>gX;SKUh3+UNit!QfD? zq+4CMfQyTh&W0qa7#^#~j(jKJz^6?Jpx!OxB!e*6G>qEF6KWaP*%37?FH2ar_Q_{P z46I{FymmGN|q(PwLEPYHrEOq`rz2UYL&Ib;oBN2L6Gw52?HvU zKkQ}GDCHVj!_zoc*%H)9Vu97rckmA$JRVY>&+7WFD2a85L^Lk%;tXtnOGdncvhH;h z*&>CwBr}qtcOoY=JtUWP`qqrLQ3A0{=(*GH(!Ky*lG)medPr)Y7Lr<$(~G%;r*d0X znq?=GJvd7QVo8azlUTxssC8yzfCudewV-M9QtdeKK7p7(PYgkM&ucq@z@7#6rC1X% zldv#}yBs!hZis1`MsU-hi|1HsAc^y`jTLmpdwCs3GOX^w>>x>QA)75#`k+w5h=4H( z2g@Y>$IucW;Z>L7fo@S2U1rv|5!cfC@bg)ufKs}+X9hGLq_pde8=~HUw z%cYf@gGu$(k0L1?$NzWcjsKs%dZDaQ-q}xwcxbX>4AlWP3h_lo_#1>Ae#P+~1&-fu zz`xzQF!*ivjk`B&yl%_(jT@NA9lmmnj~W{e)w*UV5%a^zu6DD()+c+fFbl9n6ZQ^A z$B>Oej*gk@`zU;th+uTg`pv1GbCu?eWD&XLkf>E;SXd@JrqbBuHe&OfgJ$dm)UMRQ zeT>&7dNWlZ;YrRvWbmNcClY$E&&W^$|8fQ1SXUt6CHAUp1tM%khJ`U9r+OT~ufRF{ z$W6W4xv^(s>c-T%tsCz++CR{b`2{g9`!1%{rFvt15z&=M+Jt$;C`y(I=c~9dDh`tr zb#>(y?#&GaI-c&&tM;Zh76`yrabE2u5UNpRSQrz|Q+p_Cw)U8n+p@3o5sJBoDGwk+ z-G?1suIO(NK7e-35#R-mU;e?r2lnnxAIJE{JtuOf;ZtvHD$w$@y^&Z~AUhMEvEhE9 zzee~ln!_;+BrR}GnNy7qG~L#JZ2J)z&bKSI#8~WmarnmSAc#|+Ck#?nA zAUcG$&{x3WP`F(wj)k>#$=o_wYRe6#E|+@q`T|+c4Bc$IL}a;;wiY_Hfn4Xvw`y{B z09Q%{syA*Z5Gvf$>yXrx4gzJ0{u*H#t!nRF2S4`obt<)&pGxD1SrpOR(>fCSk$ZF} zrqNt_we0a*jvhSTzx3)=UbGv&BzG@w^)b@h%UL6XVqQq-yAx2Lg1x-WN5I?5*Q4Ys z71<%Qg}wp>dpTPl1$%jWfvjhSx0flnT%_Qc<>ubYSut+l9ws{qguK0My627_B*jc+ zpv7A->}8T4o$H_D+@a?Q#pvRcckV!9w?R$!6i9i}AytY*I7v%VQu}Kq##hRzQdKHf zD)%s%?)4F~Fu5oNZU$R~^}=Q$=P+T(3Y=5waD48DeoXk`Ggeeh?<}Ht2QqC{WWBIO z$SF|g8mk_3FaeC(e&qOklDmpX-U+czMMi{}n-cy9u;UKl4z0jBF{fFf8q$Xj?%Q~% z|9(u7d<=t{j~&+oWo>Cx`rI&mV-aCq&pQ+u5w;8cgsUBVU|0*Udl;7+Kh>LxsNM~| zh4{uD@7>4+LO<0?Oik3DUtCP-eC)XW;NE-E_*R^qJEfnRzPX4v=LzYQ*+LqHaiO1h znbX4N$GVmx&!>D#5#>H8U!=%J;WDA0a*eY96_dA@xAq@CaQvS6Ot`g(32BHgk@G>L zaIw(OgoqQzBSg0F#r1D1qQ3|F3l$j=E)YJ5WBDMCt^()OIUFU<%L(s2i?#LJi)imf z_MN!qQJahl{j~K#=4sE{-0vtN%twJGxS8jECl?F-gmtBR!d{{0+v#@}(eH=mLOEGB z3Kt0d^!4H9=@)JEcNG!e5All?*(h8g^b@al7NdGRaj)=x?QYopETEdcyNDGBpns7f z8->e+epcv1kK_H{ao957{87k!tkN<|@qNE%e-JXm6_)wbm6loYOCj@pe;P8I?hTnE zFNMq%YeMEXm*6{qe~h{Rz8W+i`B2a-c`#(YQXe$mxT(y1{|AC*+li3*%e6tX=KW>n zr@kFDuX!hE;3xAe7w*DfD?|@3HBI|`M z!k_7mZGRETMvwF2is+w&@?_# z_z6fZ!E1O{I=NWrC;Zm$*p3v@e-fGt71=0UAoSCJi+5}TMZ}+i?8VY)t5LW@=qLWx z?%0sEdn+^?#%)2{!&_~s~ zJNh8>+7#I+Y!&jJ?_qg+hZR}plscG&PwhJX@S%SHn@u(SP!Z7&A*vc~z6>$)r8#>%{^1>W>d>L3 zTqmb2XZjrlDus>sV@PVKPlA@Bzg5V&X?eLWaE@-oTMj?KcT4N<>EC=&LD>cuvi{M*L16Rj(1h0;L*7RtaN5eN%D*v3U-Sm>=K5YortX zhmIURU`u_wb^2I=QemCGhO7+rSS6c!U)#P(-8^-jcZL3Zj~b5H&aS z){BT$6ln4?b!XnCv zN}`IWCZa@)s3GczdZLkNBH9U?=p?#`vH_rys3syr9nnBE5zRz95huC`0oJN2U&s9_~GC93HzreSh@+@k4`$;)f>g8@jLi zzR7zt_onWhIyic;_n>ib?4I;J(R;=Z3?7IdnAktGzkB~=f2KdxKecakU++F+-`L*t z-ss-(J%fAVdnVFD>F)GoU#2hBH?@0ockgav_t@R(yQ6oH-!*tw{H}>RhwkjYbMlVN z9jQB}ZXdn9_jcpPil z-Z;K%a94cS#Ll6e-8(0HGrg(ash-iE-X5c8Y)5)WbjSGi!R_(w6WfNib#I&8n%SD# zI(5V74ZSxQH;i4MzCL>W_?E#f@huaZhcBZXDk* zxFNn_V*Swi?)8)FGV4<7rc$G+-jtCVOQw_2M=nZSbb49Ova?GE zma3)0OY9}57AF^faNLfcvXl0ij=qj)$9Vf- zd%S(3ZK$ogZL&4fnrfYD8ExrpF!NkzwS%?s+KHN>n(ms(SSFT=O+`ney-_1N7D-2Ui};)lgM;)nsL+ zGF3TMF4E${hXsTcZo$idon_6D_a zu%?dU~g-2{ER(>M@C_8A0IDs?AlKwFO-F zSkYLk(jyRgX~>CbXU2slv@wFS}W^BUlq>+$xwplkwS|sxq5#LlWyZS7Av$bMibyGP|>E+$b0IbwmA&^a6%f#kc)Z|%eyQrws%F`^5ySN>b(^q|wo*%%!&^18FCy5aQtziI zl2^H#HX*uNM|V0%(F@x%GaChlcc_+5Zuzpik1cE)as5%+j2-D(X2Y^D8=!8F;SmI1 zuj)co^y<1s{vjF-4T)$#MApD);zkwz6mpA0Ue{*b=^NOj?CzD(5r%AP$D* zY!GPUFX7*FRjXk5%kagK5K~<-WyN`?j3zM4^?BtP>bp~wQu#S5u|1#KL>pICHA8&4 zM3qKvR3TdS7^1td?8S03j*Cm&1Qj?8k$?wV&Oz!Pqvg3PXO2~OWdxN}>9zCgv@k3| zMle9cjYu{c7I_ug43o>)U|h5L>a27#B6vbUroc>oD|4AC-JphDeOZnQ2b>k6eYd@3$4OdCUzT-tuQRb&STr* z?xUlIyuad(p-R!ze8JW#N&_eWlxDK>@{_k?^W-=0#(Y=TCMN<^jqL1M`O6!&`SPEC zbG{s`iA#lWH?Ud@Dn#Dv%@&w<8@_z(^evfN)AIVTXvW2I;XBPP|1!E-@;b7(R?&RS zkxgt~Y#I6xV1>omZrxK-=kO++-O%y|5a}+Z{k3xi8zvgRL_|()Ri*it*9JsoPfs1x z(v8=~Ay&$RH%#fumP#CXGnd$QtgLRYY|V-4K$O0G@fgh>Ky8eF1tz$M(9AkHysCIT z$MqXWK?L4#jHo5*iAJKCXeHVSn`psn^l%5k7wTcYOAnh#oLd7#BVK2RD-(C9a2RK@ za5+&))T=%fZX(JC_NZ`MVjprLR1zp5fqQ)>{9`> zlMI>=uUsb1Q(-w9;shn9sQ(upsNOE)+cofZ4ZK|gZ?Oi>y)^M5^`XQE`#v!I{?jj> zd%=F8Cu3xKhn@GGdhc0$7b5xYf#*k_JM-+&v)#{5K9hMS^~}`MqfhrfZ9F~pRQjpt zQ{zt#J{f;<;)$Urx}TVQJo9+!@u`!eCwosCC&z};L(!peXV8f|gYU|`Gy3S{BhiP` z4-Gxo`#|c%*s;+;`~LBJ`}Rloo#`99`}FOZTTkCOy7Tmo)V8r3Caxdag0~?XC)W+8 z#*q*nWYm;j3r}>hZapNj4n(s80wnn zjCXd&C+(=6>ga9fdxv=IM9X;dMAKBG(a5(8<8@Q=PGKrG8I4Bck?!hv)kNiF#Z>ud zd8TYMJYfx4W1(~?8XOA@ni=$!cx21qx3>n9s{a$xaYDxbcb)w=scY#)p{Cze(2K(B zRpIp#`7{!@C^9T;6#Dj}aAKGprLY%8UI!7!N6_ma@)=0Q71=1Xg+GUmWJ5l}ULT{^ zAh}eLrm$7`^XOxAvOw9h#Oq^3&BdbDA=Li2+Q;be0+qu4Fk?_L)K@`E(cdW4V=wn0 zoaY>T{TKf*_Hx~k6NmTZb%=3W&JzWCp1#*|zJv^06&V&b34Qfs_~k6Uyr%P{kD}Lf zz5=ZlMb-`2z?pukK(Vk+zX>fvjf0k=ze(sfJc7qYOmTRGZ>2t6Am|z3RqC%o zq)m}wVYARzP)3-}7R;;FXM7~RT0IT17Dd(zn}t71tv*|zSXisyg_fay8?+StjY8dW zX7~1+X{kHYhY!p-D*3qrJx|}O)Zc(ct0Kd~CZVsM*HZKK^6K0DyzSs&biLEPM>$~D&L1xOo+6SzK&~x{ ztP?g1`33BU{3X*5`Aa&}?=6rlY&jDUGt{4emZHB&=zDm~9FO_C5*zA{n`-)f1%jRd zUeoy@lC~)_ENm9~3eFsl`GR?EXV^#5Yde1ku@*(v3!8;MOWVm5QT!uOB4E0x_rRc8{`qe9ECaBWW1)%)Sx$F-XC>7S?-y$nR{WEAO`s;;$1M2jAQF;o5nUc{M_a5Uz1!|tUSB?LGq|J&9 z3mb&KYI0Xopq5vUANJAn>hYhTRHMjBVN7@-_4rbOQeiz#K?67K_-`rt8-!`>F_x~t zxxJTDhYugY+zNA5%T;cj4854 zIDma2WmnBO!C;uRAT<@cjRsmkqIw&*cHszM;xMOo$1_glTmgXS?Ij&U13@Emx^IhwHyypyVlgr|}SS zuUBMPSR?dRlJi`SQr;Q-Q$AYW89WS?T1Cc$HNp!yr#jQWP@q*rb7V^0QEl=BPA#KRNQITO`ozPcH?qBk> z@><8|ebl_x(IKTFV~VU1UP$Y3rcV`U71rVc|Tr+;^adVvRZ~wuE z=BmiC0y$6KtH{NWXi;QX*eLXsb9m=jD3@24U+@w1>T)ThY84q1)(9`GF27iyRalo7 zL&Z>+f|jDcL8xD5&pz|(y2KnY$NL|e^Ys6v0y$6KtIKXkv?wwxY!v#+NnIAo<<;ev zeFVL_yaZCUii`s$Ibwd5NbM}*^e$RpT@;e6RI=a76Am)jC)wmG?7%~Q8ycvjrWT3B@JjmvY<<;Uh zedN4a+=R?)6j>>Z2`{7;f4M-ZuokyM!%#axOVM91^n3BATO(h@&s~kbQlRFkd)2rD z3eAcP3mb&KYSJ1D)bi@_SAF!ndhCT#jUp?BG2w;O>Csr z7S;-VrDT`oO6AqycYMUW8tj*{kd=yz2`{7uzgwW>)ybveF;o&uO>fOSOUGy3-@RFC zK87*>(Z2|qum1|>Q=} ze*b~z{-?~4+59c!iShp%MuX-bpAMRb@KgBR^PeAA+k<`TZ$?meo*TGMeJP^*|5u*F z`2RulI(r%2XuD?mHr67#rkQ9bIHtd**#_E(4x)=N6F?OaC2ENVqKV*O|C(4IP)F1c zY+*Na^!R0GM6aW7QhM^Cr!e|F>VA}AcAP{g!;bvy0WMwS*l|3s`*2Q=M(H)o3_TC} zHHQChWo+yI+}h&vw=vJSP_A(on1_m>bGYtdU52{h$c&8J2V9+Hr%*()`{#4)SLk+3 zy$&6`b+>JaXdFfaJ5H~b9*D2HV;~|UI~2QAmr0^FglZbkVPrr_WEX)x;FQ(FG)j6l zsmdDrE>&4iG!aG;2oNEnjHo0cfF<30v%R%rh-;`N>WN0e=mAQIQX)iziE^S+g2Q{* z;h!CHA4L&$0m~8DV2=QuLHk1-=GyBZ##GBnFFtaOWuR4n!=H7@G>5r=$uG?Qe zjMW&^Ff$OwjV?!YhXqs@cCatwnob8DeA&srtZFs(P+m7*w*{m1TG%s-OrXx~?wegz z&Q(>XHmm9`982iOj9l0QAA=jP7wO}O6;uch2z^9&hXumOyAs}AI1B`{ip%j+v?av`E%wz!n9>uQXSdCTip?ChwScpdS=EYcu zGD%J~sTpLz6O0U)@H*MMoyW_)#=v~$-V8^YTW+ZuT|Fp$*)Rrga5Ftrq5{Ec>&$Ld zT~5>!&8O3TnW;AnZjAnxkg&DGyzwVB0XgiI8={z=PqGt-* zac-k(szDVu1<(P#sp>3HI>KGeooOewsHW(deHdWlGpfbwKaVskTfE~XN2thl&Cm;F z59@%vSw&;Rcc^F`(Mptz0D;p$h=>t&gn1SyB_c!(5j+QkiCRLbJ5{uj;4J6SKmrI6 z6-l6)h!J%HRDQIP2#o+`M6G?7iZ&3N+J-xP*V*A8|#E@Lx$t^C~Ws-@<% zt0^rL4G+7hvT3H7p;@%+e&ZPb#I`$Eiu$?okRbumPLW4^t~~Nmlt(!D!0kLALn{i& z5Ffb=bRZb*B1$k?AsQvBPXV<=|4c`C|K-d3hZDb#IZSp!d z=ln~Q7^=@zFt-G$s>5jN7^_!srs;y6+B7-$aZkxepWI}67!mX6lF=Ec(!AABDCJri zU{u*u*`Bi&>)v*6*TCB~@OBNnT?79YYG61s@xH0|q@N#qwpf4sv7t%l^kXBBI*;@{ z6n$vuf$j$;Ph?J{PD~viJ>GlVI6ipP{yEOYFuHFb9Zyf*ow+-8_tagZclF+7+%hztYx4fQ8Q8*vBrag!FX_@ zbf~nubTW_$qykeVqb0p1M#-3&HlyaaF^H?!M{ixUZwLPVfBC4sr19_nOPrj)|2xy) zEAn3CdNcsT_bWsNt;5NN4G-EKaglU?a%|64_}za3kI6?q=c$)<6$|9+9|@5L5jMV^Oq zvT5Axe=u+MhT4uT4EdB)c2i%UlU?Ix|J(CsAI3KuX+3!!&dH{6v;UnU**}CW!uZ?L zc{wMW%FX_Fi)8;Wwg}@-s^{gLY$`YVGexq01Y3j^c^=Nmrg5{MD3bki*dnaR^Kec! zjhp@N70Ld2Y!O!Ec{nGV#?Ais=gr=bt^fx926bL;cJ@CklKn@JuOajIo`=Bf?Ej!h z_MeyR$Ic^fB$=K49~Q~}>ykakvYdx=vT5A9|Dz(=e;ZpEGMpp3sjtt;u5q*f<09Gr zF19eF&wqAPU!Rj*<7WRSMY8`hY+*>Z@a(3(J}0}z&Hhh|WdAqV!jS&b*-d?YPIir( z{ht-d{{LVLL%I=XH}&;7*)?wVe_kYe6ZaTK!I!wRnH2bDXaA!j*;h#R?EG~eZg%#6 zQ6&3D$)3H2&cn^l{x6GU-znL%JI#5x+1Z~hlKpbYo;^&?!_CfqvPkx;C3|+dI1e{F z`yUs{J}KF=FT#1a+1dY9k?gOR?Dz-zeGhZ`bGHW@rC5MY6wJvhTaV z?BDobKH0}*hEqcwL&h~ieBcTGDj~<7&h_Eopb9$t)bei3Z;$^hus%Dy@wY{Ejw9~| zMTUhDq1M@3SaFVpkG5A*XZ@k{v15W9t-mXxbpk3~iVO?ug??J-Q{Xg-7QaDu^u*rd zM~cz zMC)PEB5{i>TBO$6KdV$TTGt)yKeSJvRKM3Q|G9|PBglD$B5}VAwg|P>fmvGUmFsk| z1~>H|?mv3)?0bXearE=I*w-I_>tDViWPa)0A#*eO`=5P2Xb$~%so9C&xBsiu+=pK& zey{&$sksTizx!#a`7D0R@caHxO3g#~RpR%#|0p$g;CJrdOU(>^tML2%e=9YQ<5!2@ zSN^rsyam6X{!6L(5`Js(`?IN1^HKcT@cUJK`)@bD|A$|X^Nqbdc>e#yD<~Nppa0us z=!;T&d(uZSo(7-i&}GSnnbJL~|96qvdk6CEP-IwGE7Y}jkon{~_B(OvSbJO0!|~|; z^xpm%57W7t|EGxNqfl#7WLOv#YE5a;d75DrM&Da#ZtFjO&yjtaIcn#MsJ&Cv$gm=# z!s2R2_MJG?zfG8GAyhWYPDGpEZO>;*_AV%9L;|zqWLbUwJ9*LajS{6y!|H!FPgiQP9j$`}ZPhC!y1#$gnUb)M~T){+6jS^x8u^W#8s~ z{rla;jGmhQ4&<%6;8Z%x)H3Sb)_=_X3jNx(5A4l;Bj?!K zwb@lRa&-?-^~O(p3~9hl**~0@$olfU++O_@2T)J+Z*~T1ZZ9kG@)qfVT>S@@sL6KcTe60+AZPo14 zndK~WuBKJn(hu+Hf2)ScMp@gY|I5cVuSq=%OI9gzp|D%1ZA&wsT$gQ9*{{&gGBCR; zuSxy4k0D-@dJZPspvW%a3ZdVwD|ePS>-DbFdh?nw=ML1{v3PP-Qg8fE5euJ(ZJQL? zC0r`h7S2AWg`5S>m9%hYe|q0rwT|25SoTH{%iax}HY>7AxJ;-mdoXtg((lYPFn$ql zb_2`Ze{)ovY?Nc$n?-DU53Jg%$S&cH)av5 zUKFdygd(pIYO7}7gU(o$`zf3n$jZHd=PeA zrO1TvN}-=M6;3xs>AP*&$DCOcD&^S|EMm`xq;|-JBG(H2?8&VinZ#wT+R2~YCC{2r z5o~nixLW9EO2}DK`@4A7|5eLWpRmk<%CPz4f3nP-6=Cx`|A_DUecv))xi@T9 z;P=!)%QUxG=G~ji%y0dA*j(}{#4Rc_-}r!KroS6DzrQbRUh+iP{KXe7b8Sh;{K1cd z=8Y#q=8xkc^Kc4d{wIUx3uiHoAPN6jLw#;2wxAc!|HiAZ6^_sUw!^76;Fd`B49tC* z${D7Vx0lL`RL#dBbcG@l!pntzRb$OGmjS;km7gIMMGW}_OjxVPgm8_}&yZ|$>6a0M zvl?!}(7wDnsVrj32#i>*$b|4Rp`R&1X92#H&6b;V_Z}HUKdVA!jdstor@Dwed>?g%A``;Pg?{!}&Jwq^K8VrUvrNewR-I=? zq=*@xgaK<5nGjwf^fM!Sa@)fJXtV6dA1Rh+NVJF{JU%a1WJ0)F=x0dCS%e!#Hj)0r zv!5Pv2V3PC5i4TEYmmQEkqO~ip`Q`u&c*mJFpW5_2Y=71kHS&fdB)TfG3IqKhD<1O zt+2Q;X*~zhEMp2ME6OvbwumvG5@X1OBG(Fw8-uCyIFx&qF@7fyq`U{7&p~mOA{Pm}g}zcwT*dRGiWRldN8c-IRzD)jE%WQoSJWmSDX*xX zMiCc%{u+5E1Rx`7M~Yv~50GUTMcr z&dU_JNO-AG@74V|hlzNdYVY|k_i@-QZ*J5~UF4iGoauHSTfA~-ZHb5#3xvL(tH)my z>(rd8IeWXqN7F0+7o_~;B1K**)a9S+soZ`3&3*88%by!Hclm7}TfFjTZHb5#3xvL3 zI+ya#shU&%xR0h+{x71;2}Ldvt`zF>&-MJz)}DR-cZ)vHQ@=Ca>0^Oc>Z}D3(e7|9 zc&pz(chA^eK5|}xzl5T8D{_%AA@nqVI%`El^y5Om6YF_Q zLcQ2W&@1*=WLJ}m6qykE6+3rV%ZrHYuJ(N|;Y=^_vB4{J)`p0v+d{poXTNXvnp^qRuZPT^dZBQBA~%I--FvM}QKdln40i5O8!)DsOv6JeeON{CV-M1+ZQqJpR*B18>QPc#xH<_8Iv5T!(ju!u6E zf~X{_i6~J^G!O;`bB0TZ01+fCB21JMl|(fWA)-W#s3GczdZK}7B+LX5Ac91Qu!u6E zf~X{_i6~J+)DiVWBhf^(5UoTzVH0K&C?!IKMU)X0L=_PsVni)bN7NGy1jm%4#RAPl z3(-on5y}A!!X!$FQX)uLM40G01E_O=L6}4d5gL zh!8QNmZ&Ehh(@A`Xd&7NV*oIT5~7p{5n-a7s359{2oWP{iF%@uFq|AaOAx?;3RpxL zQAtFI8ls+PAR38gqJ?N9%wZrvloBDrBFc#hqKb$RF`|}eAex94qLpYTj8lL~lmIjJ z8DLD12oV+$Cd!FQqKb$RF`|~JCmM(*!aNNGh#+ARWkdy0MMMZrP7vno0^ug2l`zf# zB}9M-5+NcC%-C7Zm`b9Wh!8QNhNva#hfAsyH&BxssLKsB{tz<_4_XKv`~}A~#T(8>q?+RObe2&TLRtO+8uP z0EXM>ZL>+clkDtbv~dpJg(es-Ap%5@k;^P{c{w90h)SZ0s3u}W7_e59(Ho)n(kQ)k z^scF=w}EIRnur#_y0(?xHo|6j1AXChXTLf0&F*hbeq-nx-QSq}dgkk?uTOq0^R@1; zO@4LgtKDCn{7U94sjp0ZdGyPvFHe3c^QF|6roNc@V(N>NUl{sA{0kFfgJaRL2tqe|3c5FoYzmicJ|fCtI1CeyfQL+W<-r7UhezE@W)So z?A%A~kM?}TdFj-L&weQKq2vb#J}~nBGcT$a6E93=GMQ9nYIt;*-(u^2-{gBU?@hgT z>OG_H>3xs!p0RhQ-yMDT`16C$$Df~gZs@u0=O&-cJezuU>Y34JdY>_#8GAbYboA-* zrv{&jKQ-~BdUEWE^b^r1#vdPiJpTB^$)S_oCntw8L#d%DXVmF+3}@_J>32onHU8M( zWAVo(-Z}Kn?srZ;nt3$!=+rw#-_iRH=aKG5CLhi`oO*cbq0xtWA2J>qdocZA^uh55 z1|Nt&FmYn&ME8lw;~BhQoH{motoN94Z0ugoreW`s@dq?;7?lty~?Md&6?io)HVx0Lz-%ww7-{kJh?$qw7yGQTtz1z5Z z?5^}((Ywa)9K17r=foZAj*Ot&TT-`7-8_18@6E=| zV>hL5irzGSw70j{>FMs7+>zOl+A+0#bbIf1WBb^) z^tR}>@vVbf<69?g7`mbRhRN$Q*Qc(Z+A_MOcZ;!QY;$^Zbo2P8!A%^~K6G98b(0%2 z8&eynHjHlQ-C%4OTc2JZT|d5Va9w=eL~1D2otjK$lBwj>wWHVeUTa)Cc1`-4=r!Y4 z4_+O=dg7{~tGch6yfSlT>dL9LqicKD8f(Yaq}N2(j9)Q$Mf{41%ZD!SzI<|ZW_4=y z)McZW^xJx{2DM+V0xP znoLcqW-2xs>x~()v1l4!?i-H`M&gl)>Y?iH>PbxLld77k9IfoFG%Cj`(iPE)@$$j) zc=<%xP+51`WH=K}g{Q1htJgC0*Zo50Gxk4jOem#x|NX%q?84vwFXJEe;Q06dxc%?q z*S*8?UdZ4z)I4uwmifFP@!rT}-;hM)-AG(m{54d*ByDrwI9}u<=)IEpItsN?k&A>E z3;9ZB?yf1evgPlU(ly0>3FX@%#hG62Bkz?rD<2WzHlgn)d@!;%@DcOM`VEva zp~ywTl|sL=mN}iOQ_8A)zqo~+-RH%tY-jpn9|OG7W(|mlbi2^^OFI~eRILj1a(3-X zA2qMI-$X%IC~}c-xzMk;A*UU~TKK1E^k&JvU7Wk?h%=q=5%-Fk6_1E)n^3=6l%Cxz zi02$VB`yBUnIp%QZX@pY5%Ws=%P8Z;id-aIA@nP$<#>&l9cH|u!kZ(W_oty%KJs2! zv+@xUZWsC;w8f?|zQjk(E9|eJmcw=;iF&%Y4+l;{F;6x?GWqgck|@iW_vAF~_s+_~RCJ?(RO$^lBerub5fk zh)6aIeLn-D__?nft(+oW?xW-t@iYo|i6R#XR|)-!Sn2)+B&TE1Oi2qq){)nWukf+L zD{t0{i0Iow-_Lbm5La~e=Q?sqy~an+EA=?ad$A%H30DaHN^Q-Yp4ffKEwEpwC1-lA zkGNOZtawCZTZO(~o{+y{=c(ls^hzHsub|&T5mzd5k?>-nUqQo;t@I^UI!L)C_3akr zOkd?A?-eyG9}(d;;U0BClY?LFBj%O$+bHDW6$x1>Hjubk;? ze5Ac{W~Cz{+9LFwQ(JnQoaqfdCU_;z znh+834x#UtNTkGtf-@y{-q`3P=gng9yC~(8iVO=|ge>vyIlgbnQQZ4+?C#!mQ%}#% zjk|X3-Ug&LZMNO?;kjF^x@_9!F|i^-Meqb{0KWY?b^NDUV2xy5N}>rPzbM3WeRrt zy1gjGah&lA(l{9Qj(?tXj?AVDk~ygMDW1K}d_x=)F{V1WFGpbW1qtlNu6O`tDJc-( zy+^sqskE%p8(RvLyiL8`eg>6tK#^f#i;y+ux7%-4>*v_*7qZiHEOvLZXPsVt{O)q| zlFwlt|F)oc-#hU=fIBP9%keFMFI{Pw8}YaQZ>_b=UHAsTnKhQ#|8;z~?`t9Ro%jae zn?DJeFW_(gb$=8xUklE0v`yOzw_5Yb6c%t{^ef<&AxvPng9BG_}1X> zg-i?M0G^IoX7fbQ{OGxmxeVX_QzNE&=EgU_a3h}o?|mIr1SkFf2mV$3@_gdFd3`|@ zdsRMvqx5#B&Q|gxocVU<4FyWxR^HB>KxPjrGA!&A>YX`zCI;Lq;~2)y+_ZJaIz0K! zI+QVQNdNtN4n2H9NA&ES>sHs+fyh zyW0$JED-h#`S};|CRb^RS2lO)6%o_UW4;IyUx5T0h59B&cc5}N;KFgg-nL`=`kQv{ z+_-)HZG1S`%vDk_HGQ*>T)kY|4YUr96C$<0Lj2r!yi+W2PKCUA+Pyoqefy3ZQ#Wqe zvE7hsw-$TzmI5(PT-RciWPPcyAY%y@HWW4U;C|pl`slv?eY^KOyks{9`QiJTd=}Vy zPygQg><5k<+-EOa${gGx-&$aWr{xv76%kkAIf_LlD})zV$jOZ{7VMN5b!ZYX!f(z!p!=D|j0su0cnB7M!dQUSPrRC=m0+y@FHVDiMHZmYZF0 zJ^pv=?xX#KCl2CHclV(qd+*zQ4`x?7pM8F3fi<3>SM+v7Y{vUq7M-jRUSQGhDiHI; zy`od#IuU?pmYZGlH5d=Z<94R#c=dSb#Ib`9^uM)AxVykEPui=54n%CkR6nc)vO;)) zm9V=&%oF!2fdcDA0G?THb|tLFX(+D}j@^?!ievsQHG{qaqdZ-&25dyEQ=}oR5ME#n zqzlA6ajym_lN14XW;r82#!=2Cc&V9J15$MSG3C6Ef;|Nmc@kdnBW;F;x&{1_D9R{AyG%u#Uoi0u4hy7)ZL=bq*F707$}d1dWH#5(*z zie)7$gcn%W{sJ*i+$$>uk|F@lEH}HX-mX5@e_S{4y+=+QKEC_-k=>8z)qsAp3h-_ZsAV?DlCL zDk1M@?@#M+DS3pQK&^ogImo`C*3mF|j9o&l}zVh&mxD}<Y*2n5VuNWU^Cspec4dl!0t7?rX2OMRW zRqGX#{3Lsuc-+Ykj?m{04i%THj<>SnHQtL9ZCU z!j7@luNuSPud#oub-IKcXE#~vTczZ;gXDMEUDo<8`^#G23zNTIM*apn&sx99-m}(k zRg&LlCtB+V)#PupFRk@EQSx`$rPexALr$<~t@V3#kk^qKV)xP>yMhr zKW3*}>rdG0*80;n^3T}$*7|eyzV(XnBlg0z{({|bt-lPAXG_URcEh!P%zn7mU$G;u z_1El)YyC|b`M=m9*ZSKE^6%I$*ZO;Q%(ecZn*2xh&$a$3O8zsu>01B0hWtP5t!tgD zBd6GD*ZP+R@?RUte`Due>)(yj;D4|Wul17>@}~jvKTFB~Vvke~AA@&5etXeW$N0zZ$uvOkbRy2~8 z>?3SdHIvmXWP}}tttfj8TQQTYVaH*smOY29x>B+}NH&DXMvH7>M`EkFjBH^)Vym?R zbjz{0jlGJk_A0W2or^6yLdK(HXN>G(FJo&#ExC~WjIBlWYbdtSY%4qxre=||G)OWJTQvm%(tdNGio7;5eN_< zV1xh(jBN>g8{0kNwgF2VzVS#1ao8Lq34Db(gJZ|UaU98s9oso9WfPy9EM&8ZlTBX4 zZZ`I2b3l^K%f4)OMXvR3F37QQ4&eR1uezqItEWdo*2~*Jrlk40tNW|(s{8EX_Bg?< zw3xcMV*EIDuG^(8tFGIvEvv5Eqb;kh+p8_B zu1n9*sC8;Yo<1=n@^YP2`|wbj>kcWJAy>+X&uJVEc#mSWf4J4SnRpSCW$ z?kz>yn*-V+?Yg(dv^V!_E4J(2rmfhn%amwn2eswfbq|zkZ{Du0<*s|MTzm77wy?YI z9dYf=!`dqExmIAp-n>U!8D7^jO?%U; zEfcSMyjpwn-Wi(becA%@x+i97Z=OtOp7(1@%j=$+t-X1=R`WcgEjq9JK%~Ko(+^sj z=R?|Z^tumg%hBteEz;2Xw6*DV{W0y$N3@0Nb$?-NZ$7H6TCe-qIPJ}I+7kA<=d~s5 zbuVa3*y~=@max~oM9rW&w`}AlQJq^vN{?GoN{?G$N{?G^N{?H7N{?HLN{?HZN{?Hn zN{?H#N{?H@N{?I6N{?IKN{?IYN{?ImN{?FzOOIO?OOIP5OOIPJOOIPXOOIPlOOIPz zOOIP>OOIQ4OOIQIOOIQWOOIQkOOIQyOOIQ=OOIR3OHZ!SUcPY)ed%$_e(71?h3C2kCKZ3F&bw3+Zv|4C!&J4(V}g5b1F%66ta46X|iQ73pzn7wK^; z8R>EB8tHMX9O-du9_djP5c%rddPu%;t0U=gYbEJ%D<|o3>nQ1Qt19VnYb@z;D=z7A z>o4iaRgK9vZfzz#ZlxwYZrvt5ZRO5~(jV;mz_Dk8hB23h zx3%8i^VWd_C*P8IOY?o1dk^0;cz676=dSerzJ15KMR!A2YiCb-VDHI2i9OA`GrJDo zIe16>4rk{H>^rF0addmz_Q>}BZOLsXIu3T!bR6B;;sXzPH8gDs{y#^IGAGxXJrc*a2ZajKJ z8+IA=Z%S@DvGE}G7#!Wuwjr{iA3F?Av>a@yX*t^5)*NZ>#}0!N>kh7~S$7os3nFX# z*Cf}R!0v*>*S271LGS9u)yG$LVqd|Ll`Shzt?0$Bg5%3Omsc!5f;|PNmi8`fTzVWk z3M!h8BwLcFu%DpOIeJYSb`vyQeH=RpDy}-Rq-Dt|>?6RJ^{(i=q5``JS}s3zS?^_y z*hA2HX~m^SE@{CIf?j-W@AyTX*gtS&am(UUi+UFgG`2NH8v7fP4JR%Bq4@ zpkmsQse@Gqt7@u_PHDr=fd0wJ$tNZq#J+%|m2H)g%6{w$I5FYigqjIQu_qu>(H~F7 zPhdwt&G@6`ZRL^j{<36Q8hZhbjB6Qps-zb?0gl_9c7=Te`v6YGdSi{TX3bmJaZ9_m7&3_?C_0$ zv_9`Zj;sGJLnK9B=})g6tfM0R36?S(q5iuKW{SDepI%?h3~&>0LH*^?sG9!TK>cu( z-($$5SSsb|IO5B3lrSkzu$18lmEUVHQ_Pj}#Nbk9fSZ5|DzC=wy72jwwr+QpYB*Y_ z4M7wyr8P|lFU5g_q&2}(h9lIv(_p5UE3Jt^k{RG8;DTDKB%js#+>?BlA(G;%^rxYH zM-YrKEM+)C{ksijin-FC*j&vFlo0LFLtni#xG2vCEy2+}*aXeaCQ;{auDIil5T_JUmz`2u2u| zG901icN@$UbEP@4NiqW^hJFodu9E$ZHg`5U?S6g)nkV;f+}pDM`hCl>^m6r{)Xv@M zU8zJnrY!wy5$-WWQVf;;3-Q3geht!}U@5~9>VL1nOfgsb6N9Un0d4{=sJ}|~S^al) z+|{vb_{!gB$fH;)<`d8I>5yAQ#}lLTvINgAgobI6{NG)nKNWD}xY&1{E__{&8IXQd3!CR46ie88Z>oFBgiV`ekI6_6=W-wFC zm7>I;nHk_F;DU-aVcuBHPIlvKRh$IgOtfbV0hJ6>pgmdOBEXppOBv2!n8GUKU1G07 zR@cmg%oMD2O0C?rcT3x@)K2=U6{k_$C0H4^k$G?kt`~#iTpSlk)+acJVHnq`8QSis zxVE?LY46yT>Q3+6BQuD}{DC2uU&0ItmSWupEm$NN#=I&+i7(3>OQUwSL-#J6h`bkN zuTSyJ>9>dQRx9kT1g90K0%?UE!TAhRg3e|Pej^Eoyk;&F^6Oz(jh|{qg2&3NrIbQ; zZpDY@c5d6*(Suz-nK24@+Y`naEqgwvbW0B^;SE?=S>b3gov4<%xE2C+8ha=*(C_f5e2I zawf=}e%N540w|lT#DjhKh7Q?;;53FQtO@TzdN5oD#~9)ytrUOEMbpf*OyGSU`%Kpvtz6~t}eA=S4XWIW{k6bTOGA-KY(ul{8P;8_+HHVu=$@ z7+358xC3VZp2ph$-8chK(6s^AV^Qmc=jKOlMF0QC?)*RX|EId&{}WuI4LkPUX{fH^ zL&e@IJh&9=`Y84YPGT6AlW~r4=6p9NQ!>HgGCdI^MVm#cmRL_eGK4Jaz<(Eif8J&| zgJGB~IPEsG#V^ZVeA%vT4`lLZv(>7Ahqwv_>51|h_J61J9M`}(4#lCY5jwWc*A;lz z5DILB0tW>_n_)G>6f#1G=)_Z>%T$WWOj_VmQra38UZ`ctp94e74yFpS(C7+KRoMbU z$eexVQ9~W2UcPK`j>+%c1`A~YmHam0!Lw+=lEnzlV;E*J)SsEhG>iHB(D`kb3wQWd z%n>?h&&Ld9mGYx#&-WNCOncsd2TuxuHp5zmVfMrk^O=V}ruqiDungN13voABV>f}qVX!7$8>RiY|$KrUl6nzCK%?kUbkjF-xGx**`m-F##gYvZwQTUhc4ZM zpv`a!L)zfco}*yLaT`=KCH2LLrXv2AdhBEKs;^3t<#~3foT5J%>rWU8D1}Bb)}J(3 zz!>aQQJ#XY7yS>i5y2XUVK$m7re-pljf?`;sKK+=GSJS!ZvK!#3%=h_PpLbK7JSNJ z!RBL2jRA~^R=`6HZH6-$hFNg3n4Gy=v!GtEhM7;tIS1Qm!GeZ++R#dAIf{mR#$W+E zu~SKJ3w+(^m{HOrIEA4saCR}K1~P8;T(8eRnAy|+a%fX!hqZHO&kq<1D1}DRMjtd- zD2Tim z4#Ti=4d=5^qcmIO@7cSjs{?~X=-IhDJ;F-2Af{$Se*ND*jYved5Zf_48?^)+1NooPeEWR?FpB+y6$HHU6@wwQfqO zbzokZHT9CHb@ktrS>L-TYW;3$x%IxqQS13{mRrjfMXmj(O07@DORf3=od2J(#J^qh z?dF@Jj`-P&a?FbQ|1;hGzuR}~H*BurU=*YEBL)j)0ac>x!Gr1C{IPkT>l}t*`GKPK zAT{&cS>Iq}8PS>tGc;OhuVYF@X_kN)rLGD8!q89YJBlX!sKLTCA$?J%i%&YS8CEf* z?}6>*JB80z+Nn(KO8U4`Dm$uf7AD49n5u2z7H%Ay4a-G5)EVY7+_mlc_hWL?(hpPDBorx^eK_i0E%|>04RS(m;|vwE)!MBf)%PKXM>#FV_Yct+bPNf;o zT;tmQInjl+5>dC&ONRVPpV73@%LWhAMhEcVK|#=FSj#YMP?APe_GwccS{mW0Pcygj z&?L=?1Q5N9>&*wq9BZNmGVNa)Dk&B7n{D`+_TwX>Km1Jl34^{FC2z%p8G@kAZ~{Zh zv~-M$;W8zn1V=8UmUg%8!l_G*se5W`?gRhcf zwCwiRBceZiyM4-_57V$ycFVxGMLYnA&%*#tW0-PhU+_S8Jgs$1q}I^LpDY(;cE?vl zJG%BHy!ye+yeY1pUx}MfuV132X>o=|2xO{yoHD4|`cuP*6wQUP) zL7Z}!O2&UJOO!@SP=nub4`HVqd#h!}phw)&)AZRn3!7zm;?Oq9bAbD^MU4Af>rBL~oIueI-N@S^+_WNLMj@H~WSJ84rVtLvi-A zA>`$SFz>I={CBC=KW784Gr->Z1&K7>%$JEc!eyTn>&)j2 zv6PrH`CZLItYWxKyHC5h)hwlpGW0=IW+u94WZuTxn{g~ zlKknX*gB*^| z%_cbd@C8FzrF{NkV;Jibder3p>HlT0PzG1_?7@Q%34%7mdWK>4Oo&A0QDx7Pz38K( zum8F4ms_`mYvip_uhzENZRB z?_aS7;6N1n`SDwQahdhwWl?MH*i!50(x`>aWY()z)Y^{Ua}}ld24K``7v+{{z&QdR zz48k;qyInUWtnpI_5Y|Mg2u<04@MN{OA&-Uk|;*FU<`lJFu#h9Hyy)>Ft-H)t* z`a6S{vWF_5$P&fOMZL*$&3NxzbN_t^d1dbRBE)Ti;H3=LF$^9k>kSbou*u+n+j?*ApA0#b+@n^CXHI|BV4-ZKO!0m;1wmU7tYbJ5 zQ@E{6-4ycJ&LCIy1~LU#nX7uA_&?HYZ-=_g2tSZA*sTs*SxweuL-_k z$fx8TMH3t|SePbw1`lo)1Z{?O48u&2FJt7WYy5RkUQ--5MJ*m(OJ=8Di>k#r{3* z`*>Nsw%?17TBZFS#xz%cWWAYgELD{qvA~wHU<>^_hK@?-k;PSxHR9sz|29}Cv#91v zKOVFTf)_K~#4xP+Qj=*x@#ocJ-R{Bta**6JWPa1BrcJK)%y$iWmHg5qH?nkX3^!}{ zs)->xWlBep$v>R%F9t6aPPH(|D#gr2y~%UUc<*E`IsJb^$g33m971#mf;PkX48uwf z8cxtlk1*4FWk~M0F$xqE9{N6x?-?>H9o}?`Je(aB_*a94vYRr?3wZE0LC|J6onZmD zmso!~Rb=%Xjaol*O00LH?=O0aMdp)Y;VsctG5#;Lq~@#?J%^W*Xd-&}7O}ju{QmNi z@~6w6$F(K`hqK^r5wT~>Tgt8S`}x7Fo)w~K8sA0+SBP;X1Y+or71fkKg1-ahkMPUN zOtY9c@$gDfRLlM<+>WazP(vVc44{Yrof=oP3gJr1FJVkN6|RB~f~%lY*;pq1HJuz5 zcu0qb1s>9&V1b8po?L0!ROVEI`!cD^M5s}8pnOqz8tOw6eqS43DJE650!-{%C1MB4 zS4mai8J{3fOCWX_U;=@n#A4V_7EQ(ZmSid7@3A4BqnCGJLf2MSeXQ{;3w;Of4ZW z1qQamqhSK`s{+#eSVM=HUqW&Y6$@E8$B~>fNzQWQyqHY2GM`o80gJ^#%^FxvY8*g% zI}lr3zECQ1a=DmPiF`b%xCd!_tXL%`MIim8*${kEqfPoQ2=F{iO zpAHMaqKIS5vike=xicGC^5GX2RQE`{fg_@PM1o?leRE%P1F7hNP zyDBV@vR|wL;XVRmP+{SvK$r3Ciy1v)tk#X9=;?Bq{fgizvwKjy zFGNVn_|s&}GSk}f1DsaI0imJ=rYrG19v@#PVzN|T#CT&sZDJH4<|50`NJ}xdK1kmx z$|e)2A`s~Tu=@bU5hx=topkRT51qv1@Sm6J=1qQl0yK1_QcOL9)>^za~O()Z*_V(}X-ILtY zySrl7(Vd+;Yjz&T>4=RxPHgYpp4@(FTmQC}ZINv)9m%by+D~lhY-__=h{@YKZ#{BT zkE=C{p1g7X9`>W|iS*45N?;yl6Q za}UmKoO=Ri3MS{As;#L#KKtP8-dRaHMX)-FvjZbjk5si)Rp7+HgOeI3ov7@sOje$n z*gvslVr1fx2`4IgE0Ptb#wW)gEN>_q9M@Cg*r$s7i+f|q*r{lLv?UsewiHE*j*mGw zrg6+cs}o)R=9>PG--`MFHE#c(=KrUOHv%!o3zGMXR8z+uj02{++Hk4_f5JDF!Y9?+ zw(oAMzq_q#4@Mp9)BC%3%%6{SV#f2WJGLR4hx{5o~eo_FdJWIu9!b28WR52;}G#1Z{>>7=|r3r)_$z+H&(dcLq;($gVc$ml!OkYu>fy>in^V zwT!AI<1;4=@s&FHMNf?oI1wn72MAh1WOst zU`U5LbqikfOUTNpV~kSW{Ow!s9HX7S(|p9)9}dCwv!FOf5G-X_%P@?qdy-PMf&#*6+(H8;?M6uI49($V!F$X>b_p<)DpQTK|W^Lg}fj z@&!D&OAxdfPGd+`p%Z-!#|xjg!7AnS}UoYKiTUM8iZbG(!=#K}4THH0jG4|Wd-f;Piyh9pa_ zZA^6VOc!Ly9*p2E3kam>AdVJqsFFMM({p6{&JiRKe?K)8QVNb@{Qb;ep<+bE-j&SMy6Gdg;vN4J@O!?HZ;Biwp9u!nEQT!8}?{kfs8QhyXJ`U``FY0-bcgZB%9 zHp5zmVHTwp*2B6*wQbBpnbSlazAXbG1BU#ip{3G#6b*UOU||~aRXli15VRR47={^= zj-R<-Hza50?6Q~eMCrpDz6t%o0`@y)D5sPiMf?5AU}4(tH9UBmAZRm8FwAE^bfUcC z(05Kuup-NrZ$3QOj~bq4kth!o%N<0o(N6z*2%WwLZT1O*Hp3|lNhdml#&CSb1&-NM zs{-A_cLPbmw?fdD0mLdo(FU*86~Z0uixRjfbYYafa6z{TBp~PS(N&1{~st8lb-n3L$^g8vHs(-S3&*%8P4xmSuaZc!k$Cy836jPG?A_qoWrL$D_R1ZJNp+n4ku+f_4j_z-Vt~OiX>(qu!NCDVE<>=P)Lg zIUT8!v=s}by{Za+ga>N{L7QPUL$cLYtkp9dAF8?pw%Xd!z6&2e*UweRu2~E@e>!+Z zhh>PSM9r`Lxt-B5#^9k8QtJO05B3RyHp420VM&F~=xEoIirkDID9^L$gx^!n8u=+5 zV+{?IMx$w^B7=u%rT@T#hXp~KVJ$U!P-D`CK}qbuj>8v%obqQZ9W0XyC} zU&uKfa$CJVEVeI<)ZyszWI zbV1N&7-uNY=?EUoS1gJ#%IY3o&}f{~VH>Oz>-?q~{y7~bBceb2^Crd_^i5O!CmzfZ z1Z{?KhWSi2NttSqGMRZsN2$S6$uL?rD;p90;oGd-pl{mjr+CmVe$FG^ zV9J2`BYgPfNqj`~hbm8wWxMwk27SaPJ5`?i3ckApL7U+Wh7{p+PKV+6l#X49@Ek{K z1Y1rykWjSGU-+G0*w$U;QEM`OKdzo=JyeQ4{P-QYE@riii(03!|NkAIi(2z={jwdk zetA!s^{!P>>mTb%t&WvZ>noqOt?d{C`0x{@)|D6oXn(NG5;y}eF{a%50?z*XLu0A+ ze(e4KVy4Wxjn@AU6p1a{ca&{L|G)bavWVCB|0hC*m~zOkjW3C_6GBX@w&>94!nJ(H z;9Q1F7>3oL?!g{jmhlY@8RJg*cH&Gl#8P6)6nixbv5Mg`?S5oCaVia7D!r(kIAnri z=Az!@xn{g~Jfj@gBzTPyp;3IR6|ZBcm87doMv&S87!1?$`pUZgPR3G zn_(Tp5t+hGc$lxun!=YB^O|D1A*Ygi6ircWurN(=8V{Zn1Z{?O49OItND&B!g zV_V)$oPqv9ZgdO+?b)BE?iEd7=a?QC_9o65hLTF@QM02sJJVpHEThV=GkDN02wu!^ z6T`6b%iYB3rJ1m;gt;xZql4CxY|mG)%`)Uw@=KH4$kMej+^pS?tYAwRyp(NJ!A4do zW-jVYo@>T?=N4==A>>tVrqx9l>j1PFq7RAtu-sfDH*tCeTbSvy`8hX2Fk|bRIAHp3|l!?d6Q`?)?XmakhD)WKLBId=#diom^B z5VRTAFqDVi1!os&IQ(I;?s^<2xVCxu#?|XqrZ%oxzdX5YbS!!e5MP6Hp5DWc|Ko(R^oXBQYOR7O_0e?0W45d>|9 z(-`LY@SK>Cnot(?WxVsZ$)DE07^W3{krUtKT(7>C=1sf({_2?ZB{;J4Y@OM$`y`8po5zYX3Z6Injrt$s1_!x0}{VS-Uxd#(l z**6&@Cd)JOMg0`rQ>A;R>Yi!3XS(jG);%+H&rIDDIjJ$Vbk7*wGgkK$>7J%+@`%x@V5=5%FzaLW<}fOZSY?J!5rGk?x7=o|x__);+fF zDbYRSbWf@7DbqdWx@WxZiR+#U-7`V=Ow>J>F5Pqpru zp?hZPo>{slp?hj{&urZz5_&Z19!vL((LG~zPm%74>YkYHDb_uYiD;C!u?4 zbkA(vQ>%OC=$=S}7QvS88KZl~>YgIq6V*L2-BYZ4Y~53$d&cRWQr%Ogd&+gsc-^B_ zV};v-1qv1@SfF5mf&~f|C|JO?fOBX1j=r78c8DDf+grEwbPQ}g*`8=`-jZoM+&Y+w zr<~i zrZ4Hc_}E3_qK3t-i+UOd8ctrAxUl(x%=w2G4xSf3&smV3-&cREPSiEbYn|IOXQ1}v z?8NNmnoQ#GtihS_na+%Kb>H-3)5NrfsjXE#QwAoVoRpZKzpRZwcKAZRn3$uLYctnL7QO>!!U*1G?-N=JPlrB@Kth* zqH2!8!c=WKl$t9D+6-qh3{%ZbgIU!=(qPhHs)QIty_yUbre4+1=sZEtW;lmoSl+@n zbn)lqt>8CwwFJ4;V68+MMeUXuEKKcYuyzD(L2wSkuvl}o%f?z>?Uoy?l_;aA-3o(+ zsogASG*1w;8CEgO^YLC04}82=i?5XiJH>uv8hOXvH)=dqy(u2UI#U1aYJ-Pqwi+1h zLP5}Gh}9~%51Zn2OR3drr-t#FAWgSx4Zcc_k=ZZDG547>*NuopJC-KX*8*~zuYK?S zJ^MU0&aN?dnC7d6v1$cDo8feZdA?XICg%ELvB&YuT7#pKU?{_#!_iSj8~xXejJ*qP&zn{Yh?e(p0+MV5iuRrb^8Q4^ySNP-ea$Xfv#37?#f64pBCp zb30J#CBF!&Y1d+KR+8k`t_=pJKM16|OmNrG`VrCJ;?g&hdElemXEzx1l{l&^IS(RM z34%7m2@LamvR0I2KUv$zy%0rl7}w8#IBMO7wf%o8i&_tSJZ8;Y8@2xGPf_c-HBswd z&Wl<5uZvm}u)qJAM`G3`IPd?PtFeav_n6Dang0*H60>Gw&j0z(#H?jF^Zy$+#H?Ld z>;IdFVpcEa{cC@W?*d@n|GJGa>vhcgr{5m4%5Z)52T`lOD`x!z*8Q*Rj9EX$y8q6; zm{m^e{|AMbm3}$iiuwO<9M&SM;aYM1$=g_?s@7X^SUwI{rX#26)Ok8~dK%7!uEj5n z^SKw5f26!7wk#6ibEhkCR&xa%Zw@r~(YT(?q6#NPKTn6-xWxbWnn?fWPgr8kR(T9`2ibG{cQ1}{zm*SU3j8%*hXnodo<&NK zA1SCQ@Aa%Oa4X`2kBrYgE5WmR@YYjKDW27+gyRLDjK>R&;8l2bkrBKc&(8N#jMF1J z^Ij#miFmNc2sgP8Z2jQ`(CW2#wBWDN=@j9?JcCXZ(edJb0=yNTHwxodh9re@ywf9U zGW=RZ6(a`ppk|E4@m`NH3&AJ(lR^m|Rconb0{k<)Jbz{N`Ni{FXG~gz6(I-#4jSkQX=}ggXTbr z&WpEtK+FBG25D!fMd$5P@GC(Ozv4_drVMiriZl{^mlNfbex8Y+3I z+%<)%B4Ox|exhMPW6ovD_F20ZlS*Wc7B)?mwHs-)P-tomGswPz{mjUpLClB+Ns<#0 zCPvOez_eB)Oh>RQUqrA+v}`vO5>2JTfxb=vp{a22(Iidr;TNuT=4KU%r`L*cT=W2) z#E=ycRZU1|*`%SqI>GT-gv0%>m?&-)V6k0h-6ioz5;ya?#@ob2#4 z(mB2!5rGp^@ebc>K@I}KM?sH1h5^&^%P9l+fWm=tn?1v5c@$6z7ARPtV1a@K3Kl3> z;LmA+hWpy??Y;Z>{)77}I{WvuVE=E$uH!q}Ix4pIw>I9MyzThSk(-Wfh_qB(--7Q7 z9A8nf{OGb1O~;eRowjQ_ukO4mxg>dI^759;S}yIqxc{Ofi#r#!HMTW0UU=&K6AO== z*SVl^{?WRF^OAFWYinw15=UkpopH3fcY5!%-m3m7{gY2ro|xEKaWH;xd}DdCELmDH zuBN2MJ{~&}JyBFM_7uiXUcB&wUu?ttf8`O`|EKx?+PIwmcc+dw8e=GGOeOyq(D08# z*)$^h!#>*M>Slw! zX{dS_Cm{&h45u-aC!hp(?oEIpu?uPqEg}gSUA)C$s07Gwu;Gs`-Z~=s!yjF|&7f}@ zY(7jiQxLQn&R`h!O$2x2-MYQ0_Px8)9sB4DzWa7`b+m2O64}|!L-1SxZWjoGHp4oG zG|d*o=Zryf?ba59vyx;Km1{Rxn97|GwJs0@ zZH9FW!<56h8KKED*D9y226rXRC@R=turL+80IDq#1Z{@348s%*i9PRg=|tYmd)o}o zN|KQ&mwVQB`7I}J{-C^)BEqEa(5rVcLSjRBWhtMgB~=m>1=ukX)c2t zGX+7L;S`2pQ}XWexa^cX9XhKg|4xIO;+{YGpUXkAXS)m*X7axZs!SIIZHAQ$=@6BW z&;8Kp2iiAUyaaxx+hC9pTq zs00{Ao$fMNm^xhpZ6*tXHp58_NvB+=xVonw$P*TeFgLX%^!z$FP zH6Oo$o~YF-F#nIAv-*!WZbARQI6ZXVS-_pa_%MyPdQGKs((SW-DG*c!B&YeikiL6U}0*u3_8^af;Phh!(nUY+eP7N zb~ZBv+vQ+5QxLQnPGLxFLp}*Zn<%``UywmPZf6b}+!XgwwBrK?3)7A(ph~?UXfv!~ z7^aZBG}KebpS?BJ-fr+!a*U#C4;m~?)mB2Oxq_h0a3;er)!YT_o@!do*7SPFV5)=| zMZMl(urT#n1&wA3f;Ph`48xMX+e$>Hc0Z3{q``*`Zi@RTDs;$TVJfs5s?-aDHp3c* zVG5}a9FxurQTc3w7oQf;Piy zhNM);XD_$`7yRsnrqz24mP&;DTAkD9EY9{AJWRFLL7{{oXfv#07#3IVLT@jwc+Nso zsn=kq*pH@4j~hHpm9B>}^94bhVJ$;aDOayWHQKUgZ*sdvn~Tx3d#}M+Ns?c?HW--x zAdv1d!G+%M8xj5CPsKc8&{yK9=6o|moGb|14C4&*eDeTjtg3Gv5G^;iK54K~Z1bCG z_;aD}9})fGPw_ov&^OK0!e%093xaWm!!naL#CzsxgNtULNAZRn3#*p%1$k!lvMC8{qaRwjO|1ZYxt8a~3yRZ+S6u*xhh+4~W&i{{b z#{Zo!$E+Ck0X+4GsC5zc035wMX5Ef4fS=W)|Bf+$%9~==5v>2e{Nb4O9rXWq{3L1> z;o7q)W}T05fWLV#X01p6|3^QJTD!YrRtfe1ycg^L8*u*rr~C08K1aE*f zW(tBf!x;=If zg{j~TtRO*K5UgWJ3Wgm2&M}zxRB}zhj~d*SG^42C#|##xf;U2`MnTYKIG+^-M>ZH6@r!_Kg#Nuq|FXIKx@Brgpi&SnU5 zsUT=GoW(FqoDm+Wt&&6GTChOD0tE{cEKsmO!2$&f{7<#OjxQHm|MJ^nYtwS95!hF3 z-HE>cPsbEnhtTgY!5V<)(eI!CgP8SY^!rzxh*{ruV%9#)`&ZKZzY`JluRZvct?2(R z`4rk!a95!J9~t1W92(-lNg{E2Tufl>MnOmkEF5t7PKZ8R&?$oSaI7dMtOWV+byWZ$ zJGkIkpXeD&_lYs=$8Cac9Q@)vgb36G7=Za$OJFe!d=2!LT!x{bt-A8g5x@h7c(ElC zPG&4g$O0yoiHLKs5&@E;lAcB^3zr1$sL_Z}>}FRAmV^8WB9H%K5#cKy#m7SD1a9yV z1p@T4SY!wrNMIBZW9uCei8%a7Kyg~j2U-zmEPM`lETAQt1k<3QbT}vx zPe@GazsZ1^1gK{mU^uRYfWdJDKRHJ{2-`R+uJHtKGq{ks$n}UglV=Ypa4-SVph}X! z5#>@~jGY}h6iIMUAqHgVX1sS`5-fcvBMlKyhy;_%&@CuS+Vld*cvu2EF`8(_vtoKb z8^4PxXp_V@K&A#VXQ z-&(5fW&cb0)b&tOh(iuKyG`l|;RWXto0H%B^v|zB-w*iGDZDM>UiC=3Isv?POrm?P zHMwci6At=&IqdT_K{A}+aWsCBV1Mf?Fr!R^``^G8PS|$=poNZ_6YVl zG9COTfY&AX#AFw>Ik|1yJm9`$;8AJN?vX<}dHJOU!0R;14Z_p&hYGSJ2R%JL6rNcg zY(=Wl={evz0DaB)*a|E?{kilq-w4Rp?bEk4xp?tn(2N`Mb->D7l~CH1Y%QIPH^S5H zr_!IP2U$heW5CIst~$g$K66EtaDD)9uTMV8 zKV)k&oo)k`&X?Xd08bd{l$HbOe1XBPKET&st|@(AFz9UuSKZDe8~x1kU_0cKYx^X> zKElE84TBynX4m5*104F9@kY6_O$1$#-acPBuF}=ACKXnu7petQ>JhGFzrzmd-yC?l z9x8}w7ow-z<@Mz1$H#)6nND{hHE&TwaE&9M{{-ov#E1{M9L_^*MtUg$y*~V;lX_4s zt;er}_mnTcZ0JFF_o$%S)r>d7)7v=?>_RkOGvaMG;$yc)hwuh~*Au|on=}6o0#`bv zhgtq%SR6R52E9Gtd$$UTYXa@7O~A_p@b>!RqZ#jy0nco2>_Ps}^-!cuzI#y{>Ge?@ z^m;%qVeq9|LC=?@XDfbDBYvqhq^B23C-gJzmqvWFE1__006+TuqDeiJ_DdsG>3B~i zyQ*X0+Zw>z>#Khim7fIg{N)SD6(?Qk$4>Fx=d%mRM)@cgo?g#5z{>#7tdF{&uU_7( z`j>E}lYB`!UEfyF8zdYghWJc>a1umE%NHI>~oG?0kuOgljta z_#E2_mP7kt8NJ-d07u~W(I#BkNqW?)(9;#^ancF4@9#pc)caeMFPJ8-(kXhB0)x)U zfoJx6!szMc^C8foes|`YFTLYqPv3$5|F=IIVRi@e^#3;;eKNV@;|sF={}@7?0T`Ss z`~UPl-t*$+S-G|TfA$&Qd^fr0d;g8J;PsQL@SOV9NwE%p*Ncs~+bCA!Zk-mis%h_i z-$FRYQ4cHKaFk!EkGd1-Go6i#lVmU8dg*Sqi@z24l&VsQUuq+Cp?*!HZRBq;yq^5o zm&y^IXh_$L3(2`mEEg*v-#T1VVkstzn{mBf+yMW2u?BZZ;G`I1O%`v3*n|*E@w@@Q z#rQ23H!0G%Qad~D=<<^G=fZCTTW%eACm{z(;O9xR)^JUYrGHO((IF4HjrffgADmso z`gytq+g;~s$Dm&849ym^9umBs{Ly7!hkjnXU*PH|dte>NhjP!HtnukQAocAW>M`$e zOJS-9Rhcd+ll{m}I-R{pITVW0j-p2tQt;6m&kZ0w`sq#1Nl _VI$9*&|R%Lj_p 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�%(U^vRoQ%>} z+QBROv7>a-4NFk_hDu2quhHd~@sh~uM|Pw1x0Tb>791qGLlR=B=3Tt_Q23Jmb_2h< zsj0Xha(n480XiF?p=XzT>1Htbxz}eqdb%h3dnM2tkoz9I_v}ycxDho5&BJ^3#%oA_ z4*}29lkB2W5zSTk$Lp6gJs79{o}VtY(y2zGR=OOZrF{7s@CHF!Ix3H;mX#~MRDKgp zb5}p^==8{LVY8i-?w@)3a^QP(6~2l`f4nSd>Z+!GmnSdb%T_a$4Af)ag(u1-n&dc~ z7cZ0!Z{!+&4^pGq|5o8jo1T0NjVC0U)DsIgvQAM?=<3;--s>$siRH;j?e&|H@47j^ ztVKNBiyYvUWD>ss3l=C?pkRT51qv1@SfF5mf(8DkSs?kNuC2S#|Noi0|6j>R{S^AX zBeg+;&YZ`PEmjY&hx#Rs-cM8X{QGzhp}kD=NnXE1;Zb|pb2OfQ8|ZoMSHe@D6Y%f` zfHMGk>1@A9;>r0x4^Q2B;|mf`j^nDg-j(%Xuf$7>1pYkdfM3SZ$A2WA9MARe)cE@$ zpL|=GTEau){zEJ1dF^eYN2?k9>rI<6F7*iT{B}`2QIDXq%OG&2BYJ9PR6UdJf9eB} zKGG??G_XC_jQ7VJiLc|yRka?T8jtkHFQqB}{$b)rKW{u)@|82A9zAszH{_!=r`bLm zkZ8V*)&;+A;K`n&qC(?spV>Vfcz${`gFs^np6eqzz#}_KNAl5VV(xv4etqTmbixhE z7e~geKR$?Sm(cMN=>Kj4?n$2>;p5qUeYb%Y{dvxTzTZRs5I%a_FnXm{)JR;CpMDf4 z(viM2{;gIr$){uw%5Nq;xmr)+5Of@g=eOTBccjO|dx3ZYH*WByo_WGU!}!i)KfDZh z%|1LjOTe$M3epE$=|~S6RqFPQkEB6|etvy-Kwm#Sm7Wg+*P}<{=6*b~N5(PBAvJ!k z!pd=iR^S~o=+THz%0uII(EEYsx3d~Q_YmWtL-zB=%}HN5Zl3Vac-`m|!1I?cwC-Vx zHp(Q&M~U8`Pd+t{t`StX0X*96;5phSKG`H%F!to0ReWVXN!lS(Aw~PDIILE~t zeUs~vDP8&FO|5NGRAj!T`a{r<9r2}FL9GmvPl-;Cqt7D{o~(Tn5``hfKmEM<1c}!e zqKCiUPh$o@x4y@~Uph%|v4Pj>u7enK{CG4XoKTN&?Q;;v_%$2!XqDRq8lJj6)1>Ys zU&7PVRV(U+NuWpekxt_IS2=lhZZ+`asxuWzf=tu+T8<;#RePOhf_9@Ssc5#Mg$_|p~fbsW5+A3KRhd%g7b zmD-Q&k2kr?UDub|e=y?;iVwOpkRT51qv1@SfF5mf&~f|C|ICifr1783>HxR{XYY% z0*itL3Kl3>pkRT51qv1@SfF5mf&~f|C|ICifr14J7ARPtV1a@K3Kl3>pkRT51qv1@ aSfF5mf&~f|C|ICifr14J7WjW`f&U9(so2l} literal 0 HcmV?d00001 diff --git a/luaclib/pb/pbc.sln b/luaclib/pb/pbc.sln new file mode 100644 index 0000000..ed6f4af --- /dev/null +++ b/luaclib/pb/pbc.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pbc", "pbc.vcxproj", "{82356F33-956B-4931-9977-BD7994B1C761}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {82356F33-956B-4931-9977-BD7994B1C761}.Debug|Win32.ActiveCfg = Debug|Win32 + {82356F33-956B-4931-9977-BD7994B1C761}.Debug|Win32.Build.0 = Debug|Win32 + {82356F33-956B-4931-9977-BD7994B1C761}.Release|Win32.ActiveCfg = Release|Win32 + {82356F33-956B-4931-9977-BD7994B1C761}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/luaclib/pb/pbc.v12.suo b/luaclib/pb/pbc.v12.suo new file mode 100644 index 0000000000000000000000000000000000000000..31f83663a7c6bdab1f167fc621a26ece449a8c8e GIT binary patch literal 26624 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 gRQ!Ftr$M-Wy^g + + + + Debug + Win32 + + + Release + Win32 + + + + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE} + pb + protobuf + + + + DynamicLibrary + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + $(ProjectDir) + $(ProjectName) + + + + Level3 + Disabled + false + ..\..\deps\lua;.\src + WIN32;_DEBUG;_WINDOWS;_USRDLL;LUA_CORE;LUA_BUILD_AS_DLL;LUA_COMPAT_5_2;LUA_COMPAT_5_1;%(PreprocessorDefinitions) + /D"inline"=__inline /D"bool"=char /D"true"=(1) /D"false"=(0) %(AdditionalOptions) + + + true + ..\..\deps\lua; + nlua.lib + + + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/luaclib/pb/pbc.vcxproj.filters b/luaclib/pb/pbc.vcxproj.filters new file mode 100644 index 0000000..0f79423 --- /dev/null +++ b/luaclib/pb/pbc.vcxproj.filters @@ -0,0 +1,87 @@ + + + + + {aa230bd6-7da2-4cfb-af39-52310e429716} + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + \ No newline at end of file diff --git a/luaclib/pb/pbc.vcxproj.user b/luaclib/pb/pbc.vcxproj.user new file mode 100644 index 0000000..ef5ff2a --- /dev/null +++ b/luaclib/pb/pbc.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/luaclib/pb/pbc.xcodeproj/project.pbxproj b/luaclib/pb/pbc.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e55813b --- /dev/null +++ b/luaclib/pb/pbc.xcodeproj/project.pbxproj @@ -0,0 +1,338 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + D7EF1338179E5530002B6A46 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7EF1337179E5530002B6A46 /* Foundation.framework */; }; + D7EF135D179E5626002B6A46 /* alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF1346179E5626002B6A46 /* alloc.c */; }; + D7EF135E179E5626002B6A46 /* array.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF1348179E5626002B6A46 /* array.c */; }; + D7EF135F179E5626002B6A46 /* bootstrap.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF134A179E5626002B6A46 /* bootstrap.c */; }; + D7EF1360179E5626002B6A46 /* context.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF134C179E5626002B6A46 /* context.c */; }; + D7EF1361179E5626002B6A46 /* decode.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF134E179E5626002B6A46 /* decode.c */; }; + D7EF1362179E5626002B6A46 /* map.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF1350179E5626002B6A46 /* map.c */; }; + D7EF1363179E5626002B6A46 /* pattern.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF1352179E5626002B6A46 /* pattern.c */; }; + D7EF1364179E5626002B6A46 /* proto.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF1354179E5626002B6A46 /* proto.c */; }; + D7EF1365179E5626002B6A46 /* register.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF1356179E5626002B6A46 /* register.c */; }; + D7EF1366179E5626002B6A46 /* rmessage.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF1357179E5626002B6A46 /* rmessage.c */; }; + D7EF1367179E5626002B6A46 /* stringpool.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF1358179E5626002B6A46 /* stringpool.c */; }; + D7EF1368179E5626002B6A46 /* varint.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF135A179E5626002B6A46 /* varint.c */; }; + D7EF1369179E5626002B6A46 /* wmessage.c in Sources */ = {isa = PBXBuildFile; fileRef = D7EF135C179E5626002B6A46 /* wmessage.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + D7EF1332179E5530002B6A46 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/${PRODUCT_NAME}"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + D7EF1334179E5530002B6A46 /* libpbc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpbc.a; sourceTree = BUILT_PRODUCTS_DIR; }; + D7EF1337179E5530002B6A46 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + D7EF133B179E5530002B6A46 /* pbc-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "pbc-Prefix.pch"; sourceTree = ""; }; + D7EF1346179E5626002B6A46 /* alloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alloc.c; sourceTree = ""; }; + D7EF1347179E5626002B6A46 /* alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alloc.h; sourceTree = ""; }; + D7EF1348179E5626002B6A46 /* array.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = array.c; sourceTree = ""; }; + D7EF1349179E5626002B6A46 /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = array.h; sourceTree = ""; }; + D7EF134A179E5626002B6A46 /* bootstrap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bootstrap.c; sourceTree = ""; }; + D7EF134B179E5626002B6A46 /* bootstrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bootstrap.h; sourceTree = ""; }; + D7EF134C179E5626002B6A46 /* context.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = context.c; sourceTree = ""; }; + D7EF134D179E5626002B6A46 /* context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = context.h; sourceTree = ""; }; + D7EF134E179E5626002B6A46 /* decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = decode.c; sourceTree = ""; }; + D7EF134F179E5626002B6A46 /* descriptor.pbc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = descriptor.pbc.h; sourceTree = ""; }; + D7EF1350179E5626002B6A46 /* map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = map.c; sourceTree = ""; }; + D7EF1351179E5626002B6A46 /* map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = map.h; sourceTree = ""; }; + D7EF1352179E5626002B6A46 /* pattern.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pattern.c; sourceTree = ""; }; + D7EF1353179E5626002B6A46 /* pattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pattern.h; sourceTree = ""; }; + D7EF1354179E5626002B6A46 /* proto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = proto.c; sourceTree = ""; }; + D7EF1355179E5626002B6A46 /* proto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = proto.h; sourceTree = ""; }; + D7EF1356179E5626002B6A46 /* register.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = register.c; sourceTree = ""; }; + D7EF1357179E5626002B6A46 /* rmessage.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rmessage.c; sourceTree = ""; }; + D7EF1358179E5626002B6A46 /* stringpool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stringpool.c; sourceTree = ""; }; + D7EF1359179E5626002B6A46 /* stringpool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stringpool.h; sourceTree = ""; }; + D7EF135A179E5626002B6A46 /* varint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = varint.c; sourceTree = ""; }; + D7EF135B179E5626002B6A46 /* varint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = varint.h; sourceTree = ""; }; + D7EF135C179E5626002B6A46 /* wmessage.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wmessage.c; sourceTree = ""; }; + D7EF136D179E5837002B6A46 /* pbc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pbc.h; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D7EF1331179E5530002B6A46 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D7EF1338179E5530002B6A46 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D7EF132B179E5530002B6A46 = { + isa = PBXGroup; + children = ( + D7EF1339179E5530002B6A46 /* pbc */, + D7EF1336179E5530002B6A46 /* Frameworks */, + D7EF1335179E5530002B6A46 /* Products */, + ); + sourceTree = ""; + }; + D7EF1335179E5530002B6A46 /* Products */ = { + isa = PBXGroup; + children = ( + D7EF1334179E5530002B6A46 /* libpbc.a */, + ); + name = Products; + sourceTree = ""; + }; + D7EF1336179E5530002B6A46 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D7EF1337179E5530002B6A46 /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + D7EF1339179E5530002B6A46 /* pbc */ = { + isa = PBXGroup; + children = ( + D7EF136D179E5837002B6A46 /* pbc.h */, + D7EF1345179E5626002B6A46 /* src */, + D7EF133A179E5530002B6A46 /* Supporting Files */, + ); + path = pbc; + sourceTree = ""; + }; + D7EF133A179E5530002B6A46 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + D7EF133B179E5530002B6A46 /* pbc-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + D7EF1345179E5626002B6A46 /* src */ = { + isa = PBXGroup; + children = ( + D7EF1346179E5626002B6A46 /* alloc.c */, + D7EF1347179E5626002B6A46 /* alloc.h */, + D7EF1348179E5626002B6A46 /* array.c */, + D7EF1349179E5626002B6A46 /* array.h */, + D7EF134A179E5626002B6A46 /* bootstrap.c */, + D7EF134B179E5626002B6A46 /* bootstrap.h */, + D7EF134C179E5626002B6A46 /* context.c */, + D7EF134D179E5626002B6A46 /* context.h */, + D7EF134E179E5626002B6A46 /* decode.c */, + D7EF134F179E5626002B6A46 /* descriptor.pbc.h */, + D7EF1350179E5626002B6A46 /* map.c */, + D7EF1351179E5626002B6A46 /* map.h */, + D7EF1352179E5626002B6A46 /* pattern.c */, + D7EF1353179E5626002B6A46 /* pattern.h */, + D7EF1354179E5626002B6A46 /* proto.c */, + D7EF1355179E5626002B6A46 /* proto.h */, + D7EF1356179E5626002B6A46 /* register.c */, + D7EF1357179E5626002B6A46 /* rmessage.c */, + D7EF1358179E5626002B6A46 /* stringpool.c */, + D7EF1359179E5626002B6A46 /* stringpool.h */, + D7EF135A179E5626002B6A46 /* varint.c */, + D7EF135B179E5626002B6A46 /* varint.h */, + D7EF135C179E5626002B6A46 /* wmessage.c */, + ); + path = src; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D7EF1333179E5530002B6A46 /* pbc */ = { + isa = PBXNativeTarget; + buildConfigurationList = D7EF1342179E5530002B6A46 /* Build configuration list for PBXNativeTarget "pbc" */; + buildPhases = ( + D7EF1330179E5530002B6A46 /* Sources */, + D7EF1331179E5530002B6A46 /* Frameworks */, + D7EF1332179E5530002B6A46 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = pbc; + productName = pbc; + productReference = D7EF1334179E5530002B6A46 /* libpbc.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D7EF132C179E5530002B6A46 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0460; + ORGANIZATIONNAME = ztgame; + }; + buildConfigurationList = D7EF132F179E5530002B6A46 /* Build configuration list for PBXProject "pbc" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = D7EF132B179E5530002B6A46; + productRefGroup = D7EF1335179E5530002B6A46 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D7EF1333179E5530002B6A46 /* pbc */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + D7EF1330179E5530002B6A46 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D7EF135D179E5626002B6A46 /* alloc.c in Sources */, + D7EF135E179E5626002B6A46 /* array.c in Sources */, + D7EF135F179E5626002B6A46 /* bootstrap.c in Sources */, + D7EF1360179E5626002B6A46 /* context.c in Sources */, + D7EF1361179E5626002B6A46 /* decode.c in Sources */, + D7EF1362179E5626002B6A46 /* map.c in Sources */, + D7EF1363179E5626002B6A46 /* pattern.c in Sources */, + D7EF1364179E5626002B6A46 /* proto.c in Sources */, + D7EF1365179E5626002B6A46 /* register.c in Sources */, + D7EF1366179E5626002B6A46 /* rmessage.c in Sources */, + D7EF1367179E5626002B6A46 /* stringpool.c in Sources */, + D7EF1368179E5626002B6A46 /* varint.c in Sources */, + D7EF1369179E5626002B6A46 /* wmessage.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + D7EF1340179E5530002B6A46 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "compiler-default"; + CLANG_CXX_LIBRARY = "compiler-default"; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "“$(SRCROOT)/src\" “$(SRCROOT)\"", + ); + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + VALID_ARCHS = "armv7 armv7s i386"; + }; + name = Debug; + }; + D7EF1341179E5530002B6A46 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "compiler-default"; + CLANG_CXX_LIBRARY = "compiler-default"; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "“$(SRCROOT)/src\" “$(SRCROOT)\"", + ); + IPHONEOS_DEPLOYMENT_TARGET = 6.1; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "armv7 armv7s i386"; + }; + name = Release; + }; + D7EF1343179E5530002B6A46 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + DSTROOT = /tmp/pbc.dst; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "pbc/pbc-Prefix.pch"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VALID_ARCHS = "armv7 armv6 i386"; + }; + name = Debug; + }; + D7EF1344179E5530002B6A46 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + DSTROOT = /tmp/pbc.dst; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "pbc/pbc-Prefix.pch"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VALID_ARCHS = "armv7 armv6 i386"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D7EF132F179E5530002B6A46 /* Build configuration list for PBXProject "pbc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D7EF1340179E5530002B6A46 /* Debug */, + D7EF1341179E5530002B6A46 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D7EF1342179E5530002B6A46 /* Build configuration list for PBXNativeTarget "pbc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D7EF1343179E5530002B6A46 /* Debug */, + D7EF1344179E5530002B6A46 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D7EF132C179E5530002B6A46 /* Project object */; +} diff --git a/luaclib/pb/pbc.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/luaclib/pb/pbc.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..b1f616f --- /dev/null +++ b/luaclib/pb/pbc.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/luaclib/pb/pbc.xcodeproj/project.xcworkspace/xcuserdata/dev.xcuserdatad/UserInterfaceState.xcuserstate b/luaclib/pb/pbc.xcodeproj/project.xcworkspace/xcuserdata/dev.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..a3b6a2659f84162ec3b7b64f321c0ecad05d6b72 GIT binary patch literal 70687 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 P|9G_H|M>s+v(Ntki$RlF literal 0 HcmV?d00001 diff --git a/luaclib/pb/pbc.xcodeproj/project.xcworkspace/xcuserdata/juren.xcuserdatad/UserInterfaceState.xcuserstate b/luaclib/pb/pbc.xcodeproj/project.xcworkspace/xcuserdata/juren.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..1c9ffd73ce9dc06dc74edd31334186169b844847 GIT binary patch literal 9605 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 literal 0 HcmV?d00001 diff --git a/luaclib/pb/pbc.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/pbc.xcscheme b/luaclib/pb/pbc.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/pbc.xcscheme new file mode 100644 index 0000000..a33c2c9 --- /dev/null +++ b/luaclib/pb/pbc.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/pbc.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/luaclib/pb/pbc.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/xcschememanagement.plist b/luaclib/pb/pbc.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..81bb0cb --- /dev/null +++ b/luaclib/pb/pbc.xcodeproj/xcuserdata/dev.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + pbc.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + D7EF1333179E5530002B6A46 + + primary + + + + + diff --git a/luaclib/pb/pbc.xcodeproj/xcuserdata/juren.xcuserdatad/xcschemes/pbc.xcscheme b/luaclib/pb/pbc.xcodeproj/xcuserdata/juren.xcuserdatad/xcschemes/pbc.xcscheme new file mode 100644 index 0000000..a33c2c9 --- /dev/null +++ b/luaclib/pb/pbc.xcodeproj/xcuserdata/juren.xcuserdatad/xcschemes/pbc.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/luaclib/pb/pbc.xcodeproj/xcuserdata/juren.xcuserdatad/xcschemes/xcschememanagement.plist b/luaclib/pb/pbc.xcodeproj/xcuserdata/juren.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..81bb0cb --- /dev/null +++ b/luaclib/pb/pbc.xcodeproj/xcuserdata/juren.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + pbc.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + D7EF1333179E5530002B6A46 + + primary + + + + + diff --git a/luaclib/pb/pbc/pbc-Prefix.pch b/luaclib/pb/pbc/pbc-Prefix.pch new file mode 100644 index 0000000..a3c82d0 --- /dev/null +++ b/luaclib/pb/pbc/pbc-Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'pbc' target in the 'pbc' project +// + +#ifdef __OBJC__ + #import + #import "pbc.h" +#endif diff --git a/luaclib/pb/src/alloc.c b/luaclib/pb/src/alloc.c new file mode 100644 index 0000000..96590ed --- /dev/null +++ b/luaclib/pb/src/alloc.c @@ -0,0 +1,84 @@ +#include +#include + +static int _g = 0; + +void * _pbcM_malloc(size_t sz) { + ++ _g; + return malloc(sz); +} + +void _pbcM_free(void *p) { + if (p) { + -- _g; + free(p); + } +} + +void* _pbcM_realloc(void *p, size_t sz) { + return realloc(p,sz); +} + +void _pbcM_memory() { + printf("%d\n",_g); +} + +struct heap_page { + struct heap_page * next; +}; + +struct heap { + struct heap_page *current; + int size; + int used; +}; + +struct heap * +_pbcH_new(int pagesize) { + int cap = 1024; + while(cap < pagesize) { + cap *= 2; + } + struct heap * h = (struct heap *)_pbcM_malloc(sizeof(struct heap)); + h->current = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + cap); + h->size = cap; + h->used = 0; + h->current->next = NULL; + return h; +} + +void +_pbcH_delete(struct heap *h) { + struct heap_page * p = h->current; + struct heap_page * next = p->next; + for(;;) { + _pbcM_free(p); + if (next == NULL) + break; + p = next; + next = p->next; + } + _pbcM_free(h); +} + +void* +_pbcH_alloc(struct heap *h, int size) { + size = (size + 3) & ~3; + if (h->size - h->used < size) { + struct heap_page * p; + if (size < h->size) { + p = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + h->size); + } else { + p = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + size); + } + p->next = h->current; + h->current = p; + h->used = size; + return (p+1); + } else { + char * buffer = (char *)(h->current + 1); + buffer += h->used; + h->used += size; + return buffer; + } +} diff --git a/luaclib/pb/src/alloc.h b/luaclib/pb/src/alloc.h new file mode 100644 index 0000000..7b611dd --- /dev/null +++ b/luaclib/pb/src/alloc.h @@ -0,0 +1,37 @@ +#ifndef PROTOBUF_C_ALLOC_H +#define PROTOBUF_C_ALLOC_H + +#include +#include + +void * _pbcM_malloc(size_t sz); +void _pbcM_free(void *p); +void * _pbcM_realloc(void *p, size_t sz); +void _pbcM_memory(); + +struct heap; + +struct heap * _pbcH_new(int pagesize); +void _pbcH_delete(struct heap *); +void* _pbcH_alloc(struct heap *, int size); + +#define HMALLOC(size) ((h) ? _pbcH_alloc(h, size) : _pbcM_malloc(size)) + +#define malloc _pbcM_malloc +#define free _pbcM_free +#define realloc _pbcM_realloc +#define memory _pbcM_memory + +#ifdef _WIN32 + +#include + +#endif + +#ifdef _MSC_VER + +#define alloca _alloca + +#endif + +#endif diff --git a/luaclib/pb/src/array.c b/luaclib/pb/src/array.c new file mode 100644 index 0000000..5ae4b37 --- /dev/null +++ b/luaclib/pb/src/array.c @@ -0,0 +1,139 @@ +#include "pbc.h" +#include "array.h" +#include "alloc.h" + +#include +#include + +struct array { + int number; + struct heap *heap; + union _pbc_var * a; +}; + +#define INNER_FIELD ((PBC_ARRAY_CAP - sizeof(struct array)) / sizeof(pbc_var)) + +void +_pbcA_open(pbc_array _array) { + struct array * a = (struct array *)_array; + a->number = 0; + a->heap = NULL; + a->a = (union _pbc_var *)(a+1); +} + +void +_pbcA_open_heap(pbc_array _array, struct heap *h) { + struct array * a = (struct array *)_array; + a->number = 0; + a->heap = h; + a->a = (union _pbc_var *)(a+1); +} + +void +_pbcA_close(pbc_array _array) { + struct array * a = (struct array *)_array; + if (a->heap == NULL && a->a != NULL && (union _pbc_var *)(a+1) != a->a) { + _pbcM_free(a->a); + a->a = NULL; + } +} + +void +_pbcA_push(pbc_array _array, pbc_var var) { + struct array * a = (struct array *)_array; + if (a->number == 0) { + a->a = (union _pbc_var *)(a+1); + } else if (a->number >= INNER_FIELD) { + if (a->number == INNER_FIELD) { + int cap = 1; + while (cap <= a->number + 1) + cap *= 2; + struct heap * h = a->heap; + union _pbc_var * outer = (union _pbc_var *)HMALLOC(cap * sizeof(union _pbc_var)); + memcpy(outer , a->a , INNER_FIELD * sizeof(pbc_var)); + a->a = outer; + } else { + int size=a->number; + if (((size + 1) ^ size) > size) { + struct heap * h = a->heap; + if (h) { + void * old = a->a; + a->a = (union _pbc_var *)_pbcH_alloc(h, sizeof(union _pbc_var) * (size+1) * 2); + memcpy(a->a, old, sizeof(union _pbc_var) * size); + } else { + a->a = (union _pbc_var *)_pbcM_realloc(a->a,sizeof(union _pbc_var) * (size+1) * 2); + } + } + } + } + a->a[a->number] = *var; + ++ a->number; +} + +void +_pbcA_index(pbc_array _array, int idx, pbc_var var) +{ + struct array * a = (struct array *)_array; + var[0] = a->a[idx]; +} + +void * +_pbcA_index_p(pbc_array _array, int idx) +{ + struct array * a = (struct array *)_array; + return &(a->a[idx]); +} + +int +pbc_array_size(pbc_array _array) { + struct array * a = (struct array *)_array; + return a->number; +} + +uint32_t +pbc_array_integer(pbc_array array, int index, uint32_t *hi) { + pbc_var var; + _pbcA_index(array , index , var); + if (hi) { + *hi = var->integer.hi; + } + return var->integer.low; +} + +double +pbc_array_real(pbc_array array, int index) { + pbc_var var; + _pbcA_index(array , index , var); + return var->real; +} + +struct pbc_slice * +pbc_array_slice(pbc_array _array, int index) { + struct array * a = (struct array *)_array; + if (index <0 || index > a->number) { + return NULL; + } + return (struct pbc_slice *) &(a->a[index]); +} + +void +pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi) { + pbc_var var; + var->integer.low = low; + var->integer.hi = hi; + _pbcA_push(array,var); +} + +void +pbc_array_push_slice(pbc_array array, struct pbc_slice *s) { + pbc_var var; + var->m = *s; + _pbcA_push(array,var); +} + +void +pbc_array_push_real(pbc_array array, double v) { + pbc_var var; + var->real = v; + _pbcA_push(array,var); +} diff --git a/luaclib/pb/src/array.h b/luaclib/pb/src/array.h new file mode 100644 index 0000000..cc7f0a9 --- /dev/null +++ b/luaclib/pb/src/array.h @@ -0,0 +1,31 @@ +#ifndef PROTOBUF_C_ARRAY_H +#define PROTOBUF_C_ARRAY_H + +#include "varint.h" +#include "pbc.h" +#include "alloc.h" + +typedef union _pbc_var { + struct longlong integer; + double real; + struct { + const char * str; + int len; + } s; + struct { + int id; + const char * name; + } e; + struct pbc_slice m; + void * p[2]; +} pbc_var[1]; + +void _pbcA_open(pbc_array); +void _pbcA_open_heap(pbc_array, struct heap *h); +void _pbcA_close(pbc_array); + +void _pbcA_push(pbc_array, pbc_var var); +void _pbcA_index(pbc_array , int idx, pbc_var var); +void * _pbcA_index_p(pbc_array _array, int idx); + +#endif diff --git a/luaclib/pb/src/bootstrap.c b/luaclib/pb/src/bootstrap.c new file mode 100644 index 0000000..f57b75b --- /dev/null +++ b/luaclib/pb/src/bootstrap.c @@ -0,0 +1,303 @@ +#include "pbc.h" +#include "map.h" +#include "context.h" +#include "pattern.h" +#include "proto.h" +#include "alloc.h" +#include "bootstrap.h" +#include "stringpool.h" +#include "array.h" +#include "descriptor.pbc.h" + +#include +#include +#include +#include + +/* + +// Descriptor + +// google.protobuf.Descriptor.proto encoded in descriptor.pbc.h with proto pbc.file . + +package pbc; + +message field { + optional string name = 1; + optional int32 id = 2; + optional int32 label = 3; // 0 optional 1 required 2 repeated + optional int32 type = 4; // type_id + optional string type_name = 5; + optional int32 default_int = 6; + optional string default_string = 7; + optional double default_real = 8; +} + +message file { + optional string name = 1; + repeated string dependency = 2; + + repeated string message_name = 3; + repeated int32 message_size = 4; + repeated field message_field = 5; + + repeated string enum_name = 6; + repeated int32 enum_size = 7; + repeated string enum_string = 8; + repeated int32 enum_id = 9; +} + +*/ + +struct field_t { + struct pbc_slice name; + int32_t id; + int32_t label; + int32_t type; + struct pbc_slice type_name; + int32_t default_integer; + struct pbc_slice default_string; + double default_real; +}; + +struct file_t { + struct pbc_slice name; // string + pbc_array dependency; // string + pbc_array message_name; // string + pbc_array message_size; // int32 + pbc_array message_field; // field_t + pbc_array enum_name; // string + pbc_array enum_size; // int32 + pbc_array enum_string; // string + pbc_array enum_id; // int32 +}; + +static void +set_enum_one(struct pbc_env *p, struct file_t *file, const char *name, int start, int sz) { + struct map_kv *table = (struct map_kv *)malloc(sz * sizeof(struct map_kv)); + int i; + for (i=0;ienum_id, start+i, id); + _pbcA_index(file->enum_string, start+i, string); + table[i].id = (int)id->integer.low; + table[i].pointer = (void *)string->s.str; + } + _pbcP_push_enum(p,name,table,sz); + + free(table); +} + +static void +set_enums(struct pbc_env *p, struct file_t *file) { + int n = pbc_array_size(file->enum_size); + int i; + int start = 0; + for (i=0;ienum_name,i,name); + pbc_var var; + _pbcA_index(file->enum_size,i,var); + set_enum_one(p, file, name->s.str, start , (int)var->integer.low); + start += var->integer.low; + } +} + +static void +set_default(struct _field *f, struct field_t *input) { + switch (f->type) { + case PTYPE_DOUBLE: + case PTYPE_FLOAT: + f->default_v->real = input->default_real; + break; + case PTYPE_STRING: + case PTYPE_ENUM: + f->default_v->m = input->default_string; + break; + default: + f->default_v->integer.low = input->default_integer; + break; + } +} + +static void +set_msg_one(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file, const char *name, int start, int sz , pbc_array queue) { + int i; + for (i=0;imessage_field, start+i, _field); + struct field_t field; + + int ret = pbc_pattern_unpack(FIELD_T, &_field->m, &field); + if (ret != 0) { + continue; + } + struct _field f; + f.id = field.id; + f.name = (const char *)field.name.buffer; + f.type = field.type; + f.label = field.label; + f.type_name.n = (const char *)field.type_name.buffer; + set_default(&f, &field); + + _pbcP_push_message(p,name, &f , queue); + + // don't need to close pattern since no array + } + _pbcP_init_message(p, name); +} + +static void +set_msgs(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file , pbc_array queue) { + int n = pbc_array_size(file->message_size); + int i; + int start = 0; + for (i=0;imessage_name,i,name); + pbc_var sz; + _pbcA_index(file->message_size,i,sz); + set_msg_one(FIELD_T, p, file, name->s.str, start , (int)sz->integer.low , queue); + start += sz->integer.low; + } +} + +static void +set_field_one(struct pbc_env *p, struct _field *f) { + const char * type_name = f->type_name.n; + if (f->type == PTYPE_MESSAGE) { + f->type_name.m = (struct _message *)_pbcM_sp_query(p->msgs, type_name); +// printf("MESSAGE: %s %p\n",type_name, f->type_name.m); + } else if (f->type == PTYPE_ENUM) { + f->type_name.e = (struct _enum *)_pbcM_sp_query(p->enums, type_name); +// printf("ENUM: %s %p ",type_name, f->type_name.e); + const char * str = f->default_v->s.str; + if (str && str[0]) { + int err = _pbcM_si_query(f->type_name.e->name, str , &(f->default_v->e.id)); + if (err < 0) + goto _default; + f->default_v->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id, f->default_v->e.id); +// printf("[%s %d]\n",str,f->default_v->e.id); + } else { +_default: + memcpy(f->default_v, f->type_name.e->default_v, sizeof(pbc_var)); +// printf("(%s %d)\n",f->default_v->e.name,f->default_v->e.id); + } + } +} + +void +_pbcB_register_fields(struct pbc_env *p, pbc_array queue) { + int sz = pbc_array_size(queue); + int i; + for (i=0;im.buffer; + set_field_one(p, f); + } +} + +static void +_set_string(struct _pattern_field * f) { + f->ptype = PTYPE_STRING; + f->ctype = CTYPE_VAR; + f->defv->s.str = ""; + f->defv->s.len = 0; +} + +static void +_set_int32(struct _pattern_field * f) { + f->ptype = PTYPE_INT32; + f->ctype = CTYPE_INT32; +} + +static void +_set_double(struct _pattern_field * f) { + f->ptype = PTYPE_DOUBLE; + f->ctype = CTYPE_DOUBLE; +} + +static void +_set_message_array(struct _pattern_field *f) { + f->ptype = PTYPE_MESSAGE; + f->ctype = CTYPE_ARRAY; +} + +static void +_set_string_array(struct _pattern_field * f) { + f->ptype = PTYPE_STRING; + f->ctype = CTYPE_ARRAY; +} + +static void +_set_int32_array(struct _pattern_field * f) { + f->ptype = PTYPE_INT32; + f->ctype = CTYPE_ARRAY; +} + +#define SET_PATTERN(pat , idx , pat_type, field_name , type) \ + pat->f[idx].id = idx+1 ; \ + pat->f[idx].offset = offsetof(struct pat_type, field_name); \ + _set_##type(&pat->f[idx]); + +#define F(idx,field_name,type) SET_PATTERN(FIELD_T, idx, field_t ,field_name, type) +#define D(idx,field_name,type) SET_PATTERN(FILE_T, idx, file_t ,field_name, type) + +static int +register_internal(struct pbc_env * p, struct pbc_slice *slice) { + struct pbc_pattern * FIELD_T = _pbcP_new(p,8); + F(0,name,string); + F(1,id,int32); + F(2,label,int32); + F(3,type,int32); + F(4,type_name,string); + F(5,default_integer,int32); + F(6,default_string,string); + F(7,default_real,double); + + struct pbc_pattern * FILE_T = _pbcP_new(p,10); + + D(0,name,string); + D(1,dependency,string_array); + D(2,message_name,string_array); + D(3,message_size,int32_array); + D(4,message_field,message_array); + D(5,enum_name,string_array); + D(6,enum_size,int32_array); + D(7,enum_string,string_array); + D(8,enum_id,int32_array); + + int ret = 0; + + struct file_t file; + int r = pbc_pattern_unpack(FILE_T, slice, &file); + if (r != 0) { + ret = 1; + goto _return; + } + + _pbcM_sp_insert(p->files , (const char *)file.name.buffer, NULL); + + pbc_array queue; + _pbcA_open(queue); + + set_enums(p, &file); + set_msgs(FIELD_T, p, &file, queue); + _pbcB_register_fields(p, queue); + + _pbcA_close(queue); + pbc_pattern_close_arrays(FILE_T, &file); + +_return: + free(FIELD_T); + free(FILE_T); + return ret; +} + +void +_pbcB_init(struct pbc_env * p) { + struct pbc_slice slice = { pbc_descriptor,sizeof(pbc_descriptor) }; + register_internal(p,&slice); +} diff --git a/luaclib/pb/src/bootstrap.h b/luaclib/pb/src/bootstrap.h new file mode 100644 index 0000000..48566f5 --- /dev/null +++ b/luaclib/pb/src/bootstrap.h @@ -0,0 +1,10 @@ +#ifndef PROTOBUF_C_BOOTSTRAP_H +#define PROTOBUF_C_BOOTSTRAP_H + +#include "proto.h" +#include "pbc.h" + +void _pbcB_init(struct pbc_env *); +void _pbcB_register_fields(struct pbc_env *, pbc_array queue); + +#endif diff --git a/luaclib/pb/src/context.c b/luaclib/pb/src/context.c new file mode 100644 index 0000000..87bbf93 --- /dev/null +++ b/luaclib/pb/src/context.c @@ -0,0 +1,280 @@ +#include "pbc.h" +#include "alloc.h" +#include "varint.h" +#include "context.h" + +#include +#include +#include +#ifndef _MSC_VER +#include +#endif + +#define INNER_ATOM ((PBC_CONTEXT_CAP - sizeof(struct context)) / sizeof(struct atom)) + +static char * +wiretype_decode(uint8_t *buffer, int cap , struct atom *a , int start) +{ + uint8_t temp[10]; + struct longlong r; + int len; + if (cap >= 10) { + len = _pbcV_decode(buffer, &r); + if (r.hi !=0) + return NULL; + } else { + memcpy(temp, buffer , cap); + len = _pbcV_decode(temp, &r); + if (len > cap || r.hi !=0) + return NULL; + } + + int wiretype = r.low & 7; + a->wire_id = r.low; + buffer += len; + start += len; + cap -=len; + + switch (wiretype) { + case WT_VARINT : + if (cap >=10) { + len = _pbcV_decode(buffer, &a->v.i); + } else { + memcpy(temp, buffer , cap); + len = _pbcV_decode(temp, &a->v.i); + if (cap < len) + return NULL; + } + return (char *)buffer+len; + case WT_BIT64 : + if (cap < 8) + return NULL; + a->v.i.low = buffer[0] | + buffer[1] << 8 | + buffer[2] << 16 | + buffer[3] << 24; + a->v.i.hi = buffer[4] | + buffer[5] << 8 | + buffer[6] << 16 | + buffer[7] << 24; + return (char *)buffer + 8; + case WT_LEND : + if (cap >=10) { + len = _pbcV_decode(buffer, &r); + } else { + memcpy(temp, buffer , cap); + len = _pbcV_decode(temp, &r); + } + if (cap < len + r.low || r.hi !=0) + return NULL; + a->v.s.start = start + len; + a->v.s.end = start + len + r.low; + return (char *)buffer + len + r.low; + case WT_BIT32 : + if (cap < 4) + return NULL; + a->v.i.low = buffer[0] | + buffer[1] << 8 | + buffer[2] << 16 | + buffer[3] << 24; + a->v.i.hi = 0; + return (char *)buffer + 4; + default: + return NULL; + } +} + +static inline int +_decode_varint(uint8_t * buffer, int size , struct atom * a) { + a->wire_id = WT_VARINT; + if (size < 10) { + uint8_t temp[10]; + memcpy(temp,buffer,size); + return _pbcV_decode(temp , &(a->v.i)); + } else { + return _pbcV_decode(buffer , &(a->v.i)); + } +} + +static int +_open_packed_varint(struct context * ctx , uint8_t * buffer, int size) { + struct atom * a = (struct atom *)(ctx + 1); + + int i; + + for (i=0;ia = a; + } else { + int cap = 64; + ctx->a = (struct atom *)malloc(cap * sizeof(struct atom)); + while (size > 0) { + if (i >= cap) { + cap = cap + 64; + ctx->a = (struct atom *)realloc(ctx->a, cap * sizeof(struct atom)); + continue; + } + int len = _decode_varint(buffer, size, &a[i]); + buffer += len; + size -= len; + + ++i; + } + memcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM); + } + ctx->number = i; + + return i; +} + +int +_pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size) { + struct context * ctx = (struct context *)_ctx; + ctx->buffer = (char *)buffer; + ctx->size = size; + ctx->number = 0; + ctx->a = NULL; + + if (buffer == NULL || size == 0) { + return 0; + } + + int bits = 0; + + switch (ptype) { + case PTYPE_INT64: + case PTYPE_UINT64: + case PTYPE_INT32: + case PTYPE_BOOL: + case PTYPE_UINT32: + case PTYPE_ENUM: + case PTYPE_SINT32: + case PTYPE_SINT64: + return _open_packed_varint(ctx , (uint8_t *)buffer, size); + case PTYPE_DOUBLE: + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + ctx->number = size / 8; + bits = 64; + break; + case PTYPE_FLOAT: + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + ctx->number = size / 4; + bits = 32; + break; + default: + return 0; + } + + struct atom * a = (struct atom *)(ctx + 1); + + if (ctx->number > INNER_ATOM) { + ctx->a = (struct atom *)malloc(ctx->number * sizeof(struct atom)); + a = ctx->a; + } else { + ctx->a = a; + } + + int i; + if (bits == 64) { + uint8_t * data = (uint8_t *)buffer; + for (i=0;inumber;i++) { + a[i].wire_id = WT_BIT64; + a[i].v.i.low = data[0] | + data[1] << 8 | + data[2] << 16 | + data[3] << 24; + a[i].v.i.hi = data[4] | + data[5] << 8 | + data[6] << 16 | + data[7] << 24; + data += 8; + } + } else { + uint8_t * data = (uint8_t *)buffer; + for (i=0;inumber;i++) { + a[i].wire_id = WT_BIT32; + a[i].v.i.low = data[0] | + data[1] << 8 | + data[2] << 16 | + data[3] << 24; + a[i].v.i.hi = 0; + data += 4; + } + } + + return ctx->number; +} + +int +_pbcC_open(pbc_ctx _ctx , void *buffer, int size) { + struct context * ctx = (struct context *)_ctx; + ctx->buffer = (char *)buffer; + ctx->size = size; + + if (buffer == NULL || size == 0) { + ctx->number = 0; + ctx->a = NULL; + return 0; + } + + struct atom * a = (struct atom *)(ctx + 1); + + int i; + int start = 0; + + ctx->a = a; + + for (i=0;i 0) { + int cap = 64; + ctx->a = (struct atom *)malloc(cap * sizeof(struct atom)); + while (size > 0) { + if (i >= cap) { + cap = cap + 64; + ctx->a = (struct atom *)realloc(ctx->a, cap * sizeof(struct atom)); + continue; + } + char * next = wiretype_decode((uint8_t *)buffer, size , &ctx->a[i] , start); + if (next == NULL) { + return -i; + } + start += next - (char *)buffer; + size -= next - (char *)buffer; + buffer = next; + ++i; + } + memcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM); + } + ctx->number = i; + + return i; +} + + +void +_pbcC_close(pbc_ctx _ctx) { + struct context * ctx = (struct context *)_ctx; + if (ctx->a != NULL && (struct atom *)(ctx+1) != ctx->a) { + free(ctx->a); + ctx->a = NULL; + } +} diff --git a/luaclib/pb/src/context.h b/luaclib/pb/src/context.h new file mode 100644 index 0000000..e19ed91 --- /dev/null +++ b/luaclib/pb/src/context.h @@ -0,0 +1,140 @@ +#ifndef PROTOBUF_C_CONTEXT_H +#define PROTOBUF_C_CONTEXT_H + +#include + +#include "array.h" + +#define PBC_CONTEXT_CAP 256 + +// wiretype + +#define WT_VARINT 0 +#define WT_BIT64 1 +#define WT_LEND 2 +#define WT_BIT32 5 + +#define CTYPE_INT32 1 +#define CTYPE_INT64 2 +#define CTYPE_DOUBLE 3 +#define CTYPE_FLOAT 4 +#define CTYPE_POINTER 5 +#define CTYPE_BOOL 6 +#define CTYPE_INT8 7 +#define CTYPE_INT16 8 +#define CTYPE_ARRAY 9 +#define CTYPE_VAR 10 +#define CTYPE_PACKED 11 + +#define PTYPE_DOUBLE 1 +#define PTYPE_FLOAT 2 +#define PTYPE_INT64 3 // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if negative values are likely. +#define PTYPE_UINT64 4 +#define PTYPE_INT32 5 // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if negative values are likely. +#define PTYPE_FIXED64 6 +#define PTYPE_FIXED32 7 +#define PTYPE_BOOL 8 +#define PTYPE_STRING 9 +#define PTYPE_GROUP 10 // Tag-delimited aggregate. +#define PTYPE_MESSAGE 11 // Length-delimited aggregate. +#define PTYPE_BYTES 12 +#define PTYPE_UINT32 13 +#define PTYPE_ENUM 14 +#define PTYPE_SFIXED32 15 +#define PTYPE_SFIXED64 16 +#define PTYPE_SINT32 17 // Uses ZigZag encoding. +#define PTYPE_SINT64 18 // Uses ZigZag encoding. + +struct slice { + int start; + int end; +}; + +struct atom { + int wire_id; + union { + struct slice s; + struct longlong i; + } v; +}; + +struct context { + char * buffer; + int size; + int number; + struct atom * a; +}; + +typedef struct _pbc_ctx { char _data[PBC_CONTEXT_CAP]; } pbc_ctx[1]; + +int _pbcC_open(pbc_ctx , void *buffer, int size); // <=0 failed +int _pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size); +void _pbcC_close(pbc_ctx); + +static inline double +read_double(struct atom * a) { + union { + uint64_t i; + double d; + } u; + u.i = (uint64_t) a->v.i.low | (uint64_t) a->v.i.hi << 32; + return u.d; +} + +static inline float +read_float(struct atom * a) { + union { + uint32_t i; + float f; + } u; + u.i = a->v.i.low; + return u.f; +} + +static inline void +double_encode(double v , uint8_t * buffer) { + union { + double v; + uint64_t e; + } u; + u.v = v; + buffer[0] = (uint8_t) (u.e & 0xff); + buffer[1] = (uint8_t) (u.e >> 8 & 0xff); + buffer[2] = (uint8_t) (u.e >> 16 & 0xff); + buffer[3] = (uint8_t) (u.e >> 24 & 0xff); + buffer[4] = (uint8_t) (u.e >> 32 & 0xff); + buffer[5] = (uint8_t) (u.e >> 40 & 0xff); + buffer[6] = (uint8_t) (u.e >> 48 & 0xff); + buffer[7] = (uint8_t) (u.e >> 56 & 0xff); +} + +static inline void +float_encode(float v , uint8_t * buffer) { + union { + float v; + uint32_t e; + } u; + u.v = v; + buffer[0] = (uint8_t) (u.e & 0xff); + buffer[1] = (uint8_t) (u.e >> 8 & 0xff); + buffer[2] = (uint8_t) (u.e >> 16 & 0xff); + buffer[3] = (uint8_t) (u.e >> 24 & 0xff); +} + +#define CHECK_LEND(a,err) if ((a->wire_id & 7) != WT_LEND) return err; + +#if 0 +/* maybe we don't need check these wire type */ +#define CHECK_VARINT(a,err) if ((a->wire_id & 7) != WT_VARINT) return err; +#define CHECK_BIT32(a,err) if ((a->wire_id & 7) != WT_BIT32) return err; +#define CHECK_BIT64(a,err) if ((a->wire_id & 7) != WT_BIT64) return err; + +#else + +#define CHECK_VARINT(a,err) +#define CHECK_BIT32(a,err) +#define CHECK_BIT64(a,err) + +#endif + +#endif diff --git a/luaclib/pb/src/decode.c b/luaclib/pb/src/decode.c new file mode 100644 index 0000000..f8b2f50 --- /dev/null +++ b/luaclib/pb/src/decode.c @@ -0,0 +1,349 @@ +#include "pbc.h" +#include "alloc.h" +#include "context.h" +#include "proto.h" +#include "varint.h" + +#include + +static const char * TYPENAME[] = { + "invalid", // 0 + "integer", // 1 + "real", // 2 + "boolean", // 3 + "enum", // 4 + "string", // 5 + "message", // 6 + "fixed64", // 7 + "fixed32", // 8 + "bytes", // 9 + "int64", // 10 + "uint", // 11 +}; + +static int +call_unknown(pbc_decoder f, void * ud, int id, struct atom *a, uint8_t * start) { + union pbc_value v; + switch (a->wire_id & 7) { + case WT_VARINT: + v.i.low = a->v.i.low; + v.i.hi = a->v.i.hi; + f(ud, PBC_INT, TYPENAME[PBC_INT], &v, id , NULL); + break; + case WT_BIT64: + v.i.low = a->v.i.low; + v.i.hi = a->v.i.hi; + f(ud, PBC_FIXED64, TYPENAME[PBC_FIXED64], &v, id , NULL); + break; + case WT_LEND: + v.s.buffer = (char*)start + a->v.s.start; + v.s.len = a->v.s.end - a->v.s.start; + f(ud, PBC_BYTES, TYPENAME[PBC_BYTES], &v, id , NULL); + break; + case WT_BIT32: + v.i.low = a->v.i.low; + v.i.hi = 0; + f(ud, PBC_FIXED32, TYPENAME[PBC_FIXED32], &v, id , NULL); + break; + default: + return 1; + } + return 0; +} + +static int +call_type(pbc_decoder pd, void * ud, struct _field *f, struct atom *a, uint8_t * start) { + union pbc_value v; + const char * type_name = NULL; + int type = _pbcP_type(f, &type_name); + assert(type != 0); + if (type_name == NULL) { + type_name = TYPENAME[type & ~PBC_REPEATED]; + } + switch (f->type) { + case PTYPE_DOUBLE: + CHECK_BIT64(a, -1); + v.f = read_double(a); + break; + case PTYPE_FLOAT: + CHECK_BIT32(a, -1); + v.f = (double) read_float(a); + break; + case PTYPE_ENUM: + CHECK_VARINT(a, -1); + v.e.id = a->v.i.low; + v.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.e.id); + break; + case PTYPE_INT64: + case PTYPE_UINT64: + CHECK_VARINT(a, -1); + v.i.low = a->v.i.low; + v.i.hi = a->v.i.hi; + break; + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + CHECK_BIT64(a, -1); + v.i.low = a->v.i.low; + v.i.hi = a->v.i.hi; + break; + case PTYPE_INT32: + case PTYPE_UINT32: + case PTYPE_BOOL: + CHECK_VARINT(a, -1); + v.i.low = a->v.i.low; + v.i.hi = 0; + break; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + CHECK_BIT32(a, -1); + v.i.low = a->v.i.low; + v.i.hi = 0; + break; + case PTYPE_SINT32: + CHECK_VARINT(a, -1); + v.i.low = a->v.i.low; + v.i.hi = a->v.i.hi; + _pbcV_dezigzag32((struct longlong *)&(v.i)); + break; + case PTYPE_SINT64: + CHECK_VARINT(a, -1); + v.i.low = a->v.i.low; + v.i.hi = a->v.i.hi; + _pbcV_dezigzag64((struct longlong *)&(v.i)); + break; + case PTYPE_STRING: + case PTYPE_BYTES: + case PTYPE_MESSAGE: + CHECK_LEND(a, -1); + v.s.buffer = start + a->v.s.start; + v.s.len = a->v.s.end - a->v.s.start; + break; + default: + assert(0); + break; + } + pd(ud, type, type_name, &v, f->id, f->name); + return 0; +} + +static int +call_array(pbc_decoder pd, void * ud, struct _field *f, uint8_t * buffer , int size) { + union pbc_value v; + const char * type_name = NULL; + int type = _pbcP_type(f, &type_name); + assert(type != 0); + if (type_name == NULL) { + type_name = TYPENAME[type & ~PBC_REPEATED]; + } + v.i.hi = 0; + int i; + switch(f->type) { + case PTYPE_DOUBLE: + if (size % 8 != 0) { + return -1; + } + for (i=0;iid, f->name); + } + return size/8; + case PTYPE_FLOAT: + if (size % 4 != 0) + return -1; + for (i=0;iid, f->name); + } + return size/4; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + if (size % 4 != 0) + return -1; + for (i=0;iid, f->name); + } + return size/4; + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + if (size % 8 != 0) + return -1; + for (i=0;iid, f->name); + } + return size/8; + case PTYPE_INT64: + case PTYPE_UINT64: + case PTYPE_INT32: + case PTYPE_UINT32: + case PTYPE_BOOL: { + int n = 0; + while (size > 0) { + int len; + if (size >= 10) { + len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); + } else { + uint8_t temp[10]; + memcpy(temp, buffer, size); + len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); + if (len > size) + return -1; + } + pd(ud, type , type_name, &v, f->id, f->name); + buffer += len; + size -= len; + ++n; + } + return n; + } + case PTYPE_ENUM: { + int n = 0; + while (size > 0) { + int len; + if (size >= 10) { + len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); + } else { + uint8_t temp[10]; + memcpy(temp, buffer, size); + len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); + if (len > size) + return -1; + } + v.e.id = v.i.low; + v.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.i.low); + pd(ud, type , type_name, &v, f->id, f->name); + buffer += len; + size -= len; + ++n; + } + return n; + } + case PTYPE_SINT32: { + int n = 0; + while (size > 0) { + int len; + if (size >= 10) { + len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); + _pbcV_dezigzag32((struct longlong *)&(v.i)); + } else { + uint8_t temp[10]; + memcpy(temp, buffer, size); + len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); + if (len > size) + return -1; + _pbcV_dezigzag32((struct longlong *)&(v.i)); + } + pd(ud, type , type_name, &v, f->id, f->name); + buffer += len; + size -= len; + ++n; + } + return n; + } + case PTYPE_SINT64: { + int n = 0; + while (size > 0) { + int len; + if (size >= 10) { + len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); + _pbcV_dezigzag64((struct longlong *)&(v.i)); + } else { + uint8_t temp[10]; + memcpy(temp, buffer, size); + len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); + if (len > size) + return -1; + _pbcV_dezigzag64((struct longlong *)&(v.i)); + } + pd(ud, type , type_name, &v, f->id, f->name); + buffer += len; + size -= len; + ++n; + } + return n; + } + default: + return -1; + } +} + +int +pbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder pd, void *ud) { + struct _message * msg = _pbcP_get_message(env, type_name); + if (msg == NULL) { + env->lasterror = "Proto not found"; + return -1; + } + if (slice->len == 0) { + return 0; + } + pbc_ctx _ctx; + int count = _pbcC_open(_ctx,slice->buffer,slice->len); + if (count <= 0) { + env->lasterror = "decode context error"; + _pbcC_close(_ctx); + return count - 1; + } + struct context * ctx = (struct context *)_ctx; + uint8_t * start = (uint8_t *)slice->buffer; + + int i; + for (i=0;inumber;i++) { + int id = ctx->a[i].wire_id >> 3; + struct _field * f = (struct _field *)_pbcM_ip_query(msg->id , id); + if (f==NULL) { + int err = call_unknown(pd,ud,id,&ctx->a[i],start); + if (err) { + _pbcC_close(_ctx); + return -i-1; + } + } else if (f->label == LABEL_PACKED) { + struct atom * a = &ctx->a[i]; + int n = call_array(pd, ud, f , start + a->v.s.start , a->v.s.end - a->v.s.start); + if (n < 0) { + _pbcC_close(_ctx); + return -i-1; + } + } else { + if (call_type(pd,ud,f,&ctx->a[i],start) != 0) { + _pbcC_close(_ctx); + return -i-1; + } + } + } + + _pbcC_close(_ctx); + return ctx->number; +} + diff --git a/luaclib/pb/src/descriptor.pbc.h b/luaclib/pb/src/descriptor.pbc.h new file mode 100644 index 0000000..88dca86 --- /dev/null +++ b/luaclib/pb/src/descriptor.pbc.h @@ -0,0 +1,271 @@ +static unsigned char pbc_descriptor[] = { +72,1,72,2,72,3,72,4,72,5,72,6,72,7,72,8, +72,9,72,10,72,11,72,12,72,13,72,14,72,15,72,16, +72,17,72,18,72,1,72,2,72,3,72,1,72,2,72,3, +72,0,72,1,72,2,50,42,103,111,111,103,108,101,46,112, +114,111,116,111,98,117,102,46,70,105,101,108,100,68,101,115, +99,114,105,112,116,111,114,80,114,111,116,111,46,84,121,112, +101,0,50,43,103,111,111,103,108,101,46,112,114,111,116,111, +98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, +116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,50, +41,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, +46,70,105,108,101,79,112,116,105,111,110,115,46,79,112,116, +105,109,105,122,101,77,111,100,101,0,50,35,103,111,111,103, +108,101,46,112,114,111,116,111,98,117,102,46,70,105,101,108, +100,79,112,116,105,111,110,115,46,67,84,121,112,101,0,66, +12,84,89,80,69,95,68,79,85,66,76,69,0,66,11,84, +89,80,69,95,70,76,79,65,84,0,66,11,84,89,80,69, +95,73,78,84,54,52,0,66,12,84,89,80,69,95,85,73, +78,84,54,52,0,66,11,84,89,80,69,95,73,78,84,51, +50,0,66,13,84,89,80,69,95,70,73,88,69,68,54,52, +0,66,13,84,89,80,69,95,70,73,88,69,68,51,50,0, +66,10,84,89,80,69,95,66,79,79,76,0,66,12,84,89, +80,69,95,83,84,82,73,78,71,0,66,11,84,89,80,69, +95,71,82,79,85,80,0,66,13,84,89,80,69,95,77,69, +83,83,65,71,69,0,66,11,84,89,80,69,95,66,89,84, +69,83,0,66,12,84,89,80,69,95,85,73,78,84,51,50, +0,66,10,84,89,80,69,95,69,78,85,77,0,66,14,84, +89,80,69,95,83,70,73,88,69,68,51,50,0,66,14,84, +89,80,69,95,83,70,73,88,69,68,54,52,0,66,12,84, +89,80,69,95,83,73,78,84,51,50,0,66,12,84,89,80, +69,95,83,73,78,84,54,52,0,66,15,76,65,66,69,76, +95,79,80,84,73,79,78,65,76,0,66,15,76,65,66,69, +76,95,82,69,81,85,73,82,69,68,0,66,15,76,65,66, +69,76,95,82,69,80,69,65,84,69,68,0,66,6,83,80, +69,69,68,0,66,10,67,79,68,69,95,83,73,90,69,0, +66,13,76,73,84,69,95,82,85,78,84,73,77,69,0,66, +7,83,84,82,73,78,71,0,66,5,67,79,82,68,0,66, +13,83,84,82,73,78,71,95,80,73,69,67,69,0,56,18, +56,3,56,3,56,3,10,11,100,101,115,99,114,105,112,116, +111,114,0,32,1,32,9,32,7,32,2,32,8,32,3,32, +3,32,3,32,4,32,9,32,3,32,5,32,1,32,1,32, +1,32,1,32,7,32,2,32,1,32,2,42,51,24,2,16, +1,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116, +111,98,117,102,46,70,105,108,101,68,101,115,99,114,105,112, +116,111,114,80,114,111,116,111,0,10,5,102,105,108,101,0, +42,13,32,9,24,0,10,5,110,97,109,101,0,16,1,42, +16,32,9,24,0,10,8,112,97,99,107,97,103,101,0,16, +2,42,19,32,9,24,2,10,11,100,101,112,101,110,100,101, +110,99,121,0,16,3,42,55,24,2,16,4,32,11,42,32, +103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, +68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, +10,13,109,101,115,115,97,103,101,95,116,121,112,101,0,42, +56,24,2,16,5,32,11,42,36,103,111,111,103,108,101,46, +112,114,111,116,111,98,117,102,46,69,110,117,109,68,101,115, +99,114,105,112,116,111,114,80,114,111,116,111,0,10,10,101, +110,117,109,95,116,121,112,101,0,42,57,24,2,16,6,32, +11,42,39,103,111,111,103,108,101,46,112,114,111,116,111,98, +117,102,46,83,101,114,118,105,99,101,68,101,115,99,114,105, +112,116,111,114,80,114,111,116,111,0,10,8,115,101,114,118, +105,99,101,0,42,57,24,2,16,7,32,11,42,37,103,111, +111,103,108,101,46,112,114,111,116,111,98,117,102,46,70,105, +101,108,100,68,101,115,99,114,105,112,116,111,114,80,114,111, +116,111,0,10,10,101,120,116,101,110,115,105,111,110,0,42, +46,24,0,16,8,32,11,42,28,103,111,111,103,108,101,46, +112,114,111,116,111,98,117,102,46,70,105,108,101,79,112,116, +105,111,110,115,0,10,8,111,112,116,105,111,110,115,0,42, +58,24,0,16,9,32,11,42,31,103,111,111,103,108,101,46, +112,114,111,116,111,98,117,102,46,83,111,117,114,99,101,67, +111,100,101,73,110,102,111,0,10,17,115,111,117,114,99,101, +95,99,111,100,101,95,105,110,102,111,0,42,13,32,9,24, +0,10,5,110,97,109,101,0,16,1,42,53,24,2,16,2, +32,11,42,37,103,111,111,103,108,101,46,112,114,111,116,111, +98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, +116,111,114,80,114,111,116,111,0,10,6,102,105,101,108,100, +0,42,57,24,2,16,6,32,11,42,37,103,111,111,103,108, +101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, +68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, +10,10,101,120,116,101,110,115,105,111,110,0,42,54,24,2, +16,3,32,11,42,32,103,111,111,103,108,101,46,112,114,111, +116,111,98,117,102,46,68,101,115,99,114,105,112,116,111,114, +80,114,111,116,111,0,10,12,110,101,115,116,101,100,95,116, +121,112,101,0,42,56,24,2,16,4,32,11,42,36,103,111, +111,103,108,101,46,112,114,111,116,111,98,117,102,46,69,110, +117,109,68,101,115,99,114,105,112,116,111,114,80,114,111,116, +111,0,10,10,101,110,117,109,95,116,121,112,101,0,42,73, +24,2,16,5,32,11,42,47,103,111,111,103,108,101,46,112, +114,111,116,111,98,117,102,46,68,101,115,99,114,105,112,116, +111,114,80,114,111,116,111,46,69,120,116,101,110,115,105,111, +110,82,97,110,103,101,0,10,16,101,120,116,101,110,115,105, +111,110,95,114,97,110,103,101,0,42,49,24,0,16,7,32, +11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98, +117,102,46,77,101,115,115,97,103,101,79,112,116,105,111,110, +115,0,10,8,111,112,116,105,111,110,115,0,42,14,32,5, +24,0,10,6,115,116,97,114,116,0,16,1,42,12,32,5, +24,0,10,4,101,110,100,0,16,2,42,13,32,9,24,0, +10,5,110,97,109,101,0,16,1,42,15,32,5,24,0,10, +7,110,117,109,98,101,114,0,16,3,42,59,24,0,16,4, +32,14,42,43,103,111,111,103,108,101,46,112,114,111,116,111, +98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, +116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,10, +6,108,97,98,101,108,0,42,57,24,0,16,5,32,14,42, +42,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, +46,70,105,101,108,100,68,101,115,99,114,105,112,116,111,114, +80,114,111,116,111,46,84,121,112,101,0,10,5,116,121,112, +101,0,42,18,32,9,24,0,10,10,116,121,112,101,95,110, +97,109,101,0,16,6,42,17,32,9,24,0,10,9,101,120, +116,101,110,100,101,101,0,16,2,42,22,32,9,24,0,10, +14,100,101,102,97,117,108,116,95,118,97,108,117,101,0,16, +7,42,47,24,0,16,8,32,11,42,29,103,111,111,103,108, +101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, +79,112,116,105,111,110,115,0,10,8,111,112,116,105,111,110, +115,0,42,13,32,9,24,0,10,5,110,97,109,101,0,16, +1,42,57,24,2,16,2,32,11,42,41,103,111,111,103,108, +101,46,112,114,111,116,111,98,117,102,46,69,110,117,109,86, +97,108,117,101,68,101,115,99,114,105,112,116,111,114,80,114, +111,116,111,0,10,6,118,97,108,117,101,0,42,46,24,0, +16,3,32,11,42,28,103,111,111,103,108,101,46,112,114,111, +116,111,98,117,102,46,69,110,117,109,79,112,116,105,111,110, +115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9, +24,0,10,5,110,97,109,101,0,16,1,42,15,32,5,24, +0,10,7,110,117,109,98,101,114,0,16,2,42,51,24,0, +16,3,32,11,42,33,103,111,111,103,108,101,46,112,114,111, +116,111,98,117,102,46,69,110,117,109,86,97,108,117,101,79, +112,116,105,111,110,115,0,10,8,111,112,116,105,111,110,115, +0,42,13,32,9,24,0,10,5,110,97,109,101,0,16,1, +42,55,24,2,16,2,32,11,42,38,103,111,111,103,108,101, +46,112,114,111,116,111,98,117,102,46,77,101,116,104,111,100, +68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, +10,7,109,101,116,104,111,100,0,42,49,24,0,16,3,32, +11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98, +117,102,46,83,101,114,118,105,99,101,79,112,116,105,111,110, +115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9, +24,0,10,5,110,97,109,101,0,16,1,42,19,32,9,24, +0,10,11,105,110,112,117,116,95,116,121,112,101,0,16,2, +42,20,32,9,24,0,10,12,111,117,116,112,117,116,95,116, +121,112,101,0,16,3,42,48,24,0,16,4,32,11,42,30, +103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, +77,101,116,104,111,100,79,112,116,105,111,110,115,0,10,8, +111,112,116,105,111,110,115,0,42,21,32,9,24,0,10,13, +106,97,118,97,95,112,97,99,107,97,103,101,0,16,1,42, +29,32,9,24,0,10,21,106,97,118,97,95,111,117,116,101, +114,95,99,108,97,115,115,110,97,109,101,0,16,8,42,30, +24,0,16,10,32,8,10,20,106,97,118,97,95,109,117,108, +116,105,112,108,101,95,102,105,108,101,115,0,48,0,42,40, +24,0,16,20,32,8,10,30,106,97,118,97,95,103,101,110, +101,114,97,116,101,95,101,113,117,97,108,115,95,97,110,100, +95,104,97,115,104,0,48,0,42,72,24,0,16,9,32,14, +42,41,103,111,111,103,108,101,46,112,114,111,116,111,98,117, +102,46,70,105,108,101,79,112,116,105,111,110,115,46,79,112, +116,105,109,105,122,101,77,111,100,101,0,10,13,111,112,116, +105,109,105,122,101,95,102,111,114,0,58,6,83,80,69,69, +68,0,42,30,24,0,16,16,32,8,10,20,99,99,95,103, +101,110,101,114,105,99,95,115,101,114,118,105,99,101,115,0, +48,0,42,32,24,0,16,17,32,8,10,22,106,97,118,97, +95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101, +115,0,48,0,42,30,24,0,16,18,32,8,10,20,112,121, +95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101, +115,0,48,0,42,68,24,2,16,231,7,32,11,42,36,103, +111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,85, +110,105,110,116,101,114,112,114,101,116,101,100,79,112,116,105, +111,110,0,10,21,117,110,105,110,116,101,114,112,114,101,116, +101,100,95,111,112,116,105,111,110,0,42,34,24,0,16,1, +32,8,10,24,109,101,115,115,97,103,101,95,115,101,116,95, +119,105,114,101,95,102,111,114,109,97,116,0,48,0,42,42, +24,0,16,2,32,8,10,32,110,111,95,115,116,97,110,100, +97,114,100,95,100,101,115,99,114,105,112,116,111,114,95,97, +99,99,101,115,115,111,114,0,48,0,42,68,24,2,16,231, +7,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116, +111,98,117,102,46,85,110,105,110,116,101,114,112,114,101,116, +101,100,79,112,116,105,111,110,0,10,21,117,110,105,110,116, +101,114,112,114,101,116,101,100,95,111,112,116,105,111,110,0, +42,60,24,0,16,1,32,14,42,35,103,111,111,103,108,101, +46,112,114,111,116,111,98,117,102,46,70,105,101,108,100,79, +112,116,105,111,110,115,46,67,84,121,112,101,0,10,6,99, +116,121,112,101,0,58,7,83,84,82,73,78,71,0,42,15, +32,8,24,0,10,7,112,97,99,107,101,100,0,16,2,42, +21,24,0,16,3,32,8,10,11,100,101,112,114,101,99,97, +116,101,100,0,48,0,42,29,32,9,24,0,10,21,101,120, +112,101,114,105,109,101,110,116,97,108,95,109,97,112,95,107, +101,121,0,16,9,42,68,24,2,16,231,7,32,11,42,36, +103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, +85,110,105,110,116,101,114,112,114,101,116,101,100,79,112,116, +105,111,110,0,10,21,117,110,105,110,116,101,114,112,114,101, +116,101,100,95,111,112,116,105,111,110,0,42,68,24,2,16, +231,7,32,11,42,36,103,111,111,103,108,101,46,112,114,111, +116,111,98,117,102,46,85,110,105,110,116,101,114,112,114,101, +116,101,100,79,112,116,105,111,110,0,10,21,117,110,105,110, +116,101,114,112,114,101,116,101,100,95,111,112,116,105,111,110, +0,42,68,24,2,16,231,7,32,11,42,36,103,111,111,103, +108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110, +116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0, +10,21,117,110,105,110,116,101,114,112,114,101,116,101,100,95, +111,112,116,105,111,110,0,42,68,24,2,16,231,7,32,11, +42,36,103,111,111,103,108,101,46,112,114,111,116,111,98,117, +102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79, +112,116,105,111,110,0,10,21,117,110,105,110,116,101,114,112, +114,101,116,101,100,95,111,112,116,105,111,110,0,42,68,24, +2,16,231,7,32,11,42,36,103,111,111,103,108,101,46,112, +114,111,116,111,98,117,102,46,85,110,105,110,116,101,114,112, +114,101,116,101,100,79,112,116,105,111,110,0,10,21,117,110, +105,110,116,101,114,112,114,101,116,101,100,95,111,112,116,105, +111,110,0,42,60,24,2,16,2,32,11,42,45,103,111,111, +103,108,101,46,112,114,111,116,111,98,117,102,46,85,110,105, +110,116,101,114,112,114,101,116,101,100,79,112,116,105,111,110, +46,78,97,109,101,80,97,114,116,0,10,5,110,97,109,101, +0,42,25,32,9,24,0,10,17,105,100,101,110,116,105,102, +105,101,114,95,118,97,108,117,101,0,16,3,42,27,32,4, +24,0,10,19,112,111,115,105,116,105,118,101,95,105,110,116, +95,118,97,108,117,101,0,16,4,42,27,32,3,24,0,10, +19,110,101,103,97,116,105,118,101,95,105,110,116,95,118,97, +108,117,101,0,16,5,42,21,32,1,24,0,10,13,100,111, +117,98,108,101,95,118,97,108,117,101,0,16,6,42,21,32, +12,24,0,10,13,115,116,114,105,110,103,95,118,97,108,117, +101,0,16,7,42,24,32,9,24,0,10,16,97,103,103,114, +101,103,97,116,101,95,118,97,108,117,101,0,16,8,42,18, +32,9,24,1,10,10,110,97,109,101,95,112,97,114,116,0, +16,1,42,21,32,8,24,1,10,13,105,115,95,101,120,116, +101,110,115,105,111,110,0,16,2,42,59,24,2,16,1,32, +11,42,40,103,111,111,103,108,101,46,112,114,111,116,111,98, +117,102,46,83,111,117,114,99,101,67,111,100,101,73,110,102, +111,46,76,111,99,97,116,105,111,110,0,10,9,108,111,99, +97,116,105,111,110,0,42,13,32,5,24,2,10,5,112,97, +116,104,0,16,1,42,13,32,5,24,2,10,5,115,112,97, +110,0,16,2,26,34,103,111,111,103,108,101,46,112,114,111, +116,111,98,117,102,46,70,105,108,101,68,101,115,99,114,105, +112,116,111,114,83,101,116,0,26,36,103,111,111,103,108,101, +46,112,114,111,116,111,98,117,102,46,70,105,108,101,68,101, +115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,32, +103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, +68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, +26,47,103,111,111,103,108,101,46,112,114,111,116,111,98,117, +102,46,68,101,115,99,114,105,112,116,111,114,80,114,111,116, +111,46,69,120,116,101,110,115,105,111,110,82,97,110,103,101, +0,26,37,103,111,111,103,108,101,46,112,114,111,116,111,98, +117,102,46,70,105,101,108,100,68,101,115,99,114,105,112,116, +111,114,80,114,111,116,111,0,26,36,103,111,111,103,108,101, +46,112,114,111,116,111,98,117,102,46,69,110,117,109,68,101, +115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,41, +103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, +69,110,117,109,86,97,108,117,101,68,101,115,99,114,105,112, +116,111,114,80,114,111,116,111,0,26,39,103,111,111,103,108, +101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105, +99,101,68,101,115,99,114,105,112,116,111,114,80,114,111,116, +111,0,26,38,103,111,111,103,108,101,46,112,114,111,116,111, +98,117,102,46,77,101,116,104,111,100,68,101,115,99,114,105, +112,116,111,114,80,114,111,116,111,0,26,28,103,111,111,103, +108,101,46,112,114,111,116,111,98,117,102,46,70,105,108,101, +79,112,116,105,111,110,115,0,26,31,103,111,111,103,108,101, +46,112,114,111,116,111,98,117,102,46,77,101,115,115,97,103, +101,79,112,116,105,111,110,115,0,26,29,103,111,111,103,108, +101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, +79,112,116,105,111,110,115,0,26,28,103,111,111,103,108,101, +46,112,114,111,116,111,98,117,102,46,69,110,117,109,79,112, +116,105,111,110,115,0,26,33,103,111,111,103,108,101,46,112, +114,111,116,111,98,117,102,46,69,110,117,109,86,97,108,117, +101,79,112,116,105,111,110,115,0,26,31,103,111,111,103,108, +101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105, +99,101,79,112,116,105,111,110,115,0,26,30,103,111,111,103, +108,101,46,112,114,111,116,111,98,117,102,46,77,101,116,104, +111,100,79,112,116,105,111,110,115,0,26,36,103,111,111,103, +108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110, +116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0, +26,45,103,111,111,103,108,101,46,112,114,111,116,111,98,117, +102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79, +112,116,105,111,110,46,78,97,109,101,80,97,114,116,0,26, +31,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, +46,83,111,117,114,99,101,67,111,100,101,73,110,102,111,0, +26,40,103,111,111,103,108,101,46,112,114,111,116,111,98,117, +102,46,83,111,117,114,99,101,67,111,100,101,73,110,102,111, +46,76,111,99,97,116,105,111,110,0, +}; \ No newline at end of file diff --git a/luaclib/pb/src/map.c b/luaclib/pb/src/map.c new file mode 100644 index 0000000..2e859a0 --- /dev/null +++ b/luaclib/pb/src/map.c @@ -0,0 +1,477 @@ +#include "map.h" +#include "alloc.h" + +#include +#include + +struct _pbcM_ip_slot { + int id; + void * pointer; + int next; +}; + +struct map_ip { + size_t array_size; + void ** array; + size_t hash_size; + struct _pbcM_ip_slot * slot; +}; + +struct _pbcM_si_slot { + const char *key; + size_t hash; + int id; + int next; +}; + +struct map_si { + size_t size; + struct _pbcM_si_slot slot[1]; +}; + +static size_t +calc_hash(const char *name) +{ + size_t len = strlen(name); + size_t h = len; + size_t step = (len>>5)+1; + size_t i; + for (i=len; i>=step; i-=step) + h = h ^ ((h<<5)+(h>>2)+(size_t)name[i-1]); + return h; +} + +struct map_si * +_pbcM_si_new(struct map_kv * table, int size) +{ + size_t sz = sizeof(struct map_si) + (size-1) * sizeof(struct _pbcM_si_slot); + struct map_si * ret = (struct map_si *)malloc(sz); + memset(ret,0,sz); + + ret->size = (size_t)size; + + int empty = 0; + int i; + + for (i=0;islot[hash]; + if (slot->key == NULL) { + slot->key = (const char *)table[i].pointer; + slot->id = table[i].id; + slot->hash = hash_full; + } else { + while(ret->slot[empty].key != NULL) { + ++empty; + } + struct _pbcM_si_slot * empty_slot = &ret->slot[empty]; + empty_slot->next = slot->next; + slot->next = empty + 1; + empty_slot->id = table[i].id; + empty_slot->key = (const char *)table[i].pointer; + empty_slot->hash = hash_full; + } + } + + return ret; +} + +void +_pbcM_si_delete(struct map_si *map) +{ + free(map); +} + +int +_pbcM_si_query(struct map_si *map, const char *key, int *result) +{ + size_t hash_full = calc_hash(key); + size_t hash = hash_full % map->size; + + struct _pbcM_si_slot * slot = &map->slot[hash]; + for (;;) { + if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { + *result = slot->id; + return 0; + } + if (slot->next == 0) { + return 1; + } + slot = &map->slot[slot->next-1]; + } +} + +static struct map_ip * +_pbcM_ip_new_hash(struct map_kv * table, int size) +{ + struct map_ip * ret = (struct map_ip *)malloc(sizeof(struct map_ip)); + ret->array = NULL; + ret->array_size = 0; + ret->hash_size = (size_t)size; + ret->slot = (struct _pbcM_ip_slot *)malloc(sizeof(struct _pbcM_ip_slot) * size); + memset(ret->slot,0,sizeof(struct _pbcM_ip_slot) * size); + int empty = 0; + int i; + for (i=0;islot[hash]; + if (slot->pointer == NULL) { + slot->pointer = table[i].pointer; + slot->id = table[i].id; + } else { + while(ret->slot[empty].pointer != NULL) { + ++empty; + } + struct _pbcM_ip_slot * empty_slot = &ret->slot[empty]; + empty_slot->next = slot->next; + slot->next = empty + 1; + empty_slot->id = table[i].id; + empty_slot->pointer = table[i].pointer; + } + } + return ret; +} + +struct map_ip * +_pbcM_ip_new(struct map_kv * table, int size) +{ + int i; + int max = table[0].id; + if (max > size * 2 || max < 0) + return _pbcM_ip_new_hash(table,size); + for (i=1;i max) { + max = table[i].id; + if (max > size * 2) + return _pbcM_ip_new_hash(table,size); + } + } + struct map_ip * ret = (struct map_ip *)malloc(sizeof(struct map_ip)); + ret->hash_size = size; + ret->slot = NULL; + ret->array_size = max + 1; + ret->array = (void **)malloc((max+1) * sizeof(void *)); + memset(ret->array,0,(max+1) * sizeof(void *)); + for (i=0;iarray[table[i].id] = table[i].pointer; + } + return ret; +} + +void +_pbcM_ip_delete(struct map_ip * map) +{ + if (map) { + free(map->array); + free(map->slot); + free(map); + } +} + +static void +_inject(struct map_kv * table, struct map_ip *map) +{ + if (map->array) { + int n = 0; + int i; + for (i=0;i<(int)map->array_size;i++) { + if (map->array[i]) { + table[n].id = i; + table[n].pointer = map->array[i]; + ++ n; + } + } + } else { + int i; + for (i=0;i<(int)map->hash_size;i++) { + table[i].id = map->slot[i].id; + table[i].pointer = map->slot[i].pointer; + } + } +} + +struct map_ip * +_pbcM_ip_combine(struct map_ip *a, struct map_ip *b) +{ + int sz = (int)(a->hash_size + b->hash_size); + struct map_kv * table = (struct map_kv *)malloc(sz * sizeof(struct map_kv)); + memset(table , 0 , sz * sizeof(struct map_kv)); + _inject(table, a); + _inject(table + a->hash_size, b); + struct map_ip * r = _pbcM_ip_new(table, sz); + free(table); + return r; +} + +void * +_pbcM_ip_query(struct map_ip * map, int id) +{ + if (map == NULL) + return NULL; + if (map->array) { + if (id>=0 && id<(int)map->array_size) + return map->array[id]; + return NULL; + } + int hash = (unsigned)id % map->hash_size; + struct _pbcM_ip_slot * slot = &map->slot[hash]; + for (;;) { + if (slot->id == id) { + return slot->pointer; + } + if (slot->next == 0) { + return NULL; + } + slot = &map->slot[slot->next-1]; + } +} + +struct _pbcM_sp_slot { + const char *key; + size_t hash; + void *pointer; + int next; +}; + +struct map_sp { + size_t cap; + size_t size; + struct heap *heap; + struct _pbcM_sp_slot * slot; +}; + +struct map_sp * +_pbcM_sp_new(int max , struct heap *h) +{ + struct map_sp * ret = (struct map_sp *)HMALLOC(sizeof(struct map_sp)); + int cap = 1; + while (cap < max) { + cap *=2; + } + ret->cap = cap; + ret->size = 0; + ret->slot = (struct _pbcM_sp_slot *)HMALLOC(ret->cap * sizeof(struct _pbcM_sp_slot)); + memset(ret->slot,0,sizeof(struct _pbcM_sp_slot) * ret->cap); + ret->heap = h; + return ret; +} + +void +_pbcM_sp_delete(struct map_sp *map) +{ + if (map && map->heap == NULL) { + _pbcM_free(map->slot); + _pbcM_free(map); + } +} + +static void _pbcM_sp_rehash(struct map_sp *map); + +static void +_pbcM_sp_insert_hash(struct map_sp *map, const char *key, size_t hash_full, void * value) +{ + if (map->cap > map->size) { + size_t hash = hash_full & (map->cap-1); + struct _pbcM_sp_slot * slot = &map->slot[hash]; + if (slot->key == NULL) { + slot->key = key; + slot->pointer = value; + slot->hash = hash_full; + } else { + int empty = (hash + 1) & (map->cap-1); + while(map->slot[empty].key != NULL) { + empty = (empty + 1) & (map->cap-1); + } + struct _pbcM_sp_slot * empty_slot = &map->slot[empty]; + empty_slot->next = slot->next; + slot->next = empty + 1; + empty_slot->pointer = value; + empty_slot->key = key; + empty_slot->hash = hash_full; + } + map->size++; + return; + } + _pbcM_sp_rehash(map); + _pbcM_sp_insert_hash(map, key, hash_full, value); +} + +static void +_pbcM_sp_rehash(struct map_sp *map) { + struct heap * h = map->heap; + struct _pbcM_sp_slot * old_slot = map->slot; + size_t size = map->size; + map->size = 0; + map->cap *= 2; + map->slot = (struct _pbcM_sp_slot *)HMALLOC(sizeof(struct _pbcM_sp_slot)*map->cap); + memset(map->slot,0,sizeof(struct _pbcM_sp_slot)*map->cap); + size_t i; + for (i=0;icap-1); + struct _pbcM_sp_slot * slot = &map->slot[hash]; + if (slot->key == NULL) { + if (map->cap <= map->size) + goto _rehash; + slot->key = key; + slot->hash = hash_full; + map->size++; + return &(slot->pointer); + } else { + for (;;) { + if (slot->hash == hash_full && strcmp(slot->key, key) == 0) + return &(slot->pointer); + if (slot->next == 0) { + break; + } + slot = &map->slot[slot->next-1]; + } + if (map->cap <= map->size) + goto _rehash; + + int empty = (hash + 1) & (map->cap-1); + while(map->slot[empty].key != NULL) { + empty = (empty + 1) & (map->cap-1); + } + struct _pbcM_sp_slot * empty_slot = &map->slot[empty]; + empty_slot->next = slot->next; + slot->next = empty + 1; + empty_slot->key = key; + empty_slot->hash = hash_full; + + map->size++; + + return &(empty_slot->pointer); + } +_rehash: + _pbcM_sp_rehash(map); + return _pbcM_sp_query_insert_hash(map, key, hash_full); +} + +void +_pbcM_sp_insert(struct map_sp *map, const char *key, void * value) +{ + _pbcM_sp_insert_hash(map,key,calc_hash(key),value); +} + +void ** +_pbcM_sp_query_insert(struct map_sp *map, const char *key) +{ + return _pbcM_sp_query_insert_hash(map,key,calc_hash(key)); +} + +void * +_pbcM_sp_query(struct map_sp *map, const char *key) +{ + if (map == NULL) + return NULL; + size_t hash_full = calc_hash(key); + size_t hash = hash_full & (map->cap -1); + + struct _pbcM_sp_slot * slot = &map->slot[hash]; + for (;;) { + if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { + return slot->pointer; + } + if (slot->next == 0) { + return NULL; + } + slot = &map->slot[slot->next-1]; + } +} + +void +_pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p)) +{ + size_t i; + for (i=0;icap;i++) { + if (map->slot[i].pointer) { + func(map->slot[i].pointer); + } + } +} + +void +_pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud) +{ + size_t i; + for (i=0;icap;i++) { + if (map->slot[i].pointer) { + func(map->slot[i].pointer,ud); + } + } +} + +static int +_find_first(struct map_sp *map) +{ + size_t i; + for (i=0;icap;i++) { + if (map->slot[i].pointer) { + return i; + } + } + return -1; +} + +static int +_find_next(struct map_sp *map, const char *key) +{ + size_t hash_full = calc_hash(key); + size_t hash = hash_full & (map->cap -1); + + struct _pbcM_sp_slot * slot = &map->slot[hash]; + for (;;) { + if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { + int i = slot - map->slot + 1; + while(icap) { + if (map->slot[i].pointer) { + return i; + } + ++i; + } + return -1; + } + if (slot->next == 0) { + return -1; + } + slot = &map->slot[slot->next-1]; + } +} + +void * +_pbcM_sp_next(struct map_sp *map, const char ** key) +{ + if (map == NULL) { + *key = NULL; + return NULL; + } + int idx; + if (*key == NULL) { + idx = _find_first(map); + } else { + idx = _find_next(map, *key); + } + if (idx < 0) { + *key = NULL; + return NULL; + } + *key = map->slot[idx].key; + return map->slot[idx].pointer; +} + + + diff --git a/luaclib/pb/src/map.h b/luaclib/pb/src/map.h new file mode 100644 index 0000000..d0fc6a9 --- /dev/null +++ b/luaclib/pb/src/map.h @@ -0,0 +1,33 @@ +#ifndef PROTOBUF_C_MAP_H +#define PROTOBUF_C_MAP_H + +#include "alloc.h" + +struct map_ip; +struct map_si; +struct map_sp; + +struct map_kv { + int id; + void *pointer; +}; + +struct map_si * _pbcM_si_new(struct map_kv * table, int size); +int _pbcM_si_query(struct map_si *map, const char *key, int *result); +void _pbcM_si_delete(struct map_si *map); + +struct map_ip * _pbcM_ip_new(struct map_kv * table, int size); +struct map_ip * _pbcM_ip_combine(struct map_ip * a, struct map_ip * b); +void * _pbcM_ip_query(struct map_ip * map, int id); +void _pbcM_ip_delete(struct map_ip *map); + +struct map_sp * _pbcM_sp_new(int max, struct heap *h); +void _pbcM_sp_insert(struct map_sp *map, const char *key, void * value); +void * _pbcM_sp_query(struct map_sp *map, const char *key); +void ** _pbcM_sp_query_insert(struct map_sp *map, const char *key); +void _pbcM_sp_delete(struct map_sp *map); +void _pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p)); +void _pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud); +void * _pbcM_sp_next(struct map_sp *map, const char ** key); + +#endif diff --git a/luaclib/pb/src/pattern.c b/luaclib/pb/src/pattern.c new file mode 100644 index 0000000..b6d6829 --- /dev/null +++ b/luaclib/pb/src/pattern.c @@ -0,0 +1,1134 @@ +#include "alloc.h" +#include "context.h" +#include "varint.h" +#include "pattern.h" +#include "array.h" +#include "proto.h" +#include "map.h" + +#include +#ifndef _MSC_VER +#include +#endif +#include +#include +#include +#include + +static void +set_default_v(void * output, int ctype, pbc_var defv) { + switch (ctype) { + case CTYPE_INT32: + *(uint32_t *)output = defv->integer.low; + break; + case CTYPE_INT64: + *(uint64_t *)output = (uint64_t)defv->integer.low | (uint64_t)defv->integer.hi << 32; + break; + case CTYPE_DOUBLE: + *(double *)output = defv->real; + break; + case CTYPE_FLOAT: + *(float *)output = (float)defv->real; + break; + case CTYPE_BOOL: + *(bool *)output = (defv->integer.low != 0); + break; + case CTYPE_INT8: + *(uint8_t *)output = (uint8_t)defv->integer.low; + break; + case CTYPE_INT16: + *(uint16_t *)output = (uint16_t)defv->integer.low; + break; + case CTYPE_VAR: + *(union _pbc_var *)output = *defv; + break; + } +} + +static void +_pattern_set_default(struct _pattern_field *field, char *output) { + if (field->ctype == CTYPE_ARRAY || field->ctype == CTYPE_PACKED) { + struct _pbc_array *array = (struct _pbc_array *)(output + field->offset); + _pbcA_open(array); + } else if (field->ptype == PTYPE_ENUM) { + pbc_var defv; + defv->integer.low = field->defv->e.id; + defv->integer.hi = 0; + set_default_v(output + field->offset, field->ctype, defv); + } + set_default_v(output + field->offset, field->ctype, field->defv); +} + +void +pbc_pattern_set_default(struct pbc_pattern *pat, void *output) { + int i; + for (i=0;icount;i++) { + _pattern_set_default(&pat->f[i], (char *)output); + } +} + +// pattern unpack + +static struct _pattern_field * +bsearch_pattern(struct pbc_pattern *pat, int id) +{ + int begin = 0; + int end = pat->count; + while (begin < end) { + int mid = (begin + end)/2; + struct _pattern_field * f = &pat->f[mid]; + if (id == f->id) { + return f; + } + if (id < f->id) { + end = mid; + } else { + begin = mid + 1; + } + } + return NULL; +} + +static inline int +write_real(int ctype, double v, void *out) { + switch(ctype) { + case CTYPE_DOUBLE: + *(double *)out = v; + return 0; + case CTYPE_FLOAT: + *(float *)out = (float)v; + return 0; + case CTYPE_VAR: + ((union _pbc_var *)out)->real = v; + return 0; + } + return -1; +} + +static inline int +write_longlong(int ctype, struct longlong *i, void *out) { + switch(ctype) { + case CTYPE_INT32: + *(uint32_t *)out = i->low; + return 0; + case CTYPE_INT64: + *(uint64_t *)out = (uint64_t)i->low | (uint64_t)i->hi << 32; + return 0; + case CTYPE_BOOL: + *(bool *)out = (i->low !=0) ; + return 0; + case CTYPE_INT8: + *(uint8_t *)out = (uint8_t)i->low; + return 0; + case CTYPE_INT16: + *(uint8_t *)out = (uint16_t)i->low; + return 0; + case CTYPE_VAR: + ((union _pbc_var *)out)->integer = *i; + return 0; + } + return -1; +} + +static inline int +write_integer(int ctype, struct atom *a, void *out) { + return write_longlong(ctype, &(a->v.i), out); +} + +static int unpack_array(int ptype, char *buffer, struct atom *, pbc_array _array); + +int +_pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array) { + pbc_var var; + var->integer.hi = 0; + int i; + switch(ptype) { + case PTYPE_DOUBLE: + if (size % 8 != 0) + return -1; + for (i=0;ireal = u.d; + _pbcA_push(array, var); + } + return size/8; + case PTYPE_FLOAT: + if (size % 4 != 0) + return -1; + for (i=0;ireal = (double)u.f; + _pbcA_push(array, var); + } + return size/4; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + if (size % 4 != 0) + return -1; + for (i=0;iinteger.low = (uint32_t)buffer[i] | + (uint32_t)buffer[i+1] << 8 | + (uint32_t)buffer[i+2] << 16 | + (uint32_t)buffer[i+3] << 24; + _pbcA_push(array, var); + } + return size/4; + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + if (size % 8 != 0) + return -1; + for (i=0;iinteger.low = (uint32_t)buffer[i] | + (uint32_t)buffer[i+1] << 8 | + (uint32_t)buffer[i+2] << 16 | + (uint32_t)buffer[i+3] << 24; + var->integer.hi = (uint32_t)buffer[i+4] | + (uint32_t)buffer[i+5] << 8 | + (uint32_t)buffer[i+6] << 16 | + (uint32_t)buffer[i+7] << 24; + _pbcA_push(array, var); + } + return size/8; + case PTYPE_INT64: + case PTYPE_UINT64: + case PTYPE_INT32: + case PTYPE_UINT32: + case PTYPE_ENUM: // enum must be integer type in pattern mode + case PTYPE_BOOL: { + int n = 0; + while (size > 0) { + int len; + if (size >= 10) { + len = _pbcV_decode(buffer, &(var->integer)); + } else { + uint8_t temp[10]; + memcpy(temp, buffer, size); + len = _pbcV_decode(buffer, &(var->integer)); + if (len > size) + return -1; + } + _pbcA_push(array, var); + buffer += len; + size -= len; + ++n; + } + return n; + } + case PTYPE_SINT32: { + int n = 0; + while (size > 0) { + int len; + if (size >= 10) { + len = _pbcV_decode(buffer, &(var->integer)); + _pbcV_dezigzag32(&(var->integer)); + } else { + uint8_t temp[10]; + memcpy(temp, buffer, size); + len = _pbcV_decode(buffer, &(var->integer)); + if (len > size) + return -1; + _pbcV_dezigzag32(&(var->integer)); + } + _pbcA_push(array, var); + buffer += len; + size -= len; + ++n; + } + return n; + } + case PTYPE_SINT64: { + int n = 0; + while (size > 0) { + int len; + if (size >= 10) { + len = _pbcV_decode(buffer, &(var->integer)); + _pbcV_dezigzag64(&(var->integer)); + } else { + uint8_t temp[10]; + memcpy(temp, buffer, size); + len = _pbcV_decode(buffer, &(var->integer)); + if (len > size) + return -1; + _pbcV_dezigzag64(&(var->integer)); + } + _pbcA_push(array, var); + buffer += len; + size -= len; + ++n; + } + return n; + } + } + return -1; +} + +static int +unpack_field(int ctype, int ptype, char * buffer, struct atom * a, void *out) { + if (ctype == CTYPE_ARRAY) { + return unpack_array(ptype, buffer, a , (struct _pbc_array *)out); + } + if (ctype == CTYPE_PACKED) { + return _pbcP_unpack_packed((uint8_t *)buffer + a->v.s.start, a->v.s.end - a->v.s.start, ptype, (struct _pbc_array *)out); + } + switch(ptype) { + case PTYPE_DOUBLE: + CHECK_BIT64(a, -1); + return write_real(ctype, read_double(a), out); + case PTYPE_FLOAT: + CHECK_BIT32(a, -1); + return write_real(ctype, read_float(a), out); + case PTYPE_INT64: + case PTYPE_UINT64: + case PTYPE_INT32: + case PTYPE_UINT32: + case PTYPE_ENUM: // enum must be integer type in pattern mode + case PTYPE_BOOL: + CHECK_VARINT(a, -1); + return write_integer(ctype, a , out); + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + CHECK_BIT32(a, -1); + return write_integer(ctype, a , out); + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + CHECK_BIT64(a, -1); + return write_integer(ctype, a , out); + case PTYPE_SINT32: { + CHECK_VARINT(a, -1); + struct longlong temp = a->v.i; + _pbcV_dezigzag32(&temp); + return write_longlong(ctype, &temp , out); + } + case PTYPE_SINT64: { + CHECK_LEND(a, -1); + struct longlong temp = a->v.i; + _pbcV_dezigzag64(&temp); + return write_longlong(ctype, &temp , out); + } + case PTYPE_MESSAGE: + CHECK_LEND(a, -1); + ((union _pbc_var *)out)->m.buffer = buffer + a->v.s.start; + ((union _pbc_var *)out)->m.len = a->v.s.end - a->v.s.start; + return 0; + case PTYPE_STRING: + case PTYPE_BYTES: + CHECK_LEND(a, -1); + ((struct pbc_slice *)out)->buffer = buffer + a->v.s.start; + ((struct pbc_slice *)out)->len = a->v.s.end - a->v.s.start; + return 0; + } + return -1; +} + +static int +unpack_array(int ptype, char *buffer, struct atom * a, pbc_array _array) { + pbc_var var; + int r = unpack_field(CTYPE_VAR, ptype, buffer, a , var); + if (r !=0 ) + return r; + _pbcA_push(_array , var); + + return 0; +} + +void +pbc_pattern_close_arrays(struct pbc_pattern *pat, void * data) { + int i; + for (i=0;icount;i++) { + if (pat->f[i].ctype == CTYPE_ARRAY || pat->f[i].ctype == CTYPE_PACKED) { + void *array = (char *)data + pat->f[i].offset; + _pbcA_close((struct _pbc_array *)array); + } + } +} + +static inline int +_pack_wiretype(uint32_t wt, struct pbc_slice *s) { + int len; + if (s->len < 10) { + uint8_t temp[10]; + len = _pbcV_encode32(wt, temp); + if (len > s->len) + return -1; + memcpy(s->buffer, temp, len); + } else { + len = _pbcV_encode32(wt, (uint8_t *)s->buffer); + } + s->buffer = (char *)s->buffer + len; + s->len -= len; + return len; +} + +static inline int +_pack_varint64(uint64_t i64, struct pbc_slice *s) { + int len; + if (s->len < 10) { + uint8_t temp[10]; + len = _pbcV_encode(i64, temp); + if (len > s->len) + return -1; + memcpy(s->buffer, temp, len); + } else { + len = _pbcV_encode(i64, (uint8_t *)s->buffer); + } + s->buffer = (char *)s->buffer + len; + s->len -= len; + return len; +} + +static inline int +_pack_sint32(uint32_t v, struct pbc_slice *s) { + int len; + if (s->len < 10) { + uint8_t temp[10]; + len = _pbcV_zigzag32(v, temp); + if (len > s->len) + return -1; + memcpy(s->buffer, temp, len); + } else { + len = _pbcV_zigzag32(v, (uint8_t *)s->buffer); + } + s->buffer = (char *)s->buffer + len; + s->len -= len; + return len; +} + +static inline int +_pack_sint64(uint64_t v, struct pbc_slice *s) { + int len; + if (s->len < 10) { + uint8_t temp[10]; + len = _pbcV_zigzag(v, temp); + if (len > s->len) + return -1; + memcpy(s->buffer, temp, len); + } else { + len = _pbcV_zigzag(v, (uint8_t *)s->buffer); + } + s->buffer = (char *)s->buffer + len; + s->len -= len; + return len; +} + +static inline void +_fix32_encode(uint32_t v , uint8_t *buffer) { + buffer[0] = (uint8_t) v; + buffer[1] = (uint8_t) (v >> 8); + buffer[2] = (uint8_t) (v >> 16); + buffer[3] = (uint8_t) (v >> 24); +} + +static inline void +_fix64_encode(struct longlong *v , uint8_t *buffer) { + _fix32_encode(v->low , buffer); + _fix32_encode(v->hi, buffer + 4); +} + +static int +_pack_number(int ptype , int ctype , struct pbc_slice *s, void *input) { + pbc_var var; + if (ctype == CTYPE_VAR) { + memcpy(var, input, sizeof(var)); + } else { + switch (ctype) { + case CTYPE_INT32: + var->integer.low = *(uint32_t *)input; + var->integer.hi = 0; + break; + case CTYPE_INT64: { + uint64_t v = *(uint64_t *)input; + var->integer.low = (uint32_t) (v & 0xffffffff); + var->integer.hi = (uint32_t) (v >> 32); + break; + } + case CTYPE_INT16: + var->integer.low = *(uint16_t *)input; + var->integer.hi = 0; + break; + case CTYPE_INT8: + var->integer.low = *(uint8_t *)input; + var->integer.hi = 0; + break; + case CTYPE_BOOL: + var->integer.low = *(bool *)input; + var->integer.hi = 0; + break; + case CTYPE_DOUBLE: + var->real = *(double *)input; + break; + case CTYPE_FLOAT: + var->real = *(float *)input; + break; + } + } + + switch(ptype) { + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + if (s->len < 8) + return -1; + _fix64_encode(&(var->integer), (uint8_t *)s->buffer); + s->buffer = (char *)s->buffer + 8; + s->len -= 8; + return 8; + case PTYPE_DOUBLE: + if (s->len < 8) + return -1; + double_encode(var->real , (uint8_t *)s->buffer); + s->buffer = (char *)s->buffer + 8; + s->len -= 8; + return 8; + case PTYPE_FLOAT: + if (s->len < 4) + return -1; + float_encode((float)var->real , (uint8_t *)s->buffer); + s->buffer = (char *)s->buffer + 4; + s->len -= 4; + return 4; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + if (s->len < 4) + return -1; + _fix32_encode(var->integer.low, (uint8_t *)s->buffer); + s->buffer = (char *)s->buffer + 4; + s->len -= 4; + return 4; + case PTYPE_UINT64: + case PTYPE_INT64: + case PTYPE_INT32: + return _pack_varint64((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32, s); + case PTYPE_UINT32: + case PTYPE_BOOL: + case PTYPE_ENUM: + return _pack_wiretype(var->integer.low , s); + case PTYPE_SINT32: + return _pack_sint32(var->integer.low , s); + case PTYPE_SINT64: + return _pack_sint64((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , s); + default: + return -1; + } +} + +static int +_pack_field(struct _pattern_field *pf , int ctype, struct pbc_slice *s, void *input) { + int wiretype; + int ret = 0; + int len; + struct pbc_slice * input_slice; + struct pbc_slice string_slice; + + switch(pf->ptype) { + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + case PTYPE_DOUBLE: + wiretype = WT_BIT64; + goto _number; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + case PTYPE_FLOAT: + wiretype = WT_BIT32; + goto _number; + case PTYPE_UINT64: + case PTYPE_INT64: + case PTYPE_INT32: + case PTYPE_BOOL: + case PTYPE_UINT32: + case PTYPE_ENUM: + case PTYPE_SINT32: + case PTYPE_SINT64: + wiretype = WT_VARINT; + goto _number; + case PTYPE_STRING: + wiretype = WT_LEND; + input_slice = (struct pbc_slice *)input; + if (input_slice->len >= 0) + goto _string; + string_slice.buffer = input_slice->buffer; + string_slice.len = strlen((const char *)string_slice.buffer) - input_slice->len; + input_slice = &string_slice; + + goto _string; + case PTYPE_MESSAGE: + case PTYPE_BYTES: + wiretype = WT_LEND; + goto _bytes; + default: + break; + } + + return 0; +_bytes: + input_slice = (struct pbc_slice *)input; +_string: + len = _pack_wiretype(pf->id << 3 | WT_LEND , s); + if (len < 0) { + return len; + } + ret += len; + len = _pack_wiretype(input_slice->len , s); + if (len < 0) { + return len; + } + ret += len; + if (input_slice->len > s->len) + return -1; + memcpy(s->buffer , input_slice->buffer, input_slice->len); + ret += input_slice->len; + s->buffer = (char *)s->buffer + input_slice->len; + s->len -= input_slice->len; + + return ret; +_number: + len = _pack_wiretype(pf->id << 3 | wiretype , s); + if (len < 0) { + return len; + } + ret += len; + len = _pack_number(pf->ptype, ctype , s, input); + if (len < 0) { + return len; + } + ret += len; + + return ret; +} + +static int +_pack_repeated(struct _pattern_field *pf , struct pbc_slice *s, pbc_array array) { + int n = pbc_array_size(array); + int ret = 0; + if (n>0) { + int i; + for (i=0;ilen - len < n * width) + return -1; + int i; + for (i=0;iptype, CTYPE_VAR , s, _pbcA_index_p(array, i)); + } + + return len + n * width; +} + +static int +_pack_packed_varint(struct _pattern_field *pf , struct pbc_slice *slice, pbc_array array) { + struct pbc_slice s = * slice; + int n = pbc_array_size(array); + int estimate = n; + int estimate_len = _pack_wiretype(estimate , &s); + if (estimate_len < 0) { + return -1; + } + int i; + int packed_len = 0; + for (i=0;iptype, CTYPE_VAR , &s, _pbcA_index_p(array, i)); + if (len < 0) + return -1; + packed_len += len; + } + if (packed_len == estimate) { + *slice = s; + return packed_len + estimate_len; + } + uint8_t temp[10]; + struct pbc_slice header_slice = { temp , 10 }; + int header_len = _pack_wiretype(packed_len , &header_slice); + if (header_len == estimate_len) { + memcpy(slice->buffer , temp , header_len); + *slice = s; + return packed_len + estimate_len; + } + if (header_len + packed_len > slice->len) + return -1; + memmove((char *)slice->buffer + header_len , (char *)slice->buffer + estimate_len, packed_len); + memcpy(slice->buffer , temp , header_len); + slice->buffer = (char *)slice->buffer + packed_len + header_len; + slice->len -= packed_len + header_len; + return packed_len + header_len; +} + +static int +_pack_packed(struct _pattern_field *pf , struct pbc_slice *s, pbc_array array) { + int n = pbc_array_size(array); + if (n == 0) + return 0; + + int ret = 0; + int len; + len = _pack_wiretype(pf->id << 3 | WT_LEND , s); + if (len < 0) { + return len; + } + ret += len; + + switch (pf->ptype) { + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + case PTYPE_DOUBLE: + len = _pack_packed_fixed(pf, 8, s , array); + if (len < 0) + return len; + break; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + case PTYPE_FLOAT: + len = _pack_packed_fixed(pf, 4, s , array); + if (len < 0) + return len; + break; + case PTYPE_UINT64: + case PTYPE_INT64: + case PTYPE_INT32: + case PTYPE_BOOL: + case PTYPE_UINT32: + case PTYPE_ENUM: + case PTYPE_SINT32: + case PTYPE_SINT64: + len = _pack_packed_varint(pf, s, array); + if (len < 0) + return len; + break; + } + ret += len; + + return ret; +} + +static bool +_is_default(struct _pattern_field * pf, void * in) { + switch (pf->ctype) { + case CTYPE_INT64: { + struct longlong * d64 = &pf->defv->integer; + return ((uint64_t)d64->low | (uint64_t)d64->hi << 32) == *(uint64_t *)in; + } + case CTYPE_DOUBLE: + return pf->defv->real == *(double *)in; + case CTYPE_FLOAT: + return (float)(pf->defv->real) == *(float *)in; + case CTYPE_INT32: + return pf->defv->integer.low == *(uint32_t *)in; + case CTYPE_INT16: + return (uint16_t)(pf->defv->integer.low) == *(uint16_t *)in; + case CTYPE_INT8: + return (uint8_t)(pf->defv->integer.low) == *(uint8_t *)in; + case CTYPE_BOOL: + if (pf->defv->integer.low) + return *(bool *)in == true; + else + return *(bool *)in == false; + } + if (pf->ptype == PTYPE_STRING) { + struct pbc_slice *slice = (struct pbc_slice *)in; + if (slice->buffer == NULL) { + return pf->defv->s.str[0] == '\0'; + } + int len = slice->len; + if (len <= 0) { + return strcmp(pf->defv->s.str, (const char *)slice->buffer) == 0; + } + return len == pf->defv->s.len && memcmp(pf->defv->s.str, slice->buffer, len)==0; + } else if (pf->ptype == PTYPE_BYTES) { + struct pbc_slice *slice = (struct pbc_slice *)in; + if (slice->buffer == NULL) + return true; + } + + return false; +} + +int +pbc_pattern_pack(struct pbc_pattern *pat, void *input, struct pbc_slice * s) +{ + struct pbc_slice slice = *s; + int i; + for (i=0;icount;i++) { + struct _pattern_field * pf = &pat->f[i]; + void * in = (char *)input + pf->offset; + int len = 0; + switch(pf->label) { + case LABEL_OPTIONAL: + if (_is_default(pf , in)) { + break; + } + case LABEL_REQUIRED: + len = _pack_field(pf, pf->ctype, &slice, in); + break; + case LABEL_REPEATED: + len = _pack_repeated(pf, &slice , (struct _pbc_array *)in); + break; + case LABEL_PACKED: + len = _pack_packed(pf, &slice , (struct _pbc_array *)in); + break; + } + if (len < 0) { + return len; + } + } + int len = (char *)slice.buffer - (char *)s->buffer; + int ret = s->len - len; + s->len = len; + return ret; +} + +int +pbc_pattern_unpack(struct pbc_pattern *pat, struct pbc_slice *s, void * output) { + if (s->len == 0) { + pbc_pattern_set_default(pat, output); + return 0; + } + pbc_ctx _ctx; + int r = _pbcC_open(_ctx, s->buffer, s->len); + if (r <= 0) { + pat->env->lasterror = "Pattern unpack open context error"; + _pbcC_close(_ctx); + return r-1; + } + + struct context * ctx = (struct context *)_ctx; + bool * field = (bool *)alloca(pat->count * sizeof(bool)); + memset(field, 0, pat->count * sizeof(bool)); + + int i; + int fc = 0; + + for (i=0;inumber;i++) { + struct _pattern_field * f = bsearch_pattern(pat, ctx->a[i].wire_id >> 3); + if (f) { + int index = f - pat->f; + if (field[index] == false) { + field[index] = true; + ++fc; + if ((f->ctype == CTYPE_ARRAY || f->ctype == CTYPE_PACKED)) { + struct _pbc_array *array = (struct _pbc_array *)((char *)output + f->offset); + _pbcA_open(array); + } + } + char * out = (char *)output + f->offset; + if (unpack_field(f->ctype , f->ptype , ctx->buffer , &ctx->a[i], out) < 0) { + int j; + for (j=0;jcount;j++) { + if (field[j] == true && (pat->f[j].ctype == CTYPE_ARRAY || pat->f[j].ctype == CTYPE_PACKED)) { + void *array = (char *)output + pat->f[j].offset; + _pbcA_close((struct _pbc_array *)array); + } + } + _pbcC_close(_ctx); + pat->env->lasterror = "Pattern unpack field error"; + return -i-1; + } + } + } + _pbcC_close(_ctx); + if (fc != pat->count) { + for (i=0;icount;i++) { + if (field[i] == false) { + _pattern_set_default(&pat->f[i], (char *)output); + } + } + } + return 0; +} + +/* + format : key %type + %f float + %F double + %d int32 + %D int64 + %b bool + %h int16 + %c int8 + %s slice + %a array +*/ + +static int +_ctype(const char * ctype) { + if (ctype[0]!='%') + return -1; + switch (ctype[1]) { + case 'f': + return CTYPE_FLOAT; + case 'F': + return CTYPE_DOUBLE; + case 'd': + return CTYPE_INT32; + case 'D': + return CTYPE_INT64; + case 'b': + return CTYPE_BOOL; + case 'h': + return CTYPE_INT16; + case 'c': + return CTYPE_INT8; + case 's': + return CTYPE_VAR; + case 'a': + return CTYPE_ARRAY; + default: + return -1; + } +} + +static int +_ctype_size(const char *ctype) { + switch (ctype[1]) { + case 'f': + return sizeof(float); + case 'F': + return sizeof(double); + case 'd': + return sizeof(int32_t); + case 'D': + return sizeof(int64_t); + case 'b': + return sizeof(bool); + case 'h': + return sizeof(int16_t); + case 'c': + return sizeof(int8_t); + case 's': + return sizeof(struct pbc_slice); + case 'a': + return sizeof(pbc_array); + default: + return 0; + } +} + +static const char * +_copy_string(const char *format , char ** temp) { + char * output = *temp; + while (*format == ' ' || *format == '\t' || *format == '\n' || *format == '\r') { + ++format; + } + while (*format != '\0' && + *format != ' ' && + *format != '\t' && + *format != '\n' && + *format != '\r') { + *output = *format; + ++output; + ++format; + } + *output = '\0'; + ++output; + *temp = output; + + return format; +} + +static int +_scan_pattern(const char * format , char * temp) { + int n = 0; + for(;;) { + format = _copy_string(format , &temp); + if (format[0] == '\0') + return 0; + ++n; + format = _copy_string(format , &temp); + if (format[0] == '\0') + return n; + } +} + +static int +_comp_field(const void * a, const void * b) { + const struct _pattern_field * fa = (const struct _pattern_field *)a; + const struct _pattern_field * fb = (const struct _pattern_field *)b; + + return fa->id - fb->id; +} + +struct pbc_pattern * +_pbcP_new(struct pbc_env * env, int n) { + size_t sz = sizeof(struct pbc_pattern) + (sizeof(struct _pattern_field)) * (n-1); + struct pbc_pattern * ret = (struct pbc_pattern *)malloc(sz); + memset(ret, 0 , sz); + ret->count = n; + ret->env = env; + return ret; +} + +static int +_check_ctype(struct _field * field, struct _pattern_field *f) { + if (field->label == LABEL_REPEATED) { + return f->ctype != CTYPE_ARRAY; + } + if (field->label == LABEL_PACKED) { + return f->ctype != CTYPE_PACKED; + } + if (field->type == PTYPE_STRING || field->type == PTYPE_MESSAGE || field->type == PTYPE_BYTES) { + return f->ctype != CTYPE_VAR; + } + if (field->type == PTYPE_FLOAT || field->type == PTYPE_DOUBLE) { + return !(f->ctype == CTYPE_DOUBLE || f->ctype == CTYPE_FLOAT); + } + if (field->type == PTYPE_ENUM) { + return !(f->ctype == CTYPE_INT8 || + f->ctype == CTYPE_INT8 || + f->ctype == CTYPE_INT16 || + f->ctype == CTYPE_INT32 || + f->ctype == CTYPE_INT64); + } + + return f->ctype == CTYPE_VAR || f->ctype == CTYPE_ARRAY || f->ctype == CTYPE_PACKED || + f->ctype == CTYPE_DOUBLE || f->ctype == CTYPE_FLOAT; +} + +struct pbc_pattern * +_pattern_new(struct _message *m, const char *format) { + int len = strlen(format); + char * temp = (char *)alloca(len+1); + int n = _scan_pattern(format, temp); + struct pbc_pattern * pat = _pbcP_new(m->env, n); + int i; + + const char *ptr = temp; + + int offset = 0; + + for (i=0;if[i]); + struct _field * field = (struct _field *)_pbcM_sp_query(m->name, ptr); + if (field == NULL) { + m->env->lasterror = "Pattern @new query none exist field"; + goto _error; + } + f->id = field->id; + f->ptype = field->type; + *f->defv = *field->default_v; + f->offset = offset; + f->label = field->label; + ptr += strlen(ptr) + 1; + f->ctype = _ctype(ptr); + if (f->ctype < 0) { + m->env->lasterror = "Pattern @new use an invalid ctype"; + goto _error; + } + + if (f->ctype == CTYPE_ARRAY && field->label == LABEL_PACKED) { + f->ctype = CTYPE_PACKED; + } + if (_check_ctype(field, f)) { + m->env->lasterror = "Pattern @new ctype check error"; + goto _error; + } + + offset += _ctype_size(ptr); + ptr += strlen(ptr) + 1; + } + + pat->count = n; + + qsort(pat->f , n , sizeof(struct _pattern_field), _comp_field); + return pat; +_error: + free(pat); + return NULL; +} + +struct pbc_pattern * +pbc_pattern_new(struct pbc_env * env , const char * message, const char * format, ... ) { + struct _message *m = _pbcP_get_message(env, message); + if (m==NULL) { + env->lasterror = "Pattern new can't find proto"; + return NULL; + } + if (format[0]=='@') { + return _pattern_new(m , format+1); + } + + int len = strlen(format); + char * temp = (char *)alloca(len+1); + int n = _scan_pattern(format, temp); + struct pbc_pattern * pat = _pbcP_new(env, n); + int i; + va_list ap; + va_start(ap , format); + + const char *ptr = temp; + + for (i=0;if[i]); + struct _field * field = (struct _field *)_pbcM_sp_query(m->name, ptr); + if (field == NULL) { + env->lasterror = "Pattern new query none exist field"; + goto _error; + } + f->id = field->id; + f->ptype = field->type; + *f->defv = *field->default_v; + f->offset = va_arg(ap, int); + f->label = field->label; + + ptr += strlen(ptr) + 1; + + f->ctype = _ctype(ptr); + if (f->ctype < 0) { + env->lasterror = "Pattern new use an invalid ctype"; + goto _error; + } + if (f->ctype == CTYPE_ARRAY && field->label == LABEL_PACKED) { + f->ctype = CTYPE_PACKED; + } + if (_check_ctype(field, f)) { + env->lasterror = "Pattern new ctype check error"; + goto _error; + } + + ptr += strlen(ptr) + 1; + } + + va_end(ap); + + pat->count = n; + + qsort(pat->f , n , sizeof(struct _pattern_field), _comp_field); + return pat; +_error: + free(pat); + return NULL; +} + +void +pbc_pattern_delete(struct pbc_pattern * pat) { + free(pat); +} diff --git a/luaclib/pb/src/pattern.h b/luaclib/pb/src/pattern.h new file mode 100644 index 0000000..880d3d5 --- /dev/null +++ b/luaclib/pb/src/pattern.h @@ -0,0 +1,26 @@ +#ifndef PROTOBUF_C_PATTERN_H +#define PROTOBUF_C_PATTERN_H + +#include "pbc.h" +#include "context.h" +#include "array.h" + +struct _pattern_field { + int id; + int offset; + int ptype; + int ctype; + int label; + pbc_var defv; +}; + +struct pbc_pattern { + struct pbc_env * env; + int count; + struct _pattern_field f[1]; +}; + +struct pbc_pattern * _pbcP_new(struct pbc_env * env, int n); +int _pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array); + +#endif diff --git a/luaclib/pb/src/pbc.h b/luaclib/pb/src/pbc.h new file mode 100644 index 0000000..1ccc487 --- /dev/null +++ b/luaclib/pb/src/pbc.h @@ -0,0 +1,104 @@ +#ifndef PROTOBUF_C_H +#define PROTOBUF_C_H + +#include +#include + +#define PBC_ARRAY_CAP 64 + +#define PBC_NOEXIST -1 +#define PBC_INT 1 +#define PBC_REAL 2 +#define PBC_BOOL 3 +#define PBC_ENUM 4 +#define PBC_STRING 5 +#define PBC_MESSAGE 6 +#define PBC_FIXED64 7 +#define PBC_FIXED32 8 +#define PBC_BYTES 9 +#define PBC_INT64 10 +#define PBC_UINT 11 +#define PBC_UNKNOWN 12 +#define PBC_REPEATED 128 + +typedef struct _pbc_array { char _data[PBC_ARRAY_CAP]; } pbc_array[1]; + +struct pbc_slice { + void *buffer; + int len; +}; + +struct pbc_pattern; +struct pbc_env; +struct pbc_rmessage; +struct pbc_wmessage; + +struct pbc_env * pbc_new(void); +void pbc_delete(struct pbc_env *); +int pbc_register(struct pbc_env *, struct pbc_slice * slice); +int pbc_type(struct pbc_env *, const char * type_name , const char * key , const char ** type); +const char * pbc_error(struct pbc_env *); + +// callback api +union pbc_value { + struct { + uint32_t low; + uint32_t hi; + } i; + double f; + struct pbc_slice s; + struct { + int id; + const char * name; + } e; +}; + +typedef void (*pbc_decoder)(void *ud, int type, const char * type_name, union pbc_value *v, int id, const char *key); +int pbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder f, void *ud); + +// message api + +struct pbc_rmessage * pbc_rmessage_new(struct pbc_env * env, const char * type_name , struct pbc_slice * slice); +void pbc_rmessage_delete(struct pbc_rmessage *); + +uint32_t pbc_rmessage_integer(struct pbc_rmessage * , const char *key , int index, uint32_t *hi); +double pbc_rmessage_real(struct pbc_rmessage * , const char *key , int index); +const char * pbc_rmessage_string(struct pbc_rmessage * , const char *key , int index, int *sz); +struct pbc_rmessage * pbc_rmessage_message(struct pbc_rmessage *, const char *key, int index); +int pbc_rmessage_size(struct pbc_rmessage *, const char *key); +int pbc_rmessage_next(struct pbc_rmessage *, const char **key); + +struct pbc_wmessage * pbc_wmessage_new(struct pbc_env * env, const char *type_name); +void pbc_wmessage_delete(struct pbc_wmessage *); + +// for negative integer, pass -1 to hi +int pbc_wmessage_integer(struct pbc_wmessage *, const char *key, uint32_t low, uint32_t hi); +int pbc_wmessage_real(struct pbc_wmessage *, const char *key, double v); +int pbc_wmessage_string(struct pbc_wmessage *, const char *key, const char * v, int len); +struct pbc_wmessage * pbc_wmessage_message(struct pbc_wmessage *, const char *key); +void * pbc_wmessage_buffer(struct pbc_wmessage *, struct pbc_slice * slice); + +// array api + +int pbc_array_size(pbc_array); +uint32_t pbc_array_integer(pbc_array array, int index, uint32_t *hi); +double pbc_array_real(pbc_array array, int index); +struct pbc_slice * pbc_array_slice(pbc_array array, int index); + +void pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi); +void pbc_array_push_slice(pbc_array array, struct pbc_slice *); +void pbc_array_push_real(pbc_array array, double v); + +struct pbc_pattern * pbc_pattern_new(struct pbc_env * , const char * message, const char *format, ...); +void pbc_pattern_delete(struct pbc_pattern *); + +// return unused bytes , -1 for error +int pbc_pattern_pack(struct pbc_pattern *, void *input, struct pbc_slice * s); + +// <0 for error +int pbc_pattern_unpack(struct pbc_pattern *, struct pbc_slice * s , void * output); + +void pbc_pattern_set_default(struct pbc_pattern * , void *data); +void pbc_pattern_close_arrays(struct pbc_pattern *, void *data); + +#endif diff --git a/luaclib/pb/src/proto.c b/luaclib/pb/src/proto.c new file mode 100644 index 0000000..265b6aa --- /dev/null +++ b/luaclib/pb/src/proto.c @@ -0,0 +1,252 @@ +#include "pbc.h" +#include "proto.h" +#include "pattern.h" +#include "map.h" +#include "alloc.h" +#include "stringpool.h" +#include "bootstrap.h" + +#include +#include + +const char * +pbc_error(struct pbc_env * p) { + const char *err = p->lasterror; + p->lasterror = ""; + return err; +} + +struct _message * +_pbcP_get_message(struct pbc_env * p , const char *name) { + return (struct _message *)_pbcM_sp_query(p->msgs, name); +} + +struct pbc_env * +pbc_new(void) { + struct pbc_env * p = (struct pbc_env *)malloc(sizeof(*p)); + p->files = _pbcM_sp_new(0 , NULL); + p->enums = _pbcM_sp_new(0 , NULL); + p->msgs = _pbcM_sp_new(0 , NULL); + p->lasterror = ""; + + _pbcB_init(p); + + return p; +} + +static void +free_enum(void *p) { + struct _enum * e = (struct _enum *)p; + _pbcM_ip_delete(e->id); + _pbcM_si_delete(e->name); + + free(p); +} + +static void +free_stringpool(void *p) { + _pbcS_delete((struct _stringpool *)p); +} + +static void +free_msg(void *p) { + struct _message * m = (struct _message *)p; + if (m->id) + _pbcM_ip_delete(m->id); + free(m->def); + _pbcM_sp_foreach(m->name, free); + _pbcM_sp_delete(m->name); + free(p); +} + +void +pbc_delete(struct pbc_env *p) { + _pbcM_sp_foreach(p->enums, free_enum); + _pbcM_sp_delete(p->enums); + + _pbcM_sp_foreach(p->msgs, free_msg); + _pbcM_sp_delete(p->msgs); + + _pbcM_sp_foreach(p->files, free_stringpool); + _pbcM_sp_delete(p->files); + + free(p); +} + +struct _enum * +_pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz) { + void * check = _pbcM_sp_query(p->enums, name); + if (check) + return NULL; + struct _enum * v = (struct _enum *)malloc(sizeof(*v)); + v->key = name; + v->id = _pbcM_ip_new(table,sz); + v->name = _pbcM_si_new(table,sz); + v->default_v->e.id = table[0].id; + v->default_v->e.name = (const char *)table[0].pointer; + + _pbcM_sp_insert(p->enums, name , v); + return v; +} + +void +_pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue) { + struct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name); + if (m==NULL) { + m = (struct _message *)malloc(sizeof(*m)); + m->def = NULL; + m->key = name; + m->id = NULL; + m->name = _pbcM_sp_new(0 , NULL); + m->env = p; + _pbcM_sp_insert(p->msgs, name, m); + } + struct _field * field = (struct _field *)malloc(sizeof(*field)); + memcpy(field,f,sizeof(*f)); + _pbcM_sp_insert(m->name, field->name, field); + pbc_var atom; + atom->m.buffer = field; + if (f->type == PTYPE_MESSAGE || f->type == PTYPE_ENUM) { + _pbcA_push(queue, atom); + } +} + +struct _iter { + int count; + struct map_kv * table; +}; + +static void +_count(void *p, void *ud) { + struct _iter *iter = (struct _iter *)ud; + iter->count ++; +} + +static void +_set_table(void *p, void *ud) { + struct _field * field = (struct _field *)p; + struct _iter *iter = (struct _iter *)ud; + iter->table[iter->count].id = field->id; + iter->table[iter->count].pointer = field; + ++iter->count; +} + +struct _message * +_pbcP_init_message(struct pbc_env * p, const char *name) { + struct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name); + if (m == NULL) { + m = (struct _message *)malloc(sizeof(*m)); + m->def = NULL; + m->key = name; + m->id = NULL; + m->name = _pbcM_sp_new(0 , NULL); + m->env = p; + _pbcM_sp_insert(p->msgs, name, m); + + return m; + } + if (m->id) { + // extend message, delete old id map. + _pbcM_ip_delete(m->id); + } + struct _iter iter = { 0, NULL }; + _pbcM_sp_foreach_ud(m->name, _count, &iter); + iter.table = (struct map_kv *)malloc(iter.count * sizeof(struct map_kv)); + iter.count = 0; + _pbcM_sp_foreach_ud(m->name, _set_table, &iter); + + m->id = _pbcM_ip_new(iter.table , iter.count); + + free(iter.table); + + return m; +} + +int +_pbcP_message_default(struct _message * m, const char * name, pbc_var defv) { + struct _field * f= (struct _field *)_pbcM_sp_query(m->name, name); + if (f==NULL) { + // invalid key + defv->p[0] = NULL; + defv->p[1] = NULL; + return -1; + } + *defv = *(f->default_v); + return f->type; +} + +int +_pbcP_type(struct _field * field, const char ** type) { + if (field == NULL) { + return 0; + } + int ret = 0; + switch (field->type) { + case PTYPE_DOUBLE: + case PTYPE_FLOAT: + ret = PBC_REAL; + break; + case PTYPE_INT64: + case PTYPE_SINT64: + ret = PBC_INT64; + break; + case PTYPE_INT32: + case PTYPE_SINT32: + ret = PBC_INT; + break; + case PTYPE_UINT32: + case PTYPE_UINT64: + ret = PBC_UINT; + break; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + ret = PBC_FIXED32; + break; + case PTYPE_SFIXED64: + case PTYPE_FIXED64: + ret = PBC_FIXED64; + break; + case PTYPE_BOOL: + ret = PBC_BOOL; + break; + case PTYPE_STRING: + ret = PBC_STRING; + break; + case PTYPE_BYTES: + ret = PBC_BYTES; + break; + case PTYPE_ENUM: + ret = PBC_ENUM; + if (type) { + *type = field->type_name.e->key; + } + break; + case PTYPE_MESSAGE: + ret = PBC_MESSAGE; + if (type) { + *type = field->type_name.m->key; + } + break; + default: + return 0; + } + if (field->label == LABEL_REPEATED || + field->label == LABEL_PACKED) { + ret |= PBC_REPEATED; + } + + return ret; +} + +int +pbc_type(struct pbc_env * p, const char * type_name , const char * key , const char ** type) { + struct _message *m = _pbcP_get_message(p, type_name); + if (m==NULL) { + return 0; + } + if (key == NULL) { + return PBC_NOEXIST; + } + struct _field * field = (struct _field *)_pbcM_sp_query(m->name, key); + return _pbcP_type(field, type); +} diff --git a/luaclib/pb/src/proto.h b/luaclib/pb/src/proto.h new file mode 100644 index 0000000..05bb2d1 --- /dev/null +++ b/luaclib/pb/src/proto.h @@ -0,0 +1,65 @@ +#ifndef PROTOBUFC_PROTO_H +#define PROTOBUFC_PROTO_H + +#include "pbc.h" +#include "map.h" +#include "array.h" +#ifndef _MSC_VER +#include +#endif +#include + +struct map_ip; +struct map_si; +struct map_sp; +struct _message; +struct _enum; + +#define LABEL_OPTIONAL 0 +#define LABEL_REQUIRED 1 +#define LABEL_REPEATED 2 +#define LABEL_PACKED 3 + +struct _field { + int id; + const char *name; + int type; + int label; + pbc_var default_v; + union { + const char * n; + struct _message * m; + struct _enum * e; + } type_name; +}; + +struct _message { + const char * key; + struct map_ip * id; // id -> _field + struct map_sp * name; // string -> _field + struct pbc_rmessage * def; // default message + struct pbc_env * env; +}; + +struct _enum { + const char * key; + struct map_ip * id; + struct map_si * name; + pbc_var default_v; +}; + +struct pbc_env { + struct map_sp * files; // string -> void * + struct map_sp * enums; // string -> _enum + struct map_sp * msgs; // string -> _message + const char * lasterror; +}; + +struct _message * _pbcP_init_message(struct pbc_env * p, const char *name); +void _pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue); +struct _enum * _pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz ); +int _pbcP_message_default(struct _message * m, const char * name, pbc_var defv); +struct _message * _pbcP_get_message(struct pbc_env * p, const char *name); +int _pbcP_type(struct _field * field, const char **type); + +#endif diff --git a/luaclib/pb/src/register.c b/luaclib/pb/src/register.c new file mode 100644 index 0000000..b41ff48 --- /dev/null +++ b/luaclib/pb/src/register.c @@ -0,0 +1,342 @@ +#include "pbc.h" +#include "proto.h" +#include "alloc.h" +#include "map.h" +#include "bootstrap.h" +#include "context.h" +#include "stringpool.h" + +#include +#include + +#ifdef _MSC_VER +#define strtoll _strtoi64 +#endif + +static const char * +_concat_name(struct _stringpool *p , const char *prefix , int prefix_sz , const char *name , int name_sz, int *sz) { + if (prefix_sz == 0) { + if (sz) { + *sz = name_sz; + } + return _pbcS_build(p , name, name_sz); + } + char * temp = (char *)alloca(name_sz + prefix_sz + 2); + memcpy(temp,prefix,prefix_sz); + temp[prefix_sz] = '.'; + memcpy(temp+prefix_sz+1,name,name_sz); + temp[name_sz + prefix_sz + 1] = '\0'; + if (sz) { + *sz = name_sz + prefix_sz + 1; + } + const char * ret = _pbcS_build(p , temp, name_sz + prefix_sz + 1); + return ret; +} + +static void +_register_enum(struct pbc_env *p, struct _stringpool *pool, struct pbc_rmessage * enum_type, const char *prefix, int prefix_sz) { + int field_count = pbc_rmessage_size(enum_type, "value"); + struct map_kv *table = (struct map_kv *)malloc(field_count * sizeof(struct map_kv)); + int i; + for (i=0;itype == PTYPE_STRING || f->type == PTYPE_BYTES) { + f->default_v->s.str = ""; + f->default_v->s.len = 0; + } else { + f->default_v->integer.low = 0; + f->default_v->integer.hi = 0; + } + return; + } + + switch (f->type) { + case PTYPE_DOUBLE: + case PTYPE_FLOAT: + f->default_v->real = strtod(value,NULL); + break; + case PTYPE_STRING: + f->default_v->s.str = _pbcS_build(pool, value , sz); + f->default_v->s.len = sz; + break; + case PTYPE_ENUM: + // enum default value will be converted to f->default_v->e in bootstrap.c : set_field_one() + f->default_v->s.str = value; + f->default_v->s.len = sz; + break; + case PTYPE_BOOL: + if (strcmp(value,"true") == 0) { + f->default_v->integer.low = 1; + } else { + f->default_v->integer.low = 0; + } + f->default_v->integer.hi = 0; + break; + case PTYPE_UINT64: + case PTYPE_INT64: + case PTYPE_SFIXED64: + case PTYPE_SINT64: { + long long v = strtoll(value, NULL, 10); + f->default_v->integer.low = (long) v; + f->default_v->integer.hi = (long)(v >> 32); + break; + } + case PTYPE_INT32: + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + case PTYPE_SINT32: { + int low = strtol(value, NULL, 10); + f->default_v->integer.low = low; + if (low < 0) { + f->default_v->integer.hi = -1; + } else { + f->default_v->integer.hi = 0; + } + break; + } + case PTYPE_UINT32: + f->default_v->integer.low = strtoul(value, NULL, 10); + f->default_v->integer.hi = 0; + break; + case PTYPE_BYTES: + case PTYPE_MESSAGE: + // bytes and message types have no default value + f->default_v->m.buffer = 0; + f->default_v->m.len = 0; + break; + default: + f->default_v->integer.low = 0; + f->default_v->integer.hi = 0; + break; + } +} + +static void +_register_field(struct pbc_rmessage * field, struct _field * f, struct _stringpool *pool) { + f->id = pbc_rmessage_integer(field, "number", 0 , 0); + f->type = pbc_rmessage_integer(field, "type", 0 , 0); // enum + f->label = pbc_rmessage_integer(field, "label", 0, 0) - 1; // LABEL_OPTIONAL = 0 + if (pbc_rmessage_size(field , "options") > 0) { + struct pbc_rmessage * options = pbc_rmessage_message(field, "options" , 0); + int packed = pbc_rmessage_integer(options , "packed" , 0 , NULL); + if (packed) { + f->label = LABEL_PACKED; + } + } + f->type_name.n = pbc_rmessage_string(field, "type_name", 0 , NULL) +1; // abandon prefix '.' + int vsz; + const char * default_value = pbc_rmessage_string(field, "default_value", 0 , &vsz); + _set_default(pool , f , f->type, default_value , vsz); +} + +static void +_register_extension(struct pbc_env *p, struct _stringpool *pool , const char * prefix, int prefix_sz, struct pbc_rmessage * msg, pbc_array queue) { + int extension_count = pbc_rmessage_size(msg , "extension"); + if (extension_count <= 0) + return; + int i; + + const char * last = NULL; + + for (i=0;ifiles, filename)) { + return CHECK_FILE_EXIST; + } + int sz = pbc_rmessage_size(file, "dependency"); + int i; + for (i=0;ifiles, dname) == NULL) { + return CHECK_FILE_DEPENDENCY; + } + } + + *fname = filename; + + return CHECK_FILE_OK; +} + +static int +_register_no_dependency(struct pbc_env * p,struct pbc_rmessage ** files , int n ) { + int r = 0; + int i; + for (i=0;ifiles , filename, pool); + _register(p,files[i],pool); + files[i] = NULL; + } + break; + } + } + return r; +} + +int +pbc_register(struct pbc_env * p, struct pbc_slice *slice) { + struct pbc_rmessage * message = pbc_rmessage_new(p, "google.protobuf.FileDescriptorSet", slice); + if (message == NULL) { + p->lasterror = "register open google.protobuf.FileDescriptorSet fail"; + return 1; + } + int n = pbc_rmessage_size(message, "file"); + struct pbc_rmessage ** files = (struct pbc_rmessage **)alloca(n * sizeof(struct pbc_rmessage *)); + int i; + if (n == 0) { + p->lasterror = "register empty"; + goto _error; + } + for (i=0;ilasterror = "register open fail"; + goto _error; + } + } + + int r = n; + do { + int rr = _register_no_dependency(p,files , n); + if (rr == r) { + p->lasterror = "register dependency error"; + goto _error; + } + r = rr; + } while (r>0); + + pbc_rmessage_delete(message); + return 0; +_error: + pbc_rmessage_delete(message); + return 1; +} diff --git a/luaclib/pb/src/rmessage.c b/luaclib/pb/src/rmessage.c new file mode 100644 index 0000000..11c1246 --- /dev/null +++ b/luaclib/pb/src/rmessage.c @@ -0,0 +1,455 @@ +#include "pbc.h" +#include "alloc.h" +#include "map.h" +#include "context.h" +#include "proto.h" +#include "pattern.h" +#include "varint.h" + +#include +#include + +struct pbc_rmessage { + struct _message * msg; + struct map_sp * index; // key -> struct value * + struct heap * heap; +}; + +union _var { + pbc_var var; + pbc_array array; + struct pbc_rmessage message; +} ; + +struct value { + struct _field * type; + union _var v; +}; + +int +pbc_rmessage_next(struct pbc_rmessage *m, const char **key) { + struct value * v = (struct value *)_pbcM_sp_next(m->index, key); + if (*key == NULL) { + return 0; + } + return _pbcP_type(v->type, NULL); +} + +#define SIZE_VAR (offsetof(struct value, v) + sizeof(pbc_var)) +#define SIZE_ARRAY (offsetof(struct value, v) + sizeof(pbc_array)) +#define SIZE_MESSAGE (offsetof(struct value, v) + sizeof(struct pbc_rmessage)) + +static struct value * +read_string(struct heap *h, struct atom *a,struct _field *f, uint8_t *buffer) { + const char * temp = (const char *) (buffer + a->v.s.start); + int len = a->v.s.end - a->v.s.start; + + if (len > 0 && temp[len-1] == '\0') { + struct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->s.str = temp; + v->v.var->s.len = len; + return v; + } else { + struct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR + len + 1); + memcpy(((char *)v) + SIZE_VAR , temp, len); + *(((char *)v) + SIZE_VAR + len) = '\0'; + v->v.var->s.str = ((char *)v) + SIZE_VAR; + v->v.var->s.len = len; + return v; + } +} + +static void +read_string_var(struct heap *h, pbc_var var,struct atom *a,struct _field *f,uint8_t *buffer) { + const char * temp = (const char *) (buffer + a->v.s.start); + int len = a->v.s.end - a->v.s.start; + if (len == 0) { + var->s.str = ""; + var->s.len = 0; + } + else if (temp[len-1] == '\0') { + var->s.str = temp; + var->s.len = len; + } else { + char * temp2 = (char *)_pbcH_alloc(h, len + 1); + memcpy(temp2, temp, len); + temp2[len]='\0'; + var->s.str = temp2; + var->s.len = -len; + } +} + +static void _pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size, struct heap *h); + +static struct value * +read_value(struct heap *h, struct _field *f, struct atom * a, uint8_t *buffer) { + struct value * v; + + switch (f->type) { + case PTYPE_DOUBLE: + CHECK_BIT64(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->real = read_double(a); + break; + case PTYPE_FLOAT: + CHECK_BIT32(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->real = (double) read_float(a); + break; + case PTYPE_ENUM: + CHECK_VARINT(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->e.id = a->v.i.low; + v->v.var->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low); + break; + case PTYPE_INT64: + case PTYPE_UINT64: + case PTYPE_INT32: + case PTYPE_UINT32: + case PTYPE_BOOL: + CHECK_VARINT(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->integer = a->v.i; + break; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + CHECK_BIT32(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->integer = a->v.i; + break; + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + CHECK_BIT64(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->integer = a->v.i; + break; + case PTYPE_SINT32: + CHECK_VARINT(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->integer = a->v.i; + _pbcV_dezigzag32(&(v->v.var->integer)); + break; + case PTYPE_SINT64: + CHECK_VARINT(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->integer = a->v.i; + _pbcV_dezigzag64(&(v->v.var->integer)); + break; + case PTYPE_STRING: + CHECK_LEND(a,NULL); + v = read_string(h,a,f,buffer); + break; + case PTYPE_BYTES: + CHECK_LEND(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_VAR); + v->v.var->s.str = (const char *)(buffer + a->v.s.start); + v->v.var->s.len = a->v.s.end - a->v.s.start; + break; + case PTYPE_MESSAGE: + CHECK_LEND(a,NULL); + v = (struct value *)_pbcH_alloc(h, SIZE_MESSAGE); + _pbc_rmessage_new(&(v->v.message), f->type_name.m , + buffer + a->v.s.start , + a->v.s.end - a->v.s.start,h); + break; + default: + return NULL; + } + v->type = f; + return v; +} + +static void +push_value_packed(struct _message * type, pbc_array array, struct _field *f, struct atom * aa, uint8_t *buffer) { + int n = _pbcP_unpack_packed((uint8_t *)buffer + aa->v.s.start, aa->v.s.end - aa->v.s.start, + f->type , array); + if (n<=0) { + // todo : error + type->env->lasterror = "Unpack packed field error"; + return; + } + if (f->type == PTYPE_ENUM) { + int i; + for (i=0;iinteger.low; + v->e.id = id; + v->e.name = (const char*)_pbcM_ip_query(f->type_name.e->id , id); + } + } +} + +static void +push_value_array(struct heap *h, pbc_array array, struct _field *f, struct atom * a, uint8_t *buffer) { + pbc_var v; + + switch (f->type) { + case PTYPE_DOUBLE: + v->real = read_double(a); + break; + case PTYPE_FLOAT: + v->real = (double) read_float(a); + break; + case PTYPE_ENUM: + v->e.id = a->v.i.low; + v->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low); + break; + case PTYPE_INT64: + case PTYPE_UINT64: + case PTYPE_INT32: + case PTYPE_UINT32: + case PTYPE_FIXED32: + case PTYPE_FIXED64: + case PTYPE_SFIXED32: + case PTYPE_SFIXED64: + case PTYPE_BOOL: + v->integer = a->v.i; + break; + case PTYPE_SINT32: + v->integer = a->v.i; + _pbcV_dezigzag32(&(v->integer)); + break; + case PTYPE_SINT64: + v->integer = a->v.i; + _pbcV_dezigzag64(&(v->integer)); + break; + case PTYPE_STRING: + CHECK_LEND(a, ); + read_string_var(h,v,a,f,buffer); + break; + case PTYPE_BYTES: + CHECK_LEND(a, ); + v->s.str = (const char *)(buffer + a->v.s.start); + v->s.len = a->v.s.end - a->v.s.start; + break; + case PTYPE_MESSAGE: { + CHECK_LEND(a, ); + struct pbc_rmessage message; + _pbc_rmessage_new(&message, f->type_name.m , + buffer + a->v.s.start , + a->v.s.end - a->v.s.start,h); + if (message.msg == NULL) { + return; + } + v->p[0] = message.msg; + v->p[1] = message.index; + break; + } + default: + return; + } + + _pbcA_push(array,v); +} + +static void +_pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size , struct heap *h) { + if (size == 0) { + ret->msg = type; + ret->index = _pbcM_sp_new(0 , h); + ret->heap = h; + return; + } + pbc_ctx _ctx; + int count = _pbcC_open(_ctx,buffer,size); + if (count <= 0) { + type->env->lasterror = "rmessage decode context error"; + memset(ret , 0, sizeof(*ret)); + return; + } + struct context * ctx = (struct context *)_ctx; + + ret->msg = type; + ret->index = _pbcM_sp_new(count, h); + ret->heap = h; + + int i; + + for (i=0;inumber;i++) { + int id = ctx->a[i].wire_id >> 3; + struct _field * f = (struct _field *)_pbcM_ip_query(type->id , id); + if (f) { + if (f->label == LABEL_REPEATED || f->label == LABEL_PACKED) { + struct value * v; + void ** vv = _pbcM_sp_query_insert(ret->index, f->name); + if (*vv == NULL) { + v = (struct value *)_pbcH_alloc(h, SIZE_ARRAY); + v->type = f; + _pbcA_open_heap(v->v.array,ret->heap); + *vv = v; + } else { + v= (struct value *)*vv; + } + if (f->label == LABEL_PACKED) { + push_value_packed(type, v->v.array , f , &(ctx->a[i]), (uint8_t *)buffer); + if (pbc_array_size(v->v.array) == 0) { + type->env->lasterror = "rmessage decode packed data error"; + *vv = NULL; + } + } else { + push_value_array(h,v->v.array , f, &(ctx->a[i]), (uint8_t *)buffer); + if (pbc_array_size(v->v.array) == 0) { + type->env->lasterror = "rmessage decode repeated data error"; + *vv = NULL; + } + } + } else { + struct value * v = read_value(h, f, &(ctx->a[i]), (uint8_t *)buffer); + if (v) { + _pbcM_sp_insert(ret->index, f->name, v); + } else { + type->env->lasterror = "rmessage decode data error"; + } + } + } + } + + _pbcC_close(_ctx); +} + +struct pbc_rmessage * +pbc_rmessage_new(struct pbc_env * env, const char * type_name , struct pbc_slice * slice) { + struct _message * msg = _pbcP_get_message(env, type_name); + if (msg == NULL) { + env->lasterror = "Proto not found"; + return NULL; + } + struct pbc_rmessage temp; + struct heap * h = _pbcH_new(slice->len); + _pbc_rmessage_new(&temp, msg , slice->buffer, slice->len , h); + if (temp.msg == NULL) { + _pbcH_delete(h); + return NULL; + } + + struct pbc_rmessage *m = (struct pbc_rmessage *)_pbcH_alloc(temp.heap, sizeof(*m)); + *m = temp; + return m; +} + +void +pbc_rmessage_delete(struct pbc_rmessage * m) { + if (m) { + _pbcH_delete(m->heap); + } +} + +const char * +pbc_rmessage_string(struct pbc_rmessage * m , const char *key , int index, int *sz) { + struct value * v = (struct value *)_pbcM_sp_query(m->index,key); + int type = 0; + pbc_var var; + if (v == NULL) { + type = _pbcP_message_default(m->msg, key, var); + } else { + if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { + _pbcA_index(v->v.array, index, var); + } else { + var[0] = v->v.var[0]; + } + type = v->type->type; + } + + if (type == PTYPE_ENUM) { + if (sz) { + *sz = strlen(var->e.name); + } + return var->e.name; + } + + if (sz) { + int len = var->s.len; + if (len<0) { + len = - len; + } + *sz = len; + } + return var->s.str; +} + +uint32_t +pbc_rmessage_integer(struct pbc_rmessage *m , const char *key , int index, uint32_t *hi) { + struct value * v = (struct value *)_pbcM_sp_query(m->index,key); + pbc_var var; + int type = 0; + if (v == NULL) { + type = _pbcP_message_default(m->msg, key, var); + } else { + if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { + _pbcA_index(v->v.array, index, var); + } else { + var[0] = v->v.var[0]; + } + type = v->type->type; + } + + if (type == PTYPE_ENUM) { + if (hi) { + *hi = 0; + } + return var->e.id; + } + + if (hi) { + *hi = var->integer.hi; + } + return var->integer.low; +} + +double +pbc_rmessage_real(struct pbc_rmessage * m, const char *key , int index) { + struct value * v = (struct value *)_pbcM_sp_query(m->index,key); + pbc_var var; + if (v == NULL) { + _pbcP_message_default(m->msg, key, var); + } else { + if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { + _pbcA_index(v->v.array, index, var); + } else { + return v->v.var->real; + } + } + return var->real; +} + + +struct pbc_rmessage * +pbc_rmessage_message(struct pbc_rmessage * rm, const char *key, int index) { + struct value * v = (struct value *)_pbcM_sp_query(rm->index,key); + if (v == NULL) { + struct _field * f = (struct _field *)_pbcM_sp_query(rm->msg->name, key); + if (f == NULL) { + rm->msg->env->lasterror = "Invalid key for sub-message"; + // invalid key + return NULL; + } + struct _message * m = f->type_name.m; + + if (m->def == NULL) { + // m->def will be free at the end (pbc_delete). + m->def = (struct pbc_rmessage *)malloc(sizeof(struct pbc_rmessage)); + m->def->msg = m; + m->def->index = NULL; + } + return m->def; + } else { + if (v->type->label == LABEL_REPEATED) { + return (struct pbc_rmessage *)_pbcA_index_p(v->v.array,index); + } else { + return &(v->v.message); + } + } +} + +int +pbc_rmessage_size(struct pbc_rmessage *m, const char *key) { + struct value * v = (struct value *)_pbcM_sp_query(m->index,key); + if (v == NULL) { + return 0; + } + if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { + return pbc_array_size(v->v.array); + } else { + return 1; + } +} \ No newline at end of file diff --git a/luaclib/pb/src/stringpool.c b/luaclib/pb/src/stringpool.c new file mode 100644 index 0000000..9e64458 --- /dev/null +++ b/luaclib/pb/src/stringpool.c @@ -0,0 +1,60 @@ +#include "alloc.h" + +#include +#include + +#define PAGE_SIZE 256 + +struct _stringpool { + char * buffer; + size_t len; + struct _stringpool *next; +}; + +struct _stringpool * +_pbcS_new(void) { + struct _stringpool * ret = (struct _stringpool *)malloc(sizeof(struct _stringpool) + PAGE_SIZE); + ret->buffer = (char *)(ret + 1); + ret->len = 0; + ret->next = NULL; + return ret; +} + +void +_pbcS_delete(struct _stringpool *pool) { + while(pool) { + struct _stringpool *next = pool->next; + free(pool); + pool = next; + } +} + +const char * +_pbcS_build(struct _stringpool *pool, const char * str , int sz) { + size_t s = sz + 1; + if (s < PAGE_SIZE - pool->len) { + char * ret = pool->buffer + pool->len; + memcpy(pool->buffer + pool->len, str, s); + pool->len += s; + return ret; + } + if (s > PAGE_SIZE) { + struct _stringpool * next = (struct _stringpool *)malloc(sizeof(struct _stringpool) + s); + next->buffer = (char *)(next + 1); + memcpy(next->buffer, str, s); + next->len = s; + next->next = pool->next; + pool->next = next; + return next->buffer; + } + struct _stringpool *next = (struct _stringpool *)malloc(sizeof(struct _stringpool) + PAGE_SIZE); + next->buffer = pool->buffer; + next->next = pool->next; + next->len = pool->len; + + pool->next = next; + pool->buffer = (char *)(next + 1); + memcpy(pool->buffer, str, s); + pool->len = s; + return pool->buffer; +} diff --git a/luaclib/pb/src/stringpool.h b/luaclib/pb/src/stringpool.h new file mode 100644 index 0000000..394423d --- /dev/null +++ b/luaclib/pb/src/stringpool.h @@ -0,0 +1,10 @@ +#ifndef PROTOBUF_C_STRINGPOOL_H +#define PROTOBUF_C_STRINGPOOL_H + +struct _stringpool; + +struct _stringpool * _pbcS_new(void); +void _pbcS_delete(struct _stringpool *pool); +const char * _pbcS_build(struct _stringpool *pool, const char * str , int sz); + +#endif diff --git a/luaclib/pb/src/varint.c b/luaclib/pb/src/varint.c new file mode 100644 index 0000000..928581d --- /dev/null +++ b/luaclib/pb/src/varint.c @@ -0,0 +1,110 @@ +#include "varint.h" + +#include "pbc.h" + +#include + +inline int +_pbcV_encode32(uint32_t number, uint8_t buffer[10]) +{ + if (number < 0x80) { + buffer[0] = (uint8_t) number ; + return 1; + } + buffer[0] = (uint8_t) (number | 0x80 ); + if (number < 0x4000) { + buffer[1] = (uint8_t) (number >> 7 ); + return 2; + } + buffer[1] = (uint8_t) ((number >> 7) | 0x80 ); + if (number < 0x200000) { + buffer[2] = (uint8_t) (number >> 14); + return 3; + } + buffer[2] = (uint8_t) ((number >> 14) | 0x80 ); + if (number < 0x10000000) { + buffer[3] = (uint8_t) (number >> 21); + return 4; + } + buffer[3] = (uint8_t) ((number >> 21) | 0x80 ); + buffer[4] = (uint8_t) (number >> 28); + return 5; +} + +int +_pbcV_encode(uint64_t number, uint8_t buffer[10]) +{ + if ((number & 0xffffffff) == number) { + return _pbcV_encode32((uint32_t)number , buffer); + } + int i = 0; + do { + buffer[i] = (uint8_t)(number | 0x80); + number >>= 7; + ++i; + } while (number >= 0x80); + buffer[i] = (uint8_t)number; + return i+1; +} + +int +_pbcV_decode(uint8_t buffer[10], struct longlong *result) { + if (!(buffer[0] & 0x80)) { + result->low = buffer[0]; + result->hi = 0; + return 1; + } + uint32_t r = buffer[0] & 0x7f; + int i; + for (i=1;i<4;i++) { + r |= ((buffer[i]&0x7f) << (7*i)); + if (!(buffer[i] & 0x80)) { + result->low = r; + result->hi = 0; + return i+1; + } + } + uint64_t lr = 0; + for (i=4;i<10;i++) { + lr |= ((uint64_t)(buffer[i] & 0x7f) << (7*(i-4))); + if (!(buffer[i] & 0x80)) { + result->hi = (uint32_t)(lr >> 4); + result->low = r | (((uint32_t)lr & 0xf) << 28); + return i+1; + } + } + + result->low = 0; + result->hi = 0; + return 10; +} + +int +_pbcV_zigzag32(int32_t n, uint8_t buffer[10]) +{ + n = (n << 1) ^ (n >> 31); + return _pbcV_encode32(n,buffer); +} + +int +_pbcV_zigzag(int64_t n, uint8_t buffer[10]) +{ + n = (n << 1) ^ (n >> 63); + return _pbcV_encode(n,buffer); +} + +void +_pbcV_dezigzag64(struct longlong *r) +{ + uint32_t low = r->low; + r->low = ((low >> 1) | ((r->hi & 1) << 31)) ^ - (low & 1); + r->hi = (r->hi >> 1) ^ - (low & 1); +} + +void +_pbcV_dezigzag32(struct longlong *r) +{ + uint32_t low = r->low; + r->low = (low >> 1) ^ - (low & 1); + r->hi = -(low >> 31); +} diff --git a/luaclib/pb/src/varint.h b/luaclib/pb/src/varint.h new file mode 100644 index 0000000..000882e --- /dev/null +++ b/luaclib/pb/src/varint.h @@ -0,0 +1,20 @@ +#ifndef PROTOBUF_C_VARINT_H +#define PROTOBUF_C_VARINT_H + +#include + +struct longlong { + uint32_t low; + uint32_t hi; +}; + +int _pbcV_encode32(uint32_t number, uint8_t buffer[10]); +int _pbcV_encode(uint64_t number, uint8_t buffer[10]); +int _pbcV_zigzag32(int32_t number, uint8_t buffer[10]); +int _pbcV_zigzag(int64_t number, uint8_t buffer[10]); + +int _pbcV_decode(uint8_t buffer[10], struct longlong *result); +void _pbcV_dezigzag64(struct longlong *r); +void _pbcV_dezigzag32(struct longlong *r); + +#endif diff --git a/luaclib/pb/src/wmessage.c b/luaclib/pb/src/wmessage.c new file mode 100644 index 0000000..975672b --- /dev/null +++ b/luaclib/pb/src/wmessage.c @@ -0,0 +1,518 @@ +#include "pbc.h" +#include "context.h" +#include "alloc.h" +#include "varint.h" +#include "map.h" +#include "proto.h" + +#include +#include +#include + +#ifndef _MSC_VER +#include +#endif + +#define WMESSAGE_SIZE 64 + +struct pbc_wmessage { + struct _message *type; + uint8_t * buffer; + uint8_t * ptr; + uint8_t * endptr; + pbc_array sub; + struct map_sp *packed; + struct heap * heap; +}; + +struct _packed { + int id; + int ptype; + pbc_array data; +}; + +static struct pbc_wmessage * +_wmessage_new(struct heap *h, struct _message *msg) { + struct pbc_wmessage * m = (struct pbc_wmessage *)_pbcH_alloc(h, sizeof(*m)); + m->type = msg; + m->buffer = (uint8_t *)_pbcH_alloc(h, WMESSAGE_SIZE); + m->ptr = m->buffer; + m->endptr = m->buffer + WMESSAGE_SIZE; + _pbcA_open_heap(m->sub, h); + m->packed = NULL; + m->heap = h; + + return m; +} + +struct pbc_wmessage * +pbc_wmessage_new(struct pbc_env * env, const char *type_name) { + struct _message * msg = _pbcP_get_message(env, type_name); + if (msg == NULL) + return NULL; + struct heap *h = _pbcH_new(0); + return _wmessage_new(h, msg); +} + +void +pbc_wmessage_delete(struct pbc_wmessage *m) { + if (m) { + _pbcH_delete(m->heap); + } +} + +static void +_expand_message(struct pbc_wmessage *m, int sz) { + if (m->ptr + sz > m->endptr) { + int cap = m->endptr - m->buffer; + sz = m->ptr + sz - m->buffer; + do { + cap = cap * 2; + } while ( sz > cap ) ; + int old_size = m->ptr - m->buffer; + uint8_t * buffer = (uint8_t *)_pbcH_alloc(m->heap, cap); + memcpy(buffer, m->buffer, old_size); + m->ptr = buffer + (m->ptr - m->buffer); + m->endptr = buffer + cap; + m->buffer = buffer; + } +} + +static struct _packed * +_get_packed(struct pbc_wmessage *m , struct _field *f , const char *key) { + if (m->packed == NULL) { + m->packed = _pbcM_sp_new(4, m->heap); + } + void ** v = _pbcM_sp_query_insert(m->packed , key); + if (*v == NULL) { + *v = _pbcH_alloc(m->heap, sizeof(struct _packed)); + struct _packed *p = (struct _packed *)*v; + p->id = f->id; + p->ptype = f->type; + _pbcA_open_heap(p->data, m->heap); + return p; + } + return (struct _packed *)*v; +} + +static void +_packed_integer(struct pbc_wmessage *m, struct _field *f, const char *key , uint32_t low, uint32_t hi) { + struct _packed * packed = _get_packed(m,f,key); + pbc_var var; + var->integer.low = low; + var->integer.hi = hi; + _pbcA_push(packed->data , var); +} + +static void +_packed_real(struct pbc_wmessage *m, struct _field *f, const char *key , double v) { + struct _packed * packed = _get_packed(m,f,key); + pbc_var var; + var->real = v; + _pbcA_push(packed->data , var); +} + +static inline void +int64_encode(uint32_t low, uint32_t hi , uint8_t * buffer) { + buffer[0] = (uint8_t)(low & 0xff); + buffer[1] = (uint8_t)(low >> 8 & 0xff); + buffer[2] = (uint8_t)(low >> 16 & 0xff); + buffer[3] = (uint8_t)(low >> 24 & 0xff); + buffer[4] = (uint8_t)(hi & 0xff); + buffer[5] = (uint8_t)(hi >> 8 & 0xff); + buffer[6] = (uint8_t)(hi >> 16 & 0xff); + buffer[7] = (uint8_t)(hi >> 24 & 0xff); +} + +static inline void +int32_encode(uint32_t low, uint8_t * buffer) { + buffer[0] = (uint8_t)(low & 0xff); + buffer[1] = (uint8_t)(low >> 8 & 0xff); + buffer[2] = (uint8_t)(low >> 16 & 0xff); + buffer[3] = (uint8_t)(low >> 24 & 0xff); +} + +int +pbc_wmessage_integer(struct pbc_wmessage *m, const char *key, uint32_t low, uint32_t hi) { + struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); + if (f==NULL) { + // todo : error + m->type->env->lasterror = "wmessage_interger query key error"; + return -1; + } + if (f->label == LABEL_PACKED) { + _packed_integer(m , f, key , low, hi); + return 0; + } + if (f->label == LABEL_OPTIONAL) { + if (f->type == PTYPE_ENUM) { + if (low == f->default_v->e.id) + return 0; + } else { + // if (low == f->default_v->integer.low && + // hi == f->default_v->integer.hi) { + // return 0; + // } + } + } + int id = f->id << 3; + + _expand_message(m,20); + switch (f->type) { + case PTYPE_INT64: + case PTYPE_UINT64: + case PTYPE_INT32: + id |= WT_VARINT; + m->ptr += _pbcV_encode32(id, m->ptr); + m->ptr += _pbcV_encode((uint64_t)low | (uint64_t)hi << 32 , m->ptr); + break; + case PTYPE_UINT32: + case PTYPE_ENUM: + case PTYPE_BOOL: + id |= WT_VARINT; + m->ptr += _pbcV_encode32(id, m->ptr); + m->ptr += _pbcV_encode32(low, m->ptr); + break; + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + id |= WT_BIT64; + m->ptr += _pbcV_encode32(id, m->ptr); + int64_encode(low,hi,m->ptr); + m->ptr += 8; + break; + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + id |= WT_BIT32; + m->ptr += _pbcV_encode32(id, m->ptr); + int32_encode(low,m->ptr); + m->ptr += 4; + break; + case PTYPE_SINT32: + id |= WT_VARINT; + m->ptr += _pbcV_encode32(id, m->ptr); + m->ptr += _pbcV_zigzag32(low, m->ptr); + break; + case PTYPE_SINT64: + id |= WT_VARINT; + m->ptr += _pbcV_encode32(id, m->ptr); + m->ptr += _pbcV_zigzag((uint64_t)low | (uint64_t)hi << 32 , m->ptr); + break; + } + + return 0; +} + +int +pbc_wmessage_real(struct pbc_wmessage *m, const char *key, double v) { + struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); + if (f == NULL) { + // todo : error + m->type->env->lasterror = "wmessage_real query key error"; + return -1; + } + if (f->label == LABEL_PACKED) { + _packed_real(m , f, key , v); + return 0; + } + + if (f->label == LABEL_OPTIONAL) { + // if (v == f->default_v->real) + // return 0; + } + int id = f->id << 3; + _expand_message(m,18); + switch (f->type) { + case PTYPE_FLOAT: { + id |= WT_BIT32; + m->ptr += _pbcV_encode32(id, m->ptr); + float_encode(v , m->ptr); + m->ptr += 4; + break; + } + case PTYPE_DOUBLE: + id |= WT_BIT64; + m->ptr += _pbcV_encode32(id, m->ptr); + double_encode(v , m->ptr); + m->ptr += 8; + break; + } + + return 0; +} + +int +pbc_wmessage_string(struct pbc_wmessage *m, const char *key, const char * v, int len) { + struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); + if (f == NULL) { + // todo : error + m->type->env->lasterror = "wmessage_string query key error"; + return -1; + } + + bool varlen = false; + + if (len <=0) { + varlen = true; + // -1 for add '\0' + len = strlen(v) - len; + } + if (f->label == LABEL_PACKED) { + if (f->type == PTYPE_ENUM) { + char * temp = (char *)alloca(len + 1); + if (!varlen || v[len] != '\0') { + memcpy(temp,v,len); + temp[len]='\0'; + v = temp; + } + int enum_id = 0; + int err = _pbcM_si_query(f->type_name.e->name, v , &enum_id); + if (err) { + // todo : error , invalid enum + m->type->env->lasterror = "wmessage_string packed invalid enum"; + return -1; + } + _packed_integer(m , f, key , enum_id , 0); + } + return 0; + } + + if (f->label == LABEL_OPTIONAL) { + if (f->type == PTYPE_ENUM) { + if (strncmp(v , f->default_v->e.name, len) == 0 && f->default_v->e.name[len] =='\0') { + return 0; + } + } else if (f->type == PTYPE_STRING) { + // if (len == f->default_v->s.len && + // strcmp(v, f->default_v->s.str) == 0) { + // return 0; + // } + } else if (f->type == PTYPE_BYTES) { + // if (len == 0) { + // return 0; + // } + } + } + int id = f->id << 3; + _expand_message(m,20); + switch (f->type) { + case PTYPE_ENUM : { + char * temp = (char *)alloca(len+1); + if (!varlen || v[len] != '\0') { + memcpy(temp,v,len); + temp[len]='\0'; + v = temp; + } + int enum_id = 0; + int err = _pbcM_si_query(f->type_name.e->name, v, &enum_id); + if (err) { + // todo : error , enum invalid + m->type->env->lasterror = "wmessage_string invalid enum"; + return -1; + } + id |= WT_VARINT; + m->ptr += _pbcV_encode32(id, m->ptr); + m->ptr += _pbcV_encode32(enum_id, m->ptr); + break; + } + case PTYPE_STRING: + case PTYPE_BYTES: + id |= WT_LEND; + m->ptr += _pbcV_encode32(id, m->ptr); + m->ptr += _pbcV_encode32(len, m->ptr); + _expand_message(m,len); + memcpy(m->ptr , v , len); + m->ptr += len; + break; + } + + return 0; +} + +struct pbc_wmessage * +pbc_wmessage_message(struct pbc_wmessage *m, const char *key) { + struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); + if (f == NULL) { + // todo : error + m->type->env->lasterror = "wmessage_message query key error"; + return NULL; + } + pbc_var var; + var->p[0] = _wmessage_new(m->heap, f->type_name.m); + var->p[1] = f; + _pbcA_push(m->sub , var); + return (struct pbc_wmessage *)var->p[0]; +} + +static void +_pack_packed_64(struct _packed *p,struct pbc_wmessage *m) { + int n = pbc_array_size(p->data); + int len = n * 8; + int i; + pbc_var var; + _expand_message(m,10 + len); + m->ptr += _pbcV_encode32(len, m->ptr); + switch (p->ptype) { + case PTYPE_DOUBLE: + for (i=0;idata, i, var); + double_encode(var->real , m->ptr + i * 8); + } + break; + default: + for (i=0;idata, i, var); + int64_encode(var->integer.low , var->integer.hi, m->ptr + i * 8); + } + break; + } + m->ptr += len; +} + +static void +_pack_packed_32(struct _packed *p,struct pbc_wmessage *m) { + int n = pbc_array_size(p->data); + int len = n * 4; + int i; + pbc_var var; + _expand_message(m,10 + len); + m->ptr += _pbcV_encode32(len, m->ptr); + switch (p->ptype) { + case PTYPE_FLOAT: + for (i=0;idata, i, var); + float_encode(var->real , m->ptr + i * 8); + } + break; + default: + for (i=0;idata, i, var); + int32_encode(var->integer.low , m->ptr + i * 8); + } + break; + } + m->ptr += len; +} + +static void +_pack_packed_varint(struct _packed *p,struct pbc_wmessage *m) { + int n = pbc_array_size(p->data); + + int offset = m->ptr - m->buffer; + int len = n * 2; + if (p->ptype == PTYPE_BOOL) { + len = n; + } + int i; + pbc_var var; + _expand_message(m,10 + len); + int len_len = _pbcV_encode32(len, m->ptr); + m->ptr += len_len; + + switch (p->ptype) { + case PTYPE_INT64: + case PTYPE_UINT64: + for (i=0;idata, i, var); + _expand_message(m,10); + m->ptr += _pbcV_encode((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); + } + break; + case PTYPE_INT32: + case PTYPE_BOOL: + case PTYPE_UINT32: + case PTYPE_ENUM: + for (i=0;idata, i, var); + _expand_message(m,10); + m->ptr += _pbcV_encode32(var->integer.low , m->ptr); + } + break; + case PTYPE_SINT32: + for (i=0;idata, i, var); + _expand_message(m,10); + m->ptr += _pbcV_zigzag32(var->integer.low, m->ptr); + } + break; + case PTYPE_SINT64: + for (i=0;idata, i, var); + _expand_message(m,10); + m->ptr += _pbcV_zigzag((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); + } + break; + default: + // error + memset(m->ptr , 0 , n); + m->ptr += n; + m->type->env->lasterror = "wmessage type error when pack packed"; + break; + } + int end_offset = m->ptr - m->buffer; + int end_len = end_offset - (offset + len_len); + if (end_len != len) { + uint8_t temp[10]; + int end_len_len = _pbcV_encode32(end_len, temp); + if (end_len_len != len_len) { + _expand_message(m, end_len_len); + memmove(m->buffer + offset + end_len_len , + m->buffer + offset + len_len , + end_len); + m->ptr += end_len_len - len_len; + } + memcpy(m->buffer + offset , temp, end_len_len); + } +} + +static void +_pack_packed(void *p, void *ud) { + struct _packed *packed = (struct _packed *)p; + struct pbc_wmessage * m = (struct pbc_wmessage *)ud; + int id = packed->id << 3 | WT_LEND; + _expand_message(m,10); + m->ptr += _pbcV_encode32(id, m->ptr); + switch(packed->ptype) { + case PTYPE_DOUBLE: + case PTYPE_FIXED64: + case PTYPE_SFIXED64: + _pack_packed_64(packed,m); + break; + case PTYPE_FLOAT: + case PTYPE_FIXED32: + case PTYPE_SFIXED32: + _pack_packed_32(packed,m); + break; + default: + _pack_packed_varint(packed,m); + break; + } +} + +void * +pbc_wmessage_buffer(struct pbc_wmessage *m, struct pbc_slice *slice) { + if (m->packed) { + _pbcM_sp_foreach_ud(m->packed , _pack_packed, m); + } + int i; + int n = pbc_array_size(m->sub); + for (i=0;isub, i , var); + struct pbc_slice s; + pbc_wmessage_buffer((struct pbc_wmessage *)var->p[0] , &s); + if (s.buffer) { + struct _field * f = (struct _field *)var->p[1]; + int id = f->id << 3 | WT_LEND; + _expand_message(m,20+s.len); + m->ptr += _pbcV_encode32(id, m->ptr); + m->ptr += _pbcV_encode32(s.len, m->ptr); + memcpy(m->ptr, s.buffer, s.len); + m->ptr += s.len; + } + } + slice->buffer = m->buffer; + slice->len = m->ptr - m->buffer; + + return m->buffer; +} + diff --git a/luaclib/pb/test/addressbook.c b/luaclib/pb/test/addressbook.c new file mode 100644 index 0000000..5b69fc7 --- /dev/null +++ b/luaclib/pb/test/addressbook.c @@ -0,0 +1,132 @@ +#include "pbc.h" + +#include +#include +#include +#include + +static void +read_file (const char *filename , struct pbc_slice *slice) { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + slice->buffer = NULL; + slice->len = 0; + return; + } + fseek(f,0,SEEK_END); + slice->len = ftell(f); + fseek(f,0,SEEK_SET); + slice->buffer = malloc(slice->len); + fread(slice->buffer, 1 , slice->len , f); + fclose(f); +} + + +static void +dump(uint8_t *buffer, int sz) { + int i , j; + for (i=0;i=32 && c<127) { + printf("%c",c); + } else { + printf("."); + } + } + printf("\n"); + } + } + + printf("\n"); +} + +static void +test_rmessage(struct pbc_env *env, struct pbc_slice *slice) { + struct pbc_rmessage * m = pbc_rmessage_new(env, "tutorial.Person", slice); + if (m==NULL) { + printf("Error : %s",pbc_error(env)); + return; + } + printf("name = %s\n", pbc_rmessage_string(m , "name" , 0 , NULL)); + printf("id = %d\n", pbc_rmessage_integer(m , "id" , 0 , NULL)); + printf("email = %s\n", pbc_rmessage_string(m , "email" , 0 , NULL)); + + int phone_n = pbc_rmessage_size(m, "phone"); + int i; + const char * field_name; + pbc_type(env, "tutorial.Person", "phone", &field_name); + printf("phone type [%s]\n",field_name); + + for (i=0;i + +int +main() +{ + pbc_array array; + pbc_var v; + + _pbcA_open(array); + + int i ; + + for (i=0;i<100;i++) { + v->real = (double)i; + printf("push %d\n",i); + _pbcA_push(array, v); + } + + int s = pbc_array_size(array); + + for (i=0;ireal); + } + + _pbcA_close(array); + + return 0; +} diff --git a/luaclib/pb/test/decode.c b/luaclib/pb/test/decode.c new file mode 100644 index 0000000..1640e9b --- /dev/null +++ b/luaclib/pb/test/decode.c @@ -0,0 +1,99 @@ +#include "pbc.h" + +#include +#include +#include + +static void +read_file (const char *filename , struct pbc_slice *slice) { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + slice->buffer = NULL; + slice->len = 0; + return; + } + fseek(f,0,SEEK_END); + slice->len = ftell(f); + fseek(f,0,SEEK_SET); + slice->buffer = malloc(slice->len); + fread(slice->buffer, 1 , slice->len , f); + fclose(f); +} + +static void +decode_all(void *ud , int type, const char * typename , union pbc_value *v, int id, const char *key) { + printf("%s : ", key ) ; + switch(type & ~PBC_REPEATED) { + case PBC_MESSAGE: + printf("[%s] -> \n" , typename); + pbc_decode(ud, typename, &(v->s), decode_all, ud); + printf("---------\n"); + break; + case PBC_INT: + printf("%d\n", (int)v->i.low); + break; + case PBC_REAL: + printf("%lf\n", v->f); + break; + case PBC_BOOL: + printf("<%s>\n", v->i.low ? "true" : "false"); + break; + case PBC_ENUM: + printf("[%s:%d]\n", v->e.name , v->e.id); + break; + case PBC_STRING: { + char buffer[v->s.len+1]; + memcpy(buffer, v->s.buffer, v->s.len); + buffer[v->s.len] = '\0'; + printf("\"%s\"\n", buffer); + break; + } + case PBC_BYTES: { + int i; + uint8_t *buffer = v->s.buffer; + for (i=0;is.len;i++) { + printf("%02X ",buffer[i]); + } + printf("\n"); + break; + } + case PBC_INT64: { + printf("0x%x%08x\n",v->i.hi, v->i.low); + break; + } + case PBC_UINT: + printf("%u\n",v->i.low); + break; + default: + printf("!!! %d\n", type); + break; + } +} + +void +test_decode(struct pbc_env * env , const char * pb) +{ + struct pbc_slice slice; + read_file(pb, &slice); + + pbc_decode(env, "google.protobuf.FileDescriptorSet", &slice, decode_all , env); + + int ret = pbc_register(env, &slice); + + printf("Register %d\n",ret); + + free(slice.buffer); +} + +int +main(int argc, char *argv[]) +{ + struct pbc_env * env = pbc_new(); + + test_decode(env,argv[1]); + + pbc_delete(env); + + + return 0; +} diff --git a/luaclib/pb/test/descriptor.proto b/luaclib/pb/test/descriptor.proto new file mode 100644 index 0000000..c951b63 --- /dev/null +++ b/luaclib/pb/test/descriptor.proto @@ -0,0 +1,539 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + + + +package google.protobuf; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field whithout harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; + optional int32 end = 2; + } + repeated ExtensionRange extension_range = 5; + + optional MessageOptions options = 7; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers + // take 10 bytes. Use TYPE_SINT64 if negative + // values are likely. + TYPE_UINT64 = 4; + TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers + // take 10 bytes. Use TYPE_SINT32 if negative + // values are likely. + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + TYPE_GROUP = 10; // Tag-delimited aggregate. + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + }; + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + // TODO(sanjay): Should we add LABEL_MAP? + }; + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be either TYPE_ENUM or TYPE_MESSAGE. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + // TODO(kenton): Base-64 encode? + optional string default_value = 7; + + optional FieldOptions options = 8; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; +} + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Object-C plugin) and your porject website (if available) -- there's no need +// to explain how you intend to use them. Usually you only need one extension +// number. You can declare multiple options with only one extension number by +// putting them in a sub-message. See the Custom Options section of the docs +// for examples: +// http://code.google.com/apis/protocolbuffers/docs/proto.html#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + + // If set, all the classes from the .proto file are wrapped in a single + // outer class with the given name. This applies to both Proto1 + // (equivalent to the old "--one_java_file" option) and Proto2 (where + // a .proto always translates to a single class, but you may want to + // explicitly choose the class name). + optional string java_outer_classname = 8; + + // If set true, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the outer class + // named by java_outer_classname. However, the outer class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default=false]; + + // If set true, then the Java code generator will generate equals() and + // hashCode() methods for all messages defined in the .proto file. This is + // purely a speed optimization, as the AbstractMessage base class includes + // reflection-based implementations of these methods. + optional bool java_generate_equals_and_hash = 20 [default=false]; + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default=SPEED]; + + + + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of proto2. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default=false]; + optional bool java_generic_services = 17 [default=false]; + optional bool py_generic_services = 18 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default=false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is not yet implemented in the open source + // release -- sorry, we'll try to include it in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. + optional bool packed = 2; + + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default=false]; + + // EXPERIMENTAL. DO NOT USE. + // For "map" fields, the name of the field in the enclosed type that + // is the key for this map. For example, suppose we have: + // message Item { + // required string name = 1; + // required string value = 2; + // } + // message Config { + // repeated Item items = 1 [experimental_map_key="name"]; + // } + // In this situation, the map key for Item will be set to "name". + // TODO: Fully-implement this, then remove the "experimental_" prefix. + optional string experimental_map_key = 9; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents + // "foo.(bar.baz).qux". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendent. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition. For + // example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed=true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed=true]; + + // TODO(kenton): Record comments appearing before and after the + // declaration. + } +} diff --git a/luaclib/pb/test/float.c b/luaclib/pb/test/float.c new file mode 100644 index 0000000..797a2b6 --- /dev/null +++ b/luaclib/pb/test/float.c @@ -0,0 +1,89 @@ +#include "pbc.h" + +#include +#include +#include +#include + +static void +read_file (const char *filename , struct pbc_slice *slice) { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + slice->buffer = NULL; + slice->len = 0; + return; + } + fseek(f,0,SEEK_END); + slice->len = ftell(f); + fseek(f,0,SEEK_SET); + slice->buffer = malloc(slice->len); + fread(slice->buffer, 1 , slice->len , f); + fclose(f); +} + + +static void +dump(uint8_t *buffer, int sz) { + int i , j; + for (i=0;i=32 && c<127) { + printf("%c",c); + } else { + printf("."); + } + } + printf("\n"); + } + } + + printf("\n"); +} + +static void +test_rmessage(struct pbc_env *env, struct pbc_slice *slice) { + struct pbc_rmessage * m = pbc_rmessage_new(env, "real", slice); + printf("f = %f\n", pbc_rmessage_real(m , "f" , 0 )); + printf("d = %f\n", pbc_rmessage_real(m , "d" , 0 )); + pbc_rmessage_delete(m); +} + +static struct pbc_wmessage * +test_wmessage(struct pbc_env * env) +{ + struct pbc_wmessage * msg = pbc_wmessage_new(env, "real"); + + pbc_wmessage_real(msg, "f", 1.0); + pbc_wmessage_real(msg, "d" , 4.0); + + return msg; +} + +int +main() +{ + struct pbc_slice slice; + read_file("float.pb", &slice); + if (slice.buffer == NULL) + return 1; + struct pbc_env * env = pbc_new(); + pbc_register(env, &slice); + + free(slice.buffer); + + struct pbc_wmessage *msg = test_wmessage(env); + + pbc_wmessage_buffer(msg, &slice); + + dump(slice.buffer, slice.len); + + test_rmessage(env, &slice); + + pbc_wmessage_delete(msg); + pbc_delete(env); + + return 0; +} diff --git a/luaclib/pb/test/float.proto b/luaclib/pb/test/float.proto new file mode 100644 index 0000000..e1f10c2 --- /dev/null +++ b/luaclib/pb/test/float.proto @@ -0,0 +1,4 @@ +message real { + optional float f = 1; + optional double d = 2; +} diff --git a/luaclib/pb/test/map.c b/luaclib/pb/test/map.c new file mode 100644 index 0000000..80776c1 --- /dev/null +++ b/luaclib/pb/test/map.c @@ -0,0 +1,51 @@ +#include "src/map.h" + +#include +#include + +int +main() +{ + struct map_kv kv[] = { + {1,"alice"}, + {3,"bob" }, + {99,"carol"}, + }; + + struct map_ip * map = _pbcM_ip_new(kv, sizeof(kv)/sizeof(kv[0])); + struct map_si * map2 = _pbcM_si_new(kv, sizeof(kv)/sizeof(kv[0])); + int i; + + for (i=0;i<100;i++) { + void *p= _pbcM_ip_query(map,i); + if (p) { + int id = 0; + _pbcM_si_query(map2,p,&id); + printf("%d %s\n",id,(const char *)p); + } + } + + struct map_sp * map3 = _pbcM_sp_new(0, NULL); + _pbcM_sp_insert(map3,"Alice","alice"); + _pbcM_sp_insert(map3,"Bob","bob"); + + void ** r = _pbcM_sp_query_insert(map3, "Carol"); + *r = "carol"; + + r = _pbcM_sp_query_insert(map3, "Alice"); + *r = "not alice"; + + printf("%s\n",(const char *)_pbcM_sp_query(map3,"Alice")); + printf("%s\n",(const char *)_pbcM_sp_query(map3,"Bob")); + printf("%s\n",(const char *)_pbcM_sp_query(map3,"Carol")); + + const char * key = NULL; + for (;;) { + void * v = _pbcM_sp_next(map3, &key); + if (key == NULL) + break; + printf("%s : %s\n", key, (const char *)v); + } + + return 0; +} diff --git a/luaclib/pb/test/pattern.c b/luaclib/pb/test/pattern.c new file mode 100644 index 0000000..0f35351 --- /dev/null +++ b/luaclib/pb/test/pattern.c @@ -0,0 +1,192 @@ +#include "pbc.h" + +#include +#include +#include +#include + +static void +read_file (const char *filename , struct pbc_slice *slice) { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + slice->buffer = NULL; + slice->len = 0; + return; + } + fseek(f,0,SEEK_END); + slice->len = ftell(f); + fseek(f,0,SEEK_SET); + slice->buffer = malloc(slice->len); + fread(slice->buffer, 1 , slice->len , f); + fclose(f); +} + +static void +dump(uint8_t *buffer, int sz) { + int i , j; + for (i=0;i=32 && c<127) { + printf("%c",c); + } else { + printf("."); + } + } + printf("\n"); + } + } + + printf("\n"); +} + +static struct pbc_pattern *pat; +static struct pbc_pattern *pat_phone; + +struct person_phone { + struct pbc_slice number; + int32_t type; +}; + +struct person { + struct pbc_slice name; + int32_t id; + struct pbc_slice email; + pbc_array phone; + pbc_array test; +}; + + +static void +test_pattern_unpack(struct pbc_env *env, struct pbc_slice * slice) { + struct person p; + int r = pbc_pattern_unpack(pat, slice, &p); + if (r>=0) { + printf("name = %s\n",(const char *)p.name.buffer); + printf("id = %d\n",p.id); + printf("email = %s\n",(const char *)p.email.buffer); + int n = pbc_array_size(p.phone); + int i; + for (i=0;ilen = 0; + return slice->len; + } + + pbc_array_push_slice(p.phone, &phone_slice); + + pbc_pattern_set_default(pat_phone, &phone); + + phone.number.buffer = (void *)"87654321"; + phone.number.len = -1; + + char temp2[128]; + struct pbc_slice phone_slice2 = { temp2, sizeof(temp2) }; + + unused = pbc_pattern_pack(pat_phone, &phone , &phone_slice2); + + if (unused < 0) { + slice->len = 0; + return slice->len; + } + + pbc_array_push_slice(p.phone, &phone_slice2); + + int i; + for (i=0;i<3;i++) { + pbc_array_push_integer(p.test, -i*4,0); + } + + int r = pbc_pattern_pack(pat, &p, slice); + + pbc_pattern_close_arrays(pat,&p); + printf("pack into %d bytes\n", slice->len); + + return r; +} + +int +main() +{ + struct pbc_slice slice; + read_file("addressbook.pb", &slice); + if (slice.buffer == NULL) + return 1; + struct pbc_env * env = pbc_new(); + pbc_register(env, &slice); + + free(slice.buffer); + + pat = pbc_pattern_new(env, "tutorial.Person" , + "name %s id %d email %s phone %a test %a", + offsetof(struct person, name) , + offsetof(struct person, id) , + offsetof(struct person, email) , + offsetof(struct person, phone) , + offsetof(struct person, test)); + + pat_phone = pbc_pattern_new(env, "tutorial.Person.PhoneNumber", + "number %s type %d", + offsetof(struct person_phone, number), + offsetof(struct person_phone, type)); + + + char buffer[4096]; + struct pbc_slice message = { buffer, sizeof(buffer) }; + + test_pattern_pack(env, &message); + + dump(message.buffer, message.len); + + test_pattern_unpack(env, &message); + + pbc_pattern_delete(pat); + pbc_pattern_delete(pat_phone); + + pbc_delete(env); + + return 0; +} diff --git a/luaclib/pb/test/pbc.c b/luaclib/pb/test/pbc.c new file mode 100644 index 0000000..e9a7732 --- /dev/null +++ b/luaclib/pb/test/pbc.c @@ -0,0 +1,69 @@ +#include "pbc.h" + +#include +#include + +static void +read_file (const char *filename , struct pbc_slice *slice) { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + slice->buffer = NULL; + slice->len = 0; + return; + } + fseek(f,0,SEEK_END); + slice->len = ftell(f); + fseek(f,0,SEEK_SET); + slice->buffer = malloc(slice->len); + fread(slice->buffer, 1 , slice->len , f); + fclose(f); +} + +void +test_des(struct pbc_env * env , const char * pb) +{ + struct pbc_slice slice; + read_file(pb, &slice); + + struct pbc_rmessage * msg = pbc_rmessage_new(env, "google.protobuf.FileDescriptorSet", &slice); + + struct pbc_rmessage * file = pbc_rmessage_message(msg,"file",0); + + printf("name = %s\n",pbc_rmessage_string(file, "name", 0 , NULL)); + printf("package = %s\n",pbc_rmessage_string(file, "package", 0 , NULL)); + + int sz = pbc_rmessage_size(file, "dependency"); + printf("dependency[%d] =\n" , sz); + int i; + for (i=0;i +#include +#include + +#define COUNT 1000000 + +static void +read_file (const char *filename , struct pbc_slice *slice) { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + slice->buffer = NULL; + slice->len = 0; + return; + } + fseek(f,0,SEEK_END); + slice->len = ftell(f); + fseek(f,0,SEEK_SET); + slice->buffer = malloc(slice->len); + fread(slice->buffer, 1 , slice->len , f); + fclose(f); +} + +static void +test(struct pbc_env *env) { + int i; + for(i=0; i + +#include "varint.h" +#include "pbc.h" + +static void +dump(uint8_t buffer[10], int s) +{ + int i; + for (i=0;i +#include +#include +#include + +#include "pbc.h" + +static void +read_file(const char *filename , struct pbc_slice *slice) { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(stderr, "Can't open file %s\n", filename); + exit(1); + } + fseek(f,0,SEEK_END); + slice->len = ftell(f); + fseek(f,0,SEEK_SET); + slice->buffer = malloc(slice->len); + fread(slice->buffer, 1 , slice->len , f); + fclose(f); +} + +static void +dump_bytes(const char *data, size_t len) { + size_t i; + for (i = 0; i < len; i++) + if (i == 0) + fprintf(stdout, "%02x", 0xff & data[i]); + else + fprintf(stdout, " %02x", 0xff & data[i]); +} + +static void dump_message(struct pbc_rmessage *m, int level); + +static void +dump_value(struct pbc_rmessage *m, const char *key, int type, int idx, int level) { + int i; + for (i=0;i= data->len) { + data->len *= 2; + data->buffer = realloc(data->buffer, data->len); + } + ((uint8_t *)data->buffer)[idx] = (uint8_t)byte; +} + +static void +read_stdin(int mode, struct pbc_slice *data) { + data->len = 128; + data->buffer = malloc(data->len); + int idx = 0; + while(!feof(stdin)) { + int byte; + int r = scanf("%d" , &byte); + if (r == 0) { + break; + } + push_byte(byte, data, idx); + ++idx; + } + data->len = idx; +} + +static void +usage(const char *argv0) { + printf(" -h help.\n" + " -p protobuf file\n" + " -m \n" + " -d \n" + " -D input from stdin (DEC number)\n" + ); +} + +int +main(int argc , char * argv[]) +{ + int ch; + const char * proto = NULL; + const char * message = NULL; + const char * datafile = NULL; + int mode = 0; + while ((ch = getopt(argc, argv, "hDp:m:d:")) != -1) { + switch(ch) { + case 'h': + usage(argv[0]); + return 0; + case 'p': + proto = optarg; + break; + case 'm': + message = optarg; + break; + case 'd': + datafile = optarg; + break; + case 'D': + mode = 10; + break; + default: + usage(argv[0]); + return 1; + } + } + + if (proto == NULL || message == NULL) { + usage(argv[0]); + return 1; + } + + struct pbc_slice data; + + if (datafile == NULL) { + read_stdin(mode, &data); + } else { + read_file(datafile , &data); + } + + dump(proto , message , &data); + + return 0; +} + diff --git a/luaclib/protobuf.dll b/luaclib/protobuf.dll new file mode 100644 index 0000000000000000000000000000000000000000..92fb49832b5b2f8f45a30f6720d72929da66590b GIT binary patch literal 130048 zcmeFa4S-Zt`S?GxJHP-VJLsybVxpp=AYqtqYqk(mq^!+utYW^Rpevvt>?#>6=&;Fn zox}nI)1snpR+Lz1pkNDb?rLa@ZApDsTMfV6aaJYWax;?u=XuV#^Rn;w()Zu@*TTJX z?z!jXInUd9&U0RF=@(Y`@_jyEfNS4ApKlYt@>inwK5l-WZ`e_f4)bjs{LImt{8OJf zdRpbR3rEghFz=cLGp-wX)r{+}pI0^V%2^{9R9`>x+UrM7{@mwBUN>*%tZ@e%Fl3Z1 z`h}m}KWWW#Zw>dZ$tRyN{2M&4TsqGFjvaotJ|8rErT!i`{G0sl{?WMM_wu{uxi^RZ zL!S>C{&jsndiZL6K3RXuuf3{L%I>Kp(TLAC)j!C0Sm`krdTCmHc}EZRhkU-3G_cad z-fjnr!TzQ z$b4VxP@iw)BYD0vytr3Db8 z*CZX6;G`3rBYnOr#x0mRqiTlFcgJWFZ=m9n_+3rftiKZ2YMe>tYdwq?t)x4I-|bz} z)s4H>Bs}l{DFB=f<7ZcwbS2{!EL?CEuM~ISPzmxs-KCo~cOD79DCK}tB|=-5bdz}d z|J2_O`AZHw*zZgJEXwT;xqaqopD+35^@I*x$Zh#-Zu$2S_hLDrlVjX=f1bw+CGoi@ za(nG_+-{M_AIamu=XpDE3ZeFkxSf76kEhAoYveZNi`<4vDK9SKwnpOCN#c1@W$83- zt0eT(+qgY;2YH{9(6?VF&bx`*RCzp6-kv76$K>|rjoju*Xt`AWvvx{pkvcAtTRYkz`G$adV+FT05;y-| z;-0@%;!=d}7BDW67e`7d2bOWW?pwtD?tDUT$nEvt^SI_(Lc0fZD-fI>E{VS_Z(FBx zyGZKTB%wJ{)M9yYf*|{w68D7M?v%KTq~4zhWqv=Mx6{yL$$}~#e|QbIJwm9pbGSJI z#??1)`?iGkO0&wOfRD-J{qpz`c|7PUZnsS2_IW9Jvfw$nl-qJ?Z|x{XQh?CUYBB!0qoxb6YNNe?6DChf8B3uW^fB$L+i_ZXHW_ zJNyrXu9kEsNXdE9%7nzZl4RkN+z!2fxVX@*{yZKpFXa{$=wFipHXO_C2w}5BgkL5~ zMbAy;v4PGd`MTuYDv!gYj#uRIBf?T=N&!EW0*)%=cKAWuzE{bu^*P?AzC>udWP3>n zu=i`+ZkKFdmC9@7#m#cNTnaenliYqQY|$M_-)B{&Sl(wAT2MHiheCk9r7DO6D7$z=W$yi>B5rj2Ep@qf&Nfw(Rbv< zks=V+OXw|W{>1>P8ty;0|6t%h82Aqc{?B2c!fCs;Z5Jl%=P$T0v32ymefu__#?vNg z=vzOU?RO%}_w9?-2jh_rhySG=PBc(l7F>L~JWUDie95Wkh@TrYPupI~bK1*@ zaVCYL`wnjL<%h{y-0qH|5c0++hGyq!sq4H_+camu<+Ni`(2kbWqYOmp<`ch|#b14)GvMw>Ml|R%qK>Xxm$;FcxODwj+dInTRw+i7utB z_ju`AoJdnV(waKPrvKCFw$7H>1GRu3Yf6N+)q*h1lxP9?w0-i;2BFCKJX5fQEB93R z!->)sq`0jdtVZ2O^krc@QXi|S_tk`Lo@7pp^3AP5xj2-iCVy9knl{xO@zfoa0TJHv#$3ooO|t6v;IYPn9_F# zl`DNu75Yx#$6zE5SEt#$YOMLY<*i+fmS} zmh`!_nhW)$DTY?>y31YnlH>TAECbpvh5NS3QnIaD1CV&;2TfVT1(i8IrElsGyQGbuFn)2}gQG zHaA2XfykGLG?Jk?BP3;BSzDaQmNn&3#qwW_SjB1@ebs|ZnFl+X6WU#ApxPutU}!M^ zXlUSvGL{B{3E0Ucp`n3@)*=!$S{f`PT=m8IADVddE)TOuXd?%{ZkepZlH@7VFzNoV zAW+=u@zYRHf*J}FFrh*lhcRKg(|rf;O7{wFU_-2cNg;AMQ*4Kuo#JUPMbT`()lA=h zO&MUeuX61Xe#7ro3S_9V@vq$ckUllN|$H;~D@-DBapSWTU;D%7A<5NS&dF=2wDIW*oBbFM9BE6FSd zo4jH+I+2a>$OFQT517;=Z0frtwU@r(Rprxohqy_>mSHeBu7Z5IEKre6t{2E5SDlh6hGDkx%uk)-j;^G8*W& z(dTRR9)mt;XcVuVOo61zv!XcKrt%6~ZCV8uN7ZR z8f?~%CDPHmsmRd`rm%!oZCWu)n;o?M-|^D_5o2|)NGZB^E(kWdSF}_+i3B4Oo`Bp5 zj->xPnXoiT!Y2?Guq4eW!t{u?Yg9vqM`z!*QT{Ma(eUzP{ow#*29NWHZ{~WC>q+8H z}r_)Cq^-#`t?pIr}kSF8f7!HHd*?$FkZV{ z^^DwO$t&Xt4Q!P=`t>l?ukwI?Z5pfk^#OiFl2lSI__OesjD=?h64=I0X&58SFrE_$ z$La#f*HJ6!^h5Pk(9@~QC>dFmyVa=@_H?R*J)Np)YBMQ4ohl`uQw2mChEA0v?ql$6 zeyzMaNMFTkrS0)mi?}=uv$YbT6mucw|?+ zqDAuUGWoumlkXp3Jl*6QO_Ncf(`&l53;MH8v;L zDsqWNwWPS?6(jDbS)31|W~t{Lr4P0OqzERNl*puCYDo9OrK_bKt4;c+bJ9;BeM96< z5Q}|hl&(_|EO(Fcs#;3H;1=n2%)NAJJm>}Qj89=Srxm|S37WK0l6nx|`ajA%q9U&m z6`6irKob&{2AL6-FwB#}XypnFC>4e4O#w91DA2LUi8~og zSp_O$hyoo0hDCv{5Z!nxX*wuXbmKZnPgvr=LwJ`BuO+<0ruin}jW&EA;ng_{sKWE?2llWN8j#W zN22<+FaP0ZPVh!(nD9~e$v+9>1=P9J20vndOjlMigRX2>-y6jDYJ2xFJ~95wvs8Mm z|1#>{|B}{k-9&c8UfWkq1}|FQ9vDsgmoQwn`D~uN@u{ir!sEU68qvitf3ejF8@ksU zQU1z{YBgieHu0JwmY%9>QmM9i{)@DECNgW={O$SedEp7aj7Ro1)SmrEqiXCh@N>smJhaDZ z+I`iBR6Zb0ka5ZcZ9*`4Dg8}D#06UPt?T(Tj#mZ=#Um|gWGz>k5!Hm>D^@oO9Sj^O zUheJ;UdF#CfF%+FLK!`tyiG`y``^UGY9%<*StUR5ih2r((vy_dm$?@jGB}a?cw|#U zWWB&5{?GO5|6EU?IN}z>-XxmAM}A~|!Q;W$-)D$7IQ?|j7xQ0`CsihV;w_E|E=dGvQ_A>Wax2xuCobnk>`+^b$Na^h$ovWwKxFG+uLjf#!X$DLXU6g;wg^vA_oPZaTkVnqD#gQkwsAgaGPRhS7<842L> z<`h#+&7QMv@*fpA^#B>h@llw2LrdDEk(Q!Yr^7sEOo)l&3zEpQX$lEL?-lo)>JNXL zYdzP`xqSKleExh~dGh1WlL-F@PIjfo3ZOE&8WG++6A-)8)nJV`YK5W>zI#+BU44b8 zj&A>hU?rHmxLaL)Gom8`oTaN#vb-XKY5*0GRO^{7N86O?5t^fTroChDG`AP0ZAs`Jh zAUJ>x5YYRKuD(fmg}%-;0=MW4)zl<&e+%VRQ$v8Xrr!L#kv!46OG)eL>1PSokxO)Q zBVljMu$8b7SkiAGoTI0&tiJl{Sqm=D%rX7nSJ`l5m}Z2_d1(J<;HnfWNX4cfqWT| zSMYM^o}ur=AFd=mzI85loEbV?H^pCLL4E~1q)GCY;H(}e@pRH#C$R*rlNcl(XtVt! zJKIYN3Krc|(mLioC4j)|bDpX2Z(4RJbyK>wA9~qJ1Uhd{ZdkJ-&8d}GrtMX2-DUtI zk>47k7bqZDfSRl%APgjEd%#p9#o3f&ZOTZYF?((F!6w?Mle)7}5f4%GbTj`foKOF~ z8U`@^x9EjN614%8gnjUGy$%19_+>Wy4q-vL=$8({H~K2Cwf|SVdX_(Y7gvyLDDMi3 z{o(t$nz>FT?i_w^BmO_Wg&jLo|BQzUYM(TT{+S9&bM%kIItjU}e^vuq<&OS&g{;mh zc|iZHE>Zn6pC9~VGJVpn(^dm^_A5;;^(1y+^EEcpxY9 zGNsgMb1-1i&8c@v>)g|Jc52QvQ$|wOzmS+YARnR~*^tg?WInPXBk)JtEGtcxcx0W! zf06Erb&eJ7BRYYWnoWW6$m+CApVee!Ibp#2oAhG}RoRQenIsWj4pY(^H;P(xFhjV?E>z7>1i94O&i{OWUS6Nf} z5SNt7$Ej$X?DZ$suk!Xm)>fAuHtJRjJJfrNm$z52xP8RI!akfVf|U3gmUWsXlA5kB;ig4ILq5--Bten!JIv4Qussgh~ldq zy|DRHAi(Mqi?4Zck77Y9zGbi>Vb!_SgfY?DSY zAU4G-wmAGR-Q?acg~%MNr)M5B0+KbNjDCt9=_rt8dnAD!at$P*kc%hZbdn$q+8@m% zOiz>DPRfisH>JGy=c?0C4CNfJuces@0M z8{a!B6mR|F_pgV$;Nv5|>V%K;HKH4S|C}}xZV`U>`jJSp;i|(yr9CG-9L{5o89%#^Mnhs`{yH!oM)kG&$*y#3HdFmZ2x>U#1K>oo;pb4 z;VE$52hcyaP^j|rDB%|ta(CkAK|?Hl+(e`u9psj|rzt-(ijZe?(wRm)vpg<08TQFq zT)G2T-F4v6HchI93ml4)ris_s*G!srppbEHE8+cBN=om(+H?BgF73Hm`JeX4iW=EJ zf=}~4ZDS~lI4h>of|nVe=eFP}GH3DeYEpS^SVwq&+Mw|FWq-eFfVB(3-B(Wl?;rrnfz}JRvl7V?@`jP2nr@0@}cd~`JNr_lr}nr z{&Ibs)97<58lAupFk?-bYZQ=h>hqQbPBx4Zk8EL?`h=(Ak@fLX90mA5H!!mKAKpfJ z%H%)6=0B*i&4Z;{8=JLtV009@JQoP9TnYlwET=$_EV&#{s#bJMfF_(xSp4qYGSLSZ zsq_?MTj?1V{dzV}x%R^MfvA&wjr&C>dS0dx(*M}r7y{|aYUv4B;Uz=ctTE$X6h$5{ zT5JDkP`MwxC}`-He)uzs7CXUz{o@||X?y3hhJ(@;9KA-qVbY9+W(9u{N&5$Azu@~! zSNNXY+6BI$3bJ6>SeU?fl>xa6e7nHze!%B?^e=)`o6qV>f2{LP_#2mo&x*~b4E9M@xbFT+)K;Z3aKfaB4b%OVnEgn9*DwQj} zcZ}%7F_X1t<-Zl@VmiqVl`6LQHAgF#ikyp4kuVuETZF>Xkn<~P>2%{x7eHy|XTeRD zoEMSGlk-u8-;bOtJ_4RT-isF9Jh2P?{!C0Kd|dyShYw4?n9?T*{qT+sSj%>Xs|!9F zX}NJ^4mm3W-W2oQT0l5;7Re(m?iR9l+Eeftt=9SKI&iup<1YG}V$I_OfgKbb52E|W zu^uOM|Eu`u(LTXF3oKA>iYH4QvH_%;v1=$=Io+e{!;dO*Ft*eeA;kfrV5m@)GzOw-LU}5!#jF9UcMTMZ9GNT+sj_ zXGj*fk|IwDLAh;aj)4Jn7XkaBNBH8p>~ZsTjHijTnVAzX2Hv3LcVf|n?k5a zvp%gXVIpgmM5Vzc1RyH&2x>cWsU0Qe}P^l^mE&* zm=$?DAKtg`)_M^fWHGrZr+-;QdXbjVyj@0k!K`aObUQLzrvEp?s!!^mklM2%8=J@T zWc3N^7Dtwy2>&fugIso>z(A!1{?h6z?E6+wOs|Q{g#iVGxo)E>L7V<~liofRnJ1R| zM`ypIw4G~G+Zy+33HO>BRgDUakZv4geLrec+bdS7wpX-Fw!e?s+&2|rEK}%6 z9SHl&Ds%V6bR3qC6f!&xqm#RXtvp&ve2Tc%NSqpzI#Hs66c#US)38o;VHrV zQWi}F^*EQdY=WSL;gR*r_yz!{I1;QG!Y^ym!Tjs9L+-T?DOkFTMKH@kG!uj8 zMRvWn3HoI}SX)C0{yQn9%?UOj{Tj>$b#T8xRdg!6brjL9{*ToJeO1SPd&6Jz!ZFwX zUHO#*Re~H$lR0MP8-SUuq8*<5MwBIH@AaFS>vC((Y~???Q_aKsuDSR6oOZ1-TDb#5 zW#7TAdT4+gHuUoixo!MD&;4p+U-cn!s%NuLHafRcWoPwLnU>$n_)W%7BB_f4zUuKB zfTAZzpe_VM6;BLS9mW$UC6u`rQ4fN_qvbHAsvXTe{9wOY+)sF@kAa&L*y&8&8F*CK zdCqe_r#c)D91@>;NPvoa!0vvPp9t*ixg^7Y{VY!wLaE#~lpwzvG6;-M4E9>Z{+5r1 zRw1|a>8p6-&nrR+sQk*fZS$vrFKxeh^gqK_Jv>cyN==ScqoN~r#=wHxMrOjbadLCK zgQykZ3-r4G%+j_c=&Cl+Rc)!HvJ1+-RXmne>?dp6)+&qCTg%*4KNb#Rfu{h%40lD_ zwwLqE-LI@Ss!gLEz2lLdE&M2q$3on4_p6$QwQ_Vg&2%r;F|B&LkrPfBnNNr`7DpOy zsrCTa606zbtD0;|QKxfbBJ@jPrkyWQ=$3MKfPqIe=R`WJMg!;uaSJ$;Q1eHcN>j)1 zE<3AvJLMMB z5~uvu1PYWN#$%^$K9wiS4`#YAMEfx>hnmL6YQnxMkc0iC-Fv%P>H5Gm45Au-kao>U znY8IAKQe6+{@6g0c4`oeZy|i+j0Js;n|g;&?C%I23=YH&11oB2ELFl(2CR}wz#88L ztV1nWI_EfrG#*^j2=@mr5Ba^rC%!vYLk^F$r=k1G53`_a73jYDKxd?Vku<^xtlJR0 zxmobFf1vPzKV?!Du3~woVSE*Qr7^hdT3~$r`<-F@Eorh~ypvQO4p$TIFAjUhUk?8{ z3RUQZh~>BuvjME43t(qkz?^-8yHOczHUW4$A^1J6V6anGZ1%GII`S9QI$G>HAj@n?>Kb zr1J2%h;V=Bv=zP{=VQg1aSwq1bvt&qr~kFF7q4b)LXX{%8AbML+y-cj+1RXeK6%oDF%P6LouPECJb(k z8$nbrF!zT(nezJy?^Nih^xn9a{_-~f(8ZrF3+yo%zPC;_DV@}&ktEaU@%DzvLzE|S zqhMdk$)rkfy6HY!w@8)fSL zb5`y-jRS1m%+z=l*{F~Z--07irtZxU#Y5Sg#(_3BOFq1$HYzkSH_GImlT-H~n>&r& zIgK_dG&+-8qD=1B{-JfxMw>&t?|(<0FsWS&B#R^5uGE*PPSkfzaW7^yMX68H&eWHv zPSke|8hu$!5n5~J9O`S{DPBV~jmi4UtcsP?r0h(6i3%TB*PncR}fK>o}-*}MZ?HFwYh zQ>m}HmuGTIDwF%JEXWx;Sd5EOv8b?7p++yaNo8W6t#X%R;vy{+#U~ZG;YRoJ;DIZ5Fa4(GNYpNpg4{R1rAafUx_ zibO(cR9jz`^|=qxZ2b53t$It}yidyTGPo-`73r3_Cn%UGKMFWg!;E*_sC%*(ZZX~S z?uB&EtM9knvzc?bl+tgl7v;*pp_;O-{UO?}jr0PZsJ(kj&+=V; z?c5LT6v|GW{(m0R7|{N;9ztk;csAD5=2Lje_!Ahg$90Rlvr68^UiHUKV5>YHaMM{% ztpqqfVZ@DkenOZZv?q+u=xO3;Mo%T-)JPerOd07!NAW5?B^-|yij6F(oU#$|XxLgo zD}GlEUvcf_;tNLl=a>6?JnBH(Cx=LA`-0NGbF$l4BrXE?g>R^AF$(SOFltQLqM8b0 z!WQQ1y13A-+eHVIyN}!_IYZ`{vdl|SFXiqU^HLnQ_@paZ;)UD1@Q(PjZGqIiPNWDG z(Sgu%29|U=_pFifKp>9m&6+)61a8VrAm)U7)Aq2m2{9W+8WA&*u_#GeXrZXPd4zY^ za3$e|RST}Y{uuaF;fGMCN>bhANZUsK^Imu7XN#QzHxY%s? z(Xqm<+k=Y8sOARCvQ);tk#fu3)65$Ve&da-pKAh-b`gtDZLdNWE#=F(aILA829+xp zfy$QEX;j)JHcxwb2*nl!hgN??7(-@g%CHXa0ARE^GQ=VA$@LUM(@8e0p!Qq(V3P*Q-OIC+sw{?? zv5_f}s!MbxT`k+Tg2w|x*b(ztDW^^*6&2Ucq$2efAM?CCtIA6~DCd!wz4)w@)uUBeHye*E<)EZ^WSO2=xI&9Cr*XKm-!W8;jEp9{ z13C(osohtU0O90x*u+fOa$Lf`Rhr(g_M$Jr+WvcTy5%QVYPSpy&=)UKgkW0C$fYFS zZTWgVVf=&p#uNWvgclJWNq8OMtLd9(&7JAH-2A*Ba`c(EFMSdoupFqO?rKGaOk>*h ziaqL+D>C{d9NRvn+|4&^oKYqaR0=J3lORqV6EYWG2SH_TqU=6Y<~0iXM;I=#`VkqW za+krpyBN&h4yvb{rHxjpTu+gne%?b8Pp1s6$>@|IVfM;=ASy-iCri+j-$z5m?C)`8 z){EhDHFF#|uZGl&L6B)?uq?rzRrhULp=glPNMY@^GPmSw%4Dg7QwNb#qSc-}(L@^z zw9^c?mKeo=F$vH8s_>q`1Mgi4rwT6MMBiQ#w*j4a1cJA42KlV(=D(M&N!u&SNVUBI zX>ZngSGrX6Shw9ey038I>EaA$Quw2DB5k33Rjr29?ndo9@J_da8jg|D3HI<934~LR zYPMl&zjVZ>gp&6I0L!{d_?Z)F#wT{CB1R4<;(H~M`j%Pr{Kb*x#mBKkHl{~MX-d`Q z_{4S?DK;5W&vb!jlm}0v!qe!%LjYr;O;uJ~YE|VPKuGrylsiTNF{W0V&f=R{c|jQ@ z`8BUU9K~xTUFoxf%9K8*3VkNt5L*x~2 z(XI7TCJh+2pAArW_>7r>M^-y-j&uW$^r;Mj@aTq_o)ZUe)j%aW(_h|fsfH9Fj&Hh} zBBdR|ZQjvjnjfSy%4?;L>@&*fKnoXMWVx?QR!z?-Z4DXQQY=AOXaVDGEJ3@px*Cr} z>)X4M?@|tvS7U@J*~HOo!hkuZF^349apv9ST`sW+f&<;bKwokzHMk1Q~6wlSiR|`t;)WwN`0Xq)DPeN zA+vA)`YYMvr~KXd`~WnB;cww1!%u}~x;MS1!((b8hwxY-xPzY-VT9T)4Q`0nO36+_ z?z%`#16$=j{HCj%RTAJllTEdHp2-9J81q1s84IGHSCb-?JeERvu_pHNp#1III`C%5 zJSo)(i^!y?yvmnXxcBU5t9NsE{MZv-wu>d>fObJ5&d%t3MEAyp=5L3ot zPa#B*4t{GZDX4vm;&i^R(Qbp06evV2E_hkyf{UjF3lh>diGCz&L%>hXzKoUHSnx<- z$YzP#_LA&YDtII`WZO%@q1zsnxScPvpQ+%H!r|Lq4iDX~$>!{&r8cf;==M3Klv~jn zpFAX>g{tpLUi)nwd_YGE9i#^k(kZs+TD*KYj{puU)Bt1K&=`q9L)OP@Wl?@?tK0_^++HXpB;ny7_E=N{v9I`6X7zK$Khr#6QNP(i} z;50SMmwR+cosff<7ZeE@0-l&o2m$jWEoVkT3o6nwsuvXl@|07i%3X;r{OS9CQ5}Ulw!S4qbjmW5qU9f5>`Ld-nR1ggrk~ zJ>dmDwcc0Ex!oUrhU?4AiIaG)fn5Iqy`; z1OM&6! zQP!c_(PWC3?zYYgXszB_fx=lOclFk4V5{7R7u8MkHa1?pC0Urr#L`fCJzd6+AJ$~C&lCiU6W1tm2^T*&O=&nQF%U!D*6lL&nQt*u{zE^kVw&( z2m$Peb!x4zvtGz`$zNe;n5}IY$baiWUX%vtpGytowKC94m85}RCEiRH1>Kel|FhZ2 z9nF+(#YJiy?TI4`+T5^HR^&`#1$~Vo0Y>OIC7z{PX{1(Q+iAl^-WkLkVl3`ZwdPG+ z@_96VgC1y_Y4fvQn@6SFJlJbQ3Hc?~EnOnb45X%J+CSE`U+I;h-?N&KrL~gPoMxJ7 zKecOV`)<+F`b*K5s6!hoWqOS@VH!J?NFl8TlB2a+iA%mp!_25isQ;L;Pvl7FGOS;^RXDLc@Tf9O8?iR@_mc?&(u zCtZXWxh6ZMzLj!i4X_*hqSPKpeKDOW_x;;+SMr`MfNbE5y)-EH_q-}qrtGCCl!?qK z?B}3OgbST$a7-EBjO<9AG@-8gc;^76$+l1N6?QWcY3ei*`35#+mmWus+~Np+`*qE< z^*oQX6YTeaL*U(=1?Z|$Z><-uL6J_C;!vdK`@n@HYKL~BM^BRsghh{zC7iA2Zn_5| zay`k_&h-M<;II3`mvMcI@JIMPhbzG)`Yt~(Ab;SHfdlgg4G07W|NDxq%3CuCQF)V| zV)Ms&O3$YlddCy;Cbm`XxPs)wXlIo?u#36*US)rVK9&WPU!8W@#T{lG)Ly3NuWozU z=iDaaOa1an)_~|fD42YnI+f>oFJ#X4LC$h1q--{;>_X*fzPL~d`Km3X2Y&1V(wyys zz0wBfls1^sQlCk~Vn-5PedNY8y9&}_*ZWCp z`+czLt0$GmuT6w+@(HHxbsoR}8(gRSG8ubW`DM#L;g`DsyNiFqb91>j zs_qaITEDr4w}B<_p=NY|_yZ=Y#XM(?qZ2Zx#s^_<5*5V6g&a2$+bVb8 z5}avLm`h=aT1kg0({usHq;vhrKY~^BGOh=ih?ZvsS|h0&YPU!+{H6H7h=kRMlYnE= zCM2vA2umquj;7($hRu?qjO~YcOnSs?H)saAGkj`y%2*#WS;4>nT}NzetK5CnS30#) zZFG(n8*)}jIXda3MUYtzoGC1Kuh}b&<;$R}HMiV-RY!SEJPsa08ykq<-o?h+ zDYN2^sc=y!zq%#|-292)?oJAF%sruDRn_HQlmLe&=X(kQFUr>p2i?loEI3Pvj%}5@ zuV#b?&OOzg!AV`8`drUVm9jHU4RvVQ_=nO3M!FVwWbzVnc{Psm5-1%??9Q%H-$cGH zSeRpBAF)6zY++X!k1rFwdlR97x>?h!QSdr`D~(rDxc%g z(AoRM+ro^ly6!*HsWz#T0B37BKturCIRAe?uK1Oy9`pM+(K)ZVzAGtY4I_qH2aE zTz8AKnB#3L4%Wy_8TeugaqR57eO0VTVlo)lU7IeNHLsM~)oo7bq4?A$)}^!Df_dYP z)I+J#u1hSWywX-WgPQSkBCUj3X)G~LbQhL8oy*k-Z{tL-|855XoVWS*Cx5Md_Uce5rG7EFYi z%G|5H7qSABguAcTgvym|QTGaELJ(*cQwaIsizldczxhJjSLe~cMC4^WPgY*^Jc*Np zt?8!Rq-mBuvSQ#5>Bp%1tO@JPvy=unr}hh+-toIhh7mf09^_0@#b;<|>zR=@nQ3kF z)f{Y5SLUunNrB3woUQ}2ipt8-G92I$s=354W$f&2*;y~LS${_!%e95uiYwY~@p!m! zTf748U~0Z4Q>SdhmpWzjSn6xD=?#^>(7jb8SxyFkqOEq-6SRfhWi5pq4w4Af%CM-+ zJ;vmb1r3v+X!->#Q_-qU(MRSe*L0^lwNFz}&LPwCa;`cu&d`Z0vXC;{ym zj$!KCx41}jf^43y(M6Tg4PdR`ovL6;yi8CX34!Vxf_N$BL^?p4>0_nKb%MpEA=s5r zNgy>!P`Joe!fB*!s8{;KIXgvZ=0~AbTk7fequzVhcT~cGlZMN(by+3M)jis^JW&M7 z-!e?vJOvKR*c%KNumoatg@(hU?kU$=hNty>7S;3&&t0S3D-D*Fi)%jUvNN*gnKPl3)`s?(#HNa97G#f%NOHZkrVl4otDSfpx%3g3q@n` z*a*AJ*PdEU0kOq?!{1hzQm>?6nX=b0t>kcwbXh1Kg;bJ^M^-6nyw+t4Cs}sYJW5^3 z!Cyl5>D;_y{Bl0V9iB?0af|NUSuJr zEE-aKvG!^qtk{bMG7=^dEx_5Z8Pm`DEfAp`d@F3yJsAmy6 z_V>sjvW*O~R+f&Ro_>#VCmjpYvD<{RrQ_WFfJ*D{aXivpA7{r09|!ZDOllN#CJK+{ zZlh%-T2vIO)?r)9jJSuKDCF`l+h}Fv3WL?;wy0yMu##>M? z=!A>Q0tH`wMs=1q;$q#4^!SFP+D)Pl+eAN&@U)=*vfdVv>0!m{E}YuPHHWybqytG2Jl{w{6bF*60$AH*8>Y;#X;d-aqs6iN4d z&gI%@dOk#`m1W6d+!=3&tdxWia{4>t>`47gn`*nezd-f(NmgxdohJ{S$G6(br&v=% zD^)Qf+U4#UBxjhOtqZT|FCOWOQRu6VkMZA}l zu)|22G;8|W)O8iEmK~lntW8{3?_BB;#0*q|$ros-cHt2|gExTCKveQYX$#mSD-qgW}qjllwpxlfF968x0`-u(i z>34jGMrrcO+frOOwMjoefJSeNx<6Dn<*Y~!_NEf_c9^L5Dd3$b(Wm@zTJ9GNTIgjW z9qLo+*yavUS0q>`rdjv2jFG*9VkXf11?;WC+8=-2Ui^kDH#Y1t-^~Ufsj|okUk1|SwPS%d0t+B^#lWR zKIU0zDE7rrppQbtt7ZxrR(+nyJE&^B$vcQ6Q8Ait4h5^E%b|gOuh_iaiaMdARaEN%mOzZ*G5>#0V%3ec>t$nKMT<`tJs!w{s z!BwYv!68-nBy0gf1#xHIF?=~@s+}R=tu1psaqNrCdV@Df&%x~dT-W~Mxp(=?-rd1b z3$c#l%rg5JOrh_#wc^jAC585s6~iepcXC`MGNy;FeDtQzJ9;Eb!6SEXc}&(cty;;? zCaf)As(2ITh%a@j7MD6%Ki`)+eiNe%U+O6Jho_1*vC`j{8oo&u8K#D8V#$+Fmp)oT zUqNBzTrsX|xT?7>;yRD(dalJ>cW~KnWDoB4PgdLv9yoYV=4G(IINYCf{lNEr<21Zg zaq4dIaC(-(+XRE*vF7PGgW-=D3?FKq!sgxJO(lX;){nOH(Lv$$5N&KuBhYmmC!1L6y0uyt$V z+J2w(mnG!Owy#3*gjhz-D!Ji=^2fE5_^N)dl1H-}+nq7!8LLJ%rm+>#s zYOT(R78MT{;CiV>j(i|>!Oy1@!5{@c&ns^1Bgfq~$0H`kBYo$%+~kNYD)Lp0gDtef z@%K@UtPf3%F{x{x>Lc+#L7WhGQE+fU?QitKbd>6LIz1ySn8ZZ|kB8{F`Y6#%CdpvS z9E`_mD$I{Q2`{JTS{50yi~3U#HidnbrP zGbMka9Ke!C$8ibou=CI{wrM`$M2TA3;vqj)Se4U-9TMYr@DQ@ zKFq2}2Q*zW#h6tWUf|xxm zuA8~0Ht@`KD(Un2eVywf!gIK4xW2<>_iPQ2JzE3*AKJ5}`osm(s!xhUpPa>0+CC3Q z-Na|Lb3>@rSt!fW-yli4@3lh)uQU6h5;nIpGwLU;+D&gQl{u^AuD!Jew#pq@zKseT z{d^@o_WWOIk9`F{hQ~r>s5qGkkkgtv_aPUgrleEB<)jjKOy^YNj;4R1XsFG`4^qr(tCe^{*1cM04>Ie zx}2oNZ3Pd?6f-M$X|edDbkd6!cZiuQx^D~~r3#W&go>Z8(WS3bdswj5R)dhYQYc%e z8yPZEAamB?ay{T%yZQ6}F0tWM16_N;gOL!Yz$q%NbpPbj29@vCa@F?tW_HACcKD2Pz5)Jdh-`%Z{M5;hIHBv* z>s3dfII_EjnV~vLU?1MrNd^^(ialAVDCtmC#3K*HY96rV9;Us(#{9?w@yN#1k2%b; zII^qyFafu84^y`l?Qt==NU$UM8nq@OD>>D&A+lV2ONq!b>f2c6o@OC7=V0o+II^Sq zV`eusroc*>>&5VMzcg83fU~U8@Xcs^sf+8%;jIk)C#Az5!Vl4+q9HQLt^UMjH#T?OFPT1Q^wR z!JKE0@0ae9GT4Wuf{xObc??%frX7soWvo-r>q3&$nFAgT!{oN^p@_*z^$m zQAT1zhD|wG@lDI4&9RzhUkzHJImMbmR5z#LwWWSWP{r5IqPziF_RGoMyS~bt{{$ys z$qcC}PAIU97mhPBrM4!_+s=m<4R>OSw8P?ZII*($YIs9TlS+(^xNBK0OH3_@m zYX@ytGeQyGC%zhg1HOI=g0k>+6H|j}KD�()em3wTG`3!v9))b(Y7Qw5gs*^&*c! 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 literal 0 HcmV?d00001 From 206d1a37b6b08426c2a8664be649a591a1a8e912 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 29 Apr 2016 01:55:42 +0800 Subject: [PATCH 084/173] a little thing --- luaclib/cjson.dll | Bin 56832 -> 0 bytes luaclib/lfs.dll | Bin 44032 -> 0 bytes luaclib/lpeg.dll | Bin 81408 -> 0 bytes luaclib/mime.dll | Bin 43520 -> 0 bytes luaclib/protobuf.dll | Bin 130048 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 luaclib/cjson.dll delete mode 100644 luaclib/lfs.dll delete mode 100644 luaclib/lpeg.dll delete mode 100644 luaclib/mime.dll delete mode 100644 luaclib/protobuf.dll diff --git a/luaclib/cjson.dll b/luaclib/cjson.dll deleted file mode 100644 index 99d69ad928d5b5d1a0ce0e31122916f7d7250d8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56832 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 R>?n&OgP%bS{L?k?{{cE4|2qHx diff --git a/luaclib/lpeg.dll b/luaclib/lpeg.dll deleted file mode 100644 index 127fc58c2232775e6de0f08761d98d9e1eea1214..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81408 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 TlqY3JAK%6`Fs^}d4Uqo@QAJ7J diff --git a/luaclib/mime.dll b/luaclib/mime.dll deleted file mode 100644 index a9050677565811d9e8f31e53dbea76e420386700..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43520 zcmeHw3w)E+`Tv_X#ZXcbv~|@X1Z@Q;VA`bDG^IepZLNmhKm|)^Q_|Aga^bR{#nv?1 z@Dj(IZf?_kKsKkF+t42(I?+}-ii-Y$IR{#2-PlZ*ZmZh4>ZzGxoA)$&4rQ?6fzs^n+6#ozcePr8Ayl&nEWV zd%aDHH?U_(ZIzAM7~3PWNf3%;7YJV}zI;_EuTO}XHASWrgnFbb;;G5g&{;LYS2RafaJ~2W8FT~2g<7L@n=Y29^4RUuqA`{F++$j_Cq;eDue~!t7n~|=$ zO(tZA6VD9nx>FWCW_xAAF4TXv&wQtKi*vohAqbqs@#uC5LLZ|;=0zLfsX%rvR{;&&h=5$;coEAwywj1QCJ-kjDI4PFPKJ=!+1K z=bdm7p8~4S?yy%OjmfSPbTlCMMi3!b!04>?O(2|4`H-og!1I2%h)+Ryv?CJ#KMx+I zPygX1g3upW0dLJBc;C^&n{*?*hWYSX$tzt6?_x^p2VVQzDeV?2_7n1YZh$vH-j|5v z6{_Gkd2=cHo$KJ;c{w~6k=#n&1(cCb8Na0H%T&vC)W#BuexJPNYv8GfS~o1cRj&t9%Df|1KDOVky+=0iu2Pr@NbX$<(@Ec}*idrXkXv zbu!VUF#ErW0`6{w{}w#GCcn=#WUdqHV#H#_O26(y%2Rtyy`rf%)->cb9di#T-chOJ zG`Gvt@2IB9Q|e+_E%R6{YJU!^rQ6-oE4WsOCcnYd-Exs_^=&dWBP-&K1(YmiVKMnT zs;`*3S-q%_WqgZeC=bMd&3-vn1)t~PH-bSkW9pCpWDJ8NgXx&ceE>8FZ&!5qsLQRa z44k2?fmBB~x*Vu;xA=uyE)`7_i=w+nqVw!S^9Ije`1Waa zGM|swS?M?N?ud6&H1=*H;;h7rEaHAv=9N7etBpqS=>Jc(F|F-wL)?-%xqejbibL?nVC}-VX-bx@q_g1O97JMEv90Lt>Dm zR|N7Qv_z)CMudq`wMG!C5nk`Asj=DxNA1_GpF718#&a?Hc1}F|(L15X)JqSa$xi^5 zF|63x_yNGjMANZYliv%VwHy;%mou2XiMrk0au)s#4|B*BjDeh;Whzhy@a)LOli>Ci z;3k$Iqd_h|7Dj0AN?-XndPKu;ZAB4+t8Y2m?~H(+@Jf51d6%H9gx%Q) zhp?+bSi){C1Fyx|)bKe&a2UV7_x=_9J_=DW^o)z&SuB_1H;IQiey<#Z-$%g&bo{3o z`dC%O(DSLq@%yDPYYe}p5K3=lZOOwZ{W*(Ap|qBhFqE$4;m-o4tEWb=Dxq}f?`NX4 zkaNVEoLQNrgO zEExX3yer}JB-slqKE__?F)=k8rC%>(;*HX;b$q3j?1Hx;CL|iQGJrdqfq@VPQp-qI}dYIyT_S+=Hq*RZ36Hf%KVR{%KK^j<6X;`RACHIk%OT0L>*H@iupxWG!^0fc zWA*XnEc27;V-Cr%J@LPxrFdwJJ#jm$Gi*s#cRuz$~O8U4u)Kmm&_p!7{t6|P8pzyB0MWObizeece6(|zc$6BJ6FuM-n5N2;g zIHZru5dJ)4HjK};=;k@?-N^mhaTK8a+cS8M-M={?LT-Fw-|?~gw+2=Vb{4FbvHQ0* zq5azq-k7w1+s$I*?B9OPGNk?6En|$4R9*)-V*588viYVdYX3Gpw11n*14idn{X3zE z`u`4ZoSoWV2bdW8UqLpubFty=9Pu8qO`hXK;#szHn*IvXB3OOnOUTITH228n?jZZ*req{(#gkI$JjI;iaLEzMl{C_<<2Vsp?~&ALCA_| z*ie21brFOJKSzjI!p~a>hw#&faFlKQNe1j+qzRArhv4YE^y}BqJq-J)gYUqmR6XvY zM}nXf1g~cR!BamY{|$EPbn0i6DKb6gEsj1)^RsHg_+UqAbV!!Y26h$84Gp?FYS3?E zd6F{y9^~rt9DpUpE##Bv4zrL+nL6|m6y7B^%EM5Q$o(r-Pv1>hCH}Rr^O=F`4*-rV z-~Sw|3Rbz_>lp+UR0?~FK8khq&wNLus%pPUq1xZ^ z;2ucn{eo>U@zniIY=u+Cn$+8i6&(t(T+QaF+TEg-t31~tS30^nfS|DPh#;0LRr}@f zQa#>cQYl@1lb~A|MOU977K0*DrrLiiwKT=l%k@qK(eb`>(`-Bv8{O2D;$GfbDz2P` zCy1TnZ*~+W3=spvP<_P7XkOQwLR4mm|Lx_y9c2kaEE?v+{ejV??C~T*bX0F3Q=$&B z;2viABwA7)f%qN|g=zC4`Y7b}QCabB^1bDL;8Z$zN-Xg|^hcToN?m6lE`S4RHP=?n zR|AN}$ck9-9zRV$q>;qtC-zSqh$3TY3&;tF)MPut)z&K9idTOwPL>${=zNpmF9lpa zk%ib9_!CXz;w)C>c?;yy!W9}PY4F*(D9N*{4@2x{xuY11E%$S2N92YFHJs`0TfpG5 z@p$a^)^)eZ)E$LMK#jl457<)OA%f#?Zr{oB0g&?FjOa}%L=hL zai#yEKd|xdF{#l@n1>+%%mV<5kQV`f{l6ywkSGCw7@&deBM6dPKuzOMXXWh()9C-F z2A_>@9~x%ktD*7DM(m97mF{j1oBYPZrhd3T!v%~OcCUv@xet;rb57-f80UumSoCdF ze$Yl%=FPvSn7U~x*t+k<9Z09#H{PzO`MVh87*sp zSI;2Bt6_jbR-$Z5`H;7q8t>|hiRK~#8>3A8%Ut^2lyn1E3hmbb6WK_Mz{LH1go!@% z0GRkI^1_(dLDUi^?m_rJiHXRyh~eWX7-aa+6Fzi^N%-h74I?51CX1$FcD*#*)-p^g z{FW&&FJeu@hlOC^4`))jTZRi-l28as4b3VX;%_$%cgW)de5KiV#E7KB@_2#nnqbyN zvh=ZG#&0(`VEocu*Auwr4)Kc#3IK^_g<+-KK9%fiwb?(6K_F8G87mb;0bUdx@@YH) zOD591X5=Wm9;(oNko!!{EJ$v8a==oUboPQ>hXD6Cq@+?3X zp3ovDjla7^k>H#JKi;(v-C<#6ylVzzWiTmSYLYM0lSf`>GR8W&Du8j9QXl21pbiuS z@HzQ5R6;Uy)t zt(P!MS78mT2Ws2tP{JR0mu!QfgcCfW?n6euNXmZje$?{dZp`tknMJIykv-+VV}yDu zXCPvOD|P7CDE8?(#QJj#VqxQ_rSa1vCXL^CtM;fuRc@EZcX+5w>p}7pRPD5w^N7(I z*PjU83u7|YLDQyR4C(vPHQfC{g6mRNVR+?se-Q7wK-by7_Dt&Sw~|;oOp53dWNaec zOWMMua1X0)0pf;L+Y;%hU&-+`tCs|)3@jcOL>F_ZtM(Twy55w>77vT%iI_>`U)Z6H zp)$)9?k*V;yeojEeiA!67Q;LCC<%;~naGaCyDr4b3ZeFQzsA}}QBR0?)Sh+^Pj=3U z5G$>O?%|o+ZagFHmX@XCcA%VfPa#=4urr8Z@&(bQ+@5%GMP~PiV`CpRD>BBd^#v>+Y@;o)vh8Gum49Gt1Hel%Sd7$~$!34*tBh!r#bkz;%mh#}6F@1#Fq{VaP#H3YlrV1AAJOL+?X@B01=Eq$McPXRHYU& zCfi?%rtzpuil*~uj1<-JXsAIwk8%@g!15se`HOn7@YktC?TMd^7Wln7@qqh0HHtejf9)nXhNQmicp;KLmIcP!o zm8IgV-r|vpRVZGpdoM?~ZK*C8nB@CDCWIh<6$jNLVq#9)%`qd?r0YVlFh?HytXMwM zmdBWIs)NoPC?vVr|J~zEbuDrCC=I%s4~Z^?E+`%bYwN@U`BG1(YZ&3OwtQC6m)o`_ z@*3N=C9}Zfwr$fX;GBxuR#o7oz7tfRQe2{JyIISc4`O9?on;$ z^@)%N6UD++=)rl(;O=8lGB^h^U9v-H(mf!UOR!@>x9bG6-^j&?qBpD_18YM9yMRl;Ac_e+c|J z=doTZ+^2_MpPurLYOXxxxkI76Y3>2}sl1fcHSWG!YTU!OIDgHEHSW`cr#erSr6j*` zbBg+n`V_T@uvnO)_H;V)e%J3gv316&=_#TzrR{AXx3#Sc#_uieV*=Tq&2Q zpXBMU3V}o-_{XzE?K*I3O-eGk=c4;PZfC|xB>dR+pn2OeT;SBj*jf<|CY{`idkVS^ z9Kmcd2b0W*?^y>)hzaC-6U^}4EhB=9E9byhFu!`}Bt`Hadnp*S%~4~!eDp4NmfthkZY#fSV-8}rrJ$U7@<8KB+k9jn%A~SvGq5pW-q@T{wbMm(Ye*fzhD6I$1F3 zE;dSXF@g2JOXg*P{@vh+B&70u2caI*Alec9@1kkZEcceb++!kx5qCu|KN;?Pyw^17 zZW*M`n+6T0m#OndqdOntRH5@a&QgCKGC3Gl29t`w2=@OlQv_A}WXee*fRu!C@YMp^ z>0)C%OsD?EBi`b^C#iPN303>g@a!=SP=1f;G(CVhw;w0bBcL=C58E#RxZJq{+6OcV zib&6qxiBoqFq98FVgegU>np;n;Er9QEFba41j~=@CfGuBoYMi30XR&4S}gY)$_HFn z75WUO(@t#J25?b}RB!pPXgcjR;nu7Vi%$O%%sO;42wq^E4x@)Jvq4aV8r(x2-%TEy zFMOn_Q|^|dG}6y8ncvRM6ikI@m19=82=M_QQ1E}B4wlNMk?;gqWn5&6kL6KkxQaLl)f#Kj=Dk&@Og}0 z&^)H*sRNA5SXV(*6C;o(ERYMNE-@ZwgsK_8ACiaya{*s*8Z0S-?Ew1QSK>bop0G3aK7xCaB;9e{qto9}l@%87h3;tbD<#-t$ipXsQ%ZW0cPJ1%M{zz|^e(zbg*6m-wEWmBT+t}d~Q z%ZW(_rev<>kKrPLHBT8vSb!Vy%>tl9e~`g#X%Uxmj{yy zNTCj|QhELc+*MRW{9Rl&zdB>p%?HRq-q zEBQCIa=IZW+=$rx=-VjS?^u&+>HA!j{tG3t=rQNQ`R9p+D0H=d!s?`9i;~oS`{XU?}-8m1|nNdI`s@vO;j9V>*?}sS}2|KrUJPZzf z1+tDEasNa`?a#Reu#b6nd+g%&PS^XsgCj`1`ghlDUn*OQgkkZ8Cy$^&SAWdAKN4SX zzZv`P55;%3$1I8MbL!_Ab>&TgxC0#+RdZcT@G;^&_!xD@A49BmlPRNn z@kW0(%=z;&jL#xU$PfA+wJK?Q)}qk8clB?*h(lo%kGO}`_P7JkD}rIrk-B|)u4?}w zv+V$wgC#^b1v9jLEmtq;nCb3{T^i`YWUf3cpG3>9Pu@(S^E(WicD?JbXbXa=g_T-oy&*##dE%J;(4~y7#_r_&uJZ@M#$RY1k8q!x&~y(50&I zzYFOh;$;ME7YT%1mJI~~?b81tb~L{>3IL(w3QX3QQHi+@!$5V0^L_VGIu_ixU#=6O z5J>&{x4qBmh5el(GDb=(f_l$g0EF3pIsXcwr&Hxg!ceAn24eQg+y@zpE`hIfD{}5-s%7_0A`L5Gg8tJ&d$xgCI2-0A3*oq-N~My^DCvn$4CM`4;8Ta z!J0Yv7?tvQ7=6&C4F0x%J1Q10)1w)mrw`wpBN^D@p=8iePWX(TVK5{PbZL_BU=%4N zgKzCTy^PUG4Z?(x1&dOD76!)MnH$n7n{RP+vvf*}p z9}l~Ylqb02kzK))Y?I|er(eM%(K9}Jtk`&@0H}3e^8XX$fY}94V5SN$UbV;k0G%`x zk)O1T{L2c-&nO_@mYY^*+GsCCu^u(31Tv*O=>!i>VK$5WWxX^QJ zHByN011tsaY9`Uam$xion5EFoWrCAZisFWC)fhj2!Bd~rAVr82@~l(%??TmF>P)`V zxqQD5R6xFT1@NDi?rBK(d}T_;I}!jvn@k`vdvri$wX| z%-$_ldX+4+_K^FCG_6<*!PL`Oa3dN+5be1Kw4=sMX+=*QJ3&T^yYIpLcOQ}Mp=VvZ zf69}DKUMpU&>PYzope$uUB~gFFfO1wSlQ=dye!~z_31iw&#CVBPV(L)_g<^;Rw$oj zisxBDEQ-TP)iDUzQ6wZoKX~hk;y@?WP=OSJl3JWU=!@%@6P&Tu5&Wcj7lzhG?79 zH3u6aPBbaUG~~DfiO{Hql}bB~gGR(<(61x0D-=1!N=FI&D=Nm_)RqJ8QUwDZGM7!UmRK=t^vwhxN&8(&U2 zY<2@%_(nKRF!pV^^mBqNOT*rfPG;a3Vx^`)IxLI7obU-Z=V*VW+enuUf^)LlNcRAO zD^p5wg;Ja;w$rMC`=`_1o318#%`HK7S!wjdT z(|nSF+5gg`Q~~`yj#zv;N-{VGmjp$_BH>ax_eRTq=Pl#h8zui;=iY=5ws)%Jtzn8| zCc+vF2H8|$oyMS^?d@oW@5E>`q0LBJjcfl@@Jr`RW_hI2Z-e3{kKMih%;L1HjzPB`ooqb6soF`KlG6SvxsFMbBB_h)?BKO9FHGXH95Had;+ z18fzxIo||_N%+l9wU|Mt^5}mZKald#k<&^DPtKD|qt2<=ft1<*0!$N3H| zGa8A31;izB;^BX{0mQ~51=il^cu2P$t3tOO^(63Li^Dj&oIBcC)v8sth@1;6b)C|$ zxLqbOT_I+aVIXWfP<~bL6|bik$5N2{3fsM*6hBYNw(Sk2^zoD{aej!9nO>H$bt2OS z7F&aNOI2LDDww1|-8YT4`s1H+QTaTBDA>b%1qzv^;q!S;vkC>9mWJ*zsy=u(F~Gy( zVDN5gT&fvYJNLT}QW2T!yZGiX0`GOnTz4GrcfTKFzkPX4&c0$g&s2G~poSXvQ^oHf zw#GU2z#1T^#@o(v7h(f;b(eeiLe;G+LFQXH%}A%Is@oSMwp)&VNrbx@T;5@iC-vCpO3}{C-O=gy{)>E`A8)F5DMd{ zd}UoM{p6e3fA2%2r&0jUY2mq7fizO`w$;E3B!jYblkx5taK`k9>o>L{o`a_9@N(W2 z;hbNFF-N5cfoKeuazkcZ=T-P`C4th-Me;vRez{ZkV!=)R{s%uJ8FPK?9w^j3$E_z^ zgwQE*-Sir-;;TN>Q|8iOl9K61`q~V8t25}D9&{xKU7cZ#^(V2o^8lHlHF$01l(;a@ z)4AdrPxjR#059{8;`+V3Te@RprPT41m?_T}3 zVfBbzvDDo;$MAu@-|&HR?b23b4k>(>#%jYKP|L+9*%OKu%pY@iYsfai@jdSpOd{QD-nF=Z2&#<>znP9#t6BgB zB$EMVyBC#~BF{XXPBf}m&T0JMVQDE+ODa|c&8SY*zKCTE`CtXC9VroIVu3AqtQ{G% zSjGt5*j`LQ)Pz^4RPA&JjIs5V57!ALzVbd)=EEx%Vu6w@6Y$DPp8}QYaeS$*2j6Kc z9x%Lw(+JY z%!8@KRJ4V1^ykGl1Yw7{lwi!&D;6}fim+4iqw7Lx1RIIO2J3)YgzSrls4E39Y{hB8 zl57Z{o^va25)Xau-X}hnstKmvi_Qg8cQOBm%zu#i4>O;(Lcvtp=LAy^Fu#-e-ONA2 z{G-f2#(c8=gQ-Q#U&j1G<`*!Z&>l=B`zDy0&3rxcwalN({5i}|VZMg>WHkm;2@Ang z8j4`5n)yoRE0`~5z5xGRJ)X#)kidilCL}N+fe8srNMJ$&6B3w^z=Q-QBrqX?2?;2v>NQOek#U zB%wTdp*Rt)19=_DOTaa}5#GW@iwjLlmM&Yq;;Ti)*Is8{SyEb7Ua@NR^*317S5;eU zHrQ(GHr6*ZHZ_0E?r^#`ZQio=>)Nz*ojxNoD?8`vYj`W8esz;mSf8mEtWEX8*O~>m z&2~HlS0km;lTrnNQX6U;tQ4-SFqM=pzwTNJ7cVb1Y0~Cv=ciNbte=ADoYFDzQ0^d! zgMDgp*Hl-p*;M6hYN~gvsj@rCZPul)sjja_ziMhIj_~}dPzgcE?vSaMdGY^Fw#(Gr zaB_SZCmW6~ZRkVKNLT8#RBhB)>`ku5YK_xo)oilZYc1>Rt(w`wY|UniLsQjcx4W91 z*6R6GzATyqH2Ckl>#eno8#FG5wOX^e)@f^U(SPWrq}s+>XRW0k|D=tVrW(%v;dR%$ zteU18jj7bknx}vFi~s)HY_->K)i^Ah(1xYT-sEs-ESefuW0kYEsS*Dc7*fz^*uM$} zKQ4z030py7w>n()PO6Vch^2^9_>JUxi(O(`)6{4U6IC@eZn8GAs;NVfg_@gc@e;CK z6J6M%sjj7eNQXk>R5CxFeLwl^Js&@3A*ymXHO?lq?`Q!3)GYoZuEx2w*{ZS8*jSj* zEt+}~2zp7`5XABtj3op?<45eWu2|~lYPL4HG!6___HQi zrzvJ>CfNfKPOD~pt&_^2`Xxre{wvZE_bNxET#j}}Hl zQEf=ms}e(qO3&7$P~Nz)v1xOoro@HuYOrb++pL(ICcC}K9#waV;1U`Ir%)?22v$KO zEXFU2T7@cMBf=)Zj=v_j`FLw70V(C6wFv9+PnL<+i9C%^jj|5>E9H9RY(>08C_^n8 zp%^p{{8@wz2(bwt652RV&c{5I9gmYGsHGMyxWEgwe1(vTb~VC0xKy+e{R#DbNo~Eg z(ZY3XD6P1u+69Glt&}W4KJ&^(1+>IcTkpb%T#;I>nWsq|t(lKOSbu36tw5U?Us%R`S`5LiBFD0$)N%=%Od2z}v=z6eKk zb>JI055o1r4a3dFYs-|*`x#Q$lDx58P#%32OWHN0TbWuVl}Z{XQloNm=JPtG@f}lT zQMAU0(iWkG&_W}5Mtx%xL>L+ogb2Y?opm$58yuvfI4N-9$82|c) zKCO8B5RbuI=o!Q}gBGH`3ixJWxumZ~>!$)G)(zJ+TN}S>-D=vhipN*FtoE%H7T8%l ziD(uB?p6>{5pZ>#umoCt73wX)ibB1pWfE_KY?~lgl6(cy9FVgG5-(*Er&Xm1In>kn z=<6D!TUkysqhHKwKhrZ~ESoTPE;h!6sKp*8itNo;S%!$tmToRwM14nBYhf2zGl-sQ zUKT3&DW3F-^QR~_QRF-&P*Pf0+VP9@Zznu|r|F5lp03ir?0b#onJIV8QmlWj^=leo z2+pf_S=PW+)z_|HLt8WE&2O$=A8IZM0diD!;xi$Evq|7j6X#QB6U{{W7fb>tCg#Ey zY{bX!F1|d%e#r>GS<9ZG__}4>2D%c@g;JPm2<77^E5h^@%Vp|XxU=QYSs_y!;3D() zMwEB0!SABLMdss2Lc{e_`szxaPvMEr_!0=6sXu!k{dCOe8SnwbpMvXztHmkt3wR3b zlzTo-mIc^WIC^cYB-^SI+fsJ+J$?%lsS^_564-kizMe8$rrw9A@Fjew70-34GWApR zoGw#$;yE}=rappa=Or@rF+9yPW$Kf7Y75dTX#PhS4z=_A9Q{a9M_XD^caIJ7oxYcm^aC6`;gd5&36MEqe!|jFp0o=`S zb#N7MOW-o$cEJ5BpO5y*gc*;?gt>5w;MTz13b!5ZF1QEa_Q5?1cNA_AE*@=O40k2m zJ1Bn|?iILhxJThG1kJzlxd(OJ2IquZ4|gqGKHOK}lHufV@BA;?g*yS)3HNijU2r?$ zKJ6ztqU?ic1ONFzXn%CHJ}3Hh*Ivi~>7mb`Fjn~fP$(MpoEYyYahx^s-x_ZZE#s9= zTp~Mhcd-GdY!q*HIc$x!^>k($in03zf$oZ=lu!w4I7O-gC#pnaw`_J;odQmi5i6?1 zEnTQYJWr{jD=dC*Aqba;sX{4=2r9a#++eli1eMiA|2&zlk8y9r;>~tzGo`Wr+Ai=k zOLcXqJy|#<#9^vb4&B5B2yTIe89apy8k`piLL(|>R*tYrR=K#Otg@tRapm%BmzUw7 z^qaEE%EisitE-xwxRSz!uTU6MX=!k5sH8JsL3lm3l5S+1sw%73ZxBw$RMyz7Ru*nV zU3O=w)yb~!7UN>wDVSm_sV}IeL0B>xuCxlb##G`Gzp~o8-n9X}ue3EaZ4`u;&^nUK z8*zhLU2m;6ZK<;21{603FY=r+)KuGuLrt^2sS4LSLUC!u;*zv3$c}8ZKJRt zuF}=WLTedUh3hwzSeu*dPW13bv^?5_W2hGfA3x$29P&yj^mA&j-fC&Aq}vhnqNb^m z?&ll`qC1TiT#fxK20|eQD>=J%Jxs-h25@`$g3VQqs^+bgxbt~Eu5xpOWuvv(;G;e4S1Tu3r+vM;e(oVa-maWhZOj@HdqJ8p;@ER9uGHu}I$JaMtuWvBN8 zq|(c)g{cv#WdNzA8i~Rylv=vg;j}i;CFep1U5QdixJXu5>!5ctII+})#TZ0~a82wo ztEHJ;7798RUIIW0!u_HC10+Nt2z%lxYVA&3v@>P};RiCJlqwUdh@M}#QoD5L3ao4x zOC*WOI;+x~$oPUw0JaPy0M{BV2pPLG(~gslA2MZkG|gQyp=ErN zBf6?Dcr0(hmIl13VzoQ4LKtV`O|;n>E9p`!_Qu)eWlQE|&(=7cn79^F@W$C&t&Z6X z@)P3oEDndYVLjfILIsTu<7}6`G1q}L8}IqdYpA8yteR?^^PtRgEsloyo6=_Et)a%+ z8mq%u5!o85(rEIWc9+As91Db0+vVq|O?NpfhmsC!mCKIzexx{3?AEWj(2BL%Y_Ht} zJ+#5<2xmrSo3@}REsRChP1br%J^9Aj7RU0&O-&oE_SqU&?ZPTrAdRzYEcFiSY|S;{ zdh)J0dnjKq%v+YfCBHp?Xa2qUjs+;Jk>MQ| zoGEMPre&uUrkT?&N?(_LM|!Gmg>JvDOy92GslQk6&gjWdWPT^JJM&m(Z>A&b!>sRS zKb1Ye+W1AzGdUOJUX@#%YtJitF34VR z!-9?lcTu}q8C!eo+F80Qby>P)x(&K|-B#T;{kQc8Gw;gzD94{W->@cseZDQf5#_(0 z-EB)!$b>#T9@U=E{!wdByCdy}^bP5o({E0{HN7MK z!Su({r|K@&&Cr$TzOMU*?jGHJy2o@+>W=76>E6`!>*DkY`iu25_1Eb)>%W1PAJXsD z$7IaPn46K4QIN4b!<=zv#(f$0XZ$$h;fzN!4rLt9d?EAo%($%NtemWCv!2X)F-w+x zarXM`_p<+)oseVB*`M>voELL0&;4HRL%BzCf0O%%+;?;3hAD=N40(p7hGIjhVYQ*k zaGPO=;roV14Sj}fd7ivod4JCPFmI93Vcc&l&A%c4)%>{&su#2`*uNl1ax%-Pi^65v zT>ccp(l{oCmS>F=Zur+<_#*Tw6m>5_FbA^yOtH+N5=^xQQ zrSH=B=#T4P(+}$ZuD>B;T}DkteTF?_OU5l3w`KS;?#lQ+Wb#nPBN&IF9vJPhbD(i1q?`Oqi z=j1HRxg+P>Is0-B=KLz>-JB0|Cgo1gy)yTj+`-)Uaz}Dw3<|>ohMyV^8eTCxVEl#g zfU(Q?obe^&Z;fvl|7sjDD)N)_FU!9o|0joNC-UFU$G<{daKVD<3(^;4 zEm*i<$pT>=&UGNhi?y?~^R<~;llBH}jdqjvdF^ksR|D}SY1gMUq}`h4O}j5`Z`%H} z?zEw__tP#-PfgEHFG*jWeiP)pKmBC->GTiNe}WltNOxTKy6z)gtUgIUTVJTZLH{lN zKK=BJIT?B&rYK`|Ms-GWMoY%-jJnK2z{=fOzsR~cduI0B?9A-^?8VtDvhT^ZN^WbMe>nN^M1(~Q}(CI4p3A7Q6VNC91M z`o7H0oIZo!Fkn#Tsq^OMY4eKm%z4f9Cgd(&m!Oqv6?#>6=&;Fn zox}nI)1snpR+Lz1pkNDb?rLa@ZApDsTMfV6aaJYWax;?u=XuV#^Rn;w()Zu@*TTJX z?z!jXInUd9&U0RF=@(Y`@_jyEfNS4ApKlYt@>inwK5l-WZ`e_f4)bjs{LImt{8OJf zdRpbR3rEghFz=cLGp-wX)r{+}pI0^V%2^{9R9`>x+UrM7{@mwBUN>*%tZ@e%Fl3Z1 z`h}m}KWWW#Zw>dZ$tRyN{2M&4TsqGFjvaotJ|8rErT!i`{G0sl{?WMM_wu{uxi^RZ zL!S>C{&jsndiZL6K3RXuuf3{L%I>Kp(TLAC)j!C0Sm`krdTCmHc}EZRhkU-3G_cad z-fjnr!TzQ z$b4VxP@iw)BYD0vytr3Db8 z*CZX6;G`3rBYnOr#x0mRqiTlFcgJWFZ=m9n_+3rftiKZ2YMe>tYdwq?t)x4I-|bz} z)s4H>Bs}l{DFB=f<7ZcwbS2{!EL?CEuM~ISPzmxs-KCo~cOD79DCK}tB|=-5bdz}d z|J2_O`AZHw*zZgJEXwT;xqaqopD+35^@I*x$Zh#-Zu$2S_hLDrlVjX=f1bw+CGoi@ za(nG_+-{M_AIamu=XpDE3ZeFkxSf76kEhAoYveZNi`<4vDK9SKwnpOCN#c1@W$83- zt0eT(+qgY;2YH{9(6?VF&bx`*RCzp6-kv76$K>|rjoju*Xt`AWvvx{pkvcAtTRYkz`G$adV+FT05;y-| z;-0@%;!=d}7BDW67e`7d2bOWW?pwtD?tDUT$nEvt^SI_(Lc0fZD-fI>E{VS_Z(FBx zyGZKTB%wJ{)M9yYf*|{w68D7M?v%KTq~4zhWqv=Mx6{yL$$}~#e|QbIJwm9pbGSJI z#??1)`?iGkO0&wOfRD-J{qpz`c|7PUZnsS2_IW9Jvfw$nl-qJ?Z|x{XQh?CUYBB!0qoxb6YNNe?6DChf8B3uW^fB$L+i_ZXHW_ zJNyrXu9kEsNXdE9%7nzZl4RkN+z!2fxVX@*{yZKpFXa{$=wFipHXO_C2w}5BgkL5~ zMbAy;v4PGd`MTuYDv!gYj#uRIBf?T=N&!EW0*)%=cKAWuzE{bu^*P?AzC>udWP3>n zu=i`+ZkKFdmC9@7#m#cNTnaenliYqQY|$M_-)B{&Sl(wAT2MHiheCk9r7DO6D7$z=W$yi>B5rj2Ep@qf&Nfw(Rbv< zks=V+OXw|W{>1>P8ty;0|6t%h82Aqc{?B2c!fCs;Z5Jl%=P$T0v32ymefu__#?vNg z=vzOU?RO%}_w9?-2jh_rhySG=PBc(l7F>L~JWUDie95Wkh@TrYPupI~bK1*@ zaVCYL`wnjL<%h{y-0qH|5c0++hGyq!sq4H_+camu<+Ni`(2kbWqYOmp<`ch|#b14)GvMw>Ml|R%qK>Xxm$;FcxODwj+dInTRw+i7utB z_ju`AoJdnV(waKPrvKCFw$7H>1GRu3Yf6N+)q*h1lxP9?w0-i;2BFCKJX5fQEB93R z!->)sq`0jdtVZ2O^krc@QXi|S_tk`Lo@7pp^3AP5xj2-iCVy9knl{xO@zfoa0TJHv#$3ooO|t6v;IYPn9_F# zl`DNu75Yx#$6zE5SEt#$YOMLY<*i+fmS} zmh`!_nhW)$DTY?>y31YnlH>TAECbpvh5NS3QnIaD1CV&;2TfVT1(i8IrElsGyQGbuFn)2}gQG zHaA2XfykGLG?Jk?BP3;BSzDaQmNn&3#qwW_SjB1@ebs|ZnFl+X6WU#ApxPutU}!M^ zXlUSvGL{B{3E0Ucp`n3@)*=!$S{f`PT=m8IADVddE)TOuXd?%{ZkepZlH@7VFzNoV zAW+=u@zYRHf*J}FFrh*lhcRKg(|rf;O7{wFU_-2cNg;AMQ*4Kuo#JUPMbT`()lA=h zO&MUeuX61Xe#7ro3S_9V@vq$ckUllN|$H;~D@-DBapSWTU;D%7A<5NS&dF=2wDIW*oBbFM9BE6FSd zo4jH+I+2a>$OFQT517;=Z0frtwU@r(Rprxohqy_>mSHeBu7Z5IEKre6t{2E5SDlh6hGDkx%uk)-j;^G8*W& z(dTRR9)mt;XcVuVOo61zv!XcKrt%6~ZCV8uN7ZR z8f?~%CDPHmsmRd`rm%!oZCWu)n;o?M-|^D_5o2|)NGZB^E(kWdSF}_+i3B4Oo`Bp5 zj->xPnXoiT!Y2?Guq4eW!t{u?Yg9vqM`z!*QT{Ma(eUzP{ow#*29NWHZ{~WC>q+8H z}r_)Cq^-#`t?pIr}kSF8f7!HHd*?$FkZV{ z^^DwO$t&Xt4Q!P=`t>l?ukwI?Z5pfk^#OiFl2lSI__OesjD=?h64=I0X&58SFrE_$ z$La#f*HJ6!^h5Pk(9@~QC>dFmyVa=@_H?R*J)Np)YBMQ4ohl`uQw2mChEA0v?ql$6 zeyzMaNMFTkrS0)mi?}=uv$YbT6mucw|?+ zqDAuUGWoumlkXp3Jl*6QO_Ncf(`&l53;MH8v;L zDsqWNwWPS?6(jDbS)31|W~t{Lr4P0OqzERNl*puCYDo9OrK_bKt4;c+bJ9;BeM96< z5Q}|hl&(_|EO(Fcs#;3H;1=n2%)NAJJm>}Qj89=Srxm|S37WK0l6nx|`ajA%q9U&m z6`6irKob&{2AL6-FwB#}XypnFC>4e4O#w91DA2LUi8~og zSp_O$hyoo0hDCv{5Z!nxX*wuXbmKZnPgvr=LwJ`BuO+<0ruin}jW&EA;ng_{sKWE?2llWN8j#W zN22<+FaP0ZPVh!(nD9~e$v+9>1=P9J20vndOjlMigRX2>-y6jDYJ2xFJ~95wvs8Mm z|1#>{|B}{k-9&c8UfWkq1}|FQ9vDsgmoQwn`D~uN@u{ir!sEU68qvitf3ejF8@ksU zQU1z{YBgieHu0JwmY%9>QmM9i{)@DECNgW={O$SedEp7aj7Ro1)SmrEqiXCh@N>smJhaDZ z+I`iBR6Zb0ka5ZcZ9*`4Dg8}D#06UPt?T(Tj#mZ=#Um|gWGz>k5!Hm>D^@oO9Sj^O zUheJ;UdF#CfF%+FLK!`tyiG`y``^UGY9%<*StUR5ih2r((vy_dm$?@jGB}a?cw|#U zWWB&5{?GO5|6EU?IN}z>-XxmAM}A~|!Q;W$-)D$7IQ?|j7xQ0`CsihV;w_E|E=dGvQ_A>Wax2xuCobnk>`+^b$Na^h$ovWwKxFG+uLjf#!X$DLXU6g;wg^vA_oPZaTkVnqD#gQkwsAgaGPRhS7<842L> z<`h#+&7QMv@*fpA^#B>h@llw2LrdDEk(Q!Yr^7sEOo)l&3zEpQX$lEL?-lo)>JNXL zYdzP`xqSKleExh~dGh1WlL-F@PIjfo3ZOE&8WG++6A-)8)nJV`YK5W>zI#+BU44b8 zj&A>hU?rHmxLaL)Gom8`oTaN#vb-XKY5*0GRO^{7N86O?5t^fTroChDG`AP0ZAs`Jh zAUJ>x5YYRKuD(fmg}%-;0=MW4)zl<&e+%VRQ$v8Xrr!L#kv!46OG)eL>1PSokxO)Q zBVljMu$8b7SkiAGoTI0&tiJl{Sqm=D%rX7nSJ`l5m}Z2_d1(J<;HnfWNX4cfqWT| zSMYM^o}ur=AFd=mzI85loEbV?H^pCLL4E~1q)GCY;H(}e@pRH#C$R*rlNcl(XtVt! zJKIYN3Krc|(mLioC4j)|bDpX2Z(4RJbyK>wA9~qJ1Uhd{ZdkJ-&8d}GrtMX2-DUtI zk>47k7bqZDfSRl%APgjEd%#p9#o3f&ZOTZYF?((F!6w?Mle)7}5f4%GbTj`foKOF~ z8U`@^x9EjN614%8gnjUGy$%19_+>Wy4q-vL=$8({H~K2Cwf|SVdX_(Y7gvyLDDMi3 z{o(t$nz>FT?i_w^BmO_Wg&jLo|BQzUYM(TT{+S9&bM%kIItjU}e^vuq<&OS&g{;mh zc|iZHE>Zn6pC9~VGJVpn(^dm^_A5;;^(1y+^EEcpxY9 zGNsgMb1-1i&8c@v>)g|Jc52QvQ$|wOzmS+YARnR~*^tg?WInPXBk)JtEGtcxcx0W! zf06Erb&eJ7BRYYWnoWW6$m+CApVee!Ibp#2oAhG}RoRQenIsWj4pY(^H;P(xFhjV?E>z7>1i94O&i{OWUS6Nf} z5SNt7$Ej$X?DZ$suk!Xm)>fAuHtJRjJJfrNm$z52xP8RI!akfVf|U3gmUWsXlA5kB;ig4ILq5--Bten!JIv4Qussgh~ldq zy|DRHAi(Mqi?4Zck77Y9zGbi>Vb!_SgfY?DSY zAU4G-wmAGR-Q?acg~%MNr)M5B0+KbNjDCt9=_rt8dnAD!at$P*kc%hZbdn$q+8@m% zOiz>DPRfisH>JGy=c?0C4CNfJuces@0M z8{a!B6mR|F_pgV$;Nv5|>V%K;HKH4S|C}}xZV`U>`jJSp;i|(yr9CG-9L{5o89%#^Mnhs`{yH!oM)kG&$*y#3HdFmZ2x>U#1K>oo;pb4 z;VE$52hcyaP^j|rDB%|ta(CkAK|?Hl+(e`u9psj|rzt-(ijZe?(wRm)vpg<08TQFq zT)G2T-F4v6HchI93ml4)ris_s*G!srppbEHE8+cBN=om(+H?BgF73Hm`JeX4iW=EJ zf=}~4ZDS~lI4h>of|nVe=eFP}GH3DeYEpS^SVwq&+Mw|FWq-eFfVB(3-B(Wl?;rrnfz}JRvl7V?@`jP2nr@0@}cd~`JNr_lr}nr z{&Ibs)97<58lAupFk?-bYZQ=h>hqQbPBx4Zk8EL?`h=(Ak@fLX90mA5H!!mKAKpfJ z%H%)6=0B*i&4Z;{8=JLtV009@JQoP9TnYlwET=$_EV&#{s#bJMfF_(xSp4qYGSLSZ zsq_?MTj?1V{dzV}x%R^MfvA&wjr&C>dS0dx(*M}r7y{|aYUv4B;Uz=ctTE$X6h$5{ zT5JDkP`MwxC}`-He)uzs7CXUz{o@||X?y3hhJ(@;9KA-qVbY9+W(9u{N&5$Azu@~! zSNNXY+6BI$3bJ6>SeU?fl>xa6e7nHze!%B?^e=)`o6qV>f2{LP_#2mo&x*~b4E9M@xbFT+)K;Z3aKfaB4b%OVnEgn9*DwQj} zcZ}%7F_X1t<-Zl@VmiqVl`6LQHAgF#ikyp4kuVuETZF>Xkn<~P>2%{x7eHy|XTeRD zoEMSGlk-u8-;bOtJ_4RT-isF9Jh2P?{!C0Kd|dyShYw4?n9?T*{qT+sSj%>Xs|!9F zX}NJ^4mm3W-W2oQT0l5;7Re(m?iR9l+Eeftt=9SKI&iup<1YG}V$I_OfgKbb52E|W zu^uOM|Eu`u(LTXF3oKA>iYH4QvH_%;v1=$=Io+e{!;dO*Ft*eeA;kfrV5m@)GzOw-LU}5!#jF9UcMTMZ9GNT+sj_ zXGj*fk|IwDLAh;aj)4Jn7XkaBNBH8p>~ZsTjHijTnVAzX2Hv3LcVf|n?k5a zvp%gXVIpgmM5Vzc1RyH&2x>cWsU0Qe}P^l^mE&* zm=$?DAKtg`)_M^fWHGrZr+-;QdXbjVyj@0k!K`aObUQLzrvEp?s!!^mklM2%8=J@T zWc3N^7Dtwy2>&fugIso>z(A!1{?h6z?E6+wOs|Q{g#iVGxo)E>L7V<~liofRnJ1R| zM`ypIw4G~G+Zy+33HO>BRgDUakZv4geLrec+bdS7wpX-Fw!e?s+&2|rEK}%6 z9SHl&Ds%V6bR3qC6f!&xqm#RXtvp&ve2Tc%NSqpzI#Hs66c#US)38o;VHrV zQWi}F^*EQdY=WSL;gR*r_yz!{I1;QG!Y^ym!Tjs9L+-T?DOkFTMKH@kG!uj8 zMRvWn3HoI}SX)C0{yQn9%?UOj{Tj>$b#T8xRdg!6brjL9{*ToJeO1SPd&6Jz!ZFwX zUHO#*Re~H$lR0MP8-SUuq8*<5MwBIH@AaFS>vC((Y~???Q_aKsuDSR6oOZ1-TDb#5 zW#7TAdT4+gHuUoixo!MD&;4p+U-cn!s%NuLHafRcWoPwLnU>$n_)W%7BB_f4zUuKB zfTAZzpe_VM6;BLS9mW$UC6u`rQ4fN_qvbHAsvXTe{9wOY+)sF@kAa&L*y&8&8F*CK zdCqe_r#c)D91@>;NPvoa!0vvPp9t*ixg^7Y{VY!wLaE#~lpwzvG6;-M4E9>Z{+5r1 zRw1|a>8p6-&nrR+sQk*fZS$vrFKxeh^gqK_Jv>cyN==ScqoN~r#=wHxMrOjbadLCK zgQykZ3-r4G%+j_c=&Cl+Rc)!HvJ1+-RXmne>?dp6)+&qCTg%*4KNb#Rfu{h%40lD_ zwwLqE-LI@Ss!gLEz2lLdE&M2q$3on4_p6$QwQ_Vg&2%r;F|B&LkrPfBnNNr`7DpOy zsrCTa606zbtD0;|QKxfbBJ@jPrkyWQ=$3MKfPqIe=R`WJMg!;uaSJ$;Q1eHcN>j)1 zE<3AvJLMMB z5~uvu1PYWN#$%^$K9wiS4`#YAMEfx>hnmL6YQnxMkc0iC-Fv%P>H5Gm45Au-kao>U znY8IAKQe6+{@6g0c4`oeZy|i+j0Js;n|g;&?C%I23=YH&11oB2ELFl(2CR}wz#88L ztV1nWI_EfrG#*^j2=@mr5Ba^rC%!vYLk^F$r=k1G53`_a73jYDKxd?Vku<^xtlJR0 zxmobFf1vPzKV?!Du3~woVSE*Qr7^hdT3~$r`<-F@Eorh~ypvQO4p$TIFAjUhUk?8{ z3RUQZh~>BuvjME43t(qkz?^-8yHOczHUW4$A^1J6V6anGZ1%GII`S9QI$G>HAj@n?>Kb zr1J2%h;V=Bv=zP{=VQg1aSwq1bvt&qr~kFF7q4b)LXX{%8AbML+y-cj+1RXeK6%oDF%P6LouPECJb(k z8$nbrF!zT(nezJy?^Nih^xn9a{_-~f(8ZrF3+yo%zPC;_DV@}&ktEaU@%DzvLzE|S zqhMdk$)rkfy6HY!w@8)fSL zb5`y-jRS1m%+z=l*{F~Z--07irtZxU#Y5Sg#(_3BOFq1$HYzkSH_GImlT-H~n>&r& zIgK_dG&+-8qD=1B{-JfxMw>&t?|(<0FsWS&B#R^5uGE*PPSkfzaW7^yMX68H&eWHv zPSke|8hu$!5n5~J9O`S{DPBV~jmi4UtcsP?r0h(6i3%TB*PncR}fK>o}-*}MZ?HFwYh zQ>m}HmuGTIDwF%JEXWx;Sd5EOv8b?7p++yaNo8W6t#X%R;vy{+#U~ZG;YRoJ;DIZ5Fa4(GNYpNpg4{R1rAafUx_ zibO(cR9jz`^|=qxZ2b53t$It}yidyTGPo-`73r3_Cn%UGKMFWg!;E*_sC%*(ZZX~S z?uB&EtM9knvzc?bl+tgl7v;*pp_;O-{UO?}jr0PZsJ(kj&+=V; z?c5LT6v|GW{(m0R7|{N;9ztk;csAD5=2Lje_!Ahg$90Rlvr68^UiHUKV5>YHaMM{% ztpqqfVZ@DkenOZZv?q+u=xO3;Mo%T-)JPerOd07!NAW5?B^-|yij6F(oU#$|XxLgo zD}GlEUvcf_;tNLl=a>6?JnBH(Cx=LA`-0NGbF$l4BrXE?g>R^AF$(SOFltQLqM8b0 z!WQQ1y13A-+eHVIyN}!_IYZ`{vdl|SFXiqU^HLnQ_@paZ;)UD1@Q(PjZGqIiPNWDG z(Sgu%29|U=_pFifKp>9m&6+)61a8VrAm)U7)Aq2m2{9W+8WA&*u_#GeXrZXPd4zY^ za3$e|RST}Y{uuaF;fGMCN>bhANZUsK^Imu7XN#QzHxY%s? z(Xqm<+k=Y8sOARCvQ);tk#fu3)65$Ve&da-pKAh-b`gtDZLdNWE#=F(aILA829+xp zfy$QEX;j)JHcxwb2*nl!hgN??7(-@g%CHXa0ARE^GQ=VA$@LUM(@8e0p!Qq(V3P*Q-OIC+sw{?? zv5_f}s!MbxT`k+Tg2w|x*b(ztDW^^*6&2Ucq$2efAM?CCtIA6~DCd!wz4)w@)uUBeHye*E<)EZ^WSO2=xI&9Cr*XKm-!W8;jEp9{ z13C(osohtU0O90x*u+fOa$Lf`Rhr(g_M$Jr+WvcTy5%QVYPSpy&=)UKgkW0C$fYFS zZTWgVVf=&p#uNWvgclJWNq8OMtLd9(&7JAH-2A*Ba`c(EFMSdoupFqO?rKGaOk>*h ziaqL+D>C{d9NRvn+|4&^oKYqaR0=J3lORqV6EYWG2SH_TqU=6Y<~0iXM;I=#`VkqW za+krpyBN&h4yvb{rHxjpTu+gne%?b8Pp1s6$>@|IVfM;=ASy-iCri+j-$z5m?C)`8 z){EhDHFF#|uZGl&L6B)?uq?rzRrhULp=glPNMY@^GPmSw%4Dg7QwNb#qSc-}(L@^z zw9^c?mKeo=F$vH8s_>q`1Mgi4rwT6MMBiQ#w*j4a1cJA42KlV(=D(M&N!u&SNVUBI zX>ZngSGrX6Shw9ey038I>EaA$Quw2DB5k33Rjr29?ndo9@J_da8jg|D3HI<934~LR zYPMl&zjVZ>gp&6I0L!{d_?Z)F#wT{CB1R4<;(H~M`j%Pr{Kb*x#mBKkHl{~MX-d`Q z_{4S?DK;5W&vb!jlm}0v!qe!%LjYr;O;uJ~YE|VPKuGrylsiTNF{W0V&f=R{c|jQ@ z`8BUU9K~xTUFoxf%9K8*3VkNt5L*x~2 z(XI7TCJh+2pAArW_>7r>M^-y-j&uW$^r;Mj@aTq_o)ZUe)j%aW(_h|fsfH9Fj&Hh} zBBdR|ZQjvjnjfSy%4?;L>@&*fKnoXMWVx?QR!z?-Z4DXQQY=AOXaVDGEJ3@px*Cr} z>)X4M?@|tvS7U@J*~HOo!hkuZF^349apv9ST`sW+f&<;bKwokzHMk1Q~6wlSiR|`t;)WwN`0Xq)DPeN zA+vA)`YYMvr~KXd`~WnB;cww1!%u}~x;MS1!((b8hwxY-xPzY-VT9T)4Q`0nO36+_ z?z%`#16$=j{HCj%RTAJllTEdHp2-9J81q1s84IGHSCb-?JeERvu_pHNp#1III`C%5 zJSo)(i^!y?yvmnXxcBU5t9NsE{MZv-wu>d>fObJ5&d%t3MEAyp=5L3ot zPa#B*4t{GZDX4vm;&i^R(Qbp06evV2E_hkyf{UjF3lh>diGCz&L%>hXzKoUHSnx<- z$YzP#_LA&YDtII`WZO%@q1zsnxScPvpQ+%H!r|Lq4iDX~$>!{&r8cf;==M3Klv~jn zpFAX>g{tpLUi)nwd_YGE9i#^k(kZs+TD*KYj{puU)Bt1K&=`q9L)OP@Wl?@?tK0_^++HXpB;ny7_E=N{v9I`6X7zK$Khr#6QNP(i} z;50SMmwR+cosff<7ZeE@0-l&o2m$jWEoVkT3o6nwsuvXl@|07i%3X;r{OS9CQ5}Ulw!S4qbjmW5qU9f5>`Ld-nR1ggrk~ zJ>dmDwcc0Ex!oUrhU?4AiIaG)fn5Iqy`; z1OM&6! zQP!c_(PWC3?zYYgXszB_fx=lOclFk4V5{7R7u8MkHa1?pC0Urr#L`fCJzd6+AJ$~C&lCiU6W1tm2^T*&O=&nQF%U!D*6lL&nQt*u{zE^kVw&( z2m$Peb!x4zvtGz`$zNe;n5}IY$baiWUX%vtpGytowKC94m85}RCEiRH1>Kel|FhZ2 z9nF+(#YJiy?TI4`+T5^HR^&`#1$~Vo0Y>OIC7z{PX{1(Q+iAl^-WkLkVl3`ZwdPG+ z@_96VgC1y_Y4fvQn@6SFJlJbQ3Hc?~EnOnb45X%J+CSE`U+I;h-?N&KrL~gPoMxJ7 zKecOV`)<+F`b*K5s6!hoWqOS@VH!J?NFl8TlB2a+iA%mp!_25isQ;L;Pvl7FGOS;^RXDLc@Tf9O8?iR@_mc?&(u zCtZXWxh6ZMzLj!i4X_*hqSPKpeKDOW_x;;+SMr`MfNbE5y)-EH_q-}qrtGCCl!?qK z?B}3OgbST$a7-EBjO<9AG@-8gc;^76$+l1N6?QWcY3ei*`35#+mmWus+~Np+`*qE< z^*oQX6YTeaL*U(=1?Z|$Z><-uL6J_C;!vdK`@n@HYKL~BM^BRsghh{zC7iA2Zn_5| zay`k_&h-M<;II3`mvMcI@JIMPhbzG)`Yt~(Ab;SHfdlgg4G07W|NDxq%3CuCQF)V| zV)Ms&O3$YlddCy;Cbm`XxPs)wXlIo?u#36*US)rVK9&WPU!8W@#T{lG)Ly3NuWozU z=iDaaOa1an)_~|fD42YnI+f>oFJ#X4LC$h1q--{;>_X*fzPL~d`Km3X2Y&1V(wyys zz0wBfls1^sQlCk~Vn-5PedNY8y9&}_*ZWCp z`+czLt0$GmuT6w+@(HHxbsoR}8(gRSG8ubW`DM#L;g`DsyNiFqb91>j zs_qaITEDr4w}B<_p=NY|_yZ=Y#XM(?qZ2Zx#s^_<5*5V6g&a2$+bVb8 z5}avLm`h=aT1kg0({usHq;vhrKY~^BGOh=ih?ZvsS|h0&YPU!+{H6H7h=kRMlYnE= zCM2vA2umquj;7($hRu?qjO~YcOnSs?H)saAGkj`y%2*#WS;4>nT}NzetK5CnS30#) zZFG(n8*)}jIXda3MUYtzoGC1Kuh}b&<;$R}HMiV-RY!SEJPsa08ykq<-o?h+ zDYN2^sc=y!zq%#|-292)?oJAF%sruDRn_HQlmLe&=X(kQFUr>p2i?loEI3Pvj%}5@ zuV#b?&OOzg!AV`8`drUVm9jHU4RvVQ_=nO3M!FVwWbzVnc{Psm5-1%??9Q%H-$cGH zSeRpBAF)6zY++X!k1rFwdlR97x>?h!QSdr`D~(rDxc%g z(AoRM+ro^ly6!*HsWz#T0B37BKturCIRAe?uK1Oy9`pM+(K)ZVzAGtY4I_qH2aE zTz8AKnB#3L4%Wy_8TeugaqR57eO0VTVlo)lU7IeNHLsM~)oo7bq4?A$)}^!Df_dYP z)I+J#u1hSWywX-WgPQSkBCUj3X)G~LbQhL8oy*k-Z{tL-|855XoVWS*Cx5Md_Uce5rG7EFYi z%G|5H7qSABguAcTgvym|QTGaELJ(*cQwaIsizldczxhJjSLe~cMC4^WPgY*^Jc*Np zt?8!Rq-mBuvSQ#5>Bp%1tO@JPvy=unr}hh+-toIhh7mf09^_0@#b;<|>zR=@nQ3kF z)f{Y5SLUunNrB3woUQ}2ipt8-G92I$s=354W$f&2*;y~LS${_!%e95uiYwY~@p!m! zTf748U~0Z4Q>SdhmpWzjSn6xD=?#^>(7jb8SxyFkqOEq-6SRfhWi5pq4w4Af%CM-+ zJ;vmb1r3v+X!->#Q_-qU(MRSe*L0^lwNFz}&LPwCa;`cu&d`Z0vXC;{ym zj$!KCx41}jf^43y(M6Tg4PdR`ovL6;yi8CX34!Vxf_N$BL^?p4>0_nKb%MpEA=s5r zNgy>!P`Joe!fB*!s8{;KIXgvZ=0~AbTk7fequzVhcT~cGlZMN(by+3M)jis^JW&M7 z-!e?vJOvKR*c%KNumoatg@(hU?kU$=hNty>7S;3&&t0S3D-D*Fi)%jUvNN*gnKPl3)`s?(#HNa97G#f%NOHZkrVl4otDSfpx%3g3q@n` z*a*AJ*PdEU0kOq?!{1hzQm>?6nX=b0t>kcwbXh1Kg;bJ^M^-6nyw+t4Cs}sYJW5^3 z!Cyl5>D;_y{Bl0V9iB?0af|NUSuJr zEE-aKvG!^qtk{bMG7=^dEx_5Z8Pm`DEfAp`d@F3yJsAmy6 z_V>sjvW*O~R+f&Ro_>#VCmjpYvD<{RrQ_WFfJ*D{aXivpA7{r09|!ZDOllN#CJK+{ zZlh%-T2vIO)?r)9jJSuKDCF`l+h}Fv3WL?;wy0yMu##>M? z=!A>Q0tH`wMs=1q;$q#4^!SFP+D)Pl+eAN&@U)=*vfdVv>0!m{E}YuPHHWybqytG2Jl{w{6bF*60$AH*8>Y;#X;d-aqs6iN4d z&gI%@dOk#`m1W6d+!=3&tdxWia{4>t>`47gn`*nezd-f(NmgxdohJ{S$G6(br&v=% zD^)Qf+U4#UBxjhOtqZT|FCOWOQRu6VkMZA}l zu)|22G;8|W)O8iEmK~lntW8{3?_BB;#0*q|$ros-cHt2|gExTCKveQYX$#mSD-qgW}qjllwpxlfF968x0`-u(i z>34jGMrrcO+frOOwMjoefJSeNx<6Dn<*Y~!_NEf_c9^L5Dd3$b(Wm@zTJ9GNTIgjW z9qLo+*yavUS0q>`rdjv2jFG*9VkXf11?;WC+8=-2Ui^kDH#Y1t-^~Ufsj|okUk1|SwPS%d0t+B^#lWR zKIU0zDE7rrppQbtt7ZxrR(+nyJE&^B$vcQ6Q8Ait4h5^E%b|gOuh_iaiaMdARaEN%mOzZ*G5>#0V%3ec>t$nKMT<`tJs!w{s z!BwYv!68-nBy0gf1#xHIF?=~@s+}R=tu1psaqNrCdV@Df&%x~dT-W~Mxp(=?-rd1b z3$c#l%rg5JOrh_#wc^jAC585s6~iepcXC`MGNy;FeDtQzJ9;Eb!6SEXc}&(cty;;? zCaf)As(2ITh%a@j7MD6%Ki`)+eiNe%U+O6Jho_1*vC`j{8oo&u8K#D8V#$+Fmp)oT zUqNBzTrsX|xT?7>;yRD(dalJ>cW~KnWDoB4PgdLv9yoYV=4G(IINYCf{lNEr<21Zg zaq4dIaC(-(+XRE*vF7PGgW-=D3?FKq!sgxJO(lX;){nOH(Lv$$5N&KuBhYmmC!1L6y0uyt$V z+J2w(mnG!Owy#3*gjhz-D!Ji=^2fE5_^N)dl1H-}+nq7!8LLJ%rm+>#s zYOT(R78MT{;CiV>j(i|>!Oy1@!5{@c&ns^1Bgfq~$0H`kBYo$%+~kNYD)Lp0gDtef z@%K@UtPf3%F{x{x>Lc+#L7WhGQE+fU?QitKbd>6LIz1ySn8ZZ|kB8{F`Y6#%CdpvS z9E`_mD$I{Q2`{JTS{50yi~3U#HidnbrP zGbMka9Ke!C$8ibou=CI{wrM`$M2TA3;vqj)Se4U-9TMYr@DQ@ zKFq2}2Q*zW#h6tWUf|xxm zuA8~0Ht@`KD(Un2eVywf!gIK4xW2<>_iPQ2JzE3*AKJ5}`osm(s!xhUpPa>0+CC3Q z-Na|Lb3>@rSt!fW-yli4@3lh)uQU6h5;nIpGwLU;+D&gQl{u^AuD!Jew#pq@zKseT z{d^@o_WWOIk9`F{hQ~r>s5qGkkkgtv_aPUgrleEB<)jjKOy^YNj;4R1XsFG`4^qr(tCe^{*1cM04>Ie zx}2oNZ3Pd?6f-M$X|edDbkd6!cZiuQx^D~~r3#W&go>Z8(WS3bdswj5R)dhYQYc%e z8yPZEAamB?ay{T%yZQ6}F0tWM16_N;gOL!Yz$q%NbpPbj29@vCa@F?tW_HACcKD2Pz5)Jdh-`%Z{M5;hIHBv* z>s3dfII_EjnV~vLU?1MrNd^^(ialAVDCtmC#3K*HY96rV9;Us(#{9?w@yN#1k2%b; zII^qyFafu84^y`l?Qt==NU$UM8nq@OD>>D&A+lV2ONq!b>f2c6o@OC7=V0o+II^Sq zV`eusroc*>>&5VMzcg83fU~U8@Xcs^sf+8%;jIk)C#Az5!Vl4+q9HQLt^UMjH#T?OFPT1Q^wR z!JKE0@0ae9GT4Wuf{xObc??%frX7soWvo-r>q3&$nFAgT!{oN^p@_*z^$m zQAT1zhD|wG@lDI4&9RzhUkzHJImMbmR5z#LwWWSWP{r5IqPziF_RGoMyS~bt{{$ys z$qcC}PAIU97mhPBrM4!_+s=m<4R>OSw8P?ZII*($YIs9TlS+(^xNBK0OH3_@m zYX@ytGeQyGC%zhg1HOI=g0k>+6H|j}KD�()em3wTG`3!v9))b(Y7Qw5gs*^&*c! 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 From b46e7f115bac5b79011b41405226fda5338bec37 Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 29 Apr 2016 02:05:33 +0800 Subject: [PATCH 085/173] =?UTF-8?q?=E5=88=86=E7=A6=BBlualib=E5=85=B1?= =?UTF-8?q?=E4=BA=AB=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deps/lua/lua.vcxproj | 2 +- node-lua.sln | 9 --------- node-lua.v12.suo | Bin 159232 -> 159232 bytes sample/test_http.lua | 21 +++++++++++++++++++++ 4 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 sample/test_http.lua diff --git a/deps/lua/lua.vcxproj b/deps/lua/lua.vcxproj index 91eadc7..0ef4281 100644 --- a/deps/lua/lua.vcxproj +++ b/deps/lua/lua.vcxproj @@ -55,7 +55,7 @@ true - $(SolutionDir)install.bat $(SolutionDir) $(ProjectName) + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) diff --git a/node-lua.sln b/node-lua.sln index ae29c52..eaa274a 100644 --- a/node-lua.sln +++ b/node-lua.sln @@ -13,11 +13,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uv", "deps\uv\uv.vcxproj", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua", "deps\lua\lua.vcxproj", "{1F43B07D-0625-4E5D-A419-53BB749B2293}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "clib\mime\mime.vcxproj", "{2691C520-B01B-46AB-B585-716767F72A9F}" - ProjectSection(ProjectDependencies) = postProject - {1F43B07D-0625-4E5D-A419-53BB749B2293} = {1F43B07D-0625-4E5D-A419-53BB749B2293} - EndProjectSection -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -36,10 +31,6 @@ Global {1F43B07D-0625-4E5D-A419-53BB749B2293}.Debug|Win32.Build.0 = Debug|Win32 {1F43B07D-0625-4E5D-A419-53BB749B2293}.Release|Win32.ActiveCfg = Release|Win32 {1F43B07D-0625-4E5D-A419-53BB749B2293}.Release|Win32.Build.0 = Release|Win32 - {2691C520-B01B-46AB-B585-716767F72A9F}.Debug|Win32.ActiveCfg = Debug|Win32 - {2691C520-B01B-46AB-B585-716767F72A9F}.Debug|Win32.Build.0 = Debug|Win32 - {2691C520-B01B-46AB-B585-716767F72A9F}.Release|Win32.ActiveCfg = Release|Win32 - {2691C520-B01B-46AB-B585-716767F72A9F}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 2473689c87424f7b14999d209c543d18c2267c33..8f5fe088a36839b6f28febf8e0822bf400466bcb 100644 GIT binary patch delta 5036 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 delta 1994 zcmaJ>e{57$7JlEEH$OXtTBf$ZR9;J|V_UGT1xsz&LE7#vVM~i+gRDYZj4nTvL5d-u z@wF0nSKI`9aZWZdq>JQPkyPj;y({652^wTK#;vGCle$|CW)rh9#zi6qrk*!c)A)yX z^36Tx+;h(T&b{v*dopNG1`pRRA!B9~7{+fz^a--l)6=fiBk&4#tFrusr;|58$KOov z^1TS`S1=dhhAImbn@@{}Y7QJOcwU5i1a7!H)MTL5%n232Si}|9$?7J7D?cl<>had7 z7lM{L=?#~Z!Z7xVan6jxKAG=wohE|OTy#nlTkw>?%`oO04yA`f2hq?WmaQ|^zsP*M zq;fsnab(7RQ=6WCNp!zJZ45`TC%rek2PHRV`D8^lB>sj39E*gG%^_u573m5q`;ICf zb<_n6)>5?;_Em|p%~0RZt5U~z zS%EJ_{rty_yCvfezUILJpITz+ z80WnKJcHNy+Zd)puSuqagc*j;R)feX2aT`7TL|LcVk{Q8HH7~me!E;Z8Dm2+nC@+> z8ug(QhdDN4k+R~Zu2_aiI8~CO9j2+iIJ=OiDydAzS75@U3PxVmC!5gk(N;aCyiThe zLnA2F2~(S`xDJjVLX&Rl#`!!RoIejk^YF+;tYzx~l<2jY`T^;a(@|L+8dxI9cTJ`oV=$pAG8>uD0!o9EL>&O|8AlPfXD z36sh97Sby2TTGjIb1{Y88Y{TAj*^^OF2N5j&jtUjj_!5}$;Zh?`qN6c4Z5AJLH-XI z^+ub~F24q2wV=URDwcLBvQDH1<8I?#k(U}PrFCsm1M6D3b5L%-D4$*@j<--oTIoEk z3TY|vXPfCxej`S=j2BUyc;J32;gV|lgU&3LTjs8{v`B6Fq)gj)iu$U3A3^P2QNtZO zP{OS-YGykj_ne7I@T-{w(fCrz1Ml1eOINR;B5t=7JOWw#b zX}R}&(DjwQ{ABAxrT;o;_wOuLb$1k{t3JL}UT`k3O*)(&*hn$Iw@gkik4LxAH9oYS z=9})B^2mB>4#;KZ2LEq8E#lL^rum%d6o&6t(-J=QTk>Hm$Ga$#+D3Mf@eA8t!g#wd z)dTm@GX-wLDWCP%(})Gi{w~h;RtoT?N~!)Q59zZ3wjZTP&Lmn$#a+*Zkm4VvN5F-L zvB00>EUZ^=!OB!GnPyCQtAR6>JladX{9dEq*l9dwJR%1JRYvnv;?tVEu=vbW$aPO* zan5&cx3R`}(6|}#^_n0*+ea;&>7lsU_Ph23o4wR56gv6vR;tZ$`HAaI)^0W0-cGjX E2MpPYR{#J2 diff --git a/sample/test_http.lua b/sample/test_http.lua new file mode 100644 index 0000000..613b8bf --- /dev/null +++ b/sample/test_http.lua @@ -0,0 +1,21 @@ +-- if context.winos then + -- package.cpath = package.cpath ..";".."..\\clib\\?.dll" + -- package.path = package.path ..";".."..\\lualib\\?.lua" +-- else + -- package.cpath = package.cpath ..";".."../clib/?.so" + -- package.path = package.path ..";".."../lualib/?.lua" +-- end + +if context.winos then + package.cpath = package.cpath ..";".."clib\\?.dll" + package.path = package.path ..";".."lualib\\?.lua" +else + package.cpath = package.cpath ..";".."clib/?.so" + package.path = package.path ..";".."lualib/?.lua" +end + +local http = require "http" +local a, b = http.request("http://www.baidu.com") +for k, v in pairs(b) do + print(k, v) +end \ No newline at end of file From 2269528312998ec38116a54a2bc6c7a1c5eb4deb Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 29 Apr 2016 02:36:10 +0800 Subject: [PATCH 086/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0luaclib=E5=85=B1?= =?UTF-8?q?=E4=BA=AB=E5=BA=93=E5=AF=BC=E5=87=BA=E7=AC=A6=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/cjson/cjson.def | 3 +++ luaclib/cjson/cjson.vcxproj | 1 + luaclib/lfs/lfs.def | 8 +++----- luaclib/lfs/lfs.vcxproj | 1 + luaclib/lpeg/lpeg.def | 3 +++ luaclib/luaclib.v12.suo | Bin 71168 -> 71168 bytes luaclib/pb/pbc.vcxproj | 1 + luaclib/pb/protobuf.def | 3 +++ node-lua.v12.suo | Bin 159232 -> 159232 bytes sample/test.lua | 12 ++++++++++-- 10 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 luaclib/cjson/cjson.def create mode 100644 luaclib/lpeg/lpeg.def create mode 100644 luaclib/pb/protobuf.def diff --git a/luaclib/cjson/cjson.def b/luaclib/cjson/cjson.def new file mode 100644 index 0000000..f070692 --- /dev/null +++ b/luaclib/cjson/cjson.def @@ -0,0 +1,3 @@ +LIBRARY + EXPORTS + luaopen_cjson \ No newline at end of file diff --git a/luaclib/cjson/cjson.vcxproj b/luaclib/cjson/cjson.vcxproj index b3cbd97..6542e3b 100644 --- a/luaclib/cjson/cjson.vcxproj +++ b/luaclib/cjson/cjson.vcxproj @@ -54,6 +54,7 @@ true ..\..\deps\lua; nlua.lib + cjson.def copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) diff --git a/luaclib/lfs/lfs.def b/luaclib/lfs/lfs.def index 2b69094..4298a15 100644 --- a/luaclib/lfs/lfs.def +++ b/luaclib/lfs/lfs.def @@ -1,5 +1,3 @@ -LIBRARY lfs.dll -DESCRIPTION "LuaFileSystem" -VERSION 1.5.0 -EXPORTS -luaopen_lfs +LIBRARY + EXPORTS + luaopen_lfs \ No newline at end of file diff --git a/luaclib/lfs/lfs.vcxproj b/luaclib/lfs/lfs.vcxproj index 65289b6..af5c6d3 100644 --- a/luaclib/lfs/lfs.vcxproj +++ b/luaclib/lfs/lfs.vcxproj @@ -53,6 +53,7 @@ true ..\..\deps\lua; nlua.lib + lfs.def copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) diff --git a/luaclib/lpeg/lpeg.def b/luaclib/lpeg/lpeg.def new file mode 100644 index 0000000..9a2fb87 --- /dev/null +++ b/luaclib/lpeg/lpeg.def @@ -0,0 +1,3 @@ +LIBRARY + EXPORTS + luaopen_lpeg \ No newline at end of file diff --git a/luaclib/luaclib.v12.suo b/luaclib/luaclib.v12.suo index 170cbe1ef1f7cf0ffb69ed76085a351f78faf565..c17d0b9260bc2b4f4748638dd9be695cf4edf865 100644 GIT binary patch delta 658 zcmaiwK}#D^5XW~m*<_P2|VW|c~wqNNRpHzCW$fP88J@WbUGcK;x)x3OeQ}>a4WYuqT7AR#c;2!RVCniu21sEFZr8(tocqUc`3eNh@LaltoJT zn_uJbk{>2t&7o|@98(Jlt3V@0%|3knV+if?2Bxe*u2=TD-~~Tt(|~RE7>(ru6C*`D z{kgl$d`^7|ry^8PFRJ%Gck5(H7!XG%H0HmMlr)P7iZ9NPG|A7JknZv u2>;m#>XjM%@cjtJaMVhnZob9+>eG)_fa{lEl1*I$y?Go5{gbVM4L0c8s>GJ0$-W$I>9bYWm%a0X&GAa(-cfB*mgcL&lAK%q(mH-}*`FubObMfXcEj-Mdx?C8+&IAPzOlES4Xak!h zNIC!JU%gd~NcK-YB5gBC$e9-$P8=wDdVu~HGF<$nhmo}qC?T@>r#L&)qz(@bkRuUB zcZ8sYTZca{BS;!0h)X(qH#1JT5;?iMUwc!T6eCeyp6pPez{Qo!ki}5Ukk61eIkrN4 xa^r`)ppcsEP}ww@smg9s)dALti5ih^5ddF$=sExZ diff --git a/luaclib/pb/pbc.vcxproj b/luaclib/pb/pbc.vcxproj index 21d7778..6ffa79b 100644 --- a/luaclib/pb/pbc.vcxproj +++ b/luaclib/pb/pbc.vcxproj @@ -56,6 +56,7 @@ true ..\..\deps\lua; nlua.lib + protobuf.def copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) diff --git a/luaclib/pb/protobuf.def b/luaclib/pb/protobuf.def new file mode 100644 index 0000000..ec1d04a --- /dev/null +++ b/luaclib/pb/protobuf.def @@ -0,0 +1,3 @@ +LIBRARY + EXPORTS + luaopen_protobuf_c \ No newline at end of file diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 8f5fe088a36839b6f28febf8e0822bf400466bcb..4d2a7b91843530afc6a45ce522f6f9e1df2f179f 100644 GIT binary patch delta 3347 zcmcJR4{+4Q702)U?su2Fa|b?_M}*uFYn13d18KBO+`NT*6&y>V(NZZytgpDXDMC z=5Px=3A8I%Ik=*xy3*01=36)6Vbx|$yS83BBnYWOk+4{JRJ~~BT$?AQn*?KixyW_G zR&~KjaarOiPHJk%%2>Tu3U>&Nf@qH1De^X9j&OspQrIcf2n&T9h5LnJp;fp?cucq= zeeV`oE0hRz!hNd6J^9ujNaC71;&Txpyt#5@_`SF4 z|5Ezh{d0$Z^?)8&M@8s4nibsVRoz*Z3VAcbi>5pZx9u7egP?Fr{)7mPu4}2=niS5| zv8xK6@B_c!6Bj&u(lWcH(bJzK!h@G_0_sHj%{}i^aCs|UQ*F!JaZFv5|5v#!0f)lg zeHXyKv+!}?aU_PX|J!fep)^=Qzf9)kK?Jw9;*e_F+Kz)yUBn{vyWVLV2n9$$-kJZ3z$J6;tgJm^Pbe7_DiV@F{R`kF?e*Y1LVj3WyAcJtAQKnu z+M9~=_GpaSTZ}3=j+&gQ&Ayo`_pvNK_DwAA`6~r8d?r-AXbR>Mo|iaYgv!m6h7ue{ zh(MAAojV(Y=wFJ~t65POj^>zoovQt}<8`~XmY5aq--QKwK{bAjE(^D~ZRrxZIj+pK zz{zcS7;(;)dYzlMIIyFCVRRs6GLSBp`1u95xzLVYzL<}Z_!mAKz8)?BQD`Nc{flH; z-8d&U%!xBP-KFqYUx+8-P|2Z8?yf|dE?R?uI6iP1%h-E2GIU)do(2aVMwPB=#tYz+ zn^37MThVLhy1THLbN8W;2Tr3{OaB^sXd8$d{w3Ao2E1+O;`PW?Cm%WPF{@? zU9thEWGU@MF;|^M6$d^>yxzS7&G!B#Sj3S!RO@>lLyk zaJ7uI>@bc<6crNRGo6Y0y8U?9&Nbh|LLPVmY3ij{oO)#s4%kC|G8Kn!g@=bvAxUQ) z$9oQL{=3<>-ZqmcpTu>eaTSNmi2YS4)P+ZI#=$*rV2!#aKS?(YAn4$}Z)5JL@7s^z zWqa3~$mer?@aU40l8~7E6>UR6Hg;q zulp1BPW*cID|3-Cd)DXsRmSzPEzLCF7kh2WdSDrf@D=UGp-g)~#J7YJWjS|DhJV&WwtBfBHQOGPjk+=V!nr|iPqopziP0?^cTj{f zC_XeSyMm9db8zEyN@M>FiiE@iM<$YA`(1J@aAXoibi_k`JD*CW5+0n7B;MztDSV!2 ziVh@Gz@hw0bGT*z9+f>WPgl&Q--(HNG>?l4L{F>+RLk5#UcO#d^lQ%#4UKP;m(CqKQ0Jd)tV6?BDP zx{YpBQz?Z9%E-xAZlf8pbx)=At_n&us3Nk)%43rM*^a`lb>!l*3fjbb?xGLJS$4Q3 z=LOt*FJ0odR?s|`RHIMS7YE9zbG%V0N9`Qxy5Hn{E#-kLcOz34J8Ee~Ekd z?yMzm!cw_*Z?JtwuFI>qw4SczYF<~14y QKVD0l{`d1d)IhHP06F9a6#xJL delta 4382 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 Date: Fri, 29 Apr 2016 02:38:50 +0800 Subject: [PATCH 087/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0luaclib=E5=85=B1?= =?UTF-8?q?=E4=BA=AB=E5=BA=93=E5=AF=BC=E5=87=BA=E7=AC=A6=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/lpeg/lpeg.vcxproj | 1 + sample/test.lua | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/luaclib/lpeg/lpeg.vcxproj b/luaclib/lpeg/lpeg.vcxproj index dfc2925..eaa8d9d 100644 --- a/luaclib/lpeg/lpeg.vcxproj +++ b/luaclib/lpeg/lpeg.vcxproj @@ -53,6 +53,7 @@ true ..\..\deps\lua; nlua.lib + lpeg.def copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) diff --git a/sample/test.lua b/sample/test.lua index c934d74..0f4ca13 100644 --- a/sample/test.lua +++ b/sample/test.lua @@ -3,10 +3,11 @@ package.path = package.path .. ";..\\lualib\\?.lua" package.cpath = package.cpath .. ";..\\luaclib\\?.dll" -print(require "mime") print(require "cjson") +print(require "lfs") +print(require "lpeg") print(require "mime") -print(require "mime") +print(require "protobuf") do return end From e5c3bcdb8bcd7673b64f37ee8247a7eab685915b Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 6 May 2016 20:34:50 +0800 Subject: [PATCH 088/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0logger=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/luaclib.v12.suo | Bin 71168 -> 74240 bytes node-lua.v12.suo | Bin 159232 -> 175616 bytes node-lua.vcxproj | 2 ++ node-lua.vcxproj.filters | 6 ++++++ src/context_log.cpp | 22 ++++++++++++++++++++++ src/context_log.h | 16 ++++++++++++++++ src/context_lua.cpp | 15 +++++++++++++-- src/context_lua.h | 1 + src/context_mgr.cpp | 9 ++++++++- src/context_mgr.h | 3 ++- src/node_lua.cpp | 8 +++++++- src/node_lua.h | 18 ++++++++++++++---- 12 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 src/context_log.cpp create mode 100644 src/context_log.h diff --git a/luaclib/luaclib.v12.suo b/luaclib/luaclib.v12.suo index c17d0b9260bc2b4f4748638dd9be695cf4edf865..06c616fc9480b614daa97bfcdf7d46f9e520af0e 100644 GIT binary patch delta 1640 zcmcIkUu;WJ7(d_LZF_CEchy}hYsogmh{$H17&?XpS-Z@C%Od_{Ms2mNGZpD=BQl1r z{Y?$*n@;%4;~~QN<4T()(6D+POH<32@jf}Ao2l@p+bYjxzlD|^15Xql7Rx%HcqA$-Sn~74gXtS3( zB7v7W9mG7CzmA$42(^T@gf)bEf|D>o%Y7jn!-a<1QqOk=Um6A!?KC2nQb=Tu6u$h= zQcP(nWi&LY(2Ggaf-`^w}QZD=A*yT6a1 z*H9s6$TlKzBv^{i3M5PfOCw%2DvyIjPlf^jyU?dJ-~*uwc4ATqzz*G4_(U+XX%sb= zK&z+o*nz%t0cgjhH2_D@R}?TDqG1(3p80ItO09bgKb>um=4HiT_Y9XAWMZsYZ1YU& zC_GzKnwXF6Wj*Ww>ttQ5jdieg;`Y%mU9V%k)b`M<{WNEPIw-4N$^@8B{X9ZOs>t6w z7Exg{j@oNt*Hoy>X+-<#@u9pJ4x+EPN#Z%qL_#YjiyO?q`}`~>`DXOl`r{?tP<@za zk-*E;;@u>+o#eJr-HK(xEXyJiDp5=kA+xN(Lmg57Xfp{?keVSvOcKEX;Ygz`nlIj8 zCc+5BFN%UL&Uw5Y2aZ?9ds+Zn-j}0xYzWI|&p~JJTeO~>iO%C844qgtMd3hY4?v`yt z{Mu#bTr#(ykQI@(9UQ`B(Nme{G23g|9xTZU!tQ>}n0B20>Ae4+4-gh%?TqToiG@vq zd+O8wbL-kk>EBp4vZVqmqB302tD=v{7%jVh=Y<>24~p&_SIig+FSXyJz4%pO4Cqft zl{O~{h@CaV)z}pkHpH|-xQqkg%KP;exGLZhn-wbs2}BHrSI3-1bd~zTHGEbbzgT-P zVRu|o!5Pz3&<0;aF=}5{;rfZqg9-Xp{P%5#Xd^jZ-Zx3-B_{v? delta 1774 zcmb_dO>7%g5Z>9?&Nf-E-NgBAYPC@zL1?4(+VQSKKyC>_q*CHGZPgNRvtHX0sBJ>( zP1F2fH&hg;D$-1qb$9OBCNJQf+75hJ zduT!20I66Khd`(&M~d63=`31T2gQA5YKKl@Ny@{UMa#Fwdx4c)R~dB?tvYHuE4QVR zAIDN%9>&nB&%-E|>c1CQv$nH(PSWHN;AWs7S3g!TcO$_h@-!1I`Ec{vfFM@5!+Ert zhXfYQhNJ5_EH%@{d&rH6y2Bf2wOn6n;aR9j1R5w0Yh)8yRwH}I zbj>fAaJyX2RC<&Bt9M^lEwYvh~SH`#$-GBBpxh`&ko|7~i=SI1= z9e4lMBu7Mwv$!lio;iid>2^opZ}TLu^gsd$@~qWtycMVWbVMFH(WB63+RUoyv>8@q z-89m2D3n&^SXfbIMd^M-<*-&cb-{m+4@bHcXUx)ecG3sorA=O#qkQbA2ZdnUPD|Pz z2q0D4YZ9pa|KGOuun%tMzgUQKRTU?W>JeSjbzN4Kh`~-AmUS(Yq7$1+B&)@=kkQR5 zE;lHx>CupCYH}kxexfW!dwrp;|Yk z*A-KXXz7@t%(5>(yGT2O6$uqZh9em*n$bgYCbLzfA{!YsLs<;Pj49b{)(r2;^3?d& zrzf!UerUn@#tu8~hfnMkKLpsL?Mq=V+~)E4N^5ob|HQsl53$7n^x3We^xAz5(2EN1 nvf~X9$C0M^-NJqVztCkq{=Da_+R4sP;NiWW4Eh2p|4RM^-)uUH diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 4d2a7b91843530afc6a45ce522f6f9e1df2f179f..8284dfa500beb2b3754146966642fe9721c27ccb 100644 GIT binary patch delta 11114 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 delta 7715 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 FzX7iUPF4T_ diff --git a/node-lua.vcxproj b/node-lua.vcxproj index f178cc5..c550084 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -96,6 +96,7 @@ + @@ -128,6 +129,7 @@ + diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index ec3de5e..4b3d97e 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -105,6 +105,9 @@ include + + include + @@ -188,5 +191,8 @@ src + + src + \ No newline at end of file diff --git a/src/context_log.cpp b/src/context_log.cpp new file mode 100644 index 0000000..823637e --- /dev/null +++ b/src/context_log.cpp @@ -0,0 +1,22 @@ +#include "context_log.h" + +bool context_log_t::init(int32_t argc, char* argv[], char* env[]) +{ + return true; +} + +bool context_log_t::deinit(const char *arg) +{ + return true; +} + +void context_log_t::on_received(message_t& message) +{ + +} + +void context_log_t::on_dropped(message_t& message) +{ + +} + diff --git a/src/context_log.h b/src/context_log.h new file mode 100644 index 0000000..e9b52f7 --- /dev/null +++ b/src/context_log.h @@ -0,0 +1,16 @@ +#ifndef CONTEXT_LOG_H_ +#define CONTEXT_LOG_H_ + +#include "common.h" +#include "request.h" +#include "context.h" + +class context_log_t : public context_t { +public: + bool init(int32_t argc, char* argv[], char* env[]); + bool deinit(const char *arg); + void on_received(message_t& message); + void on_dropped(message_t& message); +}; + +#endif \ No newline at end of file diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 2a76368..257000f 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -891,8 +891,11 @@ int32_t context_lua_t::context_destroy(lua_State *L) singleton_ref(node_lua_t).context_destroy(src_handle, src_handle, lua_tostring(L, 1)); return 0; } - int32_t handle = luaL_checkunsigned(L, 1); - if (handle > 0) { + uint32_t handle = luaL_checkunsigned(L, 1); + if (handle <= 1) { + luaL_error(L, "illegal "); + } + if (handle > 1) { singleton_ref(node_lua_t).context_destroy(handle, src_handle, lua_tostring(L, 2)); } return 0; @@ -1288,6 +1291,13 @@ int32_t context_lua_t::context_thread(lua_State *L) return 1; } +int32_t context_lua_t::context_log(lua_State *L) +{ + context_lua_t* lctx = context_lua_t::lua_get_context(L); + + return 0; +} + int luaopen_context(lua_State *L) { luaL_Reg l[] = { @@ -1301,6 +1311,7 @@ int luaopen_context(lua_State *L) { "reply", context_lua_t::context_reply }, { "recv", context_lua_t::context_recv }, { "wait", context_lua_t::context_wait }, + { "log", context_lua_t::context_log }, { NULL, NULL }, }; luaL_newlib(L, l); diff --git a/src/context_lua.h b/src/context_lua.h index af4eb61..28dfeeb 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -161,6 +161,7 @@ class context_lua_t : public context_t { static int32_t context_reply(lua_State *L); static int32_t context_recv(lua_State *L); static int32_t context_wait(lua_State *L); + static int32_t context_log(lua_State *L); /************ the above are context lua api ************/ public: diff --git a/src/context_mgr.cpp b/src/context_mgr.cpp index 5e50752..d030ffe 100644 --- a/src/context_mgr.cpp +++ b/src/context_mgr.cpp @@ -20,6 +20,13 @@ context_mgr_t::~context_mgr_t() } } +void context_mgr_t::set_handle_index(uint32_t index) +{ + uv_rwlock_wrlock(&m_lock); + m_handle_index = index; + uv_rwlock_wrunlock(&m_lock); +} + void context_mgr_t::expand_slot() { uint32_t new_cap = m_slot_cap << 2; @@ -35,7 +42,7 @@ void context_mgr_t::expand_slot() m_slot_cap = new_cap; } -bool context_mgr_t::register_context(context_t* ctx, int32_t parent) +bool context_mgr_t::register_context(context_t* ctx, uint32_t parent) { uv_rwlock_wrlock(&m_lock); if (m_ctx_size == MAX_CTX_SIZE || ctx->get_handle() != 0) { diff --git a/src/context_mgr.h b/src/context_mgr.h index 769b11d..3bf603d 100644 --- a/src/context_mgr.h +++ b/src/context_mgr.h @@ -7,9 +7,10 @@ class context_mgr_t { public: context_mgr_t(); ~context_mgr_t(); - bool register_context(context_t* ctx, int32_t parent); + bool register_context(context_t* ctx, uint32_t parent); void retire_context(context_t* ctx); context_t* grab_context(uint32_t handle); + void set_handle_index(uint32_t index); uint32_t get_context_count() const { return m_ctx_size; } private: void expand_slot(); diff --git a/src/node_lua.cpp b/src/node_lua.cpp index 130d40b..bdf8284 100644 --- a/src/node_lua.cpp +++ b/src/node_lua.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "context.h" #include "network.h" +#include "context_log.h" #include "context_lua.h" #include "context_mgr.h" #include "worker_mgr.h" @@ -36,7 +37,12 @@ node_lua_t::node_lua_t(int argc, char* argv[], char* env[]) m_worker_mgr = new worker_mgr_t(); m_network->start(); m_worker_mgr->start(); - context_create(0, argc, argv, env); + m_ctx_mgr->set_handle_index(MAX_CTX_SIZE); + m_logger = context_create(0, 0, NULL, NULL); + if (m_logger > 0) { + m_ctx_mgr->set_handle_index(1); + context_create(0, argc, argv, env); + } m_worker_mgr->wait(); m_network->stop(); m_network->wait(); diff --git a/src/node_lua.h b/src/node_lua.h index 131150b..af01c59 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -131,9 +131,7 @@ class node_lua_t : public singleton_t { m_ctx_mgr->retire_context(ctx); } ctx->release(); - if (m_ctx_mgr->get_context_count() == 0) { - m_worker_mgr->stop(); - } + context_check_alive(parent); return 0; } @@ -173,8 +171,19 @@ class node_lua_t : public singleton_t { ctx->deinit(buffer); /* ctx->m_handle is valid in this function. */ ctx->set_inited(false); m_ctx_mgr->retire_context(ctx); - if (m_ctx_mgr->get_context_count() == 0) { + context_check_alive(src_handle); + } + + void context_check_alive(uint32_t src_handle) + { + uint32_t ctx_size = m_ctx_mgr->get_context_count(); + if (ctx_size == 1) { + context_destroy(m_logger, src_handle, NULL); + return; + } + if (ctx_size == 0) { m_worker_mgr->stop(); + return; } } @@ -182,6 +191,7 @@ class node_lua_t : public singleton_t { network_t *m_network; context_mgr_t *m_ctx_mgr; worker_mgr_t *m_worker_mgr; + uint32_t m_logger; public: static int32_t m_cpu_count; From 830bc417624cceb2494015e305d787b6dca25b0d Mon Sep 17 00:00:00 2001 From: xdczju Date: Sat, 7 May 2016 15:10:04 +0800 Subject: [PATCH 089/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0sds=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.v12.suo | Bin 175616 -> 163840 bytes node-lua.vcxproj | 3 + node-lua.vcxproj.filters | 9 + src/common.h | 6 +- src/context_lua.cpp | 2 +- src/message.cpp | 2 +- src/message.h | 7 +- src/nlmalloc.h | 12 + src/sds.cpp | 882 +++++++++++++++++++++++++++++++++++++++ src/sds.h | 100 +++++ 10 files changed, 1013 insertions(+), 10 deletions(-) create mode 100644 src/nlmalloc.h create mode 100644 src/sds.cpp create mode 100644 src/sds.h diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 8284dfa500beb2b3754146966642fe9721c27ccb..6a66efc98659a853db254600a17d97497852c709 100644 GIT binary patch delta 1903 zcmbW2e@s(X6vyAWywV?*rfL}|YMPXb3F5)QNxuxCW+!C{we7NtP zd)__YbI!fRd&S`O8un(5$P@%2o)`#+!!!tS#Ph@l==vl-5ephJa6J zN#N?Z68@~fvAQIv!0Fi zV?M!9nrf4-&GQ*83wDulI5ogc<5EIL>>-{akXTH-OOz2jkV4~DB8|S`bN*Oq?jdRr z#H1ScsDwi_8C(j7x2O%qmEd;(YjaB`l!{UZ6+a}OLB&N*-EaJZm?3!GiC?pH^xSaj zekUVPDDJ5_NI4a#eHB`{-3XlkUOd(DlEPNPWaYq0Fe=hTFsift-NR9y9IeZp=%#Tk zOi&u)!Kxf6014BX2|Lefa6FEQ823@qR{3*ul=2fcehYl@D*`g|Mkpa)L$(mg9aYg#pR3Yhj z5q~1@NcyX2>9E>&LmTfu!k99)7*ZAY9x$o)-U~zW){)yQgqLU|b`t+=?tHSvn#;G| zOY>NB_tAT-xqOXZnJHBHznkmrn))xDMeiT7DnIN8l#ZuHj^1X{nTO>E>F8~ebhl_< zG1@^49$%z^dpuHu2~x0II}|-9s{NV329NWARRg~~x;)_2^^&EB;8jqA14d|PVAEma z23w>+|NkU~wajl}6gxu>$Y!__hu(uS%8i4CzZ(sSp4+54_=v3F?F&3ty+XN`(u#m~ zHA%5}S&`!1%3L*WW8jXL4FzA36p)gk8$S}I-o|MyFTO*_i%?=X)I569nWl0nA zg~fplUldLmx$v77=klKGEfewH%j1=jGNvDvFMKp(&9d9)&2y)I+uXMQOky0CPES;> zFJ>b~3njuj+RR0px`h`mw?F7A=vbny@7cBb+UqW~Pqe7^OUuA)e52uHZjbHs_Hk-; zPQ$%3d<9!BFY!4gl$z*D{z^IA;Cb+iRz_JBV!36K+SFtPo~UsXnfQ-1fA#^h2CO3? z4jPC6d_T&p5&DYC4uk|04g=*o267**bGg+ zaISTl;z)!}|9D{LoO7k>#`@<#UyvMdyPQA*~Yt3K_*wWw{BwYP$du~?p_bxbl?5jD{MQe>)6R>Y%7ofI^ sb;2B_G6fvU-FApq3M-kcOxnu6drVkCB$ioy|aSy-KwPQd)O-ww?ujhQP zbAIRhzH?Vw8&~^%+?J;vYLp}?hS1&9(?gSFBA5xAv7{sGaMeoiv5J_l4z1m|_yc^6 z)xiP%274IfE^ zY2hWzCOi$2w1Q^ZvS$v>D+xKIdkdS*!|e-5@)N2FZxEIc1gFAda~4(J<`fS;#XdmL ziVh!+P=?Av!l&dNP$lTeYbhE#We;?t+mbX+Y`&OKM|hr4L?|REg!^*eK*qbdiv;xN zJ{_Aa=@!9x7GVi?4KSd4Ye}v@8)UsRP6l6veO{F5GvqRtFo`a`iRK}M<%F>$3!nbC zT1Wb5oR}SV$uiX~31-mm&;fh<*&6g+6~*97`1np5i_6JpDxsEegdqB$o@Q}&e_rCO zC@--V3E8{QL8Rgt`R5Epa{8-V6b|o1#Xh` zXH=ur%oMKX_ZbxwLuc|W5N6nCKO44V@GM2%AZ)qYQQc|T#sa(pC%A_j#E0{g2#rOHTo5!*?7N~r$1Kp3>4R;E>0Jes9 zZFTX)y$v4a+L?LzZA*oTA4r8c;6?bRR4@DPczZ1|Q*tbY8U?5_I?FruchP zh^{NDBKE&R-r@`%OoOI7QyOIx@C7VT4&~Cr#faw`owQh>rRt;`d1qtPrpQJIcVRpmWeJ3y37JND?sE&>LWi zDzxpJ3~)jZ9DNLOz&87fW%}!lnah6s^rOo!&DTtPQW+b}Qq7LSz z`yu&nPa`(>l4+j8lK8+P7H@cqm=FAUaEKoo4O4kX9xQ+w@y}sv)ymyB!+Zjxfc?Wt z`$vHW`;8T&Uy=keRb6 qEjA-{5&PO~iKTTSArA*$bn}XZ%)_rvVTnd{1*=Q?-*2+}BKr#p`Q$hN diff --git a/node-lua.vcxproj b/node-lua.vcxproj index c550084..6a80bcc 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -111,10 +111,12 @@ + + @@ -148,6 +150,7 @@ + diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index 4b3d97e..22dc214 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -108,6 +108,12 @@ include + + include + + + include + @@ -194,5 +200,8 @@ src + + src + \ No newline at end of file diff --git a/src/common.h b/src/common.h index 32625e1..7f8d823 100644 --- a/src/common.h +++ b/src/common.h @@ -37,13 +37,9 @@ #include "latomic.h" #include "utils.h" #include "errors.h" +#include "nlmalloc.h" #define nl (singleton_ref(node_lua_t)) -#define nl_malloc malloc -#define nl_free free -#define nl_calloc calloc -#define nl_realloc realloc -#define nl_strdup strdup #if defined __GNUC__ #define likely(x) __builtin_expect ((x), 1) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 257000f..f3f2ef0 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -63,7 +63,7 @@ bool context_lua_t::init(int32_t argc, char* argv[], char* env[]) } lua_pushstring(m_lstate, lua_path); lua_pushstring(m_lstate, lua_cpath); - char* args = (char*)nl_calloc(total_length, 1); + char* args = (char*)nl_calloc(total_length); char* argp = args; for (int32_t i = 0; i < argc; ++i) { memcpy(argp, argv[i], lengths[i]); diff --git a/src/message.cpp b/src/message.cpp index b16de82..e6bdcac 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -1,7 +1,7 @@ #include "message.h" message_array_t* message_array_create(uint32_t count) { - message_array_t* array = (message_array_t*)nl_calloc(1, sizeof(message_array_t) + (count - 1)*sizeof(message_t)); + message_array_t* array = (message_array_t*)nl_calloc(sizeof(message_array_t) + (count - 1)*sizeof(message_t)); array->m_count = count; return array; } diff --git a/src/message.h b/src/message.h index 850f343..bdac94e 100644 --- a/src/message.h +++ b/src/message.h @@ -19,9 +19,10 @@ enum data_type { INTEGER = 4, //support after lua53 BUFFER = 5, //need to be freed STRING = 6, //need to be freed - BSON = 7, //need to be freed - ARRAY = 8, //need to be freed - TERROR = 9 // + SDS = 7, //need to be freed + BSON = 8, //need to be freed + ARRAY = 9, //need to be freed + TERROR = 10 // }; typedef union data_t { diff --git a/src/nlmalloc.h b/src/nlmalloc.h new file mode 100644 index 0000000..1c4c347 --- /dev/null +++ b/src/nlmalloc.h @@ -0,0 +1,12 @@ +#ifndef NLMALLOC_H_ +#define NLMALLOC_H_ +#include +#include + +#define nl_malloc malloc +#define nl_free free +#define nl_calloc(size) calloc(1, size) +#define nl_realloc realloc +#define nl_strdup strdup + +#endif diff --git a/src/sds.cpp b/src/sds.cpp new file mode 100644 index 0000000..08130fd --- /dev/null +++ b/src/sds.cpp @@ -0,0 +1,882 @@ +/* SDSLib, A C dynamic strings library + * + * Copyright (c) 2006-2012, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include "sds.h" +#include "nlmalloc.h" + +/* Create a new sds string with the content specified by the 'init' pointer + * and 'initlen'. + * If NULL is used for 'init' the string is initialized with zero bytes. + * + * The string is always null-termined (all the sds strings are, always) so + * even if you create an sds string with: + * + * mystring = sdsnewlen("abc",3"); + * + * You can print the string with printf() as there is an implicit \0 at the + * end of the string. However the string is binary safe and can contain + * \0 characters in the middle, as the length is stored in the sds header. */ +sds sdsnewlen(const void *init, size_t initlen) { + struct sdshdr *sh; + + if (init) { + sh = (struct sdshdr *)nl_malloc(sizeof(struct sdshdr) + initlen + 1); + } else { + sh = (struct sdshdr *)nl_calloc(sizeof(struct sdshdr) + initlen + 1); + } + if (sh == NULL) return NULL; + sh->len = initlen; + sh->free = 0; + if (initlen && init) + memcpy(sh->buf, init, initlen); + sh->buf[initlen] = '\0'; + return (char*)sh->buf; +} + +/* Create an empty (zero length) sds string. Even in this case the string + * always has an implicit null term. */ +sds sdsempty(void) { + return sdsnewlen("",0); +} + +/* Create a new sds string starting from a null termined C string. */ +sds sdsnew(const char *init) { + size_t initlen = (init == NULL) ? 0 : strlen(init); + return sdsnewlen(init, initlen); +} + +/* Duplicate an sds string. */ +sds sdsdup(const sds s) { + return sdsnewlen(s, sdslen(s)); +} + +/* Free an sds string. No operation is performed if 's' is NULL. */ +void sdsfree(sds s) { + if (s == NULL) return; + nl_free(s-sizeof(struct sdshdr)); +} + +/* Set the sds string length to the length as obtained with strlen(), so + * considering as content only up to the first null term character. + * + * This function is useful when the sds string is hacked manually in some + * way, like in the following example: + * + * s = sdsnew("foobar"); + * s[2] = '\0'; + * sdsupdatelen(s); + * printf("%d\n", sdslen(s)); + * + * The output will be "2", but if we comment out the call to sdsupdatelen() + * the output will be "6" as the string was modified but the logical length + * remains 6 bytes. */ +void sdsupdatelen(sds s) { + struct sdshdr *sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + int reallen = strlen(s); + sh->free += (sh->len-reallen); + sh->len = reallen; +} + +/* Modify an sds string on-place to make it empty (zero length). + * However all the existing buffer is not discarded but set as free space + * so that next append operations will not require allocations up to the + * number of bytes previously available. */ +void sdsclear(sds s) { + struct sdshdr *sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + sh->free += sh->len; + sh->len = 0; + sh->buf[0] = '\0'; +} + +/* Enlarge the free space at the end of the sds string so that the caller + * is sure that after calling this function can overwrite up to addlen + * bytes after the end of the string, plus one more byte for nul term. + * + * Note: this does not change the *length* of the sds string as returned + * by sdslen(), but only the free buffer space we have. */ +sds sdsMakeRoomFor(sds s, size_t addlen) { + struct sdshdr *sh, *newsh; + size_t free = sdsavail(s); + size_t len, newlen; + + if (free >= addlen) return s; + len = sdslen(s); + sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + newlen = (len+addlen); + if (newlen < SDS_MAX_PREALLOC) + newlen *= 2; + else + newlen += SDS_MAX_PREALLOC; + newsh = (struct sdshdr*)nl_realloc(sh, sizeof(struct sdshdr) + newlen + 1); + if (newsh == NULL) return NULL; + + newsh->free = newlen - len; + return newsh->buf; +} + +/* Reallocate the sds string so that it has no free space at the end. The + * contained string remains not altered, but next concatenation operations + * will require a reallocation. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdsRemoveFreeSpace(sds s) { + struct sdshdr *sh; + + sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + sh = (struct sdshdr*)nl_realloc(sh, sizeof(struct sdshdr) + sh->len + 1); + sh->free = 0; + return sh->buf; +} + +/* Return the total size of the allocation of the specifed sds string, + * including: + * 1) The sds header before the pointer. + * 2) The string. + * 3) The free buffer at the end if any. + * 4) The implicit null term. + */ +size_t sdsAllocSize(sds s) { + struct sdshdr *sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + + return sizeof(*sh)+sh->len+sh->free+1; +} + +/* Increment the sds length and decrements the left free space at the + * end of the string according to 'incr'. Also set the null term + * in the new end of the string. + * + * This function is used in order to fix the string length after the + * user calls sdsMakeRoomFor(), writes something after the end of + * the current string, and finally needs to set the new length. + * + * Note: it is possible to use a negative increment in order to + * right-trim the string. + * + * Usage example: + * + * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the + * following schema, to cat bytes coming from the kernel to the end of an + * sds string without copying into an intermediate buffer: + * + * oldlen = sdslen(s); + * s = sdsMakeRoomFor(s, BUFFER_SIZE); + * nread = read(fd, s+oldlen, BUFFER_SIZE); + * ... check for nread <= 0 and handle it ... + * sdsIncrLen(s, nread); + */ +void sdsIncrLen(sds s, int incr) { + struct sdshdr *sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + + assert(sh->free >= incr); + sh->len += incr; + sh->free -= incr; + assert(sh->free >= 0); + s[sh->len] = '\0'; +} + +/* Grow the sds to have the specified length. Bytes that were not part of + * the original length of the sds will be set to zero. + * + * if the specified length is smaller than the current length, no operation + * is performed. */ +sds sdsgrowzero(sds s, size_t len) { + struct sdshdr *sh = (struct sdshdr*)(s - (sizeof(struct sdshdr))); + size_t totlen, curlen = sh->len; + + if (len <= curlen) return s; + s = sdsMakeRoomFor(s,len-curlen); + if (s == NULL) return NULL; + + /* Make sure added region doesn't contain garbage */ + sh = (struct sdshdr*)(s - (sizeof(struct sdshdr))); + memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */ + totlen = sh->len+sh->free; + sh->len = len; + sh->free = totlen-sh->len; + return s; +} + +/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the + * end of the specified sds string 's'. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatlen(sds s, const void *t, size_t len) { + struct sdshdr *sh; + size_t curlen = sdslen(s); + + s = sdsMakeRoomFor(s,len); + if (s == NULL) return NULL; + sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + memcpy(s+curlen, t, len); + sh->len = curlen+len; + sh->free = sh->free-len; + s[curlen+len] = '\0'; + return s; +} + +/* Append the specified null termianted C string to the sds string 's'. + * + * After the call, the passed sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscat(sds s, const char *t) { + return sdscatlen(s, t, strlen(t)); +} + +/* Append the specified sds 't' to the existing sds 's'. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatsds(sds s, const sds t) { + return sdscatlen(s, t, sdslen(t)); +} + +/* Destructively modify the sds string 's' to hold the specified binary + * safe string pointed by 't' of length 'len' bytes. */ +sds sdscpylen(sds s, const char *t, size_t len) { + struct sdshdr *sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + size_t totlen = sh->free+sh->len; + + if (totlen < len) { + s = sdsMakeRoomFor(s,len-sh->len); + if (s == NULL) return NULL; + sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + totlen = sh->free+sh->len; + } + memcpy(s, t, len); + s[len] = '\0'; + sh->len = len; + sh->free = totlen-len; + return s; +} + +/* Like sdscpylen() but 't' must be a null-termined string so that the length + * of the string is obtained with strlen(). */ +sds sdscpy(sds s, const char *t) { + return sdscpylen(s, t, strlen(t)); +} + +/* Like sdscatpritf() but gets va_list instead of being variadic. */ +sds sdscatvprintf(sds s, const char *fmt, va_list ap) { + va_list cpy; + char *buf, *t; + size_t buflen = 16; + + while(1) { + buf = (char *)nl_malloc(buflen); + if (buf == NULL) return NULL; + buf[buflen-2] = '\0'; + va_copy(cpy,ap); + vsnprintf(buf, buflen, fmt, cpy); + if (buf[buflen-2] != '\0') { + nl_free(buf); + buflen *= 2; + continue; + } + break; + } + t = sdscat(s, buf); + nl_free(buf); + return t; +} + +/* Append to the sds string 's' a string obtained using printf-alike format + * specifier. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. + * + * Example: + * + * s = sdsempty("Sum is: "); + * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b). + * + * Often you need to create a string from scratch with the printf-alike + * format. When this is the need, just use sdsempty() as the target string: + * + * s = sdscatprintf(sdsempty(), "... your format ...", args); + */ +sds sdscatprintf(sds s, const char *fmt, ...) { + va_list ap; + char *t; + va_start(ap, fmt); + t = sdscatvprintf(s,fmt,ap); + va_end(ap); + return t; +} + +/* Remove the part of the string from left and from right composed just of + * contiguous characters found in 'cset', that is a null terminted C string. + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. + * + * Example: + * + * s = sdsnew("AA...AA.a.aa.aHelloWorld :::"); + * s = sdstrim(s,"A. :"); + * printf("%s\n", s); + * + * Output will be just "Hello World". + */ +sds sdstrim(sds s, const char *cset) { + struct sdshdr *sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + char *start, *end, *sp, *ep; + size_t len; + + sp = start = s; + ep = end = s+sdslen(s)-1; + while(sp <= end && strchr(cset, *sp)) sp++; + while(ep > start && strchr(cset, *ep)) ep--; + len = (sp > ep) ? 0 : ((ep-sp)+1); + if (sh->buf != sp) memmove(sh->buf, sp, len); + sh->buf[len] = '\0'; + sh->free = sh->free+(sh->len-len); + sh->len = len; + return s; +} + +/* Turn the string into a smaller (or equal) string containing only the + * substring specified by the 'start' and 'end' indexes. + * + * start and end can be negative, where -1 means the last character of the + * string, -2 the penultimate character, and so forth. + * + * The interval is inclusive, so the start and end characters will be part + * of the resulting string. + * + * The string is modified in-place. + * + * Example: + * + * s = sdsnew("Hello World"); + * sdstrim(s,1,-1); => "ello Worl" + */ +void sdsrange(sds s, int start, int end) { + struct sdshdr *sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + size_t newlen, len = sdslen(s); + + if (len == 0) return; + if (start < 0) { + start = len+start; + if (start < 0) start = 0; + } + if (end < 0) { + end = len+end; + if (end < 0) end = 0; + } + newlen = (start > end) ? 0 : (end-start)+1; + if (newlen != 0) { + if (start >= (signed)len) { + newlen = 0; + } else if (end >= (signed)len) { + end = len-1; + newlen = (start > end) ? 0 : (end-start)+1; + } + } else { + start = 0; + } + if (start && newlen) memmove(sh->buf, sh->buf+start, newlen); + sh->buf[newlen] = 0; + sh->free = sh->free+(sh->len-newlen); + sh->len = newlen; +} + +/* Apply tolower() to every character of the sds string 's'. */ +void sdstolower(sds s) { + int len = sdslen(s), j; + + for (j = 0; j < len; j++) s[j] = tolower(s[j]); +} + +/* Apply toupper() to every character of the sds string 's'. */ +void sdstoupper(sds s) { + int len = sdslen(s), j; + + for (j = 0; j < len; j++) s[j] = toupper(s[j]); +} + +/* Compare two sds strings s1 and s2 with memcmp(). + * + * Return value: + * + * 1 if s1 > s2. + * -1 if s1 < s2. + * 0 if s1 and s2 are exactly the same binary string. + * + * If two strings share exactly the same prefix, but one of the two has + * additional characters, the longer string is considered to be greater than + * the smaller one. */ +int sdscmp(const sds s1, const sds s2) { + size_t l1, l2, minlen; + int cmp; + + l1 = sdslen(s1); + l2 = sdslen(s2); + minlen = (l1 < l2) ? l1 : l2; + cmp = memcmp(s1,s2,minlen); + if (cmp == 0) return l1-l2; + return cmp; +} + +/* Split 's' with separator in 'sep'. An array + * of sds strings is returned. *count will be set + * by reference to the number of tokens returned. + * + * On out of memory, zero length string, zero length + * separator, NULL is returned. + * + * Note that 'sep' is able to split a string using + * a multi-character separator. For example + * sdssplit("foo_-_bar","_-_"); will return two + * elements "foo" and "bar". + * + * This version of the function is binary-safe but + * requires length arguments. sdssplit() is just the + * same function but for zero-terminated strings. + */ +sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) { + int elements = 0, slots = 5, start = 0, j; + sds *tokens; + + if (seplen < 1 || len < 0) return NULL; + + tokens = (sds *)nl_malloc(sizeof(sds)*slots); + if (tokens == NULL) return NULL; + + if (len == 0) { + *count = 0; + return tokens; + } + for (j = 0; j < (len-(seplen-1)); j++) { + /* make sure there is room for the next element and the final one */ + if (slots < elements+2) { + sds *newtokens; + + slots *= 2; + newtokens = (sds *)nl_realloc(tokens, sizeof(sds)*slots); + if (newtokens == NULL) goto cleanup; + tokens = newtokens; + } + /* search the separator */ + if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) { + tokens[elements] = sdsnewlen(s+start,j-start); + if (tokens[elements] == NULL) goto cleanup; + elements++; + start = j+seplen; + j = j+seplen-1; /* skip the separator */ + } + } + /* Add the final element. We are sure there is room in the tokens array. */ + tokens[elements] = sdsnewlen(s+start,len-start); + if (tokens[elements] == NULL) goto cleanup; + elements++; + *count = elements; + return tokens; + +cleanup: + { + int i; + for (i = 0; i < elements; i++) sdsfree(tokens[i]); + nl_free(tokens); + *count = 0; + return NULL; + } +} + +/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */ +void sdsfreesplitres(sds *tokens, int count) { + if (!tokens) return; + while(count--) + sdsfree(tokens[count]); + nl_free(tokens); +} + +/* Create an sds string from a long long value. It is much faster than: + * + * sdscatprintf(sdsempty(),"%lld\n", value); + */ +sds sdsfromlonglong(long long value) { + char buf[32], *p; + unsigned long long v; + + v = (value < 0) ? -value : value; + p = buf+31; /* point to the last character */ + do { + *p-- = '0'+(v%10); + v /= 10; + } while(v); + if (value < 0) *p-- = '-'; + p++; + return sdsnewlen(p,32-(p-buf)); +} + +/* Append to the sds string "s" an escaped string representation where + * all the non-printable characters (tested with isprint()) are turned into + * escapes in the form "\n\r\a...." or "\x". + * + * After the call, the modified sds string is no longer valid and all the + * references must be substituted with the new pointer returned by the call. */ +sds sdscatrepr(sds s, const char *p, size_t len) { + s = sdscatlen(s,"\"",1); + while(len--) { + switch(*p) { + case '\\': + case '"': + s = sdscatprintf(s,"\\%c",*p); + break; + case '\n': s = sdscatlen(s,"\\n",2); break; + case '\r': s = sdscatlen(s,"\\r",2); break; + case '\t': s = sdscatlen(s,"\\t",2); break; + case '\a': s = sdscatlen(s,"\\a",2); break; + case '\b': s = sdscatlen(s,"\\b",2); break; + default: + if (isprint(*p)) + s = sdscatprintf(s,"%c",*p); + else + s = sdscatprintf(s,"\\x%02x",(unsigned char)*p); + break; + } + p++; + } + return sdscatlen(s,"\"",1); +} + +/* Helper function for sdssplitargs() that returns non zero if 'c' + * is a valid hex digit. */ +int is_hex_digit(char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); +} + +/* Helper function for sdssplitargs() that converts an hex digit into an + * integer from 0 to 15 */ +int hex_digit_to_int(char c) { + switch(c) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': case 'A': return 10; + case 'b': case 'B': return 11; + case 'c': case 'C': return 12; + case 'd': case 'D': return 13; + case 'e': case 'E': return 14; + case 'f': case 'F': return 15; + default: return 0; + } +} + +/* Split a line into arguments, where every argument can be in the + * following programming-language REPL-alike form: + * + * foo bar "newline are supported\n" and "\xff\x00otherstuff" + * + * The number of arguments is stored into *argc, and an array + * of sds is returned. + * + * The caller should free the resulting array of sds strings with + * sdsfreesplitres(). + * + * Note that sdscatrepr() is able to convert back a string into + * a quoted string in the same format sdssplitargs() is able to parse. + * + * The function returns the allocated tokens on success, even when the + * input string is empty, or NULL if the input contains unbalanced + * quotes or closed quotes followed by non space characters + * as in: "foo"bar or "foo' + */ +sds *sdssplitargs(const char *line, int *argc) { + const char *p = line; + char *current = NULL; + char **vector = NULL; + + *argc = 0; + while(1) { + /* skip blanks */ + while(*p && isspace(*p)) p++; + if (*p) { + /* get a token */ + int inq=0; /* set to 1 if we are in "quotes" */ + int insq=0; /* set to 1 if we are in 'single quotes' */ + int done=0; + + if (current == NULL) current = sdsempty(); + while(!done) { + if (inq) { + if (*p == '\\' && *(p+1) == 'x' && + is_hex_digit(*(p+2)) && + is_hex_digit(*(p+3))) + { + unsigned char byte; + + byte = (hex_digit_to_int(*(p+2))*16)+ + hex_digit_to_int(*(p+3)); + current = sdscatlen(current,(char*)&byte,1); + p += 3; + } else if (*p == '\\' && *(p+1)) { + char c; + + p++; + switch(*p) { + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'b': c = '\b'; break; + case 'a': c = '\a'; break; + default: c = *p; break; + } + current = sdscatlen(current,&c,1); + } else if (*p == '"') { + /* closing quote must be followed by a space or + * nothing at all. */ + if (*(p+1) && !isspace(*(p+1))) goto err; + done=1; + } else if (!*p) { + /* unterminated quotes */ + goto err; + } else { + current = sdscatlen(current,p,1); + } + } else if (insq) { + if (*p == '\\' && *(p+1) == '\'') { + p++; + current = sdscatlen(current,"'",1); + } else if (*p == '\'') { + /* closing quote must be followed by a space or + * nothing at all. */ + if (*(p+1) && !isspace(*(p+1))) goto err; + done=1; + } else if (!*p) { + /* unterminated quotes */ + goto err; + } else { + current = sdscatlen(current,p,1); + } + } else { + switch(*p) { + case ' ': + case '\n': + case '\r': + case '\t': + case '\0': + done=1; + break; + case '"': + inq=1; + break; + case '\'': + insq=1; + break; + default: + current = sdscatlen(current,p,1); + break; + } + } + if (*p) p++; + } + /* add the token to the vector */ + vector = (char **)nl_realloc(vector, ((*argc) + 1)*sizeof(char*)); + vector[*argc] = current; + (*argc)++; + current = NULL; + } else { + /* Even on empty input string return something not NULL. */ + if (vector == NULL) vector = (char **)nl_malloc(sizeof(void*)); + return vector; + } + } + +err: + while((*argc)--) + sdsfree(vector[*argc]); + nl_free(vector); + if (current) sdsfree(current); + *argc = 0; + return NULL; +} + +/* Modify the string substituting all the occurrences of the set of + * characters specified in the 'from' string to the corresponding character + * in the 'to' array. + * + * For instance: sdsmapchars(mystring, "ho", "01", 2) + * will have the effect of turning the string "hello" into "0ell1". + * + * The function returns the sds string pointer, that is always the same + * as the input pointer since no resize is needed. */ +sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) { + size_t j, i, l = sdslen(s); + + for (j = 0; j < l; j++) { + for (i = 0; i < setlen; i++) { + if (s[j] == from[i]) { + s[j] = to[i]; + break; + } + } + } + return s; +} + +/* Join an array of C strings using the specified separator (also a C string). + * Returns the result as an sds string. */ +sds sdsjoin(char **argv, int argc, char *sep) { + sds join = sdsempty(); + int j; + + for (j = 0; j < argc; j++) { + join = sdscat(join, argv[j]); + if (j != argc-1) join = sdscat(join,sep); + } + return join; +} + +#ifdef SDS_TEST_MAIN +#include +#include "testhelp.h" + +int main(void) { + { + struct sdshdr *sh; + sds x = sdsnew("foo"), y; + + test_cond("Create a string and obtain the length", + sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) + + sdsfree(x); + x = sdsnewlen("foo",2); + test_cond("Create a string with specified length", + sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) + + x = sdscat(x,"bar"); + test_cond("Strings concatenation", + sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); + + x = sdscpy(x,"a"); + test_cond("sdscpy() against an originally longer string", + sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) + + x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); + test_cond("sdscpy() against an originally shorter string", + sdslen(x) == 33 && + memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) + + sdsfree(x); + x = sdscatprintf(sdsempty(),"%d",123); + test_cond("sdscatprintf() seems working in the base case", + sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) + + sdsfree(x); + x = sdstrim(sdsnew("xxciaoyyy"),"xy"); + test_cond("sdstrim() correctly trims characters", + sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) + + y = sdsrange(sdsdup(x),1,1); + test_cond("sdsrange(...,1,1)", + sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) + + sdsfree(y); + y = sdsrange(sdsdup(x),1,-1); + test_cond("sdsrange(...,1,-1)", + sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) + + sdsfree(y); + y = sdsrange(sdsdup(x),-2,-1); + test_cond("sdsrange(...,-2,-1)", + sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) + + sdsfree(y); + y = sdsrange(sdsdup(x),2,1); + test_cond("sdsrange(...,2,1)", + sdslen(y) == 0 && memcmp(y,"\0",1) == 0) + + sdsfree(y); + y = sdsrange(sdsdup(x),1,100); + test_cond("sdsrange(...,1,100)", + sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) + + sdsfree(y); + y = sdsrange(sdsdup(x),100,100); + test_cond("sdsrange(...,100,100)", + sdslen(y) == 0 && memcmp(y,"\0",1) == 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("foo"); + y = sdsnew("foa"); + test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("bar"); + y = sdsnew("bar"); + test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) + + sdsfree(y); + sdsfree(x); + x = sdsnew("aar"); + y = sdsnew("bar"); + test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) + + { + int oldfree; + + sdsfree(x); + x = sdsnew("0"); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0); + x = sdsMakeRoomFor(x,1); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0); + oldfree = sh->free; + x[1] = '1'; + sdsIncrLen(x,1); + test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1'); + test_cond("sdsIncrLen() -- len", sh->len == 2); + test_cond("sdsIncrLen() -- free", sh->free == oldfree-1); + } + } + test_report() + return 0; +} +#endif diff --git a/src/sds.h b/src/sds.h new file mode 100644 index 0000000..57db249 --- /dev/null +++ b/src/sds.h @@ -0,0 +1,100 @@ +/* SDSLib, A C dynamic strings library + * + * Copyright (c) 2006-2010, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SDS_H +#define __SDS_H + +#define SDS_MAX_PREALLOC (1024*1024) + +//#include +#include + +typedef char *sds; + +struct sdshdr { + int len; + int free; + char buf[]; +}; + +static inline size_t sdslen(const sds s) { + struct sdshdr *sh = (struct sdshdr*)(s - (sizeof(struct sdshdr))); + return sh->len; +} + +static inline size_t sdsavail(const sds s) { + struct sdshdr *sh = (struct sdshdr*)(s - (sizeof(struct sdshdr))); + return sh->free; +} + +sds sdsnewlen(const void *init, size_t initlen); +sds sdsnew(const char *init); +sds sdsempty(void); +size_t sdslen(const sds s); +sds sdsdup(const sds s); +void sdsfree(sds s); +size_t sdsavail(const sds s); +sds sdsgrowzero(sds s, size_t len); +sds sdscatlen(sds s, const void *t, size_t len); +sds sdscat(sds s, const char *t); +sds sdscatsds(sds s, const sds t); +sds sdscpylen(sds s, const char *t, size_t len); +sds sdscpy(sds s, const char *t); + +sds sdscatvprintf(sds s, const char *fmt, va_list ap); +#ifdef __GNUC__ +sds sdscatprintf(sds s, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#else +sds sdscatprintf(sds s, const char *fmt, ...); +#endif + +sds sdstrim(sds s, const char *cset); +void sdsrange(sds s, int start, int end); +void sdsupdatelen(sds s); +void sdsclear(sds s); +int sdscmp(const sds s1, const sds s2); +sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); +void sdsfreesplitres(sds *tokens, int count); +void sdstolower(sds s); +void sdstoupper(sds s); +sds sdsfromlonglong(long long value); +sds sdscatrepr(sds s, const char *p, size_t len); +sds *sdssplitargs(const char *line, int *argc); +sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); +sds sdsjoin(char **argv, int argc, char *sep); + +/* Low level functions exposed to the user API */ +sds sdsMakeRoomFor(sds s, size_t addlen); +void sdsIncrLen(sds s, int incr); +sds sdsRemoveFreeSpace(sds s); +size_t sdsAllocSize(sds s); + +#endif From 3f10c1a466717c78b5c4703f186337f6dd0d898e Mon Sep 17 00:00:00 2001 From: xdczju Date: Sat, 7 May 2016 16:13:12 +0800 Subject: [PATCH 090/173] =?UTF-8?q?=E4=BC=98=E5=8C=96sds=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.v12.suo | Bin 163840 -> 163840 bytes src/context_lua.cpp | 20 +++++++++++++++++--- src/message.h | 15 ++++++++++++++- src/node_lua.h | 22 ++++++++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 6a66efc98659a853db254600a17d97497852c709..f7df02be4c90cd6a3367edadd7cc9c0baa4d12a9 100644 GIT binary patch delta 1190 zcmcJNTWAw$6vw~wWu`k5+mc)JU}G}YLF+BHq1JtTz2%W@K<6pKLq{eTRsDhf+&ran3ZY0tXk(-Nb^4_!FO%jG?E-rqRVF&DdinqmXS9Q193 zno=VkfR^-*dC9027JZ281m(QMX(CLVBw~cft)=H7;uO(A#EAfLkP!JXLUfJv9yDMM z%qZxcNQv}*vn#q0Fx2fey{G@1mLBKnt5uotA&~m1MSPO2HcQ@dj`~0(*{Nf?$cIZ^ zij+qki*DsUs@j_qqWc0^Qx=kFVXJW<&R62~+cMr6Sd?+qg3&bK8F$Lv#s5 zauR#;L4kVXKp~VFZ5hb3?Pg8J@Op3?n@V_|V`l5Jhn>@(ZHyJDnyc%V!&pAsW8c}d zd46*F@V@hg9gZgg87FXSth=7C{2#kt=KXcVRVa4YvCydqIzwALFx zi%~-*Q zsWh?8YzzAia}R!N?lBf*+n5@zczpMAor&GmN_5!7*4)O6Y-!7CD@K|wC}9w!6;!ZPVo=bBE-ge4$%GL| zU+Wy)0SPj*MXb!6YQlmveaJThiykBs>cNoc!63!m?TltG9_GinXYRfKbN*aab*ic} zS_h@i>Nhi~Yv$@~K89HN(#gZ7v4he#Alz2#-Br1sIQ?-&8k{EWB z!!>*&RmlnZ8>7v$#5&?Op|SH~!@%73xLSe!IK^ZPvsbu^1CBir$_fVLEK}f7Iz32fkZuVg}6vq7In(4gpbs$+KN1? zBSgF2;Djn@G46MsfbI)L+Ghoo0pl)fZKF$f$xB&MwThNAl;50S=6}#U3NxIev+*9O6I%*>Cgcz z&&>0{3=H-R161lG66}_I!Wp6Ur5D`HbQi!k$T&D2HZI*O2~Q98&mBJ&v6&em_6uSG zcrIG+WWEYOEo_{4{dS?eX<+ZhsPn~b)`Tr-#h>RJtbWFPaBC6oJrhA#pZ aF9DH!(Kk3z4LHh*G4kQ&^$Lhru$sT-(jjI5 diff --git a/src/context_lua.cpp b/src/context_lua.cpp index f3f2ef0..2c0b1be 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -561,7 +561,18 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) create_buffer(L, message_buffer(message)); return; case STRING: - lua_pushstring(L, message_string(message)); + if (message_string(message)) { + lua_pushstring(L, message_string(message)); + } else { + lua_pushstring(L, ""); + } + return; + case SDS: + if (message_sds(message)) { + lua_pushlstring(L, message_sds(message), sdslen(message_sds(message))); + } else { + lua_pushstring(L, ""); + } return; case BSON: if (message_bson(message)->extract) { @@ -906,6 +917,8 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t buffer_t* buffer; bson_t* bson_ptr; int32_t* bson_data; + const char* data; + uint32_t length; switch (lua_type(L, idx)) { case LUA_TNUMBER: if (lua_isinteger(L, idx)) { @@ -918,8 +931,9 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t message.m_source = lua_get_context_handle(L); return 1; case LUA_TSTRING: - message.m_type = MAKE_MESSAGE_TYPE(msg_type, STRING); - message.m_data.m_string = nl_strdup(lua_tostring(L, idx)); + data = lua_tolstring(L, idx, &length); + message.m_type = MAKE_MESSAGE_TYPE(msg_type, SDS); + message.m_data.m_sds = sdsnewlen(data, length); message.m_source = lua_get_context_handle(L); return 1; case LUA_TBOOLEAN: diff --git a/src/message.h b/src/message.h index bdac94e..eeb2033 100644 --- a/src/message.h +++ b/src/message.h @@ -2,6 +2,7 @@ #define MESSAGE_H_ #include "buffer.h" #include "lbson.h" +#include "sds.h" #define MESSAGE_TYPE_BIT 24 #define MAKE_MESSAGE_TYPE(mtype, dtype) (((uint32_t)(dtype) << MESSAGE_TYPE_BIT) | ((mtype) & (((uint32_t)1 << MESSAGE_TYPE_BIT) - 1))) @@ -32,6 +33,7 @@ typedef union data_t { int64_t m_integer; buffer_t m_buffer; char *m_string; + char *m_sds; bson_t *m_bson; message_array_t *m_array; int32_t m_error; @@ -70,6 +72,7 @@ enum message_type { #define message_integer(msg) ((msg).m_data.m_integer) #define message_buffer(msg) ((msg).m_data.m_buffer) #define message_string(msg) ((msg).m_data.m_string) +#define message_sds(msg) ((msg).m_data.m_sds) #define message_bson(msg) ((msg).m_data.m_bson) #define message_array(msg) ((msg).m_data.m_array) #define message_error(msg) ((msg).m_data.m_error) @@ -82,6 +85,7 @@ enum message_type { #define message_is_integer(msg) (INTEGER == message_data_type(msg)) #define message_is_buffer(msg) (BUFFER == message_data_type(msg)) #define message_is_string(msg) (STRING == message_data_type(msg)) +#define message_is_sds(msg) (SDS == message_data_type(msg)) #define message_is_bson(msg) (BSON == message_data_type(msg)) #define message_is_array(msg) (ARRAY == message_data_type(msg)) #define message_is_error(msg) (TERROR == message_data_type(msg)) @@ -97,6 +101,11 @@ enum message_type { nl_free((msg).m_data.m_string); \ (msg).m_data.m_string = NULL; \ } \ + } else if (message_is_sds(msg)) { \ + if ((msg).m_data.m_sds) { \ + sdsfree((msg).m_data.m_sds); \ + (msg).m_data.m_sds = NULL; \ + } \ } else if (message_is_bson(msg)) { \ if ((msg).m_data.m_bson) { \ bson_release((msg).m_data.m_bson); \ @@ -152,10 +161,14 @@ class message_t { : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, TERROR)) { m_data.m_error = err; } - message_t(uint32_t source, int32_t session, uint32_t msg_type, bson_t* bson) + message_t(uint32_t source, int32_t session, uint32_t msg_type, bson_t *bson) : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, BSON)) { m_data.m_bson = bson; } + message_t(uint32_t source, int32_t session, uint32_t msg_type, char *string, int32_t length) + : m_source(source), m_session(session), + m_type(MAKE_MESSAGE_TYPE(msg_type, SDS)) { m_data.m_sds = string; } + message_t(uint32_t source, int32_t session, uint32_t msg_type, message_array_t* array) : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, ARRAY)) { m_data.m_array = array; } diff --git a/src/node_lua.h b/src/node_lua.h index af01c59..87c0582 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -5,6 +5,7 @@ #include "context_mgr.h" #include "worker_mgr.h" #include "context.h" +#include "sds.h" class message_t; class network_t; @@ -52,6 +53,27 @@ class node_lua_t : public singleton_t { message_clean(msg); return false; } + + /* specific context send interface */ + FORCE_INLINE bool context_send_sds_safe(uint32_t handle, uint32_t source, int session, int msg_type, const char *data, int32_t length) + { + char* str = data ? sdsnewlen(data, length) : NULL; + message_t msg(source, session, msg_type, str, length); + if (context_send(handle, msg)) + return true; + message_clean(msg); + return false; + } + + FORCE_INLINE bool context_send_sds_safe(context_t* ctx, uint32_t source, int session, int msg_type, const char *data, int32_t length) + { + char* str = data ? sdsnewlen(data, length) : NULL; + message_t msg(source, session, msg_type, str, length); + if (context_send(ctx, msg)) + return true; + message_clean(msg); + return false; + } FORCE_INLINE bool context_send_buffer_safe(uint32_t handle, uint32_t source, int session, int msg_type, buffer_t& buffer) { From 133ab45c3ad9c7c81645caec413bc820b0e6fa93 Mon Sep 17 00:00:00 2001 From: xdczju Date: Sat, 7 May 2016 16:49:46 +0800 Subject: [PATCH 091/173] =?UTF-8?q?=E4=BC=98=E5=8C=96logger=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.v12.suo | Bin 163840 -> 163840 bytes src/context_lua.cpp | 25 +++++++++++++++++-------- src/node_lua.cpp | 14 +++++++++++--- src/node_lua.h | 8 ++++++-- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/node-lua.v12.suo b/node-lua.v12.suo index f7df02be4c90cd6a3367edadd7cc9c0baa4d12a9..3d0c44e52c356d95b521744e3f26c6f7afb88e5c 100644 GIT binary patch delta 1549 zcmbu8Ye*DP6vyY>o!Mqr%SW5gYVNuYr75}AT9IX22?c5Net>Btz3{oUQ6G9tSy51? zdu=DIh{X0oM3j?`nUPUY+ou8{DM9;GL|J|4L!oZxu4Al0NVV|e?!D*S`~TlF=gP8K zmd$le;OeszO~7$n8PZ7QKKGsKGVqad;Y;Sr&5Njq)W8Gv8_593p(&!upTIoY!`u1c zP$)zPc^7|}t+-5Sv`DakOg%y_Kg43U1gT&hW=@Ck>jj>Z?UniWw|Y?LGa_Qt61LO`lWfW0Gyu z@DvY6f5fFxht(ktpyVNh!m>2uJ&f(wVYFo z2Xs#J6gA=UhbTpMfJB==+s4xn!WzF0RD$zhzEbBU%k<+nsrDQFF>OY80wQaHWZhe| z6^*RN3Hvp5Cixo09juZqI4wYmkja=|jpG_*I&vOKKrSLISHy82avEVr)gTv;Jj9FG z5SDjFAHxlU-8VyRXeyHop25`m;@n1APLAc z{H{B~%;I))Py4$|Ka|EEeJ@{;XFV}EX?FUQm_qE-Qf@C-g*B?;R?{WEJVo+AywaKu zQWP%jM00j-Bd2s(p-Rchg$+u60yt?JiB`Hwh?~Y!i)KlHPeRiFi6usetqpqA16OBz z`Z{iXEZ*WZXfKM16MPoDc)1NsV8B~XKv@4$Z^hXQKx~@L4sRh44a6Uhg^9&7{wj=r zE%4ew32q9SG#83MZ`=X9$SN)BCkd_Wm1y5HU;^K^0Nelt^ieP`*)yh$g>N2q++CjO zSY^+7HLyJEIsLjcmAZY4!SgSBM(!j5A9)?W3)<_ed9Bk0`4E^7WaMQqpQA4$J@RFY X@%Q(idHl-%ZzGMbaLNqcJ8)!du?hPsI9kkDY1}E%%ma~+^8t%30Y`mTZAdP)>eM7xIHnl zhdZ^mEQnr9Z)|UQBm7X*hx`~6Nl4b$s30h?uMxE#joblm5N5T4|lB3Y${MICh@~)5jXi1K1f6KaGf8e zYhr+x=yIomg3H8uVh+(t)DU|Ku~gOJ6piX^K39evYS!o#v}htu5eLLmH783}Nl^5i z=3O)&C#0C*pyr;L7IT-xj6~d}r}bEHiRV23mkj=mE{YPhKvZg3KUK!mvfmv|swX?1 zA*iF4ugQ*b%n;wS7ovYm!0LDRI@&hM+2u%O=xc1f1O?z8x*||sV8-&$nyUAEY`+_? zaKXrq_qb{dI!zI>)DfC9p(xRzSneI8wU;7R?=fWhhZ@R$AwK z)*DWA1<4@bS>D}f?L1f9*mwWdyS1xh4%1V` zK8j3{X=i!yUbT^dLByBpmfrpbCmHkEc{<)8;lm>h4if)?ip!TfchJitiugLN!1U+A z?~-Ev`kT^PWcoi^Zm3pZpclz$;7KP~XBiBbh8K~EMLQx*(X9 1) { - singleton_ref(node_lua_t).context_destroy(handle, src_handle, lua_tostring(L, 2)); + if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + luaL_error(L, "attempt to destroy an illegal context:0x%08x", handle); } + singleton_ref(node_lua_t).context_destroy(handle, src_handle, lua_tostring(L, 2)); return 0; } @@ -1014,6 +1012,9 @@ int32_t context_lua_t::context_send(lua_State *L, int32_t idx, uint32_t count, u int32_t context_lua_t::context_send(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); + if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + luaL_error(L, "attempt to send to an illegal context:0x%08x", handle); + } int32_t top = lua_gettop(L); luaL_checkany(L, 2); int32_t ret = context_send(L, 2, top - 1, handle, LUA_REFNIL, CONTEXT_QUERY); @@ -1072,6 +1073,9 @@ int32_t context_lua_t::context_query_yield_continue(lua_State* L, int status, lu int32_t context_lua_t::context_query(lua_State *L, bool timed_query) { uint32_t handle = luaL_checkunsigned(L, 1); + if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + luaL_error(L, "attempt to query to an illegal context:0x%08x", handle); + } int32_t top = lua_gettop(L); uint64_t timeout = 0; if (timed_query) { @@ -1130,6 +1134,9 @@ int32_t context_lua_t::context_timed_query(lua_State *L) int32_t context_lua_t::context_reply(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); + if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + luaL_error(L, "attempt to reply to an illegal context:0x%08x", handle); + } int32_t session = luaL_checkinteger(L, 2); luaL_checkany(L, 3); int32_t ret = context_send(L, 3, lua_gettop(L) - 2, handle, session, CONTEXT_REPLY); @@ -1193,6 +1200,9 @@ int32_t context_lua_t::context_recv(lua_State *L) { context_lua_t* lctx = (context_lua_t*)lua_get_context(L); uint32_t handle = luaL_checkunsigned(L, 1); + if (handle == singleton_ref(node_lua_t).get_logger_handle()) { + luaL_error(L, "attempt to recv from an illegal context:0x%08x", handle); + } int32_t top = lua_gettop(L); uint64_t timeout = 0; if (top >= 2) { //nonblocking @@ -1250,9 +1260,8 @@ int32_t context_lua_t::context_wait(lua_State *L) { context_lua_t* lctx = (context_lua_t*)lua_get_context(L); uint32_t handle = luaL_checkunsigned(L, 1); - if (handle == 0) { - luaL_error(L, "invalid context handle to wait"); - return 0; + if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + luaL_error(L, "attempt to wait an illegal context:0x%08x", handle); } if (handle == lctx->get_handle()) { luaL_error(L, "can't wait self to die away"); diff --git a/src/node_lua.cpp b/src/node_lua.cpp index bdf8284..533ca0c 100644 --- a/src/node_lua.cpp +++ b/src/node_lua.cpp @@ -29,7 +29,7 @@ void node_lua_t::init_once() m_inited = true; } -node_lua_t::node_lua_t(int argc, char* argv[], char* env[]) +node_lua_t::node_lua_t(int argc, char* argv[], char* env[]) : m_logger(NULL) { node_lua_t::init_once(); m_network = new network_t(); @@ -37,15 +37,23 @@ node_lua_t::node_lua_t(int argc, char* argv[], char* env[]) m_worker_mgr = new worker_mgr_t(); m_network->start(); m_worker_mgr->start(); + + /* start basic context */ m_ctx_mgr->set_handle_index(MAX_CTX_SIZE); - m_logger = context_create(0, 0, NULL, NULL); - if (m_logger > 0) { + uint32_t logger_handle = context_create(0, 0, NULL, NULL); + if (logger_handle > 0) { + m_logger = m_ctx_mgr->grab_context(logger_handle); m_ctx_mgr->set_handle_index(1); context_create(0, argc, argv, env); } + m_worker_mgr->wait(); m_network->stop(); m_network->wait(); + if (m_logger) { + m_logger->release(); + m_logger = NULL; + } context_lua_t::unload(); } diff --git a/src/node_lua.h b/src/node_lua.h index 87c0582..4796fac 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -200,7 +200,7 @@ class node_lua_t : public singleton_t { { uint32_t ctx_size = m_ctx_mgr->get_context_count(); if (ctx_size == 1) { - context_destroy(m_logger, src_handle, NULL); + context_destroy(m_logger->get_handle(), src_handle, NULL); return; } if (ctx_size == 0) { @@ -208,12 +208,16 @@ class node_lua_t : public singleton_t { return; } } + + uint32_t get_logger_handle() const { + return m_logger->get_handle(); + } private: network_t *m_network; context_mgr_t *m_ctx_mgr; worker_mgr_t *m_worker_mgr; - uint32_t m_logger; + context_t *m_logger; public: static int32_t m_cpu_count; From 9243746402fb1a6201bf2add59737ef196cd18fc Mon Sep 17 00:00:00 2001 From: xdczju Date: Sat, 7 May 2016 16:56:57 +0800 Subject: [PATCH 092/173] =?UTF-8?q?=E4=BC=98=E5=8C=96logger=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.v12.suo | Bin 163840 -> 172032 bytes src/context_log.cpp | 23 ++++++++++++++++++++++- src/context_log.h | 2 ++ src/message.h | 4 +++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 3d0c44e52c356d95b521744e3f26c6f7afb88e5c..baa0f2b0b5ae1d45e08d94de639805f51a0375f7 100644 GIT binary patch delta 6626 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 delta 4307 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 O<#@^;Cw*rjGkpgmTRU6; diff --git a/src/context_log.cpp b/src/context_log.cpp index 823637e..f5b2296 100644 --- a/src/context_log.cpp +++ b/src/context_log.cpp @@ -1,4 +1,5 @@ #include "context_log.h" +#include "node_lua.h" bool context_log_t::init(int32_t argc, char* argv[], char* env[]) { @@ -12,11 +13,31 @@ bool context_log_t::deinit(const char *arg) void context_log_t::on_received(message_t& message) { - + switch (message_raw_type(message)) { + case LOG_MESSAGE: + log_message(message); + return; + case SYSTEM_CTX_DESTROY: + singleton_ref(node_lua_t).context_destroy(this, message.m_source, message_string(message)); + return; + default: + break; + } } void context_log_t::on_dropped(message_t& message) { + switch (message_raw_type(message)) { + case LOG_MESSAGE: + log_message(message); + return; + default: + break; + } +} +void context_log_t::log_message(message_t& message) +{ + //to be fixed } diff --git a/src/context_log.h b/src/context_log.h index e9b52f7..6dc06d7 100644 --- a/src/context_log.h +++ b/src/context_log.h @@ -11,6 +11,8 @@ class context_log_t : public context_t { bool deinit(const char *arg); void on_received(message_t& message); void on_dropped(message_t& message); +private: + void log_message(message_t& message); }; #endif \ No newline at end of file diff --git a/src/message.h b/src/message.h index eeb2033..75bbb1d 100644 --- a/src/message.h +++ b/src/message.h @@ -61,7 +61,9 @@ enum message_type { RESPONSE_UDP_WRITE, RESPONSE_UDP_CLOSING, RESPONSE_HANDLE_CLOSE, - RESPONSE_TIMEOUT + RESPONSE_TIMEOUT, + //////////////////////////////////////// + LOG_MESSAGE }; #define message_raw_type(msg) (MESSAGE_TYPE((msg).m_type)) From 640248e9ed7c14ed3a93995511dd66e3594a3aa7 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 9 May 2016 22:37:02 +0800 Subject: [PATCH 093/173] =?UTF-8?q?=E4=BC=98=E5=8C=96logger=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.v12.suo | Bin 172032 -> 158720 bytes node-lua.vcxproj.user | 2 +- sample/main.lua | 4 ++++ src/context_log.cpp | 17 +++++++++++++++- src/context_lua.cpp | 45 ++++++++++++++++++++++++++++++------------ src/node_lua.h | 44 ++++++++++++++++++++++++++++++++++++++--- 6 files changed, 94 insertions(+), 18 deletions(-) diff --git a/node-lua.v12.suo b/node-lua.v12.suo index baa0f2b0b5ae1d45e08d94de639805f51a0375f7..52da31c0ceac0440168eb480eb94dfddbfee086d 100644 GIT binary patch delta 5500 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 - main.lua + sample/main.lua WindowsLocalDebugger \ No newline at end of file diff --git a/sample/main.lua b/sample/main.lua index c3a89bf..928579d 100644 --- a/sample/main.lua +++ b/sample/main.lua @@ -70,6 +70,10 @@ print("value", value1, value2)]] -- # define TEST_PIPENAME_2 "/tmp/uv-test-sock2" -- #endif +context.log(1, {}) + +do return end + local result, server = udp.open("127.0.0.1", 8081) server:read(function(result, buffer, remote_addr, remote_port, remote_ipv6, server) print("server read callback: ", result, buffer, remote_addr, remote_port, remote_ipv6, server) diff --git a/src/context_log.cpp b/src/context_log.cpp index f5b2296..7f78e36 100644 --- a/src/context_log.cpp +++ b/src/context_log.cpp @@ -38,6 +38,21 @@ void context_log_t::on_dropped(message_t& message) void context_log_t::log_message(message_t& message) { - //to be fixed + switch (message_data_type(message)) { + case SDS: + if (message_sds(message)) { + lua_writestring(message_sds(message), sdslen(message_sds(message))); + lua_writeline(); + } + break; + case STRING: + if (message_string(message)) { + lua_writestring(message_string(message), strlen(message_string(message))); + lua_writeline(); + } + break; + default: + break; + } } diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 767f9f1..ebe3fa2 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -35,12 +35,12 @@ bool context_lua_t::init(int32_t argc, char* argv[], char* env[]) { m_lstate = luaL_newstateex(this); if (argc <= 0) { - printf("[error] context:0x%08x init failed: lua file is needed to initialize lua context\n", m_handle); /* to be implemented : put reason to another context and output it */ + nl.log_fmt(m_handle, "[error] context:0x%08x init failed: lua file is needed to initialize lua context", m_handle); return false; } int32_t envc = 2; if (argc > MAX_CTX_ARGC || !lua_checkstack(m_lstate, argc + envc)) { - printf("[error] context:0x%08x init failed: too many arguments to initialize lua context %s\n", m_handle, argv[0]); /* to be implemented : put reason to another context and output it */ + nl.log_fmt(m_handle, "[error] context:0x%08x init failed: too many arguments to initialize lua context %s", m_handle, argv[0]); return false; } int32_t total_length = 0; @@ -70,7 +70,7 @@ bool context_lua_t::init(int32_t argc, char* argv[], char* env[]) argp += lengths[i]; *argp++ = (i != argc - 1) ? ' ' : '\0'; } - printf("[alert] context:0x%08x init: %s\n", m_handle, args); /* to be implemented : put reason to another context and output it */ + nl.log_fmt(m_handle, "[alert] context:0x%08x init: %s", m_handle, args); nl_free(args); return singleton_ref(node_lua_t).context_send(this, m_handle, 0, LUA_CTX_INIT, (int64_t)argc); } @@ -85,7 +85,7 @@ bool context_lua_t::deinit(const char *arg) lua_close(m_lstate); m_lstate = NULL; } - printf("[alert] context:0x%08x deinit: %s\n", m_handle, arg); /* to be implemented : put reason to another context and output it */ + nl.log_fmt(m_handle, "[alert] context:0x%08x deinit: %s", m_handle, arg); return true; } @@ -394,8 +394,7 @@ int32_t context_lua_t::lua_ref_callback_entry_finish(lua_State *L, int32_t statu if (!status) { /* error message is at top */ uint32_t handle = lua_get_context_handle(L); const char* error = lua_tostring(L, -1); - /* to be implemented : put reason to another context and output it */ - printf("[error] context:0x%08x error: %s\n", handle, error ? error : "unknown error"); + nl.log_fmt(handle, "[error] context:0x%08x error: %s", handle, error ? error : "unknown error"); } return 0; //return none result out!!! } @@ -903,7 +902,7 @@ int32_t context_lua_t::context_destroy(lua_State *L) return 0; } uint32_t handle = luaL_checkunsigned(L, 1); - if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { luaL_error(L, "attempt to destroy an illegal context:0x%08x", handle); } singleton_ref(node_lua_t).context_destroy(handle, src_handle, lua_tostring(L, 2)); @@ -1012,7 +1011,7 @@ int32_t context_lua_t::context_send(lua_State *L, int32_t idx, uint32_t count, u int32_t context_lua_t::context_send(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); - if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { luaL_error(L, "attempt to send to an illegal context:0x%08x", handle); } int32_t top = lua_gettop(L); @@ -1073,7 +1072,7 @@ int32_t context_lua_t::context_query_yield_continue(lua_State* L, int status, lu int32_t context_lua_t::context_query(lua_State *L, bool timed_query) { uint32_t handle = luaL_checkunsigned(L, 1); - if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { luaL_error(L, "attempt to query to an illegal context:0x%08x", handle); } int32_t top = lua_gettop(L); @@ -1134,7 +1133,7 @@ int32_t context_lua_t::context_timed_query(lua_State *L) int32_t context_lua_t::context_reply(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); - if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { luaL_error(L, "attempt to reply to an illegal context:0x%08x", handle); } int32_t session = luaL_checkinteger(L, 2); @@ -1200,7 +1199,7 @@ int32_t context_lua_t::context_recv(lua_State *L) { context_lua_t* lctx = (context_lua_t*)lua_get_context(L); uint32_t handle = luaL_checkunsigned(L, 1); - if (handle == singleton_ref(node_lua_t).get_logger_handle()) { + if (singleton_ref(node_lua_t).is_handle_illegal(handle)) { luaL_error(L, "attempt to recv from an illegal context:0x%08x", handle); } int32_t top = lua_gettop(L); @@ -1260,7 +1259,7 @@ int32_t context_lua_t::context_wait(lua_State *L) { context_lua_t* lctx = (context_lua_t*)lua_get_context(L); uint32_t handle = luaL_checkunsigned(L, 1); - if (handle == 0 || handle == singleton_ref(node_lua_t).get_logger_handle()) { + if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { luaL_error(L, "attempt to wait an illegal context:0x%08x", handle); } if (handle == lctx->get_handle()) { @@ -1317,7 +1316,27 @@ int32_t context_lua_t::context_thread(lua_State *L) int32_t context_lua_t::context_log(lua_State *L) { context_lua_t* lctx = context_lua_t::lua_get_context(L); - + int32_t n = lua_gettop(L); /* number of arguments */ + int32_t i; + sds buffer = sdsnewlen(NULL, 64); + sdsclear(buffer); + lua_getglobal(L, "tostring"); + for (i = 1; i <= n; i++) { + const char *s; + size_t l; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tolstring(L, -1, &l); /* get result */ + if (s == NULL) { + sdsfree(buffer); + return luaL_error(L, "'tostring' must return a string to 'context.log'"); + } + if (i > 1) buffer = sdscatlen(buffer, "\t", 1); + buffer = sdscatlen(buffer, s, l); + lua_pop(L, 1); /* pop result */ + } + singleton_ref(node_lua_t).log_sds_release(lctx->get_handle(), buffer); return 0; } diff --git a/src/node_lua.h b/src/node_lua.h index 4796fac..4e0db1f 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -179,7 +179,7 @@ class node_lua_t : public singleton_t { uint32_t handle = ctx->get_handle(); if (handle == 0) return; - char buffer[512] = { '\0' }; + char buffer[1024] = { '\0' }; int32_t used = sprintf(buffer, "killed by context:0x%08x", src_handle); if (reason) { strcat(buffer + used, ", "); @@ -209,8 +209,46 @@ class node_lua_t : public singleton_t { } } - uint32_t get_logger_handle() const { - return m_logger->get_handle(); + bool log_sds_release(uint32_t src_handle, sds buffer) { + message_t message(src_handle, 0, LOG_MESSAGE, (char*)buffer, sdslen(buffer)); + if (m_logger && context_send(m_logger, message)) { + return true; + } + sdsfree(buffer); + return false; + } + + bool log_fmt(uint32_t src_handle, const char* fmt, ...) { + if (m_logger && fmt) { + char *buf = NULL; + size_t buflen = 64; + va_list argp; + va_list copy; + va_start(argp, fmt); + while (1) { + buf = (char *)nl_malloc(buflen); + if (buf == NULL) break; + buf[buflen - 2] = '\0'; + va_copy(copy, argp); + vsnprintf(buf, buflen, fmt, copy); + if (buf[buflen - 2] != '\0') { + nl_free(buf); + buflen *= 2; + continue; + } + break; + } + va_end(argp); + if (buf && context_send(m_logger, src_handle, 0, LOG_MESSAGE, buf)) { + return true; + } + nl_free(buf); + } + return false; + } + + FORCE_INLINE uint32_t is_handle_illegal(uint32_t handle) const { + return handle == m_logger->get_handle(); } private: From f89794907c61f0c58d0d7618d5118040e722b605 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 10 May 2016 13:25:55 +0800 Subject: [PATCH 094/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E4=BF=A1=E6=81=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.v12.suo | Bin 158720 -> 174080 bytes sample/main.lua | 3 ++- src/context_lua.cpp | 37 +++++++++++++++++++++++++++---------- src/context_lua.h | 1 + 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 52da31c0ceac0440168eb480eb94dfddbfee086d..0babe2fbac57fb818b3e928787e9afc6b9e45c44 100644 GIT binary patch delta 7410 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 BZFm3x delta 4350 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 MAX_CTX_ARGC || !lua_checkstack(m_lstate, argc + envc)) { - nl.log_fmt(m_handle, "[error] context:0x%08x init failed: too many arguments to initialize lua context %s", m_handle, argv[0]); + singleton_ref(node_lua_t).log_fmt(m_handle, "[error] context:0x%08x init failed: too many arguments to initialize lua context %s", m_handle, argv[0]); return false; } int32_t total_length = 0; @@ -70,7 +70,7 @@ bool context_lua_t::init(int32_t argc, char* argv[], char* env[]) argp += lengths[i]; *argp++ = (i != argc - 1) ? ' ' : '\0'; } - nl.log_fmt(m_handle, "[alert] context:0x%08x init: %s", m_handle, args); + singleton_ref(node_lua_t).log_fmt(m_handle, "[alert] context:0x%08x init: %s", m_handle, args); nl_free(args); return singleton_ref(node_lua_t).context_send(this, m_handle, 0, LUA_CTX_INIT, (int64_t)argc); } @@ -85,7 +85,7 @@ bool context_lua_t::deinit(const char *arg) lua_close(m_lstate); m_lstate = NULL; } - nl.log_fmt(m_handle, "[alert] context:0x%08x deinit: %s", m_handle, arg); + singleton_ref(node_lua_t).log_fmt(m_handle, "[alert] context:0x%08x deinit: %s", m_handle, arg); return true; } @@ -394,7 +394,7 @@ int32_t context_lua_t::lua_ref_callback_entry_finish(lua_State *L, int32_t statu if (!status) { /* error message is at top */ uint32_t handle = lua_get_context_handle(L); const char* error = lua_tostring(L, -1); - nl.log_fmt(handle, "[error] context:0x%08x error: %s", handle, error ? error : "unknown error"); + singleton_ref(node_lua_t).log_fmt(handle, "[error] context:0x%08x error: %s", handle, error ? error : "unknown error"); } return 0; //return none result out!!! } @@ -404,6 +404,21 @@ int32_t context_lua_t::lua_ref_callback_entry_continue(lua_State *L, int status, return lua_ref_callback_entry_finish(L, (status == LUA_YIELD)); } +int32_t context_lua_t::lua_ref_callback_error_handler(lua_State *L) +{ + const char *msg = lua_tostring(L, 1); + if (msg == NULL) { /* is error object not a string? */ + if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ + lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ + return 1; /* that is the message */ + else + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ +} + int32_t context_lua_t::lua_ref_callback_entry(lua_State *L) { int upvalue_count = 0; @@ -416,15 +431,17 @@ int32_t context_lua_t::lua_ref_callback_entry(lua_State *L) adjust_resume_args(L); } --upvalue_count; - int resume_count = lua_gettop(L); - lua_checkstack(L, upvalue_count); + int resume_count = lua_gettop(L); /* record resume arg count */ + lua_checkstack(L, upvalue_count + 1); /* reserve `upvalue_count + 1` stack size */ + lua_pushcclosure(L, lua_ref_callback_error_handler, 0); + lua_insert(L, 1); /* put error handler function at bottom (the `1st` arg) */ lua_pushvalue(L, lua_upvalueindex(upvalue_count)); - lua_insert(L, 1); /* put callback closure as first arg */ - for (int i = 1; i < upvalue_count; ++i) { + lua_insert(L, 2); /* put callback closure as the first arg behind error handler */ + for (int i = 1; i < upvalue_count; ++i) { /* put `upvalue_count - 1` args */ lua_pushvalue(L, lua_upvalueindex(i)); } /* lua_callback_entry_continue makes the coroutine can be recovered. */ - int status = lua_pcallk(L, upvalue_count + resume_count - 1, LUA_MULTRET, 0, 0, lua_ref_callback_entry_continue); + int status = lua_pcallk(L, upvalue_count + resume_count - 1, LUA_MULTRET, 1, 0, lua_ref_callback_entry_continue); return lua_ref_callback_entry_finish(L, (status == LUA_OK)); } diff --git a/src/context_lua.h b/src/context_lua.h index 28dfeeb..2f9f4cc 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -112,6 +112,7 @@ class context_lua_t : public context_t { static int32_t lua_ref_callback_entry(lua_State *L); /* for lua_ref_callback */ static int32_t lua_ref_callback_entry_continue(lua_State *L, int status, lua_KContext ctx); /* for lua_ref_callback */ static int32_t lua_ref_callback_entry_finish(lua_State *L, int32_t status); + static int32_t lua_ref_callback_error_handler(lua_State *L); /* for lua_ref_callback */ public: static uint32_t lua_get_context_handle(lua_State *L); From a0edbdeaa52839a9113559c3dfd8f42bd8eae949 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 12 May 2016 18:13:52 +0800 Subject: [PATCH 095/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0node-lua=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++++-- node-lua.v12.suo | Bin 174080 -> 185344 bytes sample/main.lua | 10 ++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a15cc7a..86c46e1 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,13 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* *`--callback is a once callback, blocking if callback is nil.`* -13. error = **context.strerror**(errno) +13. result, error = **context.log**(...) + *`--almost equivalent to print except the output won't be disordered(node-lua runs in a muti-thread mode).`* + +14. error = **context.strerror**(errno) *`--convert error number to error string. Error number is always the next argument after result in most apis.`* -14. thread = **context.thread**() +15. thread = **context.thread**() *`--return the running thread index.`* ### tcp api diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 0babe2fbac57fb818b3e928787e9afc6b9e45c44..2ae0c0874af813c6097464f51c835d1da57e8433 100644 GIT binary patch delta 6886 zcmds64OrAwx}W#Ve_&t+8ekLzlmRCqMHt8rLc%e~WsTHWGAchn{6Hf>9n83~xqV3I|O0D_K=DHyihU@(LMr~CW+kr@aG2i7sUXu^&L54DQg=+2}k!)|D6Xm;~O=j1(we0xT>_MV?bXPC1!Mq|fHXjv ztqv#yE=Qk611+)-t zni?Uh6Ez<&7Z|1{eF_E85Fa}#B+za&>;Yaj$k@2Ut&s`mQv3B7ctE=Te&wV=OZ+_T zqeG+o6zvDOeWU&L`1&Vmztt+Fca2l}<|q0K?cEWmx28J%PRA+BV~%_w9d(b%qKk4h zIJ;imBFFR=D31jxPFG3<4TY*Uu$5GlVcL(j1@fkx(SE1vbc8>xCymU? zBT1nS(zCyLXMrPAIu38wPKJp7HSIuT$?tgLkg01uy+Yc)(6^?qV6S`q zeLKRGtg3zy-HiJDDP%xY< zs*#f)spL0KP?-GloMC=%uh-O?4;59Meu?(ru%7(iz`Gxfl)H^N((};_^Lb!s4>6U; zL5M+RRj50At|PDM0GKS6eUlJYU%yX2p%kzqEM7^WfzjgzzxV8&9$|<=%@(3qj^NvB zB^`og%cnH?_ihT%aO`kZhAcER;BVO_`w!mn*T3y`SnfaRw_p8hxuboEKlkJtWWKEE zS2LC`tDeOlE)e65*oJs*BDr|PDLPLEjxHHeZCHjKZkAy=@@nKO@LMe>9cggf2wJXT zzF~o3A^6l7uHR*AyyUIBKfNsw-JP(jZiURba0n+)6v;7$s`?@KRz5uSy3FQx-`TvR z?r*9|Zl0RhW~UO{5a^-or;?g#Tw$luGUepasAU3UfGofTs9xtoQ$W4iu?*-BbL!PY6u>r;1-~Tz)ZaX)s*+^?MlUHqF z!Nl>+Vl=yM7h0rRBa7ElaX!gZ5yv0hEJn!6{%BtWQP)r+p_7&RsV$v6Scw{+TSITi z6Zm~yHax*bs`+!P5hngyXOyiC$ zO4bXfP`9aT8hHeD>5Vh!F8Z0PocwyyDBYPw?^BzTip?t0)ViqHhGm0)ULrR+X{uSt z5)@gjX~!#}S=W5pLuM5!gKJ%Iu_{+WBDFs4)SYALeWR}g!7-K`y2C@;NmIu?HM%LN zl-~DCrL$7N)Qy%N{iYdoJNagk;I%ixl8ra+R*Sn-+VUjGaFMysU+OUumVfh&Ei=+V^l`hHvN<4;+GtBX*4G&SI=U8*w zeE9MjZk$hRD4kEtS38W+Wpctl<+5)~%FkH0OR!>g{DhU#5?m=EgA${E+f#Nmp~s+- z1*ozMxj(SoO}-T*x-!Ti{EnWHSVh0POScxJ$&Q(bnK{%=zRYtrW!2g6T(3qBjH%q= zg>owY_G+{kZDV=Ai>?c4>@l)uE;V;$k~$b1PNy^H5b61{S$_CJiab=Gs=GJP9;2?6 z(rRL@nOfQVI;B%3AE~41++Q7+cXci1hD( zijuR(&%-vvv8!k(_gsZ7rMHcex%V|xTUs&X_*wKSaZfwhblXDeHF97F70SPCwCU4o zu>rDk6BV+%mTacKWArJUQ%Bj{`#RaU=Rq>l=St4ez5+~)1G}i0E937_Fj1qXpYKqq1>!x%QU)n+=c+Q(xsAfJwzY*+RhLL+KM1s5?dY5mdCQZ4*#eq{4 zOJDGnwRE-2{wkJx{sD{SZKKWK=AQTlePYtz*-oQ~+nGIBwLe2 zA@`WX2yWko&nr(;JF&Myz~CBoDeioZ%GiDaKkhA9RXWXL2JxkbsYD;~B4r>bN|o3C zPRVqHsfi|^Q74R(qeZix^%5NreCP@aV@HgL*6pv*=O%W)4_?|qniI(%NvI3s&*bQA zaVNj$5_bKwPw8lw8aji$f1m`pMn>Y)@foKw+&g17jb+DwQLH|#m*$W!QV8CfD9ZHH zN9X}@X1rOPA5ZGD!~D_#IoQYkkqfC&jX7C6z0$XncANqO&PotcTr#uKJkL z^wKO*Yt+-eqJv>=%i-TMF?qjB9OX+NqN&_+6Gh6Dr=s=5TmhG*5#s50*NE}~YkxjV z#Pfm8l*Kt0ihVvIg#OG$qC~K}jhx(Yh$8i@JaGU{y;k|EAn2>vG*y0Zd9+?pDk_b> zc`(c^dm-zq)5UmpeMyCSVHw_ewgpnqa^NJ*)T7JA6XdHC(LDK5u}U91Q+SP<7pFJh zDs*u_OLZ}4pWh6Iqxz0(#Fa*lEhAUg9GpR!3h7UpIzh^}{^6AFzFXuieT9m<4n}Ux zl9xE}U|}gR*Oo}SjC;Uh*7F%C41M2EJeP6xBQbv>!UNo+X&20DW3y1 z2)U9P@r;qnQ$)U=KT7=3*tJr)iQN-KpsOiZnkWL$m)a(Ytvqj%z&gq|j1(!s!-?e! zT-wzB8)LX9D1B7pin*TZhPgFWb@OW%1a+XFtJk`pq)s!JtcB7rOSb-!SG;UgR|Eor zX|ekU<N zgH77mRoSi&i^;?iFgRpB%5l1DgBWSzzuqD$_|L7PWyroklX`Ok2T{hs#8AvzioOZ6 z^P;Nj>pTlqdgj(PR%O*VnHGqVB9wDVvxtwGH^>DhS&H%)o@Sx>?79ar-Fdfoc&HrY zf({R(96SiGQ)*T4%eNwc1Gftg1qm|;0{!Lnq8_`#v;`uJhN?^VV48qJP{`YYR?!h5 z+eM1H$}6f$<1Wt4Ey|son|pIaZB^sS+Qsv-U~56!b5jr{TI>nEOE|iQNWMhB`*9QBKvznNsBu-5mpeikNU|8sAD%?vd?*hF(NE| z=V>>ED^q8H!`iFpg4ltl`13$gWCiK%_wv0h;$nT{2C+x`e;1QvWm+WS)k*Sa!zIr1 z-6yPFVR&QW&H}Pql*Lp$T?&H^9`rP}Z6e!hW>o_BdDr+)k;b>N@5fB4ONj5NZ+a4Ep*j7I?@#S%! zO?h?SxQ({veao6PI=Q#D*X3;EN;*PDh5)1s1hj zgiOSjTWFlQwgy}H{|62 delta 5589 zcmc&&4OGZ6I&5$*t;;4zn zg!nNpa(7KOBC?}LO%H~|0&0Lsz)D~NFa>A@?g#!J*ayr6W&@*vIlwlx*g9loJ!)ft`!H=6 z=%YX;PzvWm4H4CSb^{NwiSV{=&kE9x>VitJqz_6z+m7zIt-*(A3?Pf6AX$= zKut3gf*u8ONX7O0So!PHRd8;S8h1xQ$Q$1jHTDkl>80tdJPGI}e$`gATwVU>twciF zUvVo3+-|3G#~Y#a#t#nT6knYyR?o#lq^k<(MDEacAR z=ulerb=u)B$_}}+yGc?P(g3OXh>}C2YCj?6-Zeam^e!)AABsvcL*89`(VVkG9pOCd z8<4q3Vpr2Baj&LiIeH%z>6$zIN9D57({%WoJTx@4-Vz;hfBXyTcLZ$ueCtxHXhLzw zv-~`T(mp&#t^OqCUzV=YeJOf|kk{8lD!(lulZHs$uJtsBmc0TzW5*q^@pVL%Y=zFRY_E>TqqP zv`l4J=#c~e5ZRnWC02^nBU3M@U?=^kOB#}BCA}tBHF;JVhR{?)yItQ1=QG%s6Aiiq zCU`=gSGpalMO){33hC`A?~SQF`gFm=^ctL>fJZy5F0wsHgF}Pga@a!YW87pvfwm!l z9;m!`H>v#F2ZRQ^{gJixB)6Wi2kM~b3Tm?tfUvk;f$GYCR2cF4qj%lP`v=U~4=w$B zhgkm;b1qO%)Qt?K*PW#UAEX(fw1q)3uJz94ti^z3_|Qc@IY@b-yx(6YGkrd#lPX(q zu=S#CC~lD15jj|UJ${20J+k0b=8qS6I^r%g9r=S#wYLm3^O=rQOvLjLf|Vyj|1N*hJ6ig=Wc!T$o)GuJGbJ5&+ zv+5dV=gdzXPb!rM$aA|nyE&fx#`wt-s^rx@JStXufeR>IOQmDRmrSpa#Xc?yo?H}T8H3AE*Rsk%CjzAyHyLy-!s`H96HdD}*H?EW5V4HNr&#f?Wt$`(<1Dz4q}Fgz zf2|9!giGC`?@H`5oM*pSqH`<^S+$1?o8RR1uDxSET6M2|aK(kf;~giGca*BU+vDZs zH+g#NdDa#P9%uUVl_%}YDQ1eB-lzYC+Vnl}mseX;pW2$ssm##1qdwp^9lA$Hi7%JR z?Ss&$ZKFHnN-j;+?yJ0)n-G`0Umb~}{}_qP>$B-`i}f`KH`Ehpx2yDZ$>wYGXfB&+ zIdqQbCB2%v=IP*|gHkM@XVxC0!-)2bBvAc*b4l)P8`eu7!Zb!KD)HhOs_zT${#hst1X0PT{?p7A(=f7p(-3ZKKVx)F2%32(;QVwrzp_q zHr;8|ZKdCtw2)Sjct55ZaUsfvM@eBl#VG&aG}SgJ*<i1x&A-4O#RoN$Yx=BEz1h zbn{?6m09HE&nZz7mr_pf9^$~E5>+x_tm&UXtt4p`)M}5xYHtqz>Zm0bQQz+f$N8S+ z%Be;gD(?QAAe)-VFqbc-wN0sv+`zWTu({1m*QlPP zVg*&op*(i}@L_I(PAuFcHD_Va?m~_?t8KgsV~W^j+J^CIn;h7I6>d64!^{UyQyaYexJz+s{gx5k{-zk!7S$B8R94%ZY;3h=MrV3 z;;(VBZ=21@=eN0XMyJ6C~k}{+| z3JNJdOC6+!m1aoITQDY4{a=vy&rzLOXYljX+)ca8U3UIghg4nY3s2fBc9sofOYnXu z%Hv_b>7T=X+F6!}6VaZ;Bh8V2gM%TSQudghI_|WH=ORrqpHJdCi_}~ov}Q08s0%-^ zoAzw>aIhYn7yEOL`FIY$O>(%9N2;NP8RoPlypN>uGs-oW=JHAE@Nz4j7lC1p(Z~;U z`fZI^C$x(1RErC;wTC52X@HBQeHrHN3_!N5s^Q1vZXX|#iSxKdF6_gq7wzLriCMwp zJ46p@Z%3NevX||$a0NO%D>;V3VrR&Or#LaVl}SAvNFuvbwDCOgzrdYRyPC5Q_oux) z(Dc8E?TcqIm8*9r#+WVnTw{@oo5>}vLN4q$s(Vi@<2$5oH&2%CEmUa2$-#~C{oWzY5sai;xJ%{DJdpU0B$x60JY7~D*W{&5b9W$7?-~U_U94vsj z-ao)YzEEb0c#h-V+^~;V#H>e<>?waDbKUk0Ti*!KctBsBj(`c~I)wYxl_c?(y`>K4TQ&iM%1{w|+4%r_3=+ug1?Kb@)nk02USF4LpMBdUluKIYb6wc*!=CWn{x<&g=l)STvXNrG4 zo~^FAeSUJ2oIUe62S$gFY?PBt{3-78Q_u1ZQ?20?t2}UmNA#rdHT!r^Y@Ai^N0$+u zxv0m>loOo) Date: Wed, 18 May 2016 23:06:30 +0800 Subject: [PATCH 096/173] =?UTF-8?q?=E5=88=86=E7=A6=BB=E9=9D=9E=E6=A0=B8?= =?UTF-8?q?=E5=BF=83luaclib?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 8 +------- luaclib/Makefile | 37 +++++++++++++++++++++++++++++++++++++ luaclib/luaclib.v12.suo | Bin 74240 -> 75264 bytes node-lua.v12.suo | Bin 185344 -> 184320 bytes sample/test.lua | 2 +- 5 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 luaclib/Makefile diff --git a/Makefile b/Makefile index c03fa24..b389575 100644 --- a/Makefile +++ b/Makefile @@ -14,8 +14,6 @@ define MAKE_PLATFORM cd deps/lua && make $(2); cd $(ROOT_PATH) cd deps/uv && make PLATFORM=$(1) HAVE_DTRACE=0; rm -f libuv.so libuv.dylib; cd $(ROOT_PATH) cd src && make PLATFORM=$(1) HAVE_DTRACE=0 RELEASE=$(3); cd $(ROOT_PATH) - ##not essential builds - cd clib/mime && make PLATFORM=$(1) RELEASE=$(3); cd $(ROOT_PATH) endef ifeq (darwin,$(PLATFORM)) @@ -35,8 +33,6 @@ clean: cd deps/lua && make clean; cd $(ROOT_PATH) cd deps/uv && make clean; cd $(ROOT_PATH) cd src && make clean; cd $(ROOT_PATH) - ##not essential builds - cd clib/mime && make clean; cd $(ROOT_PATH) # Where to install. The installation starts in the src and doc directories, # so take care if INSTALL_TOP is not an absolute path. @@ -52,6 +48,4 @@ install: cp -f src/node-lua ./node-lua cp -f src/node-lua /usr/local/bin/node-lua cp deps/lua/libnlua.so ./libnlua.so - cp deps/lua/libnlua.so /usr/local/lib/libnlua.so - ##not essential install - cp clib/mime/mime.so clib/mime.so \ No newline at end of file + cp deps/lua/libnlua.so /usr/local/lib/libnlua.so \ No newline at end of file diff --git a/luaclib/Makefile b/luaclib/Makefile new file mode 100644 index 0000000..c89049c --- /dev/null +++ b/luaclib/Makefile @@ -0,0 +1,37 @@ +.PHONY: all clean install + +ifdef PLATFORM +override PLATFORM := $(shell echo $(PLATFORM) | tr "[A-Z]" "[a-z]") +else +PLATFORM = $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') +endif + +ROOT_PATH = $(shell pwd) + +define MAKE_PLATFORM + ##not essential builds + cd mime && make PLATFORM=$(1); cd $(ROOT_PATH) + cd cjson && make PLATFORM=$(1); cd $(ROOT_PATH) + cd lfs && make PLATFORM=$(1); cd $(ROOT_PATH) + cd lpeg && make PLATFORM=$(1); cd $(ROOT_PATH) + cd pb && make PLATFORM=$(1); cd $(ROOT_PATH) +endef + +all: + $(call MAKE_PLATFORM,$(PLATFORM)) + +clean: + ##not essential builds + cd mime && make clean; cd $(ROOT_PATH) + cd cjson && make clean; cd $(ROOT_PATH) + cd lfs && make clean; cd $(ROOT_PATH) + cd lpeg && make clean; cd $(ROOT_PATH) + cd pb && make clean; cd $(ROOT_PATH) + +install: + ##not essential install + cp mime/mime.so mime.so + cp cjson/cjson.so cjson.so + cp lfs/lfs.so lfs.so + cp lpeg/lpeg.so lpeg.so + cp pb/protobuf.so protobuf.so diff --git a/luaclib/luaclib.v12.suo b/luaclib/luaclib.v12.suo index 06c616fc9480b614daa97bfcdf7d46f9e520af0e..80e7ac4b99760c8ab8ffc853284077932bf81d70 100644 GIT binary patch delta 2386 zcmb_e?N3`(7(eIIvNCR^jPkZI-rO9;q=Dx9wKKpqX^C z(sBz-qoN7zSyugIHqAb`#4-9|UzSKVKj?z)?i z=Q-zjp8NcsdruSJ84}Be`B!RRMF=r~^^J`U7*H9&cw_KyjGrf$Yg*0Y@?R$x9^j)? z*G8gD6wi_srr(TU|AqyGbR^St2k;Dul<9anvr@JTb1Bfc0lk1D02kmezyqMJdSG+{ z{(<=fdC_>?^j=;=em0JP?*~k)x#jhu@1>mY51!^*ody#I0BtlZ+WKHlolvKAEDegv zc7c99>AlC%gRm|(6RdXwDoW(#`S}wOw>DB+1zdn_?*p>yOi%N-I2j%w9TzR;`MiN7 zjFmSAuY-b3&8#xrC&(K61G&T6(n}U>AgksWK0_iGbUaK}pbwEq7391Yjv{Uuv6k1Q-srH+^iv1iZG$Pgk?w!OlQCXj%5B#|~|A8~#t z8E4`692u;CEp?G41NEz>gC+LxB#AUYC`ORc^w4}|>5r0?1|5%)NaGwy)HyFT;{*

ex9s8$o>*Q z$-x@%W4D+(wTIty-Kw1EuvwR{{pN*0!;5nN$njAlwH8zT$;AEC5WIq$J%;A*vd(#0p z4@a{}DL(-V$w1bu{U%CPK~BbN6Xp9r@LUyH`{*c3YmC-gL5~w8vPZ`{S^4-FOW#QP zh8C4mBvPZ7$3bL8nYB;vVwTo!P01GH2rLZbaq`#}+P@sHW46QJl_n;6yn_~OZE3+0 zFiNws4kewzS6UhTV+MaFD)=0m!*HI!h$XV8I0<1((xDwHY(ywp&R5UX3j`XR2{`S=w2P6aNCL!|^5n delta 1229 zcmchWOGs2<6vyY>nYlCSo$HwMN+(p3FeoT!(ZXa(Dv{8n%(50Oq8CfrM1KZ4^?A?Ouco5m`f%~ladQl$2 zwH_d{!_k#Jr~OT3j`9pY9EkJF0pIV8p4c{~FQ`(mnI5}vGegwNM!17tD_iLZ=U1e| zY}~%3eDQFhDnn7*7|hbxaBHYkpY^zl_{*KXz{api=Q%&T?BX07S<`Ij@~tOqETgDk!HsS12<6M5ov|wk_kTM*F57>2y56sf0CU)sscPq@TL#w!Z)X diff --git a/node-lua.v12.suo b/node-lua.v12.suo index 2ae0c0874af813c6097464f51c835d1da57e8433..a4c700952bdbd705fcd66160b325db91afb1a3f3 100644 GIT binary patch delta 4507 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 delta 3639 zcmd6q3s98T6~{S;Z`KLKH{69j*YwgqrNwG1SX^C}gYEo+xY$ao$|GPk9rmxJTo#~zV z?LFVQ=brE0bME6?XML#iaOkdVI=uVQL9|sK45OvTN@kLai_J}ON6hPwh;>{^SG;#Q zl&DUSHp($6-^3S`8!~^+BbFZY=8cpc;GwsF{w1ekbH;;0ER3 zd9VYx_*1{8szAPMwETuo9%JX>^XasQ=o51~9!6Fg*cUofA6e>IVVc-OxRrn2b^=0Mm! zFFJ$MEH83Ez#G7u9ui5^B_@X^;`f<|L*uu=Mg?(HuYc8F6$kY5fs!|%o(uB93fOH% z{cW|h<7Om6R3@rKK;8x{y}DzlzXR&QagYmoEW5k+L7oY;UfpcJyRara>R>4ttW=5Q zQ`MlP;l1N)LCYENb8r^?0-OVv{0^v1ltvC1d>M-0fVaUF@D8{N+Wo%9ya(|*xC#0O zr0PH5`F-$5a0`3@J_LUPU8-xYJD)U7nYuz!{$)@b$0!R`RMPr_`xOEjj`u5fUnZc+ zPL&4&`W(9d-v{(~LNben`|)DpsIgv0)T@Jpt!Rj7;gMcPQ8l^J>|Xnb`=MT2t(`1t zg~S0txhcZ2uiBHHBAiKf!@ij8q^ToJwMfU)Bt-Twi)ekxF48&7o3pZ=gw1nU`)jX> zx5E=gGWl;5D|XaJdDB+E8R5EdPW$s`%{Qz>s|8J;cS&WfN|S9z{%u~UX9E1zSr!h<@B)HoZ=Ofk4S7)aG7U zJqz1%hvpadE^kPkhnBgZ06fua^<;0o0QJIN+25gP#a>z?PF-Cl7p*0$ckR{PL7pq@ zxe+3q57~uoi}g-Sts+hB^}Zm4wZehg$f^{H$uAd5r;RP*+LA$D=N)H|s~f4Api;95 z20f|CqH5vHK~g_?H?-MGc|;{@gJl^ngwZC}Lny?3k)7%-{<30&V`=f)RdV-sj**QQ zc`%Vk;sHk6MNXyWXtG%io0-}Jo3qKGnVQjujg5BtKK;iqi}IY|hJ6IROYRhMnA4El z%vf2TLXTPcLsmz-f5aUr__Hl*v5$G!Y!@`}FN)9TMWvNs_Uzc}h(yu>Dm+5N= z%RHlV6b&;Q$?2q%*00x_>1Swq&gjgdpb(^ZswEn)dN9qelGiq32n7?8*&W%}s|~#l z$$piTCT*1zFAjc`sDy{~$4L7huLhLny8)b_IKBjg=EtVTORWK4;xgU zPnz3Gt(v-JWSbQ+>q)mny5mjHLOWW#dHb7sKC!-x%|aV#W$FwJ`9WHiu4ljPO#++>hN-g%oWM!{=zH1I)Jr{PLJNoM^bMaqI=S|Zbx-O6)R zYm%AOG{x3!N8(cDGMvSS_1^bggjy{CNlFTjlJA7Qgt zbs@@Fsc|hy&qlKUWqJ*T81WXqF)%P7phVJTS|Hb6 zU^MK)u-nJ8_ER6{1j>9D#mf>EgPpFCK ziHuVcad}r!?i5 z2FNZacSL1l3-pwczIhPTKMNUA$2*NZm7GMn4!@;yc?`0~nsIvzcZbRIGuW!m7TZ_- ziIoQ-=}lhnZ3hR=m?TCnT=MYe9_Om_`d=;A_7HJmk^L(NjY9-(GP{SbF@ia-Xx}VW?Am!s()bc z*RPN>)n~20$jLh~UR+P^TGnJ$3rFEoAXql-;Aq3R$TP@uk9wV$I{=C26 O+q7BJRWbtn-u@0C$aV4n diff --git a/sample/test.lua b/sample/test.lua index 0f4ca13..0a35f2c 100644 --- a/sample/test.lua +++ b/sample/test.lua @@ -7,7 +7,7 @@ print(require "cjson") print(require "lfs") print(require "lpeg") print(require "mime") -print(require "protobuf") +print(require "protobuf.c") do return end From f7172f6d39f8b07192ff0ef93d219953ddb07eeb Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 18 May 2016 23:12:38 +0800 Subject: [PATCH 097/173] fix a little thing --- deps/uv/libuv.a | Bin 881092 -> 879452 bytes src/context_lua.cpp | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/uv/libuv.a b/deps/uv/libuv.a index 0c50212137c471c116c80d71e1de7310037f6e8c..30c875f8b06111f1f35ac2e2e4946d76552c0f1d 100644 GIT binary patch delta 136899 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 delta 137851 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 Td%oViGI}m#pS9?c@ZtXhhF93x diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 309f16c..42120d5 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -932,7 +932,7 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t bson_t* bson_ptr; int32_t* bson_data; const char* data; - uint32_t length; + size_t length; switch (lua_type(L, idx)) { case LUA_TNUMBER: if (lua_isinteger(L, idx)) { From 62c6ab53d50d200c6452593da918a8f3135916a8 Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 18 May 2016 23:19:17 +0800 Subject: [PATCH 098/173] fix a little thing --- node-lua.v12.suo | Bin 184320 -> 184320 bytes src/uv_tcp_handle.cpp | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/node-lua.v12.suo b/node-lua.v12.suo index a4c700952bdbd705fcd66160b325db91afb1a3f3..7c756d4175a6c32cff8ec6e63c443d8b64c7c189 100644 GIT binary patch delta 744 zcmaKqUr1AN6vywm-Mj9b&Kun6q$^(6pcRseG%5yn5fnt>Dy)}QMm-EMa>Jq|XpN9j zv(gjZ9t`FxiT=>G``|+mrY}+t8d5Ea=piU6>>r^-yX*YK>a8Dq?(dv)&-tD&mm5zz z;%Ud_km%$%E@cc?z`JAfuHjv=!55&0ZG=U-8qg5Y zNBJN@rNz@jF|+k{=0>49XU1&f03lp2T@nO(gOif)ul)W$!dS4&E+)nlm>65c-1L}5 zyDqBJJjWG?7sL#~_CKThIe|?M#q4xk;awMKpqEGzB5{@|qD!t5n5?-$o`j527GQ0x zz}l8C#Vlv1oASNHZQ>-ci(nt|BHblPR{~o~ow^*AGcp5NM>yehxDmPmPTYP4>l>(!F9#&#sS}_|to>pce zJaiyz)y?4PvFJd=YkGfqK`39E!0uuzPVmhYcgWEpa?VZ!H(zTv;uM9vmADIUx(Z8jNUs_BS;d`6&PZ delta 1058 zcmY+@Ur19?90%~7b*^r^o7UV?Q`x3dCT6X2XgHmvP7S4c2z)7p1kHl9vQ1zXz+qrW1)AVV=!@YnmpUJcEy;R`?Aiyql69-t37W zDTi$EK?f9o3m!laFj^B|3^(~kGA7k~Xu>+Y`Ge?W@rnVoZ@?b74I@B%iE6R-hu{+|WG0#qi zpwYB^A8ahI{x$|A;g{#^!|1vKLy!VgstLQ*!P~HRwahxt{;QEt(@LkJ8W+{jfV1ee zLm2MCMd08UN35mA?Z~K#9{P5s6YcAWEszOjuz*Upr7l=YO2g^diaZ@MAQQ5H`g0O7KeA+Ij!*%bol4)6jE&Bwtg`p~XV(b$q@Oy`h7g{%-$X%M1GWZ-e@@^|{T}wU1V(uijc741Sy#TD`nm r>?*XYt6wviP;Bm5x0g-e^64t9K$kB+#SAAg9M7QUV6&P-&tiW8TtZ6| diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 4ae2c05..a991c33 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -185,7 +185,7 @@ void uv_tcp_socket_handle_t::connect_tcp(request_tcp_connect_t& request) hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = 0; uv_addr_resolver_t* resolver = (uv_addr_resolver_t*)nl_malloc(sizeof(uv_addr_resolver_t)); - itoa(request.m_remote_port, port, 10); + sprintf(port, "%u", request.m_remote_port); resolver->m_client = this; resolver->m_session = request.m_session; resolver->m_request.data = resolver; From f0d5715ddf8981c42be5e82a0453669e05d6e55d Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 01:06:07 +0800 Subject: [PATCH 099/173] rename makefile --- luaclib/cjson/Makefile | 153 ++++++++++++++++------------------------- luaclib/lfs/Makefile | 83 ++++++++++++---------- luaclib/lpeg/makefile | 55 --------------- luaclib/pb/Makefile | 86 ++++++++++++----------- 4 files changed, 149 insertions(+), 228 deletions(-) delete mode 100644 luaclib/lpeg/makefile diff --git a/luaclib/cjson/Makefile b/luaclib/cjson/Makefile index 980195d..880ee01 100644 --- a/luaclib/cjson/Makefile +++ b/luaclib/cjson/Makefile @@ -10,118 +10,81 @@ ## MULTIPLE_THREADS: Must be set when Lua CJSON may be used in a ## multi-threaded application. Requries _pthreads_. -##### Build defaults ##### -LUA_VERSION = 5.1 -TARGET = cjson.so -PREFIX = /usr/local -#CFLAGS = -g -Wall -pedantic -fno-inline -CFLAGS = -O3 -Wall -pedantic -DNDEBUG -CJSON_CFLAGS = -fpic -CJSON_LDFLAGS = -shared -LUA_INCLUDE_DIR = $(PREFIX)/include -LUA_CMODULE_DIR = $(PREFIX)/lib/lua/$(LUA_VERSION) -LUA_MODULE_DIR = $(PREFIX)/share/lua/$(LUA_VERSION) -LUA_BIN_DIR = $(PREFIX)/bin - -##### Platform overrides ##### -## -## Tweak one of the platform sections below to suit your situation. -## -## See http://lua-users.org/wiki/BuildingModules for further platform -## specific details. - -## Linux - -## FreeBSD -#LUA_INCLUDE_DIR = $(PREFIX)/include/lua51 - -## MacOSX (Macports) -#PREFIX = /opt/local -#CJSON_LDFLAGS = -bundle -undefined dynamic_lookup - -## Solaris -#PREFIX = /home/user/opt -#CC = gcc -#CJSON_CFLAGS = -fpic -DUSE_INTERNAL_ISINF - -## Windows (MinGW) -#TARGET = cjson.dll -#PREFIX = /home/user/opt -#CJSON_CFLAGS = -DDISABLE_INVALID_NUMBERS -#CJSON_LDFLAGS = -shared -L$(PREFIX)/lib -llua51 -#LUA_BIN_SUFFIX = .lua - -#added by xdczju@sina.com -ifeq ($(OS),Windows_NT) - TARGET = cjson.dll - LDFLAGS2 += -lluajit51 +.PHONY: all clean +CC = gcc +RM = rm -rf +##PLATFORM ?= linux + +TARGET = cjson.so +all: $(TARGET) + +## source file path +SRC_PATH := . + +## used headers file path +INCLUDE_PATH := ../../deps/lua + +## used include librarys file path +LIBRARY_PATH := ../../deps/lua + +## need libs, add at here +LIBS := nlua + +## define CFLAGS +CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +ifeq (RELEASE,$(RELEASE)) +CFLAGS += -D RELEASE +endif + +ifeq (sunos,$(PLATFORM)) +CFLAGS += -D USE_INTERNAL_ISINF endif ##### Number conversion configuration ##### ## Use Libc support for number conversion (default) -FPCONV_OBJS = fpconv.o +FPCONV_OBJS = fpconv.o ## Use built in number conversion -#FPCONV_OBJS = g_fmt.o dtoa.o -#CJSON_CFLAGS += -DUSE_INTERNAL_FPCONV +#FPCONV_OBJS = g_fmt.o dtoa.o +#CFLAGS += -DUSE_INTERNAL_FPCONV ## Compile built in number conversion for big endian architectures -#CJSON_CFLAGS += -DIEEE_BIG_ENDIAN +#CFLAGS += -DIEEE_BIG_ENDIAN -## Compile built in number conversion to support multi-threaded -## applications (recommended) -#CJSON_CFLAGS += -pthread -DMULTIPLE_THREADS -#CJSON_LDFLAGS += -pthread -##### End customisable sections ##### +## define LDFLAGS +LDFLAGS += -shared -TEST_FILES = README bench.lua genutf8.pl test.lua octets-escaped.dat \ - example1.json example2.json example3.json example4.json \ - example5.json numbers.json rfc-example1.json \ - rfc-example2.json types.json -DATAPERM = 644 -EXECPERM = 755 - -ASCIIDOC = asciidoc +ifeq (darwin,$(PLATFORM)) +LDFLAGS += -undefined dynamic_lookup \ + -framework Foundation \ + -framework CoreServices \ + -framework ApplicationServices +endif -BUILD_CFLAGS = -I$(LUA_INCLUDE_DIR) $(CJSON_CFLAGS) -OBJS = lua_cjson.o strbuf.o $(FPCONV_OBJS) +ifeq (linux,$(PLATFORM)) +LIBS += dl +endif -.PHONY: all clean install install-extra doc +## get all source files +SRCS += $(wildcard $(SRC_PATH)/*.c) -.SUFFIXES: .html .txt +## all .o based on all .c +## OBJS := $(SRCS:.c=.o) +OBJS = lua_cjson.o strbuf.o $(FPCONV_OBJS) +## get all include path +CFLAGS += $(foreach dir, $(INCLUDE_PATH), -I$(dir)) .c.o: - $(CC) -c $(CFLAGS) $(CPPFLAGS) $(BUILD_CFLAGS) -o $@ $< - -.txt.html: - $(ASCIIDOC) -n -a toc $< - -all: $(TARGET) + $(CC) -c $(CFLAGS) -o $@ $< -doc: manual.html performance.html - -$(TARGET): $(OBJS) - $(CC) $(LDFLAGS) $(CJSON_LDFLAGS) -o $@ $(OBJS) $(LDFLAGS2) - -install: $(TARGET) - mkdir -p $(DESTDIR)/$(LUA_CMODULE_DIR) - rm -f $(DESTDIR)/$(LUA_CMODULE_DIR)/$(TARGET) - cp $(TARGET) $(DESTDIR)/$(LUA_CMODULE_DIR) - chmod $(EXECPERM) $(DESTDIR)/$(LUA_CMODULE_DIR)/$(TARGET) - -install-extra: - mkdir -p $(DESTDIR)/$(LUA_MODULE_DIR)/cjson/tests \ - $(DESTDIR)/$(LUA_BIN_DIR) - cp lua/cjson/util.lua $(DESTDIR)/$(LUA_MODULE_DIR)/cjson - chmod $(DATAPERM) $(DESTDIR)/$(LUA_MODULE_DIR)/cjson/util.lua - cp lua/lua2json.lua $(DESTDIR)/$(LUA_BIN_DIR)/lua2json$(LUA_BIN_SUFFIX) - chmod $(EXECPERM) $(DESTDIR)/$(LUA_BIN_DIR)/lua2json$(LUA_BIN_SUFFIX) - cp lua/json2lua.lua $(DESTDIR)/$(LUA_BIN_DIR)/json2lua$(LUA_BIN_SUFFIX) - chmod $(EXECPERM) $(DESTDIR)/$(LUA_BIN_DIR)/json2lua$(LUA_BIN_SUFFIX) - cd tests; cp $(TEST_FILES) $(DESTDIR)/$(LUA_MODULE_DIR)/cjson/tests - cd tests; chmod $(DATAPERM) $(TEST_FILES); chmod $(EXECPERM) *.lua *.pl +## get all library path +LDFLAGS += $(foreach lib, $(LIBRARY_PATH), -L$(lib)) +## get all librarys +LDFLAGS += $(foreach lib, $(LIBS), -l$(lib)) +$(TARGET): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) clean: - rm -f *.o $(TARGET) + $(RM) *.o $(TARGET) diff --git a/luaclib/lfs/Makefile b/luaclib/lfs/Makefile index b1ba450..88c054c 100644 --- a/luaclib/lfs/Makefile +++ b/luaclib/lfs/Makefile @@ -1,54 +1,61 @@ -LFS_VERSION = 1.6.3 -LUA_VERSION = 5.1 +.PHONY: all clean +CC = gcc +RM = rm -rf +##PLATFORM ?= linux + TARGET = lfs.so +all: $(TARGET) -# See https://github.com/keplerproject/luafilesystem for platform specific -# details. +## source file path +SRC_PATH := . -## Linux/BSD -PREFIX ?= /usr/local -LDFLAGS += -shared +## used headers file path +INCLUDE_PATH := ../../deps/lua -## OSX (Macports) -#PREFIX ?= /opt/local -#LDFLAGS += -bundle -undefined dynamic_lookup +## used include librarys file path +LIBRARY_PATH := ../../deps/lua -#added by xdczju@sina.com -ifeq ($(OS),Windows_NT) - TARGET = lfs.dll - LDFLAGS2 += -lluajit51 +## need libs, add at here +LIBS := nlua + +## define CFLAGS +CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +ifeq (RELEASE,$(RELEASE)) +CFLAGS += -D RELEASE endif -LUA_INCLUDE_DIR ?= $(PREFIX)/include -LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION) +## define LDFLAGS +LDFLAGS += -shared -# Some versions of Solaris are missing isinf(). Add -DMISSING_ISINF to -# CFLAGS to work around this bug. +ifeq (darwin,$(PLATFORM)) +LDFLAGS += -undefined dynamic_lookup \ + -framework Foundation \ + -framework CoreServices \ + -framework ApplicationServices +endif -#CFLAGS ?= -g -Wall -pedantic -fno-inline -CFLAGS ?= -g -O3 -Wall -pedantic -override CFLAGS += -fpic -I$(LUA_INCLUDE_DIR) -DVERSION=\"$(LFS_VERSION)\" +ifeq (linux,$(PLATFORM)) +LIBS += dl +endif -INSTALL ?= install -.PHONY: all clean install package +## get all source files +SRCS += $(wildcard $(SRC_PATH)/*.c) -all: $(TARGET) +## all .o based on all .c +OBJS := $(SRCS:.c=.o) -$(TARGET): lfs.o - $(CC) $(LDFLAGS) -o $@ $^ $(LDFLAGS2) +## get all include path +CFLAGS += $(foreach dir, $(INCLUDE_PATH), -I$(dir)) +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< -install: - $(INSTALL) -d $(DESTDIR)/$(LUA_LIB_DIR) - $(INSTALL) $(TARGET) $(DESTDIR)/$(LUA_LIB_DIR) +## get all library path +LDFLAGS += $(foreach lib, $(LIBRARY_PATH), -L$(lib)) +## get all librarys +LDFLAGS += $(foreach lib, $(LIBS), -l$(lib)) +$(TARGET): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) clean: - rm -f *.o *.so - -package: - git archive --prefix="lua-lfs-$(LFS_VERSION)/" master | \ - gzip -9 > "lua-lfs-$(LFS_VERSION).tar.gz" - git archive --prefix="lua-lfs-$(LFS_VERSION)/" \ - -o "lua-lfs-$(LFS_VERSION).zip" master - - + $(RM) *.o $(TARGET) diff --git a/luaclib/lpeg/makefile b/luaclib/lpeg/makefile deleted file mode 100644 index 7a8463e..0000000 --- a/luaclib/lpeg/makefile +++ /dev/null @@ -1,55 +0,0 @@ -LIBNAME = lpeg -LUADIR = ../lua/ - -COPT = -O2 -# COPT = -DLPEG_DEBUG -g - -CWARNS = -Wall -Wextra -pedantic \ - -Waggregate-return \ - -Wcast-align \ - -Wcast-qual \ - -Wdisabled-optimization \ - -Wpointer-arith \ - -Wshadow \ - -Wsign-compare \ - -Wundef \ - -Wwrite-strings \ - -Wbad-function-cast \ - -Wdeclaration-after-statement \ - -Wmissing-prototypes \ - -Wnested-externs \ - -Wstrict-prototypes \ -# -Wunreachable-code \ - - -CFLAGS = $(CWARNS) $(COPT) -std=c99 -I$(LUADIR) -fPIC -CC = gcc - -FILES = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o - -# For Linux -linux: - make lpeg.so "DLLFLAGS = -shared -fPIC" - -# For Mac OS -macosx: - make lpeg.so "DLLFLAGS = -bundle -undefined dynamic_lookup" - -lpeg.so: $(FILES) - env $(CC) $(DLLFLAGS) $(FILES) -o lpeg.so - -$(FILES): makefile - -test: test.lua re.lua lpeg.so - ./test.lua - -clean: - rm -f $(FILES) lpeg.so - - -lpcap.o: lpcap.c lpcap.h lptypes.h -lpcode.o: lpcode.c lptypes.h lpcode.h lptree.h lpvm.h lpcap.h -lpprint.o: lpprint.c lptypes.h lpprint.h lptree.h lpvm.h lpcap.h -lptree.o: lptree.c lptypes.h lpcap.h lpcode.h lptree.h lpvm.h lpprint.h -lpvm.o: lpvm.c lpcap.h lptypes.h lpvm.h lpprint.h lptree.h - diff --git a/luaclib/pb/Makefile b/luaclib/pb/Makefile index 240532c..f7ac05c 100644 --- a/luaclib/pb/Makefile +++ b/luaclib/pb/Makefile @@ -1,56 +1,62 @@ -PB_VERSION = 0.5 -LUA_VERSION = 5.1 -TARGET = protobuf.so +.PHONY: all clean +CC = gcc +RM = rm -rf +##PLATFORM ?= linux -# See https://github.com/cloudwu/pbc for specific details. +TARGET = protobuf.so +all: $(TARGET) -## Linux/BSD -PREFIX ?= /usr/local -LDFLAGS += -shared +## source file path +SRC_PATH := . -## OSX (Macports) -#PREFIX ?= /opt/local -#LDFLAGS += -bundle -undefined dynamic_lookup +## used headers file path +INCLUDE_PATH := ../../deps/lua src -#added by xdczju@sina.com -ifeq ($(OS),Windows_NT) - TARGET = protobuf.dll - LDFLAGS2 += -lluajit51 -endif +## used include librarys file path +LIBRARY_PATH := ../../deps/lua -LUA_INCLUDE_DIR ?= $(PREFIX)/include -LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION) +## need libs, add at here +LIBS := nlua -# Some versions of Solaris are missing isinf(). Add -DMISSING_ISINF to -# CFLAGS to work around this bug. +## define CFLAGS +CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +ifeq (RELEASE,$(RELEASE)) +CFLAGS += -D RELEASE +endif -#CFLAGS ?= -g -Wall -pedantic -fno-inline -CFLAGS ?= -g -O3 -Wall -pedantic -override CFLAGS += -fpic -I$(LUA_INCLUDE_DIR) -Isrc -DVERSION=\"$(PB_VERSION)\" +## define LDFLAGS +LDFLAGS += -shared -INSTALL ?= install +ifeq (darwin,$(PLATFORM)) +LDFLAGS += -undefined dynamic_lookup \ + -framework Foundation \ + -framework CoreServices \ + -framework ApplicationServices +endif -.PHONY: all clean install package +ifeq (linux,$(PLATFORM)) +LIBS += dl +endif -all: $(TARGET) +## get all source files +SRCS += $(wildcard $(SRC_PATH)/*.c) +## all .o based on all .c +## OBJS := $(SRCS:.c=.o) OBJS = binding/lua/pbc-lua.o src/context.o src/varint.o src/array.o src/pattern.o src/register.o src/proto.o src/map.o src/alloc.o src/rmessage.o src/wmessage.o src/bootstrap.o src/stringpool.o src/decode.o -$(TARGET): $(OBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDFLAGS2) - -install: - $(INSTALL) -d $(DESTDIR)/$(LUA_LIB_DIR) - $(INSTALL) $(TARGET) $(DESTDIR)/$(LUA_LIB_DIR) -clean: - rm -f *.o *.so - -package: - git archive --prefix="lua-pb-$(PB_VERSION)/" master | \ - gzip -9 > "lua-pb-$(PB_VERSION).tar.gz" - git archive --prefix="lua-pb-$(PB_VERSION)/" \ - -o "lua-pb-$(PB_VERSION).zip" master +## get all include path +CFLAGS += $(foreach dir, $(INCLUDE_PATH), -I$(dir)) +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< - +## get all library path +LDFLAGS += $(foreach lib, $(LIBRARY_PATH), -L$(lib)) +## get all librarys +LDFLAGS += $(foreach lib, $(LIBS), -l$(lib)) +$(TARGET): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) +clean: + $(RM) *.o src/*.o binding/lua/*.o $(TARGET) From 065a9001e855264ed921c0a299b31524e028e4a8 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 01:11:34 +0800 Subject: [PATCH 100/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=9D=9E=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E5=BA=93Makefile=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/lpeg/Makefile | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 luaclib/lpeg/Makefile diff --git a/luaclib/lpeg/Makefile b/luaclib/lpeg/Makefile new file mode 100644 index 0000000..7046338 --- /dev/null +++ b/luaclib/lpeg/Makefile @@ -0,0 +1,62 @@ +.PHONY: all clean +CC = gcc +RM = rm -rf +##PLATFORM ?= linux + +TARGET = lpeg.so +all: $(TARGET) + +## source file path +SRC_PATH := . + +## used headers file path +INCLUDE_PATH := ../../deps/lua + +## used include librarys file path +LIBRARY_PATH := ../../deps/lua + +## need libs, add at here +LIBS := nlua + +## define CFLAGS +CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -std=c99 -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +ifeq (RELEASE,$(RELEASE)) +CFLAGS += -D RELEASE +endif + +## define LDFLAGS +LDFLAGS += -shared + +ifeq (darwin,$(PLATFORM)) +LDFLAGS += -undefined dynamic_lookup \ + -framework Foundation \ + -framework CoreServices \ + -framework ApplicationServices +endif + +ifeq (linux,$(PLATFORM)) +LIBS += dl +endif + + +## get all source files +SRCS += $(wildcard $(SRC_PATH)/*.c) + +## all .o based on all .c +## OBJS := $(SRCS:.c=.o) +OBJS = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o + +## get all include path +CFLAGS += $(foreach dir, $(INCLUDE_PATH), -I$(dir)) +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< + +## get all library path +LDFLAGS += $(foreach lib, $(LIBRARY_PATH), -L$(lib)) +## get all librarys +LDFLAGS += $(foreach lib, $(LIBS), -l$(lib)) +$(TARGET): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) + +clean: + $(RM) *.o $(TARGET) From f93b60d172be6ef0b30e45642cb07cb68cd0439f Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 01:15:59 +0800 Subject: [PATCH 101/173] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=9D=9E=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E5=BA=93=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sample/test.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sample/test.lua b/sample/test.lua index 0a35f2c..67795b2 100644 --- a/sample/test.lua +++ b/sample/test.lua @@ -1,7 +1,12 @@ --print(package.path) -- print(context.parent) -package.path = package.path .. ";..\\lualib\\?.lua" -package.cpath = package.cpath .. ";..\\luaclib\\?.dll" +if context.winos then + package.path = package.path .. ";..\\lualib\\?.lua" + package.cpath = package.cpath .. ";..\\luaclib\\?.dll" +else + package.path = package.path .. ";../lualib/?.lua" + package.cpath = package.cpath .. ";../luaclib/?.so" +end print(require "cjson") print(require "lfs") From 8baa8d8b42ef439b57cf6aa47a82f0d7c71cffef Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 15:14:45 +0800 Subject: [PATCH 102/173] =?UTF-8?q?=E5=88=A0=E9=99=A4suo=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deps/uv/libuv.a | Bin 879452 -> 0 bytes luaclib/luaclib.v12.suo | Bin 75264 -> 0 bytes node-lua.v12.suo | Bin 184320 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 deps/uv/libuv.a delete mode 100644 luaclib/luaclib.v12.suo delete mode 100644 node-lua.v12.suo diff --git a/deps/uv/libuv.a b/deps/uv/libuv.a deleted file mode 100644 index 30c875f8b06111f1f35ac2e2e4946d76552c0f1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 879452 zcmd443w%`7wLgAlCL{w15Cjp$$AF@sk`O?72_}$%L?DTIAoys=V?w5eBxYs^2x>Ii z8Yvap+G|@{wYAkgwDv7f6{%LV)>mz%wzkx&#p3OyRaN_WJI%*IIk+=Q(H3>`50j^|Z7v8c`g{yh>(YIO~GBvr8_R8Hvo`Bs+{mE|@iM zuF0`>gy#h&dftimXaC!f^t}Itzrg&km+^Pg7B4`5zq|8)Cca?)K0M9~ z{dfPKyWb0C`O7K0*&Fot8PCfZ;&0fDk9kA>{p^4@?7#V!`;!juzx$VWdBpo)|NBL` zmuLNjud4C>%fILE^}^2I@X`t1KlOL4)f;a8jfn5{{;&PzM^E+m?}oWvKK$eGoJK737JSX^)PKx6S2-#J2jJR>F7$t ztmHwmy1FT~y(bx8&wS|&>zl5QH8R=Q4WaSQb;KD@FeX%MtgR{4k!+HNPt5P0O8X5a4M?MbQyT>&bsA4sUQ2td^iS8!T zb-H`Hpg+-gb-bg467&;wV-nIr6Y+JO=%nj9x|;FP1-pH78zqffh}FIX){0OzU#6t{ zb>q`gJBcKE$$CqTq1Cwf8ShDg^YuERvEXG5$9;}cQop)g%riS|^oRfYua8Z(L0 z?sYe=ZCxEJWj7qC1V?XCm71AI|JyPW~gM(rc40CoJ@K>y%h7s32Dg_ zqzAK*nI;8*%t2UB>mb3sJ%jTN!g?{LDI0YOs=`Dp-DD|lnM7oFSAvHEiuX2|iI(Cp zOG(sUt6wlCEE!CjoohqVZTlTGMI_<#%-@OS|{2`#q%)!QGMw?e`RCEwS~@v7SVG zoL6y*X4JKU$t1g6N$Q+&Y7dQB6KJfa`l2k(Aj6oyt~N5oOit>FwV;*jGTerYNUUJ| z35--I?Po~?CWFu6*OYNOCJa*(v~JNj#`=zyZXUZhYMMuLs?B$E*VT=r7R$*-9VBU{ z(8VVEHj~O&W^y`a)_7aIC2lWEX=UG-H6cSr2l?LD5$~SeNDC{nD&Bpe6`$=}NVr-{ zL#{Rxjr*-c6R2MN=0jZQ_qxomNI#!eXhwY!ky)J1;%{o#>^+c?rjSAG; z)WK`uZmb)VjZIj^n94J&8UykjjE(oiIB%*`B08ydcJaMayc0dKQzu#?x|3ZzhhTC~ z#51Ba)5`6bbsyK*jr)hTuAcSIA~q9F-=3xUDNa$34mXvFEo zcm@FP#(LVCu5cK>Sj_g}f`Hxrj2!=Z}5y4=XPj9V7NeU$& z6^@`9EnM2{B$<8GnElpc6gOrQWSfobrEK;e$!y=^8L${mP8}R*_%$*gs@U4sPR<>O z9yz=W02=Ed7=jY9mep{=nG}7h)T$4zqN9(JD^Td;FC7kS=d4>x!z2jtLlwig&K5+E zBquWM*AA)Vw0Zkd9~ZmGCS=-5KF@m?_IQU+dn$U2BJjkatn()AIThQsy@1$mk25?c zRl*&t|GGoo^?77LAo@ndjiA7j3Lc(Wft2H^>87K2{YUeYldbr8Kb`~TVN4zVI9$Oh z;Yjkv0f;@YwY0SV=ja3W)Pa2!TUUa<#gv@5j{ofNX~ML%;f*1ZD{g#(+;v4pYdBExRMcpHDtg3toDD`B z=)Vp|pJJ!8NnD`0+(ys^x2`;d_5nM^qo$sYrwUl;R(LHZ`3uxw#hn$@8qP!|9#2j1 z6Z4bftav`hw;#^gjyB~tj-x0QTHxH{xJT&K7gKXj|Khjn1O_bZXT1^`YS0eGLO14 zg-=^CIMe>YphnFtd8%P5&0u2BrJW1aTZd5t#Hh6d#SVMv<|s9p48vV-ZzCrXBh~2H zNmEfHyW8dFFZC78kL_P#`MKIR)gO(h+3EDZ~6?1@XpuB1p0VYKc5mvJA7coF-YIhImdd3S3;E zf-A?SMV~PnqASPFE+DSR+3bT!HglSFGFUCOXQnN+1)i0UDn0>iW(rpoTH4v9B5m$D zgY$Xb)Debf*cfVUHx;5O;1l&rq{jh8hPr|Qv>~*jAUEnz&M@3Ic)>7J!2ntkrRDKQ z4u4=kh4{H~N(eJDYyskZ_{$|Q;N^vxC+EA1L5h4vhIQTqgk=`yE_wp-;rR1%FQ%x( zODP`qMuhLeC+Es7qbTQ^np=G#N@H@>kXngfdKqyWyq55=iPsZeVB)I@FEsJXDL&4` zuXqOW310rx+?6y>7l86|V?Re|qHSq(9hJx%whaNTbGW?ch?VVRnRrC}$L8nde+mhv z(0L9>6Dye;yGQKhlT~m%j>RMED@Wk%7M=9L2#)sOV8tNTkvF zVKhY#1c(11k5bSOpkh~EAAK5PPu`iRw6Gx_$)l`=hIllOv`;X^V@ymn#N*61*AV;i z;>fdC#O=!?Pww|A67fO?bGr0-Bfg+IuH3? z@TtkDAstM{`)n;TR52;BYL5<2XE#!|@!R z#Nh-EPv-Cx4kvPWDu<_Wcm{_N4kvLqnZq+VJd49A9G=bLIUG*qa2ki_a(F(6(>W~S zu$aRc9F}l6lfzjY&gSp}4lm?z4u^9&oX6pO4i|8E5r+#oT*TqU9PTwvf82cRlPVg% z<1SPls_3Cdw2J;$E5|g$;Xham?XY6kNDNkN?tjw?k+*k06gv#!w_#-U{>~E@SLlfjvl( zG4`zhxmCv4w*u5pBSz<2tY(H1G_cJToj?7#>g*f-a1ITChHF=jrE^z~rE^z~rE^z~ zrE^z~rE^yfj{+)Ufc3}ZOiYqEx$L%vi!?Aam(^Ab0(dhzRbA}sC7S|4ujab zjl+ME`)l92XLBvTKAUU#_1Rp@ug~UMetkCA^6Rs?mS3OEwXFMT?k6nko?||>?)lsT z%r!cBKA%g&t@_na@2TYn{-BmehCdP@`Npr0a>Mfp>O9g4ALX`Ih~b->`FM!-hHnZK zA?JwjY=k4RR>ojYq9k>5UH;h`qM?vzsjfSrg^B)As!&hIQ znb-RI%q-U@!!KnfT_eJ~!8+k&M7_XK2+F(yJ9DrYJ%zx)QEG$19qkkG0t^%-1b3{J zG^+C8jw>OL+ViQL!LuF!i`c-C`X7OvpHmZp(@(K1Yh&J@rIuet2IKtwenUcG_Df5eh-G|mKdqgEJ1WkGZZG(BH=A$D@{HK8 zHoZQCO`|a+85OTfw`704Zd9!G&S9~C&SIcZ`Y!27JHmkPWrFP7_r;*8EHvbsW9V@{ z?Rm3;D2#V0kU-!cqedd+VTkBNPfKyCGrrL)P9=JZ+f&WOv?XbJN2;l~HP)RdPHj+Oh)&15=MD6B`U7YB0GzPg^Z3Oo zw!Ia#dnk>0J=a1}+B@5s1dO65H+9Dnh+^#1C~CReyeC%#iJj{MGdyA|8Ya` ztZ}Igcg^Sx_wJdoCe&LL%8&fvhv8SkPebO+@Sc12_V?e@-rxVFa4J0co9n{8p=(!{ zt}N+);DM5G>7Kj$*RA`+x>R`ihVYK?19v^RrsUm6!VkRi;GS1P8~2AsL`rVGCp>B0 z&3hgU_3jRhjNJ3|x;Njv0#tH$=!D3cU=WQ&3uZpGr4*}|J0lAhMrhYZSKCyKj?;u) zv(cMrW~I%3xYD%$7F&{OqthqBVLbT}^dXuN!EdGCZ6mx@g61Yy=C?6`r7>nJMXygo z{7Rihjx=O;z0lxbW7u0kR|EGPiji3~BBju*E}Y$%^lk#t*q9&(fTB@PbU|$fo$%->1Qmn!e>Z!y z6cQ@w(Srpc5*`h6>EeQwo+S8yN6!*KsaCoL14$cpT4*~KEw(|+CLroT9xZkN(MBMq zY3&G_cbq0Ydd?*Rk{+#kt=t|hUqPD!S69HI&zQTseqWlvRPFv3^ZWv~gwGYEtc&192*ClJZ1r%c_<|y_WW- z9*m@BD+ligOxt@GMCny?XrgeZVg9j zYOCw3tE%f7YHF%$*~loUnk8NeTlm&>##$rj8y@Wu^m?x`o`o&(4%s;Z{Um;Md32R$ zzO&%(P!ju0H}G1TQtR5WYlk;LCp_8c)!D_n%rd^P5nE4N_31kvB)P1-ytb;kzHC)l zZ)aAjNk6lapqIIDy!Dha%-wzA%?DV~iI?Oi>| zh+FpP(z1pX^;8}+5Rt~ZiUw0l()4-6mo}#x_;eSer(b}gdPuG3;#8ZK0MFMlT~&>0 zhda2tL6h+*_dFivjSrTURdS`Hqt-`P*3_GhTvbi=k4)Bt49Xt=JJbI6JzBrIez6P% zRn^pseF>;9**Q$#_#s>eQWRYq&5{+>b(LseCP~YTDYqM2fVum$bamkSNyaFxE&kfd z2CVE*zZ4Q+T=! z)9?j@>nfK~+eWOcZcWt^aW{{C)iokcWuMLtr5URRF}wbGM1H?5IaR<5Y5TAtAbjF!4u z^uFTuuJy6vjjb)$emIrwK7kdLt$_6MH5mTs8%F86*7c7pl%UYeZ6?!_B~czN{JugZ z!Cq5efN45BY{_gAU0qoxRid+LJzBZxmsFqR1G9QE4yaqhDr7*k)t5)>>S-{ljb3WT zHOfw-dPl5{+Xb~LyA`pYjbEew07Y7AqO~ji3D_T>{FP>U!I#Kb{884*I%%o8R^u)A z;s?~RJ+*L)q(uR6?RWl~PQUcz*KAE~w5F^!>f2=|k7ZFVb7d6sEEkMiXw^4HBl8Pu=C;BCQg9NnJ z5>*K=L#aA?;#eJ|*BrdsA=i~H&FDjyRo5=(v4*~@fOKshC>oyI zHFpZq;~QkYdBl<{sn@WlL4qm06w@!3>Qr1^&z%uM%(7D=+zxfE3Cu*XQZVZ#zYLVQ zHcCrC(`T@>Fy9N)E<_u*8)>ZuFQG=!)*F{LRAD($UDepg;;;o;)&~6jIzJ;<26Y7; zS2KIF_Wv5Pwfm6{pqkkOxPh z71Q?&NKsYw%IHdtVLTmt%S0@dRjV)tg}k-5Rk!C}%aA{^Ho3N*cklR58|gyZUgJU>0O zK0q8KdkZDvT1bKB-`pb)mqH*c6Xd5#8DJB>Grf)&jS5)i715Iqb+2t)q zii;8R`?&R|iyjc!m&zzzX?fIt4ZvKPlw&hLaK_m4U)Wy* z-l6m#q^DZAR1fJV-LC#7V5HwsJACupduf2HD>a%#}%+z9;(EI0bWguLti?`U`nd$n+oHCk@hnCooqgAa7KJLfQe8 zdAYpwgmftVQ$@e#r~1Rg%t88T+$NdIhbUi*BIa`jInBCMzkYrjX+!1jJkMk*vhq?? z^Xcav3$s~wN`4!oxaL#*1;LzZ^6r-Wdz}p0el`D35E;sUtHpnFB|rI()&iPe`^6Yw z?$`s!TRWXX&wJH;_@QGCm&di8nEPg%ECC1~QmP560@1nhGB1;DTUiTXTU^n91_sZ6Eo zaSLdY^Q=t3k4yT;nLq6}jol@<()#&L#z%Oi_@t}Qd|>0J(OV-lUWNEq$jkTRb|mDf z)iz4?MI*@IE96lx7<`4iv4cS%A%9h!nH=&?$OJ(B4u4t}JMkS5C%|u?7LeD_i2q&i z+ofsklk^d2B16fUm<68>oaBe4o$wkQvK9!wUmVZtUf`Dq9uXl(}g!rtmu`H*VK$B*D$ULUu?#c)wZU1hlj6D(>MM7A7>FO z{O>Irm&$M2(4z!D1#x3*T9(8pv8|EbI$gr8;M zf3t8~en`e0;=e2OK1so+%J0{qRuA6+#LZcx1Pc5of>FSq2=+^YWBXyNBr z_yNIb<{`c03%ZUvxXzPj$oNI&B~0Z{w{Y7Jmt?_LWx<;*e2OLih=reP;Ui_d({`fs z|A~T=owW2+J4-D5d<(zD!fB1H{GYV&Vhevb3;qiWCl{)mw=JCNR`KH&Zu>1??zi1` zb&`dX{G+D396!s!k;KXFvg2P9G3wc?vFuh4a(`SAI_FM@f8BGQPBe5cnWi72kmQKkt_^2KCEwEwBz zJc{7bb*tiyk|}DEeS7W_e1(IT(E=G)o%!(jpOW!~)~j@>{GS@qUpFiMuE_6@bj3d( zHbB3FUnux?2ftG2I~@Eq@$=mdUN27lhJ#O&`g+*G>3cDB(S03VYUle>U%xQ0kB^fj z@aqnKs`%|s4&E>J&^nVYl|NVfnJeW`{8Qow`o^HmUn};Qt+r`7!=+s3I{Y^aezAjB ziF{gr+VYQ)0k|3*{Of{W@k5;P}2SUw1h8F=;>dIQUP6 ze!#(BHDbIM96T;^{=>n4Eal1!3)LzKX&kDp`Uf|T#@sV zgV#vE)A33DSuJ+{#^L{!^outfT*u!(I{1BB?+(6M?D?yM|BLV+bMUd!&ds;a)9vAQ z@q_sudK!OKnY5F3 zhrdVc>2&btM1Io2H;Mdf9XuiB?Q`&9;=8NB9R53mp5frX5kJp$@CIpz%N_hW zsV{xLsd~R8dM|VM$4a}p%E5a@Z;ON1NqdVsc&_N}a&Xd5SIWWP5&4@PT<66b9lT4* z`%wq)75le2`1L~Ta|!jsM8QAf@PA9}zstc_3;tyXr)O$(eci!7BYystgLjFYKXCAK zjTrAy2j3y>>O}`XQ{=qj;GY!yH3z>`?D@Tee^csFpSP%gPLcBdo5R0V`1O8N`M)ao zKOFu>u_qw%l>Zi~$2z?IQTU2 z|4$seO4{2m9Q-xGfA8R0t|Jbv<@yf?*K&;z{puer*GUepH)8pNAb>{dv^EKPl}$SIVLG?-xGv(?{uf^K|i>j$6uqpN#)Sj-1a4 zzQDoNKNSwH{%LS<^-r^dtABJnR(sSxTO5A%&wzuge?INt-ywmx?sf39#Sh(R&d?drMUVnDE2C@{u%Ayf0uFTOb1^h<9?Zg|6S_w z!w&wW_~DZdK2GHS#KG^EapZu5&yjMy>EJJk-~Qs@W2B#kWnD?h^!%KDGJ>x04z7C7 zba2(H`-@bL>RssYtKLf;e4g0zAqRg#@a+!%9r5R#4*sr`_ihKDDE#+3_#yHC4;}m+ zX;(iIoWzO<_Rmioypd7t6LREezx%6$YrD#q7Z~a{`fW41#tN=_RsKW=*L@S`I&xI+ z0tfGx@-EFHr^>-~-^5jp9F>2ygHMw7v&q4AocySRFBbk!2u|gtXbm|5*B2fB>C(R* zu=uH7)XwiYxbEY4!jYqPzU<(;rGNb@i=5v(xV~Thiz7$n>lPfXUoCIGY|YW~mQrDH zoh!KV>wSKS#ZTo`z4IJg_dQiOapq}yvV}{>hxbJOsSd8s?@BD3n(9>i(Y07` z^}{Y1_bM%ZDwpcL)WLOsR+l4ZCmDw8+ARDxIk?`R?{MU3eeH7aGBOI+FC6@{G7r9% zMgE%(uKV@gbL6OA^K)Y9_1hn%Ura1C`qlp`=S&CJ_r*nmtDhH0d!BFcOBJ%@*E+b)k9`iV^Tpi`uJgrS2iNiTpo8mp%Z4LO?bLDUEb*J- z+ONwUT>Dq6gKPh~*}=8H-0R@l4qLiHoU7{oB|_@k8$Y2SfNtZuu4UdT>5U?2l2v8S$&v#5S<6|Cs>A z<@fRNyW2R%<^QTzK+qAVT1Nf;6{Llry z?gF26fdL0NyxCT9czp)dm_c2dLD5+dzO9EZ$e_;2pr-7C&Y^#9-V)(>8!7DRz|DJ8 z;_1&r%Fv$fKNw6`$QOoYqtgg*ki!J@17lsyT>dmiWS}IRWUQ#G=znJdpHo0*0#Jop zW{{5un_<{2Grp0PjoL*Jx(}Ilft=JBdRJB4DZjD)vw_Dee)ju{fddr-`)+*wL+1p% zid$YvRWsFB1N%W0O!4|Cwl`IHn0{s*zdmo8&EcsT)G5aKPYt#P#{_WUrg#xPYJ!e+ zpifd*!*m)2&PlM2br1kL>A;WLh-u%%6A@^toFD;=%uS*aNQU{K zvl}Y0CJ`0=?>~L*@U^{4_tG|ImNk z5ij*iX;N~~1=k}wu6=$(h1u3Zb`6*K;qxD*p)%c@k(S51jt-wtVSWUjj1ca0t9|SM zhHlgS>0kn!T;Qc7-}$iDKdgdTAag8%T4_dp4nb*&{?Q&%vy{4xzoOYT(awQ9CFzDjMyJS{KeX;nP!a4npbF3Y?oEC5xK0?eun=qg(qp zI&Yu)jL+`Sx=hRePmLq3Q-;z?jRq!|hQY$9stylh_xUB_CNz-3`4gsB+y!spB!RbS zU{LJfzjJHxdyV3zYSX<*@rhVJJrzAl$y=ju@OYCNt%-!9&iTX?bQ}L98#`U&C;mrT zajr3p1)^c5PNL&Ql611pA+C(kH?IVTIore_$$Uzb6KimIfnR1bMUi*VSVAbATjAP= zGg?0m`Wd+Hoq^P$frd9Aci{0GpQZyCaCXPm=sSbX(^$(*mrh?8pSp~ARvsFHEqSqX zr~(Q$b`X?21(39BoU?*r9zUEXr*7EgBK!KUd&k=(b3i{T+!=iR^B$^U%`UQkH&qC8 zi3T}GV)QMv%JWN+lN$DRpADRy+LCd~0}q`L%JK%EFEYxKwDj=2L1i4O*pmhqd-U7$ zQTpv!i;wE5*w#RqYiHe3u8fmTe&)Il`RRBWbjVAQ9i0U~MuIASr()p8 z1F!t&vYv8fQGJ_fW*|!SavTEz*WCg#k2<3yqjOFX_rS<>HiI=B!|@}WFN7qg5z`qY zG*FoQ}rkb0TaY%SfmAo}v?{;_7{ zr{Z?gG)gl9h#K|*n6SEi{9veJTMkw{9{j<^Tj~9K11`&v!-e*VKc)s=?%x|krOrg5 z`VZkKrlY7!g7#Ky8^?=hDSLN?HU5(O`>#9brOeStV)sDw*x~Ug7aJA=3oVX3PfEKW zdbHMijxvIV70%|KHVn5)3}`0#tmAAvW+y8lj8JJ zgL>3;lDuhfGVG^`ILx2vWu^T`ksok~%^ z1O&!>m zZ%)CJ_i_MICWNQtr!=QdD)-OpDJs-=#Tj+=uBE?ll(3B@o54!mu z#wP^8cer`mN=MBVGB5EM2p*D?=8UV+EaYUlG#z>SA(f?|QIaZ$w4>+`Ygwx1RO#m2 zI#a>hd>$C%TT2y9c}Ye$;cx&By0ZElM!E}!W(bg%U@qN^V6nGlTaDbVZpk?QN{$1R z69?T!@U_8JV>g1Y4^9>**7v~!v%n2y5K8JEUJ>a^k4U$Klr^mIGH?w(dW$Qd+D1{_$B-GKYg~Co*p*bKf#L+85@y4 zKa5WO`cKXl%gH#LY?Ph|HrgDsRj5ag;oU7A26jT`(PLvXj~>I%z1v5RotSy_*myZe zj14@=K8I|AZ#*9|cCvl^*ePUzIaqC?eG-|TD3);unVu*nr;eSTc?j7VLmfhf&B=W7 zmmESismL3A2pJxo4}IL&nfA$KXJwu}HpR|jpFVc>ptHtAW5(fVQ~m6K?d;RirLf_1 zMXHqJJTXSd^Ko_=9|}hk<8=EVv!eV!10L8Hi>rixhMtgCk~a3@f{W`xy(suCT>nbGjVegnu(i}&`jK%gl6LABs3Gh;#Uw)C!yu7q%UxhOTE0%Z4}!Eu8;lB$z^nM?Ql%s|}B$sKiH8oC^I}eDX`u zoDtK;V|3#ejsXsX9MXY@@C%2-ILzg61c!Zn5%XDSTsQnQJjoQ@Bfhy50$KNnhe)=> zzeRA+6lxWsT&R(-WfF*RxEbMSDlpeYet8e0w5~1;d>r8z4nB<3F_(c0IX(rHca|Rr z7W^QOQZP=znQ|bTA@=0`0WY({hL8i<4Do0lIbnh!9%EvvA>=?dL+F8QN-cnj{i10f z=XxQ7I_Oh(oJ1$gXg)IfXa;r68;1kg3XG6GI!Y17@5@__`E|QbeH*VRANDCa!RpSS za^3?4cl#8T=AjH~ZwB>326fP<=u1^ceCk@rd^n^UJ_M8Y`cyZl{XX?0?Pv!754$t7w3=xw!KAFQaIXsKQDIA{7;W->mXEPiI8Km zycOspnMyn`9vx2!a;uETZw07NM>K`Tg&9iFASj2o6+HDB)p?*`Uhr$^r-o~O(9$_S zXz83Ev~)@ej92vQH;D~c8b^I(on2n&LAexObW3xds{4)~l8 zgF5I_zXNs1r)Uh($zlN;a=(oFhSE7;LGTaAx8G0W5i^5&IUrTI|9fx;*T;c^uLS8k z)}{dW*}l2Y_RW2^Z|<{wbD!;-`)uFbXZz;<4ByZ|)D;zPUeW`{w?j z?VI~Ed}Ao}&HWj^xu30kL40E<-#1Uc2zRh=?k^Y->cc)w!#?sMP?&VmPdpVZnUXEqCmt$G(&Y?xOv1gZU&o0}ZUA8^DY`Qe=VEl+-! zGx?r;p3XQEd#=ryj0LkP`)1po&9*(8ZF@G`_H4H8*=*ah*|uj(&Wn~kTQco=VLD6@ zdp@2+3wUGC?Y2F)+xFaU+jF~Z&+WE7x7+sIZrigx=kJz1+cWKX@e#FWZNZmvY6{h! zdu@B}we7jrw&z~ko_lS3bV{w!~dZ|e=YUjbo?)R$}7+LvqD+LvqD+LvqD+LvqD+Gmb5RcV&3 zH|Em41CF!A4N$>NxtCg##!W2Y1>8lV6gRO1-_n=ArIuC{4CKF!1y=>=jPG!mPVqh^K)1To6vl8ss|6&{O@m>+I#9~YOA!`w z@y3w)F|?s^4CMtk-7gsKo+>9*cZq}_X>v#5EcebLpX*5 zVWf%IFy0s_X2uJcaXB$^K#W>+nuZMb_P|xl-NM}06E_F6dSh;py+v|K31d~rHPS(-8s`RV4yvqv72}X zAwA!u$Q|r%o}VW`H?8gDh-8R*J~!!$GI0@Q2oYrn5%oL|vn0wNM#FeENRJeaN&E81 zJSyks@EH!%YMQ66Z-L}TtMrgy+gmovPwXg-jIvU1c zolw;KVcnS|Z3>vIBYMr_Yy#QmVQ(}^5heO{n6wpvogKcCouY)rZW&4}fh=~sH=6RD zN`ivA`QMhh&zE|yk-D0tzBH6n0$FOIH=6Ppskk$CuE5SyPf>@wY`nYrtZpy(bE9GH zSvZ*a7g7dqigD}jvmAq4H};Q1Y&4BBl6`Ep>?{53WBu&Y z*o3pPW$E*?oW;c^jiTnfY<;a7X>Qtn_>?B_y7QBb=uT(cy{H zYKL;#XfzTdtJXE=vTWuo@$+03&`OsgT$L@)cl|t9iCtG3wMt5fl#~*ENDFa39rP63 zoUV3J*q2S=9CUG`p-&YWC*7zbxg#wDo7L;5vmZa_t0^MdDZ}CU~ce)YY zXwoTmeJ`6`p94=ZUMK{=r)Cu=VknxDtEuk3uQsZ|6_B#eDvJWso?6J37on z7pxyj_aA)S^{Ts=k7loz+~vmK4MAEVz!*cW;u`~)W5~;dTx-bHlDGZ5xEEaGn;{=&|z(Gn0WTge(Xc8()zdDrC;z_FXtG3dwW-9%v_{=D! zJhoE1WKR#J_+&&AK{4V#S7fgc;@v{Vfo9^Da8}eot`P*qmVK+3Smz<7oQeIpe~`4~8GybA|P< zWRLalk&^H&po8a(#sBcSaB<1=5}y$&3@!~2ZzvJIDKsVm@sPLYz1~OPe5-iRo*Oom z^oJ*vEZ_5qaPbC2ZV4~n5MI8gcX`R4ABHb~`k6f?{i%{Y4{Qj(xgmVlhIcoBe&ElS ze=U4s$)Pu|*n{hbsk`0^kKME9P^jYzp%cSxXFu@Z!je5;3oo1*9v}W;{L%1=c<}78 zcZCw$FJ2rP9a&iN&G4`934iOJJ(oWc>fRk17YTo2-JV&*(pwygtzH}|xTyThg|l7_ z-xZ#`u;f)L(d31p$GxHlo>{jcTpWJ7cVWr9uRIb?ed0jLo_7)4nhM{za{8o_XN&g) zr;H7^?+INS{zmw=-qiB`9k`Y+oN@TCPlw+OP8rvKOL#^s{C;Z9p70qz3{N7~`0mhz zND0Kg8GZ$SZ$5C>1K$Q2JacULmEc+AE2RAkw$@B#-@bKaczLjVT=?DaE1}+SQ7Hcs zVLtGF@T?QVz2OyalEH7mkl=!`5CEBDe-d6EilZ79hfau;ycMg9N! z;aZ(G+8bP?bRoDywY5eTEsV_YTACx17DlE{-Ov?pjhs7e#x&2QOfT_fL>3~254=dg zC)ZCcfiGs04=9Vly%!S{_<-u^i}Xy{E12Ud65A_Dbkulc z5$vGzG;l13Ic{31%tJYFq_QUXCwVlrw8XlTPA!nEHn1ex>4=U*%t>Y;d^iZFHtJEL z$Y$8-x5CYsaTR6@x^qX8oPF}7p$y}>xF;oLLkOcAQY6I_EEA^!dut4Wajz-Wk>vA7 zy^RLrvq(E*y&l~lA{W!Gv5pu( zV4e2NdECFsNRyMI-^u{Z;lT;sAE`q0Kw)~bl0IQM$;*l~o#5Z4*Gg)nIntwjiisv1 zfwMl|u?fb}ougp^BB;qi5@&aX@LT zX+4zFJ{i!-mTnOAyc0yKl?ZyI4uVb(21U=OiR$X;07Va>DHpm%4@i3KM~QOQZ_=YD z#Q<>bGtT=?dh|RPB%eT>^ytAfC_VI;9{+M?bF^{Nqldcy+7jkuAmpdlYX%Yh^jH^w zIZ_%7^l%U~JH(?W_mtS4O15_Ob|RS``U7d{>gh#jd`?<0d!Lb z4pnMIZP7*sO2^SiMAA+MA!iazZ%;t0JRtOL28gc{5N%aRGvS~n%1O@;38Z0@XnIuu znu`UJUc-a*PgJH?r=a~-M6bSyT^x-Z^zs>q@ib_9`3ss|4U*n&f{bm9CrKT>GX&|o z77)EB10=2lK)bytOHWT@!lUxs1>1;t6Xz=TKJTaeBzFyYar4Wg(8COq1BK$LhQ;nACa z0LBrp)oOAHk6wEtQ4YoO=$Sl7kqHb|o_9X}0OEp=tjlbhwE&4O6}CLMkgfvx950^+O@~;2L|5{u z=FsamAfT1yE24a+_L7RSS~^P{SVMUY?kCXj$z=buF0BN63T^DhQO3woQC0;x>66Zp z(XVwR*EUo&R#z>Fdh44u(V^@yKGPdarWr|uPhOAKmQ^i_l4h+u)O#FfB*)t}nI5M{ zl5494D;ufSVyvY`fNU72`Os!q5Us6VTIcZs)0CFaPG8zk7cKWN&bGyRP-4^n=|uxK zsx~^^nYkA?)U8R6@+6MWx6e329>!eesd#^Dq%WG+mceMH^s*{w} z<)c&J@ojJSk`+-;5zQjg}}?OH&GG+DqF?cyg{Aj(qcEQAiH47ay_pZE-9B z@cfE&mX(*+R#n%RttzWrK`!&B3B+|4A-wDAMpO2(@}+dLe6p*ht3!RvD?oqTA+am# zmeo~W&K0MNC2D50G(s{pfb!_lvW6A)TC9Xe<0lW8&}KI(^#d$R&{=Zk0h=hxRu@)Q)kkZq%B0zt$*-fUb6tdkR3}M| zwMMArn}sY4MXO6(9q%R+SC*|tKdh~;ts@is*%T>cdwC;Q3w0Tc;=NcobYc0^+vT-2 zT^-Y2W0jZMab*=cFbUJXo3IJvmx}7T`i3fab4dlN1v5T%b)8^4_2x+YUsJte1$)y- zUs~-^Bla)`>Zn7mUV_1+Y;kpMJq8cZ7%m&@qE+R5Q{}aGt#68V8hI36R$E!0F`luF z+WL~Z$hFs$iFO>f7|HM_$~e@0jxIsSD$~1o!9rwRMT2RJl$Gui@R^>*38eLn-hE+_ z+a2#rXxB4C4w%du)bw;SIwZV~rbLoPZcj6V&)jm5{M35Vq$>=vqX+0slI|5{Yk0K7SPOR;Roe70 zsL)`@_hxV~6-yTsWcrda%&;raB-Qsw=Z-J8vaGMBY{_yn$x|baE@9{R11h^)Zna5d zeI@#3bwj;ACG_t?jH~L)D{DPdjAgZDE7>5qp#_6IdZGiFJI3^IL8An?>MEDfh=N#I z-I}T;Itz=tjUJvItMLOSD3QG!q#zfNw(=0o?xMh@8E-hP` zp7HGoi&nI$7A_9VVD75w#SK_+z+gE$K#Pc%WP>S5#IlAM{9%4}~?dG3KB!zR*St#N}m+vF0S# z(9NS64$W;ONvx~IKwaG4wLVt7v9;ye52uQk#gpx+=HgDQNT+wCnu=Rv-3dHdCkfot z*|X8I6(o9%tdq2pr6*!}HUJf7u}U^!QdknLW9zKZGW!z~*N3pcUTB&A%~LWa8Im7e zU0GMpu_|7Cb7v9vBD1;kkw`LgrXzc~@^}G`r!PE0n#Nd<;mu4E)Qgax7Qki^LCerJ zTqId&SjCk^1Q+c$mo+i55=%tvuFprZoT5EO0+DvOk|Ccd4>QADgP9E@3DQlv& zEB!UPKco5&d62A4?hsq#if}g{0Cy`he&Kt zZFPNh{hAtXW!6JL^gWKwq|vga>5&maXfUqBvK6<4)Wa}x1H7!db~#UhbWdP9LiEz~e8l}jpZ7$Me(!MbM?iLYL+_VRc@_G1L3PK3lL*6SGDxJiISV)|Z{ zSDezb*@NcsL=uZ-yzA=ZB`k?RW#|Y@o@f73gnejcYQ{{I7IwTEW*_;hJ2r;I)JExM z+YD0#O5dc_A`g#RLpqSr!}vzJe?_U#1Tg|ME^Vm7Jxz60Bj2cr02&18hJhW7l@{MY zm?eQP$}CDSWa!F*idV``y!>9r1tUANtak=sB$|$cN()G+S83(FOacav~qV#%aWd;Q^_*Yh~GK&anh^r?z zc*~Y7nID;o*?-yxnEd&92_DSx6}Yz63v4V5Of1L?Z^v_DJfb&S;PBZ<9A%>lKN4Ir zGBU4e=j5b z-~4pXJcsk}<|nPcA+0|m>3F@8PG6HwFO~GW?eyU1eEDl7{dh+D-~IGHNiVh2H>c&_ zE$J)l^x!f-|6WON&Pcz?Pd_N>S7fBG^3&y~JG=|*^zO9&2wwfuRYHNbj}DU_0aPmK zciHL7`$NIo(=u9xr_|=L%6PM+UqE%GIzlu2esHg(KW66-?)J;@grpCnvikYGATdz8 zenZlWGt$rX({u1XhORaWG=H$kmw%R|uggep_S4HHJ(iKameakW#HRJhre=I5d(3CM z#(Ho!T$H4zhDE$UDQZq65REmb)-^UYH`DE35%U-*-r3fb0bsXEOn{y)Bf(FNK# z6@d(D26*w6ag_??J|Y*_`@DD?Yrd7@BPLSVV?HE>T6`Spxtl@-y5d{RG?AuA(A^Y4@Xtcfmfd6xW>@qUFaddqHK zZvKmr=$482Z@tmv+J2GwB>zzzx&EVh#+6AqZkS7<=RM*$#^tR6&rtd&Jj&V47pM>= z{iNH~PkoqVI&Shx#qNlcfY&`4R}-kA^v@9e_`)?`q#y662I;34JZ_mN!`ej@dftmp zqCSBXKDG2Zzv)w`_y- ze;$}Clk_!2Da6k;m=8a6dGAEZQ2LLGe$7wir@C{?{|#WSOhDc(A5i~p$*+1SFJ0f0 z{6|Ttb*V1>d=hCCck@5M3m|+Q&dN(s&8MHwS(wfGE6HzT6xV!;|6VYsnR^E%|60en z>Oal@8$=uyPMW&caLkbYOa7-JMf2FW3Z71#{%_h$g zdF4s#wX^W&>ZjzP^dIan`DY9>pBlRQ6?Z?0FUR}yaTg~#G^iE~S7=B}h<_*#6Ydx% z%0h!?LzS&?qr%1z=ohzGne81%L8e2+T>pJx|v>{1L9Sttn)FzlixX zxP01ZW7h#+mkItwhre6!PYF(AtzIGX%Wz8ipCSF~ zo{yMFh(}5X1Q{~FlQt+JWWG!|1Wv7J@D<{bU?^PguG47)D33FQaw3)U1bFV#!m9Q1 z1;OtTobQzpzb}iN?`6U1M`(xA`|~XL@3Y{4&Vq-~ZibRSHVZyE3qCUozBmhBp9QDQ zX+znwAq#$M7W^~7sa{6oldg}L5B#Lu(DHwj1*dU@S@7>f-e#I_lZ5tV$bp{{MEugT;?NL4tcAx@ONdwH)O%D%Yxqyocz`*dM^+=@65vg z1>ygU@YDS$U3;?d)3(>4{QtDb`Hf6~j~OxE&jtUyOo05%25GMg{zbVz=Vvv*|0MW} z(y`h^4(*{GO7D2|H!ANO?8&2Ro%!%43;qScV}j!qG!92=p@-V(S1d%>ulk01{hNW& z#<(G#)ECW}HEUj$gt=xPe#YMUp+(G_W2_tEwJsUTkKN5)B`!q9K94~!4~phoFmJY( zewR%21-x}Fb01E|-n}91nltx;p^G+WUY0V?y>RBxIp$q3i;F0m5m1bDOkd$OCGeIl ziLKaivoDQbC!0hnw!9`!1N62vP0^dJG^MX7(unN0<8LsKIJ2w5C(T=)G`qYD@zeGF zO`5~sWs!!=OA|kjzS>GN=!PAiWr*)OSY>UEq0n8M*mG3AjHU#>%vYgyd*v+LZuH9? zOwgXO_58laYs1?%;$mF3l#pthULRXeUp@wGy*slgauU7$qkR0@%>uATfpOZaz|Q11 zNW8;_T<@nzO)-sESmZ)Kjq8jkyQ_jszl9~uvPDHc8tD}In z!`F`Ec!_PHpTlni1 zKdlv1{@a4P^{8j8D~>FD9d-ES@vHYAmVCP&^^2oq&xQC?z2_2u%aBH80sl$((eZH=6agnpu!GAA!OmO>9 z&!~S?{_Bn$mH!6^SNq?|BL7mX)9IpQdS;~c(rDrIXkYO*!Cia09UNKsN;$Z;lWQ&c zc6o2Xx{ofhhoUcw-8-`2pBJ3$ktkv~OWxvN09x(;u7y+d1(E--;55!i6fqp^E%eBtJZM`{iA4>L= zTk=0@;Y%(2lNP?r!u9NFl2c*f`z`(@7XE7sue9((7Ji9^e<=?HE|On`KlR(UEWFyn zpRsV8|8)zmvH0J&@JlT`6b6Bd^wKj3)mtREwts!jIM=}`FI@{=T*imRmi%+Tr}8T- zoa*=2WB{(1h1Y{t{$2~W{cvj*{0<8z`8vLQ$HM8^tIB`e!fpA#v~b&R?^w9)=f7LH z?azgBe@(@tXEdsJxrN($2Q1v?{}&6l`5(6M)t3BMEZnyLpoQCV{>{Q|``@#0n;&Pc z@I~di+|s+)!s!`-mbc2nue9(63%BKe$ilC(_%~WOy$ewJ{T6P^zsB>g}-bW()s!!ATrN^?7bN?qDT;)IG;O1v&Jn#7|@?UlMRsI_euJYe@@KUk=Pg&&u zKZjrCo1gu&)?=c;oFI|LSBU%*gK1ZG z{q7xY(zTuF`;})L+;G9q4zB)xS#a0>-#Yv%|7{0X`G0b7_5ZtBn!|X!PTGoUTvR)o7^}E+QGFwJZs6f+uJJ+zsmoegRA_v99-MO;VklH z`NQ`?vSedXGE6ca0TPh;M%?4$Iv?m8Jn{qaf0H7(=zTt21{Bk`l{rp`Ae^=Uxz86vZeS^{Fh6)?B_EPq`xM9`!|PwulVPE2j4FK z|A&KrQrcla%AtDo{wL4D=Zju_U#$FpmT^Fz|0#Zt^b2|)PM6|K#Ev2dzd_{8ckuU3 zcCX#Re=UB~eI_bDE`Iou!@o|-OYgVoQvMZEFLbD@jnhxl(e;djFQbgOUUBdTgw}na zD*tgQ*Pk7J+J8dVaR;9*{3E5msvKR9PIU0^ikxWe5uq6y~n0Y?f;gP>rMy1PU`C`4*o~+^LHKmxX9V(;ETjgdXH`E{l3)u zZyfv=|;I-0EuW|5S88JAt&qUN7ZC9UiaBWw2JNPu2U%uhsZ%VnIaPT)o@AD3Rn)vsa zgPUI$$IqTiJ*b_FgucMR^CW+jgI^%+VU2_D5x;df_(#Q_9tZ!ejGr4Fe51(MeIRNl zo$yE3%?|%q?H3NN&&9SoI3G9&IiGg$T#4{{M}G|4RDf8xH=c zwA(*AI6DWy5eL6Y{PR}_r+q$j9dmF#G8cGI>{9<+C-ok7@D8zOl!Jdx>>uag)v_Kq z#lgQN{?zrC>b+I?&UW}OmU=ng!B3ZVGSk7oE#t{t2Y**+9d}jlTT4nAJ|Fwen1C*``>!N&+4b?{|U-sKMdP3aexI{3L#uFD)eCjIUz2cISFyv4zP zBISxZ__w9h{zt({+=B|A*A~9S&|zu=TvpIryJM{yh#pTI{*c z!F#11A8_!~q`cp8a9zjja`0Jv#h)KbUlIy}!HB!6%BJZ+Gyif`8V*pO*e|pMz_;zU$yxE`5Ke_G`JG zbNIDfzjAOb*C7Yja=q{1TCSkjt9m;rf~(NMS4jIg-N9cG|DW&RpOSi?@8J4;s=~ql zB;)5Q2iNqP>1^jK^_8D?o|JC;P-rwEIK5M=;Yu2n;vmX1A+1iiV?>!B!{jU2*<=1{c z-SBI_pKEaK_o%_O-!Cz^_Pf6SjO={+r~Te)__f~`8(jPSHiK)wuQ9mx`?n3Q{l3xQ z+V49I?!H>?c|SJzKAE>)Gr0Eqn+Df@|G?nd@7dx<$cBBi-}QP_aqahf!>|25)Zp6h z=Ner5H)`;4R5y-G46glBXK?M8R)cH5+-Pv^r_USwi(;3r8eHvpx53q(KQOr3v)$lo z&u0v-_I%mkYR}&oTn~u)$xDc{2EZMLyZ4O8R$?;a?{FZy0>0 z*x_A+>;5=H%Bh`K$o{0e!50hO&){m$0)wkPbsbRoYR?M|zuL3h;A+n+46gQUG`QMx zzQKFRKIdkG-zRqYlEI5)Kl62i>;3NU7+meJ(co%_Ck(E3__4v&4tif!?WT5k)9|Yu zJ}|i2AzSv{DrcKqcl0*6+Tmn_>w86o27dtp=@@NrwL{e4YKJO=s~u(;Tn~w!zg7`dmoc zrFQ5l^MT@OhvN*cb{J&vX>#2$!r*F$3k_Z+^XQ=uJ(Dz;A)@k2LFk3b8oM~)jn?-{Bhae{KeqM%k@-5UT{%6 zJSq0?V{o<4K!dA&iVUvyInUr~pHhRXeJ(M$+NajwYM*%qFO+e#+~E3r_FD$uA%60J z!8Z&3sKM0^y9};&_?f}g4sRG-?eLDl)eiK>mwafys2#c)T=u^5Ia=>Hndf^Le5?3Le}msA zb~wY}1)_hk!L{Bg2G@EoGq~0}$KYD;bq0Sy^jT)`--{hK8~j}H&us>OU)uYW!EYA- z`LV%IlYaT7!RJZ6zcKjv;#j{k_-itsykqcvV$Tl@uJ>h*82kp2pCtjbw12-Y^1B-R ze$hYA;CF~Uk2mMA(Qg{eWGyPaE4tGW=f?yR`-Q!K(GHGPuV1T5IH}KHoLC>a!^z2m0(4zuIH?|0MInYXN@fqxJsA z;2O8+JtIf`?L-8mqeJ^k@AnN69BM$m${B8Ojek^Z@H~1Z5=hBzh6J}VzM6_#m<8T*M3wvMF!V6bYqMhm0xD?^Tqy`rI9ns;QId4)kcoWzscbL zA?wj?Y2@5)aEfh6b3kylr`G!igKL~A7oa@ZFRD+^ z{;BIo04AuWE#mqvNi`;QDvA7pIXk!{8c!s=>(ljM!~~!F7GS#o!l+ zAAZ^3H%WWHBe=HrSXu8LH2klMoNb0*^?b_U8i(s=Mvm6I-{9Yp{q6e(*ZDbog6l8n ziJ_~1AKgW8oj7}ThX&+8^j@(;nc+W9_C=Qk z_`#}nm}PK{M|Ovi^McGv_om_hzQHw)*qcVqhvFxP)9`!p;-dDu#uq!m;ID}tPBr*n z1TPd^?LS=bVuS17GfXyewBBh3*XQoFMoxbyOh>E1@0WU)82n1{t1qOH{}qF4{IZ9P zoFQ^w@zFH=I}H953_`~~BPUn%`CS_RKN?))hh~bis-1NnD>V4M;{WFguKlZWE;RVP z(ykgK=T@h_*O-R?YJ=-@&BaEJ>iKnp>;1|54ZdFVdD!5HBZuQ@gX_NHfWf0OPX8dd z+ClaFz~CBJZg@Udh(;8C>JmT_?E8 zQM-M`;QDtEcN<*w{C+?_^whtPe%|muBzFE;fFCAPeST?hjiYx+aI0t60aTa{#Z}LK z23I`?2@W$tPyIXJvkm`svL1~I@Iz14XM({seqWW5qxOs${7W)#T$e`95`$|Tz%Lp( zDu08)C&_&Na2h$=4X%GDyVuB3d;Z?wYR^9fTz<6SpTsDAImhs8+>Z*wul4HRIYNF|WZ#)Pj^NV` zzCrMr2Hz!kgTb}lc?Q=w(+dsWOXMszxc=SdGJ{_t{3{Kv{=eGbs?S=3j}STc7+m{( zgTeJZoQ(!A5jpJ!*Y{&(xnlp(G*~qaztZ&I!gG;H2dWG9dpZa~2!?E}_>NT<>GF8(i-vyl!y4uFn)ZX}x+qeu}~MdVIXW^*XxF;JSX@Y;e7v zU1xB;e%x+wy?%V%;CkJcDaKX(^}6X4gX{Iqc!TTpPMyJZ|9`W=b>F+r;JWYKZgAbl zzHV^cA0mD;4rJq>?hj8fxbEM^8(jBe4F=bJ(K3VUzUUr<>;7S>f03_O0k;}i!i|M!OP;|+*T*4gB3ZJJh^Q>TA5?E32lww3IUZhmFNgD>6mYQJ$*V1M-eUqv7LZ7)hvnU(FNykCqeahkcJ&}4^u zDIeTC9Y@=CNG7S(7G@2Wd(oxsiSC@H?A=uD!7QF6jbv_OafG^yV|r}6wilCStM)scspUKN7myT@fo2Dk>#T%r z25Q<*ne@*!1Ks2Z(a%-iMoKPObl8iZ$dXj|wr$K#J-Ly>b{;v{lSyf`7>tw(^$eZb zJ+Dhf_kP`bhI)l?xf4Fc>(XTmLG;YbB zUJ>n0b9zuA`YZ*0z|ko$l+nFQ7Zd0B0|lCWB!XE z>_WVZ3y_p_G13t)68QrCvh0kpNOGxyjPgOGy(?9LY9xK}rQmk>RNxVpo(8(ZAY-P@%v-%RPgUYCN5DF{Zw`~HmjCs2_7c^R{l=$s3IWT7!LiIv+oShQ?_W?})c z7ptGu1zQBy=&Ww{QktvH>W-wOdmxQQUxVKWzG=}7m9T*9@lP;{H$J+Deo5yZe8QKt zdZ2w&;x~lyPHj&(=b;?r@asA`n{pO|!4X?>&ZYiwFH+?^l7phTE@x{FD(>ruN0}&a z#AD1h$`RXg(4p-jZd(qFxYMT~Vs{F)*QaixDdCV$q2|LW)Stax3$FHZwsF;qLt5Pp zWPp`E^)>RojXrfInQ?VkId7v1*7_7w*^olDr%=07sJ%Xgmmd!K)EttzF+*$kG@9;H z^U!pkLXd~uK6MUt_OeVZ2O}+Z(X^<2kh09DP;RA9Erv{=Lb=^p)VGgQZ?gN0$}UBL zyxLh__C=eiiOzenC$ZPCS7lG;j&$iMuycV+mmz(6-t0OryBv~-iEmAWbP`I=TzNYE zMj{A6(LIE1jB_(ip)}>eKCDVK`%?4`t1^86r9_n(P%x6W0QK+~Ygg$vVZijx&A#(H z#Nl*WyO_#J`mUQO84*ps@j2q@lbLf{8O=q0b9>8b!WxkU+?cOdqmD7XxJebb~d>+E*)A)QkpNI0fkk3VY9>(Y4d_IHE zXYzRjpU>j+*?beDg_}uP{{+RpOCf%8{>Ot2<8}Rqo z%;?VlqRw%SlJn3Es+}BV(Z?vp{xpb5mxZ&P|ztIyYqo>fDqW zsB=>$*XcxW&fG%^v`a;sGcP4-uTNpF+n++|60kWFd56`&&)-eTvgR{$zL|;X(}`af z)O=k~^L0VZ*9A3S7u0-RQ1f*`&DUox4rsof3+Ym}o=fdf?S49*6k_cb<~*H^IBHJ2 zUD*Mbys%4uDh}WcHNa7u@A<20o}cqb2=blgTiNk^0)t1qa4Y*-E=~1t^S&h7qb0e7N=71+=-fSo zF75$Ql6zgKmUA09_gdug2~DFyaD69cQRwr`_(f*?CK&l7jPO^-xH|MhX57MzyTHgN zVT5}`B1I(kxcr>Wna7YZ)ESXZA*5A~OUBk_?%lp51LGwe;W194p3AQBMY*(ya)gL- zgot{MI|ibB7m3gskIjx#XB9vuR7k_;gK$S^4gM6c zABfOl_)~aQLx1`rJyFOAubL@&=)Ul(D@Z(ilOG#~yujT8UtWLO&z{KgJf3Vwpm!1} zL&XR1>?NH3PiPII_;NMj0pBA|sL<3ni};a2Do~|Z&-0y>A^hVPr$lJYN@8?nhPX0* zog>rKi90o}#7HUOG#KeLnAsm6-wBTdTX@xU(qJ)FB<&az0+T&LYY>&g$sD6v3;E6vQi<+Z-=ym@_+8G_f(>keF4}+)`IRv?)?&@VU8rP2GL(7rpv*b+%ZUK+mT z$#))kc;9!2N6w!S*|KH$lF0qTA9?cKFD4>$7HqjJOkY?GHMiuuZ=_6wSs~d&kh1>N zulNi~Q_H;iW)I=am~x*mfj2QpAKCU^SHg*b06aZRiozn3pw^u|qB`#3BC@(#3_zbh zaptLRYK+A_TmdHY08xP_Qoy+h`fzu3jIaAth{NI@Ml{*3nr%lValx0QV;=VE@`aV! zSso?10nsrJ zdn_WPjWG|q2%?>+n1|_|NLN$L!xT-V2#$HUx+7Y@MuhDik!+0^^*miI(Ld))BsXvj za9{v&N&0lre6Mv@eRWg)?6|k!YNv=-Ta%d65SM!St4Ds@si&J7=g>Ea)JN&FI}2*! z^qr$tFYt*a$M2dM^Q5`#Yvi=C#%t@ns!OU%%EnG9nO0stxx8#5)04}~D?IM_dG+(@ zTkbKM5?bi%MAuZ)#hHG;N`*qexbm{Hu@{z4omMj5w?rJGCYDSaJAVAs(y|HVY_Z_y zmr$@`YWcMCvhvERiV7-CI^p9_LED09>e#Z0C7yivh(5@~I!4PYr&X0rEg3s5%AX{2 z4Jq+4Di|GGHhyx6*VNKHC!bGbD-WGmUzcCoP}A!1m%D=PsGLgDP^GVQvT&kVin0`$ zs*8Abq|SG4g`$-er4=PQTlyo;uOBSs6S$JnvP;HJMrzu)3T`t#y`+h_*HlAu3HdJb zPA#8M$%zZcj_1;)Xd0ER8edUeSyDEhGfT^+O+})zbYdBa7QN!0xJ^p}Q`gbc6;zlu zgKOpyp!~DI3fD|da5|T%Lx|7CxcadZl3htMOUlYGtRl5Z4Vp<>TirLS{NdU>yN-)h zl}#!uzqAYzri`6V-95E@DisQvo3hF$aTOCTEOkCgHC2qGzHOOD1E-<7wWTFau30~? zrnO#%bga{6Yc+IzbVz#S2Z@*QKRV-S2bR9&D?s=4H-B)^un1u4yVl^$0fDhd?^W+KW+N73oB=UbzHQB8sX2$)zvKvn%Spn;ayTwNtrVW z8VQv};jyKaB~vdc9mkGaQdTl;y!88}M02X(n#H2KiG?Bzd1aY(&y^%c||fk$ro?t zNlentB`}|o>Be3%wsf)x@|6onblV{IO$=n2uBi$dA0)o6341q6s5@Y65t-Zq;H!hR zSFv#>jIEl?URW}|q>@)5n2osIu7}0BogvK{^)+#F5Lyys5)egTPV~go5*g;y|Lis8 z6;AZDQW~1&RgNgFgr7-&kS7OcH(iWe?^R={VYc%omR04C%O6oVqHtvX8N-I3G3?CY zXXY17r4=e#6L&dO8Ig4g(of`dxjEc#+<&VZG zl@lvVFQains|2}hU_%C##!ehtTISWYBxcbkD_z5-`?#7ZJjB50{A~h_U$>^0l}{;| zLN8s78+UGg0lCYNkKiqIyIl5|p=+mlp@q4jeqD1SD`}sKSFPoBYxli_vE6fT36JZR z9lne>T;6$7b|ii^zm>DO>=lxKSuj6b<(I!+@~=$EpYG?ck^J$&{2P+;AC~+6xa6iRjV3_wQ z$L1aryPKYwxqG5Eb<$HS0esmpvl>Mp*vocX`72h@VJbkwh7!J!@L0Cui z_npY>?mj9danl-hw*6N_7-ZV+dQoBk(3Nt^Ve4;D#Ekg0r>->dbX6GIh zIh2pH=e_KH{Ik`+Bi+HATi}Z5w>D89T+-H$@zqiNdrx!aKkt70v#sCHFbVKwdVe@# zU?wyC-b>BR=ui{r*O7&R^G)DXAw*>ywHi5=48QfsBA65D4zLeYOA59Et~Bpm2s>Hu zholJa8Kg{xdx1cxxf?_Ws{Y`J!?QBGyGj!YF>s0$_c`61FrAzk57E*C>1kPH!F9&%FEFb}%;3ht_F7MM-&3pf{(4 z7YF7oOtp${2S^8SyoI26 zA89{u%ms=EzdepWFIRk4fIlc-|Aql_uy<4b?+ZVs`=Gb~JRm1nFJ2qNVfELCkHGQ# zP~~Hs;(+|%sPD?C!?8a7DaQdiQos*f^^;|Zy7HkM(rx9W47*rB_@x5~nKyusrlM`OIIoG*)-?zth&tXKhW`Sg^=}t_ezAl8t&!sO z;-BvsIo}ogWJo_Ne;=W94StdM+X)7rBZ{78@Ll33BMq+Kz8P=ulSKci1}_u&GYuXR z`Rc!_|K|kPm|2RC6gz*;$hleUu-f2%6#54S&lG=t%;5B5JRi>)Tw^=^!r=D_|3QOK z6n#E0xc&`Oj^t~*7D&JLG5CC;Pd4}=vGZ_)&k%hsF!d z|34c1dg1@j;Dd!fB>k!K&lLU~gX_J{ZU%RMgpm5pI@o!&*!eiaf0^JX8N5R9Qw^@` z-=_?&^Xzbgzb*D3Y4EPnuJa9!w=HmtGx%eI>$l(3K7SB9mK*-@Qg4;PkCl2aH~3G) z{xt^gi;C!&V{rWjj{fbX>a$Jk7Bl>}ivM3@@VkY+!Qgwv&zBm!Q0%bW;7^GiRvG*O zp}%7A2GQpZgSQI(O@sf@nZdi);ESZ*?-~4uVuv3Z{0GvmEe3y4^m)wSIu3Uj{3~LI zXAFL=$oYxECky}24377vaOgMxv>&f?u(!|fUoG+v8eI3&e=xXyTl0N`e_!PM#o$F^ zAC2Lt`e>}sPU63cpD2FY!{9TeU-}q)r?j`9!F3%SVDLer&tQY!E&V&x;CD#9I&Z0- zx}QGB@DCCGVuK$RyG%5AmgrM%@CNDM;5YX$@9hyi8w`K7*uUA}_lQ1mgX_1ogWueP z{5M6P#fHC9?0k#Che>}0zqtoF{iNRDH}`Ttxd;4Kv48NJd%&j%|4t+S4xyhlI9}|-@l%5j zm44iBaE%eG*T?E_rwiY^hW|>D|0jcgM(nH?`6}l+;m?-(6(1$->T2+}#m>D9{uhzo z*WfR@=6WX@{I^1%YVa4N--j7|m&h4yaQ&9<1cNUZeJTxpK>B^A!A}u?ZZjze*6S8s!By9O9s+f`_AZP#dnYrCQb*LGDIT<7;%gRc~S*7Z&G ze_YyogW> ztvC3MHQ-wBL?cJ*on~;Yx53~&q+b#SA0u|S)8JX6kbW}_#ih$BMX}6;Uva%Z{)myI zl=g0@9Jr{F!iqdQ9WLTL(|v)79w1kYXsFFF{Z zjQx_a+l!yhPtc<7K2LOcV*m0fKc_f9yGz?B{LiZt*JmSmxxm4bQ+cQCUtUF3r7|%m z!X~vX`t$OVKQCzyFFAaDk6Z5}M{8@3F3)@d;*RWPsRzDB=texsJb?b*h=*1OZbj;3 zq!uBSk5mk)fk-tXg|U2~8Y#>U2da?5_&YEOsZ)@`pD}L4!^s09k;1BVU?@@;ZwC;0 zZX>3t1IHoN8!4;|8}T^zKo(NNk@}EM{MDKRe?aOOV81~M+k^wZKnnBlfuA6CCQ?r# zg*oHEqex-(IPgQHFendv2dREY-Gx+tq`rdGIY_NQ>LjF=AXP-CgV%4wNIjU~)*o!% zI1JRBjRp9bxp4%3X7Kk{4^G{97N|)Z&&JRAjic~${>J0+bG8GEHl7EnVB`7t8L)8- zevaRG0e17z+hA*4WNWb zPA7w}G;cZ6rUS?GeU=fQ8^peKKBt#psrX)L5a{;`Nk8NrB3yr0ZmaUoUWlD8qr zah9-_@L!UfVaLM~-bxtfIY_946e4FX+q zb`q74OK8`P#L7*TkW1MO(5!=yOF3QEQ-*7FPPeBh&FbfLM^e%~kVd2NP(KoRkCcyF#5Fnnz7J zEYz@21yPGbPM6`Kp+wyz)ES|LBy)*SXNT}n*JVOo5W0>yR|*vk!68=*Rm#*_p)O+T z9-$^NwLz%Kq4iX5qflk6XS+}pq1&jw?IEw*XyRc9?KJ*Y>Yhks1)Xz4-=uR-KH-5);d@ZOwsaxbE!yC=;#+J4;L~ z$EGo{l!A)VX`Q!mDd{w!q??H9OO29_Aqq-MR|xfIFOOnkNipdcqQ=r9Db^-xIC-{M zji@JSpoDd3s2&Be2?l>iUPfBXL+42x}JL6 z4ew5qcv$nW?=+b^(xn42u{yb!SiR}5-Z}+iVs)Ab>CVk6-=btB@-CfoLkQLC+>BG= zX0Q*d676&;`i51R{%a~Bs?30bk=}@j)hQ(=R;QaVqxH$`eB0}^MLUKH{9l|a@82uV zRp(WcsY|JgHhhMr3GO0y{+GtN>ip2}$w5eqO`AWa7S63Zwu!}KHcV_1=c@BFH))-VJ8#Uy1n7!v$_&)GDKk*#rp!Q{ zn=%7+ZpsYQDRHh;8rSKF&6&-lbh}ivIrDd<&R(Cw{3YvcXBXK@r}fl0SDl|fkCbI= z&FuWmOiYPR{JNm#>w=oE3u?YDsQJ2}<`U;hr3Ex!pLt9`^YvUvm#5S?SDk#pp8U3X;%>?(1tR9Zm0XRd6<0PRma`)AEYeXHNW#C>?@9KD{nER8CydbJmQ60+1C)~3T}QZ3G+H%6MBWj zP{=Ae=Z4V5J)x@PUKjd+bB}OtE~(a&PjFKz1lMJYv$5Q$vOj0kkolTX43_lQKE!1%}~x4Mt=U8`I=g^*Uc92r~5I9C`i66cCUJ(vBy zFUqAwlp{oxBScg(&Xw;X5!!8F1LIWMmIL*m?}>y(B3SXV-~l6utcrgB3-CO zk+&twJ`_qJ_;V>??_#R^qeZ$(333$( zdqsb*Uo@w-wrJs~v#ZY@F|@V5uAwGAl>Qhuv9O5$a9+b*ee@Vt6eH{72gY)@NNcGB zlaa8(^p`CZlpsa{ugGu|Agiu^whMw~!e>z~{h_`eGK-v^n%USwyd)wSJ&W+fd;)1F zfoNNjPrF9qa>r4DwAN7|t)+>zOB3PK`-D&Kb44O@XW;loAnlR~KIYGNzc^pcF}Ab< z&#P*_s+ppENXRW3Z=`Bse*SEVj?(17!u(TX^w;U9)(xRV=MEYC%%t4^OZ}e({?7vc z`z=6!I2Wh52eBrKLs%_gyeO^=?v=Y~?6UNlh#0Wur6~)e;d5fi^4LlH z!O(DXiXs!uo=wr|uG2J!@>@?7;+|0k?o%cMTcw8Qc_k%JqWZm&0%{~IT!`DKe%QYR z$|xZ6N2lb9#i@(308a05Yzn1@>dApAfnxMSc09_|?sr6GH8sYRq8;RKs% zqJzP5ustCNVU{?)8}^7qb6lXfhx=I~Ansvz8z}8zn@Y5XT*79QNT*rc!JRB?e6zKC`9gptt7~~HLX`s zz$@%2L2}#{a*VVw|MV|*z!N-zfoGtD-}+=IC~;Iog^`F*5}FK%iwh&Mi%5WPO=P;@ zM@jD%4~D|An)wJN<)Yj8VP_;_oCM&L&}U#@(Ar3&c2-S{|674PXRNpiDBYxZh<8<=9LUWQqKOVeR9%f-%pA1raDY5apA2v z;9cwto<~`4o)f^OvB@;7Vs!$JTz3Y?%93D&$$*ViA`l}{qti)%)9Mxq`zLK7Mn4c5 zB3_~@jwqQ7^NDD5fc?mB60!?eFit8*uSEB{2~s9h7hCb@xUK#u_G62|84xef#;k-$ zx|Vk{u7pF?ApzY|VwT!{2PrABMExa>x=7NlT@*NtqanKJe}1esnzL)_hGQ7lkd^u8 zO!qUw{hZ}h$8e86b>OagIld+nq{a1BNm`IN+8ysAJR@t7Kq^% zTwYNa3c3KJNBj9l4eFN+LC4Wtsj)J{$I0ey_j+`6M~)*$tWF^gwdj)4zsV4|E+nLg zbOc6yGU_LVxW z)vqy7`~b()X$ZLI`c7lTstpj_F(p!EY6MTZA40AWh)M}5e%xNPi|5VcMS+H_rH5&* zLO+sY^?ZsHNAW{tmY}k_rDmC_Aq*ioHBc{%D&Z;vp_fsVBeYV293~l{P<%_GX8OTv z!5<82tkK|$*x?Inle465-e?d}{85xE>_XQ z@wyw1PdfHuUy^wROZL3a<5y!dUcMwFpU8#4=y;MYP5iu!?I9N!k+6S$Y(zv@{2v=2 zF`rBX)6rFR%26zoy^`Zcp8-zXL$?^R_u$P%Iu5xXj^~4V=%SVn^ec`*^ba^)g{B;* zTR?JcU8fTcnU?*dmd7iZsNWu1{tqV8kZEHhoZtyTsm#vxB8B=M_N z-F;l*QX@Q98RWNyehmxfG)VpYE-WFapKfFvRey{y+a`j%!FWfNj$%G1PnNftvO20i zANSViP(Q^l-8ea_{$+$&nFM)rr2a1$!&u%W#M@E*qdKS`u4L_h2VqtwLEd|K515W& z?#Dk{-qn=TQT-KCzm`Y)(Ra4~`v`+f<)b7YgT!yw(~Ya(q4n$ULzLN3`KJq9sls4k z;RU4S+XHFfdVC<|mDXP^r!?N>1ZKL)^M*JM*e7^s`xVZf~!9oAnV^Y>E94<5GuU|ui{ zzW)ia7192VVk_d^rH*1NqKzHJP;~29XRlbCf!|pGGaVW3HC;yp&Kd3{i~!=2868Fm zgdBc9vjcwJeWhk)u*aohpgM}hh;<0#+a4DY5R9$JdoaRg(7%rOXQsg$(%_hXA>Tc& zmwg;z2;<(;N>>2b^!oQ6K?Fai(!pK1!m~#XJBv#tV;%J zBSD8O|2{rJCOLksh4N9oOif_-2JktF>%LQ_L6##`GUqVi*LrUfVIvJb5d)l#68Gcl zvrpPT+2F^Do|Oj2QxqJRxgTH7Y1ov}QSE+wTw{8u|EQk7l=lo6@}K2MPh&eNeyZ4KwBgSXd*UP2IFx^lBfZNFt}&Hn8~jm` zbCbcxi$8q9;M=9Ww;Ozg46?5oe2(znZSczlf56~3%06qW!50XwF;2C;w@H5;F#Iox z{x%lkKC!39gi|?qB#OhvLhK^#vat}q>DWCR3$dH%X=5R77daZEOY7BGSQkq>6#u>S zOSQq@mwM+KTw^#~XYjc2w;6nb`14l`UMO~4Z}1kekByO-A?>m;5*q}!F%mVVrHzre zT;?~OFVzlri5+Z=#HXcQIntlXzgF61V zEHU_p;%}=A{#ofq8&gro&;5o!NBFlGd<_gm$CCyhDf~7@qF$8kGyHFf9o{i`p3os_ zxAx0GX>SjMe<1y$_j#264(XRq8U8bb{~UwwmUc}v_}k()HU^-^zN|I;pBMhC4Su!M zdyB#OZ=1=UHin-1m5r6Ber03gJuLd$*mv{9ZZ>9}#zK7E=%f3~p3|2F@v8e!I@BB6b*H z_|Fu77;Nw{B41Uu^L8 zV*g7GuGbY;8oWgGuQfR0Mc`;O_;02ES`7ZYWA_pU*BGPM8T>eD*Np~0U+jOY!S_nL zRv3Jx&^9*RL!#$b4Zp@jyVKy?ME~^$|CZS2I|hG7{P6n*|DE*XLk7QD+WUyXua|Z` zZt$~(|4D=EeDR#YKP~?JqQUX%B931eoc>Ijk9`K$adp_>4@kfK)!=c_GgIaX_1o`@ z-8vgwuS0STt}!i-G5A@cXMcmMT#fmy^-dCf3Jm{C(qA@4-$3CXVfcHA{^uIJo9I() z@M+?26AZpu_%+7A>bXejooe_q#UC_wk@7Eh-Q|7S@LwT%)*1XBY424A*KaF)*5EPe z*P9K_QDLa=&l$W<{9&cRe=O~~-Qc3Wr!fV!U5GM+;~Rz_-#Eu{kHM!&d%tV&V$t8m zB-GewTMYkT87~@xU-i-0ozENo2ZjE*!5?sHdK!aM| zG57>0#yi>I?+O1I2G^K_=Nr7MjQ5KSuJ*jt;A+o0gR4ESHn`gJvj$gtE;qQ^bG5vhX3hF`CL_8VO7^GAcLeZn$NsC>0g4}+_H z`WsyBGsNI(pR*0F_8DjJD@DJH4c<@aYJ;nP&NcWeVz=uI{(G5MKWA|LHpZ6?zD4}) z8wOXqeb3-(pN9=TNcwlT!G9}y+E|WLWV{?J7tY!*gJr!aHn_&(UTE+egny~Q5%B zeuwnqc?QoBe~23V6xruYGx+xfpK0*!V&^*z{*bKucMA?us${*tYjAze^oWt8^A(xGLC+c z2LH79h3d&hr;|RXRXi^BP8SBnUl)9)!N-f-27^x*e4fGQ3%=0c`n+VZ!L{CH1}_si zD-Hgl=(*b9DrapP{2qhTnNV{ol^ufa7| z`F?}XmU<5vT%SK3Hn@HRj31;^9@Kz{F(OC5Wv6&l@LbVXalIej*WjvuzQGY*0Y`zs zm4BGQcS^mZ46fs)*x+9m{;0w45n7+yf&{BRZ&UwOT%VK8G;+Q!bc4ZF|9J-2=Wq)R zuKbHFF7z^sOS@JYe3sCw4X)2e)*Ad6k)!rNHXzk!gW*?vV;a0Y4ZbrCzB>)RCk?(g z4Zc4OekcuoI1SE?r}iT|XorZ{$>RE)+TwlF@aLz&3)0|vooeOlH#aO^oJNk0SIb|K zhF{> z_aUMNSN@7L`1CaR%rtm|!S#98JcH|dDhmxhLi%H|!F8TmW^f8G!^cX4Yr9q(T)%<1 z*5D6|J?}BN%Gr-!j5ufF#qmxX-Yq-i*Wrg5#H>A!{NB9ji4?2T-a!-kC9jbMCc=Nn2UPY8#gu{%QE7}j5D{atviraZ5hlmG6q@hLQZZnSODVG4wQc==-N z-P?BX&OW;O$;T0}KDuQ4Vq#e4Lg6oM@3C|q*@4)Xz1<^saXzKrj`ldcor37^7H}DZ zJ#zWJ$=f|`WP5 zQMG#$++ZtCV%Rnc|G((ZUZOL72Ozroz_X+?8+^I9_m;rm%&>%!?Mv8B`de$@Ay(a%s|%PfShRC zi-fa{)%H1T`-4@!;k(7pUUIm1eE5>X;l#NtoyWpf%-O+@JuEqVB+=C`)hXVM(>wT& z0I8Q)tQ$A@=tN%{IB*C0w>XzNGP<<=n$sP=}Q^yfT=9` zLvb{^;>vdRa@QC9Gim|FA1a65%~O@>NwJ)#Q zAFcgy^s!%ML_;*4&{sOz^Hkkv1`YHj?I8^KB_;bqWRKA$Z(a{y*yHoG(dRtyWsk(M z(lNNHx})UHBXk`2B9z`yvKz{4wV(OB)k>8e@~xPjM>uI(wKuw=YuKqmlM{XX<2hD< zkxf{M_egMs3M+<;uP<@@y&*O zsQbw3*Nz;CE????7V|jbHGq-ji}Cj;^hFopkTs3m&M(2EsjXzgjuL!+1s=im9C#C6 z>H3Bo>iOu9$FTljUAuA7Zjb7o56f_B$)fwb_&{pp22yo*bj2NONhdVD%^!qqCG7{P zUC3SG=jzBNsqJLR_TXfa8NU}04HtaZ#pRZAMV}&Kqn9{EJY~t@tax$`Iw8@O8ba;x z4t&a$+vxRJdM1+8F!aoU!H(F;Ob|k?+)1jD%lNI_Mvd7SU9l9ZMngN7PkA%i_9Jy- z8C9v;ZYHhv9*K7&VSA&YlAQ-`BgwvsUE;?D(%pPrzD7*smu)3$XYVLkm+8^@Zc=DP z$=c1(m0$k%-D5S`iN|wl&Ck1pFM_w{vt!dymg| zCfP)_lcLmR{EM}0V{~-Mo*p-4|CRhVb0wBpvhp_p%Pu1@~lIZQqX}x=* z=WJUvocasHJSorbI{3Qe`MT~uSmB%hn0U~0`uh0vfEV>jxbE6P-6Q@%V{{4qt<}LC z8Q?ULjOt(_vAaN?0st0}*Xh>qFlkO&7Smcmb3}4I)=egVp^0pX7Sca|u^i@TUG*qS z7t1|%u_Ra7fAAc~zf5|J_ya|C!Sss;#wsaC3NG1RkZj>FU!S4FFn};W(uBCYIG;8N zJ-*!DUnr#q^{~)W+1>inO*4G|p2I%hm4>X%`zQ_=6ud3JJeVHF!b6CGFFrZ8V!X zqaAJL?NJ?70inuFEH#XQD;T`F#~f@8=n26 zSW&!|2FQ;6pL5qo;Mk7qJ~%|%{#~i~;IWGQPLV8UFWPS$NgU%(TA7K?yr*1>xyhlqDB4z0;p*a@ z!zh|aX`3WL(FZ>?r2%I)NQc**Y3E_%$&&3>(p&j-z52 z|F-Qo^5f*Cz$jRUzNoi1+E%rvZORLi`Lb-vUSi$98TWx?`xp8>xfX2^b`QKE7iy+k|Iu=@WmbNFb zQQyCnRgjh*oVUE{1+cWap}S;;>`?6Cb#S zI>f)y`rcmzUS3RI=`W$WdkC6vJnc0nx6w9i`O#+F{5#)_eWmf#i%GNmH=1z~>_Db$ zTPe#G5xd*mD)upLdNn3I-^#vCFQ>83@X;-8$qK``c~b+y$)o*a^qLboA_JbHpl%lY@;(* zz)h$rWS`(bqEW>=vyVBD3b4mG+EBf8&icm&(y0f03*n8;e}VUW+<}z;Zija0tnv53#rz!3hNZ zkZ#}8=?&i&cv0>Xw?)UZ2W^OG%5_&zA9Kq1^W8{82Y;Kqp-9=(C58u6NQ+ozL#|UA~uVJ8jjq?{GQzzvYtgi?aJRQ^xf= zlN>!|j0#Q}bk+U0E*Wpdt$dpDXb8~s2LJxIF=O(Q5x2@PC6jWW%w_l(*|i&+7U)#- zH*6}GjBrc3CTQ0-==sp{E6E%_irs)^1zpdIp#jSvkj8QwXXTOA7>2<$%ft- z@1R^T%b3>30RKN@`cFUi4cGghVK_3#KYSYqy~y`3_`dDO+%|2MJ+Lw1Jv!8n_P>JQ zm`=A1*!+rbKLo-1#2xRya~rT+w#vq22_4DKWWl=|(T}dbMpzx&I6@@`(byH=}S z@(qWV?mltD1y(4!Q6*2hQg30=f<)7aKE~S{T&|WZ`dI5zjoa1BU3Y)aIY}pwe{gcW z@6#E3PvuMp(UiGkyl_iTde4LA}nQl*SXWNV1jPei9wpaYb9{{=kj7j6a za{vsLExQ>2$Ldsa^Z@W@TiloV`!}*q`mt|3yaWG<&$xOcYftK}gS~R=facfat%KAj zoCj_cePl-dC*1XVPWJW2x|`$@{%>6|e1yxb?Yn)`^1F(k^u(O|-+Q_BMcLFF<6SQo z?#6h*SM}W-rSAsN6Z_=NDoO`$R^bVMG4(&axw&n6^qk%CTyjtc>Rl?(aue*y$GuR` z(5c*N-1?bjk~5bnnsy1;E$2n_qeqJ$meNY$%!6HJL|$uRn+cdS3TF zp}}2Ikm6W^&Sh~~BrXeRPbrdBng?;ch>Rf5k$FOrBFOEX8K|sJ0V&d-&|`cBS>mzM zJQ6`4(a3WpIOjMi&cyM)9^9;ch15#4ad1~yuedXm>!0PfHB3_kMcicNNE?tRN|CH! zk&~nd)efHgq}bBDq~HM~QUnhq60H`&6p6;^(v$B0oI(WWfjBi;Wl-E8QA{cwEaHSL zkjjJ{A_B7@@HFmq+HiiV3;9nkLQV&FY2JvgP=9D)=z^}S3pFxWV_`7EwTq^#zYIi( ze;jyM(*3CremgwEA?(?_aG3wbBqK8m-`nHAZORxj1sM^}2#4@!j@URHLpYOv9NVZk zvn7$tTYzw8=B=~*im&ET)CjSe`NMtCPN7~QaSr@J%+$ASI;3qG>#ZS)oiJxr7gJtH;{s}a}V=6B< z=Nbg^ramJTu7#G8zK&}YrpV-WWr|EmGDXThApVFjbsDoznL1s7q?6RC80iRU4;fs4 zr?E(K{RN%MFAXavzojIlE@s=ZUY(}Gf)SUV2E40FPY3Seadx^4>D~^%{2+<%>vbvU zH04GTj+cPEPW1>7?vk^U=o~cD%YtE75i57mV9~MxnuR0Ift**d`klM{kTRV4I(K`S z(p+ul?np|y2hwQtx0Q8em!iAL$(gmwutOphNpQo?`T9 zf0rJMKF@dQacDISbvn9~KxTnUU$m3b!(6&7n;JLDr7JLa+oj^m5h`P+5LbZMBgB;; z_6zYDsC}4>1XDdoX*N=r+V(IJ-C#O4OV{zch>k=Mh`M_Sf2-AlPY8(KV-}UAytfF& zj?>!{?)Fd)a&Wcpb=#DaNn(W9l5-y!H{x<0$wARvM{Lc3Ir}=|Q6>r;@ffp>a>TYA z_;Vt0dZJe-j4x^zkV3VmP`gv8y*`Cl!H0aR6Up3|p*1w3=|1%;n(k94P`TYc z^&Qf4S*DhQkrrnu1u4sX3guS%6uN4sPodoIEb7~*s5f~~jOtp70(rHwysj5LMm_Ev zsp}*(*ExFE$=s3blwGI5&dzbWmLYw59)10>YdItj6W^K$>CVk6&m`fI$T@WG9xA7^ zb2Cn%H08lQtV*=&rMFO;RhiBanO&7LpkO3#0qWtIqg@IVbiHyLWjU@-zd%VzS0j$D zC_fW^otsCV(6xr!L5e&}**$Qg>QQAR0y*77D8_gXG>71q32+U$7Klq;zn4tok~d)< za>=ib@WncZ${r)7;lRdNHLT{^_+FrPE{oXO`bK4tD<#S&?AIIn8`P`4s{rP+XpHJd5Kd1Eu zaC#u0Pv-L}d_I-WgZMm{&joxQ!spZYd^(?p^0|=DMSLE{=iz)lgU@I3c?6%&;`7;j z9?9oXd_ITI=kj?ppU>m-`FtM3=L`7U?u`DJ``ISF)ooP)%>vX#8zzwJF{3;Gi#o^o zOt*)gCI=xcHr@U)wGesjh#$`G*ljyzZZsPc62>vO=`jB&Q zSL8>()gr~+_Jt~Ggt;PbgpSY*=@Xb-Wa@t-^e|n4$khKv2xgV3|BVoaUA_w7i9!j? zx1&VOXFg5Uu$qgzZOp{H?6@{%2I}0D8K`qpW}wbZnSnYtWd`cplo_aVQzqBxL~qXA zMoPC!MVm8EAZo8qHBw9Wr%<}uY|ca;Ewj#A&-W!|S@W6QzL|-c+KFEm)O=k~^L0VZ z*9A3S7u0-RQ1f*`&DUp62xz{Z3+bx4o=fdf?SA^8YPYc4)7ka3t8&`y$`06dS9ZXz zyRrjz-IX1%>#pp8U3X;%?7AyEVAp4|zZB5!S>{vip38oM-bd6m{kiN}WJ$HFquy1` z_sk<@*{=EB9to}YHQyS7veJyLAq*bz!maFUxzaDMZlEH(gP9)c){7N%P0!=jih#WA zfPg%1pty1G><38Id{?Fq8>OHZEtK7k$!?+c4RaaCX3r#TM)ksHcDwau$?YQgxNK~} zwB^TVW4vk0`(^)`7MDH3*`GQ0%SNPsHUhpM@+sK)U7y0oS`LSL;WN_R`g47Y!@Zj7 zn?YSgdCS7R=(Ee9s)$+{?v-e)19bvTd8@;{<~XVsQEOyd(m#7EHB`4cj=IOs!wN}( zZz2&)9eBX$b-O0ig$xjh^rUn55Qa?;bid?Y7aGF3MVwoVTt1;0R0z|F6SF8Zl^Lfq zVq405>=9aXD!mBCb%yIOC`kh;(2}OW_x%DbD3G!0 z@Mi}=Y&Z@hbizdl9|PktFPs2(cvbPh_J+ z>131*FJ}ojW#Rf5<>Z!57Ve>-pwhS~{-x5#d-*67elU&hz37&qYwUxrvD2l%R^C9N zZ14!J8Ham}fWljmgmoej+_vn7L6Ofn+tXC`d%v>n&QSMA!=FG-#;OfM{s>LaSoQD? z12OT3cVHEO$*?GdcRDIM5DP~5N&LZicvZ!~Mlbx7v)J^3#PzgGUvWxHBJPFXgj#$= zB7dZ+B9WxBAEZ$>+FLF2fmp`X|0j42IijooLsx%;cPhk(`-jprE8Hx#gp6WQ_^tJVm8QV8oFyu{__a}^n@?h$%`&>MsvDD+05 zPY#Lw2DAN65i&ZM%ycUAlKq_ML0ols)pSP=7V?V0Z0mv$T9LVG<)b$YVYA*sddb0e zv8Ge@X>mf1oFw+REuB5~`1ZJs?UAuc)%}80Dk`lMa@wb~D*YYI&hZttPIy&xFpZhj z(wymZ+Zk-(m($gMJnh3=f4t1~Q=45QUkPE(rT!HOze*?JGGD^4L;|buYhMMPl)@i& zG$}oRvI{)Q#8o>f@9h0&-`?yge-XJe(X_vc+y*zy#utl(*7T&U1LTejJGs+& z<|ERLhG~OY?x?VH=!Vl#Z~&DFB_}Dj3<2c%q>I-LLNTY1qEo`GA=1GkwB~l=adk}z zyIFR+vu>HxRpD~W!`MMmgB@8Rij5yc+tBdEVQfR;30mKbboKS=tM$!Dt?#nb`YzY{ z24T|}z9NiGV|dm0LD)5huMA_?NHYsp|LLQupOdcogkSxf)avJ?RzD|WUgQi zS3uQi^P1Dif8CegoGQO1RsKAc@636%m@~@Nwc6^gO;=ql{mq$^aBXUJ*QHi>y;kR} zxk#)Tb=Lf>Skrap4M$mXS-R>U_p4u)TK%%r>X-S|!&{cw=6xZZ{F7;q=9>3~RQX>> zmH&kl`CqW|Z%-$Gi7)^5RQb23%D+8D{_R%&9qHu1fLu8)gSk!t1s41?R9Tzecw*4?>kzbGwyw1Ty;@>j=Y~qjAr)6?@Ij}{K5TDy83_O z*Z)vz{ST$q|Byep;SUd4du~l9KSBE!r{h+UA9a(}qat5g(9ZJF0>}NB&>LKfwn>Zb zx#6g#$xY|m!*1b~l}t%moMbwEGM$F|d<~yWwZK!U7I<1M;1t}IGMzqiRFD5OU43;Y zs6~F7THlMQ^}Uo@-yW^cRsS;~-E{i$QPuxCUG?wy)&DxR`d_D3|GGNdAl{Gc3*){C z9Go{cZ?L)9;n@Fw!~Tz5B|G4L@ekknZ>LkImR4@pqPJ7kc_&q!cT=tLN3{l5_uf&> z|7*JX9{20}YifN*QtR_FWbxz*LK#>s1FK0SBhBJmPmOWyiDbCNS^T|IhT8~;zjtQ& zNq_Gmv>31}SBQOQ8h`Jek>c-4CjC7xorX{N8s>?HvVF)C4Q2a~mtuiDYk}j_$*;^; z3ml&+zhA2S{u#1fJ9C{NWONWa)QK57p|Zc7#Le|5xO~yZ_pj5^Y4ZbLo6}OYIW1M2 z(^6V{nr-dybn@#5XlsY3_V*d7{e7nC?-71~yXK#jfo)^Ps{7mkI$QdGZMyy+mD>MG zCi{O(I*p(3H6D{{kuj+j8Ixj>G1ej_>ExFTREw0P%Ab%bf1=8F28d>)tZ1c7`W=3e z*dw{3Ri>-|1;75v)cU8T)?cOm=O(yIGEyeEOOp=A{y3fe(VyUEh&ep3(CyZ1Gx(SK z&_6QCFWr z6wPX+n;OCFqS!S8G&RmDnp0a_v~bkf)n|_w+FD=NP!k{8)YzO@STv$=MB&J!#JSD! zqJ}xMV?`4i;|+;fMa?aB^+THyHAQvx^I}Db`N~Pjq4QcB=hwtZjgMN0K1bOcuWxOx zX)0{+s96-8w-&##cpYUB7WTaOHS_9Yl%$IjO_EuNqpp57!Swt$-Z-~jcwLHE=fxXZ z>uc(?1R>3H77o2SQJ(-S?fhf$8dN|Tq&O_;;KY3Tr7MrR#@2e)fEa39nrAoHa2;Sz zRyVJu35xThnNFmtJ2Ku6h4$SU9-nvSmhh0g%y7o9K3n*3WW?}{E}MTAnH0Vz52xPY zfq8S*Zdserx;dj)J|V4uTl2!F_KwV$Ge2@!`1HPyXLQQX$elj?$#=r1_YR+xw_rpVE8noV7Qv3ZLHdk#`gKCoZRCL0z}mp>IgGcPhMvE=dy{hKqV5xJ3~`bl6CNI905IGM_jWKE{7W64kMgIwxKl-dVkL1YP~sYVvO1?fjZj!3JDQ;f<(fDYHX4&8{mtwazQ_3JcZU{}=u0q*}!D5WRd-FsOiT%M2aU)Y39<$j~u0 zweiOJ_0S&Eert~By-B`tKkHPKv)c^+54g7K{A;quf0O)LbL zi$XUxU*+NI&XIGkq6yZ+wUnb<=F$CQTEuWEskE$+DL}L zCc@Fw)z!64^)=0jdEA>}Uc!+?S6)cJw6L8$qB`z1QaYi;bwpHG*VWIbj9WNOH^nHu ziqmvQjM8g3-PqhhX*|ZNuBJ4LdVneNje5#@gbCK0sGUsFo`ljr(KHu&izzgRvOZuU zmWb8UVpkU<1aAjcSI=s?D%N-{IPiub)3wcUBJt8_b#+WK@j{YQ5>Jdp5xkn@T7jG7 zP6gbc*Fv}=k@9$M0!?D`>T5kbGyyTcrparkbak~X=G0!dS*UJmjKwJ&dN2GfU; zI5!cmUsxUEcQ{pu!{Qzu7Sf)en)d`$5-)Ei>6o{dXm(<}sz#k#-PlrHJIlj^Mxo*! z-aZo|=HWdu5Imm1ir3A2z{9g`PzzdGukvs$Lj=1c9?nx5bIpQMEh35rL!wbnRvN_2&shtykJBCnjG`+(gqQzGv?tvA|j;mF%NIb z5bfl~JUmJ#(p4Mt@IakNXb3am^$kbHJUnrxwA2~%@E#@6u4v4|+fGEX1!MfU+3giQ zJe6eTztsHxy)0`@vP&uP)9L;$x@y6NLP*2s=RWGQC*EZC*vQ24B#YA~Gle!wlMW>XH z_u|wEG#?ODGPQg{r8m2&W=_ntzPzk#YRQDE%98O+UszQ+gA)}~%cqr>l~-0(RFqGh z#tKa>8CN}}w5)pigp#S%m8F-JaK+T|P=;rBR6u1a#)&4g{Y5d+3@@m!%O_J(GZ)4^ zj9xe#YNO^=mXwX>ej+QWFDD z2jSKJKla`PzN+flA3ygdBv%N7;DDlXaX@egpa?iYLb#9=NYV@nID`-aiH0QRCJK&G ztP;@*9V`xQX~n5(wc09!1LA;ItXQkXp%txC9BQ$)O0C0xeb-*=+VZ~+#~t>IZ+ z=L|5NJh5a-&^&LhbA|Gf@`T!v>c!ra8cc{DPUt+gu^H9@i^7u1M8!!ZMbxh_iP9(q zbXr+id62#a1YDY^nuO{*v%+>d!DpJ8oYcyh)7h3R<#(R8*8zut;jPx&|yO=}al7eB3i>fQD%BHh0NGhC2g9!~aFgV6D z48o`zFIT9ZZfeGi;8qNCYU|FV#in>0ja9_gk>K$XSS&U>LdhQgB4q6%*; zboHG+6_W!gM+&3{O={)TpsD2Eb37Tr@G%3!;;YAW%6VPp-`2ZZBc3LmaZ|+zCP2IwrryV-4LkCv;j%!h| z4q0V9U?oaQt18$^H1pBK30Vm$M zC}L}&!BX=qH3kjC0XYT4(X}7jj8++w%Brh4LpFzt8qTCXUkap#FHF=_xRU&{a2isD zyZ`~e(lTBhl$8s|8Ptp2I=XF6Lrq&tOM5V-v^riC=R2VBqehN8YUI(Qj*btjpanp2 zZM(yd95rTm&?=)7se^ii!yip7lMAP()*tS?y9y^2s*1{`G83z5RB&hc8bj8KP_v|x z2RBM$=5lUaQ*&lxv+J3K)25ZtC`3a(RyE)ej(XHqwR1;uH>BCYF>u2U_>u)H%ZjG5 zb*jjvrU&A&uD^oB%~$ZO^1`ZO?$dmSLaNF42|!m_K_fB9FcFlLmP;EIPJ^e;q;*ey z-I<<;>6MpUq7jGU!ctn))>O?br&`d+5kkzBn@ktFg+)aPHkI@Iq`CmygnBzJq3EKJ zYo$XS3_{~ZsDZ4{NeEfAtUOUF*Q%~Z@T5x|xZ1RssG+tI3MXciR8|FZF`^+` z%1b`EV58f^G^9D^ldCGKON$C=pr=m5^A`aiwK7T!8E3E-#sV zS>;TgGi2c<=3>#45~LK(m=%ey2kiCWh0fblKd(KYSHHqZr>1CH8BMBAF>eWn#k&lI ziEvugdk=J#o~$S3YIM|qf3pujvGPR4^l&X7PO;%l3@1uQD$GGN`mh!J>*`b*t2;a` zA@|a2UH^`QV+WT~>rN`Ha@{#~=YiG2q94BGj7pOUI~C2VeBVU)OqVIH7Nb5{jcttx0zp|Pxu*6X!r z*Uxn;_5jlj-JNqo2KV}17hGX=)FpWFMs48kr{OgEadkO8ph(i>M_p}hcyU0id1>F+ z+{k`P-kvxKvyhnIu;ctXl$V2lvaDltLwqfFhTMtgUPrVi&pPQP<1>4)|>ubmj+ZKTn*6-9VxTHF_o*WSK4sj^s zff2PO8nQQ!Gjwzvo~{?DvDw9lmZ(xg7m>?AK(xe`G$sAq-7a_u58za!vZ|t_2#ZLf zq1(s{R2O$i$qO5rX4pcquycyYJzU3-geNdN5Ib7J5FNV|?#|aIli_#=5I4_~?R1j| z7tN#)`7n(?bR|?;R8>+|T2sRk>CR1SV{1J*G!|0al8v}^6fW4@-5qazOiIB#ygr-T z(lLj6h<8^I6-NJ;{#V;X&LuB&aDU{3;RU|<>khf(TzvCo$X%0reh5#3j6fCELzk%CpwEL+_@8g(>4}6J>SNs zx$LRHX&Zu_ov4{@Y1k=E zbP5y13EE2k*fvm|!t^FU#8D{Ux80Q_#$nCe0|71(RWk&j24=a zKFwJ~^GS+khS1=%bz$8b$c8y78=fyT5BfAsL~~_|W~I=4S$jPuG+)+U_&qna6Mb1| z)7?_C^7!e05PX>|{g(2V)vHSQd|AB~3eA`Cxj|@-^K~ZQ$jVLWy#6cjc~fZcVcM`Q zT8YoKDLyXvMG$Gs+= zL4LBm%^e#w)mGnBn@>-H+Jk&v)8@}fCMj7zr(=Fi?VLHdxXou82Q@a&Ye@rWdZ-tm zt;KQh$Xh$+;8q-QOb2lnARVl2t8JbS%*i43g8aIc1q*OZkx#eB>+@;yIg*wVwEl9; z>Kkh2wc$SBzrDqY1I$kkn$orc$=Syc()1xMJ;ik|xrB&IZ2qP@E|Ce5o-?x?eaL}4 zwxRS7`O=*L@%CPZ#~)Tc9-n|`rt+5F=0{Ok$hVuyUo2ysp0~7<=!C^U+j6ukfk(Uk zW@#tTNvjj+XWZyY6(8%4uov3M+OL{0%M&G9Pr^P3E;Gz6Z8^~x5-zv$RX$KmoYWDr zt^9d}fu}K3uyd9x*J=c6d3QDlYAMm3{M91ARTx7L{1#Emt6oXMj0i%4py5z2?fR931IE;4bo)5N3IzNPi4{@~D45`nUGKgD~(^I!f}^DDuyur=9+$^7VK>o$Rjs z%V=2I^4%faYdJlxr!$%ki6{}n58ArfEbR+K1I+rbmR}}wi?Y)CYko5&y0hOBvEOIQ^^s&<7h%cPD@I z6?{7Q%$&6H9o4RT&}9c7e6i~p$m^ay8H;p60vUZux+=;BP_9?9}rqY{i zAy6Z!0fK9uugM5INbqZfZipOl$a24~_K+YLO*!y~pJU@|GdfPBe+ldcIILkMr9uB^ zvHLgpth;6e-Y%x#>oYpnA@u77=j$@UE*1O|RFJj@+#&c59l>Wjy)1%_ufgbe8~p>{ zEdIjRU4*R>{Amonw0+$jf+y$*`u*sQ2yDyUfnOv7ey8AkT}9{M$H0F|FIQmOUrhck zr6Xjw3dv)P)h){fU(;-O%nC3P?z(012-O|le^-!@tUwkg=4_Vyc;CQ853fkyaIK4R z(QbV+;QM62hi1UXX21(F;8QZ-(=*_(dw2TJ%7E8qz!zk|&&hyam;wJr1{~M&-RZeJ z1Abiw{KgFUZ5i;NX292Ez#qkg07 z1lb+lGXvf?1HNYle7_9%K^gGj8Ss%AaNJ+%PX7rR@I(f@G6Q}_1{~K9{b_`IT7>hx z02(Z=&Om=n2K?3x_-f(bM}|1QXF>cQ6MT*gS$rRd@XdmsAwwVEOCtPtf?t9~3T=G< zh>q_Femnj49h>s`MDTm}PRDa--a>uX$pS;^@$GWpc$XL(-w&eWfr9^@-WSHk_kid) zLhwHOG3@RmQ1W=e3+WADY6HrgpAS`Z&Yx9vmf46a2eF9M1O_DA^$R zuMc#%@;O`ZJr8y`-`AkzHv}&}#Nn#Xw*>ETXgd851Rpod;e0QKl6MN;Hawkvwcs}$ z=5W5}LdhotPacs@|GeNgAL($uw?fI+1kWDfaINpVf)|c-_!;gXzqi3HeLNN6$41Eb zZJ@PB7KZ-L)l7&Dq4aJ1DeXbozcS{rJU^zIIzI(jX)vCW;tGqVM?O~f)- zP`{wAbx|;no>K8s82s9ZnXx%st?+t4pe7*>uHvnHlCtgv1NRn!dp06ZjpWUQd3Zua zbo2NL{ycqGj}U&Wh$G&mckiU(g(E`b9W(bVP0H)*D)MS!?HsBZnWr{M&pPSBb8TZ2 z%-K$Nx{^(JFHzoBq?bz26!c)ZhF%_NDrR)$v94sySNIF(dN=?^GcgunqRz3 zcFb8o&o;FXUOJPs`{jdsw(7XK6Ji0$;Qk%kK=P=UaB#K}TrH&MLPsNA-IG{Hs2)pj z_(C70`JF9Cp&fxxeL9*t;T0Ei%Q=34>C)QjqKc<+*cx1GX%kn-*Ej4JtU~JLMH&N| zWE`MjK8VvleNUUWyF462r{a%$I4(sL|H#8}NpLEyFR*DG6z~T=SMULP-r$!ST=^_B zxbpc?20R9VwBc|d{i~jF4?oDm$9g#GMV|rYZN7*5^-3CC^|>?y{=UJrUYK98;o#e+ z7me50EPjgMxJ(1RZfAM)n7XvSmwGs+F2%3)@Pj=3aStEr;m>-wPyb2={3sZaHt3J3 zQROyzIHpF$y9C#I>FuQD9zCW^rT?*^*DJQ4WT1b;qn9a`xCOx+?eo#}YyLAXG6n$o1>>YY+GN;Fm1eKtGE9mCpdV4*}fQ^L-EZ{UJ|oV1eHEpZz@C zmpdf`UYP-3>)}Uvdj8VGeg5xcz(2}>A0_u!p#RYx|4AP1^RLT*$I&5Z10URDQhRoI zxX#!EwO9-oM-@k217D zF7DB(9lqw_<2-zxhacMwEb{c%AgM-gJ{w0K|o+rw6IrRUUho9!* zQ$0K>xYdWgTF0B>s?Q|`FOYS~9gF!OFev@;LrzU^uFtQ zgX?|Tr#(Jp9-q79zJisz#lwBMePzP6a`!N}${j2?`1^AAmirTy&wd71K8Ff!`MCJ* z?%APl2N&5rg)1Kyuie?q*Jp;@|FHU;W^m=xAh^|Mw%jkVeCiFZd|Cy!d>Ui`w0ssA zT=^^%-12Fa`!SYJhryLkr{I>)Qn`O)`7ATI^0{7c%V!;4D4@;qS#NOV^R(cW&#iLb z2)N&0p7U_uZ{HW(%KgybD))1bkMAe1$$crvJ%avqoWU>Fv01#Y+^+(DB>gM>I1l&r zZ1eDZkA7JO{C2@@z3w)+)@z-|$FJA*gGm@|)}D`fxUc8?f?K&C8eHXm?(y;Ez7c1! zyU6V|B!&BOCkk%mPBFO3t?>BxaxXg2@wa>~HMsJ*T5#CM=hK2ojyB-FAFl9lU;hn) zTe%wzu5y3v@$u!}buf$FMeY_4_vQXga4Yu{gR9&ghot!Xa<_T7@Bg1TR8;%R_cGx32yW|jzrnR$8$3RKy?%&`4ccrwKI!4Uo^J_m<-TKZmHRi3 zk1u!da3|ODIoROJXN2I^5AzOle60S*c(|{Bh2U21$p%-sb38u2{!4Be@<#2hd72@+9%Ku1T@MZqVnYUdYk&DR&6*+TIQ*H~3Jg=*b5ERUZeOZg6~z6I;DI zg#4GFg0!9C4k3Q0@IS}ke-wSrH~3jXf4RXELjNs;eHTXeN zuZIkNu{7FK27g%W{~Lpk5dMEQ_#~nK#NdMk&lUS=JN{klfDc(>Q~b_;F2BFQ<6<9u zzNz%<#fgqF^s~iJ^mfU-ZFy8`zZ3?qYxa4Ta*LOMBtH4WIr- z!514Gv4F5$ZSZ%cU2ZV=c+uxpgDan(8~inC_eTtVi|GH1!LNupeO@y7nPTVn4892! zr|n~de@*-(OX{KaSt$Ju?>Asm{BNSqAcKz(yB%uq_2Lgl8{B#+KNJ7d`+NI6lGsWL7GI*WT_ez7mDsuICklNu- zV$ThReus=#`re|_ZT{zX8hX4JgN?ra#GBGzF75TC z!S%h97Y#mM+C_h}qkQtk4*EPx@lOTUS8El22npKyh&>cPPw43b*1ReHl(gev20vfg zeVoBh6@0S6&yakT!RLzHIR;-Mc&ovmkoLXM;G?Bot~B^OvDQ;RZiJ{Ou%z*9*NqA5{J= z!vAtZ|C!{!ZSX(Ic%sh}mCqGO(003_|Ap}Xi@_I*JynkKxn20XZ!f3j<@cps^f{x_ z-=X%A{-k&x;WNtMOT|yd8oWj5Pc(RmOT8{K_Z}4)--)QhtW&LxT!FNhOy362BY7qRw;CR0h+d6}HNk4kT;B%y28x4NF zwEHs#e?|0p-r$Fb{x2E4kI=tn@b{$M-!k}2$-isxeZ`(17`$BkgX{IuAcG$!Z zllE#cc(c%V82niA!}AQ@Tj(z~_!i-Rxxw26zslhENdDUf-$(3!t-d2e%u1w(wE;IzA_*UDg5u%9or0kl+;)6cPjrKqR)kf{+Gh%QiFdadR}4hpGi9|Gx+tQ|Mv{8F)4m* z@W06Xey717k#<~d@DpX6eB9uAKl#@N-$&-(tp;xp{9S`zDgL1IyxMK7*r$iIv*LPv z>OS_GT2Jb_bg-d+SnPR(!S(v|ScB{J=469^Q}|RF{CsKO8iVUR(PVI~*CK;!y)HAj z*6Z5_*LtlqxYp}VgKNFk8eHqO(csg?uU;_tZ^eK9VDQhyJ|7rd=hrU`{sS4;`bfXQ zX{{;`0TKwTdgKN9z$vmTWI8FTOP=gPb zb~(o2zZCx{GWbn`f8F3ebb4$;WNzOJ;c8G2A?GM9BuF$#s0?`T*uP_gX{B; z$p-H&_MB$$dqn>VgRgMS8)&~*`;^Fa&FO|-pGVF$_*{{DhQS{b{;dY@C-ynp;O)|m zIv%J#(}n&LLw|;hGfNEqN5Q{o@TsEDcMN`?wBvOKe^~6W(%>=itD6n3_ucL=c$T#L zy#~KW+WirO-z@XOvj*3Gq0d9qKH4w*_mi=%(0=ie;iLVcr^r!0w@AJAHh7DyUkeRh zDt=XJ@J5k0%i!C^&hreuS^THX;73S1UTE;1(k?d|e6{3nGx$tt_qz zw$9)e2>l}l*Y(gwgKrc&=sd4>{)5=fzL&g3d8@y8N|Czxr5Ijrf8Ld~b`15WC*Zc2%4ZgSNzo)@(7XE__evtU*fdX%-}WB?%y?h zbbazOgX{X|34V|KmB-~H?5cQi5Xn|d8pv(CuQPq zqcYGRYjAyzd$Qs4sjSE9JbGcx`dx15b^Z2ZgMUv7-RkjyDJP0O-!Swa3jQZUuX_H? z;QD*L0p9NpFg|O%ngaw^dn)}m-@i_BQx9(PzBiYPZ{Dyqam~ z_Yu6_(5oF57+m8iU1|8JKGz#u_4$e6^RdXi$Ka32IQ){~qj5{$GW4p?pA4@3Wsvtf z7xbg8GCv+FxY|eQM;Ki1(Nfk&SpxYyv9OFOR1z~@ne zYn+zX44>uVKc5-AT=b9a?G%6=Ff{1z)P@PJ{`RD_*JzI(Lz~Jy!QdL#Wvbz$^F^b< zb-Z0@aJ_C_VQ~Fj^eVx%9aZif2G{Xxo#CVUykv0IXK(L!N${V2WS%=naFwh44>!2R zt2xf_QMoe=uGjVF7`%tH*WwKPml|B-;aq3ALFIm8 zaE-&WoA>)H*i-d6)ZnU5y}=hk5N&4(u5y+CB7y4CPexlb5e<^Ij!znAq=M1CKq^;Q168C>Hm4fK9z=lj(dgR9(x!Sy~^mBIBs zSck#$WWK&waMe@w=`y&+eOh7osD17;xQ;(B7<`_LKd)!t|F*$3uGCJ$N9FDXW6`GL zyviMF@Si%eAR)Nc_qX!SfnyV~Gd-;D;>aqo`??;-0t{e7j{LFN8K=oQyET|LE4YG>7Fn88(_u?E-sx|0pA zdd@TWC})PCO>nEvxdzv`VO@rg>UoR7wIBV>;6Iagj7a;dT;;!;!S_7aDLPPaYo9R& zSNkLkuJ)-n_%q@^X9=$QsN6*c*LY}43?H?_%?4L}9yj-A2x!MDk}s8(>b zzshYixW>m@X!xi;*BD&w@C$>#A=mGZ2(EIK|5FCn_!&!BuX~kbpO}kNVqQ z2G{<0jNq!zgu`9=6Ak{U;FArX&<_nB`k}$c%laW{_-lR7Gq}bZyu$ENJKSn;wZle( z>w9(2XW;*e!8M-YJBE+SjUAY7XO+9R!FAm-)Zn^qnPTww9owK%@CfCj^soAyV(>7& zqT!=@E-|>y3ojb{yD|>{J_G-42G`#$B91LK)zjrtadZ?vM#i7G5GekdtlNhfT;IzY zY4AN|{u*cSgM@#9!B+@YyxidPM4uT3e^ajaXB%9fD>oQ?chRTS;QIV{p}`}< zzti9yf-f<6FVSfpZuo5^?q^;iqoe0=zZW}2G{$s(+sZn6)T8<@EQJDp&8z>F>!D*ZXXLwfx2K13^fe((C=A6AZ5Rb7mV{@8|e&5kaE&JrM60 z8xHu_`x2WBuJ>(EsO*XyY#4PF?h zO3?P6!M{7i;r(R&rE+zhKic5B-kxD_U2mUna9ua9G`OxC^}Q06tLrQMeTm|_{>hX3 zzKZL5V5GryJ)pnaQhJ>q7aDqtW8?9ojv96J7{+J!yeKhkax@|iOJ=379Ps$yES%aGAC^iNaI%2n0PGc1 z7k9l?+;zdu;;xPzUDfXuFHP)NTK!&Ed5ls!iR#euO!i zt3sNAOmh{}62tOgPd&=)7rz&Wi0u$t+?Ci~y!MsR_x<*g-w!IH0^5r}exvx2cluM3 z$}C$?RdK~CixKa7qrg?gt$bWsFr&C@gCrY@yB?L~?BcH97k6!R z@|IR_@0z%CW)y#8eLGCxGNSvtCkxWxpQehs zs=Yf-PS5sFQ|0BfC|5u#b*J3Mf*H`3d2B3b@Y1t2y|iE<=~WIAN-o~{d3#=%{zu2& zB0l~Q96b~}MB$AE9C%i zbz!j?PQ&7bBmy3?wd+@;%@@y`Mkm8vu$uh*?&7ZMTZ_A|dOTTtRd%#Ei`-MI3h!Th!FJUN_dfO9+Y_PF(&=|Y zTaM;g%qG}=0EHSMjPPozd3jvYRQqz+>~7D;kyeL5S{(xE*(3`Ma5uFDCpRXx@{y}B zlFm>okm;|=i&A>oT2!gH>xts7XI)?DLMJ7&m(M6(oY*?j+2*M9V%3`|Pqyl&R0Eya zTpS@GXqt9g@JTvN&CpH3*>vVfE(q~g%@{`c)vn93`l(^UwcFyy8f1{5v4^@W4U3B} z*cq_b?^I(y^=M@G$RT|O^vdcpsL$?^{t<*9i5?vE>NTDq`ofANV{~D(SCG}`xL(Ki zDxoLTJtC2k0TD{jWpK%W5%j<;w=Wf<&kNuHirof8vikJug#w`K**h$aH-&ob9Z8*| zS4mTxdxzzEpj;n0*P~OsP|&;TkFL&g=_L$ah7 zcsK^%{r%NKY zN^y(S)PxF0F?NCWMnco(I`(^dI!g8UIT

reZ1SBP0fOIT~#crY_ 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≦In1CZZo+0Y}E6I_IIq-^SqhD=l2z44x`{^9=r?BM!0YbzbcPt|4ZYupa;nUyH_m_Dx#Nb0kpOFT?Pvqts9Dme|>m-A#&+_pG z-yr&&VemOJ?o$muOXkma41TJNhu$BwzsC#z3k`jd%(sOGpDy|@Hn{q7yTaf%2>+`M zu0D;gH#nXTaouF_7sURz8eC&e-D&Vr(SNnU)d$%92CtX#`l-S9Id#HwklO8Sp<8e0 z3#9yv!KaA*UoiL~>DMm|{$m;6?FRpa==n>7KPc<#eS`m6^#8=*AB%l<8$4C?{H?)v z$~cBTmx(XVZ$A{eZw&qI(l7m@M(w6PQ`4j$ioY%876u`f=@7bYr)Sn_$Zm@dfrjF!(<$%8TwMOZ;`>X zME{EnewxrX^twK8Hn{pG{l3BPlKJ^VgKG?* zH3rxBUJn@j7@2RI46Z(YpELL`Wj<^%c$wJqRfF#ld%k6GQ9t;V!6%D-J~H?*!v8aa z-zej<*WhQ1p1(7=`ry=kOUET9>m^0nDLz=rEe*b1=G$Qge@i;n)8HQqz4BB3>I-*_ zp&u>u;|+d}^!FTtPZC`3Z^~bv@5&7QUMW`^JX7qy+~E3rcc;Pic}@3Sm0KwD>TyFq zPx@7BaE+Pps=>8i?;2eD^|`^dUk41X{fdZu)l>VW?^_kueswhT+OOUQKNAh<(tSwz zXn)2U`gSre&oDT?C&o41;F&_dz~GO|y12~X4+#EUgR4DnHMrVyjltEPj~HC-sn2cN zU$y5}L$CIH$KYzuPYnKzJV)&}_z$Ff$lyPd`JW;4PW93AZhM2P9gZ}(+ChCWD<8GP zXhW}dIMv{4hp7fvI}{mQ?Xbw;=ey|;R2p3EaI?Wj$$snmc*c2Spy2AOSNo-Qc+Buo zJ3MD_wZm%$S3A6CaJ9p3gR33>U~shqd|BaAJwKHBpKWlpLl=YJFXf{QK3wLN#_~Zm z?4x$@eMkdWJ7|n)rB^$A$M9D>Tx4*y!xDq59j-OF+Tj+1?~(m^wZYX6j~HB^E1ov^ z9b(U|2461tI|f(#_&%+D`+RBW)jkIeuJ&mr_ghqhkJ_i5!PP$94X*adGq{e&XoJ^_ z9^(zJ`}Vm8*YEL)4Su-HAARql`fKb6{eDC7-9mq};iL0vmBH0M4;uUw+3%h4V{r8e zpDtg>tNtg+K7WM4UzPpsXoIWV5e8Se1qN5SXBb@N&N28p8J9AH_Y`~HXYgXdA2xU= z*#{pt_ycYjgQpGNU+ngR!C#a8;T6GA6q7Nhw+yb|OMPPa==%Mu!F7JNmLEdsxO^_- z-cfLstNgngT)(dxWcaAu6AiB4d!N<>pR)|EzdI;0e3XBg!SQFGxT*|(lHfNr!T$#a z*WWMPXZR@pT7w^u!Fk2w1Dj4_ZGvF0p+8#a|LD;JQn`OMxPEVundKPjc&R=e4X*n1 z6ddD-HuAM-P2e?i7RT?=@x{J~}Qp8eGpS-)n-;4-Kxr`*_Ik(f)2U z_y;n+FE+vFRfFqu^!tX7>i>noRqi(iFOYSbDnEwN^`iVU4X(dW=_I%v$KeLoaXi7} zgEoC+9A_GOjUhYVqsKU^+zNy1?_#boe6+u}7+m%Fk;e!6=kN_)TJmZ<^o}l^-tXxafHxM{sNZt_I&F_l3Sq@EKxoeNS|v;iLMW zZg92p41*U*zveZ;zue&Z`=ctuNBQ4na2>}7JwC97+$MqzhW=tX|GePQV;oiPHiPSP z_a)k-s?PzB5A@Nijr=ZK$E!1h)74RM9bc8(-QarP8D#kAxSVTnjg2#-2|gtT z*Wa;}8$Q}!^&q5rI_(p`<43<_3+5`#e_LFpfB3r^<)14Vm`hB?NWQ`K{yyE{dVjAp zxZamn8(i;SwFcMwNS(p;KEjGqo$9Ike=ZE>;kvKp8(jCd=?2$*rqbZLM?hmyF z*L7WIaGn2ZT-9IaVXhcmah-?wYc|9p(d+NVBspgAkRePwJ!4tH_>-a$QG{$02}aZZ zhFATt1eVX)eDd+rF5qAr5>KIe%076bubHw>qDW9ghu%Oa3PCo1y4V5;^pUNRCMd9n z(sW>&@NJ%Cxy>_(TcLvW(91W z+zfF^ShEQfVWOaZBW~`6)vswt2$s1eznGar*Dd+e6Zy(Iu}Ds)UQs1@hkC;hRZDjV6-mwT$fP8Dve9e{HzPRMh~ycJ?z2c(vFd^YRZ9;X zs_5!;reR{8phER8Lq=POym0xo3rYUQQZS+ap%^mF?!x8YM`hviQ=%K^aotOW)vq(p zIa|10gcvXl8?Uf>d(DIc%&V~aC84~wwtS#dBdDs6mN%39-qiKDlN8o`pG{nIMs_tZ z-@&ze^R^W5&+F8RuUJiGvOT3i)zbQ)oD6p`DDUg+ci0Bt8)s9( z{dyKf=FUBncrY~u2PEgCPQ@wvtFviph4U^C@lL8MJ}s=CvQs)iUinE=GSMM4cSBxP ze~5$6kb`|Y;HyZ51mU%{mx_{CG_IuMS2N|)>R*bI)ddHskB2HcI{8?BEG99idq+8J z%1$!aR*^@ue<5XAcH#2Eh1!gNQs%81>32Q)eK71dEozCkQo{?UkVbSUv7q2BuAH!7 zqtF(AxzTFg!eWxyS63VWN6en-q-bIx+x55vwyu7hr)9O9I@Qa~>a5|Z8IDHQt+iQC z)Y6iWbxJEEC?DR~vZ2Wc#?@D^W@8yP*X#niyr8nN#p2f2@+p;#FP4HztduF0x=ch; z%?*%b7K{#Z3pX6JYGUQj^ROq7vWjWkjb5}upmNRiU?c@&!fR_QXtLn-hw3&BtvYpJt2@VH!hQ=7uGE2tjL29+}K3O+OM%vm;q@d zZRkefvNhj#TOndXIb`{yJk4@^qDIgWtYlXrb6eFUn%!Xs3lj@N<~FVAaOUxXrW;9J z^_2I;)-EJbU18Pkg&M%9Cci^feR{bp)i0?t4fm7%ZnBwGIyoG`=2_R=K@I(Kby&tK z-k-cRJ4Dy-{%2@}af>+g=H4l&s+n@Idd1r?E4NJ05rhq#V=R$QAQ@F~u!8JK65PUP zNlh<&F%GSGT9Pk6PYnLm@jtSH=FP{oCdcrtBPlJLHy_!2RPzWGGctpemMDyCjW>AB z+eZ?0EfRI~{1HoP*RnUY>qITGTs(~Iwvk>fz%VB@fS6V+CY3m+0&Oj`F|KujbvFtDA{GT*_Y7g3L&t<8QKykadiWd? z?RzGN5a|_Ch1$^U$ZD&9t>%8ejUz~t*FP6RBxOViag4^(!8dgjC6)A_y;er(uMhZj zWbCmM2#d$RN2y3*Jhk*{LO7fD7T7eS|3P;8=y&J?PfkJl@yJR(ANe@(Sx2ATDt!#H z+^To_M4Z@Mt4Yv9@~58-YKNZz-2L<*eKPPC4xb9#eWjItF7j<0e%^bO?+`Taoj&1W zV$Scz(~EGYaoITubS}CWq@s&g5h)v>muOiG&BR2}IKNS0_2bR&qYBsQcqSr+u-JG@ zWF?=4JUV?Red0_;ed*JVc5Qya7~z!MLDH4NX^hiUPSZHe;Iy(b*L`L?rJ5ZviP|{X z8UKaX>MT2B9e7LrXMm%wQ)f|@JC*4gl{W8!-*j`M=DCSR&AYynjYjeKRaBh?dvIS{ zj9p3PcpN|M&W=1xX$~idUXX*Kpt_$E%Fo|BqnS^pb6f*dWNt{W#3wCCDr`#6i4(Ca zNIVo*cqSb->fj2`a-p{?JeLj$BV1u~dI=S3h27?KjQ7^C1Qy$qN_AnWgnG6=EP-Wx zQt4pO=8}tp%*`yi5*rBVyEz@d9b6HXUZQV^)`z9BG$^-6l@f3FR);01vM#Aqn^fAK zRH_S0hm*YhVd*sDxjscDe1}x34ND8Dv^6Y!LPN1VEX}4Vetk^a!AO;739xf- zmp={pzHP~=O^b=(oF{YZWN@c{v@XxYFM8u~{C+n((uOSIrWxnZn(AO5R;94T*{4#T zRhjx5w0C08fr9b2mp~402estpJiA53JR)`!ipSO+b)Czalg$PoVGBQggM;qJ^sDJ|%p;yMt-Jlh1Z zO5z~n5yU*(1ToJxLCmvF-~y2-H_tYam~Wd%%(qP>=G!I`^KBD}`L>C~eA`4~zHK6` zh}y=L)HacrZ<`2fskU*YwZ+eGw+Sz?(8&Q>ubK&*LuG);H`3K`pR=-R_s#-R zi0!&0^OdyDbWnBLZA#J!iJnb~piz9qJ zErX6dx>jFL!<}F4>PiPx^PPQ2S=Kx^^XbTULd_-Ai{tl91RJufq-S{ll5=$CyCvE_ zFY}GalVSTeBb6jn%;v9gvYFS1(Vu{?Yw}SPLgX-9$5eSPTtMap5!{sHaol_lkKlv@6X$S( z^-fi|K^%r`=0%aSnD~53vsv*RFwVJ?Ds#}5sBv#_)Qck5F!c>gjbCEqa1v7IV9==v zwszNKapXyE@-#QWzLCQTc0wYAbsga)kvb;a#e~>WaySt}45K4l5@|-WBp%PAG@EZ$ zPGu%^B$r0|GRYt&!Sdwp3xmrer*Q2guAPBePDB#6UdLu>q>KqKWkNW%&*4M}vDY}l z+as%(@E#`oIS4rsLM-igJdMoQF*kE#>@QUBM$zSy3Nj;IjofQBR!%&Qy-s4~5UbbI z3TaI^RxY1Z5LT{6SZS=BcsyL*aeAP^bCBb+IUVXj-vxxl8LB??s4=p<$sZcy{RXm$ya1mfBG_- z{c=U>vDZ*2m(JvqBZ$Q8vsS45V(t?FXyJICFjtFj9(e4;}s36?>HNov7dOCLP`=Ncx%AHqA5jVM%mD{iE z2KA!-@wA?@vQCNvP#ax2)m7#>Vbfh{pexOGr9rM#>`H@OXLtk<f$whXc$y@wmU8ylHC6GP>0bjlTLcYf4FcWw$>{771KrYFegk1nB& zF}iZL3PZr0%@#bDgU!1Bfc4`)(N@j=Z$E)nY48y^|_nWQ#)Tml-L5I zD_l3ykQG1hEHyAa5JZf1%7G(EwqZW%aqFXL&9gD~a zXwk`-9Rz1aNv!~XKK|`O+5`hC$`%bMDV;U1Vs_DhnI+|A$p|?NcEG%nnFHp|nl)g_ zh+)%)4e7V2Xm;_8@_zG5N-LHO7}9@8|KZ9c7%;!Id_eKsIb{P*E-5drm^q+y!R(@b z^D1Txm|e86Y(T|grKD`Xg^NlS&nPeY_Kku-BN6m3rhP2nUn+2ro3irRR7EJ60PzXR zC`&&J(rhdUh+=lp9D-@aE-WvGuXU{@LUJ+Pk3A?8K^hS+n03*N*|QfpE+`d&IT2Qr z(kHPa^(#tCmN@c?#q^2$eb9{LyDQ~Sk;rFvN5{4vyeZnJbu5~)=F0x@0r84Wn?8H_ zoPqHh?yjn+xFp^>UU7bWB_)ry(leDJ_pZp=bQ7c(-V`*72_KuF<}2=f?kZ_n`RTyPqPd z@#E&kKO+^^yd1CEMeGMYOfEZ;Ct~P^S4@wOX>&?v%rDCAdR%Vr-isHM%+5WkPhKCf zLhs(rIdPwUqZ7`2`_Gx(CwKI5xp_Q*{YGOPa*sPMmz)NBe&3k`+#<1z8M9^;Ei8vm zBQ7G2485Sz;>?oL*})yu!kND{eK&v`npU%;C)}(a;mK4 zvLf<8jT5BiaYz+-9TUmKou&J^=8pbNXEAg@!)8@>WUo!7f(zz?jvSb3h_k<0dQ)rx;q*NZ@Ri+fm0=$$& z!MUuSH8a4w%Mb`~rgTDK#y}bm3^<{I0O+C zdauU$lgbjR2d~_PL3x1Z0k3s{6F-&9$XoY}`J@Pr^HkwI5soDV=O>~7eN`12~>97qB5S8sT>Xz zo=vHoa9fUdZUkTqC{$0Pn`HqWAVI3#EDP|mjSv~1vH&l_K;bN07U0Q{%4&wP0B?f` zV3U^xcvCO`_l<&VT(xgpWuHW5K@M!@vN^j{PBfv6+=FlY?y&&$n^ zH^UC>5tT(k2k8C{4jh|AV~e=>J|vk1H@s6orzH6l2B_eSv&Nn1f&y{07%-*aIvk~= zsSr&>qyG6R8%719ybIPe?S%0ZWMdpfJ-K92NjWY01@jlqD=IIVEu*2KJy@0(BPCqN zm^d?MlogRpDeO(snxj61TOQ?k!qO(vL`V&HUnjxzI6>09P)yV|-1?}-I~h<-xHnOr zZOON0sOus}&@6{iI?s89XrW@Y8;DXDamF64E}j^5#%;ua!f;uHCid&3AS6`d zZnAFTxz$oeqdV)Oc?;$SVK4@ntsGE=VnTrX#FO}gLRGjhA*W45)F+8LHoIuvj7w=? zNg3xnQ*V=DAP742c!vrwbiq)NqfihojEgHEUJ@y)OBsg{4(dd;9Ek~35=Y227+Y|b zHvtk$K3rWAlZ|&v;;eTNF%m|JW~4*aBnV71ZS09BPC~CK63;Y5%o;!D9F7_?Yr#C~ zrem-BGc8YqwxDxhc|{pM7L}9hPUxj~Bq$pO;9&lf#+-O68Idad@K0gzB71mqz2%@k zPQ8=Q7&C!ekDquZ7P!QsNi08v9U={Q)yT1zn4B2~kaN+Mpd*vW!Q06RBdu@|Q9URF zOPpFzFlo&AacA+W<94#z$Tkub#lO{l+dw*g7?Ux{v0I#A$oFE+=n|*>W+rV+Z0c~w z2B}2oquzxFjzk{ea4y1=1VQ2IcLH2cBFZO%-66CS-AZLjCc^KysBvyzWt0})WiCkH zWQyZ6fg;F^89U~L@d;D$?!-oOTN6j$`&L2Epqz$WasFa;t|smb@;pGK66K268o zgFuJsDbqDy$Ovb_@#p-$saHazhXhCx)WL^K~vB=;x)xpb0nQE=q;KVYzAFAPJ9BQi( z(o}hOfAqs;g@OOdW-NC5Z0UmVK+73w(=dots8^7fvl4ixkzjrpJ{+d_*2n{W#+b9w zgV1g~d&3g%E$$410nku_9DI(-I_wx!ew4(3y2xbVfl@d2q^MKW7W)jgwDASg5L$@h zJrT&E5HVNr9@kC8g3}XwD9=wKqk%ZF;LI}vddeu8R#aNP=u$Lx5ze3s6%f3VHh7M! zM8%{yPjshRNYC?pQ!Fag!wPOv*rZ_&*oZB`Cr=>mR=}9cmh-JsBQS>db(Za7=OIj` zTfhKiLEv=2+l7tUn20^jq#}O|j zd}P90*gqzti~mGqDCZ{v&w2mO*idsIAdKBKBaGdIKgPh-ik?fu`jpHl2=Kys6)NeX zugw$n(XYbxPXVWkzsv~vpBvV{@2Z1d_|*EDTa$4Wgtz$e-lI{yC`I|)W<`pTs$n2+8)CtdkcvhN@0-C5GrkxCW=!Tu8+nfelJ zPesVl*BSid04nzsoZeCVU{O^9o8Lb5d7FoEK7SO(KIH%xDol-pRE0EC(QCBD5%B4pexUP zgsG+d9@R7^zf$CDdyF5wJ#8TW$Ap2W(ovSL{UZN|ys0Xh&{g$#l&TtQUo*tD>7QuI zIc=w(o20!V3pPl5i)%Z@w@Z6F|7xZERMSB1ukBxld*V4d#IfR)h z!Yw+;-xtzz=T%@7)AGpb30v6ZlBNVds{zsh~f&#x+4dsR{f7;gcqt z8=uXI&%7q+mkNE6(95wSxSJ@X}A8=&BSb<@ZrYX4y)hK*?K*|q<$V+Ib!!(`Ii$i_Gf&l@AnJLu7G4^NkQrrVMf3uA&Ww_I^z9k_dgdaI(_R$Jp_dY%XN}~QtbCy3 z_=ZnIJvkcpjTP$TEoKNX3;r&|tJN}B>U&xJ6bW;RirkCo#1Ac;U>8-2o9eqN@0Shp z-0<_c6Zb`p9rd(_;~uGaJDNARaIZa_{wqGi!|^Pmc!h^|^6=X|96!oZ`lmd+vxnm^ z4RKkyAA7jZ=a7fv2(SG0IRt!iJ-iSAUHIrq|CL^2%viY>c=Wy<@EbT>`0(|4QE)uY z;J@AGcqVYQJ9^8^+>i z$o>l4ANLCd*Zx*gJ+5+tJ2VI`HF%y>Xv{D0??(Ss&s#mY*kcvH$HRU7pYU*hT;38K z&oq#s=a8>F`raP@dJp&c50w2IJi2@IV?Err^E3}X%A>!|!|_b6{d&y9eYszGxW8Wd z(vNI#K_7qq<4*u_0nerX%KuUi$Fqjw-}P``?j23wFMGJJ|5qOF+p}dF38M@8`21h@ z@Bvh(`e-ZzOaGNe@AJ`EV>%BPLKt0Lr$DCEX z(8GOwrZ#~WH-TT_;r_hc=iviAxxe#pU#^&k_Z}GvY9)UwPM@#?{hTfsF75F=hD&jc zaiXtb6h9Xa4s`Kf56~yJUD!e|?4`IA*Y{w39L)ShBqO@+m4E*hj&Qg~4?R2JfsL*L z_YvwjSMc!$KNSm{t~1?7NM9=J=Ujt-BV|4BsXk8#|9OUf4G8F}avvf89KrRxuY4|- zLHMDe$1n46-S0j^KIe&^KQs6;p?})o8XN3ogX3?Fap}8c)#nZw$Io4LD0iMbzpWxyaQRAIkq8ncz6b`}BQ4K$jn@ z5A)|#>DL@X|3{f`R~uYoecWtt^)dGYgFh(x{LtX<%KW+C;OZ+K=X+e*uQahIyXo@q zbfJ60&>tt``+>nzMeeT+exvBAKEqY+Z^dr<-b3+OVz)mSJ~zp@{Mq2Y5q%=k59KpK zZwD9+13Szw0%eb^R^fP5$bTjx$(Z9dJM+%>j244ZA)1~iuRnMbk9?mlKE5)7* z4DOr+1i^O=-c9HqGx*`s-^~VpPVDBN4`B!V92b`#BM^9BvHKpwCo1duj|Trn=u_l8 zqy4=??2~QqH7u3>5X9hL%DDG6_!zPONQ3LTEj0LU(dR6Ke=6nK2Ja>PS!VDdVz=c6 zZz24DXz*W%eI7LUJh8)*2JbK9^`gORgpclXYR{L1&&P&-n~dX^2G5pt@fU-CB>ieG z?UcX1mpIJeZwP%agTE#E3^jOLvCoMHzfADc4gRk5SI@DkPl?Qv`G)>Jng5p?e5TBk z6$Z!m0l0o_aGh5_H@MELXAM40*6%9@pC$eJwZXsZ#0I}L_(Yj+9mTHN-_|n!2N_() zX|ll&3ZMA~e_rG*G5AEWPnE&l}@Y{s{DuZtlJ?}C2HzM}|gMTga?-7GPCgc8? z!S%U<9mA0g)jl@~pISqIjoAMsgKNx#Z3bT^a^Ez#z86rRt19<38OIL|y~f!5)ZjlB z`Y#MVR@TdYgP$$-|D(a-7zo!vgNM(bvc6T%h|t9iex>X)`h2AHKb861#?U*d^bBS2 z_r=b+1}~F&($nBqOTYRW{LfYYaFY-`PT^ z=Q71{kH>Y3;WJnId%MBU7d`JX_*SvoT7$2WdHayTe<$Ovv58fm(*=LR(0?RypECF= zvFB!kUnulj4X)1vuNi!bjF-L#P<{40^91i2`txNS)fpV$x8T}k@b3x#eFpzb_5qE7 zt8(*&&W{y`vC{X9e>HseNI53srhKj!xfur6=g(||tGxCG&ysQJZ14%P5Bo9apyyC1 zK-V#bewd8c@dn>6`WG1d2$@%>8vGs^-_s5LThT{j@Tnah68$eQ^rB`k%iwc`Pl>@R z#hwccezq{GF!+6<|K$e%t(0}2Q#~&e{JVz!Qn8yK8xMBQ5&V0G9`EdMX)I~w|B~4G zZbSbg(eploALZBtdVf$p?D&G}o;CFSgwKlxe@^gM46d;>-!S+IvTy7#_%kw&9~iu+ z(Er-t#|pm3;8%)1UmAQqI!M3a^fgZ8VH=&QK) ztBb+4UwZ#n`ol!tNJAf&`J=JMl>REQ|5=9qcQWp?4gRFq*^ljqed9~nKPwHrK408q z@ayD0rT1Ia=Q-i?kfDEA^jU9kea?Bw;A3PSzGLu{#XfZgKTh!97+lBw8-we(r$ceN zRDT_J=lnE*>$rC{^g8bS4X)!p%HTTgg$CDgKg-}c?z0W9VsUJ5BeOb`sjR^WBBNNC^NXuhf0I5ld`_=RQ@@#53Dlu*Gc&y zgX?qhdV}k8*A|0!mv#N7!8-{4k-^oT`wXu3{Mz7Z&otqu{Zf0jHn`d|*WhYTKXxF- zMeV8YUzPt`vi}qsJ{pVCk2MHBdu3lOGW4xwUs`DJbitPzTnN*5GQN zpBY^3^NhjOKCc*D?X%P1f0gnsgX{Oc2Mn(BGb-~@?Tp_&;mS7nYapPji@~#m?@iNRIwH3nC?D-Eu4?=tuq(q9fOLiSL* z>3iYl4gD&aSKAG)`g~w;)#nR?t3J*_c0#V|<9v@La9tOjTk^1ldY&ixoNDkcf?sOz z)p8#Dsljg){2hZoEB9%Q9jNyCk?iwb|}d>Df6L?!BuWogR9*B23NVG46bq~8hohebH2g5 z$++BP@Y{s`R)g0I{hbECU;4G$;MdE%yx-t@uKlUO_4(&fgP$Y(HyHd8v45?>|0MHg zi@_tJ|7!*>k@4MS@Q-DG_>JJ$?nERH>>muS?^R;*LkFF=y3gktT-WbVgI_57>T!ar zT;*S2aQz*?WWz`078(2{SuYEl;IqWw`a9w88a~SZ`v%v2=H~_<=axh8OcVTHGPwTE z_8r4V`G0EgJQ=UA48B9;Msc&JOULDTR}8WZt}(GY8~je;-`C(hWW9_u_?rL`{b(zSNptY zaJ9pif@^>OB=fD_&})C43x4-|9`v_T`rEy=%jkG*l67&E;L2b7HOS!ld+9NTkM{R; zgI^_jp5FwY*#_6&SC<(+%72ByTgiO5tqDGN8(e=k__X1p{I?lg=l>pq>-?`bxQ=5Q z{&;AZep*1@ZHgXc(c!@*-#;ovotNF1u_QfM3`e%-0m1@7Rp=*(^;PU|hZCsL5P z!ZIOI#jjv)1V@QrS8Ed7S1IS=FKH4 zMP)9<+#I6Vq-@IFFr{a6>I`&{B~XDSfHGO}wS45A6&*=#Xhr4%D{hu0Kma0WPRdU< zNMayK|1P9IMacVC$HxmJ%W+t|W{J>u2#c4Y(ewUBd^`<+*U|;R%SsM_N3V`JDx5^T zqc@&@0K8Vo0q|P;G4I-Fq`kJGiX7Ljoge&;T(L`3Kdz%Vc^t;iMagR{03Nv;^`q3$ zn`=J+p2o}zL(U=QhQ`d30C=4d%g#j(M4Y=WC~9cCTo)9u=@@xoP`fZHAI-vt>Ggs; z5&YYN+Qmkckf0`m+DQyMJ{D%DjDCb@u^$I1$0IBGeB|RnM!cFn`DB(d23c;^J7ps7 z%C41*R_F3ATAj38xTqetJqN!dBw4a}wy> z69^4bucqW&B26oyj6|zTDTZc^M5{|}ekE17PN!zxOL-QX+7emGXCaSHm(eG)-#{5= zpXrQ{HueQVGUE7AS!Se;(w3Y&MMK*1Y+^)py9niXNIRqHPo|@Wk7nr-2hJ5XrFWp` zhqx<995`2aCLPi{xWcns=Zy}OC!jh`@<5Hu1_i* z400$AT)JaY8BqcF-P($<)QqgRJ}j-FwQ+k?De;TA)nN&}S(j9*O)70qD%FLh2_$cS zSUQ4uu1`@3-yx-I!_q=@JuJ1QcH6_!k4ew#W7-Zzs!Y`qxLhBW&~8Oosszulgmx4M zE+f8~Mw92zh_rEN&}!DqAng>)5;uj?PDOX)Jhjrs^FX@1iv#EKE)HBPa^02Y$AL>b z8Qh5}O}R6Vrq7Hx{$?yQax$fEnsH918SKNV6sDbhCFNO_skxLBRnCEe@m7cfm!@&x zP#dIOj{dmp)mT8SW9c{HYbAc7S>~Q=IE`=`9#8<+L5A?K$nh>0z86&S^(ZJ8^mhr(HPB<+LlO-8k*e z>5-iF;It>Fy*Ta7X&+9H;SgiI3398AWjE!>Yl8Ja()=6!#N$n=`oy+ z7>Pm zDD7LU?mwx8@T+~A`0*S}e*rtD%f8s1xbp*aJbg_BKNWL}_1*}7?db|hvE9;NI!l}6 zr+*f~ub3RwuE>w^=&XfG%FA}UD^g1Dh_kf@W|i%BR|HEoS8K3L^0a_GPGY;IZ~KMH ztV|yjgTHG>b!^O&d2Gy+d2Gy+d2Gy+d2Gy+d8~_OrQBGiD;yVlkrb#EL8D_>+*{Rb zui}sF*ld;Q>tooPU84=YJ{x>}Hu(B%@b%f?>mzZ&l$)o|#u&cfR(&?cz9Q}FM6AXI zbImj^m|v<_&EIH4%ChFu)9;O8w{~P}ea+YUny>XWU+ZhW*4JF(f+;so^ZR0*Jk9Up zMtbK=jtiFl&ZDZ`lJr;7W>6O$zinyWI7?hGt?|ZrTbeh{+tR#ombhTr#?$WAv;t2% zjSJ=oUr+lL)#-g*@5m%Bm=>^@WmP=Gb3dEzI#_n? zh*^++X#~Go&WLZIG&6z;*b=Oy_Oi$uT)Ts7e}h_1uxwf)p_W*Wj@RXpLrjhDZ!;t9 zC~e7!5MmKI!ljYkRGAU)&xH6{M@vqG5VPA6-X1xf3D0K2Vi0m7gqTbj@k~;nJ#>ks zkKrlHdzb8;L5JM*jj?Ui(iz0%lL}%Tp;9u4=s?`D?j%MPv3fnNJsndVjmsw$gq2V! znX(F}TAYqvIHNg&&FN4NJsC|{MjY!t6*Flv75Qk2Z8<*jaw>AyDl6Uny0X%BvQlm< zAdAe#uL^t%aNgb2-7VbRm~$DImdZ%@I_k=}`-|R4J?WBsMOIPhbN*Xx3RZ>XK%uKT z!ku`e9u*Wf3V(M@CCom=jmn5)X?0@IL?dBr)i`Q~zikdEvXwA&(xaUlkzT9Pqn#b` z)Q%M3r!(wF0e)C^v@=!<1^DRw&%>Hx^LZyw}A zT36O0I;@G%N(eFQ#10efr6giI(h)5>%t;NSXpL@y*}{<7=p<&Ng_&c0JdT90E&thd zbZjGL`dP?mtZQ1#9R}=oIQKznD;+$g37rmxtWNP+wV=l!pA|n+0c6{?2y)R*SfAbm z>#K;|b?J1+da9J1xh6{qdlQA(as$YZo;rYF;48uX>E;GZznjHCyDPHFF}zUvK~FM7 z8V&kT`t3q4HH@^Cq{kxmV;$pe9H`{{=uB&*RI(tLPlB9Penu1W9ojU=Ef15jw<2s2 zKA^6Kp73y%kVCDN(D@9y&LNJOa}$J4Rg<)YKs@V)KC!E*kZ`q|9BJsWq&o2|j<+z0 z1{!GykB-UydddGWVZL8&ymU#F%K|(qi$5ZIbjHn0O638bex*YbKqWDoR4{)cWvhyL0QzR95&=8gfyBL+3 zF%@y9ref%D8Ru3ihc>}Uk;(}l&3Jku0NpMNZ~~+PB$WktNTPxmpe(=x43*tn4ayxO zE^#oH0LOBwccRJyoO7t?G${*kR-vK@E(`E>hRPc90MBz&lps7bcY?n3-%UnhPdT zcDQ3>#-1c$FldqjX%Iu_Z-vf5gQSo-I%s1~oQ&`iY_f5aICw&0t`n+svX6sMA&Pp$ z?f&h-beamAYqeG`(3-x%JP-t5NOwPESn3NI_H)Zsz|) zv>IadkHx6@+repwU84bMUJNLOE@QD=x$&rYzJ4LRdDeTxt?VMv*OOBflb zAz@U#pT@(EUa{dD&y+AD+;Du&l;xI)7|IP?6_Ou>Ge9?8{jv&xt+=K#&JC%t4 z0`>n+&=>#2naDR0<;6v)3X+1ou#7V%PM*lILL{;asTUq7)lp^`VC5eO=JGEM*kTXh zq@>$Zu>Ss5Y!(p8o=Oic|N2NRB>q1)Gz-S}zZa0D5&yKj<0ZBLL?|hlJ+DX(-4q?n zg$ez~!mfmee_b5{YgpnW5W7_ zQlCQ)NuhozEy5Tp8iR%3L#h5#oc#Zbu_DH6;v<)En3Z2bc{KTww~w3l>9ZrzSqx1J zhd2gxU``jlP(W56W;+0+t0(;jPH!@jF7;iN1X97u!ecUc{- zF&IltECw#K#GrU}7g1;M=v$fvefxRf$hC)AxMf-hD=`Lwhpgg0it_*t%j zuRp!AX`p`N6if@)dc-#LO({vi_e~f zVLZX-L&5n>Nmv?9=*IMHLpbP5X;u#U& zA80_0q!=Hl7Rr%N6mc^(dZCPM+bhP#hYpKGO2fx+Jve7wOcaigZ|O!pD;`9SP- zuEBRnd78n8$pJvuOK2a#uQl}Q3*!cZt50rSAIfKf49-1<{vz4$9yfSP>2IyUFUMh< zu5Iok?C%7z!%lhANQvsiTRTW0=lr@<5K#2rN8*K zijUtU{D&BPqV(%{gVziH^9+8J^tagHA4q=}82lm8r`+JDiayH>e!So{2Hz&-+YJ7d z>t?Xg;5W-Ses1uirN6#!daMieaZEoZ;Y;m#jLefPgLe?VoeaK8#;cFPYlVK8!EYBk zpJ?!hq+c3aNcCwe^wSLe8nN4agZC1-8goebJSjMSBZ5oud9r@hN3`Of3H_sneyP}} z*5LJyZSb1GkC$=rebdAK*Gs>?u=Fxs^#%`wPnzhfdTtdyZ48dTroh$B;K$4S%rkfg z!ABeXCMo;(FX*p6h|e|j?}$Fd29Jn67aM$z;MW*@qV)F`gX_6|wZVJHe0ap*8wG#f z;NNBI(DR+abzbcsXEh}?S({;}+P>T5{ls?YoXGW6hzfQ`}8C>V( z7K1Mod%kLL_4W9c!4Jr|{L0{W2%nD(UMu7BnZfT8JFAa1wZl50|DBfJ4{lY&*)}Qh}Rq$p8pDOLM48C0UjkX5=j@Utc7%G3KCH)rF(Emj2)63we$~@_3 z@JyLkgAJ}exQ{XTnWB&GL#oeNqJM#*UoK_!rLXj7i`>%<{S2|s*#^%=L%J?7_!Xkh zEQ22s{v`(2^|Qd>>Z`cI;0MK?mmB;`;eVCEUv_E+8e>fRTPgHvj}Vvk>Z4onR>DVP zk|};peBc#7EhX9iav)lV8+eK$XC@HHa$d4qS7{%Y(r)&B&c zf8Ee$iJjjuxPA}tp26Q2`+RJ0{4NmJ=LTQn;NUj~FBbeOgMSW%>H6B>#Zo?GaE(cj zD&wR5-63?%4X&{xX-(=`x!v9u-Un%{%)8PDbf9lt2gTEklzTe=_i=IC<_%OCk5d7TW z8e2x!tLi^l_-r%up9}t`!F3@&mRr` zqS*PM!T%!kDI#C{dzI`b`h2YTP}v_2GxYLxTT-kJHVgKNJI8C?6-LiAEQXus6Qwc^^Zo`zogHQ3;Hh#kfl zT+i*kk9*i{k<9b+4E-U&iw&-Js4%$N;cA1c9d0(b+F_N!)ea9DTIM??;AylhFUh;Og5~WA5mg8=agRUIl$1XJ&!fG z+H;)2)tq{tp;j&oRC) zd(5|7vBLpFuiuktY#LO9{&V4flC)D?-v?C~{ExDqUTyI8at^uP;77?g-fr;U2%q~5 zzF6%1sKMWmae3C@Lq+a82LGM(|JMdrx%&;Sa{pp*m75`7c&L3;ZfAq*bLPKE7{v@V`aQLn{pZ6Joa?82mP|%PNCE zF5`HQ!S#IkfWa$-|9=_$I??|LgZC8upEmfHg1=z!yJY@sGx!mLYs^QOS48p*eNX5W z*Y9t>Fnn}>OOqcC=zP%i+tJ`>$vAcw-10x#;QGDJNW(|vo?`GfS<(0qkImht7 zS@bD3e3bvy2G{qQD-2#L+eoZGJI6-WP_{RnFgOH_wkDj zuIGj&f~!6%x6zfgX_3F;PJt@RMUT4>kYle_poU#aNP%18(jB+T7&C)sWZ6FTQ&^UsXjV? za>Z_ntNj-)S}?1qtSofDJ8;Ob!9zz388|dAH<$j=<AQ=PL`@?=-NAUe#*XNcS9_>&fQ(O@x38W?6~^FjwizZXW^edDSYmWR+ObSD{9F`VKa8_ zSzU3UYUzPsnYc^sM@*gpr)QBko@km1>xM1!s82hqE8eb|@-{KvS^Z16H@%&#s3e zPV$+BRr{8Z=E#8h_zU>L>X)7+#SU>-stfj2E!}shq6L>~ zf~xvh`8$LJS=Zq1&vk9Xx{R!AP9#)~a6KuSjnU)Y{+^tnQlEAfRxRBbRHW|7AxhGF zXTldNyCX(fJ=*SczE~YeZs?13C-e2(5d+9CytbCO;{tVszwxRrSXWc9u19bv2%f8tR~LNBRkf}~ZB0QfwWz9%Y_Gqj_R4l# zx82okuPNA0b(lfikLl!qHkY%LrsD%@y1s*+w1Qb(#nk+oDZ6VXe2Nmg13vWDp3BHU zdnzbdu{W}!ug?cV^IC! zvt(B{1Vko|b01O&BiODyV?8w4b1R`+m?4@#sK@9TU_P(%bZ)hG2B>NRuBS;%R8E1a z+E_A58uq|%gUKqGw%@7^&t2+!2kAS_UtM%z*T>Zq9H`!W)i3bFW8zz%Fma;8KP0W( z=u?M#YKN~S)OMH_x$6X}>GiNaxi64Y*hmi#_&xkqZM@YkPrJx>98*Ha+ z64rHlRehwqGbM|%s_LWVi?H(M@4=#F4trh|YMNwmOnupo$SMt1Hb#}GYVtc&)u)%c z<+_EvZ@GDJwPRJsJA#^H?*cbw&aZL{F67hdIJg%c!5zcO)zp%ps-*`HRkUJzdwloy zBf>h`k7G3j2dks3_Fhr*M8H54iOri46v)A>2#^g>PJLxH!z7|JR%(V zSb0vEFDp;wJS#;*xh0V0NIV-%=FnUf9ial7uW~2JBR!gt3+m~V-P^8e>H7f}^HEGE zJeM-8W;|>*<>24)_e~434xMxN8{XL6bfo1NS|qo6>Ava;a%eqaH~Ammh+`o+wARH( zcMaN8>ytO>w=9%PTN6>m$`9W_&4Z1tXnmVoKtf<13B;_V5vVB`!G7h%dg6Y2&%4Bf zhPCka!sqHz3R5sJ)ddHVk^C5`Mlyp-&!HI-&ANFtHKJTlk?tl#>UtbK=zc?~o7Ox+ z)C$YGfbO%@D;Z5%6z^C6lKQ-xcF1R!Q3E%!1qVkJ)K}zC1MZC&Wp5Ta0S6Pb0Cy;` zEQ|E>sc0h^Rj}`hOl&Bj)vF5No1VDt%ewJ!nj+HUy#t!)+>%yIU03{kb`|{^fx5kpVWxd>J9yx zbEcZ_2Xv^)r6S#R_|^>rI%|icFf)kDH0k{|rbZIN|o+Q6${{Q<>fVuk+mgJDP;s z|8?T_ADla|l!V)V)J{o1Pe`)FNP?A-Gf^~)Q&>*yFsZP&YXI^`=lV)Nk>(_kG<=t=xp zlTV*hum~m*Mpoygw3G5vIqxPlmAM(Qt)5g!4U|bfh!RJ24x50ohD})Kj_QsiH$1AZ zqs7OOLo{pxO+~i@CQdOp?#k{WntG>Z8icL%u(6uDt=3*fi;kx4m4_2`ve9reO{23A zElY1X;mmueoKEgZn5dDA=Ep#KxCMol^h_+ktQ#w6L6QoI9`QbR)eG1J6USGY+e>kB zC(7M5WW_0;hW8|Qatg|G6TPRw^q(2ri93~TWlsZmfS_O`dV^DDZjYh6u`~1D^g?%V zmgdz<>q!&(pHIWi;ZbNhV2}Y#5@@Q-kov@c^RpSs`fTERrYjjVJu5qL^Ns6w~Lz+l*jh+d%<60*e_wu7`^iGbz(T9rh zL_m(Cng>(prQFees12VLec|X7$2$Z1wWjtkN_YSM!b+4GAcCZr7qX-t_$&ts%T%x& zsSd-xdcX#g7BRZ-istJ)5=|m%Toby?GR& zsYuq)e|F9q3DV<^?y(aHi^m_MR3e8ko_fONgt+YK3&ZTJ>%wg5y_!vXtAw)6=zox% zKDs^G4TrBF{di<0pO1W;1pS^MW}7|+S#H%kePVUk$^{&899+N=mv;e2T;2s7ad{VT z#N}PU5tl#j2x5tVBk2=Mbe zuTNa3Rc7V_vce(=cO(ZrhfnMxSH=Z|n2<% zZnZtBR2P=+BIWjnB`95=R5}>6p*SWPj!7kUEK+`R`i1nIvLYac{~tV=4@CY81)mFmJ$Cdu0$ma2&7dKV&-bomacR2!C7QfX^gdWQ_YJuJ1P z*>QbLHG`2VQ?&#x*M}vvTM?EpR9nLm+EE;nc>HQ2;;A{J**G+4J8Ndp?37Ds#NEtn zb}G6X=Na2)@f zi})pA2u?w>tFdrh_Kr;ixa^%TQMP?7<0g1cXE}XiJpeyI$R5%E_ zbLzg*?ZNq;oc7|hH>Z6#J&M!5oc80iKd0_%-#pF_Muz zI33C9C{B;%^f*pOb9y|dwa)0zxsS~Vh_3Z)@h_n;2Z|LEYjiIVYTf09mGZ20=W zsfF;XeT?|<9L#tD8?DQ}csOmQ9WZF|j5U!HsNmN4y%Ee$DI|qI$#`jkHp$QUEP@{* zx+c3KzrdHCTEIRayY#NeO8Q+t+&#BCv8OKE5 zq}A)FMn*lEBcqga7^RP+Fq z^foan+KoECGo-|K%XMLC4V89>CG0GE3mL_VJRtW1SJFGfsOXQW-PW*<_tB)%+YuSU zUwlC3;33?daVP~p>~tLnVxDb+m}i?H=Gi8QdA12+o^1jb8b-N!wu!`i+eBi%Z6Yz> zHj$Wbn@G&JO(f>qCKB^)6JbTvHm;<$iNt){L|Du1VjEX_JJP0P;jADd%5^)XE+tk< z^S(~)_G())72B;cV|@&_W!KXUzTGzXcH7|FZG&&O4ZhtZgpG3Z?6xs>8!ZH#QyXKu zy_upRY+N%9VdIzTbXWU+ZfwA#9YJr}=%c z98dH6xRI`g5O z46;95k?Lu;G<76v*JfeK>>%Sxrc>>fF$-O*%ebyiE&0x2q#oi?F8Ba%W8gOLKM4)U~z|BK;;b(ZS&6Zu`UEKb;=Xn`#L}rBT-}KwR8S&b`>DoIn zZ$&!M+|6x6r?`x_BUe(sw=jNxo-)qQc%OGo*Wv@-okg(^q8{T9cpuDWULQuMfUj%v zQ4~Vt3}44oc`m$2#s!hLNK8EbD@qTK;9v$5=Wv3(iK=ijW49I=7e(N^D;`gyG@BLA z0plF}5n2w~QXTGNj(Sm~KT{83>WLuaB&5#4pi>jvhFp`ykr~`%E;qp*m%|BmZ6btq z9pNRB8<=nf6JqhePM8UJEhr?At2;L2(d3Z!mA=DG2wV7oC!isK$s)c*oz$X z?U8b(zKp4BK+TB|Vq1vE@z+-!b2B!^-l2Lo<}RO9kooIs_-=;{!%I6ZVAeJ#Dbp-7l*pY_mrp84hg^+} z)9Yy%aEw#9)5hsB6i?EQ&*pTDJto6i!s2lp0(i&XNJW05fKzabksni$6|Jmv?3d@k=FuY~7q73tW1FGCC-N6>YD`s;fgegPfeg?ks1J zlQXtAnnVYqadhR>KE*+F2oxq8^tm{Q4t4orXUgaajdZ;W`6Y54IRU#w%F6mHr3eWr zD-T@hM4aeE6uQz_Cw{Uk6}Zw=S31cxym46{*7W2zpyA5%*&+i-nrD%tpuKyIg&HFUzQs14{i<1;vf)c($byr_}M6Z`pDC5p1WE>1- z-05T#I~jL68M9q?S2ZT%!BB=9-e;Q-abY{P{NelIoMIf(f(_MT7fEm2VeZE*MZzwrD^}>8yDbvx^!=nj27dX_+ILS2AAU!UP)=ik^w{d59vQ#nfzx4r<322b9}lm8XZ|vgVd4P zG)pHGqL^JYr$5J{GtumbkODx25$w_sn5thzX~`0z<^p}D6Nd$}E-EUgJkk5n>}W8F znD|o_iKiO}r^q#kZ1>QW{XdKExO?E9`1l>0;+>=2+n+P=>-f9zs(80GbN_H&ysF~d z=-4(dpIfmwJ~zHP{&4)#alC8% z+)b36cg`id*Tgrirm7_yQ!;bE@@j_uadGs>Hfy3iTYvTN>iD3SpNhAc`|u?%UlPA| zaC~5V?rI9LS8?u+c(Zi(Ur?*T;tH6(ys#7hEM*a##s7Xio}E3}wU@WQ z_y7AnpXAw@@0>Yv=FFKhm*?4?&d|Z{EP1Cht8sJIC3#sR-Xq#qZ+U{MGVa@^&cSq=q-vvhw3m!Kd=l8v{WXbZ-?D*a1Z=kf(9^Vk0bYRx-&7rlSd)6$u?Y8rm z1kWFK{-%3EzX%m9UmhwvZ_|e0S;K;3ht)h0njJjz;M*Q14LzLovn#%pb=c`yr{;y$ z+`XYQ^wrQAp#@Zt%a6`F;Jrr|e0z83yd|N|<>wVry_S5iyl@TajgA8}Cjp{m?3Fxa z#5X4L4tZzN0e(1$A-)WU`4vv~>RMZ3wM{Jz?WdesUmL53X@n{;G#(3lE8_VOUp{i&#j6^N=w4293*94xN>?iov#utuAEgfH(XX-#b+Uk{>)FhTGjFIniA5{ zR(o-a`4!cR+nZty^h2t#boBPnDmq2d{xWP`V{^U9#NQ8z+EY_5rL49)^{0p76KQ6J zGMCjZZQ!3{ZL4i+_b{vT@wO&9sqYgSiG5jqPXiJ~g!9rS(maM1!b}*$0 z03J4QD7GlRn6!dttrQWVu>Pf})e~066tSwp;|+@V$LnBEhvM#ejaax5WDZWmd5zeu zpg5n`h+&r*#60XZIk`RTCQ;n>Y!VAwMHGiIQ4E_e6qD1xu*E`ATfLZvJrvM#Pl$Qg zD!dvlb=k0 zqS&D4=y=4j0q5i=1lxOr_+=1;9rz>>c^%}$HWfge$%Z)gq$utmD03h!?I`ZIBQ|X* z-mroWoFj7Vi&8XskQ|;(A>AAJRA z!^2Y(A}~$T;bBLeVpg;c51UF9wUT#u*jh5o$iGC5ANH_kW}kOmLzPokj2m2LDu0ejTY7o46codx?h#v&HC)Gjk(Wjs`qn+u}TS#?zvGZ0E0 zHEAY?R-v&QqZW?)^5~>L>$U0{o0{vR7uUw>8XMXTlleFlln)w|!v#5=hp)QY_>x9C zo6)p1o$j=<1AU{VHEQY^Z==}+xtAsuyts5`@m!LurlO*}(&*hB*huH<70)X!or65S zYooAuKH#lOqh5V$d{J`)Vs;2dJ*VRwPC~>~&3NZ`XHfJxmlFexaV!7-AJ9pPBG=Tg zqM^< zN%v2NO##xc{IftQ-3C|(=C1?uw1Wh}gfJa5j%qrY*B(Oa| zR+MAsebhl)+oQBABQrXliKRJ`)Xv_nJo z?0m^~UU4`7_F1O&4b8PH$)E~gjN{wd3P%AZ>t$?Vfiu!xBWX6mNH2A-E4r(k;{yJ9s#mAu< z{uRYDX4_#>jz+cfDUya97~~p{;=?$pvZTDGy3a%$iG0?m6?j%<@myq)b5tobv2sYab*)weD^mIN8tSxEv~*S1VlWe>B!Aq3 zgvq5R#r!E{G907cy%dh0Ab<9|thQq*j|BdiojBDNjbc=34sJxq9-4{3oboDiH#`(4 zbIqMoS~lC|MM}EFOi%Oyup|I9NmCzUC&LF#yJ)>`>i(}C4r|X~tZiRn*oBMdV7OY~ z(Uhfbsej01a(T#WMk?7(=1hsjGiY}KA^&J)XsD@WiO;~1RQ4cvWowPn_+*+SQQe|u zVNV(OI9YC&PAdEv>@g%alP@(vYORiKd^a$JUZV z=K&2`GCkiMU~6?|PH>iOjWlQ4qDA%YOX@kdra7rwgy)BOf=w=@GVICp-+HB4v~@*_ zE-jmh(?nayUA3Do?RRiH+m=Ik>`-q9M~EN|U^`sj36WnlFWDv0k!vcv`X-tkV-8>M zPs_m(6KhkNk-xI|T&U95y^+n2*)xLds(`3O82A)gurGzhh|$54%+?9$(9LNYQ*CebV~pbIU7dn^CSc9`kJ937^A55Go?lv{JLM z=Q9f=JoF^NOqX*kfct_+tL}zqLrbiErKvbit$5qhuFGV;C7`jpa^o3MO}B9CQmx-L zJ*&7BqKcsrc@$wBW=~4%XlrWepm{Ovuea1o&!FbQa0<3)8`A=2^#jCC2@Ga~F*6OI zb(^otf9L34($5TXnAKsP+{aqm%;o{f*ym6x$1lLgVpT!eOJ|jpld+q2DJw5C3yy#O zgkQ57rb!3p9#l(N9Mis8Gc6WmrbCXvpO~}1{g;mTt*xtTXu~4Mc10TD=7!C5BTNIo zHUE;iROQtDLd=F}h+XE?8{@;jb-*vZoM5iNC6!)aMQ-3oI=Xf}?O7Z}DE@Ipag(!c zgXj5YUQ7I`lKPSgf@NP1;w zR@Ob{_+2lL;4Soz>oeShW?pAj@b}4b-bNZ-Z{Q|0!JU3RvU!ijoX;caSvme0zsGaB z;Unq6H~su2oSyIUZ%US5&*>Mr>A_}0K>Oj|8cv^#JtE;x!94ok#Ayf9{;Qw1gmloI z?U(-)(^L|PPZON$r@zhVXSwN@B<0KIy{WjH9&ED&`5h~lk&~pejAQNgvr$6rv~bCf zVP_^E&tkm%MI9X!Y*-Xu60KddsJ&simv3k+)YP)LH3gvOn+*iC+RP4RTYM3=kce3- zXdWV_fVJ(lElWUXi%5-;oL)X{BrGFm>gBhz#v1ZzVtfkqY8n|V>xRbY;&$v-{ZFqv zVgNPMQ_7U9h+}$xkhbMht|KX?F%aaPZ^?F<@6On_PEii+(3%VOgX;wP2hQ7zfXtOk z`@-oiT^3%f0nbeNr99!K^A}PAo0*W9PbvRRwlPW6v?Uqx|CKgmap9Shd+GeJZ7q|b zUu<*DA7?+IFSL==NAy=inC6KbADTCgJWtNL1BOe}RuGo1{P{N-a{DSI1yLT#*5%g{ z2A)byUPS?cbjfcg+Zes`C;|R#p-(LnlHNnZ(1jmTaW75VM2YF-Z%ZRT?eF)IzmqV{ z6Xjhr9(T{XMlsj4mlKU5G5M}dQ$Fq4_bGoPVVWlx^iIM(dA6R7^`*Um64I5wiOc6^ zFztt}e%*fGBP?C{qs`#>kIR36^Gi7tHP?L3U!)pb%9775M2)b{zj2mf%Q!m9RtRJI1|B_$&FFhaX zb z{yPlHb4d!i$5%jh3`u3;SQhU;qj$CsPL2IUiS@Ry!I=BM95VU*j=gl6tY z7~U)Z|2F1-7{zh@ivB_W8Rl_xy=_0dee?-@7X~G|q@VVq{J`Z5kBe-wH;i!bm$M#+ zGJZ1CUopS}W-dv=8BAYEpSYyH7cgGLxabo!|L4zsc1uHv_R8{PH6n=M=<$88Ec+UK zN?$*_^`@E3-}^iSQC;Iyrxr0mpBtr=$Ov z`43_{G;18<-;bPGI(nRqnGQcV1AasX9A_G*<1;M-UYr4sWWdWa;58ZW^D^KIGvG@y z;P`S$x_T|ofUhDP?fX;iSZ19@`oB5@{kjbJH#6Yh$$)<^1O6kzA`M82dx*FX-4U1lGP_ZjW}_#6 z^7z6DDZ5+di81n;z3uc_=+|75Pp|VQPZ&SNe;7ouQ>UabboP6(`Q)TxuwZH47eo;=l7h)-L`i(a&&8;dTkZEE%|u5F6Z zzC7i$?>^8TX)RuR^lBHiw%fhbKF6{5*<`k_p_#Y+jOO{Z0EAmwTNaspS47O_w0Sgz z7y{$X_NQlbV`^*nv7%6-8@B{TV;;%VK@x*x5*;v)jX1A9-Zq{dq}0>@$`xnd1E**-HNBwx5=q+w-U+UpumA9DoT#+m$XdaB18-el}ZE3hT z$}f(znnx;l*TYmU<;_c&ely!Ybqh0Jl(Wcx#5k7o_?P+2PZiElGoL_M=!bE_7XAeP ztf54%4ahZ>S z{zQlV6##VM19L&)KZ3_k;5^h($nzo&K9=G_FK2gy-YvJ?p$8wKztO>6K0k5rlN|bO z8Svc>j;#aX|7iyND6WjuOX%e+Yv7m@3O>i7ck5N>;0X5ON9yQW?%>!05k5CKxLYqd zGZ*E$_%?^$t=AhF@M%2H6+09=bI(Xcnp|fqdbB;Ra>gOg@$@h9*E_hYhqVqq#-V@2 z!Cm^d7}s*{Q#i3Q*SiWYWBenBzboe%{Vf6HFQ9*sU(T8Y?#d%)N@`rrjs))Zm&+ag zZoB-}!LbD-<@V$C0r-q}aQt8jF5naBU+CqGKP}HW4!tYCdzK$`D(jRMrWZX^lDRq* zzL@b94u4mlw>tPlq7^yiOef)gG4qjyI^;jqp+A@x@VZ_nJ2gCEm+`*?hd`399%V(;CyL{$4IM(D+ z-+2!1@@a8!m(NuWKF#5ClY^h`;I}xq%l|$Hclp1?xY&cNfA=YziZIu^3cr%^j~xE4 z9rgobx-|bBgENy&)*y<|g=|QZ z{g68u2ZlMn@c*HM7diN24({6R_6+!h!IYUU@IR6Mh5s22?()Hl`?x?~O#edP?%-~H zZ^(e(=HPC*-*<4g+}+qrrVHgxr++E8*TLO#2lKiL^rId6W(RlqZ_I%I%)#AqyB)m5 z;s23?yYdX=^_G@L&ISVR@{zNFfV+I=IDBS0<>CtsxIjOP{zX6i0n!D#;-SyPSNA{yc{vOs_ zx1v9W>EBoQkGb*pD|{d~@*vi$@RxbpF$(`H+tnC_ADn9$%bA(NC&F?TD|%Un%vE>? z+w%g2U(W5-pzsg4UtFZ{RcxQD6#gjJ_p1s&jQM|4;eX_QdzZp*V_e=DkovYV{}&bg z_j%p2Q{hiB{TmAZZ?>y$h2O>a2MQl4otr;J9`jqX)HK5sek9xHu?k;>jC74s_;oDj zNeUm#?OUjD{LT+9**_O~9%A}46#Z{lo*4?C%H@_Sd=9tQISQAv+2jm)Dfcn17xw#b z3H~Iv;{yu6hvnI-@Xg%6UQqby+#athyqNpT9)%yu@sAXK7|WBz_9AkA(~9jKsPMIH z=f^7iOxDjS3ZKn#PE)wNyHcv~HQXQ1RXFyiamhY_$axU!ZMC95ip#xT;d$IHw<^4s z>-7VLzsmY~P~pF4JwL5*Ig`&EH9_)wIPKTFXsFC-j*x;cg+7vg^yzSZ&dg;mj4!o+n3SYx|en#QH=6*-NuWT;i{|fVYMd8m_GVgVTZ)JJh zeI(3pZ)f^$MZbgn!(SAh&F%Gp!e?^)6NSrupS*A;^8beE`m_E7f12w%SmE-#Sp1*R zv-sX{Mc>Q%IY!~Pvz;8T@c-g^ja7ID3Zkn(;kRcR`?FCZ?nQHS#RwMf06mGQ25JM4W8`#Nqc?7 z^ILBX7_+M;wJ$dg(@oy@;o5#o76^>^BxPGAUvsn+a9u@h^na`7o-u`4fy-%ROeeoU;u72EZf$Rh zuV6npTH*PYy?3g@8@XJ09wFu4&v==lpUHgASNNr@pGJj?UydvMk4%4+!Y^cfensK3 zew6WC2Ap?{y{e@fB+h3osW!t2VN>vlTA(aIV6|9_ke?_HdEH#U3tKxIHP#^S-R`&D<|;QTR`|U&wx{ z=;wQ^pPwrF;jEvZEBqlI*LEoU9>(8Lxajjw3KxBTtZ>n%tj|PF(dU6Y-U=@Il=-9J zqR*2Qz36j_!vD(S;7o(|Xb8G;SRc|Zm$UyrLgBKndZNNb zKNA%$`YBep=%-BKqM!2>F8XOyxacRYaM90I3de7=;aacoXW34^rEuxLKT^0n2imOg zeXRFiDEzzJ?|!B5TN(eo!bNX?QMl;mQ-$Bm^4mkNlI?pO(;dv^Nc++mm*yIwa49!m z;Zm+WG%Cqo%8e-c-*J4A!sqckQ|8?wPbuS7zu2zu zLs*^<75**m7ss(3iTpBuou}~sW`A;p!oSY`^e%;8#eV)-g@4L?_9%QD%Xtv*TZla0 zU_R3nek12^Qg}Pt&$ksmo8`Pm;lF15VTGT_^VRJNe~;zat?*ea&t8Rx7=Ksc%UKT} zD|{1=gMU}}7;djDenCO>vxfN$RQR{J{~oLG6PWL0g%4%>C{eihrE?T6_8e8XJr>UM zmMZ)imVbr9#m}!*_!g%Bs={~hy!j!8i=0m@{HJVJFDraK+ev^o7)76Na=Akkeg)GX zq429&o;-#3TDRn#pzvAD|73+1KmfYND|{d0(-i(R&mT$^E_Oao;bP}?3Ku(XQ@Ggq z8ikKw``n=LQ78@8*7Vq{4s4@{d&bAK0IaQTRcu&jN+t$m87< zh41J7eiq{}4=&PFbe6)Sw));Y#Yg5d?FyH1>KcW2upNFS1OKln{AMoqPQ^#c{i(w5 z=6XGmfzK}#zJvMiRD6X02MQm-{&~N{2R0$!cQ}T>>L+&cE-Q5m zBl29Ja2ek_6+WN+z;zk;e^ue~J-%-%KEnTAh0DD0afQFb`g~sD*RtMTQ}}6Yw|f+R zAotV${1r*jr|ADc#-UH7$@f8yaOh>v7$Qw_aICw>vYiw=e9%;)hf;;h_YfB=J~EEP z6uyz$eYL{}LkkZtUP96Toc-Qc9D1-=#rQ3XUf$>auA&z??^d{cpZ6KXN95nB@CB^@ zw;etrJBj7}S<#F9?>qF6U*2!{yP`jt{bcA+a7(@qDRSm2T)tm?EaPGi_se`w;RD#; z&QrM9Pp!iryySZvs}((dR~uKCLyvliJU1wO7t8Y<#Yg14SK+&u|6>YY#`tpzm-c#1 z;b9&}{=m5S8IfnN!sYwdpC~>e=fJ~Ewf+6WUvfV^h;iXBe2!4KJO`>$d_?~jI`q)L ze4k>OqQ8dwY22ZQ{)PW4h0FfzmldBGY;WICxXkx{pzyCiD7qd}IDTdx*LHvf^RMGq|s z7rouDaB1Ji7)QMzt9(yko1zbJfBB_DkM{kT?f(yo{!P}~UlqOR=VOJ-_ka8Ii`Swz z(a#|YmvL=^!k4l=oW;1bm++sZaQVJ)gW@CnI~D#ZJJ+rZd~Q&`^F3(T)CKgVfIMLt>2VN1LGt)i5E#RGL+Lu-6e{4M04|+u=SVRX~ z9_rOZ61yXbRlSi!yeCn!FVYq6>8jb6s0dN0H_}xx8b~Bjk!wD?is-YZC(^k!moQ7S z&Zik}Xx158VpuWy7f%}Yo%`}oglX1DBHSI>{My8yzIxT~j+{Xmx+5RI6?x)M2T_pn ztlvVq<7|mlJ4vb?d;Uh#J44u2w2-p*m{PimDk9Uu-8pM}C<7z&DYZA!xvJNTod$MY zMU9=kfp|W`+lm@dYYKKJgFO^PTbcZc@Qyur(-$O>uA=$Gen-yQZJfy?3sI-*39tgEJ*>c7w?nosBhailMd5b-3=NuaGt94bJ`gw%k%V(-xknZI`s zAvr;#AH>(pC;7S#h{>d-f*V+sgbuY42}YX3#p!DYd;Vd)wZS0Zm$AK0&Qi^1s{O zR-FGyd)vNZD~C!siY}V(R*n+?m)qNlldRkhV@U8DovXS%)62ST*Unk<_NV*zlk__y zT^^fus`H2>YPRp$Km#Qafe%`Fd(PTo+s}bO5!C)+VY&9jK5k-1(oLk~U_Y>fZPcc* zU09RqszD-pBqf?p$4-)d06C?r>@Z!05!<m_$teoV9N!-Dd@5 zppj!$j~9a%gYTt8lRH_0Rh#eR*}tagcRi+Nef?|?>l^9+gr5a@s-Fdt)Gx(yAuQ<^ zEhqg>O4(tgum-fFtD+ILPnZwbj8xAMkzM%8O{TdFsP5c=wji7Kf0aFbES45 zr-A-&wGNG)ZO%?LH;Z#1waNw~uPgt~|()Z1xxyoEAt;SNY) zW1n$wLIei0a}R!<#|OyYODeRsbI+x2Y9hR4Z-{7nDamrS)^8`(@!dWf%E{q{M7j%M zszf6E0g1fRiw!1#2x@kjzT3HKmlqpL5YZV6+7cgXV>LU`^YA;lA*4qIOCAJ&ZbI4$i&a4sz&D1Cy5hT80o5PB*u+I-)(YJzxv|oHnCO10Fb0C z6oV|_My1stkxF47<#=ckffG^boHbY30d5yb-AnZJPjx{Uy*U2oy$uA~3jUweV&|$4 zy!c^8rCoEOJ+ho%MiSe)U;4<*p1OUrDj>5Wy~lS%wuO5zd~FMxA1$OjJFV;Q-dj!) zavI?tVo3k+-mie!(X<N9U8+Se+J#>Txz1G`)>YAV7G0L7lGp&!iZ;y*B) zl2c8RplCiMuy|^}rru!OotaFG^h<<9Bn?}X#FB$KrR5qD)W!;Z!@K+UKZs&{737f$ zsCseeiK^hCrh7}cuGEmGu7$MY>eiLYBEtaX5q@2Pp{_l9`xC34y@RQuJzo5Q)Zz+! zjVDzs%HKPOiX|C*6>p{uS}FEWBcEvoN7c#Vp?<4s6yHrNN2BMvA&Wmp7NazCzcG{q z3q`J864%C1Eg^#wj{k9QJtvv@)yaMYDwr1TjUVA7;4|5c`C;lacEyhlfg&km?ALxW z7uiQnGYW{DMlxScBQ-NXb-qYWQ{2BJr>Wo<$l0BUzfCfT-B3gJ!npR1Ca?#J>|FJ> z?Hx&rfuem|u{QD|>R~JY81g@ko7p}gz4bEzV@2IxBHV}4W?&U|?#t~myVsF*b3ff| zI#1%4)M>$3ENZZcb$Ok=*|C>QryB4eenxC>zf_aWeLDQ<*#8i>EBCD@2_lI{S5QHb zb>Y?UBoNB4Rix{tWZKh@WA7}Lp!-P5>XRqyOC77XyVOmCRyTurB$190XSE_F9=(jR zcCE!7i=J&^2-w`=ut7}VFz zwam%ar!@5bxZBXrP($a&CewX?d^n5N**hpU$_XF-5S8U^zLRds9FZ-C2}Ms=QQNwT z078k1HY?G#?wheXhl?_fI@i)sSARWcO)=G@`-gw08+g-VKauO}|6W28k6wV9u3Nj1 zJ~nTZqD4uZ5b4|!6391!$TpJ+d?V}DA%E9eFyp2dZ4iAfSCaL!cR<9N^}i&^KV6#b zxTyw8D(UT7jg92a-ukBlVq(GWp~blnajPHbgEdcoAo za9MXPQV^70FWgc)b)FgajO!|*FpXCQl!;od8!BH>3Q- zXIuA1dJcwgm+5Kbb7G`hzgdtu#em7XHbR?;2hbN1H<^yrwH8=cQ9@Dz6@G32XZ11In|N4Y@(8zwak34G}%-S|$-evB@iY6qMm3dfk6VgoMFvmBD zqZ!ur+=5E59*j~F71Xa-40iEve?Yl8=j~XM32(nb!l9^O6dtUQctuGlv32z?C7P%x zNG6PeO_8t%`wYo%SLAkX4Uh%8O@HOS3L5gL3AdB4q$b=#ABmeDL1bHa7uA3a#Sm>mygvs)iaSXUzrVeF)$#$&cEIBXwWMOd}^%dKEkN6*}Sa0S{8my}eN+ z(0-Yf45mGGYX@h-V>F$%ob#P%(#RtVG1d*eaM41cXLsUhv~T!P+7>Vl3GZ*D8to=D zIr|;%Vnx(-bJo0rgmtE`Lg62O2<@i!xx@cT7>_yRN#Li%KRudG217wwBzDuVprtNI zQxXRq*Gp)!%-51-ZYyFB%+%6{W291ns1LvMI7id=VOm)mS~K^eKKv*2VbkJN*T8{+ zQA39f${Kp)&;tVp1#)T33?5J4a66MAI&Fc2A$sZUP%mrfX@jN>Dy6q3`vn4}!vYlO zKf)^=Hjb8k19HsQ;zGj$g9d>Li3bevvrM7I_rPI+tf9%&LC67SgAa4^3`yqkyrGAs zl_9GGKhvg6PPNY@uFjGiBqUwjlgPC2w(qRyRzBytzaP-h5 zL!=&-?Fce_Gzotcp@;io8;(b?9*BkK9m&--DM#g#v=Hya!BAzYU6QT0jr0ZoYVPj+Fq;8XmBlzQg7uuDIV zYs?BL;2LwZkX6Xh@x}sa?KmN+OP3k_!oJw;S%Xin${d(-ng2O8YtjaB~Ii z%T2+cS)FEO_rqDQ!H|gs1Jp05zu4cm2xgnt#LPQDSyP&jV1MAkAlcX81qU1a3Vu|! zA8vRvr9Vjd7?&(NoNC9?mq2oevZ{FeR=j~vUsf8GOx zn5+X%Kq569of{E4^AM`7$sRfjK@Jxo9P$Q*dI&PPLd6K0T%$wfcq!NBs({2CKF8F? z;+4QdHe3ySuno@#Zoi8jIuGH4Eq?xy#B#Vdcyws)PbfrPjIuYJ;0G5c(Irra*Y9?^ zJwfTFnkTZ9jgX90%nf42Uyrg(@PI*h`@+`$fFXy_aAzbqU?_qd&OsRU-%X_E1uWwi1gw~# z)W~Rw&qiq>5SKsY6IVFg&N199aU~Py4LtV%GGYtPcZe4_#7673Wd@!PTeGb(@B)N~ zL;l)hd?t%b^&rNQvwW~|dQ#>l$Q<$pw+)VXsSTXMFNr=oZcPeM4`;!})RHoO#)=W-i0 zgPpO1LDjt!92EK-seyrn9cY*h4h=qL48@EfgY*7O$u>ALjC{F)vxM|O6EYea6oO2H zLda-LYvbS}uA{J#VDRza&f$~M`>gs0k3)gi1}xF|FB8%FfOk+}PzYI(#T!!cP5K-Z zx}EO1frsdRpt;>dL-K*v=naLw_~^Ddv^?p$`o(qS?s91Ky!xLN@Z~ z0A$Uzk;ewW$cNj=<0dlNMxHQaQ*31GfF{bbg?Vos0MWPmF|gQ?65Hj+@XgB}KZcTf zQ(~Wahg^J-H*~8hdUZgGJC{7?dOtRcrV|hPu{X(OZww0MX;i=_KL%0mO^IzuiS0;< z?eb$MP@TG79e!*#$$4$IZ@nKw zQ*HNS$VWf)HYkK|JsNwOGNcq44y{|{4LSR()Z*5hhRjBFtvL;uV;a&}(~!B)^Jp6` zL-^!F>B!z8<=|Yvwlxdf!O9y_g>h<72tQJr8_1)(H8T@JZc2lGj3|*I=b~+lDD(eD zELfBU5HNJ;#VE%(nJvQoD){NcvWH&(35|`z!R`ukx8Z;Z2hBap+_TNSpSkxp_W|Z^ z->E*pga?}YAafsV?nBIdsJZ8uyM5RCKodU5+=rR_!RCI5xgToohnf3ub3feNk1+Qm z&HX5IKib^wd)j#>Ji^>Zn)`9)e!RJlGWQeA{X}ygZSG^teXO~kZ0@I+d%n5bH@yo? zxX|3koBITFpJ?u8t8Kf~P5GoZla+Z z@Vjf&ME9;Hn=$0}{=d{X)(nUKtRIz5Qaprjcm7YLV18S=h>x-Gp-;h0+ThRe+xg~o z=Fre@2k?XTwujyxfPHf0y8(0+K3{L>)5jB)$x<|QcVL~L<(|@^v zTu#FV``C8^My*1Iewrr{(<3DU$2Nt*>HfC>Y;3>%!jg_G9Suz%6ur> zDUJCTIU7GexrGbboSj9nU49Jyt2-qoZhdn$(t1U~FIJMUMq3Mq z-kuGYXxZQ4N`8kc`5mt0ces*Mo}}b=xRT%DO8(vKlO4&wYck33^j(u{r%3nf9+7Uv z&}aMKMjE%$J=fpS>vR1by*}69(d%>l9lcVXq;${qcl7#Pe@Cy+_pfoJ`=y~1>0apn z0;S2|`9goVThXhHeISzW`~eAT^qM#H(E#{c$saR@=SR?a*a{yDK)zgZ-!Stdh_yF# zW#C=PIVkio-E#wI;se2oQ!fqRmoo;1@OuimffJBwZm1f;Fn!BrRRGK5L7_7ZVL1rR zjR|3|mT+UB)(|c+geyR3ZcGUC7!-PqWIi%)=;rLLlx}Nf!zmH2l}+Kkwb``paN>df z5)7F>POM(&KZM3`%gTmRBFxIBFsm0#!+@1t*fWXNNjFfaMuhoKqMvUrW6j zD}`X*Tf~p_NLm;H4Rd%T6dkfoC3qalBs~!l9Mzw`yJ_i1L06u46m9|e$y7w_6}YvW zNRLJ&(2Kqh+|YOo9gRmZBm_4sjKS>J_*ZKN4X|2u?&WxFK>(L-R5(I1yq8Hx!LP28qp2i7gx%Th`{MHIih1raY#i zX^ZO0)kSf^T$EFA)`kbKNZ~&JxKzPC?@PojRUC6@N(xy@dL!-Bn958F*d|FK^#Zp} zpx-ZWQ~?=MM7sBi6n>GESjEWJ=6YWlqA1u$a6|nGrre2A;PDcW&lFDoP|jOZa<$2Cf{hz!|{Ss17ZpC8Mt+{!GhD%Bv~_# zm}!(`kk7!a_?du_?OxFAc?35!+a^EzcA^MwSjx4p&XD;z&RoM5Vl&T^%(incOe50) z1w{|xboVB6na`F!dS{5y7Se)*&XaNgyge>gE0poL}iu@V4wad?N zF~rT?Lmh<+?c3y6I93H^j6S|kUXm^|`vA>|WHV-x=7|0 zRaqPEy;M@qB>}TG{OHmGW95|rQ^~NG` z0;PGuuVreYHAGT)aUm$Us~288J{emmZT!Pb44xwfd8UjX3I`+e>x8>98)*R=;f8u+ zku6CqlrSS@Vz<7z-~k!ib#z z+W<{Aeb-~bahQu~u<&ZikOWg0dL_gm=xrrlfxxFjhtS>B2=R{gx^eNArWM|}ct`uV zrk1+qczr`kWZa^rScgTLn-+~*Qdc)_#gs|WNfS?LZ>Vpqjh)im)DmAYZesq#{K@GV z&|$jXxMeM|ag9qBcZ{3W6l;tx8rRZV-*8HEymnlDLtDqV_;Sfg!Bg7Wo0iwcNQ{3r z(?3B;74CP>{6N5v#9nSWIE^#6(U9 z5HsG;+)#&bKl-tZSR+msc5<~WS#gRv-kJz#u|pY~S{Ao*&ZZ?+04j(QYU^+^vrVF! zqbY2r_;UKB?Ii;1T9+*|G}vhI4xo(o%KA7E*nL~DWY~mIAI8?v*z2I*G2Zv6My%&rU)^gBQ!A${s`%&=h!)AxZo%ia3!r8mWUlY1J zG%_@zaLrr}gpPavywKg}ZCFtF@P_k3^btC2!AcNV_?e(0;g_F;G5eGgG?35|H9F!YK`Ac&oefK7Cii&_d{ns5*iV#I+(@ z=!VenSARVxt95hMA))+h;#pd6JK==9(WA%ebGh?Ij~RnZg@uOr3)07s3mGxGv9_hYx#5&E7dO`~>Bu9N zHS?k~=9E{Jmd(n$ERQ4M5+d$PnMcF!_OAe?tPuISZltEJl|xRpgKfLnp+puHb+}q>KdXr zuie8`#Yt~&ZEcIzH8<3@#M?YfOp*l}a?BMMCV|vJ4uqnZJNS_v zlg3VjYHB@Hw7IDx=HdA+9ja~}jDaXOp6@2XW${?UifD&jpPRzq7%M4;3Hu{|09(L>~9&1|G&`uS?z8poZWTZqJ zr7Dsur(|r~P_ik=!+t15jJ=^2*emo|Q5;*YJ}-)6qDgUPMgTV22|&#{JZxT41gtwe z?59(N>)7F8$C%<)tPT%bc@(umcX-&2qbM`(@bGkw;x@g*!`41UjW#+wOxTdf)a1C( zw5edMy`h1mz;!bH+n#I2B!l7hUuMScNBsb~o$%b5rE|hwb8E|zJhF0+pwbcoI%-iU z+lnKv>6=7UQ&QnAX{&9Ai*Y1`FyIj>E+a0{>ID_y=-lG@Ao2B+44bUbs3|vGSzI=Y zN^T-u)YGJ(HP*CvCF!`fK6-I&tgf-4-IPQI+aUqYS3a`}2y4ms8B}dXd0AOycxFvi zxCAnVr`J?1FoBB7^6K)k@~WDOit@^8sysOt5D-)`!|-NSR=3g0>CwvY-12#0FW!Qb zhI*r`mWCBEr^`8NfUiMC$d$$79p1$kS!?jx+FR=yIyzVv9j4IvCEn6E~P)OKa3KF22LF#$yDJx7E`e%>Z7*vc*l!4N-cCiOLn1lvI|L zR~OGKE}a8XzXMXZb!jwxwdaAT=~B_u3aVMEe?0yv67ayk<@>o#nMGt~Y8Diz=Q`T}thM^or67 zY7o~o5h`>%@`6wxG6k!M(yDOfywVw#%bfD^3Imsgt4qqyEraDRtL<3oIP+BRPaJE? zW|x7~bWA&V5IVCe8lD#}s|L5K>dJ8O-01W<9#30No7-mMZ=Yq<&{;)h|)@;qATl# z$elG(w=&g+S(KJhA8`$!&nQo}97kT0B~o5hT|+&qct*skz`6;xUfWB#3br|;G&PFG zTNat7jYeB9ZlS*HyW$q#SgaB&%I6pZ6_q4AVQCq)Ty=B?>8{cderCC6WFyZYj)FLu z?q58eI=Jord7)|Ga6i&n;HpVmw` zz2@4E7_yV3EwpG_0@G@VFGD}At*>u4>MFM#fNaRBudJMmo|@1&GV~-dJTs)g?aeH; z3bS?-gC{dXz19A#;?gn`BEJ%zTT#6Lr7fbyW)Pi$*t(;CU1P10#WZqsX;X8vp{<@@ zJ)NC%Svee{X~0NvWfcin*Vsf2LX3P@>KPSLh%l#kfpJlFt<9||CY?0LGNTq9p8W<-BFgUr)hwy(phjL#G<%rLD>u#{^F*FX6tQfBs61Wd4(;nY<_7uNTHnB z;c!Lq95~_jMUBz+)>h-6!lh;Nh~2ERn!Fi#X4fHad_m#(f(eBa@o8X!F1$VXxsgDESYUSp>M!re^zxv8UMZe*Io z$#*>!wkZC%KmtH^PKr*-5ALDST5Y|OShLeRN$O3NHlnkf{Q6i=rqR9cZM zD%rTJD#?3}YiwQCFm6SC-6da&XWD`>H7lM2whO2$G|(zW%r&{*z`DfFqU_AeW|}c0 zY$isc4Z9*lt;FS!v0@DNIoj@E#wv2rs9tz}X%%}@wf^33~5QYsv09yW%wMgrQu>bGGpdodN>NAZo$qh z><>zg=FLPpxmt}zjaPsa72(Rc{w&iUg8bE_yZlOq+19H{N-NR6vh2a|$eo?d+LSBn zVE9*Kbnwd}dD!$Y%#c|r)nFhR*fc|^89%8k>guFjY!XmuX0qatC%cCoE+Hod z8)+&#Sj#ZMQ%q6_S!P9XW!P7Voi@%28~vA-(I86$MZBY-ohEgrY%>S7z9wauBbm&C z)F>G>YF;+%yi$>j+SzmMAFI^i*UmU6IZ*Jz$b+BuqV+ltuN3(t3&}IET6WImS4l>!aPiEfJ0e!_h1lGo zWlk}5H1d>ABNz{Z0?#e4oNWe~)_961j<@vD1j$OO!y2FRncju?;@Wt#u{tsr>dsZ3 zXT%HMP)u zqqc4-%`Rj`K@DbxAu7bKggIb}wZo#B&f1_^Dq-p5E7Y#fFv63ou(KFz6{rMz0?fX& zH?_-PNM>?TUCDOI<3wlHl+p5_yet}ZIKXjY3f@G!bH1M=#bT2{%^0i9G`YStzNopu zRUK{h!nILBXdN=LX38!T336)eH5Va|>G-DFCWKnkG7wW|r!8zBr6kyOTZ|^dR01)^ z+!3Oai<}#tYeF>eCf&TXbaaR)?Gd)O$6K6=!f95crld`JejjUXCl{W&o9KD7X3RJ( zZ!`_lWB!Rznl=jPiLbc=msEOz6}f>U2M-9*o89Kwr+K8!s%zb>A|qi|8-6;OGz*F(?8?%`6=mD ze)>^%ugSwhSYQ6-N%>Ca^z+>GV2z*u0#3))sh>Y_g$BJtTZqj}oCfUe;I;WdA1SCD{ zF~5EnaQcpv`akQZU&iUTx%`8-_~qZq=`&N(i~aORIDJS8|B&JD<#()H7OP!EpRsoP z*(jm*hUVIQ+P{u@`DV71zo?^wf(?t}OQN-l7GZspZ)hxJ274EvM~@9e(P}e0lx^`v zEw#&N$?8%QXdcp~fVJ(lElWUXiy+Cod^~W&c4I#63^wGG3p<5YSv0I$W(|$e#qGo# zy7&)VdBg*1gX?jxB97=SRk$$sI+7w9LwaMArP@gQ=D6tn0#lA`*wRxEbDh9AHzA|+ z<&X?pxwtrY|vh>^Y?I-kyHWK-zUht`!Cvr?X4R_CrD8*>n3Zh9@{&v$D<&A#Zekfa)UrQKx zDm8iQ&mfSl8LGfs3;XvL3Mmqk_VSsQIWO6PkUq0`nv~>A@Txm10`T86rpL{;d`F#QoyutZ3F8KuCK>=Xe z{&sQxovQt${*oVKVmkd5ZL$0}4x z&i}IX_N&LXAEJ$P`Si3dZTY+EZT>Z?a=Ls=)%Om%Z13IueN#|gdM;UMB>}w>f|+LF z{gpIVR-e(x5@q?dPiCTrj@0%^d7_+z_5v>P$&8;!pZq0lgNS4$jEjEdvzqZ-L!H$B zQi_8=9=hW)b9?$+NB_WIX2xbtPuPzczZXu3E;E;>PuL&m2Mh&Dy5g$*k;1^2Vt}QK z-HG=Jg@F&`e%WeL$u=n;@Rf|4xjdzfWBg;r?_&B=#&6?_30}weEEqOjX3kEZS1^uu z#Bmkc5ASBi89)GW|MU0Gc^CrQ_Fdz~?Zt=ZvHHB% z81J#L@#P49!1yl4g%6@x9vd5{$w!v`cC_ve}oGl{^m>;v^&c zFfeVVGCZbAn_`{@rA^@%FPt<-uP!rwVZtFad)-c4JwI?#(mb7aQd6F+I=JlIr`dMR zpFHu@Q(fu$Y;rq%(rke{sp`RvlVYD@IRNib_t^x_pM2_+skD2VCSlTqDd`g?kDrhs zVZuaHvBq|PGk00-QhJ4jo+Ep;i|G9rx88kTpl}~H(55Usq}A`6dKb4h(c9J7@~5Zb z^gzvjKtYgs$g`|r8DKo*pvN$==;GR@X3+B!9cTp4$oTyr`_x+A?4g}*v-1xkyg_B& z<8pME^1RAEy`WUv`I9;Em@kFBQ206M2^}fLM5FR1LXweFEODauPwAO+T@&qr(_S{o zOBKYsuTUhHY?>Bss2Ml9XjnIEvd`#O$#C7t;~Hi>r2>-|gV8K0k7BmwqTu?R0w`kpVw}ambG?J(+(O zD4deab*jQ;oqd|aA8P}t*HsSg%6Y$oyLx!q!CiZJ!NJ{j{4L{{Nu$oPuK38IKi!dM zzk|E-gm^*<9@rWa`Q_|f;MnpK{0xWQmA~G>-Ex;XxGVo%4qoW+e}Qr7@3L-r)uBJj zq5sIiiyZvALn%TR(&7mHqt{i${o7$~}VDce+3BV;pjx>d=4U;BI|$kFWxO z-o=l~fS>8$Zu{QOxL;q^!`&LU#d-HB{0_!{=J0p*F!aczoUZ=Qaqv?)K_QS{V3!1p9?1ztE!1X#$;p5p3W&cge9mZP{ z&5FKcumvts_zg^dnZlptN`Fn^16iMUD!hXm@P`VoVfi0ZcmeO1y{7OYTIb?=$A0*F zn8k{FSK;#f;O`2rV)+kXJ&At$vz$jMd<)m>M1_Bk<(#1KZr0~n3jY$zKU?8g7vnlt z;p3PO_62c?oPS|EZ&mncwl|#jeM!-qw8v4LF8Ed4E~6EG7t1q2 z;j38>XDPgn zDf-pS=R$>VXZd3aAI9=rq3}(t|LYWPf2q>*?o{|Zmh(P^pU!%DOyOVQa-UK77B2S{ zg%4)`@CSvLaJ~Mb@C4HjvfdEpXT^jg%>dW6or4rdY-9poC1fdTH)uhJc|^5HP@$2;kPrrJt!qvukoz6 zuPgdSF86y1pTO}46n+uYKdEs1JT|Tu6@DM<`Avo6ONzMutnm9d{;9&lGVXIdq+PNY zKTP4zuzp4<{6mgUQ1~Y-PqD(sa=pqG{wC|;zZ8BD(=S!{t+u+}N`(j699{3O=zs|tUD>-ATKZ{~78QTUT=Zzpm)NV~ki@}H@3ZkPEA zKa=&aRN<$xpSeik+u46!tnhtYuT=_vl*{c@IKEwsE1~ddT+gp4Tpr2ar0_kgw{IwX zEX({R;mr*XtpL%l!Lsg^Ng>!Yizbd?p?d?N_%a5phs_Eth&4!gaeLG%9KRueYl*@)a(tP>-(xvD z6#h5vUn>=U73=v5h3Byz)+&4j_s1@Ux3mA*pzyyjpRXyL9@d-dn+m^@{lo1F53?S= zukgW4|6_%3Vmo|5;ZNFPy@wT!v(<4uq42@XXPd%XxV@fN_${pemlb{}$A6>ntGV1a z72ajV@pda*`olhj7jwJ3uke>y&z~y%9k#=voKO1oDsC_7Pl9K0{v#CqZ`l6x6h52F zJwf5?*&m*)@E18gUg7+hz?-7*-!uO+6~2P?S)%ZPEa%w@{{i=l3WZC3<|+K=tcME} zzJ>L+Na5!)-l%Xq8^G0~@V~KL#T34g<-A1U=UO(N?DI)`)w3RMRP=vkJ=~)3Uornp z3cr-)k#Sh~k7U2`BSrra$7Mb%^nc=Ze^AlOI^i*eFJyV1Qg|NA|BS*zJT8bGNx7e} ze|TNdpU?gJj|#tv_4%H{S8{##D||W%qH8dJO1VGfa*t5>a!c-wQuvn`AFps(AD*Rf zS>Mf3_y8_BmZ@J6OTN#QTD z9;Pb%Jnml+h1at^S1Eh};|moo`dp@P(WlHiq+X)WYZSfc^G1b>KEJJS(dRu17kxgg z@Gy^$zfkxZ?$@s>{MX#?WV{mjZ({%duA)yc{<*?MKZCd&;UoGPu5i)MD20oD#w%R( zbC$wIKXVi=`dOgxGuf_|DEtl9LtNovpPdT-9{Yg}3crctn-pHbcJ)Jr&tm*Rg^S*P zu5i)MOA7z4w4=g5R6r;3O|eWS*7s1 zSfA%>oaeT@Uc9;T&?ieIR0gYKgIg|s=~j*?YL3lvzh<5 z6#jLNe^=q>vL1e<@B>-?`xTzg`rNGW)42VfQMkzcio&J;{z2g)$6plQ!g`SXHfeWh zUphz8T!P=n{c0%V=>FVo zd>>;dzoabfCGs4laFJ&gWBdE2 z!iTUv?_yk+d#}Rfdp?gVJ|fQ^g-f};3Lne%nZ@rVO1Z*+kiw;39l^M?qm)~za4EM| z;Xh=*-JF4cOyOd$UsZfAbBg>z|6RpL+Vx4rX9zpvUuK|xMd9*(>~6(J^pL|F zBcdO%hhr4}7TfJ8#zlVNe~QB8`z=!ypP}rBi!#th6fWP(s#1J#L^rMrGte(q_{m)V zD-|D^f38Q@9PRK-y58x_(*-fr0_QO0~aa& z!e^zz<@<-%Dn7#hPKEDeyZuQ9J`X8ezW23V@sWApPK8%+e|a+lpFb*Gz9%N{6^ovQ zf9|2M#^iUqkL37pg`dUo5&S89#D2yr{5i|kJ45jidBO^p@26EOJ|gELg-f~Z3dcEX zxGu@S|0;#c_uMupKEnSy3LkCRd-r7E^HYV(``$lSe1!k66)yW8yA>|>_MyVXkM-mC zx20XApXM@-{^GvBeYk_8KR&?kbB|E?e#XyH{CD$wV1c5S`qnC3zF*y@_(=O+uW)&< z;BJMB-kwwV7T));hrT8E4MY$2)KhEc(1Upam_EW>KhfLKJa0UQaq%-E{{n@}_ZzQP zd@kX6*H<&p-=c8&-tzYqAF1zy3YU64>F`0ldQdmI-ct0#*>C^Jp+~z*x$h}l-hU1_ z@8O?J^dirJ3jYJ^El=TMp9KmR`KK{1_PLA7z;(8w@6Yp@3l#nl&j%VEJ`5Q?7b*H# z2Bq;=(Q|WoS1bBgr5zPLFS|Ukcd;LlQ}zSIez;iw7Z*U!Qvs7C;eQsF@-_cFE(q#k zl^LW+;j%BWP~kUoe6_-5UB5};vd-P2@BwUZyA&?#JL!KSr>ukI`z3!f=A66?|{O2Zxi~roB zaPdp@OI;1M%ko>t<=Lxn;-m?uPMKJEYC&Ee{n2Ibg#`tZCr{4Hn>1m5 z%wT{Ukm?wqZ+<0X1ju!T1U#?E1dHf=*2BD-NMd&+v8p$ci1#FF_C>nFJzX{X5)~l| z^+viXMgxf?Dss(dR}p>I^h7$h<`QOU*7-EU4b3`3OAISU|Kdr*zH?t5is(kMkwmyV zviY@%KYjJ8-yJ!FGIU2iek=0CpAMoRzAC;G_7$P>G=BUvPUS5YVu2={b`KMPR8wD8-Py-9`jq}0LH zF6j@tG5R!`Hd@2cA#t!bX5)~qC6WfqEDlAQlnA2rRm%X8rwkY3@sSjM%Y#~ z1;U#A+lnfj@O&p6Nrn+(^3~f-M509tlSxI565h7@R}_SPQO35_JCHz^DRJHUyCj%M z22;>`g<#!!w4}+FNCs2TEkdxZsEC3f?(L$ZbvQU2>sR}GhWr3h<}i%>FHecfw%JThmgD(-$ZfP0yBjc6(qI}qNX4L z5)}m&8s6DEIA`sZNs>|MfNQtJ^1H$xxQ0d0k*4&nT;wFn$u*X2u)Q^0z$myXBAr0F zH=j;i|9KXs4|UaikXXNo@|g}|D_Rxl+&7wPx|7P-86k~4hMA-&g9_tnuT5L+on1u* zox6f-x5Sz3>hxq(p@osPTXNPsO6jH~xC`qZsARZ~qS2A5TZK*H3)plOksa4iuF8e< zPpt%%feA&850WHw0r(-LkjcF@PIZb8hQz{CGDqI6dDhRB? zV4YhRMyBqFK_eDqqc-tmXGdBdwMT3`6BdB0RuNGd_3TQjW^Z7(-@kv)+@!*`7?uB@QP_9?=L)0xSDD&$%`Y-~AZ2xiU?snejM-{Z5*0S(-_H7+X5DDI z*N>oaw)ijTUYpY@58a@V{)bcH6t1MOSe+!1Vfjg7eMswLJDkA`K_;BEAtT>59xghc z8hyU+acK-&WrkJiU`Z#=dRb2S7-gfz&~JTqBHY`#s&{{EFr2T2oY6iz9^5<0dRLDo z1dj8*_hU0AblWk(lGJ>b$YtWa!M)$`g{vUpw$oH-OQPlx5@ic@?l#O=I#)ds5GVP5 zTD_9g7!YYd61opE(7~Aol0Nst3}nJCXYIp80lh@lMcT|KH3b@%Z1|Vr?DpKkM192g zJQM#-#35C+IcuRd)=Ovapqw=eD6<=%NQE0mz z^Zr63bt3$MB|>x1@Jj{mBLQsaEngI}N6AH)RYlkO?Ho+n+#am!Oj$GmSdZ2~B;t?~ zgyF$>f2YBYF?3eD+qGu*qF;AYhoNCUKG}u~M&TLFfetiSk$RBGjI%>xJlzs z-=OKK8QhTFj$b?Iv&RT*Y-#P5l}A|S)RVEp>f6p=5TRL|tz>LyXKzldth0AO&f2SN zN_W?_tj?az3kgcv9qHhbWD#sm0Fv{=Jzo(f(k45S(;muy#y`lvx6;nZ@GFO^_M+M^ z>KUoR@Fbqit~ZfObM}-rFs>;9|Hq9!Aa*QTej)%k#;&<~*!6rL_!)K_p? zuXyniTLu|Z5sb+eL36Fd*44i(LYkdolI;;mp0T$BZCORRWFVbe1GJ2A<QnBL*EcOM~7ma`TQMtmd}$T5tN1!K^XDc?02 z$_5o1YeYs3TV`Tw=UX3xH!H(*2|K5xy7ie;emQLc)C$4k`q^wR~CZZ#Ew`S@of>E zTd7ppd2q={C?Z>D$a`rcfmfBi1hr8TF{SoSHXBzGJ0FzDo^K#L-+|=$;=>JUJoa96 zI;=OTPweeywiGz?mHT#?e)8yO^1P9*wfL}Jo_sCqcxO5t8_I}uQXBL8Y0jELTAeXF z>b|@pxtFB4mlqokQked!MW>m}(zV}ASD2wBU1PHQU{_JZw~`<=>0JgiCWW-bi({Th zY)^!rx^mT17~(D;uq|u?Tp$cOXH7rbxgo)5wBda;oF&4qcdmNfUqJV!k!0K2Hc}92 z%-gnh1&4_5T_ncpuJBVNS0a4vw(urUMAoe>fKn6T^)$3@JQz?{cw>YbXnB7Mt*4eS zbcyf|itgA}6e6KOLqYRBA+orQh*}%nL91SBezQ#5MW1AU;qI=Q*AuxZ?G{-@hlPE9_d`QeSbX8lbX)n?AX(LmvpXrDiA-JSdkiyP10v5m0=2#y(3c+yK0__ zbj_vu_bn(nlgf^L9c6nti4CMvzkHf2VdCM&xA<|YRQSP!S&=-520EFh24YZVn!_eX z^Tv>z$lbe0G|$rB=TcOD#DPIvnG)O)8O^a<4k2-w&6#n%0pPrnhTQj=#v=9 z{)CZiPf0QX^sA{l;E!Mb-SaI|1DJ9}1uCcQxQ9Ucr}esZQxA4kL@eF>sar4OzBr!t zU;B=H+l@e(4YJ&7C{tWg9=b?9@`CKO-56b*>LK1R%<%h;c$wElP{uA znR);sJ2TL59?XDY@b9}>@d}o&|L<*9q}$7oR>tp*^zDZ`BQhXDy)tW!4>sy1lRNA~ zQiQXWaOJ*DWPgcAn=wwT3$NY`Q!;F2Ua@WMWt0XuvaZH#sCbdY|3}`N$5&NdedFhx zdqWN+Kp-F}4wq2|NeCby2nItW5i$rtz$t{}lB9+tCN~T!ibh*wv^BN1)(NZwbU^K- zKpY~q0v0O{6|6&f`Upa`Emc%(ZGG2Td#!W#UF7!Z=Xu}H@1NiKBy-5_n~li@#J&U4+B0~z8Jcn;RRBzpGr zd{Rp3FXur=0tt#xp!obNVMv8toON9=e*PTv6O5NIejoV(0GtijEwLorePX%6#007W z6Bh9Dx6lCD?W_i-EV;?qoihPz$c;OD_Efdmz1z65XZ?a1>D+~l!C@V+eM&tF&U^Sn9S=Rjtz1xSrP;d z@oefC(mlU={m4@wv#C!;K$^IB%C>3zB6wYnpCCZN&KJQp!A4O8n2iZt_afNTLVMzD z2X+&AB>vlprf}q3z)Z8;d@|@$*!*Xj#=^|3%WPsozknTT5}Kw-U^vixxpC-!no`9E zhyeC<%EA(6a&ep*c3cquw|YHN7@wRKv?pm@TeU|9QwE$ZpgT`!OKGF|IOYY$ba|JM zwY>*zIs2=ro4eMW&lQ;8zD#V~)CES#|2ht9u@^;? zmU3se!PM0#_Kgq62OJ87gWV9OvkEyLPISQ}dH=N+1bnGewn)v{d%|{TV8_M@oz%MS z4X5vhuGW=rxHrKPVmVA3ahiC;3kRSom(IQ{VXpzEwk;qe>=eN48>UUL?-m;wgi~eu zFs0kJKdQ%$sY%GtLFR&nry0%=gB`0Da9vm?#C(XI8pQC}vriC%O2jA)YMk-x8Bhmk zR%+3$=z>061Ag&1Qe(Qkwz}&*96fOt0(P9t!9Io$Ll`_8(!<2Ot+a+q!o4IP!)Dj( zC~t6{z!n6s&w1gPcLMDJwzV8+Tl5YvIKU?uD3t7S;HHcTr;>V2xR0p!;%@Z@M4%h% z+yWm`Kd}cwIdljdqfHZ3&IStwf|2;c6d#tF#6(ryoQxxq72I9~*0SgrPf<~Rdp{E%Dri04 z-1nx}krb=SN8l6&o8|QlsvraY?c@56Zi~eRA57L8tZxv4%(&8AAnTjN!z+|3aeEo_ z&|&o~cz!{IiSO0{0u%)i5Fb>g4^fYU!^1;V@GPb=aqU+S9H_J{+SOL{!hD#i&TlJv z0`_d2>v?Q{sM{*-<;KQ-V#21Mm~hZfHYLd{hK+|Udr=kix(o3WM{;mnY+bk2iCq!r zPcCL}`}+N$7;rf8toV(XAnRu|9O96=^YE+>zxs+#bh;^IkDPR!_d|RdrN!g9 zpy%-Q_(Te<>q?i=XIp9Mho_pIK74u#YC%lfaJL0{l=3d%j)Ld^7$&S8CkREb*a{9h z5r%!Uw$ddS+L>FxazRy>v~3U+4tl`J!(h3;t>_J~?Og@!ExX!_-hk$TCc69plz+Ie z?Qix-ZnWL{!nDN0_~XH-+g60x{=;G7pWRl4hY1)a(T0zc`Qy|4(%45nzz7ur=UlBX zVKWDhQc2HYW%WxrafE4IcQo*<{kuu0GHF-^!=d38bVRlSve3|5K)5;VCHeG$FH2{i z%3-bKR4$M<*wW;&4%)6=PUWc4;=X9K-ClMJnK>d&%MRDV7MiucA^TTBJKOni_W_N= zOwkT!C1wQ+$$%1}cG#Gx=Rf`f!=^LCi3pwaC9OO?AO@`)G#c3WoJ6g}CI`G}yEovC zChtVZ(7R=&;p*yH9bkjyE2FkT( z)>xYO8wit_xg_TQx+Z1@V=>)H_KWjCQVt)wuQ?+gOCZL{yb%AJXY#H&(aLxK3U+Dw zxg+~zriJ

C?~c?`FWZk2k_eOPd7{{8}3aefYtXlbleW>1i|43gKI7DXv?X=|Z5# zP^U068=eAycMGJ!hmRjf(KFKx^+`*^3`p0jcaVD;eCsG}kQ+}+kEg+J(S;N8^%)KM z@ICK+nJA?&6B%R#>{F0^zp&v)k^UT^f-^^ffbdg<1Kl&zk#b-P#ZRLADIgwY83f#Y zj2P~NISMtw!cNY#q&e#q8n;#4Lgey54D;3dIXP$5*qndzwD++HZf87YA} z@a3)%h+^?j9!7_9mJ~Y+ygZBeK)FaWJkGW-GtPL#ui2UUZ0ukIyE*JeR&k;(5?7AX_-4 zwm#-~KE*uqMoZ75FO+&=`anPcP$2lf+_V6NwCN3$fqa#I~l2K@ezH{KJdDlzJ6lD*APP{ z@@L@>Oj3e>9tJs_i(wziMIKa&KO2L@dbD41H-t^DQmg`pFCv)?z5sFGgv$^&Z!q(h zAf93HOE5gZgfBe{SPpj5M*BthZhUMb$B#}8f-B-^HP*mML6zXoZj$cKWGQP8IgvWn@ize5VMI_5|`a z0;K&EVb3UG9|TDWy-lX|X;1rL+azh)GghW&YazdBleFiMB*QSkAFCt=4TizAwBy$V z48Dk0JMHhN4QB8ql9+}}`zNYnuqp5>q>s?o*3ujo6Godzii^!X0rWc*xMV=s$wY!F2To5)~_L`>vlikMpVIfWwT=QsKc zp~y5tb}B{SQ~;~g=X8p}b{oacpx9oHMJTqPW5e9ML5_2PVu!c_im0A zQfwo~E~MCIj?JUk6C9gQO}mw2#Uy7J$4cEOl=lLAzrJ%eK+E_(zR+uc+X?r9bo(AS z)`5$ma7cR|P@LgA`@M{(QZa>Um9Z_AY}G_MQwNwy2GC_ZlZshQOJ+QqiXGgvWX5w8 zF^!k;Jdv69%Gi;L-G$o=VraeGUJyeT++G~x7J?Xld79e{2|2Ccrz;cVO_ z5W5+sPONB%;WzPEVGw&0hPk^vQ?nhZ*FgargBXhPL_(}9A+|Rmb|8q2hVqUEvBki1 zYe-7C0;?XxzK&H7Vn;#YdxO|acq7X#VabO|TAv~@I<`K@9WlO@X$( zABf2HP3v2T83tD_clut4z129hzVooU#s~GCPYp?ar*9GJd9(=^WB9DWE2^BnCCGV# zajbpkB6k`O`Y!ANwfBAeoreMLFt{5tqY&nXG}I4?QqXttQV5eMOX$tkrkJHDpg(vu zmP2D%7fb*%`nKSglnuoy^d`>Wx@f)AceOQU^j(7tjU+eXAl5&e@l6z-9NYDDPw-@f zBpXJ|mqN`eN_!He8CcRNoKE-Nbnip=zI4x^dq2AOr+X&d&8y%BQurjg52CyIs`JSd zK85Z>=zc2QPow)8bdS*8ygF_eg@@C91l>o{eH7i#q`UdioiP+1OZT(rKA!GbbkC-{ z`8kIi3Qwf_B)U(g``L7#Liee3pGNm{=sun9<^|v9Qg|laXVLvUx_23+KW{#Ea1&*8 z+ySixP4oo5K7|O){XZGw{~t7tF_es_CPC>S#kPO_UrNFJy0!ryvcZfO(50H-ug?It zNyDU{@t`{wBBnP#Gs;5FSDy4aJf%V1~C9^6fH%CZv(aOo+X~Luke>{1qQ+!u=VKdiW|x zQ-MvkZZ_Gv*<|ZxldYRgwr)1ry4hswW^;mWHYez2bAoO*C+KE#f^If@wr(~j=w@?* zZcI#cvpGRGn-g?nVu5aU{|nSXy4jr3E3^eVv(Zgj$g-QXkYzV%AmsSr2m`P zadE}3{s@F6$(Ln36vl~`k^Es>@`r87AGRfb*p~cZTk?l($se{Qe0#O9o*tGx?&)FK3R(jGaJ#Z2ydNr|QBKdv~&bUbONX9enREQY8K1*wsAcDgzk5|vq zsKo2@jNhLx`6pz&>fRCLf6dPSnrr2M&Ez-5yzYj<9wLKaW}ESb`z;8M<}UvBy~227 z#y33NH8eSHAzvLtEXKExSIi(@Z63aLEn>3V>R}V-A7D*KumTZ6S~D)0rz=i8vrLZ zr$*rPvIlg0V{ay$5aAwdQh3I>ojloKkOjvE&up~Mb=ibRqB}8dy0dJY$PqVyO&x;bw zjM{`Vi>kCiOl+?}!j#P{1I^+tLI~$y&+M4Hp&u)zzo3=w;6B@Nvk6Vz>C=fp z4nK{%PG;5JrwgUX0BQOo<{yV9q0Ly_HsT6_WkH0{7C|$e(~+%v9O|BUx%WK_MEGbE zq~Z|ab<{+fqE|r-6TFUPoQD3x>$nUG#o=ZsWpLbX_)ENw;*cJI48;I$O}X~1hK^BRdc zyi3q!LET2wI^LzinD*cuFWOC=@YQ2RrYKj*#8#kN6CHWg=%-LeXA%pq-c3^BxhJ!V zfW&a98I5(UCwi}=iu4ymmyJQ87egkuC+LSSYGDMa-TOM3$aSnK`G)Qq=INl+8@SYh zaoEz{jV?M*ucLGvL|R?kiU++>p?kV36hSJqzmthf&q9g3my^}@eDG4HLNC+O6L?FM z8)Y0;{Gujg*2#SS^vAAS^^ag$f&{eQ1dHI_jJx zl^WsUmxR2IT-YPWV+FRHERPD*jNSX53u>1|W3|^&V5%e0TvKp1r!Fzk2^?K!qB$&9 zjfqYaDXDg^B-U<1Lkk?Z$#4IHL}YhJL?+PF$wZl0?y6*RUvR3lN|i`v9=p*GZ$Hj$d3quHNz9@Nfo!y)cIwYfRw5NGn*VrIi!<(gTn_Ze??| z<9*`cSy`y#z;&kKj(NKv4aDI1r`~>uLsv4%pK-g+KcVN1YlJHGqHPBBd5tgzq=j$_ z0FDWctx?Kx%Uf1BUUtX~AImn-$an(?Xj*hds2h`< z34?}F@QRRe`|N&7)VJKilJJgy9N9KFs|s4awNilL5=ScA7R`Qhuh7C-E+7Pm&E7C)p~keQIaeiXu) zB^rilf**%W(?4;&X~Ca_5?gRf2(^c%Vdx(VCAR3}B#+lIhb-kDDA&>iwUf#BFDeJT zM)yrUDEuJkN1A$YIB06qg2r$Qbisx7I>4c$lS_?!SsQoInev(A8lyDsZpV zXvid?P;`2%;d_&5_)(~h(eS-t(=m9EyN?CQHPyX8jQtbs$HX5X!O-!T_y!_J$3!i% zF^p^UxOqOv^|*{A#X=J#wT88ilSw*cxJddjOUhH5k6BV~n2$-)V6gs}OP)h=eZq2W zy`DSv@npq)3yL#UJI?&s^uD0&K~TC${X6Xs2J@_c&;}t`2~~6hFtIC2ZVW*(#eq&H zmcmVRhIw$nwnYrP_k9*faz=`=dan2xDY#J?SY#vxcPgRc!f|9Wjs+v6ZX**pj!fh@ zDg}2tEso=oal9koIF31*j<6B%6BK|TDInd+#Eh(fS;?5c6)>Nbf?*t6eg6*-%EX-w z&YqVn`(Rjyn6}Cbvh&=1X^MNIzAp>tmnPJu4)7D|f*{o;!^y;qlaOEkO}LD7-Gqqq zR0@dhyaOe=?mznUhP#WUW4yVkGP|X|c8!zW(%h6?TVGk%QWZ^zWG}CcH76p?YZ<7k zU7lTCS(&|N+LZDslgBqjt7b)oaFI)e>z%f*y|3 zQrloyH8)gV8O0KSEru(qs+!_4N`X>9qm%)}07YQSFq>8I2^$*#RyM3$*-#Hr7=}S8 zA%~-M$Yie2=dOEjgEuF0Ql~d2Gwg+)zb@;r|4H>FoooHp>O(Vgw%pv|7d|_0lArBe zmD$; z(_5M8&+~Ubv-F@hazLkd`2c_3Cr|J8TSLu$EY#0`Kfrf;!+`RWXE3eN8|#J!_;31y zIs4P0KCurDuJQ-IRJ|dmbAmTMvm-myE6bnM>FEnaq} zp9>|oUbfr6>5#uA$A9dT&=Nl@)aTq#QzVq;Ul@v9IQa`NYruw8tvBuS=UwXG>3`~H z?z`OI0{2Ow7XQXMqx^&WR&SV@xT7H(*{)=QG}!r)+`Bb$LaZ{)U`Z|I%lkxg;ml z(~o##2Y4d~`a?Utu_yZn{o0Oe{FD3%{{Af+T02&4xyf(cvgL`+*6&~ii>ke|26)2; z`Z-(tL;E^`zkkrXG;^t6bA{jeG!(P}s$1=M-t1qw%pU-)@w7KK(|_6@<{x}Iv~)>m z;I7cg5%0`_-dO`fUtH&nc0<2$&JE3sH-1p)_Uj+;5AK}*qtG$u zff3L6GrgPvP~yJ(=igU!Z}B}P{=7B*7BFB??V+X6oKJf*2SWPp&PzAI$J2-5p4l0? z`pwZ(p6*=bdiR?q+XiS3P!UbG$1Q<(spPJp!GBN@AEU?!d~Wq zqo)3x?TDMs4t&;%s>rOFkqMMOv}IL!d2K^^MP;mZRdn zYa^4#u+JMmYeii}b#r7?WYNXtdGkva=FdS!qeqV#EqUu28XCuppJiBYGIM6+ z-x2_MV^eh17$lr9#)+Z|Ia<7ZhM%bRPjj$(7*C(w=NIzdVCCdgV*HO4fV z#Ri2mB04Lo%3}@X&C&XJ!xEt>r?$Q-x+ZciZrYM~mGFS{Xe_QgHl`lg;^MWN$_Aog zdOa35fj=VGUK=3*8iB8F+hSqag8bP<<>${Y$(u)Q0`&_l%m@b~Qe#~dn>DHC70C&0 zP*GRcP+1PUL!kOBkTo(31jX?3isoogF&t_qB9*!RBfB3H88s?0OjLs$fB`g6MXaTH z=J=d3kt%56`i5Af5@d)#PpYhIXpW8^GYskpqj3w^b8U5fLsM;ibtJkb)>IL>U=B1x zWfZzv7473YL3({d{rH7>Mdb?$=N6PLj8xQD*4EWkG_8$PRm3W$M@BMzVDdO^z&3$i zSe93cEh2JSDaEsk^5>M77MA9ls(^@Mv60a@Ll_fjsIOZaX>Mt3Y-oZW2L#4Q%VUwI z+UlAZRBts@Cs3os{68r+iCkr6OSv7o5&A#ji~R}P7;KrE8w{FWnm>Nl|1$vtjgg^> zx~dwY&D7*;qcKriq#*`=GJ+*HM;caeLo^R_0?Tw9ZExZV;+;J3v#c5Of$rH<%@`NV z;=tE{AvVVv8i54UIbP8eD>oB7L`mw2lrH%j>g%JGF&nCFz?hf>r64m)0_4v<6>77* zqVmdSA|s5;H|fwKNA4(6H7jocVKl zLnAO61jCw{tKJ3+7d*^C37Mj{zBWd`0%Kv6>oV9>urMhJ4;~1np#tSO6}IgFVOifW zF|Nag2&Dzua-m-UEi3xRR?K-AR=aiOgoT+qgepfw*cKy5Q+tXN(b zb>0skEQTOl8A3LxGr1hn+2dhbHCLeWU|lk0a(T=_ODQjJSg``a*GQOBzDqG<9u$ z6lpeNgVSkZu-*Wt3aPkPCuz9R$z<<95c4-TMqxPw%~M{^E1PmzGm#ZI_$88f8Y&f- z;+II`;L4U*bWM3PeRV{b7%b-Cu`Dc*%s2r#@jD~&c(XGU%mOx}K?vMm!ex>X`yz;e zwrB}ej(ya@Z(TH3l&`2*SzEUjIN{e2WLf3l4yZ)1lQmUTM;+Xjggxe(swM}wa4R{C zPd;N)KqrQQ1rLuo7IW}nW{xyF_*gPVDw@~U(@2F+F9(2wo1zc{cLu`XgXR#CTH|w_ z5QQTr=-aTo#uG${i<8Fc;K3_E*#D?{c#scqoc91fe9)d5#2kDA!^-X8P6Wic`@|f4 zR1@N{O3aBz_z-ES!U#TE0g=YqMl=+B1_9}y*_$AWPZ~hfR4?Y>^8^rWhOw=p4wCUa z7~&+LgAYnzqD-7(4nB+li18vZ`dS}ED~-2;?6_Y9K;TSq!wBNkxj^l>+rv>B-*FEQ z;)WfhkL^ zAkOs$0(@E*0Bk(iT{qPvH|gL*N=PbNXm;>1T|l^Dn;m?F7Aa_0gY5Y95yVZknjL(K z6r$Kt%?>``0}-iWGd;Wk05%;=Hy~xXgO64+)a>BXiV&gJYL)28W z*}+FAAj-9BcJR9h5I5<~4nCX=QL?sX_(CXjw!#vKR$d8BhYulObY(@;mC+^#pGLsw z1%>nT!E2av3g~Zefz?~rljE$275p)@0A9Hu171b^Sc+s3vhx#FEAnx8l^|-MDvl63hXjqs|L5D`w z1WgKluA*wPtsh85#adGauf)*3;p8352A5+7VhF_0 zo8dGOeH2;&45M{8X^%m(fj`7LEGW5Pp+n0gQ>BvP;syB^EW*{Bm7U7Y%pGT4uBTN4zBX=TL) zJ*?DhZeS)z9{5wVrrCuH^A}uPm`8;y$iJw(Y-wqJdC}}8q~7@@C8ZQ7&M%u&vbfk9 z;1g#A3kw#Nl`ojHc!5*i*g#cSR6MU3b6_Fo&z^Gu1}<1wo_}$EG4(&Sq9lWBu2>Z% z6|;zmD@rK5vY`bOh%B+e%1TP+mp~N*--~u{CJxlDh8k)dc)WNRnt`T@$V{|dSX`FB zpm;VL5-ky-TfmBsZV7$B+QL8%pfBi{3rZF&LFOICTsC0;Fx?Lv5!7Pwg2J+Vw2X?XvuQ$A zj$HwTg4Htjq-OMB_2|N&7eQC2J&S~?Tlp&LPB^t~jza68+l?gXT&4-AxC>@4nqP*h zFe5TTC@R?~pghmVUQ4;8o0l%gFP*)Bv>hMYf!_36Gnt2IxmomZC#LNTEXz#mOlK31 zR!-g!3ov8YGfA0xVy! zMkUl~^1&<@P`tPVx*^e_yr6L^yDC~&u@-h+prD2($J~LJu`_biGy?^4d*<9+*@T;d z#yaNCE;Jn#Txot$DJ_SyiXfr|%2ny6ORR5T&0z~IW3l${R)4%VW$ z1jhpi!H8SFFu!&=(K{_hQs4#DKabEs>=v%e0aTxRpFe#h|kPM}>^X8ek33kQ& zJk!+d?rHIh>MSdSji8c6WsY7|8C{pnDFh!Jm?Ig!so~rOvx~49WMHtgN2_g!Q(rN? zAnx~Y$cJnT3+JM1gwX7TON-3}f&8`fEof+(Qk0aE;P#BQX?aa~Q$quL?j?mK$OctC zFCY5jd>rC%Fvd0|`$hNQ%q?CN$&1hdVr1fkoQV@An8ndLfbjRt*O zOcMXXh1h~<0l}m{9)|fy`IWGfi^+lKChwVJoajXJF^Tf?vI1=kHX5*6pgoy#aAnG{ zfiY~xRLAsO+AKztxAwWe8gGV-isly<&tqajVVnfL2Ykw5yqPome3&|eq`bh85P1OO zB1njZ3t(g_Uy18lWL;Q%v9Xo>+4GUhQkW)2VI3iT4ytR8OvzK5Su;<0?D>a*V9M7R zTg!7s*&G&83NIaEO|_L*$|ew2D4t^lc*15H6zAqsD-;&fq^Z6IW{b@ZErwy%68AGF z&J4>NU^&E-n4nVRk;%^D-4DiESbI5DwV(<-o`a2G8l}u)5alPgO!ZqZdok7^Xf~n= zV#eBNs6<8Q7370EfSDew+%YaThZY4)%q|cF?A=K+0+_&=Sqbe_xn4=_OeS29o3Mkk1b#v5YN-lD?v5k+<_hUa?}lPOi2j# z!eO=tOX{E^W;H$0+A$U@z#)|eH`(tkuWUhYQrEJw9%}_{QIuaKwvO`;w2xTZUeh?;`Wb~#r<#;FF4Cv^~P<77Syu9g=(J;*!^B>G|9EUf| z9QW!4j=Ltq9g?2v-vK-4@EAM&Gve$zbnY!#pwqV(hmgb2RMDEoxX;WP5YYdRp$ZNrj6I{ z`zc5f0Vu-h#7F913_5(7L?j;gLp*r>3vWW>eL;mp0IK5j-@-F%LHgyb;oCx?pY#AK zY|C4irU2y?9-+KI51ToCMnd|OAbl67znqZ1i_#;&@-U~rgP+2GIn?8q)Ra_@bl85z z>q5KD~@VHT~@; zoKAgKG(U{K~2{pl9Ko%Ul#hfgfHf1e` zF9T#%MVGf!msc!bj*HbSqA^fy{fdSJ03O<3#z0Od3wPLYA2bU##-mx_|Hi}O2Bs>8b+o2@MHB8?|KDB_V1Uh!rfgri9MLBe z=z8o6PK?d>#cdG6qrYQ-2z>PdFF3fSa^&0t<9LmNe=MJy5+S;dCpi((<>NO$kmvt4 ze-7lu^7SR<@8NzX>6&&9Bxnq2U!aHo9S2YC?Mu_12Z_2)NMG=Clk16G^NISxHq!cA z1eoTDIbd2y7rw8|zBFwqBz9N+@lQ-HX(#-|vUT|tfFVz%CMV+(0O8uJ3=59l60UlP zX_=7Vz%sn!SL@BE+*Q=6g@o?p&p2js*z&^(;|cP&0;YLl&VN+k-En@dm}}bWfJTu} zzR}&34=0i*lz%s1nkO=NYz5x&ZDEO*ro9uAyDLAJ%a{D92ROt&q5MsNX`TQ%?{WFd zFk)Sr_Lq=`n3N-=v#L$#2XKsQUy@%wyCAW<{0I2C816;^3&|&+yE%VAz=1wjYsADQ zpQOGA0mM$QU(Rp7jxW@4{R#3G1iI6IBkNzrY1BU)m!F`2IBY(_cLC%KM#F;Zu=xn? zTK?{2N8A~?W+@0usmH0 zLlx>)5~S}=!-y;4xUkR(qnYrR+Q+4WXGx&#$= z;8kFT9-r63E6;q;J!IZnU?Glk0mQJ}-9rsb^FRoe!M_XiUF!$0C*<0{j70I(myKl1NjKJZ`!UB6=d8;qk~@WM3*(yvqar+_2> zU!zlli{|_Ai4BhQ&5C|7=mqg*jEnp^fFqxQT+xHb46X|p|2yL}-v_*m@u}Ex;G%gx zd|tu)%T&3mnf`bD#KZxJ>yd@wCUFUec%HsN-x)f_EjsUrmC)3wVEMu}h$x@uIap zeEvBJ{TED+KNyVH5%b~Tdo8+?b5Iie%p~|ZN$`1qqn!T*pLo%p0(@SPguX5besdE1 z)+G2HN$`6CM|o1Y1JV8j$n(P_^!TRc?)0-G365(?la*zmi6 z7B5_Lc31A-li)pJ=<1HXe-ixkB>1Q#_*qHtNlEbON$?Aj;1?yq@mI3CtJf7t@Msde zE(sn>g5L-@wPS>u!=e2Z2!50CS4S9}_C+9gcM?7ulHiXrpDpY^FEs2NeApPvy?l%T zaJ7Vyi zv*^r;Hp=DLy4-#~47PkvIH9uk=rP%B(Bebl-E4AaO`SA#YWE3~bLdRgIxh-Nh!c*M zy5)NIlykc0I%V?NNfM?_#Z6>>7^PdLQ*+=U#1l8_v!+g+GKKPLnH zXZ77PnKUU0lS$L2k)ZLX9pEH@9{TK7n8{PS*YUKor*v;8)6SlhV>Ho(#}^Ksmrg+* zaDoXBH^Q-8MGT$;A`H{hc4p0IM=L*wPAo%n-97o3BnUvZ(qQui`{32H`4{kvSC634F@dJ*^ zxhF{gN?H+(R?$V>kj0-Y9D}kB{Frh4z%{4H*$?IycnO~_UJndWIA?bv3YT$aB;!bT z4*U!MY73uk;f)q<>)|E~$1zX%{K&%3weX)?xXov$h1-0-vhZ0JAK8x)J#1t>;Cu=% z!9@>)6doZeIDcSV>mggw3;%NzF8pUHd>-@9OTvGZq8I+_6)ya5R(K8bzcmT}H!b`; zpp|y1=5?ItN6NiQ;Zp7@g-f~kb6j|7z3sH{Tu7I4zp!vyp1Zl-v^+mhxX80f;UdpZ z7}xTgnTk>xIdkDtOI2{Xdf6<9WR%d}Lo~s=`HY=PLY3Q>-(a zaovuK6us~-SGe%6Quq$$Uz>#gwTfQ&e_i3izg^+DKZcj=vugQ&WtBSz=%jt$QGBG_ zLkgF2KUBEX>!`)wwl^0W1TM^fKKx6$nHFx_$?zmN{>%ej$j7G7OM;gq!7ojMuTO$M zkOZeUAG17m|2>V@^(bdP{7Zc=v+xTnd=ukX435jP@A*@OBR{;JRQTTwOy4NPAkx|T z@3P9Z_4bv8+w#xg$pP}gwWY{kYTuT;3m-(>N(<^Qvym;LL{ z6)yb0RCvS%Vc~LlLl^06{zEO?w$EC|rCw5Qv%;m^H40zM<*u{%+vUEb=!O3q3K#xw zDZGYi1?PcD_z&T82h2Yo{>5&`Sh(HpGcDY<|GO9$JuKsKeS^Y9&W9CV$9njo#oyM$ z=ZaqVyS#}a)|D7cK7w{Inmj5z^3;zm*A7uV37}xSgcD_}(OV+5jjFE|lNy@53$JUe|oUxYp<26fXMwOyTk( z^M6?UZTtK-ACYMO_>OzL1Q-4fDtr(pJjysmZT|QhBX|j)z}^%t{P!t*G$*{1g#REu zu+sd8DqQ%FQg{I;jAI<5w)~eXdXc|c;ljU8;U%1KRTBPfieC8Nsc_+cx58^U;r=B2 ze`VqJ_?wRh*>H*8a@nuqk1X1_lv}27@&8L1M><2CU!RMz)Z~OTM#&Cq1EDV%d_9YFS6uGIT<2wVfF>^FLD-G_(BUm$hgQU=evJZxX5`-;cs)o z7Z(3>EdE8OKm;z$f3d=a|78mQh!ZLp$EeM}LD7r+YZWg1uT!|3N46&6|9wR-{2x-d z@ZYR(8Naq9;s1_>mqFd6y^dP=WDD;%1R`*0eGXB$$P-bx%ll0u8Q1#!hJ`PJazvi* zS-36FV@dGsN$@W%-0r^v@IhO+P@Wm^FXdim;dZ%qS-4H#?=<9M_}Jslsf=sAjZ(Pi zZJfgKO)+>)u=v|{xWdBiaqv0|x8?b>h1>fiKRex&qvd>B;Ueer3YYeMk#XI=J|9S8)dVbczZTs&%%+O1H z<++(b3Kw}!Rd_+zw`Iokt4d-TeiZb+{p@; zdDl6NYrU+OCEpJSE#k%eDs;gd%v$|KM7%~H6?lc#X;hXssld9Ji@+kU>Q_(-`M6)xpIqHyU) zKeG7Se&$Iag7@7{Hp%b=mC*%9%};zlL~!}O5jPj{ zNfl!FoWNm`=XKs+o2u|tyzh){ikHy;nsMB##7poySx)rfcnL0gzQn)*UW@|6Rc<~4 zyg%;?*D1W3_fM}<`1e@;YZac$`(ocy_*qQX zmi0MD;pS(0;rmhwe}m<@OyTeII8~$Y`P{xSh2Mt)!?j-F-{N+>P2q!BKMyK=7q{Sfx`Q9zmVT?6FDcae~|C^3ZBmVzoz)?=5}vX_%d#n zRSN$b_d9&<9xvfPmfPhg!glqL!UwYcA6NJv*giWI zzSW5B>{qxvr}DnSi&*}n3Lnezf2r_n*3Ze@{!%YFKa=N|1b-I;aOEg^X{VVAFJ%6O z3O}3MYmvfRSq~Ko@1j!Sjl2pM{obhXLCpVK3SYzRa-YI4Vma~ocf6#&&$8aS6n-Du z^NR|9fbHRT3ZKj6zOC@%>_6pu0a9)Q(@DP+{9A1QJ=iY_F8(f4;d@!mh{Bh1zZW#qG62;U(N&dli0+>EBcMT5gw*6n+NR_wNe-Df7qY%56CdOw>6^ z;ft962!%JZeNI&PDcpz!aqoEIy6Kl`OBg@4NS)THnyS^nD<-jnrqufmscxj$6+4J`jt z3LnCH__e~{XZ&@A-y!}@;rFmV`K!V&;rKrlzL@FLxE|78r!s!B!cS-U<+((m@5A(G zEBb3#{yc@(vVJa7_*;yZE4&Ze^Gb!^%64*%!dsrtrtP+%FY=gzaq%>s9pp7xq`V3LnnxvRvWv{P8skzliPN>k60W zkiM_*>)8KqP&iwyN;aOa-4-|fo+xO23|Ah7SiNb%$cK(IJ-)8<_Df}hY zLkioS*vU@Tf11Lt=KA(i_*%>e*C2%()NxKz__w%!4OcjR9}}-J3O~a2%2xO&#?Myx z$t=$dg^%O$PM))s`hLuMnXBlFSk5Aa%lkYQDja_j0k5SBKg9Cb&+BFZ-2>boql*4Q zw%aQeek<4aDuuty{e88vrSPvfey_quaQi-} z@EGfDlfwVPcDqI4r?MV?uJ9|_KDR0S9WM7dg&$`=zgGD9O#d5&uV%fys_=>2Ui%b2 zh3Vf__?v7G|E+Pd9{B#V!oSY^|EloYd3^j-<806WQ1}+M6L~IL?7xBOQdus+WnAp7 z@U<+bJV!0`-(^0hD0=)!47`Ra{7UveV-)@h+u^wi{|>j;`3hgc$y(h&D@Sn3YYWBH3}cf{o*=>f6Vcl6yBfXw<`Pq z>+KGOH!%KPg`aMk%aMIMOh$iI%zFNTqCc7C+^q1&S#PrL5k4|M+o9-v9%pwcyqx*} zR^i*(&fidY4f~DXEBqst=YYcR;C2x|jmcQw<;>?JMgLzcr?i96&t!W$uIMMSy?v$d zW9%P#v0TFE_uQ`sD!dV7!YiWigDmHGg^x7k&UA(UoXagxI33VHo`niuzRmx`RyzAcJAm%OUuv?^TMr98;G#Yg(lQiV%Ds#du4qZWlrd$lTD+N(q1(q8uWgR;ODq#tcj^wN(y z6)yc~pTha)q@6eD^EHKwKIJ@9Sixn>VsZ_Y=r%~aepLGfs{oJZ>(a-l3F8X;`;i8|PD*Q=~Kd10VSr0EO zTED_%%F#x=`WxzAwBMDf|h> zmn&TK)}V0F+qDW8z1^j7(a#SQF8Y!0EsB2DvOMo9`k9Q&_Y;M_hV?mXfT^G0^8Jo# zg->DnI}|>I^|npna{l*@!XIKje^>Z-SC-2RN=R? z9=@mWF|6ke3YX`8HYvO(uUj8i_-8!cy`XS87kNqHKI?g}!WXf>dQ;)wV!!Z?!XM>! z{G-BU-{-KxedhmHg+IXc`b^=IS)cz@_y*Qzc#yFpY4@M%VcV;qM|ZYq-KW`&otoZnG=WS;PZ!o`pMTH(8STz)wT z|KBP6yIk)3ijS0gOyP^!&wQ1HPbz;8RO&m3;;y=H-KTG(#yQS`&u4j)WX?hh3%-|O6}_=uigRQNUA@7_?j zwEO!C|26lQql}CGrQG8Rm*>n<`2lfh7b$my!lhj%DSS5TXBOjFF1iLePrpLZ%ln&F zSoGL0M4ozu%X_rfDLx|SW`&D9^1f)1XCvF&Yl=RD`{{d0$~~lTc~9=AijTBon7=10 z`aHsRJCt#0mzTM{#wh&nj89a2K4yEHqwqp32(I~xkH}f3aCr}JrQ##<-=J`L4x~fj zqW@F>8mouI^gwzx~&nfHZ z(-r=E9+$^5F6||Ho2YPkPw{NUXBhJ-Rd`Rfw{nGloyV7Yg`dm#I)z`#d~Q>C9ox^n z3YT_ylyPYndH>Rr7LM)m8ISL8Dn9?qh&3Xidz6$*bA1%|6p@qeG^A!`)wa=9BUKI07wy8pq#vj8b(fAWFiBl`cV!h_#| zP<*6a#++da)B2puxcG-$w(~qipUdNNiA9fkmU0&>T;>zsQG8@R_K3oN&*g4O!snL? zzae7k^Mc|d^?hIA&FtsHoKN&1?K?o>_p+ZEq3|$|Qyb ztSG-c=X1NFe-n)zuDdLHghbB!6)x}h|B2!w@^mU(_V?aW_*S0B9#*)>{|VzR$U-iI z^&A?8(#G}QgZ)xp#*rT77dZzhTz*&JY{f_9pQCVDCzdH()`?XLm;KdNh410<$bP>B z`a`Mj{Y)?QmG8N4QGDb_2ew)C9`KQRJ+E;29hyHVK2qPmC|v6MPlZc;PaO`0!6o)T z)T^51eXF8W+(@j-pc_v@P!eJe@hIM*k^kD!2XiJT@D{7e@42R2zsk}y_N z!k8dojq|kZ1pX1s1Q#|3Hwnda=^n?+IlfHcvd_6*;j%xuQQ@+G*rjmUPdlJ+*}n?2 zend{$zZ#)%*`JZ`#S6XcGgK*hSzq6za9PhjtZ-RBzMybf$Gxv`S;vK0xgw9OzeXrr z=I!!+N1>Pbv%G&raG5{fruf_tF^c?&!et({N8vI*`AFe1?q`GyKTO7d86PJoT*j$V zg^QnWRJi!tI}|Sd_6dcH|Jkc>@jpiuF8v*TSR|_tk?DV^DppRZdj&&8lWHb`LugQ;xb19hXoa~(BEGlR_ zSkSiactKms(Y8e&6}0CcZC~_JTd5DB;|1-dqY)`+E6t$K_FVW}bhMy#M+RVq=JtSQ zFwxvjw7{@*^zL5~`__*lSj1s0wxBKlaKZMsCqKFG#`lKgL59NxpZ~Go`9JlCAmq8D z3#t-igF=jC1?@#gkzhNzv4XbW7PRdoZd;LMK#rvxZfkkJZP5W_+`fJzq_!UaDwaxg zAFgQ6e}6mXpoK59Xv_byb={X=wG1JK?O4yl1yIknH>HpdvxwWG1MNj$#*4nWE7q?) z|4R`Bf8XT8ltg(Zusj8Ai}tq_z0qFuJ~GkqDH(tN>&=g(DfyHbJs9#*uo^52Wnx`;^o7DdK7=^pk(u3e7X52X?MU z5%B`!6&37-@PYPQHv)>f3A7;gkRGTa9NR?}QWzl3v6(@*p(WFV(Q*zLZG3pT1tl8O zk;h1kqQg=(3O&v<+q;6S?w)Ly!b!nYSR z8Z0+syRo03+aTUfNAv($hPht&P;PFp_6x#$3Q zr@g3nV@sfrV{u~w=hHGQZVTOu@L^he{;{?l$ha-T5HC93mI2Ns(Bc1oD-G@(orq~6 zZr7m{OVX}KK803mPk|e{{+6khb3yxPU3c7x4FU!**qAW{3?+3dI$d_(ZIst=fV501 zEO$cNj`hC{W4O)q!R-;q5?K7zUy$QTB~Sig3+18Vr+v};ZEwa)`ZwM>7c+q&?T1lt z7x1R&&fG=_ny~56WJB9&kcbaPRzF=>(E3pUbW~u|0^M{M_};Cc!7k{nyMlgl7|gT_ z#(=E_?U#e`=I<|T+eKZtpzS@>%jCa*^;KK`M{JCT(HK7}XnmpJQe%-=#(^PUpdO zy&5jLg{FZ4K;xc;-8G>Y^ptinWF6=z^x#fzP25#5(?HWaZYCb>i;meX&jn9vU3bih z4J0ySR4#_Ws6IqXJKj#vsPNe!m(nx1T$*Pi9)E&yYU--2QF`w6HhA zNlTjr5d7*m2YuM2Jjn_5nVvQytq@KjQe3w%6OSW$40Q@Kvthptp3zT(5BO?d8d3Dj zbVGg8(l7(k!B=V|_cYiQPaEXM)6(NAR;d#h`?wRSx zy?+YDGpWoJC^H4o0n9h0FcZrh2vHx?O!Op16yda#pxPb`y6|EQ5&_D@=oy?P#m*ApEKnHI49#-SOBcq4 znQ_*`;^o=!@W}}!j({junoAsssfC%7(~28HL*01yhNzz;4uo_R?Rx& z1#1L*#9L_M3b=b79e5aI@)|_K7BcNtM0`S0W{6ilgqNP<0H$IP^8nUOjR7k{8l=mO`_I?#l3G3*1&cO+NpYz$Ja(WxcPL9S91 zi8)+E#TgC@5cf^E4DoamUV?ar315QY0VaHDDzF^vq>WB3x*tNgQgc$H*rX=7B92yL zZJiXX?G{KUU7TsEnOcLAv9@gG`)RL2f~mCM`!fhrv3?&6a=0&svC=QXCuyzc@J>jD z{sr-#WAF#t!K;Ac>F&`T{S2hiJ%#Q)=-!L&>(@ujXNFoja}BSz21*8xKkqvsRI zo5Mdv*faIJ9fDN9-XPWzh?uNtf7}aU%9{4y@vLd@zX#@uodbN-!DA2(oABZFP#xc7 zJ~i#=$&g|a{$^$V*vkCLN?^g6k5yx4L;oq_gTbAp4Ml3In|-%6V{~G);S;6#Mq57$ zpG5c5=suM0W9UAP?q|_Gi|*NUpGbG}UAE~Io>Hdxp;*aLz1M~5b`MAjlb&L7< z%6zQ%OoOCVT#7Y?e<$sBtQ;vgoc68WfSEeqaRh1#$r)+8rvgaknD$aUxCdWsX3&=x zBd3%?xFJX_*VjqGA~1#GsZI)(gG!}%NZNEKHj*jw6)YVXp~JXC2vflX@LB5&G<-@= zpM&oz^ZlQ|y`PKkA?r`K2f!2c$36#Xy8s1O?!apRdq0(mDFZOpdt2&*_-P`Yso+f= z-$b5C#jF`7@@y)0hQTKC97RT($n!)t%|v#j-U@lTnB9(4?AW`47_!)#5IYdW?g8PB z1~Dx8ctY$;XW;6qoZdUA==H7?_dW23cLcG|!3eenF?;~?Zciv5g#tDPF%;#AgjiQX zY;QvBKoHA@@{R_v>w)Likd$yeRy~MyVAX@z=b-StK@5L7>z1(OLnW*;R7rkDSF7oAG<#x2AKXdkTez(EU`p8wYp>g(GwyO7~%OA5QlXbRS9gQFK3(?&iTO z<2J_$I!Lh%XB{N&|56I(*M%?KAsg)d0(w^y{B;g+ zAB-04_kPe_3K7$>A9B$?Ir4~W?AK&@u}ZS!_CDyo9Ar7XCfwiqQ4f#LOa(UCy4hsw zW|OU(O}1_}*}Bt>U!o6QNj*_@!8%?Y~MoS>V{o~@hBo~@hBo~@hB3A!;c(aq)r z-E1Z)MK>lE=;oyiPzUMeaPO}|=mCswoUmm#PS~;=Cv4e`6SnNe30rpKge|*q!j|2* z;a4rYal^LVxMACF+^}soZrIk18@6@hhHc%rB#79JiHUC9ux&RkNh!K9u{Yd-wT+cd zZ;#UUvrUD=HuZ7=sEYKqzW3HJ&Qpxuw%K~yX6tR6t+#Eq-nQ9#+h*%+o2|F) z;iF*jU0l%ia0A2+1TmauNH5wR#+dXX6FV*r?NtvZDMv{@`IDyihnmR1@I57_Q!zyO%(c?=OSqmn3N5=hM1iJp17pQUEG}KM*FNwO7sNY0Fx&_qzvC$z5x^|Ogm3x@7{Drch-{?;_ zv;iPQ?Ha<>Za+|!@8iqC`?=^+`qPaGu^A2F8h1Jo;;%yVqk-IrOoWDHt&3k3_x(yD z!R|@bX9m}}_~4K4-$1F~##Fj-N$7eFn|1EPMED~j>_kGkF(LXILwL9QG7-K`g!p)N zf4VUtc5UAu0%{x*>AgLi1%_-|(S#EsY>_5~=ONpvXATA)=<7VQB?YWr>9ICoWx~wL zM3|L{Fe~Urpm$^ybZ;M)ez-<7BJD^;@lf84@ag;L%~P=VJ_%7;P9us;V8^v89WsGP zi5oU%Tf)rx&0Ic0G(3l0FZ%-ot~b={eFsk=9QQaBm3X=LErL?$(SG+hdKj;x=JclM zRX~dgUdJ*{!+zs+Tn6Hyw>ks4xDIZ!C0_1*w?eiEf{@G%ouNeMok8=*#0)@p-%BEb zcZP@nPlY(%8JGYfK%qF*8-_W(kx7`0gYQd|tlmhIZ3)LvonA*-LacN+@fu~)>X`L8 zNm$l zYDz6NoG(f!X8}Gk;dRV89Xz795S>`4W9#)JnjEi;3mu77JquX7@|9|cr~HCJvbr=U z1Iy-SYE2>@{^G0=q16af!?8Q5;!7lddy@P=4f3}q(- zw}C75I;y1ndy?c|4d38365nI;vwH6_3T5@)i+vHA(OAfRM!i)gcE3?+&4{K|j`slT zcT__Q?38aqEz`wXd@hL;{|uyfES~u~S65bMubDQb ze9GkUP0^~FirDzN+WM9?*^{#-XHAWBTv;E>uBl$poISTTR@1UPyS||+I=-%@BD*Tu z*qq(6N+=;XzOkuxRYgpRQ6G)f!oQRKpK@{>ILnJR)mPMI)xfCi;1idX7-)`FK?;DN zme|_HXfp)iut0*)k%6Krx&mN06>N;vG({__BozqjtJjRbswLVI1p=7KG&fXU8AW!G zgyD*+swNYwt%pyXE3X=lIyU4jtKgGP6MI7W<_dl8x(7FSb22A&dSf!fUg-YovOe)! zmge}w53cfSs{M_A%ZAlUC;ONB9UEJ`voigSTf9kd_cNEC?LX*^9I)HJv)RA%!MD6o znf|cqr=RmD_`mVDbawg&pY{*!^EU#k4*xqjo$!CqzjUI1-s+9}{4Fh)?(^rhO#C(! z>bHLTi48N8Cgk`z`}|{D_IYClZUEjLtAO3c4?6urAk^UvQ0m5+SNp{#uzH{WNsgcC zjm%sPqK499OLGn$ge=wme18H6GW4L|Ns-A*bG9Iuy)>t@)APVC#T>IuW7SmDSJg$w z&qC!#X3mT(y12Y7uhcOgeLo0+yL`5YeHzb-?R{Kd?Tfg60 zd#!U$7P+6k-~WBy=X?I=NzUE-x7S{K?X~w_dpPIbMbrc=@91jvE;hg%?|Tj*itZj9 zZND4D+fo^7<*ww)lt)vma0c9yqTU9W<~o5pJJK2Cr+G(6UmmAR1Zcr85`x^ z(%GF(ahI&7>5N09!77BZ7&CJd8Sgv^&zOS=;i z%EVzP5tJCX2_Cq}Ne`BTc-o_-2DPh`Zy@Rp=@Cz%81z1`21q)YSdm=W(YY4+>9MYk zc8{K_c623rx_e0|dh&=E*#X4pfv&{(@nJ{T98U6RdRGppt4GsqC_cxdM?%yx9o>nR z)tA$AEv5pUTyjx$DSe{)0X=u%er0z6V4gfup1E6Z6 zV{b%Ly}cMrmfD&t_V?S5tSR69FJH@&M4OB!FaRXE$q%&Lug2vXvA_2a^(=NpV_wh4KTTBN!ll z8GvZj7!Y-IcTr9{*CLPx7RBk@0C86>#Ode^alh&4unKXh7zpSA1psQ0v`2?fh)^}t z9-Sx=sa7-X(US=v(pYJao*EE^Q+L{`iP2{X^$SQBJR@D9z9?|l)FS4V;UPV{G)&4;;D~Abh`v1_IJU=$7?F8 zs^eZ&eSJe+Q(dB_bTJPP*b0oG6`kFyJGxeMd)!MwU0GUNj>({DNqwA2QM|7Qgq{8* zkf9kQ-cVY*FwT`yE8o%8o#|My7WzduSe?wYw5NLg@~i5(h8T=#4P-PoPb;tvt;tN% z@vf_A^j35x+tM5@tE;VTh*vZ>#>*iv&r#Hf9_xAq&lx1qg6760z6s!rT=m+z#^(C^ zx`rl?6zb}qZo#~i=xFt_UDODv)?!#ouPe2NWeTP?u&sh#yww-GKIXNwcXS4oqf!@_ z#}|3YmJB8pQCZrP$~$YRwG7XEEy-+Kdqz4y+QW*FRNU2_@KUQ%U6@v&>OON5#j`z7 z5C%6oQJ~g^HT7O<<%*8ZR07)q5~#GiyrH(PsdQ0kRW};%xyw$xOP;^W8%AU?tCep=St^*U_vQSsmYSz}(#=Yf9EECWg{`e2V8IPM6 zKzL<>C=V(aG-Xs(zi19Bo^`X~T=YO%k3d$}3ozUuZF8mS=PP(wx%u{_~72U{fY zCF!Z>RMldbQ63#=+!r;17KRetERNDKJz$9Y*15~?EZ_$H*4I^6hZtAXQ47c{4@00P zBGr{#-Whc1`exU6*1H+IwLJy>RS zw|SjOtl?laJgl&>BWpt?+PbnU{X(HIF0rnHKdNe*8aO~*unD?jYsX7u^cwK#?xhml z6qO;1$BP#8cujrN5-EU&6?mz&p#@+|d$N~OxlaV07}ElA zYFga10LGhwwRL1r$*9vyF-lp{P`a>2*h*)VB?8LvZ3V*GZ_ye(sbt3EIfZZ3Uz>^iwPMfdkGBSc(HPuzMXZx)aZ>*O&$nCeBsdC$^fN=toR(a`y&?2u2Lms8c8dO7Wz1G-J zR_T?rcdty9tZ8kzp^WTDmak?LTte6FM)YTRJcP4tdcEZt=xcje%WlXk6s%M=h^)c|eKM z{i$)r98wAK=b4NGJd0rw%$re44fb;=qX}lr8GjluB%IqpQt{|-OSm$!c#?HP)R*G1{c?63{;`} zT$($02++I}oKuAM-@ed|Wli;dqz2)HTj%q#9V}^Up}P>8vSc=sH5WH222Ff%ob6$K z0}KwNRms6mtLGLz3*)Tys#>fzFvn%nWOmcZRc?;!>gJ}ZT3B0Jjf`&b#Crzh?te+g zM$ijJDyBN@C%o2{(S0m38$zerTbDrIGH7&~R$o zsa06_6kxTxnVc~fq`}D>Lspo-Fk~5sO+%dY;_NtqvW1{!C!6G+-tLxEI_(>|bOz@; zw53Ihq7%c&Br2L~%bKd{Y7>bN12VfbF|$^&RO3B~*MW1~fR#J839X<>F^#;WZ|%;~ zT3VDDSX3Nubs`&A3P(O@7=KS7MmE@5@R|o4Lg>O}vJd4>HoUiD)2@&{#>hfl*!qz4SeFbgQMR+C>I@ac)U(Iq;hf_)HK*>9FC~M$3j4M3;iXrOhK8 z*U5C#^j=Qpyyp{+tAuWveqoS)8R57#(oNH&H~9QF6OQX|bo0~S_tPIF9M=nw*H6!T zE7|3kuYO{SZsw*=|qi7&26bkp?ZLHayNr*8`T>CtzXfXYAr zW702^^i$|l`RC1M`HKNsjtj;k--wq-Xu~R!N^9PQNrL|7uCcQ-h$M%`V-WmR`Fu zlU$C^Ot1TF*HAAWWlY2Ie8!u`JDO?B(`f`#%d>5XgPVE_*mQ=sT} znM0I4+2u47gIQmYAK3K)lfB8VHX?LIKr(L{j!0J0xz98#F;deo7N=s@gXzjKOSLCf z^wJZZ|DLNDY^Zs0c;DxmFEM)i0qSEOkDs_4J!-{+CcY*L zjwcd*t_S51)|O}EbcjnlZT?+34smUM>eJG_`;@QwFOa^aiI%oJNB*O6a!nUKstR8= z|Cva%G7;O;t8L2Sr(W?6ZJYk)}Q=y`;i}y8V-?vJuu6Y zN^YT!g{$5$x3pJ)#*nyt{gh8#!s_ofV3sE_`2KXd2fuCVVu#Xx843NB-!A0~8*V>5 zAUUM`Zvvz8l@39^UKQZg;flCVl~q6g18{%&A1`(E)B0xj>#F(bDXfOWr0+}qFh*fZ zyH_yV{|-w2ttLVBuY7-sK!5tXP4u@<3Z(u|YaPw6_6twp4zWFeyxYp@?s+e{5C3lE zr??T3X}6#4vh?6}54xy49fKODPdp3lxBSWHP^#xO80NNoM|J3(=<>aHKRPsp%Ilv? zUcZtMeSaDzTqWzn9dG33=ha}|rtM|T1c^;nlnrju}#uPBcXK^2i8s8%HyjDl}M*R0j z|Fss0mHTgGSaI>51fPcsUM%a%`ILxjmf*_-=RFAUQsDjRUtamc{y#XzqDc5T z^dXPLh=AV;qktT=_jlwmZO+NlPoa~6-~e>moVh2R!l!2Ky>uv{rx<*GM(pHBK8WME z0k1SBk6%90s8z+e_>ym=&#)!lp*oFU;U%xT8~_ zh%h&LZGj%=XkDXFei zUNY0&;RytS1cY9N_k23KSw1RRHBYIbIG=?xpf9~CL2y(gC58xy!6E7Wz740`{0D8S zbq8=a^g7)KuO(=mz&|R7-!*z5gdY*Y{~5xm&no?3j0?KZeLdQ`D1J-`r#-#mCxvi& zqhE3Q%|p6~&(Zi-oPRM)@MA*wk3;m~a&=xMKH+kImxG?(lB0`0it(@I4iDjB{^N7t z(?fW;+>=9in2-JjIGKSV_&*K*bgdJ5#T|;D1vI$M=${Mmp8#T&Kl~fDVR?qil7g}w z8=@Z#rd^ zT<-BQ&k_GHzBGhS36+?T4=juKjr;(&+j_h<+;KO8>7APJ2PcN6WlU^$qhs zG6&us!fB1Ed@c^*;d)&Y!o&5VACjPpR@~D$sTGzZZ|=9|jai)yRth=S;O=Kya3*i?E2tn`9qz-gZ<*+U&bR1Nc?zhrnoLCe^dWWLqA92|1|gtkv}H=LiwnVvC#(q zUqpcGNQ0~WEjIXU>eAM9XXD2=H zS%a^Z_WiBFi^Z-UF!*mop1&HL=1#gI(tlOXF9?5K-zq*%`q{CD{&S9vH`(BSm3E(I z@JmGxvkm^T@ITeyTSPze4X)2uDh%FE0^_PS_zy%64F>;E`iZWqwZ4BA`*VSze_7hS z)!-+I-YzuwOA_xf_z|LqRR(`j>U){Ne=qgA%HWekp6d;MzsUauga1tW$xQ~oPW13q zgKv`fR)hbi@cB1`Zxng%HTWOJZv4RD2Zhg0gYOgi-3DJT{GT*J?B`8v$te~|nW3?3CdoM`YjB;IcD6QsTw zga1&*`DTNkCH$W>_yX0B!3)I>zh>~)q+ahDyhq0GzYM-r`r%;7r}{Zx>a*718-)HQgD;Tr`wfHFOS!s! zQ9XQ3I^x5I{wk^0QwCoo?e&tu)hG0RgYOkS>SIpJ{h83^i@b`rNxP3U_#DBD4X)#M zn!zUv{XB#JR^&O$;7de5iw*uK!B-gk3DH}|;92P>R~dY$^oNZGe_Qao41TlldC=h6 zul5*R`_(TD{-oH4eFoR_IQ5yR`v1C=nMvxey^+t?l*W$^zx9wZxH!^Z1C%(-Jdl0a^drg z!DkAe=MApE1N3WyyC3p|Z+e5DF6I8g;JV)ZqrvGp7G3Wde3!`cH-rDgk$WE*e5s6= z0n(4OKU^v8qWcWRFPC;4Vd(b@{ow{L61^Q|@W;i@9B1&8#GX$vxQOqS7+lx!CmH+| z=_jWd{8u7pslneC{p&f8)_1tbQ)B3_7Wo?u{;KGAiNVj7{+uxQSkX_);KQX|E;9IP zk>_HApDW{3&!bfSwZi{$L*FENSa0wzh~73Be4+6FqQUdTe%@^GHt8p~8~kz6kDfEB zoaHipziH@yFY$W~{!@|j`v(7|@Y!MTTST588T@%^_s0xgB=}Dao)P=@tiki8eP1y6 zuSCw@8eGp8UNv~9w3nU}s(v06z5UtHZ{V|0V5mn!)ducBwV^1=9bU z46b%(slgwS{=dxN#ZvAHgRc`i+-YzX<_$ILre=+!8p+9KwzX|>?gP$+*I9Ce6Ip+tW zw?ZjL$K&flKf>Vp13%*pUM==vlED{=K4%)dM({HYK1J|qga5nq+oc8{BX%!k@KWK^ zYw(q#pDPWn`^3*1{4go^D+YHz=#Jl^GPv#&zi;qIMV?&-UncthnZc{2{eETe`GUV; zaIM#S2G@G&D`J#P&tJ4&LuEWEuJt<7;99Rq2G@GcHn`TS)ZjlB`RfdRob;d17(6TU z=|u)_ly+Zh@Rvl-*BSh3v7a{^T=y4u8vG)W^LqwAQ~3PI;4@_&dD`Gp#BTiB;C~T5 zZyNk?iT~B$!z3Qn@ha`8?OtSXZTIm8*LI&`aBcTF2G@2kGq|>Uy}`BJKVxuh_lpd! z?Y`FF+V0mGT-*I-gKN9rX>e`#?-^X%{YM7Zc7NL7+U~zLxVHNNgKN9{_Ep+T+g+a* z>9`vp<93A1CyM_=`k{UwKyhvNPaAq|ck;zWm(pvy#|^IS-e7QT_k_W<-8&7g?Y`FF z+V0mGT-*I-gKN9rX>e`#?-^X%{YM7Zc7NL7+U~zLxVHNNgKN8gU~p}B=V>X>v$nf) z#S!4z?#_o$fWP6I$#YID0{mpL8&xt7Ydan#>+?kh*Z$CAaP1F02G{;@xxuwR==w;@ z)&6j+q1XPf&EVP}zGv`nNc=|zKT+)e(*|#q_^%DF=Sl|*ezoZ5puta(eMg>rYQ3gO zT=&6>t3Ho1^s3KK8C>;wvcXlK`hJ1(SACvi=vAK=7+m#vk-<;WdC=hJNPoS~;D40) z^cI8vyUa&-82nDbziV*S&rXA@e)bq#_4B;JRX?v7T=k>-Mb(??=R-rU`WYnsNa>G| z_~8cstLWhbgKPhsW$>-C4lFhJa?x|W!A}tR&NKLU!P^b4ddnJI^>dZMw~PE64gM{W z=XQhNF8JLB*K+^U;9Bl(gKN3Z7`$ETb->^?`Od(-Z}9noN8|+{Z7-E)n88(^aRyg; zW*c1PDK)r`i#mf35qT~%_%qV~zisd-GB5wu;Nt`@kgq^!y)G4dRATU##LhPuJRy8~ z3_elh{EETf5E2G?>s4X)*`Gq|4n-)Qh&S)V^x15g7($*$58r$Q>fjq5&JM&a58t& zk3X(4~ftmiu{wf77w|Zq31Gi@_fg z`tKS(%Kuq|FOu=~n;d*zGq`>~>^;Lr?NvlxeAMyy7a8wG27grKJj&qHq#aK*_>E#u zP8M9-SLHd=;QAiY`G$|mbD_b%CiZQO!QqCNubT``KmAJA7Qs~>E%%!S*Y7z!YWS$$ zo-?@0v(Ml^BE{m09p*k&&zoi3jS`&Xp)K8Mj?9~7=;`}Zbe$2Rr}3h4Rv28rkJW7W zsQfJkSNYQhk4igUk%RxW2G{R<-E8=1xpx{|%l*E=JGi#+DV~G>;|AC7lRaV+7as)pCzBxSkixF!&?VKhHF{p8wVuyhz4f zm*6VTM(O`+4gIZRT(36tD*xvVuHT=#-SE+Reaqllulo(I^?J-WNPGokO<+V;+I9vHiM6q zdGoV||6gR@ywT9BoHrYMhR}cC@X>bJZEzi5FB@F-{Eopd7da#H;=AhSdMS6P;Hqbp zXN23I+|4X$#oGx#GU7_QF?u5zk8HyM1V)awz$=U%EfuBUU* zKW}jTUZ!`X%cpv~P5RFWgYS|~bd=yKr}8<$;QIZ}*@lnmv(e!CWzIwnK5Ygsmin$T ze3bu}4X*XtX7KOJynJ5{{@V?{Ov-)2@X>OAY4Cexeewr`7fHYUa}NF=7+k-v5tSEu zwY{|5uSh@Ac5$s5{O%0V%TVVe4S!Nxmhb*NqWp^`K(<6oHY4*5uIu4t2ERq(>kR&w z#J3t;*JHa3uIr+G2G{il3yw6EQ`Z~CqBq5LJuu(kI-f2xxXwrG46gQktHISy()XD3NQCLqK|$77|zbv(8kT*uM%2G@S>JfTeME-7}`jM;N$oium$ zjFYAp7vm3?yU&?H^Am|a6W#I zV~p2ax#9K74VNFR+>m`|L-X5}H^kq$q516%^)ZAFR^CuQnUKm2^~3q|hWYqxey4K% z?%}{3&5b_ISf;s=X~D35@{>Pi_Uqp+rXu!Jv6UO*`zs&#_3R(MaMka|l_A6a$`4+t zeB{lM2qMqMT@c>ShC(123*tTOazDXbuGy6txE2T%r*-}-9m#Ls+(qTkz(?63+--00)*sBz{GPj+>B#?uoFjZ* z+HY@&f9O}lF}jh=fABO z2O5{&zO`g~xrc=9WCl0vt$bwvV3^2#l{eIY^d}!n+Of;~$yZM!$|<`kJ6YEon<@KV zFog&|Qw@tv%8HstqKkAP;*4lNCJ)^i91fyO_vy|bZ+W#qP=2x==&^@ZphwXh=W=H@%}mDZ|Ei^gW@X zF_B3_h~4l3C=K3ixsU-UWB{QfCI5h`QB=q%L}QfZqN62>aw&C8eu)2JlOf)CpojZn zGsm$~SFpf0kVPU+IdU56N41+Ygw!>^kOUYvz^`Q#>(B9sk^m@?qDM)V0pTo1OBR$s zG{;PfoH;}pSB(l-7l#u9c*5*HMI7r>p^$L)<3LB^N-@V5N^}Iw#tGp}0qcpvTCz+! zlnNGSI8NEz2FiUOx4%^otrhr+MtE@^jq(;hFMk022zS(dQ7{@o*Fu+z^7bK`&mX+S z$eT+?P|+A81L#<89sUal6c^|DH!nbBU`+Tkqu~SA?f}S#W&K0+*|vj}Tq> zoO6lVg&PQuxo{KVLtJ<<;qGH_o3%+^=daM)f_E3d4hbsIv3QL8*PGM=HEfki@ zZ>6v_(H+D`6!8rTyI)%$ z;UWrCAEz%t4la&Oj3O(G6Px6h7n>YN7Mt=aD2GJ~V?#m7#%E!So?8}0=HWh^ zZ}feH;Z%L3Eda`oQD2M}-an91_+e$?j)ByfB(ihhJ&-WwQXU$}E#M*#4 zLLSk<`4J|Y>ms`clIC{_yWIn+efIbQ6$evC>!*eCX(H){38Ug2&o zdR;_|dj}QS=*Na&Hr(#Vwn2@zMV0a+6tLBgktp}|iS6nW+uJ9$&yRfz<-Oy_UIfqW zd0N5+RCPbrLsj=<7bD+ZKlW|Nd40a-BPFdP$8gZ*?t#SRdOt?_Hu^DYsy%*;^6edf zwmlj|+{@+;s-g^|Tb6r+&KiRjcb#m|*;HLO#s*b$LvlwPR6}}p<77}Rg-;y4qSYHz zN1Ufi-&#oAiIq2~@j3(xV>jYn6uA?3*UdOYxsgWtVNogvolB41S(L?>Ata(KApv8f zS5rA`d3P!Ib>wc=74%t}Ph9XSGOjMTp2n{WUQMIK1+SrR;k)2XG#1C?7k+`h7{bpo zu5?c{_#WYVl<#?b$MOo-0KOOSeIVc6bE`odF68@Qz7OI1P`(f2dlBD<^L+&0NAi6X z-$(O(4Brpq`{8`YQU})&d_R)!Wa#j$qb`!Rek=KBP`AItaS_Zo?)hsxZMA1ZT4eyGeH`Jpm*JdjUm2UWq((u>?I`Le=0^U0_>_S?deZwpJlEiC!Au;kmql5Y!3zAY^IUHR`q zR+aoN&ZHCEU7YJhmF{`^*#nktP2o=qT9M63_f$bhuTK?(^!ijmNUu*7g!KAUK}fGp z6@>KqR6$6uPZt~+((BKdPNjRM;3lN$^!rS~xzMEQ)y3Xd$zSY-uq=6T;X@JP?<9XX zLc;nH8a&bqALhO`91{R_^RYx#xHj@b#(0c_)iVXp`K(-6__~O&auH$m3^xq1^1Db3 zGe0eXoD{nUx>vaiV}Aoy7^69J0QG<(oDURqkc!+hw}^fZcKk*bjo~>7y zoar{xo5$lb9j!Rmpdds*F|VT*lJCSE`N&-_ix)kSf-WDe@rqflXhlEbeHw3-xI7h_ zN2sg&pw{P zoS)OOL^AR|)Ax#OCdb0A9vhWfB)cVtWHYd#aXD@YNp`D|j24i6ugKU$`NR&k}?Qv@S`0foLzYh96cUk+(sM%MA^)JiY9kAgmzePoHFn_9u80E;7$ zgMJga?-kiR2G+rGcwIOs^;`W=m-*Ch8R~cYp}yRwe%DcREB{4xDRuj2j=JsibN@4x z`(K*-SS~O+Hj*Rz(Kyg!3j-1gM>j1#jw&BLB0{GQQ1S5`{j@K*i|Y^aA+azv0?IqV z6*RLyGuGr6GE)j^SNfCtqrcjxKiSgH>yQ2iKK(pPU)mr2dp>=s(mNfLMx3=+=84`G z=F(eowCZi4u&8t_77B~`8odB2%GOR}q`_VjkF zf-CAzo(VrX*_BE4!rT0`b`N67qwp3Ar!(+gn*okWu-733F~`#{fICp!f`!uHpKvOB zU}`+mgJQ(_W9A?(=&1 z_1Lj(OJ>jqn4X?DeA+|rt%}veI{w;wLSFWlXXX_a?_4qy1x?p~VlpFdP;B0&=%+_T zPa74xsclu;s-=1Jz?Yhs3F9f@nqngr8$?b!?A^xl=&-l1Wy~c_jA8 z>MFFnw>#O|0&mYA*;YlFJsD30Xuz~GO7;-w@?>vs2mLI37X@-M9 zFph%WL}t@>8oCY<=g=6g6K_I<3QqT=T0Af(%2+Or{s|(P5gx)XaeB_)H<`su_=t%oJ3;Wjxwz zgngmXId%}otl^9gn9?aD^eC=kX`>>sj7JBD5=nb>1V|C*WU^(sM<<0o;L-XCF_DyZ z3W&)d&Umx~KwPyz3t~k5I?%ESaq6BKkCp+5h<0c?LM*5m9lZeXov+d+8}YEmZrT_D zVi%d@!JGDsh_hG7j7KNr!XV?(Za0+MqirkV)G??LXmg6FI@Y8uD5Bzf8%}Yt??T-9 z;-o_XMA%;dxv8WLGvbaF;&kqSxUWCj=_4-8KtQKW0H|hZk9P2g5bLx@hf0V@9n&5i zn;`C3r9IluBI-&?d$cD-R2Zi{I^;%NJ$cjl7NX)K6Wtk4oOH}9_N#=5HWZJ?z;!56{MKgonZCDb*C%+Si;rqbckVZ}UrS$ry9oGVPqnItbTIX` zOPQSOdR;e^_)~Q-G-bRJaSc0nZObNmTiHpc^Qhr_mmvN za#M$9N0cSrs}qUU$%|51_>0DA0bscEO*F=9%bBC|226sHZ|ADo=0=~lcr0e2wOuI^ zc#B2MIdo=NTBx)_RRsB3`B-1OS678(vj?RQnIH3nYMPs7A zuDY6PD7{5yK>*sZ)c%89-SVQ*dK2u;yf^LYf-V9F!p_ybKOn)xA3-DyyPZY*!OIFo z`}*f)N5Ldg6}*)D?wAQ^OvD$(Yn`j?1*PQ`ecbI@=efkVwyr$Bi0b6Jy3F86Q9sGr z&0TuBKM&205Bz5nA07AEE*j(TJkOqfF*)TJ{NL}*4 z`Z!;_gE?rR9&=fEC%aOI0?`9pvvX(;?TFv*+QUAF-5!CXQwisz`Z=G>7@>!H5!a5Xt>-tcbFR)l z+EFWYZB8xHw76+O;}WmSZ&w(lZaA}6P1Tmx#LE*r^u%8}>cB3Tk-M~UNi91|Cr|b~ zs!4(HgRY~RN~l;+wNMqty^rPgjY>Ehk%{cRt--j9lPxQ+gS&gJpe$Qd-I&>(H)<-6 zByOs!tFD7@>#h~8tYmVQ9rs$2S$HTH4Z8WEvpWsDv)p4HV}l6KO9`B!(nLZY$E_dg zmhLRg$CdNPI2p`7&a_o_>EYD9$bC97b4|(;N!T?Qx=ndigGUw-?yG!n z*yJV4soBjRP<>Cbb%y(x$)?o#VrO;KHP&+*#T!a%7sh!Q!Y-B9om-0xuHKNrS3CDJ zWQ3!1${t@_)yPJSY8>v?JU<1F-N^-)=!T})mTv6*!S)c(-o$f3GkP2X3*$|0ZmXzs zV!`1(T(0+7_y&t$R*8-la?&1BJz5I>*GWgbSyyiHntF6hQEAAFIW;fuBf`rOVQIRS zZ#t+re|=2Va^vsNK?vW(#buwsQ8;Ws7Jin|2(-!}k*mrvccB=W^)TVOsUWCR>B7>g zS|X9=^7oe{9It`76S<)Dp?Fg>e8`uURiY#}=@J7rQ@rR4xCJ|5SE9(_A_1AK{iqNu zxv4?nTph`}U`?%D(E%s&c;Nt0cLq-2X?-Iu(z?16L`!{y{HZx#@!VUOQEgKLb1bb0 zy4LE8oh_#XERj4JZ%kKPx1ibCeN`H5AOcyn$9BP?H81tiM=umqjoqitg{UEAsjcI&P*>06Bs9FSM5!pP2`WM?$-f&b z3xNy|RdRIij0(4j>#e9HJkDV&FJ&yIB?$^cCk^IX>DWCTJtpBf&;D55L?9}4PFa%RRfgO+?8;(c#id@p*Mb-?D zjDxFodTK*{n&_V{{yvuaw2v7E+Na@OzzFE>wB_b_9 z8}NTn(yPMh(Q?0iej`e0XjRnQhk7)?DDQ8);<>GCmwykWN)&ojR+lUNaRgx>0Y^# zrmAUO-I>%hn764|Fyny3$&hMKtmp-E($RmzRSX_9EbN)qd|-6h!!DeX^||PYvBijB z?pcluFLLrl@5E6#dX&cRwje%HaA`Wk+@(GQG_IevEIOnkp8vP`XCSYb1ucR5tmT>aQ7?*tXqvgO|ZtiSs2mGY-kCS0U{Jl#8_ z{4KzUr_v$F*UzQ=9-MNAFD+j`zm3HH@|VqWx!9J67-&BI{J!K5k#O*0$!~GZr}!QO z2s7Q(TO;`on)cKFr}=-3K!5u4);fy)!kF|o3jdmatV`za4wxc1rH2=Jp7)&4>4%lS zKiP@4@(h<_9Uj!sbvXX<0P>LX$xQTD{+>7za9wCBXUlg~hu(=U-+Pyy%N=s%9nuRO zNnXE_kbFi6;h5*1!}r7A&L+xVwI5`mF^#9)KEP{l#7JL+Yh0Rx>GC|vb?BAnzF=}l zLLQHtLtxZv_@N+>JomcdA!&KsgARc~Pc7T`nuKV7+-Yw>KHhH;a^5Q-T$+QvR_JM* z(8X(We4da0{`hwTC;lJcldj|3hqn%&{n3*g{o$K|6CZj9g)Zeo_M$)fhkz6P=|W#Y znQ;9K|NYUw2At^E8~*R-pdSP}qW?FcS3QhHyg&XY3jOm!ukxRfgT7hl^~F=AUy+0U zGNB(Q_C@PUd&&Of`IgWpgi4T3Pj4qjWJo+wPf919aeT&em9(r@oUm^6@8v4)Wp#QSa ze@p0jF9o@_ALPJCpuGO{c3cj8 zUJm>m;M6YL#dIG>mB5u0{MQC2-;Dj0OTUFpeAK6%^0_4kJ-uN;^b-cS^0favkc0jy zp;sSuyf;MF-{qhu--E<|s7x`uR|Ne4)TclB$;UgFB zCAqBpu%R!dKId`-IF;;&Mp2)SJS*zUNk9kV3LvEYopv61_M4L@6(Wk@Pq6A(R3<< z=Vv&j(E9uzIA~4!kSeH!+qfLq_sJueW(gi5^`Q!2CFC0SpeFU2&X-g;?qJn{rsBZ>f@aFgz3)-(T@+&UlhW_^tXm^I=WE)TSIu5{zoCa zI7ELSgdZEi{}RH(e1?$Vxai|}{A;=D8_3qHBt$NfrY0a(t=Z5ewz50SD zdOBNE`qd$N+S)6=E`*2qs1Ii1Lvy^+-pB}=~A)JmBlwN;}kK{Qsgx?;bpC7{Y zw-zn^Q#t6L58+|?{~W^0Li`Vg@G$*ISqDPif*J|Ois%$3i((!L7~{bG@) z(crXyq$^?YuZx~D27kqodsiB~P6m*EPgCVlpL=>)vguKYI|T>0y>ZsmWJ%pZDwrT9;z+y@LFZLh}- z{xzY0&ft5c-G68BSz>42G`RX&|6c~z`b4Gws+=(j;2LJ|H4gTUG`RZKo@ns>BIitl ze@VvaLW92|{2L6e`q%ZC%BlMAF!Tq6zdoZ^dgXJSp;tb-9#i@Y#2$Xv&_5{se22mB z6Z|oQ&k{b*8hnc2ZyQ|Y)b*RnqjKg+|5E(xlK(J+za#yj%;0N8&T|Z|J~J*b_*o+7 zMFv;BtTFgp5)9Wh27g85{F1?^IC5``!5@&guJ^RQKM;Ge)6l;r^?K6aY9C)P_)4*B zuN(Y08F%j){O^Jflm4ah93lF_4;=EPxcb=ml)-n&xR`73aiX6JgP$t&O$I+l+IP9Z z*9v`)!G9_Bxx(O;Vi!Jd@B`8=Up4rnQtsUbe^J`yhX(&h+T~G$4;T994BjpMXP?1$ ziTr;u_^}fI(BS3Te$sB*F7;CGF$TY0@Hqz8ex>KG%18TEt)ahA^t069$4WoxHTWhe z_i}>^8}Hi&KS}7-hlR@1DExnI=szX%=^F;G5d2+(Unu-PG&t>b=^7~gOUr#z^gPnw zzmoh%8C-p~PdE7MQsFrUS09t}4E}YYUtsXbB7dd9)z_%{ic7d1WFf{_n&P*9wFGUF6jDzLr}clfqwpJ}Up$ME=hi`aemz z8x2n1m!<0#ga2Lhx!K_A^Z6SF-zNO;HaP9=>H4n0A91kv1B0ut+6N3iRP>{ERO|aU zX~)M6{bwfG-ga4<*e`oN4Vn1IqIQ_^ZU2ht^SLAue;M=5L|I6TK z%DDc};6>6OqLNSbP$>Lk2LG|hIn3bSlYTPV;O9vENQ0{nMd3&OwL;F|v|gS(&X@Vt71zbW!BGI+k==NtS8(f@LTt5589 zgR4)SE`zJ@y^O)>OTTnoV(=rRzUvJBY3Xm*8vI(Z&uUjx&zq#5e96#XBK5t^;O9wu zecj;nOQm#a|5g5ZLicS$KV16r_YAH+T(=wiXz91R4Bjd6pBr4)E59jwY3l>3&!7YY8Z!M`Bw@`1tc61((IgP$UL%ae4~+a1zggAA_EiHi)b`_(Z9uNQgL z7pL-9`#!vM%k2G{e!sRrLe3~|je__Gf7PBHia(c75@r{~dh>3T%vd`0*#G4y*x zkLnv#>5mh-l%YRa#;N+YR{D=b{}&s2CynQ=Hn{#u)#V0%P2^v1aC%>Yt_=piS>*qs z!S~4c(sLS>^H(xX?=bXN37_v6e52^?euEE^{_v>5?-2TD4StQ_zc={35`WX+_e*_0 zF!*-`&li65K_)==n=(S#346gP0j={BFI}EP%dfebgOaJ+W!H<-B={Tcgl5?i4 zGu|=upG6v7|1$U#p&u%GRXzzRcdWrL7khhx!Bw9#4X*msb8+Rb`m8qes?Q|`SADK9 zxau=)aMkBJgX?+a7YsgA^s?FD3&qadWAJZ@-hOECuL=HRgR6e_8eH}BTZ5~9-ZZ%C z=L3VQe)6T=RL`oP5e8TNX#Z0BDMELmp?^r?ry5-IR~p>;IPknh245!qCuQ)9#SZrv zyj}3i4X%3ooWWH;w;FthjF)>1ez>%k?!#0M*Sq23{l(DhxzadU2PyqeWS-J}yy8j0 zml^s$OSvlz{#9w$OANkE?C?f|zbgIn>ju|y?=iTRyWQYg?qdema(`v;R;nPbHw^x+ z$Ul6TOIJPUbA`hNr|Ced#DvEfT=#L)3?CgAXBk}EJz?-oLamm44<i&?XPCkD zee0tH*LGC?Qw{#0=y`SyKJyH&?`NNF_$dGL4E`;Ve?<;HT?St->y66|ALaiQgP$aJ zX=@HXcN<)v=iP7kDE}u6uIrfRa`1V{;QIXUfZ=nA=;0%SzboUhKwdu8_EkQ^46g5& zA0@c9ukxR2@CmYBot=ZvJcH}|=w}-~%Ktor>w0lT4nAE5Pm1xl-0)HUUop6z!*0#N z=Wc`R`|kG}KFa?IgR4A0%faWD2G{3{uNywf|E~t0F72*g@zC~FJ~4SALvekd{&2x< z`_3}>UYQ?H&B14Z!S%iTa||DqKWXrviTv$3`1BZD-{Zg1@cF6O$r}y6O2+%02464p z<9BoL|DnNK#18!2@cEbE2MoSI#>G21_#8C2et+Qbk**@zF7;x!j}~0pQRycdT)$Tk zH+=4r^-6UP`X+zq2f|~-X-`j!BziHi9H!(=)WxV6Ak@^qMvDoUge)-aQ&V`-0;zQ zEi(9BvW~hS2cH!N*Y8DS4Ikxyt-)u@c>h8UKDQWLzejPG;iLS2XmC9jcsK{2#|^IE zyLjI4QU0$PT<6)p8eG>i5&3})ZFl8A$l!V|H&$@%4_fXdgKN2S46gg`7K5KJwA447(UA1{YG^#PF-z--vglPiz(+M4S!Nxrc>VzDF0#!(C`oMN9G$`_an;;uKR^` z2G@1|R)cH*+-2}1#lGz`xUQ4+{W_IX*SE!zPjOwB&NsNO1D6?G*MaK{uIsn02G@1Y zE`#fOX`jJ$eWJ=$Idy$fEJ{~g*A?>(uIqti2G{v|oxye9+-h*0H+LCa=fQmj*Le+J zuH}o8>0j-9vBA~O&o{W*XFdN=K5AFj8G5x>TMe#uW0%3zZtOF-j%)W-ub%GiPUk25 zV||3rK553xV!A%LkMP^{Au;qbAOCb8hqtQ#-}e!|pM(wh8sGmT0vLU(h`$OL0F~~Q zze;*L-pjnA(G74v{@Ke95||wlP`@>gyx>;eFdxp&oAEiaa>Hj}W zg7vY0kMb_M`U#Z49M!Xi0_VvRYs_hN@ z9y!VhG~)E7UgMvb&kJuy!E3P~cMuBrKfyG#mInbagr0D8f z!QP2;1{(2+_=jBHM8CWbrM!Mh`Oq)r!`^394Q?bAX;k`6P~jjHuBI%&JulEcTz&iU zl9zFG9(Z8i&7eH6_0R8Dm{$sKu|+>-B=Pt+EeHEkhzP=j^r zsHRZ!3MRf`-SrfArqWL)mNyXFX0R7aw}BL_*0fJWgy#+DO6%WT=V#!|)G$V*w^jm! zW{4O4v-QWPSbv1bn&HE@{_j*ebG{E5@b9_l1rF99!dK^NWl%iMBn`A zS@3fDIc0bDT3?^&An2te+xq=;AlzVpA5xj zkJtf?dJnvf+o8h>WuTY4$!)mnw*(CrNc#|B(`f)KSbzCzk7dU=>E;(dOkR!DbU3hb zI!L^XdYk8NL)GhzL~f^0pZ&1>AA7sc#SpSNQh@3EN)Zn~f zJUhA17aWuCfJmfj6uF8om;ev__QoxsyKpGHh%qLE`FlZH@HqXuw%G-nz>&f*Cj zgG}Va9&X?%(_s=7c@EDH$uo8`_>Tt>yvS-n@Chh_F}HC-&yn%dBI@csa65n00GAg9 zM6pjj8c`}=qrU-M1ddH2`-;av%4v=qt4>N&ij3;m2s^tCrOr%EL z^Wyyc0rbnf(FkwvqfsV{MtG?gjq*`PG@m~>Z~k1$%fSKH2Epq(eDwMtxFI08AwWML zpf^tSvweYr11fNP75@c96OnRmrlf%}SLn7N%eR8y4=5Om(O2B0CXRZSUu?mGO(0>k zVBt6Y;5pa&!6keAU{?Vc4MNl#K5*?d2-BH|H}Db?O~RLQiH>1xCW-6lV`u!Q(#OuE zpren?r*I51($5637_m|ca<0j-x=Glcaw)NTQi6ofA^F{lK(PkG-ItAGO@t3|^ot1} z?!rqcJlciNqZhKrdV?p&YR&<3KBbPO9tY@xD+08QD&q|x_0eeqYk!hR*-nxTogQ07 z-z#^VSBE5A6OwQ(k%)wsP*|k8l)__O-pl@kl8RmUa>_f|g|DFSiP|d%Pmg8jeQzh} zm7U1%g6jhGvxkuyS!fEe&?R6HboAI&^t-4|*&9jbVRYm8puuJM9E7Mhe9%zxBgA41 z8b(107g3m+jK1;Cq#FxMW@AIcq=nPz2M8s668&hFt9jw+|ADZpdEpt<(_GC9=Us4^Om8__DJM>io7V1 z&roE)L@p$;4?hQ%V(@WCgOuv+4LNE#?oKU(|NTm>>)`w95Oll-e~;j( zQ~Vc|)ljHuDI)xgbo$U!ql3{5d;&Q1v?x_jBJ((s?@~_ZNX$jf;K&dcIWtN^4tJ6H zQ7UGviw#+j9BdL6Wiy<=%L0tevC>!*eCX(H)i$4UeRtYdR;_|TLb&O z(T{Dw*xByKZUND4QKejf0=D`w66L-=v0Z&)d;7%p`LX+;xOe>6IPlz_rzP}I)&1Dd zsp@`=zO%8{k4+ltdDpwXff|vL)(r@Ax!#XazKwp2nre?9qkQ=7*;woZ5OG(YJFJQ_ z9M-bj8+I0d?Tkm&u(PSUZqyE|=7w~54e8m9!eO-(KJl;>t=_OY;yhjY)@X^g zUqCPxy9xJ^k#FPfx*3NkH_}KyEK23DbLsn^EXv~b2)RKuYzYY%J8U(T!$y3UWSBhc zGe@B@onRM~(7f!zi3)^8_+`|uhaZNXFf7USfFM(lJc@28o{Egch|kCfWn+94RR{1% z09-{bA;bkQ>%ylCuAA%!KTC6=L$9KV!UeB6$|v~B6rbR$XCiobe$f}^L0&9XJnu@r zyKscVQNHK#J)iFb_+G&GfqakgeGuOZ`97HML-;_U4(R?4n z_rv&pIN!(e{RqAv$@g)5AJ6xr_OTKbh}y`F;xDPv!e*e4oen)A@b|-_PXx zE~oTI+{bQdxS~z;6$CWVeY>@Z{zn_fb)Ta97ov1Xv125REQ|YpDTVOc^)&c#&n$YB z%)1LdHVfQ&c8V3<5uxv9ILmTpg!-pM?uyU|$d@dS)0?lHWq#4?k!SoYZ$vgzUYGxk z2w5MQ8{UZg3@;zZ-0((()v9DPE{iq7mP8|DkmpL7PrsyPt}EJ}Plnr3?Z^+6xg$SR z=8pVOnLF}BW$wrimANB7ROXI+F4M7oApaK-dY2URK>h=O_xZ6N)NX&Dm`+Cz3roH&Ecv#uGkP? zyFz;X8PlnB&lJ3XgAtwdpDCbeLiOrmI8k;T_rk3z4-F3%WlK_~5D1w$b1beC{=K{LdgJEjM}xnDGvIqwqI zM-+^JblOZu7Lak!I*uzi7xq%?IG!o@%d%>GK{e9e@nh5}-uGj(QQX1EnC00OUeS0i zZ(VduXR3>0vq5=%bWHaOPCE;f8>3^gaFKbf2v5i+)cp7Rtc9c>r}#r-fSv{0T+-k&sGn8NeOLk=;6g#(}8xwgJ--ktOa| z1~dga{ptWJbS~BtWLx=Ng`%~QyTKzC`!4PyBV<=bQSp*`Y2zUeFsEDL|Q{_$Gv8Bpu=U$XF!CVn^dXGV&=Rq#F?G_KxQ2$ULT@x9dhm zYKew!prOv@Xs(GYW11CAL*1Nd+=9uGTpL->BpaAy3z6`RWEw>s91Ll!I_ldZ-(%|g znR*XV^G#|%#uCdjRQSl^q6hLvqGcfq8qJ0KL}ZK$m68#ovEV_o$GH5W_Xf}~;JNhw z=|z{Qr>I~o#Er(Vhhr5yQ$X*8xw^Sl#`EZ8Z<`mL zMx#5rY4HSPEO8l^O}N;LPN!3ifXSkM%Dae|fOJt`(hK?_-3HPL9bPm+Ggx#}>jXH% z^rFkihz4a`+fT-4BqN_3MmKeO?rX-;E&b4*fJf7;;pi6CJ}R|UD&tf%a zT~2gUz5DU<=smoy3-shdkx>-ov$NCZX zpFY>e$WG;L+J2>z>M_ckx9JC0Qky*P_|`kVPe}RHLVKLrmrcNaF8U;y;^?ON6UZr6 z^e0+8{jjDNeYu~~=N#rb%gc`c;tAAIqp#GuZYy19e?J*FNyhz>(aF5umDuFi91u1q zQ1N#lLu3%IQYh+9gb3u}G|U@899@5o9?a1K(ZjWAWnf7Q{LK|q?}Yd}%{tLdl`i%V zns%TP&%MDGjYV=WZvyklT>V(Ywdmq0BxrOH?~XBUU9^yw?bKggV~nG(s0S5u;Q00Z zfJf0mi={l8#)1Wpc?iM;U@W#0IS0_~=SX0Useh z3J*uwH6^pB&7O90Nk>;pXSOxv$oq?wEboACI_4(HCGbkvZOWDlP<}wQqBlY?dk1UmCT@!PnyYtyFfVQ>q>S`YxhvC(0f-c6i;Vb zTT?5L21OtYVuYb1cFBZbeh`G!qM!P8>GG4kAu_nioXWl$K~O-oyK%XW3Fae1?=@QEo1O$D*smG?m;^7@u&`KVbtqfPn! zk*y`K{^7e@9*mwaDt6)4U+sK9w&c6fC8J_XVoUO}i}QvQ&)B&oI(yWXEi+7_#hP8vFKc5Hn%Ha(WzxpQaiy(Oz3 zjxF8!!t|Xx>2GzcEeg*bXcPDnY^o%$f%Whsn{aLjds|9KKjNjF-EZG+JTO4Xl}v}Gs91B z??s7pcKJ&DN;XXuKE|2<4b}~aV@ISO88aX)$*z`EC-dHm&JpmP4U9bd!Y^eHf?0IM zIkOR=Lw`6}PvPg`y=ys)^*_R!IE>Xl!t{Uv&Momf-Wl(k9A1e*gvftzqzmKpBE%lz z7&a3K@6j+9@+!xudn4%`jx6uINW`H>3h?6Gc~MJO2FV3zA~+$IM0z@a82UK2EJ&p@ zJ|`6IYeWn>?Q>Go7RCucyDVk03}Gsqy~5HlqW&Uw1_#x|U*kHMozqr&h83iVxBAEX zfbMtf)BNO0naFS3dvr3X82>DJ#-r0rg~SytnbEKtTzWJV#M2&~h0Cntd(=$S}5 znOKor+0nTcdZFhZluD!DqX!ZcV3%=p=1iRjPAyxOd$jbFSjMAcWQn9bIuNFa?^&D9 zjeWqQ9Tvs7v(bJN5%L7<(Y_R6k`a4Mh(Z$>0IACt_mx-8b zVA_Bp;u@Cr!ibP(S@tJOM(w54o#=(HLd;nLZ5vHvj!aSZalw6FQ zKC^3T+L$8Mm5lbGLnXxhMxc`e#|eqF5>Zx&(o%$IS6~Km`~lLA5nxyzpmZ7pRH^`g zP9y=4I?^7U@*qMLN_%whh=^!5?a|R1;!dKpN4q>koxo|24tNj^7nk;E(+|*@Fpsu_ zh><4 zhX!*obl{I5Mrb-@-5_2?W1{A4@&k_I{9XV&UQyay-Q*=Z64bBgyyg&7)RWA#vu&WW z9m-O}E`Jj;evoxVXR?hQ67xuf1S_egq?D?KwWZ{+o}J>t{wFg@Hj%x)<6kFRS!GRK zIY}Xe>^hgqYN&%}W(qVml#%mkHEVrMD7QG9uSBAIbyupF3va^gTjP<6h%=_F?k;j% z$?Qt28siO%s>g&YN{vWoZMY z5oJ}QG-cqE1#nI2VkoSkuA$NMJ0MZlR9DrW?L3V`ZIY&*tI5Sf2RvwBlH&eVUsqjC zMWDZE5S4?&<3{!~-O}CJ-OIk@*{q;${s5+u>Z|IVb9ks1PT1McGw^fk8rTs$m{zO) zqz`pv)8uU0l^9K_U@Ibk~OU@mt2_5 zwR;c+(Q=YnUX2_I7mMuHW1%%8mscK#y35NO$Su87aYGH|Ctdmmi>1Z(A&D+0&U>^$ zD%`kKU*-N#p>jiOOvk#cxv{CPhIqT-6ZjYhxik6_;GP|CUeVi~Y;7S&+vGN$s#{wpeJfsFS6A<`rRqwpPOx>;3ihUw zflqhjq7fM{(=JKFox80oTs?&ocOooZP}k4|hvL1rgfkz)_O|HC(#wE37 zlr5O6JG;Buiv2!JmO^XR5O=Q9b%ao{$xN2}HZ7o;us+_vjgO&KU)tczK-1!;1&vEQ z_>`w{gmF%j1+OJ3M3W<1ZtBEvRIhDC1HU}My`u;2>pQyIpgAsw}bQLo^$wXHMT#b;oeNb zH7)lEo;SO**jM$YdXl{<-_E7hpkml{q?2tanC4WnE8FAsX~&M%&VXDSQJ2P~p0fH- zS72$RTev=e4op@9<)*MhAVJY4e)+JR$=2!I?Rz^=DW{XV#`-c2HI&vajCAM%^U8mDob1iEO_8|-J)t=jNcDh-rj;E7&d~sD{6Boi0aBW> zVm?7Do;iKS%;~dc%qpJTfLXdSnQ{2k8FQvUZ7aAjVF)|YT=ObgXQ6OeMr1(ZHr6tg zv7zJ&mo6-=swGla4_1&1x^}^2++2%+hGim_6stN~Qld(j2*}DyPvn-P3+YJl+Qn6M zo-0H|a1no#>vjpKqwc%3Q&rZTTg!rhL3?*P!%IslfQ4f5)Iz0J(sYx+i%&@H&Llh8 z(&5-p+?J7`Zi^%VQUlgxZL}JPI{0wIHA))mSsYIiXSd2l|E?%6ZE{x6^>?y1PO{o2 zH`kX|1Y=|M#cshu6j;PEVQt-lW~{SOy0!ytp=d3hkkRh7w0Cp{b7Ln>tq|Eux5F1- zv6@Y{>P7!2J@B$9I02$T=4DnTy3(l@7~}3t$BMP25;sJ60N2&S;6jz&YAhFsN61FS zORFkMYl3P}3FzglX9{H40FhzDxL*#B@|Zc4{bE`Kq8#-4U{TVg3I!)Q&XU2?)6tXS zw!*yCfn`YAqy0<@1+*u6ySrU?tE_7b`Wx&o)ecsHC*gMJgO^ZPbu=z<` z$@3JE^T7r6BM|9Y39y_H5!=#g>Z(h)h|)4_GAM+4)YZpp$)KT^K&N`{hmPx}0;v^m z72O#Q4{jEZIu36hGgvC1qfs$1m6#aFCS!|`>Bb($3)x3kB+oUyaPvp)h@we>p0}{9 z?9}4Pux?X6fpL@b0359H6}hCri>w(Q88>7gzYtH4v-pt~J`+SyI&Ap0(Xych(WRhp zY4Zrjbu!&Fy_b{uQTO?Ttl%1!CFQ6jEobW`5Z^Zc^^ zH+Sy>UR81Z4exUjk|Vc-n<6L#1i2^y6afJ>0S=zXC6SAQ+J+{CdeRcwdAh}=3h{o6uuab+tLJ5y^k7Ph871Us`LX`P zFqds<$2L>G7afoyxEF6-99LT&ui@J^fi5x~S9;SC4Wt15p^vQorV(a&66B5Vg{$Ym z2X!!5+C0i^s{Y0+T`BD+)Q`Gt{RM=9r>Vxe|p?h`8!9sGMVwB9Mf|8yG6Z*eWB_%11L z?SH3~-)RbH`?dVr6lqF-HKIRWUx^0#qsP04=?^-!V}~H`q0@1tZ?n1||7yfx-C5Z| z%zwj2zw2ALqFv~xH~m-n)qXI|HdTN61XoUd#<^6y|1{m)FXT-2{`P%S`AJP$EaYfP z65vf~7`QafRFZVqYUl`({MN?{&~q!A`{G*Vy&_>)7lCV<_lSgHKNJecqmse?foIS! zf{uq%C=PrkKni``k2jKjfiIV|@);}mO2M_i&>f&(D|m+dUO>OV8zh}BznE8n?=X0o z;JXFadKXa|?Y&8G-t$uYD#3pxIPZ5UzC!S0#Q0`PK7Nwi9~1=;x5oqjONE~Iy+pBw z{sZ4AUH?#^RFa1oKQXMMBgajjO3`Np|ApYZUnT4{`X3@W(Qbs` zG?m0(VRv}&nv_5l&q>k`dd4A+C3*DZvx$)8dst1(OyU_L5ko4;y}+K3v7b`f*TIax zH-jH)25(8G-xMGG&0|wI-o9%JAKDB)wi$eUGdSkUrud)R3_hzFe10=HzPZ*E|LdE< zZ*B&^rx|=b;qA$?%Edl0J`uJyL%&1lGg2I#t{3k&Lw}$d9KJwNZ?Q}m7*_}#1P{r6 zn(wuc;m%{^r6?Q}-~fR=&?8Yjk8Y0Wy&jxv@L@7P*L4R1{!xw|>DZ@P2}k7g%4zVS zCz!_%m*rrMPod&Z4E$4dqUB=-IWR)mz@waal24GEc+8kNbnwujd^%P#pPN!pNattq zqb_|u#19#8`h+Y_xU;D^Wp%mI%Hu~m@ABx`P;vPJI{m3A_2w3o5rtn~73q%DH02bQ zUqlbS=zT=0OMnY2O3S_3bXXOya8@zhM^-HM83xi$C-N2Cfd?<;;-uLHR|!{pi2SGm^$9g3{0Al;>p$4*LG|U+H6l z+j?sP^g+FS6TnXh@JR<_3YLFA!L2-*0s0{SQv!HUpXUm$a;iQHo1vd0xYnD&(ve*S z=!1H@$k5Le`UL^{px&+u;E=OM=<#wg0_w$nTf+?j`V$FM{r@_E4+!872XOGeQW&X^ z9b^abO@_Wk=wC9p^4V!{rT??Rb$|G=;Hv+%!e76^iR_>}2Mr&s7hk(TKsN5JR1a+e zIQU#k{}DPigLgN04O5eC8(ihj6x_;>cgqp1o!|{h1jsp%{;QnX0X#VWj5B;@QW=Et z0s29dRz6b$c#zNe0UUbR3MLft1y}ji{%0F{#V>4z{$fL~dcIC@=mBm16)L5mzRiIR zrvEDcZ2>+(`R@(jL3?=A;5)&b!d8Rta4YbKab7!{x<RPXHuM=FrZ6r* zk9$0&pBTUqRr^2J;5C$oP+)NFm#YO=d(iu)YXi7Mna`>KAKa^|JbyIwGnv}+J`B(Y z=l^e-!RN}YHu|xDfd72Ktv(kvLw~*C=tuC<`^|L$`k*{XDMUm8v?tJiZC9rN9+c<& z03PJ?X#fw>tFK!t&l{f}uaJwF5ph_`5>?H-j%0Js&do^&)2~ z41t2yd!tKw`VDo(pBDXhH}tcmUHuJyu^i-_V(@2o5sOL+H z>z`*982U9JprAhOmHuZU&tgO04-XS4TxIZ&#co#_yhPHs8a!9h_ZnRFrO#MZo^7sL zZ;PRSR{HC8gZB}6{%G)(qR;&Xzedtu8C>^sNuqC+XQs%LX7G;E@A?gUr5_~rHptN9 zTnb^N!3)IR#uRab;hW>WZv-+A)`ZEQm@6mEl zyr0y2mcjM?i|Gch5&B|-|4rtr;C{Xb)s!jnEj9Gdi$1S4_;R8Dxxr5mJ=|^Zv66n& z;OZlDv%xPw!zs}B_&BH@^gQc*gX{Wtz~J~WBf>WZZz=P?-d`yHV$s`iGR_pgU-UNE z;C~T5XBd2$jKhfr$6r(;=>3cGKTr07rH1}Cp{L@kNU7&Z0IkQdapFNsKI;K;O&HdtHB?Ze)+)Q7l=K4 zYVZrCU%oMTj?B*~QcmUHDfAN!-a_nTy1`3?Z;`?Ar@RQ|2Hz(5VuMdp{TO_o@c*g7 zFBki`#o&8od_7?BZlbr}8hozk;R%E9lKy?h;K?HA^9Dad_`hWEnKDnlYVfu)9^W?j zk(x(}`M*4A# z!PV!njwjW_QzCz^p`Ro2Of&eqqIcczD<6GcQef!+CjC3d;I~P;)UK7!(TGr}H1xNK z{VX>4ZDJ2g4cod%yNc6hJF#jbv1 z@CQYn#|*B|KQJ@O z_b_;8k*|-ze<$tAH25uIC#M*^R`Amd{#)UnXYgxeK0L?Zbt0$kBaq#L{@*QnD>U@_ z9IM3O+eMyogTE|xRb}vD(%y>=K3?RhG58kYf0e_W7*Aw+R2Y46b&t%is@6`U8W% zDg5^u9G^Tx_|)JIrB8VpyiwZqjlq`)e?5;!b`Sc0jI=jJ`d{&|ly7bDbuzv>7`(mA z|J@A!zSw_1gXf6eh8R3c@N9#Z2|mf-rwD$5!OxKN9E0og>?(u*RqXR}gX?|nbq3e{ z?Jo?j?_1nsaJ|oc%;0+8y4m1wNxOC!yjs$FUatLhq2PNBy|(L1gKN9OQjhY{cBL6y z+jWe=wOx8nseH6uLk+#QYmCAB$vl6y!S50~%s05cpElRv`W)*LgHMrhbdAAFq~041 z{;iCQI}EP+{Efj?pSoXDJ*Ylku=FxcRUb;P`qcYf#Z{k;hL4v2hrw5gJ-3qas(hXi zJ2=|lGi3hkYw+!&x04P2tl(J&SN%*hxa#LTgR6e#7+meG%HXP>%MGsjxz6CKAKmY$ z9)?K2-)rboWFC9m;A)@G8~h~E!|Mju_Z~hlIJr*Z@E3!37yKK8tKRfEp31NK=_u_` ze2VmMPlM~Z&j5o@mwm_xgKNEKT3qaQs=>A10)uP+mK%JT=y|!p(;6&oGZhgE?-=?Cg6}oB>fuX^iyp#KkMdVNq#1mk+;1LZaMjN#2G5i6 zn`iL%ocP|44gQU+vt(rpo!a*xPbL|A^o>8C=KLI)nETdp&6IRidwybSHq; zyIbfx8eHw+ID`LL_+%RVJei+I8eID;W^w7SX$IH+Dm1wEONGI!WuCm$;FTh0ox!zT zw;DWK=8X*o|F!hjhX${eerY2wQm8&}7W*G;@Q$(`Of&eeMb1SA*T28G+u-YEet6&D zZ3N$M@MN*Wg9cwF{obN|qCMzy#GVHKtF*VT!M~SrlxgrBvA-b(UoG;CF!*xOPnN+) zNxQ}we7DFm!QlFwW3s_}iG5Bt_=jSLKQ{Q~(l4_NzC`TpLW4gB1E4U^;QHS10)xLM zdb`x%_e*=PF!&g6ya1;1 z=(sq>;73Tm^fUM#8DCQjuJ1jcCpgScmKJo2S7>nkJGF}pADs_Z7+m)ucNlz)*wuZ_ z@PEYM`u^S~!$<3V)!=%6wX+#MyAA#;ZY{mPX82qr`b_HR2vk2x-^$=RPi70Q{WV_n zA8Up_&*1tVW|`r$PVB0(8Tv~Mu7B@#m*I1b*zNtz&_8N${X3&q4WF3w6O`j_rWpF(QKi=SrWPTVdxb~OUd#b_p@1bIbkIFO8;6*aO)foKu zf?wSX|DPIM-=F-Y;d3b(PT>KA|4sC~)!-`UcLpEj*my1Q@+bw>gVx)|;QF5DFu_&- zjiS%fo1q_PaJ}y?Fnm=0B?kYE%=60wd=S<5VDB;XnWBf^2Iw(gX}uc^uFsQRG<;NV zdkn7ow=WE?`?utypw0NY@U)EUbiq~6T5o5A|4i&;sNs_*e4++dIj0%Cr|>BV@RzP) z`7Si{Yakef1%^I@QF3u-==Hg5y`i5e^fws#M@9a%hJLxw-)rb+$-MfQp^6yLEO1P$TGfyQFuA=vDh& zVE;#PorlGId0(M%5NjOcPUHU!m+iklu0e~C!B@A22iNf|gX=mz)8IErTHhZA5B%5l zZjGVW_3kNy>-x3J;Hrm12G{lF7}2NJtMm3KgX_F~fx&ftyVT%1zpXL2&KnH|*YS%# z=bWEeF)%~I;2}d#K4tij!KVz)$QZSXxOk}85t*?deWfbjL&SjG&*5iI3$dz zy&>;(?k{P&|FioHKk8+1G>g9DaHKaaR`(Hks3&ji)s1!24v=H^#`hdD&qP?D- z%r}yQ`E=xvM|k=r7w)y2(+P7lD}0*HOtXS%iD6#f1W)q^_o7;I2fsJ=$6H?r*5tkfATY$$Xk$#KU?mjBu!cJ1mj(uO#3PNSbZ+%uC9NG)dtk}rt-n3i@^bmQ=#G8(<0+6(RWV|}BW>9h zDZ~iaJK?jKsxB|)Q!i_%LN^gX7G+M`OI?uXGWi!>f;95;VnjStN)ku~s43Ox1=q;> zX&}$qf2=`b`&$vRlh{+f)W$VAaa=K1s}pqx_c&^$)`3|wZHEZ)#-UL#J8*4e@dAyb zOtL}O7|LwEaVVK5jceq_2@+^r5NWb;sL6>VjoXL!#C^H`)BgUYV+O6G4-)&^ssvps ziY98KlK*ahLnS0MYm#(K@qf3!V}bs5{p>56Oh3>#%KR_)w-YDcxE*Xrn7V40?Dcq* z?XBmbop$Ai-+uo+wV#HBC#Ib^dBp0bZQZwu)>|S1AN2Cpv}Jf`E(jDss*EbjWv?DK zP3(wI6X4;OAnS*$G|1RSU7o1UnN>4q>GxCr*4o>|iOJ0qv;In+|E~_y;zl&0`|63tzeM zydVQK!FAyOwf2N@M%}n|UqO5Tp}R=*=w2C<|9SxVC8UFQpc9A#l;KaT#F9H0nRzbr zzc7H%!6XKcJE@iJksGMuX+Qp-7(ibJS0J(x9YBtE!T`cRmhBA&klE76KE|mnzLrC; zm~+rDmuKd7WTK^%$-n>IjSA`7*Y7_aKx`Mj;u8nZ|3mhq18DzoG!t%hGvQV@*S4ch z;A~!@CVWi`Tbx81?CsYuZHe-IJe8sT^hor*`*SI=mtu{?kp5%)^A?yr|F`eIuZte4 zU2@1id{eaAn<+6@vs0=lP3ja_a<*2A=MC zGttwp5fU*CTa>2ai#g?`GYMMbg#H-`9lYnPJ&-{vpypLWPt*joxpDtkX)ARkxAhN= ziEX92$S^?J#cwMxw6$@63bAV3-!O3a3>PJPp}v~jnFdORE0IONG)!wZXAll&IOHplI0pGV7YDPI%jqyNRzH#IIeQT`H59882t7d*D^}uI ziVM{JK34bk-Zt*GF(7F55M-0!b(?Em$wIs?Z;(K}p|pRXqpV)NKeSR5Q+vR-9cB8$vvi)^F4VhihgL~#yS8l?Y9C6cbBu5= zuT`tl38JrgN|YXiBp>M|wH?uFWUCx{y4@la%IOfINJagC6m8prIMcUInPCfJ*aB#}(6-3w z0EYCJhe;9Sxnz4uQXRG7(zSwA~MG#rCr3r^N#A^N^nl+Olk{S(x)|4 zlhqOe9Nofi5nf;KLP-cfH6qzninIt8A^)e$hiU-Lv2nIJ9pa3;9nbCUJ|uyE1|1{E_rwGTH)<|mg)XCNx^EW{&T%SavlGS{SRM7dPoq}&V=-j&Kj z1rk5|Tu?iFGVq9tPX*rE#is*Lck%NO@95&^KT7e=UaP)I6XErjA4Vn>KZAnw-%FYu zN9T+N(gJ(+^N5sN)<>i)fn?Hl(G-i{qSa-T;Tqkd&7BnIYFo5LRN`rfqtTW0%j}<^ z2(xeF*r$wrj*ym-7wOt2w41JN`SKKXXp)}<|KP*Ztrs5|%-5s&+J&!O`Fadr zkL7E3zGm>X2VZ;g^*Fxv;%jfd9?#c4eC^BEethlE*Aw|VfUlW+9mv-~d>zc!llXcv zUx)DZ6uu7S>oC3!=j*9_9l_U;d>zHt)A)KiU(eucgX@4z?q{=fQR=EX>OAVAhkm79 zNL7KqCHeBj_86P_0I%`tbCu0J1R8J%a>U<(OQ0EiLfjXZ^4%GQXa-hy9 zl6e+TZd|8JJemA!5}-jUdNR2`rFQ!%%wKyGQaY_anT))Hs^C}g$pw~tX6l{Em=YcP zbwSD31tnh>lzd%K@^wMU*99eCmmHA%uH-2J$?xJqx;)**rFN=xZyrSgv2=@4UrNDS zdrrD-DFMB1O9|+8TS`E$+fo90-Ify2>$a4DUbm$LqeZ$Q8g|^hiq0UsYWuzNj z+l0`?ZNW-%F9{9h+)i5-KGFqt3(w<0Ty7F;1+ur{E7q9gT}8B!rbv zDVehJO(a755^P``!RAyJiRwC^u$B?5cr9Q77g3V;ZJ53yBUV$AXWN<@x31OHxQVnz zre6q5A#{++CWg?OKT%=+c2(#g%r3mDqzjzig$^PkylST8p_jv}E+8pj!d<~7n_)MzrTtd6S5V#HD6Pswm zCL&=u!zUsdUKQ(7TsGGWp9uYhS7mkQ`Xx0zAvH6jYVJIrvV`ixUaa}5is+^=u_{SP zRe_3=R;^!}zLAVY#k4=qjL z7fVRxWmJ^S@|B^Af|Z6>%{tE2s}=r-a#khEd03YvDlS3FnUZpHmHi8a;P34M3JI^8 z9?(a4RbE0x{~qh%bRU$!+L&De>**Qu$(5d(AA~pkp=yTLQ8omm29(S&&B#rajmn*{;HZjrF_|z9l#ZHV1T?>6x zR)hf95L)wyU%o;nTa~Y>8TrWfiZrzfQ5rr@r`4{!n8E_lFioE+MAZ%Jt2CpoiDsPX zGp%zLAxy84MtOalMZrf+VhF8q4Zc|^y$^{d?DeN>DD-XHHgx4x32F5W?hUN2oIkL% zyr`^tR`I~XQgUS*M7)7>%c};K%$Z#|@XXSxlIp^N<>b9}Kv{Lcz*)ufDhF0C@XJ;& z7%*>s=>j-8`N4&L03`|Pkuw?c5lmj(GfQY?W$(B1Gm8)vPwVWTlQP5ft)nXPW?w~d zGUM_&iw3Z-6H3zlfF!IgFI}Vw`laJE0^zr_qMVYnj?*nPF>xX3t5E2p+rnczoV+32 zuS0S;>F1YaZitMpj*MT-*XkLApA0`7Y5!UHTAyV?fhH#%wGZt>x zFu1mM@H3IM)e9o@@1xtU96$K!ff2%!E{;qO_v(23;0+tX*>86p zCGzvd7RaBGGZyCn{n3Ox_(Uf^*3Tq>&RZ3a;X>^-)s2UgIu+lH#bl%EO+P(p-^; z`!Y&!ub{zLXDBUwRp{Z?kJ5fCakE8fVMYaT!%u*7#g3aON`Q5xhx>X;NE<6X+__TP zv8wcNOF>CjQ>BO70!j+wN)J0zO1u0@4@V4?WNlPZXVa-0{deX=d;_5y-x>t~iIUIi zDY0o&$HE0Y82e4a7|WksRxpPhU*}9=m*4sMKPfGr1XP$G%bqlLLX`ZkkApvN z_({&sXJ5yzW~WwmoO5Ii4mJNHZOll)HTUD zW_QKLj-8w{Y1$OOm>Y$h=l2a2kD?1EN2f%mB5P{S#HbT@Oe}jcz*(iUXLF&PDPwac zv)*BHJo{0BiP_Whqmw7+PM+fVoeZwdSA1DT`J4=zQY23r0Cwa>Jui2{1W%XJfvjm- zmne_C%agD5Ddf+-m_~3Jx!v-I40WY%Ugj$41Wq zuQ9RcnDN9cZ*p|%)EW8X$esPvoZLzI`GKC*8F5x=Xz1r|;UH zt0%`}^GeGdY0ji`$UqBjbSq>2UsdI(yY!o5K;?pciTO1Ish zUaZEt!qy{$nMRINfDSGy=LS)N9ZkyBj+&60o9By2{@`Y*oZK&D#L+RXM`6&}qjM)u zjgDm#Dl48{#qy!ClX9nKpOc+4f%=R6(`n|kN#iHcY^CFhT9@F_kJ9mJn629HHJCSA z@5a$M8gXL->c^e}xp~paJegXvmyz-#FCuL8Jj?HI9LIze=WqdyI z=8+q{((*YZer4&!?ENl4GdVgj_Z;S(J!QtEF{p&BG_G}Kq|;w?+~}M$J#LFXOd%yTAE=^^V&h*M>&tm&IcXH0us8>`_J*T9~H}H7{^WnsuME8d* z?~3wEXBjaj=1hV;p@G=T(0q!rzLk?CIxCNvkUJ%ZDo)UN>8!FivE6r|-DC1lp})k% zJ4ltcTN>Zm^EvB6LrPLzV?A$4Nti|Z$>`7<3PNTug%No^@%hO9VIz4B~RHmni zYijPK+$q!Y^2q$CkJ#=Zhrb!2xU8!hb5)I=MwUQ4&y4bz%$YPUS45bKIW1w^6yHK| zSv6gZV=<4wTu%*+PRt`KaN~@pI&x=7TP~fAWk439KJb8iUIh<~xOF5b|IA6#GR9;K z$sCe7EaRj>gHIZC^5By*`c9@9G*(dM@BxE|_QM#XEhG5m(DDjB$mGoy65O}S+{E`A z-0ti%vvYXw;H2ZV*F~Mas2iryvXxD1>KrjTS6FIr398W*3T&lGnrKe0u|_v?WVNPJ zGN`=bxwA{j(CArU<>E^8VtGZr_9r$81!bjk%4rIm<;F?Qq^WN8%pMmvgM}BlsoqpM zDLQ>Bno8?8e$?8tX+fbe9G3xupJokSerO>YJk(KSfZ3 z+zQ1;Eau5~e)EbK5OcS<(y-&bthdm;O2~+3BXRdmV3R$8#=}^iMQB{m4$8HBIvG2eAorLj67m+8H@JQW z@`jFgwcthK(=6td70?|YS-lsSF1$0xj2V&9m*#+eKVS-QHw63;fuf;{Cwrkq>7lNz zQzI+sE(7QJe5Oyo`5?`1n|@VzOq-POc|_szMggZV3>VFx&)Hn|0^k&CanbznWq$cf zfm2|ATbiFVJQ)P2dkyD$-g`K}@bh=3X#P`@&);M9^CyQjf0yJZQG5LI;qUzV4@rIn zezkn~LO=f)l%sGNE`I)EKYx_u-;$3N`S1c?#7>L}T-d%L+29aL<^@ zBPz47vXY|3h1GNN3knNypP0!s4k|65U6BBkm6jJ1P~i#(DCbodmKV&Wv;AOk0{Ofy z0W6qbP(BBQt_qUO%fz`HwqlvIsV~l?(K>)OVnsiZa>XV2v*#0YZrp!<$siW!W(=WV z$dZITC!hnHgwT~z76ZY~@s6y){dh;wFY3`#2!5PK>Ei{bL!*Q+vzhY=TNlnZ!1I4v zelV34GjFo~o?>5`X=%qcQ~nBRAPygc!InRRGHshczj}fzm42N2h5pb-R)3fqEKij9 zqCc+mx`fFzNiUCRnyUXEp7i9gC()pO)NSi8APhW>n!H`;7z+Go(na}d>n|tNVj%ol z%5UXT@r$J`rL3mpZ)ie(Ix9O&eylx~Cu-X?09VgD!!*p&V(xFM{+&(KPfvCatA90N zmM1}YM=to|5_Gk+KO?NE`WvNwVZ;5GMzps7ekDAWj*=V(39t)F3k0oSe;=Vd#BKT3 zqg2owHJ=}-U{alJHZKX5-CD3_!k<_}sqpAww+%7o_$zLow|0^wTs=y{(^^tTAUUvO;+e6~Q&e+aJiJ|lP?zc)xe9Yvm31gAf* z;h_Ber^UF7_mBONsGdjr)ndLekDpcK7tyIMa`~<}aBO+l!3qvFnmKccXEn*nfP9*n zSfzWwV=x@HBtm?qk_gF}WE02xnL|$*GK|i94mhbIE+P8c}y9z&F%>$~_wn zB!kbI-Qfvj!J}Y$h+I0mw5XI$>FCy*&er3l;)nS@7C6}ggM?>d00Iw(k#w@TlN8S@ zlm5rrfptNBULO!c0^TEl%lqy$N6=sV1n^tL&Mf_=0G<(`e_ZU((mxx(dj{w`i(OiJ z>}3%!GX+-xnNAspE&q|8eF!<-9hiwK|AEi4D zo+6#_p}~iu<0v$`AHUw~h5sRgXG+@r?U}PT^w&tyLr3AK?Zw#@LO+9VcCa_Z;Dutm zXBhlr;d8#hE2JMw46eQpD-3?0@UJrXk3~OA4L(`$dV{YQyVCckw7qKuf6~yaPnwSn z-bMK1qc8}{=PuzxFXklRTLn)uxPDt(zul;OE>Zm(diBXQ)ZjYK#~3_W?Eh?o_eDh% z@(r#&Eaw`0g|zb$gRAebI)e|8{<_)Vy99s4;44Kx4F*@Ag0C3-Ua_BD27gM@pBVfk zp;wSmZA@_^ZNyslnAZ*7XKgUskIP{%5hD zUmCo>@YiqftNiOkp8E{_5}{Y0gi3$9^zZKsz0QMA8C>PoZ}%!6^*O%P(BtnY5MD9( zuf)#ZFnFfShwm7Cv7~n!T)$<#$KdzKJafR{w~HNoX7K4wOz)t@J~1Rm4Y8>@Zq92`eStt%KvS#hn@!ivB;yohLnDV$e(HG)raU1gO3z> zMi~5;Qg4>QcZiTG6L}^Ze4O;V`k+?%pB6p**wRaX%rbbb@W0UD#bR&s z3|=krFEIG$(%wrA-XQ$1F!*{&FE=>uGZC&c_(2(`HyAu7^tTwiQsiH2@Lvf1-3H$$ z^51XpbfH(DKdR?#LZ|Ieysh9H4WB&G|8oXES@iRw!LOG7-C^)&Mb5VjzDDd>*Ljua zfK#XUfuY|f`q^u6T@OAr__1PFUl{y$Ne6wqV?Ej~{iR1~DvyrC6lsUzFH5?$!LOEj zI~e>s>6b1B*ZpEogSQoZo?`IdNWY9U_+`?rY=gfgdOOqLzYu()!Mh7S#o+lO{|tk- zm43`O_%M;D*x-j`-uQ{Zj}rQe435{i5f&Q!bdhI?!Iw(9*5JPr`Z|MOE%pA?;QhoN zZZ!BEP8{zS2ERt+yxrhiq`mhTe5UZ3d09$ARMSi@hCf z=-+niz2gn8KF&`z`0K(a+u%nEKEdEKq`m4>QRPveZnF)&-rrRk{Ao$o7<{nke}%#I z{_Ylo>;2lV46Z)8A2Yc6%4{%rOxpXh!L?oQ7+l-+vB9-nUl?55<-SD|zyH;C>HMMk z)OK|hxfIuS^)>j-AfPbR;17r#V-4P4>~FHcqmGR?)8IP4R~USk)O)eP^?vVagR4Go zFu3aTc7v-vA2hh?bA!QEpIZ&C`h3&is?QG$uIChu2CtU%cLqOC<{7>J*8aL)^sK(P z6~9XG-ZK9wuKGF2;HsZ946gc_U~tvX41=qFW*c1fqdwbJ9@S5cp}zwJ6s|M)SeeJx z7+mf1K7)TEdRuSs7P4LheaB;e@@K(cGxU1@{6~YU-VPXC_4BpGrC-}f`&19QA3DL{ z6IctLr@l9peuS(SOAP(1f~$`^rN>uH5H=h7C&W&+8~j*F>-bYX<79sR%+NnCde%pA zO0V^{k$zKL>+NE2t+$WCwce2i-zfTw8T>+#?_z`BFZdM(A0+*Bjlu7CYV)o)_-N6a zo_}b&-jVf1&o7Y_l`$vvy{5RHn?G*&>$rQ};A&TU4ZcbGw^4A*|DeJ3JUvwoWK@2w z_b7vR7XCd2SN_VUzrpp~{zrz-m!ePgain~dUVW7-uFtoFKB+NI%SEX-8~$I59o}W| zxnd_<4SuKK+Xc7vzHM-QuD-|cQF*>FxXROA9z`qvJz_t74F005r$YqSe%UPe7(?Gj z>{)&2DSv#l5Mip}Gg$Ch1}_!8RT%!--h~F&_Xw^sd{htX41S6e$9u%!s-IU3en95o zUCrR?8(P~tM_vrrFZ7CEE&cJi!NWp-$ne+mzSfej`j3i!juKq?s~)-=T;He2G<;M) z(+#eAm~HTnMQ_yx*K?2>!BrluSA9b(uJ3W&Z1|`=n+&e??lAauBG0>mTmI^ESaE$% z+LV^m#Ch#-ct>Jq|DD_1-JYs7+l{&xzO+#Eqtn*p z{9~DCMmNL%EQ9O&DKiWoqGuG0`y>^^6xUZzF)K7@X>aCZE%$*SzZ)Sd8AohN5QpU_DQ?C2k0S>*4xM6`u@&P z!$;*AXYk8qUY*zsAN6^y_M`6s%`$wH|9pdMe_dhl<+9GMF!d_`8x5}S8LcyXwBAPz zUMLEErWrn446g4hy=D05xcJcETJL8De+i1B&_>>G(SGbH?d>SI>Qn1I#^Cy%)Cq=< z%5$p0Rh}G!Pmpn%*9?F4sjc$pdnQGOkMbWT?NfT!+W33g4X*1~jlp$2T5E8f{~HXh^Z#yx>-?t5RXKH@=>;IrE}dt_8eGTkEQ9O#z0%-n z|LY8{_Fq-CIN(t-BjaEClpH?nq~RF||AtS=p{{MXW^pu&KBLy@|7M?(?gQ)e*>v`H zSx4XNub)VtYmXj$5(}I7BtcWy&s(4R=z)#s@c38O8|xh&M$u&r zY0EAUg!~HN&8qt7A#w{MQX;>W^6Po4U3>8R>Pt|VoD_gG<}8O&yAx7-6H<){se=hA z4|V%o@Zy!E>TB>cua2uFiCiS1YVu5@^-kMLQCBH>OsQY#Y9t2^^($R<dE2a_Qp^(dZI8>k^zsTz;T|nASZ#fkdh0tGBo% zSF{f=vD7a^hTqVtmg_N6_RUAPuefn05-D`9(z28!z;o=GD;WYg(?y z(!UP}F!jp}_|4&noL^(&wca-31OT{@ylTt5`nFGEGO2gB7} zq3ziet7<8+mgGMIw;=mRDOITY#3re5qrLw~$qG?1G<$yw7Q>l}8`#Sl79HhcPZEK* z5f|wua@;_Id=I3l@PFE;gL-W^!uOoO&K+9D{Wiec!awopkeuKYqOE#jNOLX^($(cd zJLmGDeWJ^U4v8)wIwrb&=#=R4;Ye}dzycl>^#9P=7oMFv936D~&;=4WhZbFf9w3g1 zyK0DgNjNsq14Oq(4-nm(@&J*M=mDZf(9c59Nkh*>Zx4x{9TFWw^v?9+jvkzFWD2() ziNEGRz-;R7dhy$2_@DV|NDBID;KR=3t4fK#i(Y-MA6*`g*2M|xX;e?ByznECU;Y4I2UdQDVyGZes1iI+#I4TY&pc1@6!5S5Z z6Oj@~)`Y`}BU<4lT&I~M+LTb7t39GEq7qL-9E~2Xq$^tv96~0?q%8-{^Oe~0lvNau zIQ+CB`>9)~NTZ*E&<7JzhrEvDa3sw! zsev~h>YvT27t>0<(ocOw{lDH%Rnw+ubyz9yrpQ`9h1NWjkZMRs?MO)N_EYVtzD7T_ zlz6UB(i(nDA~pD_rzy47PrXA5-{Gfjq;1RcWGx3J)wIwQxGeWmD7Vs2p{us~DU_pk z?IMw@iHNOmc-tHl=u}kbwLJ?~;*7BEcr@1;UfT)Wk!)0Lox>3qcMeB7(N|{L1|5#H zJrmr)%4<8Nk)n~v-|3o8U&K%|F&cTXi^c zWP01`Sw!q87JQ4!I+YcdduKB2bljLHw-9@j!WP4O{+I7cLy*&Px^7V($ z9;r+p;p-86b@K^60#0L;uWk6+mal1iP3LPnzP9IU2flXXYbU-Q$yfJWrZdNn=4%(e zcIE3ad_9)0?n#ZC#d63p&GaB5AjW@XDJT z*ms6tpOQ%MQ{33foXJf{8<@baz_+@I|6Z(X5(lrNam8p482*W!= zb1+N>X#(@1_$f)-vO(+InRaS;8$G#kR3pNHI!A;9b&d!J>KqXc)Hxy?sB=U(Q0Is+ z*XdY~3}Y}iNJS&VlSmw08%BmNp_Hx-Bg6MnYNt>6J*9U0slL?oy?zSQiLM(XS&(~V z0dOf@4n~GEsoYjS4^r+(NWCH3-?SIsCUtNZ?oInXDVcU8t^rL!#N)J-TksGCr7P&c9Epl(9RLEVH{5Y>%Kscu5a zLEVH{O4W@^y%FkIIWH6;&vnj6}KZPsJIu$4FIda5ZV`ld*|$ zdV3;ha8Cpc?unqmJrOjxCxQkiPJ@(NKyObbH&RbENJUR3S5RuVpTZtQhnRB{q(dyx zX;9j$VcN;Cw=Q63rfB&D7iQdQf>js?@C@Bko+z#q|->E z)1b6B*Q#`j(q2l*O;_o*r3CD8TS~wlx1|K^aa&5j9=D|g>`|NsIq9~g1f+X8Wm7;p zbsFRdx2KGxh)#0qG)VKXf%-yMk)7v}u&mdNw5LNq^(EiPtAHqZV+bpmED0NV;+H$0 zw0CaN@`KV|4ej;IzZNY2TCn_UuDp}x_0XL(LLV_jpoHXI}4zcY&`f^2abLk-Lc9Of|?kNl5!q=se1bL}t>pO9)#- zsJIQ2*+wsMx zZih~%B3Kh$kp-c>T;x+Of_bAIUoeJ=5ZZNw3q$QlRguV1bWIOoN@>RzAw)Mi!bPDG zOqj)lFh(ab6FQQ`p&u~`9)6~WFg&^W!r+q7C7gRX=U$IozDP}&dL5f3p><4n9}{i> zAzy?LbB!Zh9eSAwUuVJ(LC6;&#L$jJz9ZFi%}9GPIg`53^`eU>B*Y?Jj%-q%Y9kV^NFM% zn?pRw;;84k<>AN0yCV)?u!LtI?v4f0dmx^|p9b`rbS`y0u{##ULI*KDk#nbR^m!6W zA%k4MNFD|qoJ&O_nCiN70do0(-(U!>*+RuK0Fm!0Vd(W>x^S;%9GLW^k4A7c;a(~N zJq{(m#mFELy3zeyxEFLv5(uG7O(%JPx1xCB=YQdxO3l{Na6l{@*TySmC@A><4vAraw1d8;+4go)epOP3QAsUF^^Mfd7#ukxd|Zb}?ZOvcql+foXLZM2M%E@*+88{{oe3PeYv2%^km&TK%@lBt( z_(C)Wv|#vZ&qDglKfd9Pp-1qX>bTbd4`W71$-9>_fFAHC@$qW0E%iOQ%%cSPttcij z_{&c8m8MeqD71GK<8wH^isSTcXTos=p3kCD;#Zs~CtLjqr5@o_#q8M>f0^U31xnz! zJ3qg$>?aVN(m3+wbWu5c!!&ZTQZjLRP2V&kgP>7Ox!6%?9yTpPhVyW+ubfw0;JDqa-RloEIYDJ4e8=q7QhyAzYAOSd9+DEK6DVa=C}oV2bPax^dz{ zN&2po^NoWUo6^CLiDS(q$p79nb~u#guhv(2I1LvDRUUSnfzlrKl$56L&lVTVB|)%Z zq%=O&O(`sSl)@0H@~|I6g1UV^C9&(Gq<&Z%dn-!H*ZZqHtlpGnnLKP7ky%n*HH#dk zP-*Np2`Q>5FE1{F8RDLofPyme@c>Udxa;Ne}6S?S?^1*F={ zN)Lx(gh*#qdN{BGg;RH>hZ_+}s~RdjoIVf$jaPa&!l49r2CcYG!%nbD4_i=Ba(7gE z*hW&)_nv@LeM-ChN)KmyloUq>*aqlaM#H~ZXF;|6$_^+J195^o5AF&2_Bgu=z&FU% z0}aLTjePyczWC}1dL;2RLafx3A)wQ$MBFFhog)W=oKhrGrxJkZ z>-yxEBH^R*{6%-)(?C&4X<6Jq3Vp*}CTy;Pzp`(f%7`xr@f+cs8zp-72>3sckH|wO z!OsB3eI-D~1ZOKm>dzD!6$9#vLcMeBoeR-x`fxXysX6@LbRxfB*u@;3(kp-HXrr%4Q7 z*gZ6W*{B)!9c&M@Tvd9!L{NPJFHTh4pEfBc(I1UJuR%uVJc9h)ph`7q_Vb{L!@V-7 ziz|P^OmKdqPNCx5$qNcG=dr4rprU;8t3<0R+j7v?4}{|_1UoR{g`C&nL?;vEJ%iXg z=QXIuxdQw?ZU zd=W_SenL5J8Fx17=CexLV7pDE?~(y7Bl2|{p>Bbwuq#H+_sBB|`H!G-JlShzqn?^kMtOWSumN(nl!cwgiVqzC#I`Hy62i6O5hL7Q}qFGcExq zP9&R7&g`@VE~hA$okf94+#$IF;t9leZbpU0s$}K$TS|5=p5k;W)>TXtES^Ffs_KMO zo&2$5$V(8_N6v!s;o@sT_6(j-oJ%XGNcECKqaUC0=kItXdNX2``VKu3920RZdD&ye zla{F-SS!3#73Ehr6Q<6g35OZ@ZkOz?)#-!16*-~Loa{Wqsb3`VvZJOzig8V?BHwLI zc_54Xy>nio67}k;^L@Q=5-vn20yT|~lK-j+@KED>UeP^nz()v5Ip<|R)KyT>cS?4m z2N_p0D=F^&2FpppTtjBSwK|uAqy&Fk6pzDW54##9$e)3zV+&>tA}4YIw@=RJ67h@s z;e)oxUrQ0)iIBerROMXUxw)KYa2nBcJLi|858P&t%^p30=SSIgQN4-R&L@w$t%?gP%OoUa1qU6}`7X-h4g>j21M9!~aC6QJ z6K~bH%DAs6>OK}$Zvnx_u6rfY`%c(tPm0fy=+k$^AkM9kta|1KO#?6v`Lrlj^EA`A$x{|-NRYd z?1CzCNKPnQHvQ7v$L=R-X`_XJrVLQhO=Zw~6g=L!vF@C}L0l>tP4qyS;Kz#kkd9-B zo%8QVJ0U(@K`Gx^R8>CtdgKwq+hwTHtwOy1)5#96>guV|-<;s?Wq!p%mH=yvbLZ)n zI)E~;u<7CX$hx?Udu0vGW`Tm3$gpqa?xj5gZ)C-xoNQiYtqrUJBs*r3;7J$S>YPN1 zZ^6LHk@`{#?27d69r~y9ibCvV=0gd@TJAkHcDMsUsh-U;-uc`Dn#!Zoqhrt&=){7e zqT+ejhP#16y#epDkd>A_XVGIP5^>_fOs*~UJSVPUOkGo*uIJ zeK>`0VE;$Q5OgWmOb3fNS=9WbfA~J0a8ih{2p7!{SNi3j0#4z#bQb65Cq3ww-^IC} z*9X5^Ui?4(7kn$hLz8oj^#3EDO7=K~&SVloS4vq71k1A>*e+glhCn_7(16R+x z!!WnB3y8*$aJg6$_2VxOZ2MOdW_g0aA9~|@xUV5gTTe7i)jw0}AH-bT_`#EKTmNl@ zfv3_5xpxEx7KJxZC=j%M{k@O!nkxU^5LYNOP!>@wr@y}qU_sJWrvy{+xRz67D@A}A zGxgG?{6Qs@Uv0m_&r+l*{jC)J-6MpsUpihsOn-DHf7slCB9WoEdfsd9$G=+no01*G zyJg~8Boot7gf&$^J@#m_{^?niL1BQY&?FsE6Iamvzu*&z9vo5M$6J*zZNWYTxTc2* z-iv-i0gY+j!(8QkNTv+V`%U>20#TCtTOy_pUXt8U>I-$pp<9W3Kx5v39SNdKFn|A=tV-z)UI2PEvvX6O$!gC|ovo8k{&QcdAq2}ivb z$bN$Nmc-kmyAFEUf%gCL`%)x=k1FhmXE4nr1I~Qt9!6dH=$VqAF0UvrIuz+qB~uMOasTNHoL;5zT9-&)iQ40{BG z7Y)7MckMLzF^=5ZWAI*re_`+w1!o0NT`4pCti2$mgv9o)O^lZ2<2Pz#o*3fSf%8_`U#sTmUbW zaSVE}R5{CLx_MBR@sPj8WP zg2DSrL#G&A`{_J`4~M`Mbe-3FZx#M!F59nHztMS-!K;M+QiFG(_Yn}Tc0WF!71Ej4 z8@yhWdaJ=V3BB$oRnEVP{J%Bye-}NxV({Apf7jq2i2QpD{;l-O-z+ZlSkDktp0C8{ zjxczU)T`fXQTmv)x4WUgQQF(z;4#6~x0Uj_MD#q`(4Qjwa}9ov;6a~Lu*17$0L?M< ztE62Q8~k*!&t(R`Tkd;S89Yh!aI3*1GQZqwaQ)`wV+Nlu?cHSXG8v~Y8~jtL_YVfo zl0o^Y!7r8m{o3G*rCrIQKh=MV;28!_6aE7XuD*+g7+if_oNDk*BF|WZ>oK=h!#=2UMNi5>Fd6d2dXiM_Rve5Kzh_TR_qS4Sp`q_D_7?Pkg?@ZVGv9gzbp7v1}_u-*BSgi(a%i=UnBZaUq;&A_R?Pu82VF%&l3jU;MDK^$>8S;f1Ov9 ze}m}lD?`s;C?Z~ADW~*j3VmCHcNM*LG59mmU+No8`J6BId6Jj94r5ULRV<$Ka>6n`tX9C>=rriH}vkWrakXTgXajJEe6k&@gDSn1^()j=ud`z zz4W7wdzHVRjN5Mw{S`tVk$RMVm+0Y0gU^)my$n7~`s*Zv<9%aWErwy*(RDa3fuSh@s!Qh=G z{jtGU3;mY{pCfpZ{HmO1iGJD{Tz%?vH~90?t^o$0BKjF=@U4QYJ!-w`%ivr?|5Mk! zUa`TiML`Oc2A?i=vfSY79JzO!!PTyQZE&@##|_>>#SD$fR) z4{tH_bEMw225&Fp`fh`(4~+W_zD4*vV(>?$z5InVl2_$pUl@Fs=;0fKmy6!? z0AJhny3nPF{VJX#>DC6nSn6$W@K$0EoejQ5@NNeGk+iFq!S5CQ_cwSSNe?pkwK7iz zedu7F>MrdXW$0g)dPf^v=l7VwzY{x|WbhS|o@(%QGLFtO`1_*&nFjwv+B@6eb3|`? zKcxL~gYchk=yA@9u*l#og#I#vhebbE8eGrWt}%EUNv|~c5|Q&JgR4&n^_8dc>%QR* zLw}p-;U0tkUD82cLg?RgvGYd_z4};u(%^cZ(_rv2(cAA0{;KrXHiKsh{c8rlN$hZ^ z!C&WI@x1p9o+j(ZhX(&d=7CQPu0GX*zKx&<_3fp4Qa$T@eaP@hmU_dYZ>294IU@$Y zRqQ0q;Hr1^A)tKpzM`9|~C?CyJbN4ZcDus5JP`rJoiXJVS8Z2dSLn5TUTl(5vsI zdV^;$wdbue_*~KR%?4j4a^7n26NQiZ@>O}%x8>u8zNPSa+Tfc6f7ak1i+#Re@Qb7$ zw;Q}j(r+64XyNm&!G9ur{$%h9k>_KB7fC<<#o+40M(tPi@MoDHzBlyl%Tu&3k$zM9 znW9f!=M_I!@ScXgkKh9hez(+nn!(2leazrz2tLi=Ux=L-8eI3~6$U?B^r`1<$i}>M zwCJ*6siYq^xUQp58C=)n7YwfLdduM2u0I=G+tp}rZPz~xuI*|m z_JVBaLECkd!L?nz46eSnPBOUr3LD+e8vI4k|0IL!Ii~vVR(U=nnGi0t^wRH(46gSV zR~h_TS*LVA;`5hz_zpu~BlFBd245}n=SG9q$a?y+!4JrMxYOY33-BX@YrlVHaP9Z+ z4X*v(TI^TbrTwnIifg|gZ|Jq()z^X2Yrkh1dhPc~2G@SSz~I{N7aCmqeUZVn->))w zhV=Ul2G@SS!{FNQ4;lP3>GzEW*M8q-aP9YZ46gmI&wo^J-#N4OT8P~#eyQN;2Co#n zo59r{PB6II!*GMEJwy$zb}-rCY7hAaS9>TkxZ1;FgR4DUZE&@R8x5}ZaHql59v(Kh z+QTyjS9^Hb;A#)=8eHvRpTX50zB0JlgZm0@{61an!F`J|j;lSmuS&-8VKQ&H??cA% zT{0iKuRF%^T$z7zWL{DGnI!v!a}2I_Qe<$olX(VLJ6U3IwUcWMu6A;>!PQRI8C>n; zVT0czy&_5vhIcV?+qW>f;auk$LSLyF`gR4G|HMr_C z=(7wYs?TADUiGOy%d}qA=h=o{_4#9it3H2XaD9JkvB7^S>%`RtA1ive$>68Uyn4IA zPZC^xnW_A$pACjy^|RIBs-HIvuKM}F;Hsa$8eH|GzI0R`)z1;~QkUZHOS1ItkipLt zJ@huX+ULmzzghOH*#Z z`!5WiHw3@O;9Bov2G@Ew8(iz%Zt&^S-hBq&F81? z41SNu^K*j_6+W8{{-vxh-xyr)yHYzixm3<>GT(MI_-V3V>S6Hfq~2i$|3d5`YH+Q0 zvca|9e1mJfWd_%JYYhH7k!OX$AD40ZyunWq{3U~{PuN!tzFOM#w!t^adh?#aQ>5Sj zZ1C;UzxxcX`>;lX|55b+mBE)vd%rWdKA&hI2c+7+)}mtJM?rPA-$8b0l0Ub@-Pzb)hC4nwc?-e+)q-+PPUbC0y^O@m)0~{$h22UR1{P`aZL^mqEJ7^uhaKjU!Lv(1XVR87|AauTRh-WboCE>EO7|GPsWG znFhZ}(lrKGdtPgBwW|h$t6l9jxb}PXta<;I&%q(X2M-yNf$+n94yJ1(Nro(zBa7Zq zKl1->pM&Y-*zF*>VLKRGk(bB6Da;eWtul*!cmj~x^2kUEUNF@QLTNr>ZFyF~s20NJ}=W?;yhP;g!Au0vceDo8P z_MRL`myL)$gUeoAh&{QZtDzV<6jZuVlx%_y442bD+m}Kk1qEaEH7miRjx+!*)MrIv z_0#CLeXNcJkJS?$fXR_qT^?l;QSDyxhZk*hF-OvY+AFN&SIqe=;9s$RI@maLgn3tEE$^J1i|6I7gy&{qO= zecn7!ZiMD3bO34$7+}C_EZrwsmS5|K{Tw&okY9Sr!8uNc13jUlfxAcG>A$zWKn0VrOJ1vJ)V_C zuI=E^?iiva&vcl#>Z11`la*N)eF*XTtP5hRsnmLi>})5tV&d8-iJG+aikfL1OmWHH z@2gw0q1BUtC0A{8P=*h+O1tu8vZi4AI9L~#Y$NbjJ7cT&CsTE#VDg|?H@bxLt4g;- z4{@zqqK)`vkDV-Q{j@`|qSs=ZK1hy*cEsx0^crI;lEW~)+UTK>G-PD-(9)Nf@yKYS zn*SBV>Tq>~?{Kcaell5bIyewCNTA_jcdN;zPjjeaIwf}bfxhUtx~C6f zx~O}sk$&oKJiv3uG9+k_=TT?wBq3?!b*?>_re^y4!@Ht>8A`HXI(KY2oC>T+mod_% zQoYbDRaSuN#lxw#L=R*T8e6d}omASyEVE)+9#58>?`qD=!Y^4-$aP$-Zc~i>aMrEZ zf%eud+v!>_DY(3h)jP0mS;VFICocY5hYLnUxMZB@?Zb(-EbC1CYFq=Dylzzv%)HTNH-X{UGX^Dg; zss`3BIpC$;)=)e507gv)2;=(>Y))=P)qN_Xi(MoK$aJ_3pZ9yNDW# zAI8N&iqi%vI4)ADoSCBPqq}N%(`Zz4$7hla3HZckTVkuTZ8dM(;?p& z5(!DnMZil#NCJt5BxWXDR5TT>Mv4V(y|la)E4H?MZMC&kK@rgwtyZzMiv4U$TeVni z#d@RG*6+90UhB-6W%9lKzu)_O&;LBhnZ18|?X}lld+oI^=ge$K(CEH!f6BN(ukBvs1r$Vtwo1#%RoCY^whR?yvYET4T|v zyqMkCQ+acwQ+%{P?F8Ji4R05ro%i?kyoj@spXyumWGPO87Fvwld*knup`sxA*cjiv z;lRIOp2wgn`{B`s@1hl+*6~gHUJ28%#cf#sV)j6kGI*vevIiVr7?1AHPg=B~-2H?IX!wkf_FzJa{afgLo9Re#BH5V~S7cG4)Y zw}`CN+Z%tC=-z6Qte6C#C(%6EW<7|k*_0I|yno^*bQ&BEPCR{8Fe#qI>b+9`0mF$P8>%2*sFl~VYa;v8uZpHWKKJL*1y(QeIaDexN0P)ZK__&pMBNK-a_Ct ztScTrkf9y8tZ$E|@+U3m;JC=x4sma%{Wc|b)p`Yp8O?_fr_0ki`9<8(jeFfE`s+K6?)+2Q*5jmEzLlj zV?0^kuqOsA>eFo4Lp1pu-{hJM@zEULTQmop9lyOrMS*acAI2!NgRIN;nSc`0m6p<9 z-{#HA-JgjQtqhdJ!4LLr-Uix$N@_7~Mhbb4k0ov@NT=mH1Hw4tT{$O9vYtFx6 zvHbqtI0k$k<`1Tv)lpPFTWnOg;KO@s9xN3ccOZuwS-j*J8X@{!y}UJwm{1SmVFl$7 z4_9#g`{Y;;`(hP3UGyA)*Vs?m*c3m+FHxsA3~d`E-P8+W5Ia=ht)Z#SAw*FqxM=Dj zjEe9fxf>3LdPZUtJ`s7|iXkwb0;y`!12xU{)&drs2M6pE9Ky(0{1EAZg%Q?Z8W^-# zSE-TEP7ze=ef0+*9joquw|4O7G0z0sD^p?wX9GrzPoPORi2k?5@U4YBn^dp<{nW@z zTf;o*>bH*MY=#e9M`e!j^4i^3X5(Y7Upda2Hr08n0y^$j2%dXE5S<>REBfCRqMrN0 zuCd@l&6>ne;v1VUsSu45qN*TKnnl81NFryuusKKp%VrJI4CHu`oq+tK5>;K z_d-(@j39oOs_5HO(f1Vk*KW9(r^+_1$B_Oaq}X4!kyk;eKo2xCV|+0?o$|iJZb5YL zMD+H+7~el{<_H&LIif(~NDe8*@r94lI6_$JASlnx8nFI49`MrGmXznGL&-&qe+qDR1alV zmvPt)oy>iQD>gVz2bL&qB^DSu|Emr30f$bi%zsfVYat_0+5f2}6W2L4f*#iWVHwX* zVrWEYLT+A8BzH{ih|tK;a5$3icrPdCEI|0B773yuGLG~jxu@rxkyDN*+&DhIJde)y z%pB{L=S{&oEm^~m2|wRPA4D-YFBHkm$)OBHhp)wJ?m2i8nR8Sql{O@mhSTOV((>iz zBj2&eF)SmH121hdw?XB3#BIbx2!WrAIwEw^5GpKh5XVQc2!kNPAVQBorYJ>RrXwW^ zX^F>Cc>(^Tec?Ih(NcBf#EmCV5U6 z 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 RYkS*naBU}#8C=Wze*kyT$HM>s diff --git a/luaclib/luaclib.v12.suo b/luaclib/luaclib.v12.suo deleted file mode 100644 index 80e7ac4b99760c8ab8ffc853284077932bf81d70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75264 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 diff --git a/node-lua.v12.suo b/node-lua.v12.suo deleted file mode 100644 index 7c756d4175a6c32cff8ec6e63c443d8b64c7c189..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 184320 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 Date: Thu, 19 May 2016 15:15:44 +0800 Subject: [PATCH 103/173] =?UTF-8?q?=E5=88=A0=E9=99=A4suo=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.suo | Bin 98816 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 node-lua.suo diff --git a/node-lua.suo b/node-lua.suo deleted file mode 100644 index 4aeb038e5539cadc9b3cf87637c9d74015d22738..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98816 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 From 7585dba616590d4cfc417f5eb0a73ac62d95b47c Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 15:29:33 +0800 Subject: [PATCH 104/173] =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=9D=9E=E5=BF=85?= =?UTF-8?q?=E9=A1=BB=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- UpgradeLog.htm | Bin 42014 -> 0 bytes node-lua.cbp | 336 --------- node-lua.cscope_file_list | 105 --- node-lua.layout | 235 ------- node-lua.lua | 7 + node-lua.vcproj | 715 -------------------- node-lua.vcproj.SOCODING.Administrator.user | 65 -- node-lua.vcxproj.user | 7 - 8 files changed, 7 insertions(+), 1463 deletions(-) delete mode 100644 UpgradeLog.htm delete mode 100644 node-lua.cbp delete mode 100644 node-lua.cscope_file_list delete mode 100644 node-lua.layout delete mode 100644 node-lua.vcproj delete mode 100644 node-lua.vcproj.SOCODING.Administrator.user delete mode 100644 node-lua.vcxproj.user diff --git a/UpgradeLog.htm b/UpgradeLog.htm deleted file mode 100644 index f78437ee9a8a184a2fb071bbb76ba0ebac8deb4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42014 zcmeI5`%_d&mVocCyAk_8)aXuYuZ_sVXHWM8AgJx5RZttpjtLY5l!pR>I5YdF@9y{I zA-xZZqN)U1V~L8Yx^-{n$&=@uC(ph0zyI@>;!nlR;@4uLm?>t9hs9*kDwc|^VzpQ) zelGr_`1isV1H4+rW-(W67YoHa$FGZxVx3m4;sZx3#ZSfg;u5c+Vzl_4b}za50XR2` zi#a|QQs2Qt$C4@^8F%nA4Sq~GEdgZ%45Zdiz}#YH15ox# zPdLpKyI@|$Wefbbpy&dl{GIQ0=6?t7mot*Pj=Y@a_n2SrING4sCC1J?Ytg^{x=)Wq z+Rf22`nHN{Z{?`oL(UJT)`5{c+T{0c!tZBVx9ih{k$(>s|3!~+aGeK&lA0m?z^~V7 z4lT|p1ufokdl`KFHP6*oP+6()d<$5EJ&mrcJ8mx+|D&hYd7dw!@T=l&qP6<9#<(}Y z_-rv%jO@Kfiy!-ftu81N8+#Ckum$m+>Jy@Lm!bo3U@qzE3RDu`GsQI2UgWwQc!Ct3 zDdf})?Up#Je*61Y;>iM97r&qKdxJTvZE;4Mq{SHE?X_jb>TmwC}*NZfT{NIKG&Otg1F>YN8v}xIP%jHrZ#8+HBQ(A~#wP1-cd%?Ls z4cO16A?W)KJ1U*yyF8PR`jd!Kezl07pq|_uW}fe$RDUqrX>jf3=vxR=4~)vD0WgLpye|bTW216Hg#GZ zf5q?c!ke7wU5|%PK#xmqRCQ~pxb_9QRl+m{ru{T}nR|j0ph4)o*S9rPdi`A2BTVtcQNurHsmEY3K z^)AbECm_ise)_kwc;FE%>oA^v@`Pw=B>xiHNv$#t&Hkvj*kbE5tmBU_UCWhm(pu!sdvr<82-P5p7GgldE?*Q>dc9FuBm`h#Cez|niM{oY~(xpFme zW$(NGySEwiZo}*HHh%)vH6n3i>{m%DnzG?K>s_CmJDj>X(v0uksGFsFf8-zs`-4@r zYD%uFW2K>7OX`8XTocby-jdG;LFQ3vAe$!1y|R0u|g7yUb8wE8+gk}rRw-OxPvUuGtZ?I z%ezZ(srYk`I^HkO9zw%%pDFxy-peaJZPul{Cpni^8(D9I>+ZPpqdRAl_JySS*_-D5 zBk||o=+)h8e?(jE(+uy$ibLck^4?7x^}7GiFE_FVWjmLxTxdbgV7O23Jj}O;%`>tp zrAQ0vFC|Kjs*!Uk3NG6iC%xv%b)wZj^WD46I}3#REwFOLBa5$iMZ7VIo(k36%6zILC|lm)n%R*~ZJs5Lucg(< zV#k(~WTjFmeK+t1?w<9#j?WPFE#>ZL39~ny%zEA~x*mXDRu);U z;0~;7(E7RFWU%vCRxr8elJ`V!Bsn?RIIS+9W(q>;qZX-@)#K8E{7sx)6t-rBmoR_bfs#HvQ^NsCmloPGfEG{;6( zk^h#mXQ?0kF=Y&mw$2v61G`_!9T(oqP=B17jK@gDrQ$AiYSyxi?Y$l_t0ze0B%h0W z=f*!@9V;HOW*wv2Hn)F`-5w+^T>5-w0xplknP+_8-#hCrM)dd<8$ZUFPZ@a!I=+1q^p4UL%2PKz++ND;zoNhxB<&%ZJS6CBH|(>?7CK;hfN| zOnjQS^Ah+MfPIe^uW5ImqfKVKPQMi}eM!qn&fW$8c_7@Q{Y_wBX8d26_ZzN!q~~=; zze&#v3EyA9=O(iqW(MyW@eO^iF~SERk0Lu(o!tdvd#!T3#B4u8)hqDLs_jKy+l+FT zzQWheTm`}_aJd7NDWJ?Sk2myqz|jcrK|Y^A^Brb3&DraG&OyH=;OzqEDJ`CW|7+kb z(dsr(r-As4E5D^#Dkl?QBv;>q<69^&10GL-^@tYF6IY*eybiun@I5d-0`)1MpPPuleFDZPXD@L68jzIT8Q@5jtH7S+ zQw;M<{hFf1Tdsd#7OPNVB3Z0nd~Cl_bB7YpHYmF$zvBvd?ViU_hg9n?%?@wR>$N9X4)zzO&Vev<>qQ7Bx zZ(}2G<6pM1y1(EBTmh_NWA*pTd|u}B8kYTWYCT0eeT;Ni#%{ZxtMAaOSv9x?eD@qz z7GUI)enuK$wga-S=%93C^q81Gf)w#3L6xPB8# zY(TkNQ0P)>b%Cq*q1Fha84*kZZ4+D{;M=6)4*2{63}diauHWJ81b91hqnBHWL#wo0 z;>=y%ubHzk*EpXu;JC`SG3gMP?(i~NxXY}pCpVL`2tBPWbIx+{ewxP=wEPIg9s+TL zD+{#Q;dlaG-2~zyI1EC`S*{r+?(lxk`CCxN7;F$sZ!=Tl99t~Hl@VU{n`abb(N~Nw zFIH)B3rx1TcAuF)hYLm&(_r?I(XKIij-U1AM(9t0Z0vLyjAj|@4tGMi_UOgO_3O#& zIi}%CYe|!Gh74apkVl^Z14$C=>jeL~6fd1tp zHrF++zG)Ym@7i{PU-z-vuBPX)_H&%~F3BB!O<>)pvAKFHy~|a8jbV2mVS#5-Pp$JW z*y&}?&2oGf-|3^AAObnZ4iyrP$%0mcPJU8R?JZZY#Wz}aO!ThLml zZ@^=LYvz$$*UxiocI63I9svCbeRjcgj_c#}(A&LXq)%L12yFQDxoulm*o@6<#iM$`@8E0#)hih>m`8rdw>jTIuDgTr5pVSpOg6#gI%jPEiqDnw zeH|>Wrv9$fT>p+j`$5Lk-;IFB68_RP{cGCkvp)jOwYMucqXu_IT%|o{j^?#p?LFt* z6<*TFr*q5#*_`;*G^)7<&wT<*?|#^3tZPv17Wi)hX_xb6z~>oljd2z^`x-hdGJE5L zcffad;}Z~l^2I2hMjnG;?ppXd*T=zfoAa@o@{r@liQ@Md0pX?Jx%1Zor!iZ0c zS!Oow(|V_?ag@(LapyFi#qtK-u+GtE&E&RcXziU^)n~let9{!}PcP{dUqqF^n(BV& z7P@2g<>5VUW3|?yxO=en$otay+udvRJ$9kh2xC(z5PR8WkLI&b2H~Qz#Xor0F*A2*)-mRL z9*#9@z0RbJPpkOXA$gxpm`jE8HA-D%E?Rzf&D{si6#u>>1rCoVtK2wfjPu1gxTS3f zuAfVMQx8h1YEt#EtXE{Y4$`;<#xkp5q;7@dep*=XT2jILJj6$?EWmSl*NMKp)1~ux zQm7Z|Sl#IpY+{y2MXN8HaZ}TjhCg=Joq5=4wqf^XkXKikYHZX&Moo_uxz=yJRFdKZIL?pDcY4Laj(Hlc2Rw164U8DK<>uvG+( zJ`Q#d_8_1CJjR#my?0-PbyNyh@V9xcTEqRaU{t<^##OCf;3me46%5bOZUcQdOsYfo zv%feG6@MZUuu^xK_g{F|G4oC#^?NaKBHCRbLg-A180Bz%&z2}t#mrRHed%Q~{afJJ z#OrV1`#aTTL7_2PJAb9i%+CV0%X{KNGP8PdqK}AZ)%Xz5}23S1*Ete%2`D z*W^z!7FtI$FWz_F4fT4ZVUw0>n|pAfb8@j09n1LYBG}vO9h|pDI%9nfiuPL3El%z5 z_$%k@a+dko8IM-tYCOHcyBw`o>lco*>153^J^k+NH=||eHl43_!ehVXiip-dRO@xt ziQ;_*o|LQeJFH99dUdvu-RNu9)H>BevQF(+dz;Wn?~dMnWe&B|yMyg$XT7suulj!y zcC>{h))w!d>+xCGy5yI3E1qAfPFgo(bfGr-jIZ;_H<`!LJ9pN>s?~|(4f?r;v_`^6 z$h{4pC(%8e&bFr;>lJM}S*dooma%qcOWPU0PNPP|={m$G`{byw8g;gd7;}!GxvF)2 zAhpBu#a$@2iTlOM3hi=rT8~o8C*bDQtJgc>zu&g!p3Y@ANlxT5I?Ho6mRk;Goh&Kv z&*Gn)zr@?vL_N>f>XBdP@q_z*c8f{w(Uk6(ZTHe0veSvid88IuB=1hvTNkzC@+NPPiDKli= z;bP?OQ=vOi?J)aOUwOJ(oM-NxAa7tly7n!5^?Qe7rbJY&Qa9eMGk=8GiAP@VCBJnB znXK|HR*qK9x_=VS(7yo8_7v+T=hO=}=h|Z9{VTEivB6%K&$-ya61VU&Uk_fllZ9O9 z0&*R5oZqjV-t(ir9hNPqOTej?o{W~3F==FQVue?|7xvs|X>UFsW;4l|yxlp} z8f5F(Ywqaibg{F2*J5>NNi)TKI*~p+o^<0q%I*n7WN#F=&97?iGw4+Am3F49@t|vM zIbqE2r@NQ_Gsp_R+;J%VT;8?ltkurZ*U|8xw9bcH!Nc+DY;ihWjotZjkKO%w{|P0m zwZD9_p#Q7kaXjm$*MBYflK(96e`@0Xb+hsVa8DivjzbA2^WEFDF}gM8k9+!E2b;&q z|2yOJ-J5v-ns$UYlB}8Ou>vIi2gP2^t1;$q+cBF@go#nz>y3RWX{S8K_fq;EcZa>6maX75925++iylSh%Vb<&2JHc(X zJREl2OLl_YY*~dZg)=Ynw|49m(ist#a+sf~Qpa)pBkpVSxKN( z4-F89O9_jNO?B*EVb$06`zcYUv>04Hwz1`$T$1NLN91j?J^e;&@dVH+S7X<+zVfKn zKm3>|JluAEf2@3ZKblrL*9wIsn8^)K+_ZB|JKO9(z1LGX&1)gw0Xd{S%USPI@AEv? z5?U5Yd6h-ix|F2590j zh78O%e5!t;8W}YElsV`63VSnQ>$r~Jj8p0{sH=2aY43B*fnKC(olB3gMEz`g%O6*a zII6VJuar?z6K*vIc#H=7-!|ftV+ko+jaKTuu09uif$LRqZEAbnuO1wO)Z2v@D&wZ? zb)8X_T6K+xd6bcMbIy5&`?aGx-`x$r>KK*Wlb#2A)r08ih;_@>oKxL<-)OtCY!?+| z`}{Nep4P)J5V`tPpoos$O^Z0w=bqf+SL8#D6Mb5cIYg~~?Bzzh?ygD1F+y?OWL<3j zCqrWdpDs0nR9V|1oPgk6Ztmmw#3#oIALw1@)^EzI@?S4^IqMEfGl%48?z`%PjHEUh zYrn6^94PHa=*X!=RU?rvm#DF14f4~C<(5yZioBMbj@>xr$oNqXSD*HktKDK1p-YB6;FxiR&ZSUDwuD>?vX8v&)1YP($*RKx=T~`Dl@c(B8+tcbQAr zK}wDCtY(ZI<@gSm!q#h;QxHzJy3WIYD~;#*iiJAhQ^Ph>1%MXSEJsyqtOwt(DYl6E zf!srA=1g``QdNf%1|Vmx(9y-~w*-`HJpHb!Lb;rSUYZ0T?9yR*yxBPw^Cp;U?| zs0z>4!549kXBP@7{GipI^3*KMW@@cYR`+O?19$#od|?Ey0=E5xt~Hd8?v4fqdF;c+ z5#!9y`W%CEO<6p(64ks|>BmpP@7%}VjC22r|Li!FY6BnUo#LeIJ6qo-=IFYT5~n5zX^jb+nOUr?3rL zt5QSMpzxMzL{uclU1nu&G;4>j%DlAC0bEFTAw-p}dM>OT;Dk=Dq?x-*lQqx(bdCSy z)hdg#{~G&ce7VoK`?+9b@B&LUy2mr0F6X~h%GZP1H@TPT9=!2+;v;+9IRn&F|6gXj zPc>T|>#W&Vk3h5Q7R2cPRHsjMdjG2a+gl}`L`?q}e^th~r*VDcPfz3e`a112t~WaW zdh0olF6oPV}r ztv<7;=&j!8a5mvm-M47Yu?|7Z_g62ti<9rEueWbs3Epqj!a)_VnF1{`KW3Zu)1g_p zw|U_HR;~l+W{;;n*TZ)W&1Rd`c5R|1ms{?i$^G4wxs>|uko7NF-Rv#a@h+wD>x~7? zw)(83*cZrI&B)v3N;mVEk>Pb;XENo0?~;YIVl*l}UXZhNKjLkox;se=_y+))1$o0)RY`|joodwdNc1jos=B;Zy4?+yg^EP z$u4(qJLD@AR|9`z(roi!fH*J63e{SbPnzc)%*RX16 ze^l~tPsZcFyl&P!-2+BiMdGSbsI)c5FgwvrO;WR86>eDBEX!pj(6?Tb)SPpk;ZfEk zHODylm1fjd_TvE}^33;bOe5VNQoNPzzHzwwec=hBp1^8>h`>>5J`l4C`5k0iFS=-9`iDvI;yN25l&~4YZQH@sqtFQLd+FmO}^8Y$U&0ak9G-^q{WYy;X zWqLn_@Y=26$~yhBX0^KiAvF)G53X~dxpF&|oP2+sE4Qehvi@hCHF!H45EV7``;|(b ze7zD>pIgkLdJoB$=ZsDzsg$JtZBUbnX8)}IjoRO^I?87|>(o70yY~(Kt;d_Q_&TDO yyc#{4^>}lRbvyfYMlYEHt+ehvuIQz?9v@7rm+f?KP5rofpSA1dEu?*gcK-(<-Oh9X diff --git a/node-lua.cbp b/node-lua.cbp deleted file mode 100644 index 87a9c2c..0000000 --- a/node-lua.cbp +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - diff --git a/node-lua.cscope_file_list b/node-lua.cscope_file_list deleted file mode 100644 index ed38cad..0000000 --- a/node-lua.cscope_file_list +++ /dev/null @@ -1,105 +0,0 @@ -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\uv-bsd.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lstring.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\openbsd.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\uv-darwin.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lstring.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\pipe.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\uv-linux.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lstrlib.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\poll.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\uv-sunos.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\ltable.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\process.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\uv-unix.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\ltable.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\proctitle.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\uv-win.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\ltablib.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\signal.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\ltm.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\stream.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lfunc.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\aix.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\ldo.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\ltm.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\sunos.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lgc.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\async.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\ldebug.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lua.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lgc.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\core.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lauxlib.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lua.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\linit.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\cygwin.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\ldump.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lua.hpp" -"E:\Kuaipan\workspace\node-lua\deps\lua\liolib.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\darwin-proctitle.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lbaselib.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\luac.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\llex.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\darwin.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lauxlib.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\luaconf.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\llex.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\dl.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\ldblib.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lualib.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\llimits.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\error.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\ldebug.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lundump.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lmathlib.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\freebsd.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lcode.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lundump.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lmem.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\fs.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lcode.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lvm.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lmem.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\fsevents.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lctype.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lvm.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\loadlib.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\getaddrinfo.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lfunc.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lzio.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\tcp.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lobject.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\internal.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\ldo.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\thread.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lobject.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\kqueue.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lbitlib.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\threadpool.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lopcodes.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\linux-core.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lapi.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\timer.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lopcodes.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\linux-inotify.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lapi.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\tty.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\loslib.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\linux-syscalls.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lctype.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\udp.c" -"E:\Kuaipan\workspace\node-lua\deps\lua\lzio.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lparser.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\linux-syscalls.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lcorolib.c" -"E:\Kuaipan\workspace\node-lua\src\main.cpp" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\ngx-queue.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lparser.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\loop-watcher.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\stdint-msvc2008.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lstate.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\loop.c" -"E:\Kuaipan\workspace\node-lua\deps\uv\include\uv-private\tree.h" -"E:\Kuaipan\workspace\node-lua\deps\lua\lstate.h" -"E:\Kuaipan\workspace\node-lua\deps\uv\src\unix\netbsd.c" diff --git a/node-lua.layout b/node-lua.layout deleted file mode 100644 index 4f70e6e..0000000 --- a/node-lua.layout +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/node-lua.lua b/node-lua.lua index 358219b..a2b7995 100644 --- a/node-lua.lua +++ b/node-lua.lua @@ -61,3 +61,10 @@ snprintf()函数并不是标准c/c++中规定的函数,所以在许多编译 #define __STDC_LIMIT_MACROS + 将VS2010工程提交给Git管理时需要哪些文件: + *.h *.cpp *.sln *.vcxproj *.vcxproj.filters *.qrc + 以及Resources目录下的资源文件。 + 如果使用Git的过滤配置,则还需要.gitignore文件。 + 其他的诸如*.suo *.sdf *.opensdf *.vcxproj.user均可以过滤掉! + + diff --git a/node-lua.vcproj b/node-lua.vcproj deleted file mode 100644 index fe6a72e..0000000 --- a/node-lua.vcproj +++ /dev/null @@ -1,715 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/node-lua.vcproj.SOCODING.Administrator.user b/node-lua.vcproj.SOCODING.Administrator.user deleted file mode 100644 index d10f43a..0000000 --- a/node-lua.vcproj.SOCODING.Administrator.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/node-lua.vcxproj.user b/node-lua.vcxproj.user deleted file mode 100644 index 0a79b21..0000000 --- a/node-lua.vcxproj.user +++ /dev/null @@ -1,7 +0,0 @@ - - - - sample/main.lua - WindowsLocalDebugger - - \ No newline at end of file From 2e5f367fcdc8724320f3d9a6ffe5a56e4e098ba4 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 15:49:52 +0800 Subject: [PATCH 105/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0github=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..09123f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# On branch master +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# .metadata/ +# gitignore +*~ +*.o +*.a +*.so +*.obj +*.lib +*.dll +*.suo +*.ilk +*.exp +*.sdf +*.pdb +*.opensdf +*.vcxproj.user +Debug/ +lua +luac +node-lua +node-lua.exe \ No newline at end of file From 77588cea4114238488f1e9cc3e25356f9656569d Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 15:57:16 +0800 Subject: [PATCH 106/173] a little thing --- luaclib/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/luaclib/Makefile b/luaclib/Makefile index c89049c..28d5bcb 100644 --- a/luaclib/Makefile +++ b/luaclib/Makefile @@ -10,11 +10,11 @@ ROOT_PATH = $(shell pwd) define MAKE_PLATFORM ##not essential builds - cd mime && make PLATFORM=$(1); cd $(ROOT_PATH) - cd cjson && make PLATFORM=$(1); cd $(ROOT_PATH) - cd lfs && make PLATFORM=$(1); cd $(ROOT_PATH) - cd lpeg && make PLATFORM=$(1); cd $(ROOT_PATH) - cd pb && make PLATFORM=$(1); cd $(ROOT_PATH) + cd mime && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd cjson && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd lfs && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd lpeg && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd pb && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) endef all: From d9040405ae00cb7dc8303d3a9d938e4a481f801b Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 17:20:36 +0800 Subject: [PATCH 107/173] =?UTF-8?q?=E8=A7=A3=E5=86=B3macos=E4=B8=8Bbuf=5Ft?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E7=9A=84=E7=BC=96=E8=AF=91=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/network.cpp | 3 ++- src/uv_timer_handle.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network.cpp b/src/network.cpp index dd5a7db..e03afa6 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -15,7 +15,7 @@ initialise_singleton(network_t); -network_t::network_t() : m_exiting(0), m_shared_read_buffer({ 0, NULL, }) +network_t::network_t() : m_exiting(0) { int rc; rc = make_socketpair(&m_request_r_fd, &m_request_w_fd); @@ -27,6 +27,7 @@ network_t::network_t() : m_exiting(0), m_shared_read_buffer({ 0, NULL, }) assert(rc == 0); rc = uv_poll_start(&m_request_handle, UV_READABLE, on_request_polled_in); assert(rc == 0); + memset(&m_shared_read_buffer, 0, sizeof(m_shared_read_buffer)); } network_t::~network_t() diff --git a/src/uv_timer_handle.h b/src/uv_timer_handle.h index 287c414..2d6d4ab 100644 --- a/src/uv_timer_handle.h +++ b/src/uv_timer_handle.h @@ -13,4 +13,4 @@ class uv_timer_handle_t : public uv_handle_base_t static void on_timedout(uv_timer_t* handle, int status); }; -#endif \ No newline at end of file +#endif From 782d11eb41350e2d4eab56884e8a425b354ad2b7 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 17:39:17 +0800 Subject: [PATCH 108/173] =?UTF-8?q?=E8=A7=A3=E5=86=B3macos=E4=B8=8Bpbc?= =?UTF-8?q?=E7=9A=84=E7=BC=96=E8=AF=91=E9=97=AE=E9=A2=98=EF=BC=8C=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/pb/binding/lua/pbc-lua.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/luaclib/pb/binding/lua/pbc-lua.c b/luaclib/pb/binding/lua/pbc-lua.c index 874fc25..81c8842 100644 --- a/luaclib/pb/binding/lua/pbc-lua.c +++ b/luaclib/pb/binding/lua/pbc-lua.c @@ -8,7 +8,8 @@ extern "C" { } #endif -#include +//MAC_OS do not have +//#include #ifndef _MSC_VER #include From 5b9ebdbfbf5e87b690e925eb7989abea0a635031 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 19 May 2016 19:33:18 +0800 Subject: [PATCH 109/173] =?UTF-8?q?m-m=E5=A2=9E=E5=8A=A0systemtap=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stap/sample-bt | 298 +++++++++++++++++++++++++++++++++++++++ stap/sample-bt-off-cpu | 308 +++++++++++++++++++++++++++++++++++++++++ stap/sample-bt-vfs | 233 +++++++++++++++++++++++++++++++ 3 files changed, 839 insertions(+) create mode 100644 stap/sample-bt create mode 100644 stap/sample-bt-off-cpu create mode 100644 stap/sample-bt-vfs diff --git a/stap/sample-bt b/stap/sample-bt new file mode 100644 index 0000000..65b31ef --- /dev/null +++ b/stap/sample-bt @@ -0,0 +1,298 @@ +#!/usr/bin/env perl + +# Copyright (C) Yichun Zhang (agentzh) + +use 5.006001; +use strict; +use warnings; + +use Getopt::Std qw( getopts ); + +my %opts; + +getopts("a:dhl:p:t:uk", \%opts) + or die usage(); + +if ($opts{h}) { + print usage(); + exit; +} + +my $pid = $opts{p} + or die "No process pid specified by the -p option.\n"; + +if ($pid !~ /^\d+$/) { + die "Bad -p option value \"$pid\": not look like a pid.\n"; +} + +my $condition = "pid() == target()"; + +my $time = $opts{t} + or die "No -t option specified.\n"; + +my $limit = $opts{l} || 1024; + +my $user_space = $opts{u}; +my $kernel_space = $opts{k}; + +if (!$user_space && !$kernel_space) { + die "Neither -u nor -k is specified.\n", + "(You should choose to sample in the user space or ", + "in the kernel space or in both.)\n"; +} + +if ($time !~ /^\d+$/) { + die "Bad time value specified in the -t option: $time\n"; +} + +my $stap_args = $opts{a} || ''; + +if ($stap_args !~ /(?:^|\s)-D\s*MAXACTION=/) { + $stap_args .= " -DMAXACTION=100000" +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXMAPENTRIES=/) { + $stap_args .= " -DMAXMAPENTRIES=5000" +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXBACKTRACE=/) { + $stap_args .= " -DMAXBACKTRACE=200" +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXSTRINGLEN=2048/) { + $stap_args .= " -DMAXSTRINGLEN=2048" +} + +#warn $stap_args; + +if ($^O ne 'linux') { + die "Only linux is supported but I am on $^O.\n"; +} + +my $exec_file = "/proc/$pid/exe"; +if (!-f $exec_file) { + die "Nginx process $pid is not running or ", + "you do not have enough permissions.\n"; +} + +my $nginx_path = readlink $exec_file; + +my $ver = `stap --version 2>&1`; +if (!defined $ver) { + die "Systemtap not installed or its \"stap\" utility is not visible to the PATH environment: $!\n"; +} + +if ($ver =~ /version\s+(\d+\.\d+)/i) { + my $v = $1; + if ($v < 2.1) { + die "ERROR: at least systemtap 2.1 is required but found $v\n"; + } + +} else { + die "ERROR: unknown version of systemtap:\n$ver\n"; +} + +my $context; +if ($user_space) { + if ($kernel_space) { + $context = 'both user-space and kernel-space'; + + } else { + $context = 'user-space only'; + } + +} else { + $context = 'kernel-space only'; +} + +my $preamble = <<_EOC_; +probe begin { + warn(sprintf("Tracing %d ($nginx_path) in $context...\\n", target())) +} +_EOC_ + +my $stap_src; + +if ($user_space) { + if ($kernel_space) { + # in both user-space and kernel-space + $stap_src = <<_EOC_; +$preamble + +global bts; +global quit = 0 + +probe timer.profile { + if ($condition) { + if (!quit) { + bts[backtrace(), ubacktrace()] <<< 1 + + } else { + + foreach ([sys, usr] in bts- limit $limit) { + print_stack(sys) + print_ustack(usr) + printf("\\t%d\\n", \@count(bts[sys, usr])) + } + + exit() + } + } +} + +probe timer.s($time) { + nstacks = 0 + foreach ([a, b] in bts limit 1) { + nstacks++ + } + + if (nstacks == 0) { + warn("No backtraces found. Quitting now...\\n") + exit() + + } else { + warn("Time's up. Quitting now...(it may take a while)\\n") + quit = 1 + } +} +_EOC_ + + } else { + # in user-space only + $stap_src = <<_EOC_; +$preamble + +global bts; +global quit = 0; + +probe timer.profile { + if ($condition) { + if (!quit) { + bts[ubacktrace()] <<< 1; + + } else { + + foreach (bt in bts- limit $limit) { + print_ustack(bt); + printf("\\t%d\\n", \@count(bts[bt])); + } + + exit() + } + } +} + +probe timer.s($time) { + nstacks = 0 + foreach (bt in bts limit 1) { + nstacks++ + } + + if (nstacks == 0) { + warn("No backtraces found. Quitting now...\\n") + exit() + + } else { + warn("Time's up. Quitting now...(it may take a while)\\n") + quit = 1 + } +} +_EOC_ + } + +} else { + # in kernel-space only + $stap_src = <<_EOC_; +$preamble + +global bts; + +probe timer.profile { + if ($condition && !user_mode()) { + bts[backtrace()] <<< 1 + } +} + +probe end { + nstacks = 0 + foreach (bt in bts limit 1) { + nstacks++ + } + + if (nstacks == 0) { + warn("No backtraces found. Quitting now...\\n") + + } else { + foreach (bt in bts- limit $limit) { + print_stack(bt) + printf("\\t%d\\n", \@count(bts[bt])) + } + } +} + +probe timer.s($time) { + warn("Time's up. Quitting now...(it may take a while)\\n") + exit() +} +_EOC_ +} + +if ($opts{d}) { + print $stap_src; + exit; +} + +my %so_files; +{ + my $maps_file = "/proc/$pid/maps"; + open my $in, $maps_file + or die "Cannot open $maps_file for reading: $!\n"; + + while (<$in>) { + if (/\s+(\/\S+\.so(?:\.\S+)?)$/) { + if (!exists $so_files{$1}) { + $so_files{$1} = 1; + #warn $1, "\n"; + } + } + } + + close $in; +} + +my $d_so_args; +if (%so_files) { + $d_so_args = join " ", map { "-d $_" } sort keys %so_files; + +} else { + $d_so_args = ''; +} + +open my $in, "|stap --skip-badvars --all-modules -x $pid -d '$nginx_path' --ldd $d_so_args $stap_args -" + or die "Cannot run stap: $!\n"; + +print $in $stap_src; + +close $in; + +sub usage { + return <<'_EOC_'; +Usage: + sample-bt [optoins] + +Options: + -a Pass extra arguments to the stap utility. + -d Dump out the systemtap script source. + -h Print this usage. + -l Only output most frenquent backtrace samples. + (Default to 1024) + -p Specify the user process pid. + -t Specify the number of seconds for sampling. + -u Sample in the user-space. + -k Sample in the kernel-space. + +Examples: + sample-bt -p 12345 -t 10 + sample-bt -p 12345 -t 5 -a '-DMAXACTION=100000' +_EOC_ +} diff --git a/stap/sample-bt-off-cpu b/stap/sample-bt-off-cpu new file mode 100644 index 0000000..c342f3f --- /dev/null +++ b/stap/sample-bt-off-cpu @@ -0,0 +1,308 @@ +#!/usr/bin/env perl + +# Copyright (C) Yichun Zhang (agentzh) + +# Thanks Brendan Gregg for the inspiration given here: +# http://dtrace.org/blogs/brendan/2011/07/08/off-cpu-performance-analysis/ + +use 5.006001; +use strict; +use warnings; + +use Getopt::Long qw( GetOptions ); + +GetOptions("a=s", \(my $stap_args), + "d", \(my $dump_src), + "distr", \(my $check_distr), + "h", \(my $help), + "k", \(my $check_kernel), + "l=i", \(my $limit), + "min=i", \(my $min_elapsed), + "p=i", \(my $pid), + "t=i", \(my $time), + "u", \(my $check_user)) + or die usage(); + +if ($help) { + print usage(); + exit; +} + +if (!defined $min_elapsed) { + $min_elapsed = 4; +} + +if (!defined $pid) { + die "No process pid specified by the -p option.\n"; +} + +my $condition = "pid() == target()"; + +if (!defined $time) { + die "No -t option specified.\n"; +} + +if (!defined $limit) { + $limit = 1024; +} + +if (!defined $stap_args) { + $stap_args = ''; +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXACTION=/) { + $stap_args .= " -DMAXACTION=100000"; +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXMAPENTRIES=/) { + $stap_args .= " -DMAXMAPENTRIES=3000"; +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXBACKTRACE=/) { + $stap_args .= " -DMAXBACKTRACE=200"; +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXSTRINGLEN=2048/) { + $stap_args .= " -DMAXSTRINGLEN=2048"; +} + +$stap_args .= " -DSTP_NO_OVERLOAD"; + +if ($^O ne 'linux') { + die "Only linux is supported but I am on $^O.\n"; +} + +my $exec_file = "/proc/$pid/exe"; +if (!-f $exec_file) { + die "User process $pid is not running or ", + "you do not have enough permissions.\n"; +} + +my $exec_path = readlink $exec_file; + +my $ver = `stap --version 2>&1`; +if (!defined $ver) { + die "Systemtap not installed or its \"stap\" utility is not visible to the PATH environment: $!\n"; +} + +if ($ver =~ /version\s+(\d+\.\d+)/i) { + my $v = $1; + if ($v < 2.1) { + die "ERROR: at least systemtap 2.1 is required but found $v\n"; + } + +} else { + die "ERROR: unknown version of systemtap:\n$ver\n"; +} + +my $preamble = <<_EOC_; +global quit = 0; +global found + +probe begin { + warn(sprintf("Tracing %d ($exec_path)...\\n", target())) +} +_EOC_ + +my $postamble = <<_EOC_; +probe timer.s($time) { + if (!found) { + warn("No backtraces found. Quitting now...\\n") + exit() + + } else { + warn("Time's up. Quitting now...(it may take a while)\\n") + quit = 1 + } +} +_EOC_ + +my $stap_src; +my $d_so_args = ''; + +if ($check_distr) { + $stap_src = <<_EOC_; +global start_time +global elapsed_times + +$preamble + +probe end { + if (!found) { + println("\\nNo samples found yet.") + + } else { + println("=== Off-CPU time distribution (in us) ===") + printf("min/avg/max: %d/%d/%d\\n", + \@min(elapsed_times), \@avg(elapsed_times), \@max(elapsed_times)) + println(\@hist_log(elapsed_times)) + } +} + +probe scheduler.cpu_off { + if ($condition) { + if (!quit) { + start_time[tid()] = gettimeofday_us() + + } else { + exit() + } + } +} + +probe scheduler.cpu_on { + if ($condition && !quit) { + t = tid() + begin = start_time[t] + if (begin > 0) { + elapsed = gettimeofday_us() - begin + if (elapsed >= $min_elapsed) { + found = 1 + elapsed_times <<< elapsed + } + delete start_time[t] + } + } +} + +probe timer.s($time) { + println("Exiting...Please wait...") + quit = 1 +} +_EOC_ + +} else { + # for sampling backtraces + + my ($gen_bt_code, $print_bt_code); + + if ($check_kernel) { + if ($check_user) { + $gen_bt_code = "backtrace(), ubacktrace()"; + $print_bt_code = <<_EOC_; + foreach ([kbt, ubt] in bts- limit $limit) { + print_stack(kbt) + print_ustack(ubt) + printf("\\t%d\\n", \@sum(bts[kbt, ubt])) + } +_EOC_ + + } else { + $gen_bt_code = "backtrace()"; + $print_bt_code = <<_EOC_; + foreach (bt in bts- limit $limit) { + print_stack(bt) + printf("\\t%d\\n", \@sum(bts[bt])) + } +_EOC_ + } + + } else { + $gen_bt_code = "ubacktrace()"; + $print_bt_code = <<_EOC_; + foreach (bt in bts- limit $limit) { + print_ustack(bt) + printf("\\t%d\\n", \@sum(bts[bt])) + } +_EOC_ + } + + $stap_src = <<_EOC_; +global bts +global start_time + +$preamble + +probe scheduler.cpu_off { + if ($condition) { + if (!quit) { + start_time[tid()] = gettimeofday_us() + + } else { +$print_bt_code + exit() + } + } +} + +probe scheduler.cpu_on { + if ($condition && !quit) { + t = tid() + begin = start_time[t] + if (begin > 0) { + elapsed = gettimeofday_us() - begin + if (elapsed >= $min_elapsed) { + bts[$gen_bt_code] <<< elapsed + found = 1 + } + delete start_time[t] + } + } +} + +$postamble +_EOC_ + + my %so_files; + { + my $maps_file = "/proc/$pid/maps"; + open my $in, $maps_file + or die "Cannot open $maps_file for reading: $!\n"; + + while (<$in>) { + if (/\s+(\/\S+\.so(?:\.\S+)?)$/) { + if (!exists $so_files{$1}) { + $so_files{$1} = 1; + #warn $1, "\n"; + } + } + } + + close $in; + } + + if (%so_files) { + $d_so_args = join " ", map { "-d $_" } sort keys %so_files; + } +} + +if ($dump_src) { + print $stap_src; + exit; +} + + +#warn "$d_so_args\n"; + +open my $in, "|stap --skip-badvars --all-modules -x $pid -d '$exec_path' --ldd $d_so_args $stap_args -" + or die "Cannot run stap: $!\n"; + +print $in $stap_src; + +close $in; + +sub usage { + return <<'_EOC_'; +Usage: + sample-bt-off-cpu [optoins] + +Options: + -a Pass extra arguments to the stap utility. + -d Dump out the systemtap script source. + --distr Analyze the distribution of the elapsed off-CPU times only. + -h Print this usage. + -k Analyze kernelspace backtraces. + -l Only output most frenquent backtrace samples. + (Default to 1024) + --min= Minimal elapsed off-CPU time to be tracked. + (Default to 4us) + -p Specify the user process pid. + -t Specify the number of seconds for sampling. + -u Analyze userspace backtraces. + +Examples: + sample-bt-off-cpu -p 12345 -t 10 + sample-bt-off-cpu -p 12345 -t 5 -a '-DMAXACTION=100000' + sample-bt-off-cpu --distr -p 12345 -t 10 --min=1 +_EOC_ +} diff --git a/stap/sample-bt-vfs b/stap/sample-bt-vfs new file mode 100644 index 0000000..d77b222 --- /dev/null +++ b/stap/sample-bt-vfs @@ -0,0 +1,233 @@ +#!/usr/bin/env perl + +# Copyright (C) Yichun Zhang (agentzh) + +use 5.006001; +use strict; +use warnings; + +use Getopt::Long qw( GetOptions ); + +GetOptions("a=s", \(my $stap_args), + "d", \(my $dump_src), + "h", \(my $help), + "l=i", \(my $limit), + "latency", \(my $check_latency), + "p=i", \(my $pid), + "r", \(my $readonly), + "w", \(my $writeonly), + "t=i", \(my $time)) + or die usage(); + +if ($help) { + print usage(); + exit; +} + +if (!defined $pid) { + die "No process pid specified by the -p option.\n"; +} + +my $condition = "pid() == target()"; + +if (!defined $time) { + die "No -t option specified.\n"; +} + +if (!defined $limit) { + $limit = 1024; +} + +if (!defined $stap_args) { + $stap_args = ''; +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXACTION=/) { + $stap_args .= " -DMAXACTION=100000"; +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXMAPENTRIES=/) { + $stap_args .= " -DMAXMAPENTRIES=5000"; +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXBACKTRACE=/) { + $stap_args .= " -DMAXBACKTRACE=200"; +} + +if ($stap_args !~ /(?:^|\s)-D\s*MAXSTRINGLEN=2048/) { + $stap_args .= " -DMAXSTRINGLEN=2048"; +} + +$stap_args .= " -DSTP_NO_OVERLOAD"; + +if ($^O ne 'linux') { + die "Only linux is supported but I am on $^O.\n"; +} + +my $exec_file = "/proc/$pid/exe"; +if (!-f $exec_file) { + die "Nginx process $pid is not running or ", + "you do not have enough permissions.\n"; +} + +my $exec_path = readlink $exec_file; + +my $ver = `stap --version 2>&1`; +if (!defined $ver) { + die "Systemtap not installed or its \"stap\" utility is not visible to the PATH environment: $!\n"; +} + +if ($ver =~ /version\s+(\d+\.\d+)/i) { + my $v = $1; + if ($v < 2.1) { + die "ERROR: at least systemtap 2.1 is required but found $v\n"; + } + +} else { + die "ERROR: unknown version of systemtap:\n$ver\n"; +} + +my $preamble = <<_EOC_; +global bts; +global quit = 0; + +probe begin { + warn(sprintf("Tracing %d ($exec_path)...\\n", target())) +} +_EOC_ + +my $postamble = <<_EOC_; +probe timer.s($time) { + nstacks = 0 + foreach (bt in bts limit 10) { + nstacks++ + } + + if (nstacks == 0) { + warn(sprintf("Too few backtraces (%d) found. Quitting now...\\n", nstacks)) + exit() + + } else { + warn("Time's up. Quitting now...(it may take a while)\\n") + quit = 1 + } +} +_EOC_ + +my @probes; +if ($readonly) { + @probes = qw(vfs.read); + +} elsif ($writeonly) { + @probes = qw(vfs.write); + +} else { + @probes = qw(vfs.read vfs.write); +} + +my $return_probes = join ", ", map { "$_.return" } @probes; + +my $stap_src; +if ($check_latency) { + # analyze I/O latency + my $entry_probes = join ", ", @probes; + $stap_src = <<_EOC_; +$preamble + +global start_time + +probe $entry_probes { + if ($condition) { + if (!quit) { + if (devname != "N/A") { + start_time = gettimeofday_us() + } + + } else { + foreach (bt in bts- limit $limit) { + print_ustack(bt) + printf("\\t%d\\n", \@sum(bts[bt])) + } + + exit() + } + } +} + +probe $return_probes { + if ($condition) { + if (!quit) { + if (\$return > 0 && devname != "N/A" && start_time) { + bts[ubacktrace()] <<< gettimeofday_us() - start_time + start_time = 0; + } + } + } +} + +$postamble +_EOC_ + +} else { + # analyze I/O data volumn + $stap_src = <<_EOC_; +$preamble + +probe $return_probes { + if ($condition) { + if (!quit) { + if (\$return > 0 && devname != "N/A") { + bts[ubacktrace()] <<< \$return + } + + } else { + + foreach (bt in bts- limit $limit) { + print_ustack(bt); + printf("\\t%d\\n", \@sum(bts[bt])) + } + + exit() + } + } +} + +$postamble +_EOC_ +} + +if ($dump_src) { + print $stap_src; + exit; +} + +open my $in, "|stap --skip-badvars --all-modules -x $pid -d '$exec_path' --ldd $stap_args -" + or die "Cannot run stap: $!\n"; + +print $in $stap_src; + +close $in; + +sub usage { + return <<'_EOC_'; +Usage: + sample-bt-vfs [optoins] + +Options: + -a Pass extra arguments to the stap utility. + -d Dump out the systemtap script source. + -h Print this usage. + --latency Analyze the VFS kernel calls' latency instead + of I/O data volumn. + -l Only output most frenquent backtrace samples. + (Default to 1024) + -p Specify the user process pid. + -r Probe file reading operations only. + -w Probe file writing operations only. + -t Specify the number of seconds for sampling. + +Examples: + sample-bt-vfs -p 12345 -t 10 + sample-bt-vfs -p 12345 -t 5 -a '-DMAXACTION=100000' +_EOC_ +} From 747755a5931affc55dc6af92d246e28bc2c597b7 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 23 May 2016 17:27:30 +0800 Subject: [PATCH 110/173] =?UTF-8?q?=E5=B1=8F=E8=94=BD=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deps/lua/lauxlib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deps/lua/lauxlib.c b/deps/lua/lauxlib.c index f305417..cf99875 100644 --- a/deps/lua/lauxlib.c +++ b/deps/lua/lauxlib.c @@ -1050,7 +1050,7 @@ static shared_lstate_t shared_closure[] = { static atomic_t shared_lstate_count = 0; static shared_lstate_t* get_shared_lstate() { - int i; + size_t i; shared_lstate_t* sl; for (;;) { for (i = 1; i < array_size(shared_closure); ++i) { @@ -1192,7 +1192,7 @@ static int luaL_loadfilex_clone (lua_State *L, const char *filename, const char /* warning: need to wait for all threads to be terminated in muti-thread situation */ LUALIB_API int luaL_closesharedclosure() { - int i; + size_t i; shared_lstate_t* sl; clear_shared_closure(); @@ -1208,6 +1208,7 @@ LUALIB_API int luaL_closesharedclosure() { static int cache_clear(lua_State *L) { + (void)L; /* not used */ clear_shared_closure(); return 0; } From 761fa9c42009a2c18be0c0333fc32dbf91f78020 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 23 May 2016 17:43:31 +0800 Subject: [PATCH 111/173] =?UTF-8?q?=E5=B1=8F=E8=94=BD=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Makefile | 2 +- src/uv_tcp_handle.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 0b8120d..a12d995 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,7 @@ LIBRARY_PATH := ../deps/lua ../deps/uv LIBS := nlua uv m ## define CFLAGS -CFLAGS += -g -pedantic -O3 -Wall -Wextra -Wno-unused-parameter -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) CFLAGS += -D RELEASE endif diff --git a/src/uv_tcp_handle.h b/src/uv_tcp_handle.h index 22f7e08..2ebb000 100644 --- a/src/uv_tcp_handle.h +++ b/src/uv_tcp_handle.h @@ -162,7 +162,7 @@ class uv_tcp_socket_handle_t : public uv_handle_base_t m_write_cached_reqs.push_back(request); } void clear_write_cached_requests() { - for (int i = 0; i < m_write_cached_reqs.size(); ++i) { + for (size_t i = 0; i < m_write_cached_reqs.size(); ++i) { nl_free(m_write_cached_reqs[i]); } m_write_cached_reqs.clear(); From cbba2f7c68c3ed477c17060f00ff7f6b747ddf2a Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 24 May 2016 13:21:16 +0800 Subject: [PATCH 112/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 5 ++--- src/lbuffer.cpp | 5 +++-- src/lua_udp_handle.cpp | 1 + src/message.cpp | 2 +- src/ref_sessions_mgr.cpp | 2 +- src/uv_udp_handle.cpp | 5 ++--- src/uv_udp_handle.h | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 42120d5..1be3537 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -604,7 +604,7 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) array = message_array(message); if (array != NULL && array->m_count > 0) { lua_checkstack(L, array->m_count); - for (int32_t i = 0; i < array->m_count; ++i) { //extract them + for (uint32_t i = 0; i < array->m_count; ++i) { //extract them lua_pushmessage(L, array->m_array[i]); } } else { @@ -929,7 +929,6 @@ int32_t context_lua_t::context_destroy(lua_State *L) int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t msg_type, message_t& message) { buffer_t* buffer; - bson_t* bson_ptr; int32_t* bson_data; const char* data; size_t length; @@ -1001,7 +1000,7 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t message.m_type = MAKE_MESSAGE_TYPE(msg_type, ARRAY); message.m_data.m_array = array; message.m_source = lua_get_context_handle(L); - for (int32_t i = 0; i < count; ++i) { + for (uint32_t i = 0; i < count; ++i) { if (context_check_message(L, idx + i, msg_type, array->m_array[i]) == 0) { return 0; } diff --git a/src/lbuffer.cpp b/src/lbuffer.cpp index 4b47090..dde519f 100644 --- a/src/lbuffer.cpp +++ b/src/lbuffer.cpp @@ -91,9 +91,10 @@ static int32_t lbuffer_find(lua_State* L) if (buffer_is_valid(*buffer)) { int32_t top = lua_gettop(L); if (top >= 2) { - const char* find = strstr(buffer_data_ptr(*buffer), luaL_checklstring(L, 2, NULL)); + const char* ptr = buffer_data_ptr(*buffer); + const char* find = strstr(ptr, luaL_checklstring(L, 2, NULL)); if (find) { - lua_pushinteger(L, (int32_t)(find - buffer_data_ptr(*buffer)) + 1); + lua_pushinteger(L, (int32_t)(find - ptr) + 1); return 1; } return 0; diff --git a/src/lua_udp_handle.cpp b/src/lua_udp_handle.cpp index 3d08cda..3dc9f79 100644 --- a/src/lua_udp_handle.cpp +++ b/src/lua_udp_handle.cpp @@ -268,6 +268,7 @@ int32_t lua_udp_handle_t::read(lua_State* L) request.m_length = REQUEST_SIZE(request_udp_read_t, 0); request.m_udp_read.m_socket_handle = (uv_udp_handle_t*)socket->m_uv_handle; singleton_ref(network_t).send_request(request); + return 0; } int32_t lua_udp_handle_t::read_callback_adjust(lua_State* L) diff --git a/src/message.cpp b/src/message.cpp index e6bdcac..1e8cce8 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -8,7 +8,7 @@ message_array_t* message_array_create(uint32_t count) { void message_array_release(message_array_t* array) { if (array != NULL) { - for (int32_t i = 0; i < array->m_count; ++i) { + for (uint32_t i = 0; i < array->m_count; ++i) { message_clean(array->m_array[i]); } nl_free(array); diff --git a/src/ref_sessions_mgr.cpp b/src/ref_sessions_mgr.cpp index 9f93817..c53b5ea 100644 --- a/src/ref_sessions_mgr.cpp +++ b/src/ref_sessions_mgr.cpp @@ -153,7 +153,7 @@ void ref_sessions_mgr_t::put_cached_sessions(ref_sessions_t* ref_sessions) void ref_sessions_mgr_t::clear_cached_sessions() { - for (int32_t i = 0; i < m_cached_sessions.size(); ++i) { + for (size_t i = 0; i < m_cached_sessions.size(); ++i) { delete (m_cached_sessions[i]); } m_cached_sessions.clear(); diff --git a/src/uv_udp_handle.cpp b/src/uv_udp_handle.cpp index c9ef007..580104d 100644 --- a/src/uv_udp_handle.cpp +++ b/src/uv_udp_handle.cpp @@ -79,7 +79,7 @@ void uv_udp_handle_t::on_write(uv_udp_send_t* req, int status) } else { buffer_release(uv_request->m_buffer); } - if (uv_request->m_session != LUA_REFNIL) { + if (uv_request->m_session != (uint32_t)LUA_REFNIL) { singleton_ref(node_lua_t).context_send(uv_request->m_source, 0, uv_request->m_session, RESPONSE_UDP_WRITE, status == 0 ? UV_OK : singleton_ref(network_t).last_error()); } socket_handle->put_write_cached_request(uv_request); @@ -91,7 +91,6 @@ void uv_udp_handle_t::write(request_udp_write_t& request) if (request.m_shared_write) { uv_udp_handle_t* handle = (uv_udp_handle_t*)singleton_ref(network_t).get_shared_write_socket(request.m_socket_fd); if (handle != NULL) { - uint32_t length = request.m_length > 0 ? request.m_length : (uint32_t)buffer_data_length(request.m_buffer); if (uv_is_closing((uv_handle_t*)handle)) { err = NL_EUDPSCLOSED; } else { @@ -109,7 +108,7 @@ void uv_udp_handle_t::write(request_udp_write_t& request) } else { buffer_release(request.m_buffer); } - if (request.m_session != LUA_REFNIL) { + if (request.m_session != (uint32_t)LUA_REFNIL) { singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_UDP_WRITE, (nl_err_code)err); } } diff --git a/src/uv_udp_handle.h b/src/uv_udp_handle.h index 386491a..967033c 100644 --- a/src/uv_udp_handle.h +++ b/src/uv_udp_handle.h @@ -72,7 +72,7 @@ class uv_udp_handle_t : public uv_handle_base_t m_write_cached_reqs.push_back(request); } void clear_write_cached_requests() { - for (int i = 0; i < m_write_cached_reqs.size(); ++i) { + for (size_t i = 0; i < m_write_cached_reqs.size(); ++i) { nl_free(m_write_cached_reqs[i]); } m_write_cached_reqs.clear(); From 9c0e09c63b5e585a9f39e3a4d44d4c399a4ef28a Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 24 May 2016 13:23:22 +0800 Subject: [PATCH 113/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/uv_tcp_handle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index a991c33..7dba8f7 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -221,7 +221,7 @@ void uv_tcp_socket_handle_t::on_write(uv_write_t* req, int status) } else { buffer_release(uv_request->m_buffer); } - if (uv_request->m_session != LUA_REFNIL) { + if (uv_request->m_session != (uint32_t)LUA_REFNIL) { singleton_ref(node_lua_t).context_send(uv_request->m_source, 0, uv_request->m_session, RESPONSE_TCP_WRITE, status == 0 ? UV_OK : socket_handle->m_write_error); } socket_handle->put_write_cached_request(uv_request); @@ -253,7 +253,7 @@ void uv_tcp_socket_handle_t::write(request_tcp_write_t& request) } else { buffer_release(request.m_buffer); } - if (request.m_session != LUA_REFNIL) { + if (request.m_session != (uint32_t)LUA_REFNIL) { singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_WRITE, (nl_err_code)err); } } From cda37aca6862b7ba392167105e2f3a709a87c47e Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 24 May 2016 13:31:56 +0800 Subject: [PATCH 114/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/endian_conv.cpp | 7 +++++++ src/endian_conv.h | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/endian_conv.cpp b/src/endian_conv.cpp index dddf548..e93cc51 100644 --- a/src/endian_conv.cpp +++ b/src/endian_conv.cpp @@ -1,6 +1,13 @@ #include "common.h" #include "endian_conv.h" +#define LITTLE_ENDIAN_VAL ((char)'L') +#define BIG_ENDIAN_VAL ((char)'B') +static union { char c[4]; unsigned long mylong; } endian_test = { { LITTLE_ENDIAN_VAL, '?', '?', BIG_ENDIAN_VAL } }; +#define ENV_ENDIAN_VAL ((char)endian_test.mylong) +#define ENV_IS_LITTEL_ENDIAN (ENV_ENDIAN_VAL == LITTLE_ENDIAN_VAL) +#define ENV_IS_BIG_ENDIAN (ENV_ENDIAN_VAL == BIG_ENDIAN_VAL) + int16_t endian_to_int16(char *src, char src_endian) { if (src_endian == ENV_ENDIAN_VAL) { diff --git a/src/endian_conv.h b/src/endian_conv.h index 350bd54..2addda4 100644 --- a/src/endian_conv.h +++ b/src/endian_conv.h @@ -1,13 +1,6 @@ #ifndef ENDIAN_CONV_H_ #define ENDIAN_CONV_H_ -#define LITTLE_ENDIAN_VAL ((char)'L') -#define BIG_ENDIAN_VAL ((char)'B') -static union { char c[4]; unsigned long mylong; } endian_test = { { LITTLE_ENDIAN_VAL, '?', '?', BIG_ENDIAN_VAL } }; -#define ENV_ENDIAN_VAL ((char)endian_test.mylong) -#define ENV_IS_LITTEL_ENDIAN (ENV_ENDIAN_VAL == LITTLE_ENDIAN_VAL) -#define ENV_IS_BIG_ENDIAN (ENV_ENDIAN_VAL == BIG_ENDIAN_VAL) - extern int16_t endian_to_int16(char *src, char src_endian); extern int32_t endian_to_int32(char *src, char src_endian); extern int64_t endian_to_int64(char *src, char src_endian); From 1bfb359610a45fa9a5daf567e361890041923fbb Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 24 May 2016 13:36:30 +0800 Subject: [PATCH 115/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/endian_conv.cpp | 7 +++++-- src/endian_conv.h | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/endian_conv.cpp b/src/endian_conv.cpp index e93cc51..3a2e51e 100644 --- a/src/endian_conv.cpp +++ b/src/endian_conv.cpp @@ -1,13 +1,16 @@ #include "common.h" #include "endian_conv.h" -#define LITTLE_ENDIAN_VAL ((char)'L') -#define BIG_ENDIAN_VAL ((char)'B') static union { char c[4]; unsigned long mylong; } endian_test = { { LITTLE_ENDIAN_VAL, '?', '?', BIG_ENDIAN_VAL } }; #define ENV_ENDIAN_VAL ((char)endian_test.mylong) #define ENV_IS_LITTEL_ENDIAN (ENV_ENDIAN_VAL == LITTLE_ENDIAN_VAL) #define ENV_IS_BIG_ENDIAN (ENV_ENDIAN_VAL == BIG_ENDIAN_VAL) +char env_endian() +{ + return ENV_ENDIAN_VAL; +} + int16_t endian_to_int16(char *src, char src_endian) { if (src_endian == ENV_ENDIAN_VAL) { diff --git a/src/endian_conv.h b/src/endian_conv.h index 2addda4..b8c59fc 100644 --- a/src/endian_conv.h +++ b/src/endian_conv.h @@ -1,6 +1,10 @@ #ifndef ENDIAN_CONV_H_ #define ENDIAN_CONV_H_ +#define LITTLE_ENDIAN_VAL ((char)'L') +#define BIG_ENDIAN_VAL ((char)'B') + +extern char env_endian(); extern int16_t endian_to_int16(char *src, char src_endian); extern int32_t endian_to_int32(char *src, char src_endian); extern int64_t endian_to_int64(char *src, char src_endian); From 38c88042b5c6e414d1cf96a59216e18f37fab9f6 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 24 May 2016 14:17:34 +0800 Subject: [PATCH 116/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.cpp b/src/utils.cpp index e25d0a1..e2283e2 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -47,6 +47,7 @@ void* nl_memdup(const void* src, uint32_t len) bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, bool* ipv6, uint16_t* port) { union sock_name_u { + sockaddr sock; sockaddr_in sock4; sockaddr_in6 sock6; } sock_name; @@ -58,7 +59,7 @@ bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, b #endif if (result != 0) return false; - uint16_t family = ((sockaddr*)&sock_name)->sa_family; + uint16_t family = sock_name.sock.sa_family; if (family == AF_INET) { if (host != NULL) { uv_ip4_name(&sock_name.sock4, host, host_len); From 033f7beca210a1c8ff1c84a9741946243729429a Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 24 May 2016 14:24:00 +0800 Subject: [PATCH 117/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lbson.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lbson.cpp b/src/lbson.cpp index a46bda1..75af518 100644 --- a/src/lbson.cpp +++ b/src/lbson.cpp @@ -765,7 +765,7 @@ lreplace(lua_State *L) { int type = id & ((1<<(BSON_TYPE_SHIFT)) - 1); int offset = id >> BSON_TYPE_SHIFT; uint8_t * start = (uint8_t *)lua_touserdata(L, 1); - struct bson b = { false, 0, 16, start + offset }; + struct bson b = { false, 0, 16, start + offset, { 0 } }; switch (type) { case BSON_REAL: write_double(&b, luaL_checknumber(L, 3)); @@ -951,7 +951,7 @@ lsubtype(lua_State *L, int subtype, const uint8_t * buf, size_t sz) { char oid[24]; int i; const uint8_t * id = buf; - static char *hex = "0123456789abcdef"; + static const char *hex = "0123456789abcdef"; for (i=0;i<12;i++) { oid[i*2] = hex[id[i] >> 4]; oid[i*2+1] = hex[id[i] & 0xf]; @@ -1091,7 +1091,7 @@ init_oid_header() { uint32_t h = 0; char hostname[256]; if (gethostname(hostname, sizeof(hostname))==0) { - int i; + size_t i; for (i=0;i>2)+hostname[i]); } @@ -1245,7 +1245,6 @@ static int bson_encode_safe(lua_State *L) { bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx) { if (lua_istable(L, idx)) { - int status; lua_checkstack(L, 3); lua_pushcfunction(L, bson_encode_safe); lua_pushvalue(L, idx); From d1b722619b55147d2f83b8b4f5892b9a7540d91d Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 2 Jun 2016 21:03:17 +0800 Subject: [PATCH 118/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0lua=20table=E7=9A=84?= =?UTF-8?q?=E5=8E=8B=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.vcxproj | 1 + node-lua.vcxproj.filters | 3 +++ src/ltpack.cpp | 1 + src/ltpack.h | 6 ++++++ 4 files changed, 11 insertions(+) create mode 100644 src/ltpack.cpp create mode 100644 src/ltpack.h diff --git a/node-lua.vcxproj b/node-lua.vcxproj index 6a80bcc..c90fdb3 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -140,6 +140,7 @@ + diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index 22dc214..113bc52 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -203,5 +203,8 @@ src + + src + \ No newline at end of file diff --git a/src/ltpack.cpp b/src/ltpack.cpp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/ltpack.cpp @@ -0,0 +1 @@ + diff --git a/src/ltpack.h b/src/ltpack.h new file mode 100644 index 0000000..50a7c44 --- /dev/null +++ b/src/ltpack.h @@ -0,0 +1,6 @@ +#ifndef LTPACK_H_ +#define LTPACK_H_ + + + +#endif From 967ef0b22f0c9025c50d2151e4c84590f497d92b Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 8 Jun 2016 14:33:59 +0800 Subject: [PATCH 119/173] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=8C=E8=BF=9B?= =?UTF-8?q?=E5=88=B6=E6=95=B0=E6=8D=AE=E4=BC=A0=E8=BE=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.vcxproj | 2 ++ node-lua.vcxproj.filters | 6 ++++++ src/context_log.cpp | 6 +++--- src/context_lua.cpp | 21 ++++++++++----------- src/lbinary.h | 9 +++++++++ src/ltpack.h | 2 -- src/message.h | 22 +++++++++++----------- src/node_lua.h | 21 ++++++++++----------- src/sds.cpp | 10 ++++++++++ src/sds.h | 1 + 10 files changed, 62 insertions(+), 38 deletions(-) create mode 100644 src/lbinary.h diff --git a/node-lua.vcxproj b/node-lua.vcxproj index c90fdb3..143bc64 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -103,8 +103,10 @@ + + diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index 113bc52..f285b71 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -114,6 +114,12 @@ include + + include + + + include + diff --git a/src/context_log.cpp b/src/context_log.cpp index 7f78e36..0875512 100644 --- a/src/context_log.cpp +++ b/src/context_log.cpp @@ -39,9 +39,9 @@ void context_log_t::on_dropped(message_t& message) void context_log_t::log_message(message_t& message) { switch (message_data_type(message)) { - case SDS: - if (message_sds(message)) { - lua_writestring(message_sds(message), sdslen(message_sds(message))); + case BINARY: + if (message_binary(message).m_data) { + lua_writestring(message_binary(message).m_data, sdslen(message_binary(message).m_data)); lua_writeline(); } break; diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 1be3537..7a124cd 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -583,9 +583,9 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) lua_pushstring(L, ""); } return; - case SDS: - if (message_sds(message)) { - lua_pushlstring(L, message_sds(message), sdslen(message_sds(message))); + case BINARY: + if (message_binary(message).m_data) { + lua_pushlstring(L, message_binary(message).m_data, sdslen(message_binary(message).m_data)); } else { lua_pushstring(L, ""); } @@ -945,8 +945,8 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t return 1; case LUA_TSTRING: data = lua_tolstring(L, idx, &length); - message.m_type = MAKE_MESSAGE_TYPE(msg_type, SDS); - message.m_data.m_sds = sdsnewlen(data, length); + message.m_type = MAKE_MESSAGE_TYPE(msg_type, BINARY); + message.m_data.m_binary.m_data = sdsnewlen(data, length); message.m_source = lua_get_context_handle(L); return 1; case LUA_TBOOLEAN: @@ -1334,8 +1334,7 @@ int32_t context_lua_t::context_log(lua_State *L) context_lua_t* lctx = context_lua_t::lua_get_context(L); int32_t n = lua_gettop(L); /* number of arguments */ int32_t i; - sds buffer = sdsnewlen(NULL, 64); - sdsclear(buffer); + binary_t binary = { sdsnewempty(64) }; lua_getglobal(L, "tostring"); for (i = 1; i <= n; i++) { const char *s; @@ -1345,14 +1344,14 @@ int32_t context_lua_t::context_log(lua_State *L) lua_call(L, 1, 1); s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) { - sdsfree(buffer); + sdsfree(binary.m_data); return luaL_error(L, "'tostring' must return a string to 'context.log'"); } - if (i > 1) buffer = sdscatlen(buffer, "\t", 1); - buffer = sdscatlen(buffer, s, l); + if (i > 1) binary.m_data = sdscatlen(binary.m_data, "\t", 1); + binary.m_data = sdscatlen(binary.m_data, s, l); lua_pop(L, 1); /* pop result */ } - singleton_ref(node_lua_t).log_sds_release(lctx->get_handle(), buffer); + singleton_ref(node_lua_t).log_binary_release(lctx->get_handle(), binary); return 0; } diff --git a/src/lbinary.h b/src/lbinary.h new file mode 100644 index 0000000..2e94981 --- /dev/null +++ b/src/lbinary.h @@ -0,0 +1,9 @@ +#ifndef LBINARY_H_ +#define LBINARY_H_ +#include "sds.h" + +typedef struct binary_t { + char* m_data; +} binary_t; + +#endif \ No newline at end of file diff --git a/src/ltpack.h b/src/ltpack.h index 50a7c44..f312cd0 100644 --- a/src/ltpack.h +++ b/src/ltpack.h @@ -1,6 +1,4 @@ #ifndef LTPACK_H_ #define LTPACK_H_ - - #endif diff --git a/src/message.h b/src/message.h index 75bbb1d..1948528 100644 --- a/src/message.h +++ b/src/message.h @@ -2,7 +2,7 @@ #define MESSAGE_H_ #include "buffer.h" #include "lbson.h" -#include "sds.h" +#include "lbinary.h" #define MESSAGE_TYPE_BIT 24 #define MAKE_MESSAGE_TYPE(mtype, dtype) (((uint32_t)(dtype) << MESSAGE_TYPE_BIT) | ((mtype) & (((uint32_t)1 << MESSAGE_TYPE_BIT) - 1))) @@ -20,7 +20,7 @@ enum data_type { INTEGER = 4, //support after lua53 BUFFER = 5, //need to be freed STRING = 6, //need to be freed - SDS = 7, //need to be freed + BINARY = 7, //need to be freed BSON = 8, //need to be freed ARRAY = 9, //need to be freed TERROR = 10 // @@ -33,7 +33,7 @@ typedef union data_t { int64_t m_integer; buffer_t m_buffer; char *m_string; - char *m_sds; + binary_t m_binary; bson_t *m_bson; message_array_t *m_array; int32_t m_error; @@ -74,7 +74,7 @@ enum message_type { #define message_integer(msg) ((msg).m_data.m_integer) #define message_buffer(msg) ((msg).m_data.m_buffer) #define message_string(msg) ((msg).m_data.m_string) -#define message_sds(msg) ((msg).m_data.m_sds) +#define message_binary(msg) ((msg).m_data.m_binary) #define message_bson(msg) ((msg).m_data.m_bson) #define message_array(msg) ((msg).m_data.m_array) #define message_error(msg) ((msg).m_data.m_error) @@ -87,7 +87,7 @@ enum message_type { #define message_is_integer(msg) (INTEGER == message_data_type(msg)) #define message_is_buffer(msg) (BUFFER == message_data_type(msg)) #define message_is_string(msg) (STRING == message_data_type(msg)) -#define message_is_sds(msg) (SDS == message_data_type(msg)) +#define message_is_binary(msg) (BINARY == message_data_type(msg)) #define message_is_bson(msg) (BSON == message_data_type(msg)) #define message_is_array(msg) (ARRAY == message_data_type(msg)) #define message_is_error(msg) (TERROR == message_data_type(msg)) @@ -103,10 +103,10 @@ enum message_type { nl_free((msg).m_data.m_string); \ (msg).m_data.m_string = NULL; \ } \ - } else if (message_is_sds(msg)) { \ - if ((msg).m_data.m_sds) { \ - sdsfree((msg).m_data.m_sds); \ - (msg).m_data.m_sds = NULL; \ + } else if (message_is_binary(msg)) { \ + if ((msg).m_data.m_binary.m_data) { \ + sdsfree((msg).m_data.m_binary.m_data); \ + (msg).m_data.m_binary.m_data = NULL; \ } \ } else if (message_is_bson(msg)) { \ if ((msg).m_data.m_bson) { \ @@ -167,9 +167,9 @@ class message_t { : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, BSON)) { m_data.m_bson = bson; } - message_t(uint32_t source, int32_t session, uint32_t msg_type, char *string, int32_t length) + message_t(uint32_t source, int32_t session, uint32_t msg_type, binary_t binary) : m_source(source), m_session(session), - m_type(MAKE_MESSAGE_TYPE(msg_type, SDS)) { m_data.m_sds = string; } + m_type(MAKE_MESSAGE_TYPE(msg_type, BINARY)) { m_data.m_binary = binary; } message_t(uint32_t source, int32_t session, uint32_t msg_type, message_array_t* array) : m_source(source), m_session(session), diff --git a/src/node_lua.h b/src/node_lua.h index 4e0db1f..54dc934 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -5,7 +5,7 @@ #include "context_mgr.h" #include "worker_mgr.h" #include "context.h" -#include "sds.h" +#include "lbinary.h" class message_t; class network_t; @@ -55,20 +55,20 @@ class node_lua_t : public singleton_t { } /* specific context send interface */ - FORCE_INLINE bool context_send_sds_safe(uint32_t handle, uint32_t source, int session, int msg_type, const char *data, int32_t length) + FORCE_INLINE bool context_send_binary_safe(uint32_t handle, uint32_t source, int session, int msg_type, const char *data, int32_t length) { - char* str = data ? sdsnewlen(data, length) : NULL; - message_t msg(source, session, msg_type, str, length); + binary_t binary = { data ? sdsnewlen(data, length) : NULL }; + message_t msg(source, session, msg_type, binary); if (context_send(handle, msg)) return true; message_clean(msg); return false; } - FORCE_INLINE bool context_send_sds_safe(context_t* ctx, uint32_t source, int session, int msg_type, const char *data, int32_t length) + FORCE_INLINE bool context_send_binary_safe(context_t* ctx, uint32_t source, int session, int msg_type, const char *data, int32_t length) { - char* str = data ? sdsnewlen(data, length) : NULL; - message_t msg(source, session, msg_type, str, length); + binary_t binary = { data ? sdsnewlen(data, length) : NULL }; + message_t msg(source, session, msg_type, binary); if (context_send(ctx, msg)) return true; message_clean(msg); @@ -209,12 +209,11 @@ class node_lua_t : public singleton_t { } } - bool log_sds_release(uint32_t src_handle, sds buffer) { - message_t message(src_handle, 0, LOG_MESSAGE, (char*)buffer, sdslen(buffer)); - if (m_logger && context_send(m_logger, message)) { + bool log_binary_release(uint32_t src_handle, binary_t binary) { + if (m_logger && context_send(m_logger, src_handle, 0, LOG_MESSAGE, binary)) { return true; } - sdsfree(buffer); + sdsfree(binary.m_data); return false; } diff --git a/src/sds.cpp b/src/sds.cpp index 08130fd..e51f189 100644 --- a/src/sds.cpp +++ b/src/sds.cpp @@ -77,6 +77,16 @@ sds sdsnew(const char *init) { return sdsnewlen(init, initlen); } +/* Create an empty sds string with capacity. Even in this case the string +* always has an implicit null term. */ +sds sdsnewempty(size_t capacity) { + struct sdshdr *sh = (struct sdshdr *)nl_calloc(sizeof(struct sdshdr) + capacity + 1); + if (sh == NULL) return NULL; + sh->len = 0; + sh->free = capacity; + return (char*)sh->buf; +} + /* Duplicate an sds string. */ sds sdsdup(const sds s) { return sdsnewlen(s, sdslen(s)); diff --git a/src/sds.h b/src/sds.h index 57db249..ac77bc9 100644 --- a/src/sds.h +++ b/src/sds.h @@ -56,6 +56,7 @@ static inline size_t sdsavail(const sds s) { sds sdsnewlen(const void *init, size_t initlen); sds sdsnew(const char *init); +sds sdsnewempty(size_t capacity); sds sdsempty(void); size_t sdslen(const sds s); sds sdsdup(const sds s); From 47212fcc73ab4f3be748985a570e5c89ddccbd94 Mon Sep 17 00:00:00 2001 From: xdczju Date: Wed, 8 Jun 2016 21:26:11 +0800 Subject: [PATCH 120/173] do nothing --- src/ltpack.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/ltpack.h | 5 ++++ src/message.h | 8 +++--- 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/ltpack.cpp b/src/ltpack.cpp index 8b13789..4c8ae21 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -1 +1,72 @@ +#include "ltpack.h" +#include "common.h" +#define __STDC_LIMIT_MACROS +#ifndef _WIN32 +# include +#endif +#define MAX_DEPTH 128 + +#define TYPE_INT8 0 +#define TYPE_INT16 1 +#define TYPE_INT32 2 +#define TYPE_INT64 3 +#define TYPE_DOUBLE 4 +#define TYPE_STRING 5 +#define TYPE_BOOL 6 +#define TYPE_TABLE 7 +// +//static inline void +//pack_int(tpack_t *pack, int64_t v) { +// if (v >= INT8_MIN && v <= INT8_MAX) { +// pack->m_data = sdsMakeRoomFor(pack->m_data, 2); +// return TYPE_INT8; +// } +// if (v >= INT16_MIN && v <= INT16_MAX) { +// return TYPE_INT16; +// } +// if (v >= INT32_MIN && v <= INT32_MAX) { +// return TYPE_INT32; +// } +// return TYPE_INT64; +//} +// +//static void +//pack_dict(lua_State *L, tpack_t *b, int depth) { +// if (depth > MAX_DEPTH) { +// luaL_error(L, "Too depth while encoding bson"); +// } +// luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table +// lua_pushnil(L); +// while (lua_next(L, -2) != 0) { +// int kt = lua_type(L, -2); +// const char * key = NULL; +// size_t sz; +// switch (kt) { +// case LUA_TNUMBER: +// if (lua_isinteger(L, -2)) { +// lua_tointeger(L, -2); +// } else { +// lua_tonumber(L, -2); +// } +// // copy key, don't change key type +// lua_pushvalue(L, -2); +// lua_insert(L, -2); +// key = lua_tolstring(L, -2, &sz); +// append_one(b, L, key, sz, depth); +// lua_pop(L, 2); +// break; +// case LUA_TSTRING: +// key = lua_tolstring(L, -2, &sz); +// append_one(b, L, key, sz, depth); +// lua_pop(L, 1); +// break; +// case LUA_TBOOLEAN: +// break; +// default: +// luaL_error(L, "Invalid key type : %s", lua_typename(L, kt)); +// return; +// } +// +// } +//} diff --git a/src/ltpack.h b/src/ltpack.h index f312cd0..1750737 100644 --- a/src/ltpack.h +++ b/src/ltpack.h @@ -1,4 +1,9 @@ #ifndef LTPACK_H_ #define LTPACK_H_ +#include "sds.h" + +typedef struct tpack_t { + char* m_data; +} tpack_t; #endif diff --git a/src/message.h b/src/message.h index 1948528..c452865 100644 --- a/src/message.h +++ b/src/message.h @@ -3,6 +3,7 @@ #include "buffer.h" #include "lbson.h" #include "lbinary.h" +#include "ltpack.h" #define MESSAGE_TYPE_BIT 24 #define MAKE_MESSAGE_TYPE(mtype, dtype) (((uint32_t)(dtype) << MESSAGE_TYPE_BIT) | ((mtype) & (((uint32_t)1 << MESSAGE_TYPE_BIT) - 1))) @@ -21,9 +22,10 @@ enum data_type { BUFFER = 5, //need to be freed STRING = 6, //need to be freed BINARY = 7, //need to be freed - BSON = 8, //need to be freed - ARRAY = 9, //need to be freed - TERROR = 10 // + TPACK = 8, //need to be freed + BSON = 9, //need to be freed + ARRAY = 10,//need to be freed + TERROR = 11 // }; typedef union data_t { From 070f679b2a21c5ebbd8a52f553278a563e1a39ba Mon Sep 17 00:00:00 2001 From: xdczju Date: Fri, 17 Jun 2016 19:17:29 +0800 Subject: [PATCH 121/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ltpack=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ltpack.cpp | 198 +++++++++++++++++++++++++++++++++++-------------- src/ltpack.h | 2 +- src/sds.h | 17 +++++ 3 files changed, 160 insertions(+), 57 deletions(-) diff --git a/src/ltpack.cpp b/src/ltpack.cpp index 4c8ae21..048627c 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -14,59 +14,145 @@ #define TYPE_DOUBLE 4 #define TYPE_STRING 5 #define TYPE_BOOL 6 -#define TYPE_TABLE 7 -// -//static inline void -//pack_int(tpack_t *pack, int64_t v) { -// if (v >= INT8_MIN && v <= INT8_MAX) { -// pack->m_data = sdsMakeRoomFor(pack->m_data, 2); -// return TYPE_INT8; -// } -// if (v >= INT16_MIN && v <= INT16_MAX) { -// return TYPE_INT16; -// } -// if (v >= INT32_MIN && v <= INT32_MAX) { -// return TYPE_INT32; -// } -// return TYPE_INT64; -//} -// -//static void -//pack_dict(lua_State *L, tpack_t *b, int depth) { -// if (depth > MAX_DEPTH) { -// luaL_error(L, "Too depth while encoding bson"); -// } -// luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table -// lua_pushnil(L); -// while (lua_next(L, -2) != 0) { -// int kt = lua_type(L, -2); -// const char * key = NULL; -// size_t sz; -// switch (kt) { -// case LUA_TNUMBER: -// if (lua_isinteger(L, -2)) { -// lua_tointeger(L, -2); -// } else { -// lua_tonumber(L, -2); -// } -// // copy key, don't change key type -// lua_pushvalue(L, -2); -// lua_insert(L, -2); -// key = lua_tolstring(L, -2, &sz); -// append_one(b, L, key, sz, depth); -// lua_pop(L, 2); -// break; -// case LUA_TSTRING: -// key = lua_tolstring(L, -2, &sz); -// append_one(b, L, key, sz, depth); -// lua_pop(L, 1); -// break; -// case LUA_TBOOLEAN: -// break; -// default: -// luaL_error(L, "Invalid key type : %s", lua_typename(L, kt)); -// return; -// } -// -// } -//} +#define TYPE_TABLE_BEG 7 +#define TYPE_TABLE_END 8 + +static inline void +pack_integer(tpack_t *pack, int64_t v) { + if (v >= INT8_MIN && v <= INT8_MAX) { + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_INT8); + pack->m_data = sdscat(pack->m_data, (int8_t)v); + return; + } + if (v >= INT16_MIN && v <= INT16_MAX) { + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_INT16); + pack->m_data = sdscat(pack->m_data, (int16_t)v); + return; + } + if (v >= INT32_MIN && v <= INT32_MAX) { + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_INT32); + pack->m_data = sdscat(pack->m_data, (int32_t)v); + return; + } + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_INT64); + pack->m_data = sdscat(pack->m_data, (int64_t)v); +} + +static inline void +pack_double(tpack_t *pack, double v) { + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_DOUBLE); + pack->m_data = sdscat(pack->m_data, v); +} + +static inline void +pack_boolean(tpack_t *pack, bool v) { + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_BOOL); + pack->m_data = sdscat(pack->m_data, v); +} + +static inline void +pack_string(tpack_t *pack, const char* v, size_t len) { + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_STRING); + pack->m_data = sdscat(pack->m_data, len); + pack->m_data = sdscpylen(pack->m_data, v, len); +} + +static void +pack_lua_data(tpack_t *pack, lua_State *L, int idx, int depth); + +static void +pack_table(tpack_t *pack, lua_State *L, int idx, int depth) { + if (depth > MAX_DEPTH) { + luaL_error(L, "Too depth while encoding bson"); + } + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_TABLE_BEG); + luaL_checkstack(L, 2, NULL); + lua_pushnil(L); + while (lua_next(L, idx) != 0) { + pack_lua_data(pack, L, -2, depth); + pack_lua_data(pack, L, -1, depth); + lua_pop(L, 1); + } + pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_TABLE_END); +} + +static void +pack_lua_data(tpack_t *pack, lua_State *L, int idx, int depth) { + int data_type = lua_type(L, idx); + const char * str = NULL; + size_t len; + switch (data_type) { + case LUA_TNUMBER: + if (lua_isinteger(L, idx)) { + pack_integer(pack, lua_tointeger(L, idx)); + } else { + pack_double(pack, lua_tonumber(L, idx)); + } + return; + case LUA_TSTRING: + str = lua_tolstring(L, idx, &len); + pack_string(pack, str, len); + return; + case LUA_TBOOLEAN: + pack_boolean(pack, (bool)lua_toboolean(L, idx)); + return; + case LUA_TTABLE: + pack_table(pack, L, idx, depth + 1); + return; + default: + luaL_error(L, "Invalid data type : %s", lua_typename(L, data_type)); + return; + } +} + +static int8_t +unpack_lua_data(tpack_t *pack, size_t& rpos, lua_State *L) { + luaL_checkstack(L, 1, NULL); + int8_t data_type = *(int8_t*)(pack->m_data + rpos); + size_t len; + ++rpos; + switch (data_type) { + case TYPE_INT8: + lua_pushinteger(L, *(int8_t*)(pack->m_data + rpos)); + rpos += 1; + break; + case TYPE_INT16: + lua_pushinteger(L, *(int16_t*)(pack->m_data + rpos)); + rpos += 2; + break; + case TYPE_INT32: + lua_pushinteger(L, *(int32_t*)(pack->m_data + rpos)); + rpos += 4; + break; + case TYPE_INT64: + lua_pushinteger(L, *(int64_t*)(pack->m_data + rpos)); + rpos += 8; + break; + case TYPE_DOUBLE: + lua_pushnumber(L, *(double*)(pack->m_data + rpos)); + rpos += sizeof(double); + break; + case TYPE_STRING: + len = *(size_t*)(pack->m_data + rpos); + rpos += sizeof(size_t); + lua_pushlstring(L, pack->m_data + rpos, len); + rpos += len; + break; + case TYPE_BOOL: + lua_pushboolean(L, *(bool*)(pack->m_data + rpos)); + rpos += sizeof(bool); + break; + case TYPE_TABLE_BEG: + lua_createtable(L, 0, 0); + while (unpack_lua_data(pack, rpos, L) != TYPE_TABLE_END) { + unpack_lua_data(pack, rpos, L); + lua_rawset(L, -3); + } + break; + case TYPE_TABLE_END: + break; + default: + break; + } + return data_type; +} diff --git a/src/ltpack.h b/src/ltpack.h index 1750737..1bf3629 100644 --- a/src/ltpack.h +++ b/src/ltpack.h @@ -3,7 +3,7 @@ #include "sds.h" typedef struct tpack_t { - char* m_data; + sds m_data; } tpack_t; #endif diff --git a/src/sds.h b/src/sds.h index ac77bc9..f9bdc03 100644 --- a/src/sds.h +++ b/src/sds.h @@ -34,6 +34,7 @@ #define SDS_MAX_PREALLOC (1024*1024) //#include +#include #include typedef char *sds; @@ -98,4 +99,20 @@ void sdsIncrLen(sds s, int incr); sds sdsRemoveFreeSpace(sds s); size_t sdsAllocSize(sds s); +template +sds sdscat(sds s, T t) { + struct sdshdr *sh; + size_t curlen = sdslen(s); + size_t len = sizeof(t); + + s = sdsMakeRoomFor(s, len); + if (s == NULL) return NULL; + sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + *(T*)(s + curlen) = t; + sh->len = curlen + len; + sh->free = sh->free - len; + s[curlen + len] = '\0'; + return s; +} + #endif From 24a2a5179eba2729d3d96479a2142c9e21ab8ae1 Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 20 Jun 2016 00:50:47 +0800 Subject: [PATCH 122/173] a little thing --- src/ltpack.cpp | 36 ++++++++++++++++++++++++++---------- src/ltpack.h | 3 +++ src/sds.h | 17 +++++++++++++++++ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/ltpack.cpp b/src/ltpack.cpp index 048627c..cdf193a 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -5,7 +5,7 @@ # include #endif -#define MAX_DEPTH 128 +#define MAX_DEPTH 256 #define TYPE_INT8 0 #define TYPE_INT16 1 @@ -108,38 +108,38 @@ pack_lua_data(tpack_t *pack, lua_State *L, int idx, int depth) { static int8_t unpack_lua_data(tpack_t *pack, size_t& rpos, lua_State *L) { luaL_checkstack(L, 1, NULL); - int8_t data_type = *(int8_t*)(pack->m_data + rpos); + int8_t data_type = sdsread(pack->m_data, rpos); size_t len; ++rpos; switch (data_type) { case TYPE_INT8: - lua_pushinteger(L, *(int8_t*)(pack->m_data + rpos)); + lua_pushinteger(L, sdsread(pack->m_data, rpos)); rpos += 1; break; case TYPE_INT16: - lua_pushinteger(L, *(int16_t*)(pack->m_data + rpos)); + lua_pushinteger(L, sdsread(pack->m_data, rpos)); rpos += 2; break; case TYPE_INT32: - lua_pushinteger(L, *(int32_t*)(pack->m_data + rpos)); + lua_pushinteger(L, sdsread(pack->m_data, rpos)); rpos += 4; break; case TYPE_INT64: - lua_pushinteger(L, *(int64_t*)(pack->m_data + rpos)); + lua_pushinteger(L, sdsread(pack->m_data, rpos)); rpos += 8; break; case TYPE_DOUBLE: - lua_pushnumber(L, *(double*)(pack->m_data + rpos)); + lua_pushnumber(L, sdsread(pack->m_data, rpos)); rpos += sizeof(double); break; case TYPE_STRING: - len = *(size_t*)(pack->m_data + rpos); + len = sdsread(pack->m_data, rpos); rpos += sizeof(size_t); - lua_pushlstring(L, pack->m_data + rpos, len); + lua_pushlstring(L, sdsread(pack->m_data, rpos, len), len); rpos += len; break; case TYPE_BOOL: - lua_pushboolean(L, *(bool*)(pack->m_data + rpos)); + lua_pushboolean(L, sdsread(pack->m_data, rpos)); rpos += sizeof(bool); break; case TYPE_TABLE_BEG: @@ -156,3 +156,19 @@ unpack_lua_data(tpack_t *pack, size_t& rpos, lua_State *L) { } return data_type; } + +///////////////////////////////////////////////////////////////////////// + +//static int pack_safe(lua_State *L) { +// bson_t* bson_ptr = (bson_t*)lua_touserdata(L, 2); //arg1: table, arg2: bson_t ptr. +// lua_settop(L, 1); +// pack_dict(L, bson_ptr, false, 0); +// return 0; +//} + + +tpack_t* bson_encode(lua_State *L, int idx) { + +} + +extern bool bson_decode(tpack_t* pack, lua_State *L); \ No newline at end of file diff --git a/src/ltpack.h b/src/ltpack.h index 1bf3629..9d25c05 100644 --- a/src/ltpack.h +++ b/src/ltpack.h @@ -6,4 +6,7 @@ typedef struct tpack_t { sds m_data; } tpack_t; +extern tpack_t* bson_encode(lua_State *L, int idx); +extern bool bson_decode(tpack_t* pack, lua_State *L); + #endif diff --git a/src/sds.h b/src/sds.h index f9bdc03..5108f3a 100644 --- a/src/sds.h +++ b/src/sds.h @@ -35,6 +35,7 @@ //#include #include +#include #include typedef char *sds; @@ -115,4 +116,20 @@ sds sdscat(sds s, T t) { return s; } +template inline +T sdsread(sds s, size_t& rpos) { + struct sdshdr *sh; + sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + assert((size_t)sh->len >= rpos + sizeof(T)); + return *(T*)(s + rpos); +} + +static inline +const char* sdsread(sds s, size_t& rpos, size_t len) { + struct sdshdr *sh; + sh = (struct sdshdr*) (s - (sizeof(struct sdshdr))); + assert((size_t)sh->len >= rpos + len); + return (s + rpos); +} + #endif From 01ec14be481ca7cbf2d62f1c042a1a964ee8927b Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 20 Jun 2016 20:03:32 +0800 Subject: [PATCH 123/173] =?UTF-8?q?=E5=88=A0=E9=99=A4bson=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- node-lua.vcxproj | 2 - node-lua.vcxproj.filters | 6 - src/context_lua.cpp | 24 +- src/lbson.cpp | 1278 -------------------------------------- src/lbson.h | 22 - src/ltpack.cpp | 45 +- src/ltpack.h | 5 +- src/message.h | 24 +- 8 files changed, 53 insertions(+), 1353 deletions(-) delete mode 100644 src/lbson.cpp delete mode 100644 src/lbson.h diff --git a/node-lua.vcxproj b/node-lua.vcxproj index 143bc64..785da0c 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -104,7 +104,6 @@ - @@ -139,7 +138,6 @@ - diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index f285b71..d897d0e 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -96,9 +96,6 @@ include - - include - include @@ -191,9 +188,6 @@ src - - src - src diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 7a124cd..b517137 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -117,8 +117,6 @@ LUAMOD_API int (luaopen_buffer)(lua_State *L); LUAMOD_API int (luaopen_context)(lua_State *L); #define LUA_TIMERLIBNAME "timer" LUAMOD_API int (luaopen_timer)(lua_State *L); -#define LUA_BSONLIBNAME "bson" -LUAMOD_API int (luaopen_bson)(lua_State *L); void context_lua_t::lua_open_libs(lua_State *L) { @@ -141,7 +139,6 @@ void context_lua_t::lua_open_libs(lua_State *L) {LUA_BUFFERLIBNAME, luaopen_buffer}, {LUA_CONTEXTLIBNAME, luaopen_context}, {LUA_TIMERLIBNAME, luaopen_timer}, - {LUA_BSONLIBNAME, luaopen_bson}, {NULL, NULL} }; static const luaL_Reg preloadedlibs[] = { @@ -590,12 +587,8 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) lua_pushstring(L, ""); } return; - case BSON: - if (message_bson(message)->extract) { - bson_decode(message_bson(message), L); - } else { - create_bson(message_bson(message), L); - } + case TPACK: + ltunpack(&message_tpack(message), L); return; case TERROR: lua_pushinteger(L, message_error(message)); @@ -966,13 +959,6 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t message.m_source = lua_get_context_handle(L); return 1; } - bson_data = (int32_t*)luaL_testudata(L, idx, BSON_METATABLE); - if (bson_data) { - message.m_type = MAKE_MESSAGE_TYPE(msg_type, BSON); - message.m_data.m_bson = bson_new(bson_data, false); - message.m_source = lua_get_context_handle(L); - return 1; - } lua_pushstring(L, "transfer data type not supported"); return 0; case LUA_TLIGHTUSERDATA: @@ -981,10 +967,10 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t message.m_source = lua_get_context_handle(L); return 1; case LUA_TTABLE: - message.m_type = MAKE_MESSAGE_TYPE(msg_type, BSON); - message.m_data.m_bson = bson_new(NULL, true); + message.m_type = MAKE_MESSAGE_TYPE(msg_type, TPACK); + message.m_data.m_tpack.m_data = sdsnewempty(64); message.m_source = lua_get_context_handle(L); - return bson_encode(message.m_data.m_bson, L, idx) ? 1 : 0; + return ltpack(&message.m_data.m_tpack, L, idx) ? 1 : 0; default: lua_pushstring(L, "transfer data type not supported"); return 0; diff --git a/src/lbson.cpp b/src/lbson.cpp deleted file mode 100644 index 75af518..0000000 --- a/src/lbson.cpp +++ /dev/null @@ -1,1278 +0,0 @@ -#include -#define __STDC_LIMIT_MACROS -#include "lbson.h" -#ifndef _WIN32 -# include -#endif - - -#define MAX_NUMBER 1024 -// avoid circular reference while encodeing -#define MAX_DEPTH 128 - -#define BSON_REAL 1 -#define BSON_STRING 2 -#define BSON_DOCUMENT 3 -#define BSON_ARRAY 4 -#define BSON_BINARY 5 -#define BSON_UNDEFINED 6 -#define BSON_OBJECTID 7 -#define BSON_BOOLEAN 8 -#define BSON_DATE 9 -#define BSON_NULL 10 -#define BSON_REGEX 11 -#define BSON_DBPOINTER 12 -#define BSON_JSCODE 13 -#define BSON_SYMBOL 14 -#define BSON_CODEWS 15 -#define BSON_INT32 16 -#define BSON_TIMESTAMP 17 -#define BSON_INT64 18 -#define BSON_MINKEY 255 -#define BSON_MAXKEY 127 - -#define BSON_TYPE_SHIFT 5 - -static char bson_numstrs[MAX_NUMBER][4]; -static int bson_numstr_len[MAX_NUMBER]; - -struct bson_reader { - const uint8_t * ptr; - int size; -}; - -static inline int32_t -get_length(const uint8_t * data) { - const uint8_t * b = (const uint8_t *)data; - int32_t len = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; - return len; -} - -static inline void -bson_destroy(struct bson *b) { - if (b->ptr != b->buffer) { - nl_free(b->ptr); - } -} - -static inline void -bson_create(struct bson *b, bool extract) { - b->extract = extract; - b->size = 0; - b->cap = DEFAULT_CAP; - b->ptr = b->buffer; -} - -static inline void -bson_reserve(struct bson *b, int sz) { - if (b->size + sz <= b->cap) - return; - do { - b->cap *= 2; - } while (b->cap <= b->size + sz); - - if (b->ptr == b->buffer) { - b->ptr = (uint8_t *)nl_malloc(b->cap); - memcpy(b->ptr, b->buffer, b->size); - } else { - b->ptr = (uint8_t *)nl_realloc(b->ptr, b->cap); - } -} - -static inline void -check_reader(lua_State *L, struct bson_reader *br, int sz) { - if (br->size < sz) { - luaL_error(L, "Invalid bson block (%d:%d)", br->size, sz); - } -} - -static inline int -read_byte(lua_State *L, struct bson_reader *br) { - check_reader(L, br, 1); - const uint8_t * b = br->ptr; - int r = b[0]; - ++br->ptr; - --br->size; - - return r; -} - -static inline int32_t -read_int32(lua_State *L, struct bson_reader *br) { - check_reader(L, br, 4); - const uint8_t * b = br->ptr; - uint32_t v = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; - br->ptr+=4; - br->size-=4; - return (int32_t)v; -} - -static inline int64_t -read_int64(lua_State *L, struct bson_reader *br) { - check_reader(L, br, 8); - const uint8_t * b = br->ptr; - uint32_t lo = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; - uint32_t hi = b[4] | b[5]<<8 | b[6]<<16 | b[7]<<24; - uint64_t v = (uint64_t)lo | (uint64_t)hi<<32; - br->ptr+=8; - br->size-=8; - return (int64_t)v; -} - -static inline lua_Number -read_double(lua_State *L, struct bson_reader *br) { - check_reader(L, br, 8); - union { - uint64_t i; - double d; - } v; - const uint8_t * b = br->ptr; - uint32_t lo = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24; - uint32_t hi = b[4] | b[5]<<8 | b[6]<<16 | b[7]<<24; - v.i = (uint64_t)lo | (uint64_t)hi<<32; - br->ptr+=8; - br->size-=8; - return v.d; -} - -static inline const void * -read_bytes(lua_State *L, struct bson_reader *br, int sz) { - const void * r = br->ptr; - check_reader(L, br, sz); - br->ptr+=sz; - br->size-=sz; - return r; -} - -static inline const char * -read_cstring(lua_State *L, struct bson_reader *br, size_t *sz) { - int i; - for (i=0;;i++) { - if (i==br->size) { - luaL_error(L, "Invalid bson block : cstring"); - } - if (br->ptr[i] == '\0') { - break; - } - } - *sz = i; - const char * r = (const char *)br->ptr; - br->ptr += i+1; - br->size -= i+1; - return r; -} - -static inline void -write_byte(struct bson *b, uint8_t v) { - bson_reserve(b,1); - b->ptr[b->size++] = v; -} - -static inline void -write_int32(struct bson *b, int32_t v) { - uint32_t uv = (uint32_t)v; - bson_reserve(b,4); - b->ptr[b->size++] = uv & 0xff; - b->ptr[b->size++] = (uv >> 8)&0xff; - b->ptr[b->size++] = (uv >> 16)&0xff; - b->ptr[b->size++] = (uv >> 24)&0xff; -} - -static inline void -write_length(struct bson *b, int32_t v, int off) { - uint32_t uv = (uint32_t)v; - b->ptr[off++] = uv & 0xff; - b->ptr[off++] = (uv >> 8)&0xff; - b->ptr[off++] = (uv >> 16)&0xff; - b->ptr[off++] = (uv >> 24)&0xff; -} - -static void -write_string(struct bson *b, const char *key, size_t sz) { - bson_reserve(b,sz+1); - memcpy(b->ptr + b->size, key, sz); - b->ptr[b->size+sz] = '\0'; - b->size+=sz+1; -} - -static inline int -reserve_length(struct bson *b) { - int sz = b->size; - bson_reserve(b,4); - b->size +=4; - return sz; -} - -static inline void -write_int64(struct bson *b, int64_t v) { - uint64_t uv = (uint64_t)v; - int i; - bson_reserve(b,8); - for (i=0;i<64;i+=8) { - b->ptr[b->size++] = (uv>>i) & 0xff; - } -} - -static inline void -write_double(struct bson *b, lua_Number d) { - union { - double d; - uint64_t i; - } v; - v.d = d; - int i; - bson_reserve(b,8); - for (i=0;i<64;i+=8) { - b->ptr[b->size++] = (v.i>>i) & 0xff; - } -} - -static void pack_dict(lua_State *L, struct bson *b, bool array, int depth); - -static inline void -append_key(struct bson *bs, int type, const char *key, size_t sz) { - write_byte(bs, type); - write_string(bs, key, sz); -} - -static inline int -is_32bit(int64_t v) { - return v >= INT32_MIN && v <= INT32_MAX; -} - -static void -append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) { - if (lua_isinteger(L, -1)) { - int64_t i = lua_tointeger(L, -1); - if (is_32bit(i)) { - append_key(bs, BSON_INT32, key, sz); - write_int32(bs, i); - } else { - append_key(bs, BSON_INT64, key, sz); - write_int64(bs, i); - } - } else { - lua_Number d = lua_tonumber(L,-1); - append_key(bs, BSON_REAL, key, sz); - write_double(bs, d); - } -} - -static void -append_table(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) { - size_t len = lua_rawlen(L, -1); - bool isarray = false; - if (len > 0) { - lua_pushinteger(L, len); - if (lua_next(L,-2) == 0) { - isarray = true; - } else { - lua_pop(L,2); - } - } - if (isarray) { - append_key(bs, BSON_ARRAY, key, sz); - } else { - append_key(bs, BSON_DOCUMENT, key, sz); - } - pack_dict(L, bs, isarray, depth); -} - -static void -write_binary(struct bson *b, const void * buffer, size_t sz) { - int length = reserve_length(b); - bson_reserve(b,sz); - memcpy(b->ptr + b->size, buffer, sz); // include sub type - b->size+=sz; - write_length(b, sz-1, length); // not include sub type -} - -static void -append_one(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) { - int vt = lua_type(L,-1); - switch(vt) { - case LUA_TNUMBER: - append_number(bs, L, key, sz); - break; - case LUA_TUSERDATA: { - append_key(bs, BSON_DOCUMENT, key, sz); - int32_t * doc = (int32_t*)lua_touserdata(L, -1); - int32_t sz = *doc; - bson_reserve(bs,sz); - memcpy(bs->ptr + bs->size, doc, sz); - bs->size += sz; - break; - } - case LUA_TSTRING: { - size_t len; - const char * str = lua_tolstring(L,-1,&len); - if (len > 1 && str[0]==0) { - int subt = (uint8_t)str[1]; - append_key(bs, subt, key, sz); - switch(subt) { - case BSON_BINARY: - write_binary(bs, str+2, len-2); - break; - case BSON_OBJECTID: - if (len != 2+12) { - luaL_error(L, "Invalid object id %s", str+2); - } - // go though - case BSON_JSCODE: - case BSON_DBPOINTER: - case BSON_SYMBOL: - case BSON_CODEWS: - bson_reserve(bs,len-2); - memcpy(bs->ptr + bs->size, str+2, len-2); - bs->size += len-2; - break; - case BSON_DATE: { - if (len != 2+4) { - luaL_error(L, "Invalid date"); - } - const uint32_t * ts = (const uint32_t *)(str + 2); - int64_t v = (int64_t)*ts * 1000; - write_int64(bs, v); - break; - } - case BSON_TIMESTAMP: { - if (len != 2+8) { - luaL_error(L, "Invalid timestamp"); - } - const uint32_t * inc = (const uint32_t *)(str + 2); - const uint32_t * ts = (const uint32_t *)(str + 6); - write_int32(bs, *inc); - write_int32(bs, *ts); - break; - } - case BSON_REGEX: { - str+=2; - len-=3; - size_t i; - for (i=0;i MAX_DEPTH) { - luaL_error(L, "Too depth while encoding bson"); - } - luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table - int length = reserve_length(b); - lua_pushnil(L); - while(lua_next(L,-2) != 0) { - int kt = lua_type(L, -2); - char numberkey[32]; - const char * key = NULL; - size_t sz; - if (isarray) { - if (kt != LUA_TNUMBER) { - luaL_error(L, "Invalid array key type : %s", lua_typename(L, kt)); - return; - } - sz = bson_numstr(numberkey, (unsigned int)lua_tointeger(L,-2)-1); - key = numberkey; - - append_one(b, L, key, sz, depth); - lua_pop(L,1); - } else { - switch(kt) { - case LUA_TNUMBER: - // copy key, don't change key type - lua_pushvalue(L,-2); - lua_insert(L,-2); - key = lua_tolstring(L,-2,&sz); - append_one(b, L, key, sz, depth); - lua_pop(L,2); - break; - case LUA_TSTRING: - key = lua_tolstring(L,-2,&sz); - append_one(b, L, key, sz, depth); - lua_pop(L,1); - break; - default: - luaL_error(L, "Invalid key type : %s", lua_typename(L, kt)); - return; - } - } - } - write_byte(b,0); - write_length(b, b->size - length, length); -} - -static void -pack_ordered_dict(lua_State *L, struct bson *b, int n, int depth) { - int length = reserve_length(b); - int i; - for (i=0;isize - length, length); -} - -static int -ltostring(lua_State *L) { - size_t sz = lua_rawlen(L, 1); - void * ud = lua_touserdata(L,1); - lua_pushlstring(L, (const char*)ud, sz); - return 1; -} - -static int -llen(lua_State *L) { - size_t sz = lua_rawlen(L, 1); - lua_pushinteger(L, sz); - return 1; -} - -static void -make_object(lua_State *L, int type, const void * ptr, size_t len) { - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addchar(&b, 0); - luaL_addchar(&b, type); - luaL_addlstring(&b, (const char*)ptr, len); - luaL_pushresult(&b); -} - -static void -unpack_dict(lua_State *L, struct bson_reader *br, bool array) { - luaL_checkstack(L, 16, NULL); // reserve enough stack space to unpack table - int sz = read_int32(L, br); - const void * bytes = read_bytes(L, br, sz-5); - struct bson_reader t = { (const uint8_t *)bytes, sz - 5 }; - int end = read_byte(L, br); - if (end != '\0') { - luaL_error(L, "Invalid document end"); - } - - lua_newtable(L); - - for (;;) { - if (t.size == 0) - break; - int bt = read_byte(L, &t); - size_t klen = 0; - const char * key = read_cstring(L, &t, &klen); - if (array) { - int id = strtol(key, NULL, 10) + 1; - lua_pushinteger(L,id); - } else { - lua_pushlstring(L, key, klen); - } - switch (bt) { - case BSON_REAL: - lua_pushnumber(L, read_double(L, &t)); - break; - case BSON_BOOLEAN: - lua_pushboolean(L, read_byte(L, &t)); - break; - case BSON_STRING: { - int sz = read_int32(L, &t); - if (sz <= 0) { - luaL_error(L, "Invalid bson string , length = %d", sz); - } - lua_pushlstring(L, (const char*)read_bytes(L, &t, sz), sz-1); - break; - } - case BSON_DOCUMENT: - unpack_dict(L, &t, false); - break; - case BSON_ARRAY: - unpack_dict(L, &t, true); - break; - case BSON_BINARY: { - int sz = read_int32(L, &t); - int subtype = read_byte(L, &t); - - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addchar(&b, 0); - luaL_addchar(&b, BSON_BINARY); - luaL_addchar(&b, subtype); - luaL_addlstring(&b, (const char*)read_bytes(L, &t, sz), sz); - luaL_pushresult(&b); - break; - } - case BSON_OBJECTID: - make_object(L, BSON_OBJECTID, read_bytes(L, &t, 12), 12); - break; - case BSON_DATE: { - int64_t date = read_int64(L, &t); - uint32_t v = date / 1000; - make_object(L, BSON_DATE, &v, 4); - break; - } - case BSON_MINKEY: - case BSON_MAXKEY: - case BSON_NULL: { - char key[] = { 0, bt }; - lua_pushlstring(L, key, sizeof(key)); - break; - } - case BSON_REGEX: { - size_t rlen1=0; - size_t rlen2=0; - const char * r1 = read_cstring(L, &t, &rlen1); - const char * r2 = read_cstring(L, &t, &rlen2); - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addchar(&b, 0); - luaL_addchar(&b, BSON_REGEX); - luaL_addlstring(&b, r1, rlen1); - luaL_addchar(&b,0); - luaL_addlstring(&b, r2, rlen2); - luaL_addchar(&b,0); - luaL_pushresult(&b); - break; - } - case BSON_INT32: - lua_pushinteger(L, read_int32(L, &t)); - break; - case BSON_TIMESTAMP: { - int32_t inc = read_int32(L, &t); - int32_t ts = read_int32(L, &t); - - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addchar(&b, 0); - luaL_addchar(&b, BSON_TIMESTAMP); - luaL_addlstring(&b, (const char *)&inc, 4); - luaL_addlstring(&b, (const char *)&ts, 4); - luaL_pushresult(&b); - break; - } - case BSON_INT64: - lua_pushinteger(L, read_int64(L, &t)); - break; - case BSON_DBPOINTER: { - const void * ptr = t.ptr; - int sz = read_int32(L, &t); - read_bytes(L, &t, sz+12); - make_object(L, BSON_DBPOINTER, ptr, sz + 16); - break; - } - case BSON_JSCODE: - case BSON_SYMBOL: { - const void * ptr = t.ptr; - int sz = read_int32(L, &t); - read_bytes(L, &t, sz); - make_object(L, bt, ptr, sz + 4); - break; - } - case BSON_CODEWS: { - const void * ptr = t.ptr; - int sz = read_int32(L, &t); - read_bytes(L, &t, sz-4); - make_object(L, bt, ptr, sz); - break; - } - default: - // unsupported - luaL_error(L, "Invalid bson type : %d", bt); - lua_pop(L,1); - continue; - } - lua_rawset(L,-3); - } -} - -static int -lmakeindex(lua_State *L) { - int32_t *bson = (int32_t *)luaL_checkudata(L, 1, BSON_METATABLE); - const uint8_t * start = (const uint8_t *)bson; - struct bson_reader br = { start+4, get_length(start) - 5 }; - lua_newtable(L); - - for (;;) { - if (br.size == 0) - break; - int bt = read_byte(L, &br); - size_t klen = 0; - const char * key = read_cstring(L, &br, &klen); - int field_size = 0; - switch (bt) { - case BSON_INT64: - case BSON_TIMESTAMP: - case BSON_DATE: - case BSON_REAL: - field_size = 8; - break; - case BSON_BOOLEAN: - field_size = 1; - break; - case BSON_JSCODE: - case BSON_SYMBOL: - case BSON_STRING: { - int sz = read_int32(L, &br); - read_bytes(L, &br, sz); - break; - } - case BSON_CODEWS: - case BSON_ARRAY: - case BSON_DOCUMENT: { - int sz = read_int32(L, &br); - read_bytes(L, &br, sz-4); - break; - } - case BSON_BINARY: { - int sz = read_int32(L, &br); - read_bytes(L, &br, sz+1); - break; - } - case BSON_OBJECTID: - field_size = 12; - break; - case BSON_MINKEY: - case BSON_MAXKEY: - case BSON_NULL: - break; - case BSON_REGEX: { - size_t rlen1=0; - size_t rlen2=0; - read_cstring(L, &br, &rlen1); - read_cstring(L, &br, &rlen2); - break; - } - case BSON_INT32: - field_size = 4; - break; - case BSON_DBPOINTER: { - int sz = read_int32(L, &br); - read_bytes(L, &br, sz+12); - break; - } - default: - // unsupported - luaL_error(L, "Invalid bson type : %d", bt); - lua_pop(L,1); - continue; - } - if (field_size > 0) { - int id = bt | (int)(br.ptr - start) << BSON_TYPE_SHIFT; - read_bytes(L, &br, field_size); - lua_pushlstring(L, key, klen); - lua_pushinteger(L,id); - lua_rawset(L,-3); - } - } - lua_setuservalue(L,1); - lua_settop(L,1); - - return 1; -} - -static void -replace_object(lua_State *L, int type, struct bson * bs) { - size_t len = 0; - const char * data = luaL_checklstring(L,3, &len); - if (len < 6 || data[0] != 0 || data[1] != type) { - luaL_error(L, "Type mismatch, need bson type %d", type); - } - switch (type) { - case BSON_OBJECTID: - if (len != 2+12) { - luaL_error(L, "Invalid object id"); - } - memcpy(bs->ptr, data+2, 12); - break; - case BSON_DATE: { - if (len != 2+4) { - luaL_error(L, "Invalid date"); - } - const uint32_t * ts = (const uint32_t *)(data + 2); - int64_t v = (int64_t)*ts * 1000; - write_int64(bs, v); - break; - } - case BSON_TIMESTAMP: { - if (len != 2+8) { - luaL_error(L, "Invalid timestamp"); - } - const uint32_t * inc = (const uint32_t *)(data + 2); - const uint32_t * ts = (const uint32_t *)(data + 6); - write_int32(bs, *inc); - write_int32(bs, *ts); - break; - } - } -} - -static int -lreplace(lua_State *L) { - lua_getuservalue(L,1); - if (!lua_istable(L,-1)) { - return luaL_error(L, "call makeindex first"); - } - lua_pushvalue(L,2); - if (lua_rawget(L, -2) != LUA_TNUMBER) { - return luaL_error(L, "Can't replace key : %s", lua_tostring(L,2)); - } - int id = lua_tointeger(L, -1); - int type = id & ((1<<(BSON_TYPE_SHIFT)) - 1); - int offset = id >> BSON_TYPE_SHIFT; - uint8_t * start = (uint8_t *)lua_touserdata(L, 1); - struct bson b = { false, 0, 16, start + offset, { 0 } }; - switch (type) { - case BSON_REAL: - write_double(&b, luaL_checknumber(L, 3)); - break; - case BSON_BOOLEAN: - write_byte(&b, lua_toboolean(L,3)); - break; - case BSON_OBJECTID: - case BSON_DATE: - case BSON_TIMESTAMP: - replace_object(L, type, &b); - break; - case BSON_INT32: { - if (!lua_isinteger(L, 3)) { - luaL_error(L, "%f must be a 32bit integer ", lua_tonumber(L, 3)); - } - int32_t i = lua_tointeger(L,3); - write_int32(&b, i); - break; - } - case BSON_INT64: { - if (!lua_isinteger(L, 3)) { - luaL_error(L, "%f must be a 64bit integer ", lua_tonumber(L, 3)); - } - int64_t i = lua_tointeger(L,3); - write_int64(&b, i); - break; - } - default: - luaL_error(L, "Can't replace type %d", type); - break; - } - return 0; -} - -static int -ldecode(lua_State *L) { - const int32_t * data = (int32_t *)lua_touserdata(L, 1); - if (data == NULL) { - return 0; - } - const uint8_t * b = (const uint8_t *)data; - int32_t len = get_length(b); - struct bson_reader br = { b , len }; - - unpack_dict(L, &br, false); - - return 1; -} - -static void -bson_meta(lua_State *L) { - if (luaL_newmetatable(L, BSON_METATABLE)) { - luaL_Reg l[] = { - { "decode", ldecode }, - { "makeindex", lmakeindex }, - { NULL, NULL }, - }; - luaL_newlib(L,l); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, ltostring); - lua_setfield(L, -2, "__tostring"); - lua_pushcfunction(L, llen); - lua_setfield(L, -2, "__len"); - lua_pushcfunction(L, lreplace); - lua_setfield(L, -2, "__newindex"); - } - lua_setmetatable(L, -2); -} - -static int -lencode(lua_State *L) { - struct bson b; - bson_create(&b, false); - lua_settop(L,1); - luaL_checktype(L, 1, LUA_TTABLE); - pack_dict(L, &b, false, 0); - void * ud = lua_newuserdata(L, b.size); - memcpy(ud, b.ptr, b.size); - bson_destroy(&b); - bson_meta(L); - return 1; -} - -static int -lencode_order(lua_State *L) { - struct bson b; - bson_create(&b, false); - int n = lua_gettop(L); - if (n%2 != 0) { - return luaL_error(L, "Invalid ordered dict"); - } - pack_ordered_dict(L, &b, n, 0); - lua_settop(L,1); - void * ud = lua_newuserdata(L, b.size); - memcpy(ud, b.ptr, b.size); - bson_destroy(&b); - bson_meta(L); - return 1; -} - -static int -ldate(lua_State *L) { - int d = luaL_checkinteger(L,1); - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addchar(&b, 0); - luaL_addchar(&b, BSON_DATE); - luaL_addlstring(&b, (const char *)&d, sizeof(d)); - luaL_pushresult(&b); - - return 1; -} - -static int -ltimestamp(lua_State *L) { - int d = luaL_checkinteger(L,1); - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addchar(&b, 0); - luaL_addchar(&b, BSON_TIMESTAMP); - if (lua_isnoneornil(L,2)) { - static uint32_t inc = 0; - luaL_addlstring(&b, (const char *)&inc, sizeof(inc)); - ++inc; - } else { - uint32_t i = (uint32_t)lua_tointeger(L,2); - luaL_addlstring(&b, (const char *)&i, sizeof(i)); - } - luaL_addlstring(&b, (const char *)&d, sizeof(d)); - luaL_pushresult(&b); - - return 1; -} - -static int -lregex(lua_State *L) { - luaL_checkstring(L,1); - if (lua_gettop(L) < 2) { - lua_pushliteral(L,""); - } - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addchar(&b, 0); - luaL_addchar(&b, BSON_REGEX); - lua_pushvalue(L,1); - luaL_addvalue(&b); - luaL_addchar(&b,0); - lua_pushvalue(L,2); - luaL_addvalue(&b); - luaL_addchar(&b,0); - luaL_pushresult(&b); - - return 1; -} - -static int -lbinary(lua_State *L) { - lua_settop(L,1); - luaL_Buffer b; - luaL_buffinit(L, &b); - luaL_addchar(&b, 0); - luaL_addchar(&b, BSON_BINARY); - luaL_addchar(&b, 0); // sub type - luaL_addvalue(&b); - luaL_pushresult(&b); - - return 1; -} - -static int -lsubtype(lua_State *L, int subtype, const uint8_t * buf, size_t sz) { - switch(subtype) { - case BSON_BINARY: - lua_pushvalue(L, lua_upvalueindex(6)); - lua_pushlstring(L, (const char *)buf+1, sz-1); - lua_pushinteger(L, buf[0]); - return 3; - case BSON_OBJECTID: { - if (sz != 12) { - return luaL_error(L, "Invalid object id"); - } - char oid[24]; - int i; - const uint8_t * id = buf; - static const char *hex = "0123456789abcdef"; - for (i=0;i<12;i++) { - oid[i*2] = hex[id[i] >> 4]; - oid[i*2+1] = hex[id[i] & 0xf]; - } - lua_pushvalue(L, lua_upvalueindex(7)); - lua_pushlstring(L, oid, 24); - - return 2; - } - case BSON_DATE: { - if (sz != 4) { - return luaL_error(L, "Invalid date"); - } - int d = *(const int *)buf; - lua_pushvalue(L, lua_upvalueindex(9)); - lua_pushinteger(L, d); - return 2; - } - case BSON_TIMESTAMP: { - if (sz != 8) { - return luaL_error(L, "Invalid timestamp"); - } - const uint32_t * ts = (const uint32_t *)buf; - lua_pushvalue(L, lua_upvalueindex(8)); - lua_pushinteger(L, (lua_Integer)ts[1]); - lua_pushinteger(L, (lua_Integer)ts[0]); - return 3; - } - case BSON_REGEX: { - --sz; - size_t i; - const uint8_t *str = buf; - for (i=0;i= 2) { - return lsubtype(L, (uint8_t)str[1], (const uint8_t *)str+2, len-2); - } else { - type = 5; - break; - } - } - default: - return luaL_error(L, "Invalid type %s",lua_typename(L,t)); - } - lua_pushvalue(L, lua_upvalueindex(type)); - lua_pushvalue(L,1); - return 2; -} - -static void -typeclosure(lua_State *L) { - static const char * typename_array[] = { - "number", // 1 - "boolean", // 2 - "table", // 3 - "nil", // 4 - "string", // 5 - "binary", // 6 - "objectid", // 7 - "timestamp", // 8 - "date", // 9 - "regex", // 10 - "minkey", // 11 - "maxkey", // 12 - "unsupported", // 13 - }; - int i; - int n = sizeof(typename_array) / sizeof(typename_array[0]); - for (i=0;i>2)+hostname[i]); - } - h ^= i; - } - oid_header[0] = h & 0xff; - oid_header[1] = (h>>8) & 0xff; - oid_header[2] = (h>>16) & 0xff; - oid_header[3] = pid & 0xff; - oid_header[4] = (pid >> 8) & 0xff; - - uint32_t c = h ^ time(NULL) ^ (uintptr_t)&h; - if (c == 0) { - c = 1; - } - oid_counter = c; -} - -static inline int -hextoint(char c) { - if (c>='0' && c<='9') - return c-'0'; - if (c>='a' && c<='z') - return c-'a'+10; - if (c>='A' && c<='Z') - return c-'A'+10; - return 0; -} - -static int -lobjectid(lua_State *L) { - uint8_t oid[14] = { 0, BSON_OBJECTID }; - if (lua_isstring(L,1)) { - size_t len; - const char * str = lua_tolstring(L,1,&len); - if (len != 24) { - return luaL_error(L, "Invalid objectid %s", str); - } - int i; - for (i=0;i<12;i++) { - oid[i+2] = hextoint(str[i*2]) << 4 | hextoint(str[i*2+1]); - } - } else { - time_t ti = time(NULL); - // old_counter is a static var, use atom inc. - uint32_t id = atomic_inc(oid_counter); - - oid[2] = (ti>>24) & 0xff; - oid[3] = (ti>>16) & 0xff; - oid[4] = (ti>>8) & 0xff; - oid[5] = ti & 0xff; - memcpy(oid+6 , oid_header, 5); - oid[11] = (id>>16) & 0xff; - oid[12] = (id>>8) & 0xff; - oid[13] = id & 0xff; - } - lua_pushlstring( L, (const char *)oid, 14); - - return 1; -} - -static void init_bson_numstr() { - int i; - for (i = 0; i < MAX_NUMBER; i++) { - char tmp[8]; - bson_numstr_len[i] = sprintf(tmp, "%d", i); - memcpy(bson_numstrs[i], tmp, bson_numstr_len[i]); - } -} - -static atomic_t g_inited = 0; - -static void init_once() { - if (g_inited == 0 && atomic_cas(g_inited, 0, 1)) { - init_oid_header(); - init_bson_numstr(); - } -} - -LUAMOD_API int luaopen_bson(lua_State *L) { - luaL_checkversion(L); - init_once(); - luaL_Reg l[] = { - { "encode", lencode }, - { "encode_order", lencode_order }, - { "date", ldate }, - { "timestamp", ltimestamp }, - { "regex", lregex }, - { "binary", lbinary }, - { "objectid", lobjectid }, - { "decode", ldecode }, - { NULL, NULL }, - }; - - luaL_newlib(L,l); - - typeclosure(L); - lua_setfield(L,-2,"type"); - char null[] = { 0, BSON_NULL }; - lua_pushlstring(L, null, sizeof(null)); - lua_setfield(L,-2,"null"); - char minkey[] = { 0, BSON_MINKEY }; - lua_pushlstring(L, minkey, sizeof(minkey)); - lua_setfield(L,-2,"minkey"); - char maxkey[] = { 0, BSON_MAXKEY }; - lua_pushlstring(L, maxkey, sizeof(maxkey)); - lua_setfield(L,-2,"maxkey"); - - return 1; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -void* create_bson(bson_t* bson_ptr, lua_State* L) { - void * ud = lua_newuserdata(L, bson_ptr->size); - memcpy(ud, bson_ptr->ptr, bson_ptr->size); - bson_meta(L); - return ud; -} - -bson_t* bson_new(void* ud, bool extract) { - bson_t* bson_ptr = (bson_t*)nl_malloc(sizeof(*bson_ptr)); - bson_create(bson_ptr, extract); - if (ud != NULL) { - const uint8_t * b = (const uint8_t *)ud; - int len = get_length(b); - bson_ptr->size = len; - if (len <= DEFAULT_CAP) { - bson_ptr->ptr = bson_ptr->buffer; - bson_ptr->cap = DEFAULT_CAP; - } else { - bson_ptr->ptr = (uint8_t*)nl_malloc(len); - bson_ptr->cap = len; - } - memcpy(bson_ptr->ptr, b, len); - } - return bson_ptr; -} - -void bson_release(bson_t* bson_ptr) { - bson_destroy(bson_ptr); - nl_free(bson_ptr); -} - -static int bson_encode_safe(lua_State *L) { - bson_t* bson_ptr = (bson_t*)lua_touserdata(L, 2); //arg1: table, arg2: bson_t ptr. - lua_settop(L, 1); - pack_dict(L, bson_ptr, false, 0); - return 0; -} - -bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx) { - if (lua_istable(L, idx)) { - lua_checkstack(L, 3); - lua_pushcfunction(L, bson_encode_safe); - lua_pushvalue(L, idx); - lua_pushlightuserdata(L, bson_ptr); - if (lua_pcall(L, 2, LUA_MULTRET, NULL) == LUA_OK) { - return true; - } - return false; - } - lua_checkstack(L, 1); - lua_pushstring(L, "table expected"); - return false; -} - -static int bson_decode_safe(lua_State *L) { - bson_t* bson_ptr = (bson_t*)lua_touserdata(L, 1); //arg1: bson_t ptr. - lua_settop(L, 1); - const uint8_t * b = (const uint8_t*)bson_ptr->ptr; - int32_t len = get_length(b); - struct bson_reader br = { b, len }; - unpack_dict(L, &br, false); - return 1; -} - -bool bson_decode(bson_t* bson_ptr, lua_State *L) { - lua_checkstack(L, 3); - lua_pushcfunction(L, bson_decode_safe); - lua_pushlightuserdata(L, bson_ptr); - return lua_pcall(L, 1, LUA_MULTRET, NULL) == LUA_OK; -} - diff --git a/src/lbson.h b/src/lbson.h deleted file mode 100644 index 1855b9f..0000000 --- a/src/lbson.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef LBSON_H_ -#define LBSON_H_ -#include "common.h" - -#define DEFAULT_CAP 64 -#define BSON_METATABLE "bson" - -typedef struct bson { - bool extract; //whether extract to lua table - int size; - int cap; - uint8_t *ptr; - uint8_t buffer[DEFAULT_CAP]; -} bson_t; - -extern void* create_bson(bson_t* bson_ptr, lua_State* L); -extern bson_t* bson_new(void* ud, bool extract); -extern void bson_release(bson_t* bson_ptr); -extern bool bson_encode(bson_t* bson_ptr, lua_State *L, int idx); -extern bool bson_decode(bson_t* bson_ptr, lua_State *L); - -#endif \ No newline at end of file diff --git a/src/ltpack.cpp b/src/ltpack.cpp index cdf193a..cb0a3e9 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -1,5 +1,4 @@ #include "ltpack.h" -#include "common.h" #define __STDC_LIMIT_MACROS #ifndef _WIN32 # include @@ -63,7 +62,7 @@ pack_lua_data(tpack_t *pack, lua_State *L, int idx, int depth); static void pack_table(tpack_t *pack, lua_State *L, int idx, int depth) { if (depth > MAX_DEPTH) { - luaL_error(L, "Too depth while encoding bson"); + luaL_error(L, "too deep(%d, limit %d) while packing table", depth, MAX_DEPTH); } pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_TABLE_BEG); luaL_checkstack(L, 2, NULL); @@ -159,16 +158,40 @@ unpack_lua_data(tpack_t *pack, size_t& rpos, lua_State *L) { ///////////////////////////////////////////////////////////////////////// -//static int pack_safe(lua_State *L) { -// bson_t* bson_ptr = (bson_t*)lua_touserdata(L, 2); //arg1: table, arg2: bson_t ptr. -// lua_settop(L, 1); -// pack_dict(L, bson_ptr, false, 0); -// return 0; -//} - +static int pack_safe(lua_State *L) { + tpack_t* pack = (tpack_t*)lua_touserdata(L, 2); //arg1: table, arg2: tpack_t ptr. + lua_settop(L, 1); + pack_lua_data(pack, L, 1, 0); + return 0; +} -tpack_t* bson_encode(lua_State *L, int idx) { +bool ltpack(tpack_t* pack, lua_State *L, int idx) { + if (lua_istable(L, idx)) { + lua_checkstack(L, 3); + lua_pushcfunction(L, pack_safe); + lua_pushvalue(L, idx); + lua_pushlightuserdata(L, pack); + if (lua_pcall(L, 2, LUA_MULTRET, NULL) == LUA_OK) { + return true; + } + return false; + } + lua_checkstack(L, 1); + lua_pushstring(L, "table expected"); + return false; +} +static int unpack_safe(lua_State *L) { + size_t rpos = 0; + tpack_t* pack = (tpack_t*)lua_touserdata(L, 1); //arg1: tpack_t ptr. + lua_settop(L, 1); + unpack_lua_data(pack, rpos, L); + return 1; } -extern bool bson_decode(tpack_t* pack, lua_State *L); \ No newline at end of file +extern bool ltunpack(tpack_t* pack, lua_State *L) { + lua_checkstack(L, 3); + lua_pushcfunction(L, unpack_safe); + lua_pushlightuserdata(L, pack); + return lua_pcall(L, 1, LUA_MULTRET, NULL) == LUA_OK; +} diff --git a/src/ltpack.h b/src/ltpack.h index 9d25c05..d4bf7ca 100644 --- a/src/ltpack.h +++ b/src/ltpack.h @@ -1,12 +1,13 @@ #ifndef LTPACK_H_ #define LTPACK_H_ +#include "common.h" #include "sds.h" typedef struct tpack_t { sds m_data; } tpack_t; -extern tpack_t* bson_encode(lua_State *L, int idx); -extern bool bson_decode(tpack_t* pack, lua_State *L); +extern bool ltpack(tpack_t* pack, lua_State *L, int idx); +extern bool ltunpack(tpack_t* pack, lua_State *L); #endif diff --git a/src/message.h b/src/message.h index c452865..bc5debf 100644 --- a/src/message.h +++ b/src/message.h @@ -1,7 +1,6 @@ #ifndef MESSAGE_H_ #define MESSAGE_H_ #include "buffer.h" -#include "lbson.h" #include "lbinary.h" #include "ltpack.h" @@ -23,9 +22,8 @@ enum data_type { STRING = 6, //need to be freed BINARY = 7, //need to be freed TPACK = 8, //need to be freed - BSON = 9, //need to be freed - ARRAY = 10,//need to be freed - TERROR = 11 // + ARRAY = 9, //need to be freed + TERROR = 10 // }; typedef union data_t { @@ -36,7 +34,7 @@ typedef union data_t { buffer_t m_buffer; char *m_string; binary_t m_binary; - bson_t *m_bson; + tpack_t m_tpack; message_array_t *m_array; int32_t m_error; } data_t; @@ -77,7 +75,7 @@ enum message_type { #define message_buffer(msg) ((msg).m_data.m_buffer) #define message_string(msg) ((msg).m_data.m_string) #define message_binary(msg) ((msg).m_data.m_binary) -#define message_bson(msg) ((msg).m_data.m_bson) +#define message_tpack(msg) ((msg).m_data.m_tpack) #define message_array(msg) ((msg).m_data.m_array) #define message_error(msg) ((msg).m_data.m_error) @@ -90,7 +88,7 @@ enum message_type { #define message_is_buffer(msg) (BUFFER == message_data_type(msg)) #define message_is_string(msg) (STRING == message_data_type(msg)) #define message_is_binary(msg) (BINARY == message_data_type(msg)) -#define message_is_bson(msg) (BSON == message_data_type(msg)) +#define message_is_tpack(msg) (TPACK == message_data_type(msg)) #define message_is_array(msg) (ARRAY == message_data_type(msg)) #define message_is_error(msg) (TERROR == message_data_type(msg)) #define message_is_pure_error(msg) (TERROR == message_data_type(msg) && message_error(msg) != 0) @@ -110,10 +108,10 @@ enum message_type { sdsfree((msg).m_data.m_binary.m_data); \ (msg).m_data.m_binary.m_data = NULL; \ } \ - } else if (message_is_bson(msg)) { \ - if ((msg).m_data.m_bson) { \ - bson_release((msg).m_data.m_bson); \ - (msg).m_data.m_bson = NULL; \ + } else if (message_is_tpack(msg)) { \ + if ((msg).m_data.m_tpack.m_data) { \ + sdsfree((msg).m_data.m_tpack.m_data); \ + (msg).m_data.m_tpack.m_data = NULL; \ } \ } else if (message_is_array(msg)) { \ if ((msg).m_data.m_array) { \ @@ -165,9 +163,9 @@ class message_t { : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, TERROR)) { m_data.m_error = err; } - message_t(uint32_t source, int32_t session, uint32_t msg_type, bson_t *bson) + message_t(uint32_t source, int32_t session, uint32_t msg_type, tpack_t tpack) : m_source(source), m_session(session), - m_type(MAKE_MESSAGE_TYPE(msg_type, BSON)) { m_data.m_bson = bson; } + m_type(MAKE_MESSAGE_TYPE(msg_type, TPACK)) { m_data.m_tpack = tpack; } message_t(uint32_t source, int32_t session, uint32_t msg_type, binary_t binary) : m_source(source), m_session(session), From bb28e6e3109237f6aa7f22d0a00ddb13fb04113c Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 20 Jun 2016 21:28:00 +0800 Subject: [PATCH 124/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8DluaL=5Ferror=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=A4=9A=E5=8F=82=E5=8F=82=E6=95=B0=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E9=97=AE=E9=A2=98(=E4=B8=8Eprintf=E7=B1=BB=E4=B8=8D=E5=90=8C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 12 ++++++------ src/lua_tcp_handle.cpp | 6 +++--- src/lua_udp_handle.cpp | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index b517137..cb7d2fb 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -913,7 +913,7 @@ int32_t context_lua_t::context_destroy(lua_State *L) } uint32_t handle = luaL_checkunsigned(L, 1); if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { - luaL_error(L, "attempt to destroy an illegal context:0x%08x", handle); + luaL_error(L, "attempt to destroy an illegal context:0x%p", (void*)handle); } singleton_ref(node_lua_t).context_destroy(handle, src_handle, lua_tostring(L, 2)); return 0; @@ -1014,7 +1014,7 @@ int32_t context_lua_t::context_send(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { - luaL_error(L, "attempt to send to an illegal context:0x%08x", handle); + luaL_error(L, "attempt to send to an illegal context:0x%p", (void*)handle); } int32_t top = lua_gettop(L); luaL_checkany(L, 2); @@ -1075,7 +1075,7 @@ int32_t context_lua_t::context_query(lua_State *L, bool timed_query) { uint32_t handle = luaL_checkunsigned(L, 1); if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { - luaL_error(L, "attempt to query to an illegal context:0x%08x", handle); + luaL_error(L, "attempt to query to an illegal context:0x%p", (void*)handle); } int32_t top = lua_gettop(L); uint64_t timeout = 0; @@ -1136,7 +1136,7 @@ int32_t context_lua_t::context_reply(lua_State *L) { uint32_t handle = luaL_checkunsigned(L, 1); if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { - luaL_error(L, "attempt to reply to an illegal context:0x%08x", handle); + luaL_error(L, "attempt to reply to an illegal context:0x%p", (void*)handle); } int32_t session = luaL_checkinteger(L, 2); luaL_checkany(L, 3); @@ -1202,7 +1202,7 @@ int32_t context_lua_t::context_recv(lua_State *L) context_lua_t* lctx = (context_lua_t*)lua_get_context(L); uint32_t handle = luaL_checkunsigned(L, 1); if (singleton_ref(node_lua_t).is_handle_illegal(handle)) { - luaL_error(L, "attempt to recv from an illegal context:0x%08x", handle); + luaL_error(L, "attempt to recv from an illegal context:0x%p", (void*)handle); } int32_t top = lua_gettop(L); uint64_t timeout = 0; @@ -1262,7 +1262,7 @@ int32_t context_lua_t::context_wait(lua_State *L) context_lua_t* lctx = (context_lua_t*)lua_get_context(L); uint32_t handle = luaL_checkunsigned(L, 1); if (handle == 0 || singleton_ref(node_lua_t).is_handle_illegal(handle)) { - luaL_error(L, "attempt to wait an illegal context:0x%08x", handle); + luaL_error(L, "attempt to wait an illegal context:0x%p", (void*)handle); } if (handle == lctx->get_handle()) { luaL_error(L, "can't wait self to die away"); diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 17ad59e..e79acc3 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -587,7 +587,7 @@ int32_t lua_tcp_socket_handle_t::write_fd(lua_State* L) request.m_tcp_write.m_length = length; /* length > 0 */ request.m_tcp_write.m_string = (const char*)nl_memdup(s, length); if (!request.m_tcp_write.m_string) { - return luaL_error(L, "attempt to send data(length %lu) failed: memory not enough", length); + return luaL_error(L, "attempt to send data(length %d) failed: memory not enough", length); } } else { request.m_tcp_write.m_length = 0; @@ -625,7 +625,7 @@ int32_t lua_tcp_socket_handle_t::write_handle(lua_State* L) } uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)socket->m_uv_handle; if (!check_head_option_max(handle->m_write_head_option, length)) { - return luaL_error(L, "attempt to send data(length %lu) too long(max %lu)", length, handle->m_write_head_option.max); + return luaL_error(L, "attempt to send data(length %d) too long(max %d)", length, handle->m_write_head_option.max); } bool safety = false; bool nonblocking = false; @@ -661,7 +661,7 @@ int32_t lua_tcp_socket_handle_t::write_handle(lua_State* L) request.m_tcp_write.m_length = length; /* length > 0 */ request.m_tcp_write.m_string = (const char*)nl_memdup(s, length); if (!request.m_tcp_write.m_string) { - return luaL_error(L, "attempt to send data(length %lu) failed: memory not enough", length); + return luaL_error(L, "attempt to send data(length %d) failed: memory not enough", length); } } else { request.m_tcp_write.m_length = 0; diff --git a/src/lua_udp_handle.cpp b/src/lua_udp_handle.cpp index 3dc9f79..1dc1c88 100644 --- a/src/lua_udp_handle.cpp +++ b/src/lua_udp_handle.cpp @@ -211,7 +211,7 @@ int32_t lua_udp_handle_t::_write(lua_State* L, bool ipv6) request.m_udp_write.m_length = length; /* length > 0 */ request.m_udp_write.m_string = (const char*)nl_memdup(s, length); if (!request.m_udp_write.m_string) { - return luaL_error(L, "attempt to send data(length %lu) failed: memory not enough", length); + return luaL_error(L, "attempt to send data(length %d) failed: memory not enough", length); } } else { request.m_udp_write.m_length = 0; From c694d189d425031704c93bf47a722f5f43cdc2a9 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 21 Jun 2016 00:11:35 +0800 Subject: [PATCH 125/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dltpack=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ltpack.cpp | 2 +- src/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ltpack.cpp b/src/ltpack.cpp index cb0a3e9..b3e018a 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -53,7 +53,7 @@ static inline void pack_string(tpack_t *pack, const char* v, size_t len) { pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_STRING); pack->m_data = sdscat(pack->m_data, len); - pack->m_data = sdscpylen(pack->m_data, v, len); + pack->m_data = sdscatlen(pack->m_data, v, len); } static void diff --git a/src/main.cpp b/src/main.cpp index 9d8a7f7..9f61634 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,6 @@ int main(int argc, char* argv[], char* env[]) node_lua_t node(argc - 1, argv + 1, env); double duration = (uv_hrtime() - start_time) / 1e9; printf("Process used %.3f sec total!\n", duration); - //getchar(); + getchar(); return 0; } From 13c69342f7f6387a5356dc29f01700b3e5a9d3b8 Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 21 Jun 2016 00:30:18 +0800 Subject: [PATCH 126/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dtpack=E5=8E=8B?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ltpack.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ltpack.cpp b/src/ltpack.cpp index b3e018a..d54339a 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -64,6 +64,7 @@ pack_table(tpack_t *pack, lua_State *L, int idx, int depth) { if (depth > MAX_DEPTH) { luaL_error(L, "too deep(%d, limit %d) while packing table", depth, MAX_DEPTH); } + idx = lua_absindex(L, idx); pack->m_data = sdscat(pack->m_data, (int8_t)TYPE_TABLE_BEG); luaL_checkstack(L, 2, NULL); lua_pushnil(L); From 4096072043249079aea7fbd8b524ca5dc22051ff Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 21 Jun 2016 10:38:45 +0800 Subject: [PATCH 127/173] do notingh --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 9f61634..9d8a7f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,6 @@ int main(int argc, char* argv[], char* env[]) node_lua_t node(argc - 1, argv + 1, env); double duration = (uv_hrtime() - start_time) / 1e9; printf("Process used %.3f sec total!\n", duration); - getchar(); + //getchar(); return 0; } From 84c9522f94ca79247606ac6cae837e67ecd8d8cf Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 21 Jun 2016 16:07:51 +0800 Subject: [PATCH 128/173] do nothing --- src/common.h | 1 - src/network.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common.h b/src/common.h index 7f8d823..da4523d 100644 --- a/src/common.h +++ b/src/common.h @@ -17,7 +17,6 @@ #define container_of(ptr, type, member) \ ((type *) ((char *) (ptr) - offsetof(type, member))) -//to be fix : fix me #ifdef RELEASE #define WPAssert( assertion ) { if( !(assertion) ) { fprintf( stderr, "\n%s:%i ASSERTION FAILED:\n %s\n", __FILE__, __LINE__, #assertion ); } } #else diff --git a/src/network.cpp b/src/network.cpp index e03afa6..6cf6aa5 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -178,7 +178,7 @@ bool network_t::recv_request() int32_t need_read = 0, readed = 0; int32_t processed = 0, nbytes = 0; request_t request; - for (;;) { //to be fixed : Żȡ + for (;;) { if (need_read == 0) { nbytes = ::recv(m_request_r_fd, (char*)(&request.m_length), sizeof(request.m_length), 0); if (nbytes > 0) { From 79a2f4928c6a435d950827c28acc8d1ec39e032c Mon Sep 17 00:00:00 2001 From: xdczju Date: Tue, 21 Jun 2016 16:18:53 +0800 Subject: [PATCH 129/173] do nothing --- src/ltpack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ltpack.cpp b/src/ltpack.cpp index d54339a..068da83 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -100,7 +100,7 @@ pack_lua_data(tpack_t *pack, lua_State *L, int idx, int depth) { pack_table(pack, L, idx, depth + 1); return; default: - luaL_error(L, "Invalid data type : %s", lua_typename(L, data_type)); + luaL_error(L, "attempt to pack a %s value", lua_typename(L, data_type)); return; } } From 054a60b7c30009d112f531c7a3bf67d921a55793 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 23 Jun 2016 19:25:03 +0800 Subject: [PATCH 130/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0context.run=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 30 ++++++++++++++++++++++++++++++ src/context_lua.h | 3 +++ src/message.h | 1 + 3 files changed, 34 insertions(+) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index cb7d2fb..62a54ce 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -685,6 +685,9 @@ void context_lua_t::on_received(message_t& message) case LUA_CTX_WAKEUP: response_context_wakeup(message); break; + case LUA_CTX_RUN: + response_context_run(message); + break; case RESPONSE_TCP_LISTEN: response_tcp_listen(message); break; @@ -807,6 +810,11 @@ void context_lua_t::response_context_wakeup(message_t& response) m_context_wait_sessions.wakeup_all(response.m_source, this, response, true); } +void context_lua_t::response_context_run(message_t& response) +{ + wakeup_ref_session(response.m_session, response, true); +} + void context_lua_t::response_tcp_listen(message_t& response) { lua_tcp_listen_handle_t::wakeup_listen(m_lstate, response); @@ -1341,6 +1349,27 @@ int32_t context_lua_t::context_log(lua_State *L) return 0; } +int32_t context_lua_t::context_run_callback_adjust(lua_State* L) +{ + lua_pop(L, 4); + return 0; +} + +int32_t context_lua_t::context_run(lua_State *L) +{ + int32_t top = lua_gettop(L); + luaL_checktype(L, 1, LUA_TFUNCTION); + if (top > 1) { + lua_rotate(L, 1, top - 1); + } + int32_t session = context_lua_t::lua_ref_callback(L, top - 1, LUA_REFNIL, context_run_callback_adjust); + context_lua_t* lctx = context_lua_t::lua_get_context(L); + if (!singleton_ref(node_lua_t).context_send(lctx, lctx->get_handle(), session, LUA_CTX_RUN, UV_OK)) { + context_lua_t::lua_free_ref_session(L, session); + } + return 0; +} + int luaopen_context(lua_State *L) { luaL_Reg l[] = { @@ -1355,6 +1384,7 @@ int luaopen_context(lua_State *L) { "recv", context_lua_t::context_recv }, { "wait", context_lua_t::context_wait }, { "log", context_lua_t::context_log }, + { "run", context_lua_t::context_run }, { NULL, NULL }, }; luaL_newlib(L, l); diff --git a/src/context_lua.h b/src/context_lua.h index 2f9f4cc..8c8fb5f 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -94,6 +94,7 @@ class context_lua_t : public context_t { void response_context_reply(message_t& response); void response_context_wait(message_t& response); void response_context_wakeup(message_t& response); + void response_context_run(message_t& response); void response_tcp_listen(message_t& response); void response_tcp_accept(message_t& response); void response_tcp_connect(message_t& response); @@ -151,6 +152,7 @@ class context_lua_t : public context_t { static int32_t context_wait_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t context_wait_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t context_wait_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat); + static int32_t context_run_callback_adjust(lua_State* L); static int32_t context_strerror(lua_State *L); static int32_t context_self(lua_State *L); static int32_t context_thread(lua_State *L); @@ -163,6 +165,7 @@ class context_lua_t : public context_t { static int32_t context_recv(lua_State *L); static int32_t context_wait(lua_State *L); static int32_t context_log(lua_State *L); + static int32_t context_run(lua_State *L); /************ the above are context lua api ************/ public: diff --git a/src/message.h b/src/message.h index bc5debf..6a857a5 100644 --- a/src/message.h +++ b/src/message.h @@ -50,6 +50,7 @@ enum message_type { LUA_CTX_INIT, LUA_CTX_WAIT, LUA_CTX_WAKEUP, + LUA_CTX_RUN, RESPONSE_TCP_LISTEN, RESPONSE_TCP_ACCEPT, RESPONSE_TCP_CONNECT, From c513d22c8080a15a04803f80e1ff081617830dba Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 23 Jun 2016 19:30:41 +0800 Subject: [PATCH 131/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0context.run=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 86c46e1..bd56300 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,9 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** 15. thread = **context.thread**() *`--return the running thread index.`* +16. **context.run**(func[, ...]) + *`--run the func at next tick(in other words next processing period).`* + ### tcp api 1. result, listen_socket = **tcp.listen**(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) From 7f18f86a5028f374c5dc6da1df8e82d9378f71d0 Mon Sep 17 00:00:00 2001 From: xdczju Date: Thu, 1 Sep 2016 20:53:05 +0800 Subject: [PATCH 132/173] =?UTF-8?q?=E5=87=86=E5=A4=87=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=BF=9B=E7=A8=8B=E8=B0=83=E8=AF=95=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/network.cpp | 2 ++ src/network.h | 1 + src/utils.cpp | 11 ++++++++++- src/utils.h | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/network.cpp b/src/network.cpp index 6cf6aa5..442a632 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -27,6 +27,8 @@ network_t::network_t() : m_exiting(0) assert(rc == 0); rc = uv_poll_start(&m_request_handle, UV_READABLE, on_request_polled_in); assert(rc == 0); + //rc = uv_pipe_init(m_uv_loop, &m_remoter_handle, 1); + //assert(rc == 0); memset(&m_shared_read_buffer, 0, sizeof(m_shared_read_buffer)); } diff --git a/src/network.h b/src/network.h index 4213406..39bb706 100644 --- a/src/network.h +++ b/src/network.h @@ -19,6 +19,7 @@ class network_t : public singleton_t { uv_os_sock_t m_request_r_fd; uv_os_sock_t m_request_w_fd; uv_poll_t m_request_handle; + uv_pipe_t m_remoter_handle; uv_buf_t m_shared_read_buffer; /* tcp and udp shared read buffer in network thread */ shared_write_map_t m_shared_write_sockets; /* tcp and udp shared write socket in network thread */ atomic_t m_exiting; diff --git a/src/utils.cpp b/src/utils.cpp index e2283e2..87c9c80 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -132,4 +132,13 @@ uv_err_code host_sockaddr(bool ipv6, const char* host, uint16_t port, struct soc addr6->sin6_port = htons(port); return uv_inet_pton(AF_INET6, host, (void*)&addr6->sin6_addr).code; } -} \ No newline at end of file +} + +extern int get_pid() +{ +#ifdef _WIN32 + return GetCurrentProcessId(); +#else + return getpid(); +#endif +} diff --git a/src/utils.h b/src/utils.h index c67b2fa..7efafd5 100644 --- a/src/utils.h +++ b/src/utils.h @@ -7,4 +7,5 @@ extern void* nl_memdup(const void* src, uint32_t len); extern bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, bool* ipv6, uint16_t* port); extern bool sockaddr_host(struct sockaddr* addr, char* host, uint32_t host_len, bool* ipv6, uint16_t* port); extern uv_err_code host_sockaddr(bool ipv6, const char* host, uint16_t port, struct sockaddr* addr); +extern int get_pid(); #endif From 249a2b5b2621b6628823012261b32151e201ed05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 14 Aug 2017 00:09:51 +0800 Subject: [PATCH 133/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd56300..5c79b75 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** *`--return the running thread index.`* 16. **context.run**(func[, ...]) - *`--run the func at next tick(in other words next processing period).`* + *`--run the func(...) at next tick(in other words next processing period).`* ### tcp api From 6e0ca8f03b9acddf96b6ac1e51a21ee0945b486b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 14 Aug 2017 20:41:04 +0800 Subject: [PATCH 134/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B9=8B=E5=89=8D?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=85=AC=E7=94=A8=E5=9B=9E=E8=B0=83=E5=BC=95?= =?UTF-8?q?=E8=B5=B7=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lua_tcp_handle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index e79acc3..8412412 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -437,7 +437,7 @@ int32_t lua_tcp_socket_handle_t::_connect(lua_State* L, bool ipv6) *local_host = '\0'; /* we don't support it at this version */ if (callback > 0) { /* nonblocking callback */ lua_settop(L, callback); - request.m_tcp_connect.m_session = context_lua_t::lua_ref_callback(L, callback - 1, LUA_REFNIL, context_lua_t::common_callback_adjust); + request.m_tcp_connect.m_session = context_lua_t::lua_ref_callback(L, callback - 1, LUA_REFNIL, connect_callback_adjust); singleton_ref(network_t).send_request(request); if (timeout > 0) { context_lua_t::lua_ref_timer(L, request.m_tcp_connect.m_session, timeout, 0, false); @@ -477,7 +477,7 @@ int32_t lua_tcp_socket_handle_t::connects(lua_State* L) memcpy(REQUEST_SPARE_PTR(request.m_tcp_connects), sock, sock_len + 1); if (callback > 0) { /* nonblocking callback */ lua_settop(L, callback); - request.m_tcp_connects.m_session = context_lua_t::lua_ref_callback(L, callback - 1, LUA_REFNIL, context_lua_t::common_callback_adjust); + request.m_tcp_connects.m_session = context_lua_t::lua_ref_callback(L, callback - 1, LUA_REFNIL, connect_callback_adjust); singleton_ref(network_t).send_request(request); if (timeout > 0) { context_lua_t::lua_ref_timer(L, request.m_tcp_connects.m_session, timeout, 0, false); From ce02e557dd17e77d9a0e85117b050ca35c3030fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 21 Aug 2017 14:58:31 +0800 Subject: [PATCH 135/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0vs=E7=8E=AF=E5=A2=83r?= =?UTF-8?q?elease=E7=89=88=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加vs环境release版支持 --- node-lua.vcxproj | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/node-lua.vcxproj b/node-lua.vcxproj index 785da0c..e1e26d0 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -46,7 +46,7 @@ true - $(SolutionDir)$(Configuration)\ + $(ProjectDir) $(Configuration)\ false @@ -54,7 +54,7 @@ Disabled deps\lua;deps\uv\include;deps\uv\include\uv-private;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CONSOLE;LUA_COMPAT_5_2;LUA_COMPAT_5_1;%(PreprocessorDefinitions) + _DEBUG;_CONSOLE;LUA_COMPAT_5_2;LUA_COMPAT_5_1;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -75,7 +75,7 @@ MaxSpeed true deps\lua;deps\uv\include;deps\uv\include\uv-private;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _CONSOLE;LUA_COMPAT_5_2;LUA_COMPAT_5_1;%(PreprocessorDefinitions) MultiThreadedDLL true @@ -83,12 +83,13 @@ ProgramDatabase - ws2_32.lib;psapi.lib;iphlpapi.lib;%(AdditionalDependencies) + uv.lib;nlua.lib;ws2_32.lib;psapi.lib;iphlpapi.lib;%(AdditionalDependencies) true Console true true MachineX86 + deps\uv;deps\lua;%(AdditionalLibraryDirectories) From 8e42ea1ef7cba2a82dc13bb885be8173f08fd71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 21 Aug 2017 15:21:29 +0800 Subject: [PATCH 136/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0vs=E7=8E=AF=E5=A2=83r?= =?UTF-8?q?elease=E7=89=88=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加vs环境release版支持 --- ...3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base | 1 + deps/lua/lua.vcxproj | 15 ++++++++++++--- deps/uv/uv.vcxproj | 14 ++++++++++---- 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 data/Csvs/.svn/pristine/12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base diff --git a/data/Csvs/.svn/pristine/12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base b/data/Csvs/.svn/pristine/12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base new file mode 100644 index 0000000..2e78f82 --- /dev/null +++ b/data/Csvs/.svn/pristine/12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base @@ -0,0 +1 @@ + {index=1,indirect=0,event={1002},actions={{10004,1}}}, diff --git a/deps/lua/lua.vcxproj b/deps/lua/lua.vcxproj index 0ef4281..452d78b 100644 --- a/deps/lua/lua.vcxproj +++ b/deps/lua/lua.vcxproj @@ -22,11 +22,11 @@ Unicode - Application + DynamicLibrary false v120 true - MultiByte + Unicode @@ -43,12 +43,17 @@ .dll nlua + + $(ProjectDir) + nlua + .dll + Level3 Disabled true - WIN32;_DEBUG;LUA_COMPAT_5_2;LUA_COMPAT_5_1;LUA_BUILD_AS_DLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + _DEBUG;LUA_COMPAT_5_2;LUA_COMPAT_5_1;LUA_BUILD_AS_DLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) Default @@ -65,12 +70,16 @@ true true true + LUA_COMPAT_5_2;LUA_COMPAT_5_1;LUA_BUILD_AS_DLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true true true + + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + diff --git a/deps/uv/uv.vcxproj b/deps/uv/uv.vcxproj index c829a57..b3096da 100644 --- a/deps/uv/uv.vcxproj +++ b/deps/uv/uv.vcxproj @@ -69,11 +69,11 @@ Unicode - Application + StaticLibrary false v120 true - MultiByte + Unicode @@ -88,13 +88,17 @@ $(ProjectDir) + + $(ProjectDir) + .lib + Level3 Disabled false include;include\uv-private; - WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) + _DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) @@ -111,7 +115,9 @@ MaxSpeed true true - true + false + include;include\uv-private; + _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions) true From c35849cd1901b2610760b1be46e9b7a856c6d06a Mon Sep 17 00:00:00 2001 From: xdczju Date: Mon, 21 Aug 2017 15:54:45 +0800 Subject: [PATCH 137/173] remove useless dir --- .../12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base | 1 - 1 file changed, 1 deletion(-) delete mode 100644 data/Csvs/.svn/pristine/12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base diff --git a/data/Csvs/.svn/pristine/12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base b/data/Csvs/.svn/pristine/12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base deleted file mode 100644 index 2e78f82..0000000 --- a/data/Csvs/.svn/pristine/12/12e3f527d7e147a3dc514edae3706e1889d7eaa4.svn-base +++ /dev/null @@ -1 +0,0 @@ - {index=1,indirect=0,event={1002},actions={{10004,1}}}, From a3b453b94264b2c9a8a5377852499688b81ec266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 21 Aug 2017 23:29:37 +0800 Subject: [PATCH 138/173] =?UTF-8?q?=E6=B7=BB=E5=8A=A0git=E6=8E=92=E9=99=A4?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 09123f7..80eddcc 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ *.opensdf *.vcxproj.user Debug/ +Release/ lua luac node-lua From 64637c8c5239ae9f7c1d18ec4bef8aa67b72f1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 10 Sep 2017 23:42:49 +0800 Subject: [PATCH 139/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dlinux=E4=B8=8B?= =?UTF-8?q?=E5=A4=B4=E6=96=87=E4=BB=B6=E7=A1=AE=E5=AE=9E=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ltpack.cpp | 4 ++-- src/utils.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ltpack.cpp b/src/ltpack.cpp index 068da83..52cec6b 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -1,7 +1,7 @@ -#include "ltpack.h" #define __STDC_LIMIT_MACROS +#include "ltpack.h" #ifndef _WIN32 -# include +#include #endif #define MAX_DEPTH 256 diff --git a/src/utils.cpp b/src/utils.cpp index 87c9c80..4404cd0 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,5 +1,8 @@ #include "common.h" #include "utils.h" +#ifndef _WIN32 +#include +#endif char* filter_arg(char **param, int32_t *len) { char *begptr = *param; From 341e593c06d828236264d78fbc2fdc3371044ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 11 Sep 2017 11:47:09 +0800 Subject: [PATCH 140/173] a little thing --- src/context_lua.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 62a54ce..9315798 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -930,7 +930,6 @@ int32_t context_lua_t::context_destroy(lua_State *L) int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t msg_type, message_t& message) { buffer_t* buffer; - int32_t* bson_data; const char* data; size_t length; switch (lua_type(L, idx)) { From 6ff60a238d2743236f8d3b83859fdb80042666a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 9 Oct 2017 18:26:36 +0800 Subject: [PATCH 141/173] nothing to say --- node-lua.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/node-lua.lua b/node-lua.lua index a2b7995..7f4868e 100644 --- a/node-lua.lua +++ b/node-lua.lua @@ -1,6 +1,6 @@ -14. 考虑lua_service的gc[考虑一直没有唤醒的服务的lua垃圾回收] +14. 考虑lua_service的定时gc[考虑一直没有唤醒的服务的lua垃圾回收] -17. 研究lua hook,如何中断死循环和调试(输入) +17. 研究lua hook,如何中断死循环和远程调试(输入) 22.to be implemented / to be fixed @@ -8,6 +8,8 @@ 24.lua socket tcp socket 迁移 +25.如何支持数据共享,解决内存过大问题:提供共享api + io 阻塞非阻塞? setvbuf {"__tostring", f_tostring}, From 9f632560b092fee176388c2bce6947fb6bad7b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Tue, 10 Oct 2017 16:34:09 +0800 Subject: [PATCH 142/173] =?UTF-8?q?=E4=BC=98=E5=8C=96buffer=E5=92=8Clbuffe?= =?UTF-8?q?r=EF=BC=8C=E5=A2=9E=E5=8A=A0=E4=BA=86=E9=9D=9E=E5=B8=B8?= =?UTF-8?q?=E5=AE=9E=E7=94=A8=E7=9A=84=E5=87=A0=E4=B8=AA=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/buffer.cpp | 117 ++++++++++++ src/buffer.h | 3 + src/lbuffer.cpp | 486 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 606 insertions(+) diff --git a/src/buffer.cpp b/src/buffer.cpp index 12346d2..94f5789 100644 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -92,6 +92,87 @@ bool buffer_append(buffer_t& buffer_ref, const char *data, size_t data_len) { return buffer ? true : false; } +char* buffer_reserve(buffer_t& buffer_ref, size_t data_len) { + buffer_data_ptr_t buffer = buffer_ref.m_ptr; + if (buffer) { + if (buffer->m_ref == 1) { + if (data_len <= (size_t)(buffer->m_cap - buffer->m_len)) { + return buffer->m_data + buffer->m_len; + } + size_t new_cap = buffer_gen_capacity(buffer_ref, data_len); + if (new_cap > 0) { + buffer_data_ptr_t new_buffer = (buffer_data_ptr_t)nl_realloc(buffer, sizeof(buffer_data_t) + new_cap + 1); + if (new_buffer) { + new_buffer->m_cap = new_cap; + buffer_ref.m_ptr = new_buffer; + return new_buffer->m_data + new_buffer->m_len; + } + } + return NULL; + } else { + size_t new_cap = buffer_gen_capacity(buffer_ref, data_len); + if (new_cap > 0) { + buffer_data_ptr_t new_buffer = (buffer_data_ptr_t)nl_malloc(sizeof(buffer_data_t) + new_cap + 1); + if (new_buffer) { + new_buffer->m_cap = new_cap; + new_buffer->m_ref = 1; + new_buffer->m_len = buffer->m_len; + memcpy(new_buffer->m_data, buffer->m_data, buffer->m_len); + new_buffer->m_data[new_buffer->m_len] = 0; + buffer_release(buffer_ref); + buffer_ref.m_ptr = new_buffer; + return new_buffer->m_data + new_buffer->m_len; + } + } + return NULL; + } + } + return NULL; +} + +bool buffer_append_char(buffer_t& buffer_ref, char ch) { + buffer_data_ptr_t buffer = buffer_ref.m_ptr; + if (buffer) { + if (buffer->m_ref == 1) { + if (1 <= (size_t)(buffer->m_cap - buffer->m_len)) { + buffer->m_data[buffer->m_len] = ch; + buffer->m_data[++buffer->m_len] = 0; + return true; + } + size_t new_cap = buffer_gen_capacity(buffer_ref, 1); + if (new_cap > 0) { + buffer_data_ptr_t new_buffer = (buffer_data_ptr_t)nl_realloc(buffer, sizeof(buffer_data_t) + new_cap + 1); + if (new_buffer) { + new_buffer->m_cap = new_cap; + new_buffer->m_data[new_buffer->m_len] = ch; + new_buffer->m_data[++new_buffer->m_len] = 0; + buffer_ref.m_ptr = new_buffer; + return true; + } + } + return false; + } else { + size_t new_cap = buffer_gen_capacity(buffer_ref, 1); + if (new_cap > 0) { + buffer_data_ptr_t new_buffer = (buffer_data_ptr_t)nl_malloc(sizeof(buffer_data_t) + new_cap + 1); + if (new_buffer) { + new_buffer->m_cap = new_cap; + new_buffer->m_ref = 1; + new_buffer->m_len = buffer->m_len; + memcpy(new_buffer->m_data, buffer->m_data, buffer->m_len); + new_buffer->m_data[new_buffer->m_len] = ch; + new_buffer->m_data[++new_buffer->m_len] = 0; + buffer_release(buffer_ref); + buffer_ref.m_ptr = new_buffer; + return true; + } + } + return false; + } + } + return false; +} + bool buffer_clear(buffer_t& buffer_ref) { buffer_data_ptr_t buffer = buffer_ref.m_ptr; if (!buffer) return true; @@ -173,3 +254,39 @@ buffer_t buffer_split(buffer_t& buffer_ref, size_t len) } return buffer_new(DEFAULT_BUFFER_CAPACITY, NULL, 0); } + +size_t buffer_remove(buffer_t& buffer_ref, size_t start, size_t len) +{ + buffer_data_ptr_t buffer = buffer_ref.m_ptr; + if (buffer && len > 0 && buffer->m_len > start) { + int32_t remove_len = len < ((size_t)buffer->m_len - start) ? (int32_t)len : ((size_t)buffer->m_len - start); + if (buffer->m_ref == 1) { + buffer->m_len -= remove_len; + if (buffer->m_len > start) { + memcpy(buffer->m_data + start, buffer->m_data + start + remove_len, buffer->m_len - start); + } + buffer->m_data[buffer->m_len] = 0; + } else { + if (remove_len < buffer->m_len) { + buffer_t new_buffer = buffer_new(buffer->m_len - remove_len, NULL, 0); + buffer_data_ptr_t nbuffer = new_buffer.m_ptr; + if (nbuffer) { + nbuffer->m_len = buffer->m_len - remove_len; + if (start > 0) { + memcpy(nbuffer->m_data, buffer->m_data, start); + } + if (nbuffer->m_len > start) { + memcpy(nbuffer->m_data + start, buffer->m_data + start + remove_len, nbuffer->m_len - start); + } + nbuffer->m_data[nbuffer->m_len] = 0; + } + buffer_release(buffer_ref); + buffer_ref = new_buffer; + } else { //remove_len == buffer->m_len + buffer_ref = buffer_new(DEFAULT_BUFFER_CAPACITY, NULL, 0); + } + } + return remove_len; + } + return 0; +} diff --git a/src/buffer.h b/src/buffer.h index 65f4f0f..ebba85e 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -19,12 +19,15 @@ typedef struct { extern buffer_t buffer_new(size_t cap, const char *init, size_t init_len); extern bool buffer_append(buffer_t& buffer_ref, const char *data, size_t data_len); +extern char* buffer_reserve(buffer_t& buffer_ref, size_t data_len); +extern bool buffer_append_char(buffer_t& buffer_ref, char ch); extern bool buffer_clear(buffer_t& buffer_ref); extern buffer_t& buffer_grab(buffer_t& buffer_ref); extern void buffer_release(buffer_t& buffer_ref); extern bool buffer_concat(buffer_t& dest_ref, const buffer_t& src_ref); extern bool buffer_adjust_len(buffer_t& buffer_ref, size_t add); extern buffer_t buffer_split(buffer_t& buffer_ref, size_t len); +extern size_t buffer_remove(buffer_t& buffer_ref, size_t start, size_t len); #define invalid_buffer { NULL } #define buffer_is_valid(buffer_ref) ((buffer_ref).m_ptr != NULL) diff --git a/src/lbuffer.cpp b/src/lbuffer.cpp index dde519f..40ec1a5 100644 --- a/src/lbuffer.cpp +++ b/src/lbuffer.cpp @@ -53,6 +53,27 @@ static int32_t lbuffer_split(lua_State* L) return 1; } +/* translate a relative string position: negative means back from end */ +static lua_Integer posrelat(lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + +static int32_t lbuffer_remove(lua_State* L) +{ + buffer_t* buffer = (buffer_t*)luaL_checkudata(L, 1, BUFFER_METATABLE); + lua_Integer length = buffer_data_length(*buffer); + lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), length); + + size_t start = pos >= 1 ? pos - 1 : 0; + size_t rmlen = luaL_optunsigned(L, 3, length); + + rmlen = buffer_remove(*buffer, start, rmlen); + lua_pushinteger(L, rmlen); + return 1; +} + static int32_t lbuffer_clear(lua_State* L) { buffer_t* buffer = (buffer_t*)luaL_checkudata(L, 1, BUFFER_METATABLE); @@ -123,12 +144,477 @@ static int32_t lbuffer_release(lua_State* L) return 0; } + +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + +/* +** {====================================================== +** PACK/UNPACK +** ======================================================= +*/ + + +/* value used for padding */ +#if !defined(LUA_PACKPADBYTE) +#define LUA_PACKPADBYTE 0x00 +#endif + +/* maximum size for the binary representation of an integer */ +#define MAXINTSIZE 16 + +/* number of bits in a character */ +#define NB CHAR_BIT + +/* mask for one character (NB 1's) */ +#define MC ((1 << NB) - 1) + +/* size of a lua_Integer */ +#define SZINT ((int)sizeof(lua_Integer)) + + +/* dummy union to get native endianness */ +static const union { + int dummy; + char little; /* true iff machine is little endian */ +} nativeendian = { 1 }; + + +/* dummy structure to get native alignment requirements */ +struct cD { + char c; + union { double d; void *p; lua_Integer i; lua_Number n; } u; +}; + +#define MAXALIGN (offsetof(struct cD, u)) + + +/* +** Union for serializing floats +*/ +typedef union Ftypes { + float f; + double d; + lua_Number n; + char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ +} Ftypes; + + +/* +** information to pack/unpack stuff +*/ +typedef struct Header { + lua_State *L; + int islittle; + int maxalign; +} Header; + + +/* +** options for pack/unpack +*/ +typedef enum KOption { + Kint, /* signed integers */ + Kuint, /* unsigned integers */ + Kfloat, /* floating-point numbers */ + Kchar, /* fixed-length strings */ + Kstring, /* strings with prefixed length */ + Kzstr, /* zero-terminated strings */ + Kpadding, /* padding */ + Kpaddalign, /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ +} KOption; + + +/* +** Read an integer numeral from string 'fmt' or return 'df' if +** there is no numeral +*/ +static int digit(int c) { return '0' <= c && c <= '9'; } + +static int getnum(const char **fmt, int df) { + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a * 10 + (*((*fmt)++) - '0'); + } while (digit(**fmt) && a <= ((int)MAXSIZE - 9) / 10); + return a; + } +} + + +/* +** Read an integer numeral and raises an error if it is larger +** than the maximum size for integers. +*/ +static int getnumlimit(Header *h, const char **fmt, int df) { + int sz = getnum(fmt, df); + if (sz > MAXINTSIZE || sz <= 0) + luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; +} + + +/* +** Initialize Header +*/ +static void initheader(lua_State *L, Header *h) { + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; +} + + +/* +** Read and classify next option. 'size' is filled with option's size. +*/ +static KOption getoption(Header *h, const char **fmt, int *size) { + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) { + case 'b': *size = sizeof(char); return Kint; + case 'B': *size = sizeof(char); return Kuint; + case 'h': *size = sizeof(short); return Kint; + case 'H': *size = sizeof(short); return Kuint; + case 'l': *size = sizeof(long); return Kint; + case 'L': *size = sizeof(long); return Kuint; + case 'j': *size = sizeof(lua_Integer); return Kint; + case 'J': *size = sizeof(lua_Integer); return Kuint; + case 'T': *size = sizeof(size_t); return Kuint; + case 'f': *size = sizeof(float); return Kfloat; + case 'd': *size = sizeof(double); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Kfloat; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (*size == -1) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; break; + case '>': h->islittle = 0; break; + case '=': h->islittle = nativeendian.little; break; + case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; +} + + +/* +** Read, classify, and fill other details about the next option. +** 'psize' is filled with option's size, 'notoalign' with its +** alignment requirements. +** Local variable 'size' gets the size to be aligned. (Kpadal option +** always gets its full alignment, other options are limited by +** the maximum alignment ('maxalign'). Kchar option needs no alignment +** despite its size. +*/ +static KOption getdetails(Header *h, size_t totalsize, + const char **fmt, int *psize, int *ntoalign) { + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; +} + + +/* +** Pack integer 'n' with 'size' bytes and 'islittle' endianness. +** The final 'if' handles the case when 'size' is larger than +** the size of a Lua integer, correcting the extra sign-extension +** bytes if necessary (by default they would be zeros). +*/ +static void packint(lua_State *L, buffer_t *b, lua_Unsigned n, + int islittle, int size, int neg) { + char *buff = buffer_reserve(*b, size); + if (!buff) + luaL_error(L, "not enough memory for lbuffer allocation"); + + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) { /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + buffer_adjust_len(*b, size); /* add result to buffer */ +} + + +/* +** Copy 'size' bytes from 'src' to 'dest', correcting endianness if +** given 'islittle' is different from native endianness. +*/ +static void copywithendian(volatile char *dest, volatile const char *src, + int size, int islittle) { + if (islittle == nativeendian.little) { + while (size-- != 0) + *(dest++) = *(src++); + } + else { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } +} + + +static int lbuffer_pack(lua_State *L) { + Header h; + buffer_t* b = (buffer_t*)luaL_checkudata(L, 1, BUFFER_METATABLE); + if (!buffer_is_valid(*b)) + luaL_error(L, "invalid lbuffer to pack"); + const char *fmt = luaL_checkstring(L, 2); /* format string */ + int arg = 2; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + buffer_append_char(*b, LUA_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) { + case Kint: { /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) { /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(L, b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: { /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(L, b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: { /* floating-point options */ + volatile Ftypes u; + char *buff = buffer_reserve(*b, size); + lua_Number n = luaL_checknumber(L, arg); /* get argument */ + if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ + else if (size == sizeof(u.d)) u.d = (double)n; + else u.n = n; + /* move 'u' to final result, correcting endianness if needed */ + copywithendian(buff, u.buff, size, h.islittle); + buffer_adjust_len(*b, size); /* add result to buffer */ + break; + } + case Kchar: { /* fixed-size string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + if ((size_t)size <= len) /* string larger than (or equal to) needed? */ + buffer_append(*b, s, size); /* truncate string to asked size */ + else { /* string smaller than needed */ + buffer_append(*b, s, len); /* add it all */ + while (len++ < (size_t)size) /* pad extra space */ + buffer_append_char(*b, LUA_PACKPADBYTE); + } + break; + } + case Kstring: { /* strings with length count */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(L, b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + buffer_append(*b, s, len); + totalsize += len; + break; + } + case Kzstr: { /* zero-terminated string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + buffer_append(*b, s, len); + buffer_append_char(*b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: buffer_append_char(*b, LUA_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: case Knop: + arg--; /* undo increment */ + break; + } + } + return 0; +} + + +static int lbuffer_packsize(lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + switch (opt) { + case Kstring: /* strings with length count */ + case Kzstr: /* zero-terminated string */ + luaL_argerror(L, 1, "variable-length format"); + /* call never return, but to avoid warnings: *//* FALLTHROUGH */ + default: break; + } + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; +} + + +/* +** Unpack an integer with 'size' bytes and 'islittle' endianness. +** If size is smaller than the size of a Lua integer and integer +** is signed, must do sign extension (propagating the sign to the +** higher bits); if size is larger than the size of a Lua integer, +** it must check the unread bytes to see whether they do not cause an +** overflow. +*/ +static lua_Integer unpackint(lua_State *L, const char *str, + int islittle, int size, int issigned) { + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) { /* real size smaller than lua_Integer? */ + if (issigned) { /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) { /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) { + if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; +} + + +static int lbuffer_unpack(lua_State *L) { + Header h; + buffer_t* b = (buffer_t*)luaL_checkudata(L, 1, BUFFER_METATABLE); + if (!buffer_is_valid(*b)) + luaL_error(L, "invalid lbuffer to unpack"); + const char *fmt = luaL_checkstring(L, 2); /* format string */ + size_t ld = buffer_data_length(*b); + const char *data = buffer_data_ptr(*b); + size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) + luaL_argerror(L, 2, "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) { + case Kint: + case Kuint: { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: { + volatile Ftypes u; + lua_Number num; + copywithendian(u.buff, data + pos, size, h.islittle); + if (size == sizeof(u.f)) num = (lua_Number)u.f; + else if (size == sizeof(u.d)) num = (lua_Number)u.d; + else num = u.n; + lua_pushnumber(L, num); + break; + } + case Kchar: { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: { + size_t len = (int)strlen(data + pos); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: case Kpadding: case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + +/* }====================================================== */ + ///////////////////////////////////////////////////////////////////////////////////////////////////////// static luaL_Reg lbuffer[] = { { "new", lbuffer_new }, { "append", lbuffer_append }, + { "pack", lbuffer_pack }, + { "unpack", lbuffer_unpack }, + { "packsize", lbuffer_packsize }, { "split", lbuffer_split }, + { "remove", lbuffer_remove }, { "clear", lbuffer_clear }, { "length", lbuffer_length }, { "unfill", lbuffer_unfill }, From 164d1213c7403600fde7047df88c2844539cc255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Tue, 10 Oct 2017 18:12:07 +0800 Subject: [PATCH 143/173] fix warnings --- src/buffer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/buffer.cpp b/src/buffer.cpp index 94f5789..2827423 100644 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -258,11 +258,11 @@ buffer_t buffer_split(buffer_t& buffer_ref, size_t len) size_t buffer_remove(buffer_t& buffer_ref, size_t start, size_t len) { buffer_data_ptr_t buffer = buffer_ref.m_ptr; - if (buffer && len > 0 && buffer->m_len > start) { + if (buffer && len > 0 && (size_t)buffer->m_len > start) { int32_t remove_len = len < ((size_t)buffer->m_len - start) ? (int32_t)len : ((size_t)buffer->m_len - start); if (buffer->m_ref == 1) { buffer->m_len -= remove_len; - if (buffer->m_len > start) { + if ((size_t)buffer->m_len > start) { memcpy(buffer->m_data + start, buffer->m_data + start + remove_len, buffer->m_len - start); } buffer->m_data[buffer->m_len] = 0; @@ -275,7 +275,7 @@ size_t buffer_remove(buffer_t& buffer_ref, size_t start, size_t len) if (start > 0) { memcpy(nbuffer->m_data, buffer->m_data, start); } - if (nbuffer->m_len > start) { + if ((size_t)nbuffer->m_len > start) { memcpy(nbuffer->m_data + start, buffer->m_data + start + remove_len, nbuffer->m_len - start); } nbuffer->m_data[nbuffer->m_len] = 0; From 97eb294a47998b598070bf2cb67f65502c6d0982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Tue, 10 Oct 2017 20:30:49 +0800 Subject: [PATCH 144/173] =?UTF-8?q?=E5=AF=B9luaclib=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E7=9A=84=E5=8A=A8=E6=80=81=E5=BA=93=E6=8F=90=E4=BE=9B=E9=9D=99?= =?UTF-8?q?=E6=80=81=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/common/Makefile | 38 +++++++++++ luaclib/common/common.vcxproj | 91 +++++++++++++++++++++++++++ luaclib/common/common.vcxproj.filters | 18 ++++++ luaclib/luaclib.sln | 36 ++++++++++- 4 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 luaclib/common/Makefile create mode 100644 luaclib/common/common.vcxproj create mode 100644 luaclib/common/common.vcxproj.filters diff --git a/luaclib/common/Makefile b/luaclib/common/Makefile new file mode 100644 index 0000000..faadee2 --- /dev/null +++ b/luaclib/common/Makefile @@ -0,0 +1,38 @@ + +.PHONY: all clean +CC = g++ +RM = rm -rf +##PLATFORM ?= linux + +TARGET = libcommon.a +all: $(TARGET) + +## source file path +SRC_PATH := ../../src + +## used headers file path +INCLUDE_PATH := ../../src ../../deps/lua ../../deps/uv/include + +## define CFLAGS +CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -std=c++0x -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 + +ifeq (RELEASE,$(RELEASE)) +CFLAGS += -D RELEASE +endif + +## get all source files +SRCS += buffer.cpp + +## all .o based on all .cpp +OBJS := $(SRCS:.cpp=.o) + +## get all include path +CFLAGS += $(foreach dir, $(INCLUDE_PATH), -I$(dir)) +.cpp.o: + $(CC) -c $(CFLAGS) -o $@ $< + +$(TARGET): $(OBJS) + ar cr $@ $(OBJS) + +clean: + $(RM) *.o $(TARGET) diff --git a/luaclib/common/common.vcxproj b/luaclib/common/common.vcxproj new file mode 100644 index 0000000..786dd0f --- /dev/null +++ b/luaclib/common/common.vcxproj @@ -0,0 +1,91 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371} + common + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + $(ProjectDir) + $(ProjectName) + + + $(ProjectDir) + $(ProjectName) + + + + Level3 + Disabled + true + ..\..\src;..\..\deps\lua;..\..\deps\uv\include; + WIN32;_DEBUG;%(PreprocessorDefinitions) + + + true + + + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + + + + Level3 + MaxSpeed + true + true + true + ..\..\src;..\..\deps\lua;..\..\deps\uv\include; + + + true + true + true + + + copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + + + + + + + + + + + \ No newline at end of file diff --git a/luaclib/common/common.vcxproj.filters b/luaclib/common/common.vcxproj.filters new file mode 100644 index 0000000..3f5f9f9 --- /dev/null +++ b/luaclib/common/common.vcxproj.filters @@ -0,0 +1,18 @@ + + + + + {a2d77115-a008-4b21-97b7-dba07a17574c} + + + + + src + + + + + src + + + \ No newline at end of file diff --git a/luaclib/luaclib.sln b/luaclib/luaclib.sln index b7c7360..bac854d 100644 --- a/luaclib/luaclib.sln +++ b/luaclib/luaclib.sln @@ -11,34 +11,68 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lpeg", "lpeg\lpeg.vcxproj", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "mime\mime.vcxproj", "{2691C520-B01B-46AB-B585-716767F72A9F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pbc", "pb\pbc.vcxproj", "{EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protobuf", "pb\pbc.vcxproj", "{EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxproj", "{F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|ARM = Release|ARM Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {933BAD43-4B46-4BC1-A943-7825C5946B23}.Debug|ARM.ActiveCfg = Debug|Win32 {933BAD43-4B46-4BC1-A943-7825C5946B23}.Debug|Win32.ActiveCfg = Debug|Win32 {933BAD43-4B46-4BC1-A943-7825C5946B23}.Debug|Win32.Build.0 = Debug|Win32 + {933BAD43-4B46-4BC1-A943-7825C5946B23}.Debug|x64.ActiveCfg = Debug|Win32 + {933BAD43-4B46-4BC1-A943-7825C5946B23}.Release|ARM.ActiveCfg = Release|Win32 {933BAD43-4B46-4BC1-A943-7825C5946B23}.Release|Win32.ActiveCfg = Release|Win32 {933BAD43-4B46-4BC1-A943-7825C5946B23}.Release|Win32.Build.0 = Release|Win32 + {933BAD43-4B46-4BC1-A943-7825C5946B23}.Release|x64.ActiveCfg = Release|Win32 + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Debug|ARM.ActiveCfg = Debug|Win32 {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Debug|Win32.ActiveCfg = Debug|Win32 {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Debug|Win32.Build.0 = Debug|Win32 + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Debug|x64.ActiveCfg = Debug|Win32 + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Release|ARM.ActiveCfg = Release|Win32 {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Release|Win32.ActiveCfg = Release|Win32 {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Release|Win32.Build.0 = Release|Win32 + {BB87BCAD-A936-4A83-8A9C-1BCFE8B7393E}.Release|x64.ActiveCfg = Release|Win32 + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Debug|ARM.ActiveCfg = Debug|Win32 {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Debug|Win32.ActiveCfg = Debug|Win32 {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Debug|Win32.Build.0 = Debug|Win32 + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Debug|x64.ActiveCfg = Debug|Win32 + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Release|ARM.ActiveCfg = Release|Win32 {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Release|Win32.ActiveCfg = Release|Win32 {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Release|Win32.Build.0 = Release|Win32 + {3350DD32-C039-442E-94D5-DAB4E4A0A4C8}.Release|x64.ActiveCfg = Release|Win32 + {2691C520-B01B-46AB-B585-716767F72A9F}.Debug|ARM.ActiveCfg = Debug|Win32 {2691C520-B01B-46AB-B585-716767F72A9F}.Debug|Win32.ActiveCfg = Debug|Win32 {2691C520-B01B-46AB-B585-716767F72A9F}.Debug|Win32.Build.0 = Debug|Win32 + {2691C520-B01B-46AB-B585-716767F72A9F}.Debug|x64.ActiveCfg = Debug|Win32 + {2691C520-B01B-46AB-B585-716767F72A9F}.Release|ARM.ActiveCfg = Release|Win32 {2691C520-B01B-46AB-B585-716767F72A9F}.Release|Win32.ActiveCfg = Release|Win32 {2691C520-B01B-46AB-B585-716767F72A9F}.Release|Win32.Build.0 = Release|Win32 + {2691C520-B01B-46AB-B585-716767F72A9F}.Release|x64.ActiveCfg = Release|Win32 + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Debug|ARM.ActiveCfg = Debug|Win32 {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Debug|Win32.ActiveCfg = Debug|Win32 {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Debug|Win32.Build.0 = Debug|Win32 + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Debug|x64.ActiveCfg = Debug|Win32 + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Release|ARM.ActiveCfg = Release|Win32 {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Release|Win32.ActiveCfg = Release|Win32 {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Release|Win32.Build.0 = Release|Win32 + {EB20378F-8EE9-4DF1-9EE7-87BFB769F2FE}.Release|x64.ActiveCfg = Release|Win32 + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}.Debug|ARM.ActiveCfg = Debug|Win32 + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}.Debug|Win32.ActiveCfg = Debug|Win32 + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}.Debug|Win32.Build.0 = Debug|Win32 + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}.Debug|x64.ActiveCfg = Debug|Win32 + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}.Release|ARM.ActiveCfg = Release|Win32 + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}.Release|Win32.ActiveCfg = Release|Win32 + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}.Release|Win32.Build.0 = Release|Win32 + {F09D4DFA-1E4E-4D19-8FBD-95F602ACC371}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 7237ba10a8ebd3aec4dc10700f1610b78641ff51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Wed, 11 Oct 2017 00:33:19 +0800 Subject: [PATCH 145/173] a little thing --- src/lbuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lbuffer.cpp b/src/lbuffer.cpp index 40ec1a5..6115ec3 100644 --- a/src/lbuffer.cpp +++ b/src/lbuffer.cpp @@ -547,7 +547,7 @@ static int lbuffer_unpack(lua_State *L) { const char *data = buffer_data_ptr(*b); size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; int n = 0; /* number of results */ - luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + luaL_argcheck(L, pos <= ld, 3, "initial position out of lbuffer"); initheader(L, &h); while (*fmt != '\0') { int size, ntoalign; From 944aa9733a48df8c8e2a75def621ab4b0daa7d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Wed, 11 Oct 2017 18:19:18 +0800 Subject: [PATCH 146/173] a little thing --- luaclib/Makefile | 32 +++++++++++++++++--------------- luaclib/common/common.vcxproj | 6 ++++-- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/luaclib/Makefile b/luaclib/Makefile index 28d5bcb..18fa944 100644 --- a/luaclib/Makefile +++ b/luaclib/Makefile @@ -10,11 +10,12 @@ ROOT_PATH = $(shell pwd) define MAKE_PLATFORM ##not essential builds - cd mime && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) - cd cjson && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) - cd lfs && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) - cd lpeg && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) - cd pb && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd common && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd mime && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd cjson && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd lfs && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd lpeg && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) + cd pb && make PLATFORM=$(1) RELEASE=1; cd $(ROOT_PATH) endef all: @@ -22,16 +23,17 @@ all: clean: ##not essential builds - cd mime && make clean; cd $(ROOT_PATH) - cd cjson && make clean; cd $(ROOT_PATH) - cd lfs && make clean; cd $(ROOT_PATH) - cd lpeg && make clean; cd $(ROOT_PATH) - cd pb && make clean; cd $(ROOT_PATH) + cd common && make clean; cd $(ROOT_PATH) + cd mime && make clean; cd $(ROOT_PATH) + cd cjson && make clean; cd $(ROOT_PATH) + cd lfs && make clean; cd $(ROOT_PATH) + cd lpeg && make clean; cd $(ROOT_PATH) + cd pb && make clean; cd $(ROOT_PATH) install: ##not essential install - cp mime/mime.so mime.so - cp cjson/cjson.so cjson.so - cp lfs/lfs.so lfs.so - cp lpeg/lpeg.so lpeg.so - cp pb/protobuf.so protobuf.so + cp mime/mime.so mime.so + cp cjson/cjson.so cjson.so + cp lfs/lfs.so lfs.so + cp lpeg/lpeg.so lpeg.so + cp pb/protobuf.so protobuf.so diff --git a/luaclib/common/common.vcxproj b/luaclib/common/common.vcxproj index 786dd0f..bd88d80 100644 --- a/luaclib/common/common.vcxproj +++ b/luaclib/common/common.vcxproj @@ -58,7 +58,8 @@ true - copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + @@ -76,7 +77,8 @@ true - copy $(OutDir)$(TargetName)$(TargetExt) $(SolutionDir) + + From 52793154237ae3a37ed6ee16801e95cccae26cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sat, 21 Oct 2017 21:29:46 +0800 Subject: [PATCH 147/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96lbu?= =?UTF-8?q?ffer=E9=95=BF=E5=BA=A6=E7=9A=84metamethod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lbuffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lbuffer.cpp b/src/lbuffer.cpp index 6115ec3..e67eca3 100644 --- a/src/lbuffer.cpp +++ b/src/lbuffer.cpp @@ -623,6 +623,7 @@ static luaL_Reg lbuffer[] = { { "valid", lbuffer_valid }, { "release", lbuffer_release }, { "__gc", lbuffer_release }, + { "__len", lbuffer_length }, { "__tostring", lbuffer_tostring }, { NULL, NULL }, }; From 95b9d23f177b32b181bb4362f5995d4fa90d61ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 22 Oct 2017 22:13:05 +0800 Subject: [PATCH 148/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0pthread=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E9=80=89=E9=A1=B9=EF=BC=8C=E8=A7=A3=E5=86=B3=E6=9F=90?= =?UTF-8?q?=E4=BA=9B=E7=8E=AF=E5=A2=83=E7=BC=96=E8=AF=91=E4=B8=8D=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index a12d995..97e2496 100644 --- a/src/Makefile +++ b/src/Makefile @@ -47,7 +47,7 @@ LDFLAGS += -undefined dynamic_lookup \ endif ifeq (linux,$(PLATFORM)) -LIBS += dl rt +LIBS += dl rt pthread endif ifeq (freebsd,$(PLATFORM)) From d5fb22a51d7e42e2f4ed537c14398f298f997993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 22 Oct 2017 23:49:20 +0800 Subject: [PATCH 149/173] =?UTF-8?q?=E4=BF=AE=E6=94=B9common=E5=BA=93?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/common/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/luaclib/common/Makefile b/luaclib/common/Makefile index faadee2..9704f66 100644 --- a/luaclib/common/Makefile +++ b/luaclib/common/Makefile @@ -21,7 +21,7 @@ CFLAGS += -D RELEASE endif ## get all source files -SRCS += buffer.cpp +SRCS += $(SRC_PATH)/buffer.cpp ## all .o based on all .cpp OBJS := $(SRCS:.cpp=.o) From aca4cd42e0e137cb1c285e87beb48e8b7ffa59f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 23 Oct 2017 00:28:12 +0800 Subject: [PATCH 150/173] =?UTF-8?q?=E4=BF=AE=E6=94=B9common=E9=9D=99?= =?UTF-8?q?=E6=80=81=E5=BA=93=E7=9A=84makefile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/common/Makefile | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/luaclib/common/Makefile b/luaclib/common/Makefile index 9704f66..df210e0 100644 --- a/luaclib/common/Makefile +++ b/luaclib/common/Makefile @@ -20,17 +20,14 @@ ifeq (RELEASE,$(RELEASE)) CFLAGS += -D RELEASE endif -## get all source files -SRCS += $(SRC_PATH)/buffer.cpp - -## all .o based on all .cpp -OBJS := $(SRCS:.cpp=.o) - ## get all include path CFLAGS += $(foreach dir, $(INCLUDE_PATH), -I$(dir)) -.cpp.o: + +buffer.o : $(SRC_PATH)/buffer.cpp $(CC) -c $(CFLAGS) -o $@ $< +OBJS := buffer.o + $(TARGET): $(OBJS) ar cr $@ $(OBJS) From 409ec75da8d443459212003b5babf7228ce8f1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Tue, 24 Oct 2017 23:49:33 +0800 Subject: [PATCH 151/173] record a little thing --- node-lua.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/node-lua.lua b/node-lua.lua index 7f4868e..34c6a03 100644 --- a/node-lua.lua +++ b/node-lua.lua @@ -10,6 +10,8 @@ 25.如何支持数据共享,解决内存过大问题:提供共享api +26.热更新 + io 阻塞非阻塞? setvbuf {"__tostring", f_tostring}, From 9233edaed9523b14bfd4db8e900df4a5b661cc1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Thu, 26 Oct 2017 01:47:00 +0800 Subject: [PATCH 152/173] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=B8=A5=E9=87=8D?= =?UTF-8?q?=E5=86=85=E5=AD=98=E6=8B=B7=E8=B4=9D=E9=97=AE=E9=A2=98memcpy->m?= =?UTF-8?q?emmove?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/buffer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/buffer.cpp b/src/buffer.cpp index 2827423..5352240 100644 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -47,7 +47,7 @@ bool buffer_append(buffer_t& buffer_ref, const char *data, size_t data_len) { if (buffer && data) { if (buffer->m_ref == 1) { if (data_len <= (size_t)(buffer->m_cap - buffer->m_len)) { - memcpy(buffer->m_data + buffer->m_len, data, data_len); + memmove(buffer->m_data + buffer->m_len, data, data_len); buffer->m_len += data_len; buffer->m_data[buffer->m_len] = 0; return true; @@ -62,7 +62,7 @@ bool buffer_append(buffer_t& buffer_ref, const char *data, size_t data_len) { if (new_buffer) { if (offset >= 0) data = (char*)new_buffer + offset; new_buffer->m_cap = new_cap; - memcpy(new_buffer->m_data + new_buffer->m_len, data, data_len); + memmove(new_buffer->m_data + new_buffer->m_len, data, data_len); new_buffer->m_len += data_len; new_buffer->m_data[new_buffer->m_len] = 0; buffer_ref.m_ptr = new_buffer; @@ -237,7 +237,7 @@ buffer_t buffer_split(buffer_t& buffer_ref, size_t len) if (buffer->m_ref == 1) { buffer->m_len -= split_len; if (buffer->m_len > 0) { - memcpy(buffer->m_data, buffer->m_data + split_len, buffer->m_len); + memmove(buffer->m_data, buffer->m_data + split_len, buffer->m_len); } buffer->m_data[buffer->m_len] = 0; } else { @@ -263,7 +263,7 @@ size_t buffer_remove(buffer_t& buffer_ref, size_t start, size_t len) if (buffer->m_ref == 1) { buffer->m_len -= remove_len; if ((size_t)buffer->m_len > start) { - memcpy(buffer->m_data + start, buffer->m_data + start + remove_len, buffer->m_len - start); + memmove(buffer->m_data + start, buffer->m_data + start + remove_len, buffer->m_len - start); } buffer->m_data[buffer->m_len] = 0; } else { From da4d9a7c1cceccd820de2aba06ef34ad8e6927a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Thu, 26 Oct 2017 02:41:57 +0800 Subject: [PATCH 153/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20LUA=5FTNONE=20?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 2 +- src/lbuffer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 9315798..56c543a 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -915,7 +915,7 @@ int32_t context_lua_t::context_destroy(lua_State *L) { int32_t type = lua_type(L, 1); uint32_t src_handle = lua_get_context_handle(L); - if (type == LUA_TNIL || type == LUA_TSTRING) { //kill self + if (type == LUA_TNONE || type == LUA_TNIL || type == LUA_TSTRING) { //kill self singleton_ref(node_lua_t).context_destroy(src_handle, src_handle, lua_tostring(L, 1)); return 0; } diff --git a/src/lbuffer.cpp b/src/lbuffer.cpp index e67eca3..455d4e3 100644 --- a/src/lbuffer.cpp +++ b/src/lbuffer.cpp @@ -14,7 +14,7 @@ static int32_t lbuffer_new(lua_State* L) } else if (type == LUA_TSTRING) { init = lua_tolstring(L, 1, &init_len); cap = init_len + DEFAULT_BUFFER_CAPACITY; - } else if (type != LUA_TNIL) { + } else if (type != LUA_TNIL && type != LUA_TNONE) { buffer_t* buffer = (buffer_t*)luaL_testudata(L, 1, BUFFER_METATABLE); if (!buffer) { luaL_argerror(L, 1, "unexpected argument type"); From 045935e7f3c72cbe1df9dd1f8dd07e485e84b3ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 12 Nov 2017 20:24:06 +0800 Subject: [PATCH 154/173] =?UTF-8?q?tcp.listen=E5=A2=9E=E5=8A=A0reuseport?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- deps/lua/latomic.h | 8 +++++--- src/common.h | 8 +++++++- src/errors.h | 1 + src/ltpack.cpp | 2 +- src/lua_tcp_handle.cpp | 6 +++--- src/network.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/network.h | 1 + src/request.h | 2 +- src/utils.cpp | 8 ++++---- src/uv_tcp_handle.cpp | 16 +++++++++++++++- 11 files changed, 78 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5c79b75..af8f40a 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** ### tcp api -1. result, listen_socket = **tcp.listen**(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) +1. result, listen_socket = **tcp.listen**(addr, port[, reuse, [listen_callback(result, listen_socket, addr, port[, reuse])]]) *`--listen on a ipv4 address.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* @@ -88,7 +88,7 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** *`--listen on a windows named pipe or unix domain socket.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* -3. result, listen_socket = **tcp.listen6**(addr, port[, backlog, [listen_callback(result, listen_socket, addr, port[, backlog])]]) +3. result, listen_socket = **tcp.listen6**(addr, port[, reuse, [listen_callback(result, listen_socket, addr, port[, reuse])]]) *`--listen on a ipv6 address.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* diff --git a/deps/lua/latomic.h b/deps/lua/latomic.h index d9e0467..2d75f6c 100644 --- a/deps/lua/latomic.h +++ b/deps/lua/latomic.h @@ -16,10 +16,12 @@ ((__GNUC_MINOR__ > (minor)) || ((__GNUC_MINOR__ == (minor)) && \ (__GNUC_PATCHLEVEL__ >= (patch)) ) ) ) ) -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(WINCE) || defined(_WIN32_WCE) -# define CC_MSVC +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(WINCE) || defined(_WIN32_WCE) || defined(_WIN64) +#ifndef CC_MSVC +#define CC_MSVC +#endif #elif CHECK_GNUC(4, 1, 2) /* >= 4.1.2 */ -# define CC_GNUC +#define CC_GNUC #else # error "This Compiler is unsupported!" #endif diff --git a/src/common.h b/src/common.h index da4523d..1716ba2 100644 --- a/src/common.h +++ b/src/common.h @@ -6,7 +6,13 @@ #include #include "config.h" -#ifdef WIN32 +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(WINCE) || defined(_WIN32_WCE) || defined(_WIN64) +#ifndef CC_MSVC +#define CC_MSVC +#endif +#endif + +#ifdef CC_MSVC #define FORCE_INLINE __forceinline #else #define FORCE_INLINE inline diff --git a/src/errors.h b/src/errors.h index f57ad12..ea6e03f 100644 --- a/src/errors.h +++ b/src/errors.h @@ -19,6 +19,7 @@ XX( 211, ETRANSTYPE, "transfer data type not supported") \ XX( 212, ENOREPLY, "no reply") \ XX( 213, ETIMEOUT, "timeout") \ + XX( 214, ESOCKFAIL, "socket create failed") \ #define NL_ERRNO_GEN(val, name, s) NL_##name = val, typedef enum { diff --git a/src/ltpack.cpp b/src/ltpack.cpp index 52cec6b..13a70dd 100644 --- a/src/ltpack.cpp +++ b/src/ltpack.cpp @@ -1,6 +1,6 @@ #define __STDC_LIMIT_MACROS #include "ltpack.h" -#ifndef _WIN32 +#ifndef CC_MSVC #include #endif diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 8412412..82af4f5 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -87,14 +87,14 @@ int32_t lua_tcp_listen_handle_t::_listen(lua_State* L, bool ipv6) luaL_argerror(L, 1, "listen host invalid(too long)"); } uint16_t port = luaL_checkunsigned(L, 2); - uint16_t backlog = (uint16_t)-1; + bool reuse = false; int32_t top = lua_gettop(L); int32_t callback = 0; if (top >= 3) { if (lua_isfunction(L, 3)) { callback = 3; } else { - backlog = luaL_checkunsigned(L, 3); + reuse = lua_toboolean(L, 3); if (top >= 4) { luaL_checktype(L, 4, LUA_TFUNCTION); callback = 4; @@ -106,7 +106,7 @@ int32_t lua_tcp_listen_handle_t::_listen(lua_State* L, bool ipv6) request.m_type = REQUEST_TCP_LISTEN; request.m_length = REQUEST_SIZE(request_tcp_listen_t, host_len + 1); request.m_tcp_listen.m_source = lctx->get_handle(); - request.m_tcp_listen.m_backlog = backlog; + request.m_tcp_listen.m_reuse = reuse; request.m_tcp_listen.m_port = port; request.m_tcp_listen.m_ipv6 = ipv6; memcpy(REQUEST_SPARE_PTR(request.m_tcp_listen), host, host_len + 1); diff --git a/src/network.cpp b/src/network.cpp index 442a632..0b1f294 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -343,6 +343,44 @@ int network_t::make_socketpair( uv_os_sock_t *r_, uv_os_sock_t *w_ ) #endif } +#ifdef CC_MSVC +int network_t::make_tcp_socket(uv_os_sock_t *sock, bool ipv6, bool reuseport) +{ + *sock = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_IP); + if (*sock != INVALID_SOCKET) { + if (reuseport) { + DWORD yes = 1; + if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof yes) == SOCKET_ERROR) { + close_socket(*sock); + *sock = INVALID_SOCKET; + return -1; + } + } + return 0; + } + return -1; +} +#else +extern int uv__socket(int domain, int type, int protocol); + +int network_t::make_tcp_socket(uv_os_sock_t *sock, bool reuseport) +{ + *sock = uv__socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_IP); + if (*sock >= 0) { + if (reuseport) { + int yes = 1; + if (setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) != 0) { + close_socket(*sock); + sock = -1; + return -1; + } + } + return 0; + } + return -1; +} +#endif + int network_t::set_noneblocking( uv_os_sock_t sock ) { #if defined CC_MSVC diff --git a/src/network.h b/src/network.h index 39bb706..e3380cf 100644 --- a/src/network.h +++ b/src/network.h @@ -40,6 +40,7 @@ class network_t : public singleton_t { public: static int make_socketpair(uv_os_sock_t *r, uv_os_sock_t *w); static int close_socketpair(uv_os_sock_t *r, uv_os_sock_t *w); + static int make_tcp_socket(uv_os_sock_t *sock, bool ipv6, bool reuseport); static int set_noneblocking(uv_os_sock_t sock); static int close_socket(uv_os_sock_t sock); public: diff --git a/src/request.h b/src/request.h index 6a318c6..f37be24 100644 --- a/src/request.h +++ b/src/request.h @@ -42,9 +42,9 @@ struct request_exit_t { struct request_tcp_listen_t { uint32_t m_source; uint32_t m_session; - uint16_t m_backlog; uint16_t m_port; bool m_ipv6; + bool m_reuse; REQUEST_SPARE_REGION }; diff --git a/src/utils.cpp b/src/utils.cpp index 4404cd0..beeb18a 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,6 +1,6 @@ #include "common.h" #include "utils.h" -#ifndef _WIN32 +#ifndef CC_MSVC #include #endif @@ -55,7 +55,7 @@ bool socket_host(uv_os_sock_t sock, bool local, char* host, uint32_t host_len, b sockaddr_in6 sock6; } sock_name; int sock_len = sizeof(sock_name); -#ifdef _WIN32 +#ifdef CC_MSVC int result = local ? getsockname(sock, (sockaddr*)&sock_name, &sock_len) : getpeername(sock, (sockaddr*)&sock_name, &sock_len); #else int result = local ? getsockname(sock, (sockaddr*)&sock_name, (socklen_t*)&sock_len) : getpeername(sock, (sockaddr*)&sock_name, (socklen_t*)&sock_len); @@ -137,9 +137,9 @@ uv_err_code host_sockaddr(bool ipv6, const char* host, uint16_t port, struct soc } } -extern int get_pid() +int get_pid() { -#ifdef _WIN32 +#ifdef CC_MSVC return GetCurrentProcessId(); #else return getpid(); diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 7dba8f7..0ad9bf2 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -32,7 +32,21 @@ void uv_tcp_listen_handle_t::listen_tcp(request_tcp_listen_t& request) #ifdef CC_MSVC uv_tcp_simultaneous_accepts(server, 0); #endif - if ((!request.m_ipv6 ? uv_tcp_bind(server, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port)) == 0 : uv_tcp_bind6(server, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port)) == 0) && uv_listen((uv_stream_t*)server, request.m_backlog, on_accept) == 0) { + + uv_os_sock_t sock; + if (network_t::make_tcp_socket(&sock, request.m_ipv6, request.m_reuse)) { + singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_LISTEN, NL_ESOCKFAIL); + uv_close((uv_handle_t*)server, on_closed); + return; + } + if (uv_tcp_open(server, sock)) { + network_t::close_socket(sock); + singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_LISTEN, singleton_ref(network_t).last_error()); + uv_close((uv_handle_t*)server, on_closed); + return; + } + + if ((!request.m_ipv6 ? uv_tcp_bind(server, uv_ip4_addr(REQUEST_SPARE_PTR(request), request.m_port)) == 0 : uv_tcp_bind6(server, uv_ip6_addr(REQUEST_SPARE_PTR(request), request.m_port)) == 0) && uv_listen((uv_stream_t*)server, 0x7fffffff, on_accept) == 0) { if (!singleton_ref(node_lua_t).context_send(request.m_source, 0, request.m_session, RESPONSE_TCP_LISTEN, (void*)this)) { uv_close((uv_handle_t*)server, on_closed); } From 2fa0ee2e595c550e853c1d9934ed25c224309307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 12 Nov 2017 20:58:33 +0800 Subject: [PATCH 155/173] =?UTF-8?q?=E8=A7=A3=E5=86=B3linux=E4=B8=8Buv=5F?= =?UTF-8?q?=5Fsocket=E9=93=BE=E6=8E=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/network.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/network.cpp b/src/network.cpp index 0b1f294..054ee64 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -361,9 +361,11 @@ int network_t::make_tcp_socket(uv_os_sock_t *sock, bool ipv6, bool reuseport) return -1; } #else -extern int uv__socket(int domain, int type, int protocol); +extern "C" { + extern int uv__socket(int domain, int type, int protocol); +} -int network_t::make_tcp_socket(uv_os_sock_t *sock, bool reuseport) +int network_t::make_tcp_socket(uv_os_sock_t *sock, bool ipv6, bool reuseport) { *sock = uv__socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_IP); if (*sock >= 0) { @@ -371,7 +373,7 @@ int network_t::make_tcp_socket(uv_os_sock_t *sock, bool reuseport) int yes = 1; if (setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) != 0) { close_socket(*sock); - sock = -1; + *sock = -1; return -1; } } From a925fde63ecc2f3bed46dead36559fbc456db835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 12 Nov 2017 21:34:06 +0800 Subject: [PATCH 156/173] =?UTF-8?q?=E6=8F=90=E4=BE=9Btcp.listen=20reuse?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=A7=A3=E9=87=8A=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index af8f40a..9e4a4ea 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,9 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** 1. result, listen_socket = **tcp.listen**(addr, port[, reuse, [listen_callback(result, listen_socket, addr, port[, reuse])]]) *`--listen on a ipv4 address.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* + *`--reuse option allows you to listen on the same specified port.`* + *`--If you are listening on the same port among several sockets at unix system, you will accept the connecting socket in round-robin sequence among all the listening sockets.`* + *`--If you are listening on the same port among several sockets at windows system, you will most likely accept the connecting socket at the first listening socket!`* 2. result, listen_socket = **tcp.listens**(sock_name[, listen_callback(result, listen_socket, sock_name)]) *`--listen on a windows named pipe or unix domain socket.`* @@ -91,6 +94,9 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** 3. result, listen_socket = **tcp.listen6**(addr, port[, reuse, [listen_callback(result, listen_socket, addr, port[, reuse])]]) *`--listen on a ipv6 address.`* *`--listen_callback is a once callback, blocking if listen_callback is nil.`* + *`--reuse option allows you to listen on the same specified port.`* + *`--If you are listening on the same port among several sockets at unix system, you will accept the connecting socket in round-robin sequence among all the listening sockets.`* + *`--If you are listening on the same port among several sockets at windows system, you will most likely accept the connecting socket at the first listening socket!`* 4. result, accept_socket = **tcp.accept**(listen_socket[, timeout]) *`--accept on a listen socket in blocking mode, timeout is activated if timeout is set.`* From b99a9d4d3c3a0ca72bcb2233d40b473a28405642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 12 Nov 2017 22:27:54 +0800 Subject: [PATCH 157/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=80=9A=E8=BF=87fd?= =?UTF-8?q?=E8=8E=B7=E5=8F=96source=20context=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/handle_base_def.h | 1 + src/lua_tcp_handle.cpp | 8 ++++++++ src/lua_udp_handle.cpp | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/src/handle_base_def.h b/src/handle_base_def.h index 0a51c7e..0dc91a6 100644 --- a/src/handle_base_def.h +++ b/src/handle_base_def.h @@ -9,5 +9,6 @@ typedef enum } handle_set; #define SOCKET_MAKE_FD(lua_ref, context_id) ((int64_t)(lua_ref)%1000000 + 1000000*(int64_t)(context_id)) +#define SOCKET_FD_SOURCE(fd) ((int64_t)(fd)/1000000) #endif \ No newline at end of file diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 82af4f5..2b48f78 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -56,6 +56,13 @@ static int32_t lua_tcp_get_fd(lua_State* L) return 0; } +static int32_t lua_tcp_fd_src(lua_State* L) +{ + int64_t fd = luaL_checkinteger(L, 1); + lua_pushinteger(L, SOCKET_FD_SOURCE(fd)); + return 1; +} + ///////////////////////////////////////////////////////////////////////////////////////////////////////// lua_tcp_listen_handle_t* lua_tcp_listen_handle_t::create_tcp_listen_socket(uv_tcp_listen_handle_t* handle, lua_State* L) @@ -1123,6 +1130,7 @@ int luaopen_tcp(lua_State *L) { "close", lua_tcp_close }, { "is_closed", lua_tcp_is_closed }, { "fd", lua_tcp_get_fd }, + { "fd_src", lua_tcp_fd_src }, { NULL, NULL }, }; luaL_newlib(L, l); diff --git a/src/lua_udp_handle.cpp b/src/lua_udp_handle.cpp index 1dc1c88..c9ec9b9 100644 --- a/src/lua_udp_handle.cpp +++ b/src/lua_udp_handle.cpp @@ -423,6 +423,13 @@ int32_t lua_udp_handle_t::wakeup_read(lua_State* L, message_t& message) return 0; } +static int32_t lua_udp_fd_src(lua_State* L) +{ + int64_t fd = luaL_checkinteger(L, 1); + lua_pushinteger(L, SOCKET_FD_SOURCE(fd)); + return 1; +} + int luaopen_udp(lua_State *L) { luaL_Reg l[] = { @@ -439,6 +446,7 @@ int luaopen_udp(lua_State *L) { "close", lua_udp_handle_t::close }, { "is_closed", lua_udp_handle_t::udp_is_closed }, { "fd", lua_udp_handle_t::get_fd }, + { "fd_src", lua_udp_fd_src }, { NULL, NULL }, }; luaL_newlib(L, l); From 9b0895df2d3886afa5ab594da5f14e1659fe33ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 12 Nov 2017 22:47:26 +0800 Subject: [PATCH 158/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96soc?= =?UTF-8?q?ket=5Ffd=E6=9D=A5=E6=BA=90contextId=E7=9A=84api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 9e4a4ea..f1718ef 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,9 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** 22. fd = **tcp.fd**(socket) *`--get tcp socket lua fd`* + +23. context_id = **tcp.fd_src**(fd) + *`--get socket fd source context id`* ### udp api @@ -205,6 +208,9 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** 15. fd = **udp.fd**(socket) *`--get udp socket lua fd`* + +16. context_id = **udp.fd_src**(fd) + *`--get socket fd source context id`* ### timer api From a027bbf9d073bc50987d6aa5b2ba0475278ceeca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 13 Nov 2017 23:24:21 +0800 Subject: [PATCH 159/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96cpu?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 29 ++++++++++++++++------------- src/context_lua.cpp | 2 ++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f1718ef..fcc2e08 100644 --- a/README.md +++ b/README.md @@ -32,50 +32,53 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** 3. **context.winos** *`--whether the running system is windows.`* + +4. **context.ncpu** + *`--number of cpu.`* -4. handle = **context.create**(file_name[, arg1[, ...]]) +5. handle = **context.create**(file_name[, arg1[, ...]]) *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* -5. handle = **context.destroy**([handle[, message]]) +6. handle = **context.destroy**([handle[, message]]) *`--destroy a context specified by handle with a string message. You'll kill the context itself if handle is nil and message is a optional argument.`* -6. result, error = **context.send**(handle, data1[, ...]) +7. result, error = **context.send**(handle, data1[, ...]) *`--send data1, data2, ... directy to context specified by handle noblocking.`* -7. result, query_data1, ... = **context.query**(handle, data1[, ... [, query_callback(result, query_data1[, ...])]]) +8. result, query_data1, ... = **context.query**(handle, data1[, ... [, query_callback(result, query_data1[, ...])]]) *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* *`--query_callback is a once callback, blocking if query_callback is nil.`* -8. result, query_data1, ... = **context.timed_query**(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]]) +9. result, query_data1, ... = **context.timed_query**(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]]) *`--query context specified by handle with data1, data2, ... in timeout seconds`* *`--query_callback is a once callback, blocking if query_callback is nil.`* -9. result, error = **context.reply**(handle, session, data1[, ...]) +10. result, error = **context.reply**(handle, session, data1[, ...]) *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* -10. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, timeout]) +11. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, timeout]) *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* -11. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)]) +12. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)]) *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* -12. result, error = **context.wait**(handle[, timeout[, callback(result, error, handle[, timeout])]]) +13. result, error = **context.wait**(handle[, timeout[, callback(result, error, handle[, timeout])]]) *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* *`--callback is a once callback, blocking if callback is nil.`* -13. result, error = **context.log**(...) +14. result, error = **context.log**(...) *`--almost equivalent to print except the output won't be disordered(node-lua runs in a muti-thread mode).`* -14. error = **context.strerror**(errno) +15. error = **context.strerror**(errno) *`--convert error number to error string. Error number is always the next argument after result in most apis.`* -15. thread = **context.thread**() +16. thread = **context.thread**() *`--return the running thread index.`* -16. **context.run**(func[, ...]) +17. **context.run**(func[, ...]) *`--run the func(...) at next tick(in other words next processing period).`* ### tcp api diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 56c543a..96592db 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -1398,6 +1398,8 @@ int luaopen_context(lua_State *L) lua_setfield(L, -2, "self"); lua_pushinteger(L, lctx->get_parent()); lua_setfield(L, -2, "parent"); + lua_pushinteger(L, node_lua_t::m_cpu_count); + lua_setfield(L, -2, "ncpu"); return 1; } From e2ef9905a430720ad2f61b9277cfb906b5be2a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Wed, 20 Dec 2017 00:39:59 +0800 Subject: [PATCH 160/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=90=8D=E5=AD=97=E7=9A=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加获取服务名字的接口 --- README.md | 35 +++++++++++++++++++---------------- src/context_lua.cpp | 15 +++++++++++++-- src/context_lua.h | 6 ++++++ 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index fcc2e08..b915022 100644 --- a/README.md +++ b/README.md @@ -26,59 +26,62 @@ Contact with **Email: xdczju@sina.com** or **QQ: 443231647** ### context api 1. **context.self** *`--the running context id.`* + +2. **context.name** + *`--the running context full name with all args.`* -2. **context.parent** +3. **context.parent** *`--the running context parent id.`* -3. **context.winos** +4. **context.winos** *`--whether the running system is windows.`* -4. **context.ncpu** +5. **context.ncpu** *`--number of cpu.`* -5. handle = **context.create**(file_name[, arg1[, ...]]) +6. handle = **context.create**(file_name[, arg1[, ...]]) *`--create a new context with file_name as the context entry. arg1, arg2, ... will be the argument for the context.`* -6. handle = **context.destroy**([handle[, message]]) +7. handle = **context.destroy**([handle[, message]]) *`--destroy a context specified by handle with a string message. You'll kill the context itself if handle is nil and message is a optional argument.`* -7. result, error = **context.send**(handle, data1[, ...]) +8. result, error = **context.send**(handle, data1[, ...]) *`--send data1, data2, ... directy to context specified by handle noblocking.`* -8. result, query_data1, ... = **context.query**(handle, data1[, ... [, query_callback(result, query_data1[, ...])]]) +9. result, query_data1, ... = **context.query**(handle, data1[, ... [, query_callback(result, query_data1[, ...])]]) *`--query context specified by handle with data1, data2, ... and query_data1, query_data2, ... is the queried datas.`* *`--query_callback is a once callback, blocking if query_callback is nil.`* -9. result, query_data1, ... = **context.timed_query**(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]]) +10. result, query_data1, ... = **context.timed_query**(handle, timeout, data1[, ... [, query_callback(result, query_data1[, ...])]]) *`--query context specified by handle with data1, data2, ... in timeout seconds`* *`--query_callback is a once callback, blocking if query_callback is nil.`* -10. result, error = **context.reply**(handle, session, data1[, ...]) +11. result, error = **context.reply**(handle, session, data1[, ...]) *`--reply session(received by context.recv) context specified by handle with data1, data2, ...`* -11. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, timeout]) +12. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, timeout]) *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* -12. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)]) +13. result, recv_handle, session, recv_data1, ... = **context.recv**(handle[, recv_callback(result, recv_handle, session, recv_data1, ...)]) *`--receive data from context specified by handle(receive data from all contexts if handle equals 0).`* *`--recv_handle specifies the source context id. It's a query action if session >= 0, where you'd better reply this query action.`* *`--recv_callback is a continues callback, blocking if recv_callback is nil.`* -13. result, error = **context.wait**(handle[, timeout[, callback(result, error, handle[, timeout])]]) +14. result, error = **context.wait**(handle[, timeout[, callback(result, error, handle[, timeout])]]) *`--wait context to quit or to be destroyed in blocking or nonblocking mode.`* *`--callback is a once callback, blocking if callback is nil.`* -14. result, error = **context.log**(...) +15. result, error = **context.log**(...) *`--almost equivalent to print except the output won't be disordered(node-lua runs in a muti-thread mode).`* -15. error = **context.strerror**(errno) +16. error = **context.strerror**(errno) *`--convert error number to error string. Error number is always the next argument after result in most apis.`* -16. thread = **context.thread**() +17. thread = **context.thread**() *`--return the running thread index.`* -17. **context.run**(func[, ...]) +18. **context.run**(func[, ...]) *`--run the func(...) at next tick(in other words next processing period).`* ### tcp api diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 96592db..cbc7989 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -17,7 +17,8 @@ char context_lua_t::m_ref_session_table_key = 0; char context_lua_t::m_ref_timer_table_key = 0; context_lua_t::context_lua_t() - : m_lstate(NULL), + : m_name(NULL), + m_lstate(NULL), m_ref_session_count(0), m_ref_session_base(INT_MAX) { @@ -29,6 +30,10 @@ context_lua_t::~context_lua_t() lua_close(m_lstate); m_lstate = NULL; } + if (m_name) { + nl_free((void*)m_name); + m_name = NULL; + } } bool context_lua_t::init(int32_t argc, char* argv[], char* env[]) @@ -70,8 +75,8 @@ bool context_lua_t::init(int32_t argc, char* argv[], char* env[]) argp += lengths[i]; *argp++ = (i != argc - 1) ? ' ' : '\0'; } + m_name = args; singleton_ref(node_lua_t).log_fmt(m_handle, "[alert] context:0x%08x init: %s", m_handle, args); - nl_free(args); return singleton_ref(node_lua_t).context_send(this, m_handle, 0, LUA_CTX_INIT, (int64_t)argc); } @@ -85,6 +90,10 @@ bool context_lua_t::deinit(const char *arg) lua_close(m_lstate); m_lstate = NULL; } + if (m_name) { + nl_free((void*)m_name); + m_name = NULL; + } singleton_ref(node_lua_t).log_fmt(m_handle, "[alert] context:0x%08x deinit: %s", m_handle, arg); return true; } @@ -1396,6 +1405,8 @@ int luaopen_context(lua_State *L) context_lua_t* lctx = context_lua_t::lua_get_context(L); lua_pushinteger(L, lctx->get_handle()); lua_setfield(L, -2, "self"); + lua_pushstring(L, lctx->get_name()); + lua_setfield(L, -2, "name"); lua_pushinteger(L, lctx->get_parent()); lua_setfield(L, -2, "parent"); lua_pushinteger(L, node_lua_t::m_cpu_count); diff --git a/src/context_lua.h b/src/context_lua.h index 8c8fb5f..55bfb20 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -35,6 +35,7 @@ class context_lua_t : public context_t { void on_worker_attached(); void on_worker_detached(); + const char* get_name() const { return m_name; } bool is_active() const { return m_ref_session_count > 0; } uint32_t yielding_up() { return (m_shared->m_yielding_depth) ? ++m_shared->m_yielding_depth : 0; } request_t& get_yielding_request() const { return m_shared->m_yielding_request; } @@ -48,6 +49,11 @@ class context_lua_t : public context_t { context_lua_t(const context_lua_t& lctx); context_lua_t& operator=(const context_lua_t& lctx); + /* @m_name + ** The lua context name. + */ + const char *m_name; + /* @m_lstate ** The main lvm where the lua context is running. */ From ffdcb6814b6baba532a123b424e3f216c01f8e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 31 Dec 2017 00:28:06 +0800 Subject: [PATCH 161/173] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=B7=A8context?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=86=85=E5=AD=98=E5=AF=B9=E8=B1=A1=E5=85=B1?= =?UTF-8?q?=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. message_t增加shared_t*类型支持,支持跨context服务内存对象共享; 2. 统一luaL_Reg的static const修饰; 3. metatable类型统一为 "class typename",与c++ typeid返回类型名称保持一致; --- node-lua.vcxproj | 2 ++ node-lua.vcxproj.filters | 6 +++++ src/context_lua.cpp | 31 ++++++++++++++++------ src/lbuffer.cpp | 2 +- src/lbuffer.h | 2 +- src/lshared.cpp | 55 ++++++++++++++++++++++++++++++++++++++++ src/lshared.h | 46 +++++++++++++++++++++++++++++++++ src/lua_tcp_handle.cpp | 6 ++--- src/lua_timer_handle.cpp | 4 +-- src/lua_udp_handle.cpp | 4 +-- src/message.h | 22 ++++++++++++---- src/node_lua.h | 2 +- 12 files changed, 159 insertions(+), 23 deletions(-) create mode 100644 src/lshared.cpp create mode 100644 src/lshared.h diff --git a/node-lua.vcxproj b/node-lua.vcxproj index e1e26d0..39c3410 100644 --- a/node-lua.vcxproj +++ b/node-lua.vcxproj @@ -106,6 +106,7 @@ + @@ -141,6 +142,7 @@ + diff --git a/node-lua.vcxproj.filters b/node-lua.vcxproj.filters index d897d0e..f8f1a9d 100644 --- a/node-lua.vcxproj.filters +++ b/node-lua.vcxproj.filters @@ -117,6 +117,9 @@ include + + include + @@ -206,5 +209,8 @@ src + + src + \ No newline at end of file diff --git a/src/context_lua.cpp b/src/context_lua.cpp index cbc7989..fdb0a7a 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "utils.h" #include "lbuffer.h" +#include "lshared.h" #include "context.h" #include "context_lua.h" #include "node_lua.h" @@ -938,7 +939,7 @@ int32_t context_lua_t::context_destroy(lua_State *L) int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t msg_type, message_t& message) { - buffer_t* buffer; + void* udata; const char* data; size_t length; switch (lua_type(L, idx)) { @@ -968,12 +969,26 @@ int32_t context_lua_t::context_check_message(lua_State *L, int32_t idx, uint32_t message.m_source = lua_get_context_handle(L); return 1; case LUA_TUSERDATA: - buffer = (buffer_t*)luaL_testudata(L, idx, BUFFER_METATABLE); - if (buffer) { - message.m_type = MAKE_MESSAGE_TYPE(msg_type, BUFFER); - message.m_data.m_buffer = buffer_grab(*buffer); - message.m_source = lua_get_context_handle(L); - return 1; + udata = lua_touserdata(L, idx); + if (lua_getmetatable(L, idx)) { /* does it have a metatable? */ + luaL_getmetatable(L, BUFFER_METATABLE); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* not the same? */ + lua_pop(L, 2); /* remove both metatables */ + message.m_type = MAKE_MESSAGE_TYPE(msg_type, BUFFER); + message.m_data.m_buffer = buffer_grab(*((buffer_t*)udata)); + message.m_source = lua_get_context_handle(L); + return 1; + } + lua_pop(L, 1); /* remove BUFFER_METATABLE */ + luaL_getmetatable(L, SHARED_METATABLE); /* get correct metatable */ + if (lua_rawequal(L, -1, -2)) { /* not the same? */ + lua_pop(L, 2); /* remove both metatables */ + message.m_type = MAKE_MESSAGE_TYPE(msg_type, SHARED); + message.m_data.m_shared = *(shared_t**)udata ? (*(shared_t**)udata)->grab() : NULL; + message.m_source = lua_get_context_handle(L); + return 1; + } + lua_pop(L, 2); /* remove both metatables */ } lua_pushstring(L, "transfer data type not supported"); return 0; @@ -1380,7 +1395,7 @@ int32_t context_lua_t::context_run(lua_State *L) int luaopen_context(lua_State *L) { - luaL_Reg l[] = { + static const luaL_Reg l[] = { { "strerror", context_lua_t::context_strerror }, { "create", context_lua_t::context_create }, { "destroy", context_lua_t::context_destroy }, diff --git a/src/lbuffer.cpp b/src/lbuffer.cpp index 455d4e3..1211aca 100644 --- a/src/lbuffer.cpp +++ b/src/lbuffer.cpp @@ -607,7 +607,7 @@ static int lbuffer_unpack(lua_State *L) { ///////////////////////////////////////////////////////////////////////////////////////////////////////// -static luaL_Reg lbuffer[] = { +static const luaL_Reg lbuffer[] = { { "new", lbuffer_new }, { "append", lbuffer_append }, { "pack", lbuffer_pack }, diff --git a/src/lbuffer.h b/src/lbuffer.h index 61e43e3..cbf10fc 100644 --- a/src/lbuffer.h +++ b/src/lbuffer.h @@ -2,7 +2,7 @@ #define LBUFFER_H_ #include "buffer.h" -#define BUFFER_METATABLE "class.buffer_t" +#define BUFFER_METATABLE "class buffer_t" extern buffer_t* create_buffer(lua_State* L); extern buffer_t* create_buffer(lua_State* L, size_t cap, const char *init, size_t init_len); diff --git a/src/lshared.cpp b/src/lshared.cpp new file mode 100644 index 0000000..5d5bda4 --- /dev/null +++ b/src/lshared.cpp @@ -0,0 +1,55 @@ +#include "lshared.h" +#include + +int shared_t::meta_index(lua_State *L) +{ + shared_t** shared = (shared_t**)luaL_checkudata(L, 1, SHARED_METATABLE); + if (*shared && (*shared)->m_meta_reg && luaL_getmetatable(L, typeid(**shared).name()) != LUA_TNIL) { + lua_pushvalue(L, 2); + lua_rawget(L, -2); + return 1; + } + return 0; +} + +int shared_t::meta_gc(lua_State *L) +{ + shared_t** shared = (shared_t**)luaL_checkudata(L, 1, SHARED_METATABLE); + if (*shared) { + (*shared)->release(); + *shared = NULL; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +shared_t** shared_t::create_shared(lua_State* L) +{ + shared_t** ret = (shared_t**)lua_newuserdata(L, sizeof(shared_t*)); + *ret = NULL; + if (luaL_newmetatable(L, SHARED_METATABLE)) { /* create new metatable */ + lua_pushcclosure(L, meta_index, 0); + lua_setfield(L, -2, "__index"); + lua_pushcclosure(L, meta_gc, 0); + lua_setfield(L, -2, "__gc"); + } + lua_setmetatable(L, -2); + return ret; +} + +shared_t** shared_t::create_shared(lua_State* L, shared_t* shared) +{ + if (shared->m_meta_reg) { + if (luaL_newmetatable(L, typeid(*shared).name())) { /* create new metatable */ + luaL_setfuncs(L, shared->m_meta_reg, 0); + } + lua_pop(L, 1); + } + + shared_t** ret = create_shared(L); + shared->grab(); + *ret = shared; + return ret; +} + diff --git a/src/lshared.h b/src/lshared.h new file mode 100644 index 0000000..e71a28a --- /dev/null +++ b/src/lshared.h @@ -0,0 +1,46 @@ +#ifndef LSHARED_H_ +#define LSHARED_H_ +#include "common.h" + +#define SHARED_METATABLE "class shared_t" + +class shared_t { +public: + shared_t() : m_ref(1), m_meta_reg(NULL) {} + shared_t(const luaL_Reg reg[]) : m_ref(1), m_meta_reg(NULL) { + if (sizeof(reg) > 0) { + m_meta_reg = new luaL_Reg[ARRAY_SIZE(reg)]; + memcpy((void*)m_meta_reg, reg, sizeof(reg)); + } + } + + FORCE_INLINE shared_t* grab() { atomic_inc(m_ref); return this; } + FORCE_INLINE void release() { if (atomic_dec(m_ref) == 1) delete this; } + +protected: + shared_t(const shared_t& shared); + shared_t& operator=(const shared_t& shared); + + virtual ~shared_t(){ + if (m_meta_reg != NULL) { + delete[] m_meta_reg; + m_meta_reg = NULL; + } + } + +private: + static int meta_index(lua_State *L); + static int meta_gc(lua_State *L); + +public: + static shared_t** create_shared(lua_State* L); + static shared_t** create_shared(lua_State* L, shared_t* shared); + +private: + atomic_t m_ref; + const luaL_Reg* m_meta_reg; +}; + +extern shared_t** create_shared(lua_State* L, shared_t& shared); + +#endif diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 2b48f78..918dd86 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -6,8 +6,8 @@ #include "node_lua.h" #include "uv_tcp_handle.h" -#define TCP_LISTEN_SOCKET_METATABLE "class.tcp_listen_handle_t" -#define TCP_SOCKET_METATABLE "class.tcp_socket_handle_t" +#define TCP_LISTEN_SOCKET_METATABLE "class tcp_listen_handle_t" +#define TCP_SOCKET_METATABLE "class tcp_socket_handle_t" ///////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1109,7 +1109,7 @@ void lua_tcp_socket_handle_t::release_read_overflow_buffers() int luaopen_tcp(lua_State *L) { - luaL_Reg l[] = { + static const luaL_Reg l[] = { { "listen", lua_tcp_listen_handle_t::listen }, { "listen6", lua_tcp_listen_handle_t::listen6 }, { "listens", lua_tcp_listen_handle_t::listens }, diff --git a/src/lua_timer_handle.cpp b/src/lua_timer_handle.cpp index 66146a2..0e54bfc 100644 --- a/src/lua_timer_handle.cpp +++ b/src/lua_timer_handle.cpp @@ -4,7 +4,7 @@ #include "context_lua.h" #include "network.h" -#define TIMER_METATABLE "class.timer_handle_t" +#define TIMER_METATABLE "class timer_handle_t" int32_t lua_timer_handle_t::sleep(lua_State* L) { @@ -119,7 +119,7 @@ int32_t lua_timer_handle_t::wakeup(lua_State* L, message_t& message) int luaopen_timer(lua_State *L) { - luaL_Reg l[] = { + static const luaL_Reg l[] = { { "sleep", lua_timer_handle_t::sleep }, { "timeout", lua_timer_handle_t::timeout }, { "close", lua_timer_handle_t::close }, diff --git a/src/lua_udp_handle.cpp b/src/lua_udp_handle.cpp index c9ec9b9..1280175 100644 --- a/src/lua_udp_handle.cpp +++ b/src/lua_udp_handle.cpp @@ -6,7 +6,7 @@ #include "node_lua.h" #include "uv_udp_handle.h" -#define UDP_SOCKET_METATABLE "class.udp_socket_handle_t" +#define UDP_SOCKET_METATABLE "class udp_socket_handle_t" lua_udp_handle_t* lua_udp_handle_t::create_udp_socket(uv_udp_handle_t* handle, lua_State* L) { @@ -432,7 +432,7 @@ static int32_t lua_udp_fd_src(lua_State* L) int luaopen_udp(lua_State *L) { - luaL_Reg l[] = { + static const luaL_Reg l[] = { { "open", lua_udp_handle_t::open }, { "open6", lua_udp_handle_t::open6 }, { "write", lua_udp_handle_t::write }, diff --git a/src/message.h b/src/message.h index 6a857a5..3004f55 100644 --- a/src/message.h +++ b/src/message.h @@ -3,6 +3,7 @@ #include "buffer.h" #include "lbinary.h" #include "ltpack.h" +#include "lshared.h" #define MESSAGE_TYPE_BIT 24 #define MAKE_MESSAGE_TYPE(mtype, dtype) (((uint32_t)(dtype) << MESSAGE_TYPE_BIT) | ((mtype) & (((uint32_t)1 << MESSAGE_TYPE_BIT) - 1))) @@ -22,8 +23,9 @@ enum data_type { STRING = 6, //need to be freed BINARY = 7, //need to be freed TPACK = 8, //need to be freed - ARRAY = 9, //need to be freed - TERROR = 10 // + SHARED = 9, //need to be freed + ARRAY = 10,//need to be freed + TERROR = 11 // }; typedef union data_t { @@ -35,6 +37,7 @@ typedef union data_t { char *m_string; binary_t m_binary; tpack_t m_tpack; + shared_t *m_shared; message_array_t *m_array; int32_t m_error; } data_t; @@ -77,6 +80,7 @@ enum message_type { #define message_string(msg) ((msg).m_data.m_string) #define message_binary(msg) ((msg).m_data.m_binary) #define message_tpack(msg) ((msg).m_data.m_tpack) +#define message_shared(msg) ((msg).m_data.m_shared) #define message_array(msg) ((msg).m_data.m_array) #define message_error(msg) ((msg).m_data.m_error) @@ -90,12 +94,11 @@ enum message_type { #define message_is_string(msg) (STRING == message_data_type(msg)) #define message_is_binary(msg) (BINARY == message_data_type(msg)) #define message_is_tpack(msg) (TPACK == message_data_type(msg)) +#define message_is_shared(msg) (SHARED == message_data_type(msg)) #define message_is_array(msg) (ARRAY == message_data_type(msg)) #define message_is_error(msg) (TERROR == message_data_type(msg)) #define message_is_pure_error(msg) (TERROR == message_data_type(msg) && message_error(msg) != 0) -#define message_buffer_grab(msg) if (message_is_buffer(msg)) { buffer_grab(msg.m_data.m_buffer); } -#define message_buffer_release(msg) if (message_is_buffer(msg)) { buffer_release(msg.m_data.m_buffer); } #define message_clean(msg) do { \ if (message_is_buffer(msg)) { \ buffer_release(msg.m_data.m_buffer); \ @@ -114,6 +117,11 @@ enum message_type { sdsfree((msg).m_data.m_tpack.m_data); \ (msg).m_data.m_tpack.m_data = NULL; \ } \ + } else if (message_is_shared(msg)) { \ + if ((msg).m_data.m_shared) { \ + (msg).m_data.m_shared->release(); \ + (msg).m_data.m_shared = NULL; \ + } \ } else if (message_is_array(msg)) { \ if ((msg).m_data.m_array) { \ message_array_release((msg).m_data.m_array); \ @@ -172,7 +180,11 @@ class message_t { : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, BINARY)) { m_data.m_binary = binary; } - message_t(uint32_t source, int32_t session, uint32_t msg_type, message_array_t* array) + message_t(uint32_t source, int32_t session, uint32_t msg_type, shared_t *shared) + : m_source(source), m_session(session), + m_type(MAKE_MESSAGE_TYPE(msg_type, SHARED)) { m_data.m_shared = shared; } + + message_t(uint32_t source, int32_t session, uint32_t msg_type, message_array_t *array) : m_source(source), m_session(session), m_type(MAKE_MESSAGE_TYPE(msg_type, ARRAY)) { m_data.m_array = array; } public: diff --git a/src/node_lua.h b/src/node_lua.h index 54dc934..56e0089 100644 --- a/src/node_lua.h +++ b/src/node_lua.h @@ -17,7 +17,7 @@ class node_lua_t : public singleton_t { ~node_lua_t(); /* context send by ctx */ bool context_send(context_t* ctx, message_t& msg); - template < class type> + template < class type > FORCE_INLINE bool context_send(context_t* ctx, uint32_t source, int session, int msg_type, type data) { message_t msg(source, session, msg_type, data); From b9b98aa5d5104d507817f9f3ed45373a7813dd9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 31 Dec 2017 17:41:29 +0800 Subject: [PATCH 162/173] =?UTF-8?q?=E5=86=85=E5=AD=98=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E5=85=B1=E4=BA=AB=E8=A1=A5=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持跨context服务内存对象共享补丁:解决shared_t对象转换为lua对象的问题。 --- src/context_lua.cpp | 25 ++++++++++++++----------- src/lshared.cpp | 21 +++++++++++---------- src/lshared.h | 8 +++----- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index fdb0a7a..731cb66 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -565,45 +565,48 @@ void context_lua_t::lua_pushmessage(lua_State *L, message_t& message) { message_array_t *array = NULL; switch (message_data_type(message)) { - case NIL: + case NIL : lua_pushnil(L); return; - case TBOOLEAN: + case TBOOLEAN : lua_pushboolean(L, message_bool(message)); return; - case USERDATA: + case USERDATA : lua_pushlightuserdata(L, message_userdata(message)); return; - case NUMBER: + case NUMBER : lua_pushnumber(L, message_number(message)); return; - case INTEGER: + case INTEGER : lua_pushinteger(L, message_integer(message)); return; - case BUFFER: + case BUFFER : create_buffer(L, message_buffer(message)); return; - case STRING: + case SHARED : + shared_t::create(L, message_shared(message)); + return; + case STRING : if (message_string(message)) { lua_pushstring(L, message_string(message)); } else { lua_pushstring(L, ""); } return; - case BINARY: + case BINARY : if (message_binary(message).m_data) { lua_pushlstring(L, message_binary(message).m_data, sdslen(message_binary(message).m_data)); } else { lua_pushstring(L, ""); } return; - case TPACK: + case TPACK : ltunpack(&message_tpack(message), L); return; - case TERROR: + case TERROR : lua_pushinteger(L, message_error(message)); return; - case ARRAY: + case ARRAY : array = message_array(message); if (array != NULL && array->m_count > 0) { lua_checkstack(L, array->m_count); diff --git a/src/lshared.cpp b/src/lshared.cpp index 5d5bda4..8857db3 100644 --- a/src/lshared.cpp +++ b/src/lshared.cpp @@ -24,7 +24,7 @@ int shared_t::meta_gc(lua_State *L) ///////////////////////////////////////////////////////////////////////////////////////////////////////// -shared_t** shared_t::create_shared(lua_State* L) +shared_t** shared_t::create(lua_State* L) { shared_t** ret = (shared_t**)lua_newuserdata(L, sizeof(shared_t*)); *ret = NULL; @@ -38,18 +38,19 @@ shared_t** shared_t::create_shared(lua_State* L) return ret; } -shared_t** shared_t::create_shared(lua_State* L, shared_t* shared) +shared_t** shared_t::create(lua_State* L, shared_t* shared) { - if (shared->m_meta_reg) { - if (luaL_newmetatable(L, typeid(*shared).name())) { /* create new metatable */ - luaL_setfuncs(L, shared->m_meta_reg, 0); + shared_t** ret = create(L); + if (shared) { + if (shared->m_meta_reg) { + if (luaL_newmetatable(L, typeid(*shared).name())) { /* create new metatable */ + luaL_setfuncs(L, shared->m_meta_reg, 0); + } + lua_pop(L, 1); } - lua_pop(L, 1); + shared->grab(); + *ret = shared; } - - shared_t** ret = create_shared(L); - shared->grab(); - *ret = shared; return ret; } diff --git a/src/lshared.h b/src/lshared.h index e71a28a..6132a34 100644 --- a/src/lshared.h +++ b/src/lshared.h @@ -33,14 +33,12 @@ class shared_t { static int meta_gc(lua_State *L); public: - static shared_t** create_shared(lua_State* L); - static shared_t** create_shared(lua_State* L, shared_t* shared); + static shared_t** create(lua_State* L); + static shared_t** create(lua_State* L, shared_t* shared); private: atomic_t m_ref; const luaL_Reg* m_meta_reg; -}; - -extern shared_t** create_shared(lua_State* L, shared_t& shared); +}; #endif From c88532b36c505f79b89cd2fd38fea73a188277f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 31 Dec 2017 22:50:16 +0800 Subject: [PATCH 163/173] =?UTF-8?q?=E7=A6=81=E7=94=A8=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E5=BA=93=E5=8D=B8=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 内存对象共享补丁:禁用动态库卸载,防止共享对象数据和代码可能被释放。 --- deps/lua/loadlib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deps/lua/loadlib.c b/deps/lua/loadlib.c index 7911928..2cdb220 100644 --- a/deps/lua/loadlib.c +++ b/deps/lua/loadlib.c @@ -298,6 +298,8 @@ static void addtoclib (lua_State *L, const char *path, void *plib) { lua_pop(L, 1); /* pop CLIBS table */ } +//added by xdczju@sina.com +#define lsys_unloadlib(XX) /* ** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib From d4d35d45fe3fc761bb99dbe43408aec77060b8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 31 Dec 2017 23:36:23 +0800 Subject: [PATCH 164/173] =?UTF-8?q?=E5=85=B1=E4=BA=AB=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E7=BB=91=E5=AE=9ALua=5FReg=E5=87=BD=E6=95=B0=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 共享对象绑定Lua_Reg函数优化 --- src/lshared.cpp | 25 +++++++++++-------------- src/lshared.h | 17 +++-------------- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/lshared.cpp b/src/lshared.cpp index 8857db3..c7e0751 100644 --- a/src/lshared.cpp +++ b/src/lshared.cpp @@ -4,10 +4,15 @@ int shared_t::meta_index(lua_State *L) { shared_t** shared = (shared_t**)luaL_checkudata(L, 1, SHARED_METATABLE); - if (*shared && (*shared)->m_meta_reg && luaL_getmetatable(L, typeid(**shared).name()) != LUA_TNIL) { - lua_pushvalue(L, 2); - lua_rawget(L, -2); - return 1; + if (*shared) { + const char* name = lua_tostring(L, 2); + if (name) { + lua_CFunction func = (*shared)->index_function(name); + if (func) { + lua_pushcfunction(L, func); + return 1; + } + } } return 0; } @@ -41,16 +46,8 @@ shared_t** shared_t::create(lua_State* L) shared_t** shared_t::create(lua_State* L, shared_t* shared) { shared_t** ret = create(L); - if (shared) { - if (shared->m_meta_reg) { - if (luaL_newmetatable(L, typeid(*shared).name())) { /* create new metatable */ - luaL_setfuncs(L, shared->m_meta_reg, 0); - } - lua_pop(L, 1); - } - shared->grab(); - *ret = shared; - } + shared->grab(); + *ret = shared; return ret; } diff --git a/src/lshared.h b/src/lshared.h index 6132a34..4c50074 100644 --- a/src/lshared.h +++ b/src/lshared.h @@ -6,13 +6,7 @@ class shared_t { public: - shared_t() : m_ref(1), m_meta_reg(NULL) {} - shared_t(const luaL_Reg reg[]) : m_ref(1), m_meta_reg(NULL) { - if (sizeof(reg) > 0) { - m_meta_reg = new luaL_Reg[ARRAY_SIZE(reg)]; - memcpy((void*)m_meta_reg, reg, sizeof(reg)); - } - } + shared_t() : m_ref(1) {} FORCE_INLINE shared_t* grab() { atomic_inc(m_ref); return this; } FORCE_INLINE void release() { if (atomic_dec(m_ref) == 1) delete this; } @@ -21,16 +15,12 @@ class shared_t { shared_t(const shared_t& shared); shared_t& operator=(const shared_t& shared); - virtual ~shared_t(){ - if (m_meta_reg != NULL) { - delete[] m_meta_reg; - m_meta_reg = NULL; - } - } + virtual ~shared_t() = 0; private: static int meta_index(lua_State *L); static int meta_gc(lua_State *L); + virtual lua_CFunction index_function(const char* name) { return NULL; } public: static shared_t** create(lua_State* L); @@ -38,7 +28,6 @@ class shared_t { private: atomic_t m_ref; - const luaL_Reg* m_meta_reg; }; #endif From 6c1cd88888b4b19e4d78072da086ab226d74feed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 1 Jan 2018 20:25:27 +0800 Subject: [PATCH 165/173] =?UTF-8?q?=E5=85=B1=E4=BA=AB=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E5=B0=8F=E8=A1=A5=E4=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 共享对象小补丁 --- src/lshared.cpp | 1 - src/lshared.h | 10 +++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lshared.cpp b/src/lshared.cpp index c7e0751..8fba1e3 100644 --- a/src/lshared.cpp +++ b/src/lshared.cpp @@ -1,5 +1,4 @@ #include "lshared.h" -#include int shared_t::meta_index(lua_State *L) { diff --git a/src/lshared.h b/src/lshared.h index 4c50074..9efac89 100644 --- a/src/lshared.h +++ b/src/lshared.h @@ -10,16 +10,24 @@ class shared_t { FORCE_INLINE shared_t* grab() { atomic_inc(m_ref); return this; } FORCE_INLINE void release() { if (atomic_dec(m_ref) == 1) delete this; } + FORCE_INLINE bool writeable() { return m_ref == 1; } protected: shared_t(const shared_t& shared); shared_t& operator=(const shared_t& shared); - virtual ~shared_t() = 0; + virtual ~shared_t() {}; private: static int meta_index(lua_State *L); static int meta_gc(lua_State *L); + + /* + * index_function must return a multi-thread safe lua_CFunction on shared_t object. + * It's better all operations on the shared_t object is read-only or thread safe. + * index_function is not essential for the derived class unless you want a meta-method for your userdata, + * so you can choose whether overwriting this function in the derived class. + **/ virtual lua_CFunction index_function(const char* name) { return NULL; } public: From 733e486f31d934b6ed86a5f514e30ccc43552210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Mon, 1 Jan 2018 21:20:23 +0800 Subject: [PATCH 166/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A3=80=E6=B5=8Blua?= =?UTF-8?q?=E5=85=B1=E4=BA=AB=E5=AF=B9=E8=B1=A1=E7=9A=84=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加检测lua共享对象的模板函数 --- src/lshared.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/lshared.h b/src/lshared.h index 9efac89..41f79b1 100644 --- a/src/lshared.h +++ b/src/lshared.h @@ -1,6 +1,7 @@ #ifndef LSHARED_H_ #define LSHARED_H_ #include "common.h" +#include #define SHARED_METATABLE "class shared_t" @@ -33,6 +34,23 @@ class shared_t { public: static shared_t** create(lua_State* L); static shared_t** create(lua_State* L, shared_t* shared); + + template < class type > + static type* check_shared(lua_State *L, int idx, bool writable) + { + shared_t* shared = *(shared_t**)luaL_checkudata(L, idx, SHARED_METATABLE); + if (shared == NULL) { + luaL_argerror(L, 1, "shared_t invalid"); + } + if (writable && !shared->writeable()) { + luaL_argerror(L, 1, "shared_t not writable"); + } + type* p = dynamic_cast(shared); + if (!p) { + luaL_error(L, "bad argument #%d (%s expected, %s found)", idx, typeid(type).name(), typeid(*shared).name()); + } + return p; + } private: atomic_t m_ref; From 2e526f8c5cdfc8dcec8c3c5dbf3adf1998ae3016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Tue, 6 Feb 2018 14:01:01 +0800 Subject: [PATCH 167/173] =?UTF-8?q?=E5=A2=9E=E5=8A=A0utf8=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/context_lua.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 731cb66..d526c01 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -140,6 +140,7 @@ void context_lua_t::lua_open_libs(lua_State *L) {LUA_STRLIBNAME, luaopen_string}, {LUA_BITLIBNAME, luaopen_bit32}, {LUA_MATHLIBNAME, luaopen_math}, + {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, #if defined(LUA_CACHELIB) {LUA_CACHELIB, luaopen_cache}, From 1717d577873b84e9404bb608034dbd9fbdc008c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Wed, 28 Feb 2018 02:02:36 +0800 Subject: [PATCH 168/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbuffer=5Fsplit?= =?UTF-8?q?=E5=92=8Cbuffer=5Fremove=E9=80=A0=E6=88=90=E7=9A=84=E5=86=85?= =?UTF-8?q?=E5=AD=98=E6=B3=84=E6=BC=8F=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/buffer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/buffer.cpp b/src/buffer.cpp index 5352240..5ab03ea 100644 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -246,6 +246,7 @@ buffer_t buffer_split(buffer_t& buffer_ref, size_t len) buffer_release(buffer_ref); buffer_ref = new_buffer; } else { //split_len == buffer->m_len + buffer_release(buffer_ref); buffer_ref = buffer_new(DEFAULT_BUFFER_CAPACITY, NULL, 0); } } @@ -283,6 +284,7 @@ size_t buffer_remove(buffer_t& buffer_ref, size_t start, size_t len) buffer_release(buffer_ref); buffer_ref = new_buffer; } else { //remove_len == buffer->m_len + buffer_release(buffer_ref); buffer_ref = buffer_new(DEFAULT_BUFFER_CAPACITY, NULL, 0); } } From 47d15ec201dd84bea053efb226be2c816afa199f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Thu, 15 Mar 2018 02:34:13 +0800 Subject: [PATCH 169/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dcontext.wait=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0context.suspend?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 修复context.wait接口问题,该问题会导致主动等待的服务先退出后,被动等待的服务并未解除等待的问题。 2. 增加context.suspend接口,该接口会让当前coroutine永久挂起。 --- src/context_lua.cpp | 48 +++++++++++++++++++++++++++++++++++++++--- src/context_lua.h | 3 +++ src/message.h | 1 + src/ref_sessions_mgr.h | 1 + 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/context_lua.cpp b/src/context_lua.cpp index d526c01..7f6d1f0 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -87,6 +87,11 @@ bool context_lua_t::deinit(const char *arg) singleton_ref(node_lua_t).context_send(*it, m_handle, LUA_REFNIL, LUA_CTX_WAKEUP, UV_OK); } m_context_wait_handles.clear(); + + for (ref_sessions_mgr_t::ref_sessions_map_t::iterator it = m_context_wait_sessions.m_sessions_map.begin(); it != m_context_wait_sessions.m_sessions_map.end(); ++it) { + singleton_ref(node_lua_t).context_send(it->first, m_handle, LUA_REFNIL, LUA_CTX_WAIT_CANCEL, UV_OK); + } + if (m_lstate) { lua_close(m_lstate); m_lstate = NULL; @@ -696,6 +701,9 @@ void context_lua_t::on_received(message_t& message) case LUA_CTX_WAIT: response_context_wait(message); break; + case LUA_CTX_WAIT_CANCEL: + response_context_wait_cancel(message); + break; case LUA_CTX_WAKEUP: response_context_wakeup(message); break; @@ -819,6 +827,11 @@ void context_lua_t::response_context_wait(message_t& response) m_context_wait_handles.insert(response.m_source); } +void context_lua_t::response_context_wait_cancel(message_t& response) +{ + m_context_wait_handles.erase(response.m_source); +} + void context_lua_t::response_context_wakeup(message_t& response) { m_context_wait_sessions.wakeup_all(response.m_source, this, response, true); @@ -1288,8 +1301,16 @@ int32_t context_lua_t::context_wait_yield_continue(lua_State* L, int status, lua int32_t context_lua_t::context_wait_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat) { context_lua_t* lctx = context_lua_t::lua_get_context(L); - message_t message(0, session, LUA_CTX_WAKEUP, NL_ETIMEOUT); - return lctx->m_context_wait_sessions.wakeup_one_fixed((uint64_t)userdata, lctx, message, true); + uint32_t handle = (uint64_t)userdata; + if (!lctx->m_context_wait_sessions.is_empty(handle)) { + message_t message(0, session, LUA_CTX_WAKEUP, NL_ETIMEOUT); + int32_t result = lctx->m_context_wait_sessions.wakeup_one_fixed(handle, lctx, message, true); + if (lctx->m_context_wait_sessions.is_empty(handle)) { + singleton_ref(node_lua_t).context_send(handle, lctx->get_handle(), LUA_REFNIL, LUA_CTX_WAIT_CANCEL, UV_OK); + } + return result; + } + return 0; } int32_t context_lua_t::context_wait(lua_State *L) @@ -1309,7 +1330,12 @@ int32_t context_lua_t::context_wait(lua_State *L) int32_t session; if (top >= 2) { if (lua_isnil(L, 2)) { - lctx->m_context_wait_sessions.free_nonblocking_callback(handle, L); + if (!lctx->m_context_wait_sessions.is_empty(handle)) { + lctx->m_context_wait_sessions.free_nonblocking_callback(handle, L); + if (lctx->m_context_wait_sessions.is_empty(handle)) { + singleton_ref(node_lua_t).context_send(handle, lctx->get_handle(), LUA_REFNIL, LUA_CTX_WAIT_CANCEL, UV_OK); + } + } return 0; } if (lua_isfunction(L, 2)) { @@ -1397,6 +1423,21 @@ int32_t context_lua_t::context_run(lua_State *L) return 0; } +int32_t context_lua_t::context_suspend_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination) +{ + if (root_coro != NULL) { + context_lua_t::lua_ref_yield_coroutine(root_coro); /* WARNINIG: this will make the coroutine dead, never go back! */ + } + return UV_OK; +} + +int32_t context_lua_t::context_suspend(lua_State *L) +{ + context_lua_t* lctx = (context_lua_t*)lua_get_context(L); + lua_settop(L, 0); + return lctx->lua_yield_send(L, lctx->get_handle(), context_suspend_yield_finalize, NULL); /* no yield continue function, never go back! */ +} + int luaopen_context(lua_State *L) { static const luaL_Reg l[] = { @@ -1412,6 +1453,7 @@ int luaopen_context(lua_State *L) { "wait", context_lua_t::context_wait }, { "log", context_lua_t::context_log }, { "run", context_lua_t::context_run }, + { "suspend", context_lua_t::context_suspend }, { NULL, NULL }, }; luaL_newlib(L, l); diff --git a/src/context_lua.h b/src/context_lua.h index 55bfb20..2947651 100644 --- a/src/context_lua.h +++ b/src/context_lua.h @@ -99,6 +99,7 @@ class context_lua_t : public context_t { void response_context_query(message_t& response); void response_context_reply(message_t& response); void response_context_wait(message_t& response); + void response_context_wait_cancel(message_t& response); void response_context_wakeup(message_t& response); void response_context_run(message_t& response); void response_tcp_listen(message_t& response); @@ -159,6 +160,7 @@ class context_lua_t : public context_t { static int32_t context_wait_yield_continue(lua_State* L, int status, lua_KContext ctx); static int32_t context_wait_timeout(lua_State *L, int32_t session, void* userdata, bool is_repeat); static int32_t context_run_callback_adjust(lua_State* L); + static int32_t context_suspend_yield_finalize(lua_State *root_coro, lua_State *main_coro, void *userdata, uint32_t destination); static int32_t context_strerror(lua_State *L); static int32_t context_self(lua_State *L); static int32_t context_thread(lua_State *L); @@ -172,6 +174,7 @@ class context_lua_t : public context_t { static int32_t context_wait(lua_State *L); static int32_t context_log(lua_State *L); static int32_t context_run(lua_State *L); + static int32_t context_suspend(lua_State *L); /************ the above are context lua api ************/ public: diff --git a/src/message.h b/src/message.h index 3004f55..cedd146 100644 --- a/src/message.h +++ b/src/message.h @@ -53,6 +53,7 @@ enum message_type { LUA_CTX_INIT, LUA_CTX_WAIT, LUA_CTX_WAKEUP, + LUA_CTX_WAIT_CANCEL, LUA_CTX_RUN, RESPONSE_TCP_LISTEN, RESPONSE_TCP_ACCEPT, diff --git a/src/ref_sessions_mgr.h b/src/ref_sessions_mgr.h index 45c98c1..d698c3c 100644 --- a/src/ref_sessions_mgr.h +++ b/src/ref_sessions_mgr.h @@ -28,6 +28,7 @@ class ref_sessions_mgr_t void wakeup_all(uint32_t id, context_lua_t* lctx, message_t& message, bool free_callback = false); private: + friend class context_lua_t; typedef std::map ref_sessions_map_t; typedef std::vector ref_sessions_vec_t; ref_sessions_map_t m_sessions_map; From ad4b28546f844e46a175c4e21b9a0c895564ea60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Sun, 21 Oct 2018 22:55:30 +0800 Subject: [PATCH 170/173] =?UTF-8?q?=E9=9D=9Erelease=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=85=B3=E9=97=ADo3=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luaclib/cjson/Makefile | 4 ++-- luaclib/common/Makefile | 4 ++-- luaclib/lfs/Makefile | 4 ++-- luaclib/lpeg/Makefile | 4 ++-- luaclib/mime/Makefile | 4 ++-- luaclib/pb/Makefile | 4 ++-- src/Makefile | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/luaclib/cjson/Makefile b/luaclib/cjson/Makefile index 880ee01..57feb07 100644 --- a/luaclib/cjson/Makefile +++ b/luaclib/cjson/Makefile @@ -31,9 +31,9 @@ LIBRARY_PATH := ../../deps/lua LIBS := nlua ## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +CFLAGS += -g -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) -CFLAGS += -D RELEASE +CFLAGS += -D RELEASE -O3 endif ifeq (sunos,$(PLATFORM)) diff --git a/luaclib/common/Makefile b/luaclib/common/Makefile index df210e0..e3b827f 100644 --- a/luaclib/common/Makefile +++ b/luaclib/common/Makefile @@ -14,10 +14,10 @@ SRC_PATH := ../../src INCLUDE_PATH := ../../src ../../deps/lua ../../deps/uv/include ## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -std=c++0x -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +CFLAGS += -g -Wall -Wextra -Wno-unused-parameter -fpic -std=c++0x -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) -CFLAGS += -D RELEASE +CFLAGS += -D RELEASE -O3 endif ## get all include path diff --git a/luaclib/lfs/Makefile b/luaclib/lfs/Makefile index 88c054c..4005c75 100644 --- a/luaclib/lfs/Makefile +++ b/luaclib/lfs/Makefile @@ -19,9 +19,9 @@ LIBRARY_PATH := ../../deps/lua LIBS := nlua ## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +CFLAGS += -g -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) -CFLAGS += -D RELEASE +CFLAGS += -D RELEASE -O3 endif ## define LDFLAGS diff --git a/luaclib/lpeg/Makefile b/luaclib/lpeg/Makefile index 7046338..d008340 100644 --- a/luaclib/lpeg/Makefile +++ b/luaclib/lpeg/Makefile @@ -19,9 +19,9 @@ LIBRARY_PATH := ../../deps/lua LIBS := nlua ## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -std=c99 -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +CFLAGS += -g -Wall -Wextra -Wno-unused-parameter -std=c99 -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) -CFLAGS += -D RELEASE +CFLAGS += -D RELEASE -O3 endif ## define LDFLAGS diff --git a/luaclib/mime/Makefile b/luaclib/mime/Makefile index 34fc0eb..d5634a4 100644 --- a/luaclib/mime/Makefile +++ b/luaclib/mime/Makefile @@ -19,9 +19,9 @@ LIBRARY_PATH := ../../deps/lua LIBS := nlua ## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +CFLAGS += -g -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) -CFLAGS += -D RELEASE +CFLAGS += -D RELEASE -O3 endif ## define LDFLAGS diff --git a/luaclib/pb/Makefile b/luaclib/pb/Makefile index f7ac05c..abcd574 100644 --- a/luaclib/pb/Makefile +++ b/luaclib/pb/Makefile @@ -19,9 +19,9 @@ LIBRARY_PATH := ../../deps/lua LIBS := nlua ## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +CFLAGS += -g -Wall -Wextra -Wno-unused-parameter -fpic -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) -CFLAGS += -D RELEASE +CFLAGS += -D RELEASE -O3 endif ## define LDFLAGS diff --git a/src/Makefile b/src/Makefile index 97e2496..48f6a26 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,9 +20,9 @@ LIBRARY_PATH := ../deps/lua ../deps/uv LIBS := nlua uv m ## define CFLAGS -CFLAGS += -g -O3 -Wall -Wextra -Wno-unused-parameter -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 +CFLAGS += -g -Wall -Wextra -Wno-unused-parameter -D LUA_COMPAT_5_2 -D LUA_COMPAT_5_1 ifeq (RELEASE,$(RELEASE)) -CFLAGS += -D RELEASE +CFLAGS += -D RELEASE -O3 endif ## define LDFLAGS From 7060ce093a6de90ee5d2ed6a70caa9e92fe9af7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Tue, 27 Nov 2018 10:39:20 +0800 Subject: [PATCH 171/173] Update lua_tcp_handle.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit luaL_tolstring->lua_tolstring替换,luaL_tolstring会在栈顶重新压一个元素。 --- src/lua_tcp_handle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lua_tcp_handle.cpp b/src/lua_tcp_handle.cpp index 918dd86..9689a29 100644 --- a/src/lua_tcp_handle.cpp +++ b/src/lua_tcp_handle.cpp @@ -801,7 +801,7 @@ static void opt_check_endian(lua_State* L, int32_t idx, const char* field, char lua_getfield(L, idx, field); if (!lua_isnil(L, -1)) { size_t len = 0; - const char* head_endian = luaL_tolstring(L, -1, &len); + const char* head_endian = lua_tolstring(L, -1, &len); if (len != 1 || (*head_endian != 'L' && *head_endian != 'B')) { luaL_error(L, "option table error, field '%s' not correct", field); } From 4df65aa50ff9f4b3253a003cc8ff7c23bfece640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Tue, 4 Dec 2018 10:26:03 +0800 Subject: [PATCH 172/173] lua_yieldable->lua_isyieldable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 突然发现lua原生有判定L是否可以yield的api。 --- deps/lua/ldo.c | 6 ------ deps/lua/lua.h | 3 --- src/context_lua.cpp | 2 +- src/lcororep.cpp | 2 +- 4 files changed, 2 insertions(+), 11 deletions(-) diff --git a/deps/lua/ldo.c b/deps/lua/ldo.c index 8aa3473..b44e691 100644 --- a/deps/lua/ldo.c +++ b/deps/lua/ldo.c @@ -710,12 +710,6 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, return 0; /* return to 'luaD_hook' */ } -/* Added by xdczju@sina.com */ -LUA_API int lua_yieldable(lua_State *L) -{ - return L->nny == 0; -} - int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; diff --git a/deps/lua/lua.h b/deps/lua/lua.h index 6c0e339..a6955cc 100644 --- a/deps/lua/lua.h +++ b/deps/lua/lua.h @@ -297,9 +297,6 @@ LUA_API void (lua_refsharedclosure)(void *f); LUA_API void (lua_unrefsharedclosure)(void *f); #endif -/* Added by xdczju@sina.com */ -LUA_API int (lua_yieldable)(lua_State *L); - /* ** coroutine functions */ diff --git a/src/context_lua.cpp b/src/context_lua.cpp index 7f6d1f0..f1a4056 100644 --- a/src/context_lua.cpp +++ b/src/context_lua.cpp @@ -378,7 +378,7 @@ int32_t context_lua_t::lua_yield_send(lua_State *L, uint32_t destination, yiled_ lctx->m_shared->m_yielding_finalize_userdata = fnz_ud; lctx->m_shared->m_yielding_status = UV_OK; lctx->m_shared->m_yielding_timeout = timeout; - if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_yieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */ + if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_isyieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */ return lua_yieldk(L, 0, (lua_KContext)lua_gettop(L), yieldk); } else { if (stacks) { /* stack enough, but not yield-able */ diff --git a/src/lcororep.cpp b/src/lcororep.cpp index e2504f2..bfa1b2a 100644 --- a/src/lcororep.cpp +++ b/src/lcororep.cpp @@ -22,7 +22,7 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { lua_xmove(L, co, narg); context_lua_t *lctx = context_lua_t::lua_get_context(L); while (((status = lua_resume(co, L, narg)) == LUA_YIELD) && lctx->yielding_up()) { /* can happen only when status == LUA_YIELD */ - if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_yieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */ + if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_isyieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */ return lua_yieldk(L, 0, 0, coresume_continue); /* yield again! n(0) result to yield and ctx(0) is not allowed */ } else { /* lua_gettop(co) must be 0 since context_lua_t::lua_yield_send yield 0 result */ int yieldup_status = stacks ? NL_EYIELD : NL_ESTACKLESS; From a02a11ebf227af3d8acabd590bc5a0e27aa5752a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E6=98=AF=E5=A5=BD=E5=86=B7=E5=95=8A?= Date: Tue, 30 Apr 2019 16:10:23 +0800 Subject: [PATCH 173/173] =?UTF-8?q?=E4=BF=AE=E5=A4=8Duv=5Fis=5Fclosing?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uv_write去掉uv_is_closing判定。 --- src/uv_tcp_handle.cpp | 4 +--- src/uv_udp_handle.cpp | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/uv_tcp_handle.cpp b/src/uv_tcp_handle.cpp index 0ad9bf2..5edae7a 100644 --- a/src/uv_tcp_handle.cpp +++ b/src/uv_tcp_handle.cpp @@ -248,9 +248,7 @@ void uv_tcp_socket_handle_t::write(request_tcp_write_t& request) uv_tcp_socket_handle_t* handle = (uv_tcp_socket_handle_t*)singleton_ref(network_t).get_shared_write_socket(request.m_socket_fd); if (handle != NULL) { uint32_t length = request.m_length > 0 ? request.m_length : (uint32_t)buffer_data_length(request.m_buffer); - if (uv_is_closing((uv_handle_t*)handle)) { - err = NL_ETCPSCLOSED; - } else if (!check_head_option_max(handle->m_write_head_option, length)) { + if (!check_head_option_max(handle->m_write_head_option, length)) { err = NL_ETCPWRITELONG; } else { err = handle->write_handle(request); diff --git a/src/uv_udp_handle.cpp b/src/uv_udp_handle.cpp index 580104d..56a0bb1 100644 --- a/src/uv_udp_handle.cpp +++ b/src/uv_udp_handle.cpp @@ -91,11 +91,7 @@ void uv_udp_handle_t::write(request_udp_write_t& request) if (request.m_shared_write) { uv_udp_handle_t* handle = (uv_udp_handle_t*)singleton_ref(network_t).get_shared_write_socket(request.m_socket_fd); if (handle != NULL) { - if (uv_is_closing((uv_handle_t*)handle)) { - err = NL_EUDPSCLOSED; - } else { - err = handle->write_handle(request); - } + err = handle->write_handle(request); } else { err = NL_EUDPNOWSHARED; }