diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..278282644 --- /dev/null +++ b/.gitignore @@ -0,0 +1,335 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# Premake files +.bin/ +.build/ + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + diff --git a/Changelog b/Changelog index 1a7533b33..c09af91cb 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,17 @@ +2021-03-27: + +- faster Array.prototype.push and Array.prototype.unshift +- added JS_UpdateStackTop() +- fixed Windows console +- misc bug fixes + +2020-11-08: + +- improved function parameter initializers +- added std.setenv(), std.unsetenv() and std.getenviron() +- added JS_EvalThis() +- misc bug fixes + 2020-09-06: - added logical assignment operators diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..2c8fdebaf --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +QuickJS Javascript Engine + +Copyright (c) 2017-2021 Fabrice Bellard +Copyright (c) 2017-2021 Charlie Gordon + +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/Makefile b/Makefile index 94c8e31e6..c98acca1d 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # # QuickJS Javascript Engine # -# Copyright (c) 2017-2020 Fabrice Bellard -# Copyright (c) 2017-2020 Charlie Gordon +# Copyright (c) 2017-2021 Fabrice Bellard +# Copyright (c) 2017-2021 Charlie Gordon # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -53,7 +53,11 @@ CONFIG_BIGNUM=y OBJDIR=.obj ifdef CONFIG_WIN32 + ifdef CONFIG_M32 CROSS_PREFIX=i686-w64-mingw32- + else + CROSS_PREFIX=x86_64-w64-mingw32- + endif EXE=.exe else CROSS_PREFIX= diff --git a/README.md b/README.md new file mode 100644 index 000000000..ff364d7ac --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ + + +# QuickJS Javascript Engine + +Authors: Fabrice Bellard and Charlie Gordon + +Ported from https://bellard.org/quickjs/ and its official GitHub mirror https://github.com/bellard/quickjs + +By Andrew Fedoniouk (a.k.a. c-smile) + +This version is + +* Microsoft Visual C++ compatible/compileable +* Is used in Sciter.JS +* It contains extras: + * [JSX](doc/jsx.md) - built-in [facebook::JSX](https://facebook.github.io/jsx/) support with Sciter specific extras. + * Built-in [Persistence](storage/doc/README.md) - you can think of it as local MongoDB (NoSQL) DB embedded into the language. Pretty small, adds just 70kb into binary. + Persistence is based on [DyBASE of Konstantin Knizhnik](http://garret.ru/) + +The main documentation is in doc/quickjs.pdf or [doc/quickjs.html](doc/quickjs.html). + +# Build using Microsoft Visual Studio (2017 or 2019) + +Prerequisite: **premake5** - [download](https://premake.github.io/download.html) and install it. + +Then go to /win folder and run premake-vs2017.bat or premake-vs2019.bat . + +It will generate .build/vs2017/quickjs-msvc.sln and open it in Microsoft Visual Studio. + +Press F5 to compile it and run qjs - interactive JS command line application. + +# Premake5 and build on other platforms/compilers/ide + +Supported premake options: + +* ```--jsx``` - include JSX support; +* ```--storage``` - include Persistent Storage support; + +Supported targets (these are built into [Premake](https://premake.github.io/) itself): + +* vs2017 - MS Visual Studio 2017 +* vs2019 - MS Visual Studio 2019 +* gmake2 - gmake files +* etc... + +Few examples of other possible configurations: +```bat +premake5 vs2019 --jsx --storage +premake5 codeblocks --cc=gcc --jsx --storage +premake5 gmake2 --cc=gcc --jsx --storage +premake5 gmake2 --cc=clang --jsx --storage +premake5 gmake2 --cc=clang --jsx --storage +premake5 xcode4 --jsx --storage +``` + + + + + diff --git a/TODO b/TODO index 0eec6d356..2a3b3c311 100644 --- a/TODO +++ b/TODO @@ -1,13 +1,11 @@ -Misc: -- use realpath in module name normalizer and put it in quickjs-libc -- use custom printf to avoid C library compatibility issues -- rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ? +Bugs: +- modules: better error handling with cyclic module references + +Misc ideas: +- use custom printf to avoid compatibility issues with floating point numbers +- consistent naming for preprocessor defines - unify coding style and naming conventions - use names from the ECMA spec in library implementation -- modules: if no ".", use a well known module loading path ? -- use JSHoistedDef only for global variables (JSHoistedDef.var_name != JS_ATOM_NULL) -- add index in JSVarDef and is_arg flag to merge args and vars in JSFunctionDef -- replace most JSVarDef flags with var_type enumeration - use byte code emitters with typed arguments (for clarity) - use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing and use the same wrappers in all phases @@ -15,19 +13,36 @@ Misc: - use custom timezone support to avoid C library compatibility issues Memory: +- use memory pools for objects, etc? - test border cases for max number of atoms, object properties, string length - add emergency malloc mode for out of memory exceptions. - test all DynBuf memory errors - test all js_realloc memory errors -- bignum: handle memory errors -- use memory pools for objects, etc? - improve JS_ComputeMemoryUsage() with more info -Optimizations: +Built-in standard library: +- BSD sockets +- modules: use realpath in module name normalizer and put it in quickjs-libc +- modules: if no ".", use a well known module loading path ? +- get rid of __loadScript, use more common name + +REPL: +- debugger +- readline: support MS Windows terminal +- readline: handle dynamic terminal resizing +- readline: handle double width unicode characters +- multiline editing +- runtime object and function inspectors +- interactive object browser +- use more generic approach to display evaluation results +- improve directive handling: dispatch, colorize, completion... +- save history +- close all predefined methods in repl.js and jscalc.js + +Optimization ideas: - 64-bit atoms in 64-bit mode ? -- use auto-init properties for more global objects +- 64-bit small bigint in 64-bit mode ? - reuse stack slots for disjoint scopes, if strip -- optimize `for of` iterator for built-in array objects - add heuristic to avoid some cycles in closures - small String (0-2 charcodes) with immediate storage - perform static string concatenation at compile time @@ -36,43 +51,20 @@ Optimizations: - optimize `s += a + b`, `s += a.b` and similar simple expressions - ensure string canonical representation and optimise comparisons and hashes? - remove JSObject.first_weak_ref, use bit+context based hashed array for weak references -- optimize function storage with length and name accessors? - property access optimization on the global object, functions, prototypes and special non extensible objects. - create object literals with the correct length by backpatching length argument - remove redundant set_loc_uninitialized/check_uninitialized opcodes - peephole optim: push_atom_value, to_propkey -> push_atom_value - peephole optim: put_loc x, get_loc_check x -> set_loc x -- comparative performance benchmark -- use variable name when throwing uninitialized exception if available - convert slow array to fast array when all properties != length are numeric - optimize destructuring assignments for global and local variables - implement some form of tail-call-optimization - optimize OP_apply - optimize f(...b) -Extensions: -- support more features in [features] section -- add built-in preprocessor in compiler, get rid of jscompress - handle #if, #ifdef, #line, limited support for #define -- get rid of __loadScript, use more common name -- BSD sockets - -REPL: -- debugger -- readline: support MS Windows terminal -- readline: handle dynamic terminal resizing -- readline: handle double width unicode characters -- multiline editing -- runtime object and function inspectors -- interactive object browser -- use more generic approach to display evaluation results -- improve directive handling: dispatch, colorize, completion... -- save history -- close all predefined methods in repl.js and jscalc.js - Test262o: 0/11262 errors, 463 excluded Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) -Test262: 30/71748 errors, 868 excluded, 474 skipped -Test262 commit: 24c67328062383079ada85f4d253eb0526fd209b +Result: 35/75280 errors, 909 excluded, 585 skipped +Test262 commit: 31126581e7290f9233c29cefd93f66c6ac78f1c9 diff --git a/VERSION b/VERSION index c67790a71..22ffec184 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2020-09-06 +2021-03-27 diff --git a/cutils.c b/cutils.c index a02fb7688..a78e36fec 100644 --- a/cutils.c +++ b/cutils.c @@ -29,6 +29,30 @@ #include "cutils.h" +#ifdef _MSC_VER + + // From: https://stackoverflow.com/a/26085827 +int gettimeofday(struct timeval * tp, struct timezone * tzp) +{ + static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long)((time - EPOCH) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + + return 0; +} +#endif + + void pstrcpy(char *buf, int buf_size, const char *str) { int c; @@ -166,8 +190,7 @@ int dbuf_putstr(DynBuf *s, const char *str) return dbuf_put(s, (const uint8_t *)str, strlen(str)); } -int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, - const char *fmt, ...) +int printf_like(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...) { va_list ap; char buf[128]; diff --git a/cutils.h b/cutils.h index 31f7cd84a..51f0be897 100644 --- a/cutils.h +++ b/cutils.h @@ -27,15 +27,40 @@ #include #include +#include + +#ifdef _MSC_VER + #include + #include + #ifndef alloca + #define alloca(s) _alloca(s) + #endif +#else + #include +#endif /* set if CPU is big endian */ #undef WORDS_BIGENDIAN -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#define force_inline inline __attribute__((always_inline)) -#define no_inline __attribute__((noinline)) -#define __maybe_unused __attribute__((unused)) +#ifndef __has_attribute + #define likely(x) (x) + #define unlikely(x) (x) + #define force_inline __forceinline + #define no_inline __declspec(noinline) + #define __maybe_unused + #define __attribute__(x) + #define __attribute(x) + typedef intptr_t ssize_t; + #define printf_like(A, B) /*__attribute__((format(printf, (A), (B))))*/ +#else + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) + #define force_inline inline __attribute__((always_inline)) + #define no_inline __attribute__((noinline)) + #define __maybe_unused __attribute__((unused)) + //#define printf_like(A, B) __attribute__((format(printf, (A), (B)))) + #define printf_like(A, B) +#endif #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) @@ -114,27 +139,91 @@ static inline int64_t min_int64(int64_t a, int64_t b) /* WARNING: undefined if a = 0 */ static inline int clz32(unsigned int a) { +#ifdef _MSC_VER + unsigned long idx; + _BitScanReverse(&idx, a); + return 31 ^ idx; +#else return __builtin_clz(a); +#endif } /* WARNING: undefined if a = 0 */ static inline int clz64(uint64_t a) { - return __builtin_clzll(a); +#ifdef _MSC_VER + unsigned long where; + // BitScanReverse scans from MSB to LSB for first set bit. + // Returns 0 if no set bit is found. +#if INTPTR_MAX >= INT64_MAX // 64-bit + if (_BitScanReverse64(&where, a)) + return (int)(63 - where); +#else + // Scan the high 32 bits. + if (_BitScanReverse(&where, (uint32_t)(a >> 32))) + return (int)(63 - (where + 32)); // Create a bit offset from the MSB. + // Scan the low 32 bits. + if (_BitScanReverse(&where, (uint32_t)(a))) + return (int)(63 - where); +#endif + return 64; // Undefined Behavior. +#else + return __builtin_clzll(a); +#endif } /* WARNING: undefined if a = 0 */ static inline int ctz32(unsigned int a) { +#ifdef _MSC_VER + unsigned long idx; + _BitScanForward(&idx, a); + return 31 ^ idx; +#else return __builtin_ctz(a); +#endif } /* WARNING: undefined if a = 0 */ static inline int ctz64(uint64_t a) { - return __builtin_ctzll(a); +#ifdef _MSC_VER + unsigned long where; + // Search from LSB to MSB for first set bit. + // Returns zero if no set bit is found. +#if INTPTR_MAX >= INT64_MAX // 64-bit + if (_BitScanForward64(&where, a)) + return (int)(where); +#else + // Win32 doesn't have _BitScanForward64 so emulate it with two 32 bit calls. + // Scan the Low Word. + if (_BitScanForward(&where, (uint32_t)(a))) + return (int)(where); + // Scan the High Word. + if (_BitScanForward(&where, (uint32_t)(a >> 32))) + return (int)(where + 32); // Create a bit offset from the LSB. +#endif + return 64; +#else + return __builtin_ctzll(a); +#endif } +#ifdef _MSC_VER +#pragma pack(push, 1) +struct packed_u64 { + uint64_t v; +}; + +struct packed_u32 { + uint32_t v; +}; + +struct packed_u16 { + uint16_t v; +}; +#pragma pack(pop) +#else struct __attribute__((packed)) packed_u64 { uint64_t v; }; @@ -146,6 +235,7 @@ struct __attribute__((packed)) packed_u32 { struct __attribute__((packed)) packed_u16 { uint16_t v; }; +#endif static inline uint64_t get_u64(const uint8_t *tab) { @@ -262,8 +352,7 @@ static inline int dbuf_put_u64(DynBuf *s, uint64_t val) { return dbuf_put(s, (uint8_t *)&val, 8); } -int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, - const char *fmt, ...); +int printf_like(2, 3) dbuf_printf(DynBuf *s, const char *fmt, ...); void dbuf_free(DynBuf *s); static inline BOOL dbuf_error(DynBuf *s) { return s->error; diff --git a/doc/jsx.md b/doc/jsx.md new file mode 100644 index 000000000..f8ad0c181 --- /dev/null +++ b/doc/jsx.md @@ -0,0 +1,105 @@ +# JSX - JavaScript XML/HTML language extensions + +Basic idea, this JS+X expression: + +```javascript +var data =
Hello world!
; +``` +Gets parsed into code equivalent to this: + +```javascript +var data = JSX("div", {id:"foo"}, ["Hello world"]]); +``` +Where JSX is a global function, so called "JSX driver", defined elsewhere with the following signature: + +```javascript +function JSX(tag,atts,kids) {...} +``` +where: + +* `tag` - string, tag name: "div","p", ...; +* `atts` - object, element attributes: `{id:"foo"}` +* `kids` - array, child sub elements - strings or results of sub-calls of JSX. + +# Use cases + +JSX can be used with popular JS UI libraries as it is. + +## [Mithril](https://mithril.js.org) + +This canonic Mithril sample: +```javascript +var count = 0 // added a variable + +var Hello = { + view: function() { + return m("main", [ + m("h1", {class: "title"}, "My first app"), + // changed the next line + m("button", {onclick: function() {count++}}, count + " clicks"), + ]) + } +} + +m.mount(root, Hello) +``` + +Can be rewritten using JS+X in more natural way as: + +```javascript + +JSX = m; // using m() mithril function "as it is" as JSX driver! + +var count = 0 // added a variable + +var Hello = { + view: function() { + return
+

My first app

+ +
+ } +} + +m.mount(root, Hello) +``` + +## [ReactJS](https://reactjs.org/) + +ReactJS shall also be able to use JSX as it is, it is just a matter of declaring + +```javascript + +JSX = React.createElement; // using ReactJS VNode creator as JSX driver +``` + +# JSX syntax details + +1. Tags and attribute names shall follow JS/XML naming convention and may contain `-` (dashes) inside. +2. Attributes and element content may contain expressions enclosed into `{` and `}` brackets: + +```javascript +var className = "foo"; +var listItems = ["one","two", "three"]; + +function renderList() { + return
    + { listItems.map( item =>
  • {item}
  • ) } +
+} +``` +to generate list: +```html +
    +
  • one
  • +
  • two
  • +
  • three
  • +
+``` + +# To enable JSX support + +To enable JSX support on QuickJS from this repository define CONFIG_JSX option while compiling. + +[premake5.lua](https://github.com/c-smile/quickjspp/blob/master/premake5.lua#L23) script already defines CONFIG_JSX. + diff --git a/doc/quickjs.html b/doc/quickjs.html index e8b33695e..cd07ed7ec 100644 --- a/doc/quickjs.html +++ b/doc/quickjs.html @@ -611,6 +611,19 @@

3.3.2 std module

undefined if it is not defined.

+
setenv(name, value)
+

Set the value of the environment variable name to the string +value. +

+
+
unsetenv(name)
+

Delete the environment variable name. +

+
+
getenviron()
+

Return an object containing the environment variables as key-value pairs. +

+
urlGet(url, options = undefined)

Download url using the curl command line @@ -707,7 +720,7 @@

3.3.2 std module

write(buffer, position, length)

Write length bytes to the file from the ArrayBuffer buffer at byte -position position (wrapper to the libc fread). +position position (wrapper to the libc fwrite).

getline()
@@ -1123,10 +1136,11 @@

3.4.6 JS Classes

JS_GetOpaque()/JS_SetOpaque().

When defining a new JS class, it is possible to declare a finalizer -which is called when the object is destroyed. A gc_mark method -can be provided so that the cycle removal algorithm can find the other -objects referenced by this object. Other methods are available to -define exotic object behaviors. +which is called when the object is destroyed. The finalizer should be +used to release C resources. It is invalid to execute JS code from +it. A gc_mark method can be provided so that the cycle removal +algorithm can find the other objects referenced by this object. Other +methods are available to define exotic object behaviors.

The Class ID are globally allocated (i.e. for all runtimes). The JSClass are allocated per JSRuntime. JS_SetClassProto() diff --git a/doc/quickjs.pdf b/doc/quickjs.pdf index 497964bc8..53c8e7345 100644 Binary files a/doc/quickjs.pdf and b/doc/quickjs.pdf differ diff --git a/doc/quickjs.texi b/doc/quickjs.texi index 57d13e64c..9eb6354b3 100644 --- a/doc/quickjs.texi +++ b/doc/quickjs.texi @@ -452,6 +452,16 @@ useful in case of specific memory constraints or for testing. Return the value of the environment variable @code{name} or @code{undefined} if it is not defined. +@item setenv(name, value) +Set the value of the environment variable @code{name} to the string +@code{value}. + +@item unsetenv(name) +Delete the environment variable @code{name}. + +@item getenviron() +Return an object containing the environment variables as key-value pairs. + @item urlGet(url, options = undefined) Download @code{url} using the @file{curl} command line @@ -532,7 +542,7 @@ position @code{position} (wrapper to the libc @code{fread}). @item write(buffer, position, length) Write @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte -position @code{position} (wrapper to the libc @code{fread}). +position @code{position} (wrapper to the libc @code{fwrite}). @item getline() Return the next line from the file, assuming UTF-8 encoding, excluding @@ -886,10 +896,11 @@ set the C opaque point with @code{JS_GetOpaque()}/@code{JS_SetOpaque()}. When defining a new JS class, it is possible to declare a finalizer -which is called when the object is destroyed. A @code{gc_mark} method -can be provided so that the cycle removal algorithm can find the other -objects referenced by this object. Other methods are available to -define exotic object behaviors. +which is called when the object is destroyed. The finalizer should be +used to release C resources. It is invalid to execute JS code from +it. A @code{gc_mark} method can be provided so that the cycle removal +algorithm can find the other objects referenced by this object. Other +methods are available to define exotic object behaviors. The Class ID are globally allocated (i.e. for all runtimes). The JSClass are allocated per @code{JSRuntime}. @code{JS_SetClassProto()} diff --git a/libbf.c b/libbf.c index 3bf257a15..fe1628e79 100644 --- a/libbf.c +++ b/libbf.c @@ -1,7 +1,7 @@ /* * Tiny arbitrary precision floating point library * - * Copyright (c) 2017-2020 Fabrice Bellard + * Copyright (c) 2017-2021 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/libbf.h b/libbf.h index 6749b35c6..fdbd6b6d3 100644 --- a/libbf.h +++ b/libbf.h @@ -1,7 +1,7 @@ /* * Tiny arbitrary precision floating point library * - * Copyright (c) 2017-2020 Fabrice Bellard + * Copyright (c) 2017-2021 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/libregexp.c b/libregexp.c index bbb5e9d70..379bfc7a9 100644 --- a/libregexp.c +++ b/libregexp.c @@ -75,7 +75,7 @@ typedef struct { int capture_count; int total_capture_count; /* -1 = not computed yet */ int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */ - void *mem_opaque; + void *opaque; DynBuf group_names; union { char error_msg[TMP_BUF_SIZE]; @@ -230,7 +230,7 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c) invert = c & 1; c_pt = char_range_table[c >> 1]; len = *c_pt++; - cr_init(cr, s->mem_opaque, lre_realloc); + cr_init(cr, s->opaque, lre_realloc); for(i = 0; i < len * 2; i++) { if (cr_add_point(cr, c_pt[i])) goto fail; @@ -625,7 +625,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr, p++; q = name; while (is_unicode_char(*p)) { - if ((q - name) > sizeof(name) - 1) + if ((q - name) >= sizeof(name) - 1) goto unknown_property_name; *q++ = *p++; } @@ -634,7 +634,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr, if (*p == '=') { p++; while (is_unicode_char(*p)) { - if ((q - value) > sizeof(value) - 1) + if ((q - value) >= sizeof(value) - 1) return re_parse_error(s, "unknown unicode property value"); *q++ = *p++; } @@ -651,7 +651,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr, } else if (!strcmp(name, "Script_Extensions") || !strcmp(name, "scx")) { script_ext = TRUE; do_script: - cr_init(cr, s->mem_opaque, lre_realloc); + cr_init(cr, s->opaque, lre_realloc); ret = unicode_script(cr, value, script_ext); if (ret) { cr_free(cr); @@ -661,7 +661,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr, goto out_of_memory; } } else if (!strcmp(name, "General_Category") || !strcmp(name, "gc")) { - cr_init(cr, s->mem_opaque, lre_realloc); + cr_init(cr, s->opaque, lre_realloc); ret = unicode_general_category(cr, value); if (ret) { cr_free(cr); @@ -671,7 +671,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr, goto out_of_memory; } } else if (value[0] == '\0') { - cr_init(cr, s->mem_opaque, lre_realloc); + cr_init(cr, s->opaque, lre_realloc); ret = unicode_general_category(cr, name); if (ret == -1) { cr_free(cr); @@ -864,7 +864,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) CharRange cr1_s, *cr1 = &cr1_s; BOOL invert; - cr_init(cr, s->mem_opaque, lre_realloc); + cr_init(cr, s->opaque, lre_realloc); p = *pp; p++; /* skip '[' */ invert = FALSE; @@ -1147,9 +1147,13 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures, } } capture_index++; + if (capture_index >= CAPTURE_COUNT_MAX) + goto done; } } else { capture_index++; + if (capture_index >= CAPTURE_COUNT_MAX) + goto done; } break; case '\\': @@ -1163,6 +1167,7 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures, break; } } + done: if (capture_name) return -1; else @@ -1734,6 +1739,9 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir) { int start, len, pos; + if (lre_check_stack_overflow(s->opaque, 0)) + return re_parse_error(s, "stack overflow"); + start = s->byte_code.size; if (re_parse_alternative(s, is_backward_dir)) return -1; @@ -1819,7 +1827,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, BOOL is_sticky; memset(s, 0, sizeof(*s)); - s->mem_opaque = opaque; + s->opaque = opaque; s->buf_ptr = (const uint8_t *)buf; s->buf_end = s->buf_ptr + buf_len; s->buf_start = s->buf_ptr; diff --git a/premake5.lua b/premake5.lua new file mode 100644 index 000000000..a77ed0d63 --- /dev/null +++ b/premake5.lua @@ -0,0 +1,154 @@ + +(function() + -- generate "quickjs-version.h" using VERSION file + local file = io.open("VERSION", "r") + local vers = file:read() + file:close() + vars = vers:gsub("%s+", "") + file = io.open("quickjs-version.h", "w+") + file:write("#define QUICKJS_VERSION \"" .. vers .. "\"") + file:close() +end)() + + +newoption { + trigger = "jsx", + description = "Will add JSX support" +} + +newoption { + trigger = "storage", + description = "Will add persistent storage support" +} + +workspace "quickjs" + -- Premake output folder + location(path.join(".build", _ACTION)) + + defines { + "JS_STRICT_NAN_BOXING", -- this option enables x64 build on Windows/MSVC + "CONFIG_BIGNUM" + } + + if _OPTIONS["jsx"] then + defines { "CONFIG_JSX" } -- native JSX support - enables JSX literals + end + + if _OPTIONS["storage"] then + defines { "CONFIG_STORAGE" } -- persistent storage support + end + + + platforms { "x86", "x64", "arm32", "arm64" } + + -- Configuration settings + configurations { "Debug", "Release" } + + filter "platforms:x86" + architecture "x86" + filter "platforms:x64" + architecture "x86_64" + filter "platforms:arm32" + architecture "ARM" + filter "platforms:arm64" + architecture "ARM64" + + filter "system:windows" + removeplatforms { "arm32" } + + -- Debug configuration + filter { "configurations:Debug" } + defines { "DEBUG" } + symbols "On" + optimize "Off" + + -- Release configuration + filter { "configurations:Release" } + defines { "NDEBUG" } + optimize "Speed" + inlining "Auto" + + -- Should apply only for Visual C++ + filter { "language:not C#" and "toolset:msc" } + defines { "_CRT_SECURE_NO_WARNINGS" } + buildoptions { "/std:c++latest" } + systemversion "latest" + + filter { } + targetdir ".bin/%{cfg.buildcfg}/%{cfg.platform }" + exceptionhandling "Off" + rtti "Off" + --vectorextensions "AVX2" + +----------------------------------------------------------------------------------------------------------------------- + +project "quickjs" + language "C" + kind "StaticLib" + files { + "cutils.h", + "cutils.c", + "libregexp.c", + "libunicode.c", + "quickjs.c", + "quickjs-libc.c", + "libbf.c", + "libregexp.h", + "libregexp-opcode.h", + "libunicode.h", + "libunicode-table.h", + "list.h", + "quickjs.h", + "quickjs-atom.h", + "quickjs-libc.h", + "quickjs-opcode.h", + "quickjs-jsx.h", + } + + +if _OPTIONS["storage"] then + exceptionhandling "On" + files { + "storage/quickjs-storage.c", + "storage/quickjs-storage.h", + "storage/dybase/src/*.cpp", + "storage/dybase/src/*.h", + "storage/dybase/include/*.h" + } + includedirs { + "storage/dybase/include" + } +end + +----------------------------------------------------------------------------------------------------------------------- + +project "qjsc" + language "C" + kind "ConsoleApp" + links { "quickjs" } + files { + "qjsc.c" + } + filter { "action:gmake*", "toolset:gcc" } + links { "dl", "pthread" } + +----------------------------------------------------------------------------------------------------------------------- + +project "qjs" + language "C" + kind "ConsoleApp" + links { "quickjs" } + dependson { "qjsc" } + files { + "qjs.c", + "repl.js", + "repl.c", + "qjscalc.js", + "qjscalc.c" + } + filter { "action:gmake*", "toolset:gcc" } + links { "dl", "pthread" } + +-- Compile repl.js and save bytecode into repl.c +prebuildcommands { "\"%{cfg.buildtarget.directory}/qjsc.exe\" -c -o \"../../repl.c\" -m \"../../repl.js\"" } +prebuildcommands { "\"%{cfg.buildtarget.directory}/qjsc.exe\" -c -o \"../../qjscalc.c\" -m \"../../qjscalc.js\"" } diff --git a/qjs.c b/qjs.c index 4dd11f83b..5dcd7539c 100644 --- a/qjs.c +++ b/qjs.c @@ -28,18 +28,23 @@ #include #include #include -#include #include #include #include #if defined(__APPLE__) #include +#include #elif defined(__linux__) #include +#include #endif #include "cutils.h" #include "quickjs-libc.h" +#ifdef CONFIG_STORAGE +#include "storage/quickjs-storage.h" +#endif +#include "quickjs-version.h" extern const uint8_t qjsc_repl[]; extern const uint32_t qjsc_repl_size; @@ -120,6 +125,9 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt) /* system modules */ js_init_module_std(ctx, "std"); js_init_module_os(ctx, "os"); +#ifdef CONFIG_STORAGE + js_init_module_storage(ctx, "storage"); +#endif return ctx; } @@ -276,7 +284,7 @@ static const JSMallocFunctions trace_mf = { void help(void) { - printf("QuickJS version " CONFIG_VERSION "\n" + printf("QuickJS version " QUICKJS_VERSION "\n" "usage: " PROG_NAME " [options] [file [args]]\n" "-h --help list options\n" "-e --eval EXPR evaluate EXPR\n" diff --git a/qjsc.c b/qjsc.c index f5bda57f6..bea101a29 100644 --- a/qjsc.c +++ b/qjsc.c @@ -27,14 +27,21 @@ #include #include #include -#include #include #if !defined(_WIN32) #include + #include +#else + #if !defined(__MINGW32__) + #include "win/getopt.h" + #else + #include + #endif #endif #include "cutils.h" #include "quickjs-libc.h" +#include "quickjs-version.h" typedef struct { char *name; @@ -241,7 +248,7 @@ JSModuleDef *jsc_module_loader(JSContext *ctx, namelist_add(&init_module_list, e->name, e->short_name, 0); /* create a dummy module */ m = JS_NewCModule(ctx, module_name, js_module_dummy_init); - } else if (has_suffix(module_name, ".so")) { + } else if (has_suffix(module_name, NATIVE_MODULE_SUFFIX)) { fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name); /* create a dummy module */ m = JS_NewCModule(ctx, module_name, js_module_dummy_init); @@ -341,7 +348,7 @@ static const char main_c_template2[] = void help(void) { - printf("QuickJS Compiler version " CONFIG_VERSION "\n" + printf("QuickJS Compiler version " QUICKJS_VERSION "\n" "usage: " PROG_NAME " [options] [files]\n" "\n" "options are:\n" @@ -760,3 +767,5 @@ int main(int argc, char **argv) namelist_free(&init_module_list); return 0; } + +#undef NATIVE_MODULE_SUFFIX \ No newline at end of file diff --git a/qjscalc.c b/qjscalc.c new file mode 100644 index 000000000..22dd82c77 --- /dev/null +++ b/qjscalc.c @@ -0,0 +1,3815 @@ +/* File generated automatically by the QuickJS compiler. */ + +#include + +const uint32_t qjsc_qjscalc_size = 30448; + +const uint8_t qjsc_qjscalc[30448] = { + 0x02, 0xb8, 0x02, 0x20, 0x2e, 0x2e, 0x2f, 0x2e, + 0x2e, 0x2f, 0x71, 0x6a, 0x73, 0x63, 0x61, 0x6c, + 0x63, 0x2e, 0x6a, 0x73, 0x0e, 0x49, 0x6e, 0x74, + 0x65, 0x67, 0x65, 0x72, 0x0a, 0x46, 0x6c, 0x6f, + 0x61, 0x74, 0x10, 0x46, 0x72, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x0e, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x78, 0x06, 0x4d, 0x6f, 0x64, 0x14, + 0x50, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, + 0x61, 0x6c, 0x0e, 0x50, 0x6f, 0x6c, 0x79, 0x4d, + 0x6f, 0x64, 0x20, 0x52, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x0c, 0x53, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x0c, 0x4d, 0x61, 0x74, 0x72, 0x69, + 0x78, 0x02, 0x49, 0x02, 0x58, 0x02, 0x4f, 0x06, + 0x67, 0x63, 0x64, 0x08, 0x66, 0x61, 0x63, 0x74, + 0x08, 0x63, 0x6f, 0x6d, 0x62, 0x08, 0x70, 0x6d, + 0x6f, 0x64, 0x0c, 0x69, 0x6e, 0x76, 0x6d, 0x6f, + 0x64, 0x0c, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x0e, 0x69, 0x73, 0x70, 0x72, 0x69, 0x6d, 0x65, + 0x12, 0x6e, 0x65, 0x78, 0x74, 0x70, 0x72, 0x69, + 0x6d, 0x65, 0x0a, 0x64, 0x65, 0x72, 0x69, 0x76, + 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x0a, 0x6e, + 0x6f, 0x72, 0x6d, 0x32, 0x06, 0x61, 0x62, 0x73, + 0x08, 0x63, 0x6f, 0x6e, 0x6a, 0x06, 0x61, 0x72, + 0x67, 0x0e, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x65, 0x0a, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x0a, + 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x08, 0x63, 0x65, + 0x69, 0x6c, 0x08, 0x73, 0x71, 0x72, 0x74, 0x06, + 0x65, 0x78, 0x70, 0x06, 0x6c, 0x6f, 0x67, 0x08, + 0x6c, 0x6f, 0x67, 0x32, 0x0a, 0x6c, 0x6f, 0x67, + 0x31, 0x30, 0x08, 0x74, 0x6f, 0x64, 0x62, 0x0c, + 0x66, 0x72, 0x6f, 0x6d, 0x64, 0x62, 0x06, 0x73, + 0x69, 0x6e, 0x06, 0x63, 0x6f, 0x73, 0x06, 0x74, + 0x61, 0x6e, 0x08, 0x61, 0x73, 0x69, 0x6e, 0x08, + 0x61, 0x63, 0x6f, 0x73, 0x08, 0x61, 0x74, 0x61, + 0x6e, 0x0a, 0x61, 0x74, 0x61, 0x6e, 0x32, 0x08, + 0x73, 0x69, 0x6e, 0x63, 0x0a, 0x74, 0x6f, 0x64, + 0x65, 0x67, 0x0e, 0x66, 0x72, 0x6f, 0x6d, 0x64, + 0x65, 0x67, 0x08, 0x73, 0x69, 0x6e, 0x68, 0x08, + 0x63, 0x6f, 0x73, 0x68, 0x08, 0x74, 0x61, 0x6e, + 0x68, 0x0a, 0x61, 0x73, 0x69, 0x6e, 0x68, 0x0a, + 0x61, 0x63, 0x6f, 0x73, 0x68, 0x0a, 0x61, 0x74, + 0x61, 0x6e, 0x68, 0x0e, 0x73, 0x69, 0x67, 0x6d, + 0x6f, 0x69, 0x64, 0x08, 0x6c, 0x65, 0x72, 0x70, + 0x06, 0x69, 0x64, 0x6e, 0x08, 0x64, 0x69, 0x61, + 0x67, 0x0a, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x0a, + 0x74, 0x72, 0x61, 0x63, 0x65, 0x10, 0x63, 0x68, + 0x61, 0x72, 0x70, 0x6f, 0x6c, 0x79, 0x12, 0x65, + 0x69, 0x67, 0x65, 0x6e, 0x76, 0x61, 0x6c, 0x73, + 0x06, 0x64, 0x65, 0x74, 0x08, 0x72, 0x61, 0x6e, + 0x6b, 0x06, 0x6b, 0x65, 0x72, 0x04, 0x63, 0x70, + 0x04, 0x64, 0x70, 0x10, 0x70, 0x6f, 0x6c, 0x72, + 0x6f, 0x6f, 0x74, 0x73, 0x10, 0x62, 0x65, 0x73, + 0x74, 0x61, 0x70, 0x70, 0x72, 0x04, 0x50, 0x49, + 0x0e, 0x69, 0x73, 0x50, 0x72, 0x69, 0x6d, 0x65, + 0x12, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x69, + 0x6d, 0x65, 0x0a, 0x72, 0x6f, 0x6f, 0x74, 0x73, + 0x12, 0x61, 0x64, 0x64, 0x5f, 0x70, 0x72, 0x6f, + 0x70, 0x73, 0x1a, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x73, 0x65, 0x74, + 0x16, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, + 0x5f, 0x70, 0x6f, 0x77, 0x18, 0x73, 0x6d, 0x61, + 0x6c, 0x6c, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x65, + 0x73, 0x22, 0x6d, 0x69, 0x6c, 0x6c, 0x65, 0x72, + 0x5f, 0x72, 0x61, 0x62, 0x69, 0x6e, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x10, 0x66, 0x61, 0x63, 0x74, + 0x5f, 0x72, 0x65, 0x63, 0x18, 0x66, 0x72, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, + 0x64, 0x18, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x73, 0x75, 0x62, 0x18, 0x66, + 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6d, 0x75, 0x6c, 0x18, 0x66, 0x72, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x76, + 0x18, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6d, 0x6f, 0x64, 0x16, 0x66, 0x72, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, + 0x71, 0x16, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6c, 0x74, 0x12, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x12, + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, 0x73, 0x75, + 0x62, 0x12, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, + 0x6d, 0x75, 0x6c, 0x12, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x5f, 0x64, 0x69, 0x76, 0x12, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x12, + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, 0x70, 0x6f, + 0x77, 0x10, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, + 0x65, 0x71, 0x10, 0x66, 0x6c, 0x6f, 0x61, 0x74, + 0x5f, 0x6c, 0x74, 0x12, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x5f, 0x74, 0x61, 0x62, 0x12, 0x67, 0x65, + 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x16, + 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, + 0x61, 0x64, 0x64, 0x16, 0x63, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x75, 0x62, 0x16, + 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, + 0x6d, 0x75, 0x6c, 0x16, 0x63, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x78, 0x5f, 0x64, 0x69, 0x76, 0x14, + 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, + 0x65, 0x71, 0x0e, 0x6d, 0x6f, 0x64, 0x5f, 0x61, + 0x64, 0x64, 0x0e, 0x6d, 0x6f, 0x64, 0x5f, 0x73, + 0x75, 0x62, 0x0e, 0x6d, 0x6f, 0x64, 0x5f, 0x6d, + 0x75, 0x6c, 0x0e, 0x6d, 0x6f, 0x64, 0x5f, 0x64, + 0x69, 0x76, 0x0c, 0x6d, 0x6f, 0x64, 0x5f, 0x65, + 0x71, 0x28, 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, + 0x6d, 0x69, 0x61, 0x6c, 0x5f, 0x69, 0x73, 0x5f, + 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x22, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x6e, 0x65, + 0x65, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x22, 0x6d, 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x61, + 0x6c, 0x5f, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x26, 0x70, 0x6f, 0x6c, 0x79, 0x5f, + 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6c, 0x61, 0x67, + 0x75, 0x65, 0x72, 0x72, 0x65, 0x31, 0x14, 0x70, + 0x6f, 0x6c, 0x79, 0x5f, 0x72, 0x6f, 0x6f, 0x74, + 0x73, 0x1c, 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, + 0x6d, 0x69, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, + 0x1c, 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, + 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x1c, + 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, + 0x61, 0x6c, 0x5f, 0x6d, 0x75, 0x6c, 0x2a, 0x70, + 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, + 0x6c, 0x5f, 0x64, 0x69, 0x76, 0x5f, 0x73, 0x63, + 0x61, 0x6c, 0x61, 0x72, 0x1c, 0x70, 0x6f, 0x6c, + 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x5f, + 0x64, 0x69, 0x76, 0x1c, 0x70, 0x6f, 0x6c, 0x79, + 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x5f, 0x6d, + 0x6f, 0x64, 0x1a, 0x70, 0x6f, 0x6c, 0x79, 0x6e, + 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x5f, 0x65, 0x71, + 0x16, 0x70, 0x6f, 0x6c, 0x79, 0x6d, 0x6f, 0x64, + 0x5f, 0x61, 0x64, 0x64, 0x16, 0x70, 0x6f, 0x6c, + 0x79, 0x6d, 0x6f, 0x64, 0x5f, 0x73, 0x75, 0x62, + 0x16, 0x70, 0x6f, 0x6c, 0x79, 0x6d, 0x6f, 0x64, + 0x5f, 0x6d, 0x75, 0x6c, 0x16, 0x70, 0x6f, 0x6c, + 0x79, 0x6d, 0x6f, 0x64, 0x5f, 0x64, 0x69, 0x76, + 0x14, 0x70, 0x6f, 0x6c, 0x79, 0x6d, 0x6f, 0x64, + 0x5f, 0x65, 0x71, 0x16, 0x72, 0x61, 0x74, 0x66, + 0x75, 0x6e, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x16, + 0x72, 0x61, 0x74, 0x66, 0x75, 0x6e, 0x63, 0x5f, + 0x73, 0x75, 0x62, 0x16, 0x72, 0x61, 0x74, 0x66, + 0x75, 0x6e, 0x63, 0x5f, 0x6d, 0x75, 0x6c, 0x16, + 0x72, 0x61, 0x74, 0x66, 0x75, 0x6e, 0x63, 0x5f, + 0x64, 0x69, 0x76, 0x14, 0x72, 0x61, 0x74, 0x66, + 0x75, 0x6e, 0x63, 0x5f, 0x65, 0x71, 0x10, 0x67, + 0x65, 0x74, 0x5f, 0x65, 0x6d, 0x69, 0x6e, 0x3c, + 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x69, + 0x73, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, + 0x5f, 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x79, + 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x14, 0x73, + 0x65, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x61, 0x64, + 0x64, 0x14, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x5f, 0x73, 0x75, 0x62, 0x14, 0x73, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x14, + 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x64, + 0x69, 0x76, 0x14, 0x73, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x5f, 0x70, 0x6f, 0x77, 0x12, 0x73, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x5f, 0x65, 0x71, 0x12, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x61, 0x64, + 0x64, 0x12, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, + 0x73, 0x75, 0x62, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, + 0x5f, 0x6d, 0x75, 0x6c, 0x12, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x5f, 0x6d, 0x75, 0x6c, 0x12, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x5f, 0x64, 0x69, 0x76, + 0x34, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x77, + 0x69, 0x73, 0x65, 0x5f, 0x69, 0x6e, 0x76, 0x65, + 0x72, 0x73, 0x65, 0x10, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x5f, 0x65, 0x71, 0x1a, 0x61, 0x6c, 0x67, + 0x65, 0x62, 0x72, 0x61, 0x69, 0x63, 0x4d, 0x6f, + 0x64, 0x65, 0x2a, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x42, 0x69, 0x67, 0x49, 0x6e, 0x74, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, + 0x02, 0x2f, 0x04, 0x2a, 0x2a, 0x12, 0x69, 0x73, + 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x02, + 0x2b, 0x02, 0x2d, 0x02, 0x25, 0x04, 0x3d, 0x3d, + 0x02, 0x3c, 0x06, 0x70, 0x6f, 0x73, 0x06, 0x6e, + 0x65, 0x67, 0x08, 0x6c, 0x65, 0x66, 0x74, 0x0a, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x14, 0x74, 0x6f, + 0x46, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x16, 0x74, 0x6f, 0x50, 0x72, 0x69, 0x6d, 0x69, + 0x74, 0x69, 0x76, 0x65, 0x0e, 0x69, 0x73, 0x46, + 0x6c, 0x6f, 0x61, 0x74, 0x02, 0x45, 0x08, 0x4c, + 0x4e, 0x31, 0x30, 0x0a, 0x4c, 0x4f, 0x47, 0x32, + 0x45, 0x0c, 0x4c, 0x4f, 0x47, 0x31, 0x30, 0x45, + 0x0e, 0x53, 0x51, 0x52, 0x54, 0x31, 0x5f, 0x32, + 0x0a, 0x53, 0x51, 0x52, 0x54, 0x32, 0x12, 0x74, + 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, + 0x08, 0x74, 0x72, 0x69, 0x6d, 0x06, 0x64, 0x65, + 0x67, 0x0c, 0x64, 0x69, 0x76, 0x72, 0x65, 0x6d, + 0x24, 0x74, 0x6f, 0x52, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x08, 0x7a, 0x65, 0x72, 0x6f, + 0x0e, 0x68, 0x69, 0x6c, 0x62, 0x65, 0x72, 0x74, + 0x18, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x73, + 0x71, 0x75, 0x61, 0x72, 0x65, 0x06, 0x64, 0x75, + 0x70, 0x06, 0x6f, 0x62, 0x6a, 0x0a, 0x70, 0x72, + 0x6f, 0x70, 0x73, 0x02, 0x69, 0x06, 0x76, 0x61, + 0x6c, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x06, 0x74, + 0x61, 0x62, 0x08, 0x64, 0x65, 0x73, 0x63, 0x0e, + 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x0a, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x0e, 0x6f, 0x70, + 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x16, 0x6e, 0x65, + 0x77, 0x5f, 0x6f, 0x70, 0x5f, 0x6c, 0x69, 0x73, + 0x74, 0x02, 0x61, 0x02, 0x6a, 0x02, 0x62, 0x02, + 0x6b, 0x0c, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, + 0x0e, 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, + 0x0c, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x08, + 0x70, 0x75, 0x73, 0x68, 0x16, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x65, 0x74, + 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x08, + 0x63, 0x61, 0x6c, 0x6c, 0x02, 0x72, 0x0c, 0x69, + 0x73, 0x5f, 0x6e, 0x65, 0x67, 0x12, 0x66, 0x6c, + 0x6f, 0x6f, 0x72, 0x4c, 0x6f, 0x67, 0x32, 0x5e, + 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x20, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x74, 0x79, 0x70, 0x65, 0x02, + 0x6e, 0x02, 0x74, 0x02, 0x64, 0x02, 0x73, 0x1a, + 0x69, 0x73, 0x53, 0x61, 0x66, 0x65, 0x49, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x08, 0x74, 0x64, + 0x69, 0x76, 0x02, 0x78, 0x02, 0x79, 0x02, 0x71, + 0x02, 0x75, 0x02, 0x76, 0x02, 0x63, 0x0e, 0x66, + 0x64, 0x69, 0x76, 0x72, 0x65, 0x6d, 0x1c, 0x6e, + 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x76, 0x65, 0x72, + 0x74, 0x69, 0x62, 0x6c, 0x65, 0x02, 0x6d, 0x04, + 0x6e, 0x31, 0x18, 0x69, 0x6e, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x20, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, + 0x72, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, + 0x72, 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x20, 0x64, 0x69, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x79, 0x20, 0x7a, + 0x65, 0x72, 0x6f, 0x06, 0x6e, 0x75, 0x6d, 0x06, + 0x64, 0x65, 0x6e, 0x04, 0x61, 0x31, 0x04, 0x62, + 0x31, 0x08, 0x65, 0x64, 0x69, 0x76, 0x0a, 0x69, + 0x73, 0x4e, 0x61, 0x4e, 0x08, 0x68, 0x69, 0x6e, + 0x74, 0x02, 0x70, 0x08, 0x70, 0x72, 0x65, 0x63, + 0x08, 0x6e, 0x75, 0x6d, 0x31, 0x08, 0x6e, 0x75, + 0x6d, 0x30, 0x08, 0x64, 0x65, 0x6e, 0x31, 0x08, + 0x64, 0x65, 0x6e, 0x30, 0x30, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x78, 0x70, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x04, 0x72, 0x65, + 0x04, 0x69, 0x6d, 0x04, 0x2d, 0x49, 0x04, 0x2a, + 0x49, 0x32, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, + 0x64, 0x75, 0x6c, 0x6f, 0x20, 0x63, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x3c, + 0x3d, 0x20, 0x30, 0x1a, 0x69, 0x6e, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x06, 0x72, 0x65, 0x73, 0x06, 0x6d, 0x6f, + 0x64, 0x48, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x6f, 0x64, 0x75, + 0x6c, 0x6f, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, + 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x75, + 0x6e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x08, + 0x4d, 0x6f, 0x64, 0x28, 0x02, 0x2c, 0x02, 0x29, + 0x08, 0x73, 0x74, 0x72, 0x31, 0x02, 0x28, 0x02, + 0x5e, 0x02, 0x7a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, + 0x69, 0x74, 0x04, 0x70, 0x31, 0x04, 0x70, 0x32, + 0x04, 0x7a, 0x30, 0x04, 0x7a, 0x31, 0x04, 0x7a, + 0x32, 0x04, 0x74, 0x30, 0x04, 0x74, 0x31, 0x04, + 0x64, 0x31, 0x04, 0x64, 0x32, 0x02, 0x65, 0x04, + 0x65, 0x6c, 0x04, 0x7a, 0x6c, 0x06, 0x65, 0x70, + 0x73, 0x18, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x26, 0x70, + 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, + 0x6c, 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x3e, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x20, 0x69, 0x6e, 0x20, 0x72, 0x6f, 0x6f, 0x74, + 0x20, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x20, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, + 0x68, 0x6d, 0x06, 0x73, 0x74, 0x72, 0x10, 0x49, + 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x06, + 0x74, 0x6d, 0x70, 0x04, 0x6e, 0x32, 0x48, 0x74, + 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, + 0x6f, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, + 0x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x20, 0x3c, + 0x3d, 0x20, 0x30, 0x10, 0x50, 0x6f, 0x6c, 0x79, + 0x4d, 0x6f, 0x64, 0x28, 0x04, 0x2f, 0x28, 0x08, + 0x65, 0x6d, 0x69, 0x6e, 0x06, 0x6d, 0x69, 0x6e, + 0x04, 0x76, 0x31, 0x04, 0x76, 0x32, 0x0e, 0x76, + 0x32, 0x5f, 0x65, 0x6d, 0x69, 0x6e, 0x04, 0x63, + 0x31, 0x04, 0x63, 0x32, 0x06, 0x73, 0x75, 0x6d, + 0x04, 0x4f, 0x28, 0x36, 0x63, 0x61, 0x6e, 0x6e, + 0x6f, 0x74, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x28, 0x31, 0x2f, 0x58, 0x29, 0x30, + 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x20, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, + 0x74, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x78, 0x70, + 0x5e, 0x6c, 0x6f, 0x67, 0x20, 0x61, 0x72, 0x67, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x75, + 0x73, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x7a, 0x65, + 0x72, 0x6f, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x74, 0x20, 0x74, 0x65, 0x72, 0x6d, + 0x0c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4f, 0x28, + 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, + 0x4f, 0x28, 0x29, 0x20, 0x61, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x02, 0x68, 0x02, 0x77, + 0x04, 0x72, 0x6c, 0x1e, 0x6d, 0x61, 0x74, 0x72, + 0x69, 0x78, 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x1c, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, + 0x65, 0x64, 0x2c, 0x73, 0x71, 0x75, 0x61, 0x72, + 0x65, 0x20, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, + 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x08, 0x63, 0x6f, 0x65, 0x66, 0x06, 0x73, + 0x72, 0x63, 0x06, 0x64, 0x73, 0x74, 0x30, 0x6d, + 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x69, 0x73, + 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x76, + 0x65, 0x72, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x02, + 0x6c, 0x0e, 0x69, 0x6d, 0x5f, 0x63, 0x6f, 0x6c, + 0x73, 0x0e, 0x6b, 0x65, 0x72, 0x5f, 0x64, 0x69, + 0x6d, 0x32, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x20, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x38, 0x76, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x33, 0x20, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x74, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x20, 0x73, 0x69, 0x7a, 0x65, + 0x0a, 0x61, 0x5f, 0x6d, 0x61, 0x74, 0x0a, 0x62, + 0x5f, 0x6d, 0x61, 0x74, 0x30, 0x69, 0x6e, 0x63, + 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, + 0x65, 0x20, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, + 0x20, 0x73, 0x69, 0x7a, 0x65, 0x08, 0x66, 0x64, + 0x69, 0x76, 0x08, 0x63, 0x64, 0x69, 0x76, 0x0f, + 0xc6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x06, 0x01, 0xa6, 0x01, 0x00, 0x01, 0x00, 0x06, + 0x45, 0x25, 0xd2, 0x03, 0x01, 0x10, 0x00, 0x01, + 0x00, 0xc8, 0x03, 0x00, 0x01, 0xca, 0x03, 0x01, + 0x01, 0xcc, 0x03, 0x02, 0x01, 0xce, 0x03, 0x03, + 0x01, 0xd0, 0x03, 0x04, 0x01, 0xd2, 0x03, 0x05, + 0x01, 0xd4, 0x03, 0x06, 0x01, 0xd6, 0x03, 0x07, + 0x01, 0xd8, 0x03, 0x08, 0x01, 0xda, 0x03, 0x09, + 0x01, 0xdc, 0x03, 0x0a, 0x01, 0xde, 0x03, 0x0b, + 0x01, 0xe0, 0x03, 0x0c, 0x01, 0xe2, 0x03, 0x0d, + 0x01, 0xe4, 0x03, 0x0e, 0x01, 0xe6, 0x03, 0x0f, + 0x01, 0xe8, 0x03, 0x10, 0x01, 0xea, 0x03, 0x11, + 0x01, 0xec, 0x03, 0x12, 0x01, 0xee, 0x03, 0x13, + 0x01, 0xf0, 0x03, 0x14, 0x01, 0xf2, 0x03, 0x15, + 0x01, 0xf4, 0x03, 0x16, 0x01, 0xf6, 0x03, 0x17, + 0x01, 0xf8, 0x03, 0x18, 0x01, 0xfa, 0x03, 0x19, + 0x01, 0xfc, 0x03, 0x1a, 0x01, 0xfe, 0x03, 0x1b, + 0x01, 0x80, 0x04, 0x1c, 0x01, 0x82, 0x04, 0x1d, + 0x01, 0x84, 0x04, 0x1e, 0x01, 0x86, 0x04, 0x1f, + 0x01, 0x88, 0x04, 0x20, 0x01, 0x8a, 0x04, 0x21, + 0x01, 0x8c, 0x04, 0x22, 0x01, 0x8e, 0x04, 0x23, + 0x01, 0x90, 0x04, 0x24, 0x01, 0x92, 0x04, 0x25, + 0x01, 0x94, 0x04, 0x26, 0x01, 0x96, 0x04, 0x27, + 0x01, 0x98, 0x04, 0x28, 0x01, 0x9a, 0x04, 0x29, + 0x01, 0x9c, 0x04, 0x2a, 0x01, 0x9e, 0x04, 0x2b, + 0x01, 0xa0, 0x04, 0x2c, 0x01, 0xa2, 0x04, 0x2d, + 0x01, 0xa4, 0x04, 0x2e, 0x01, 0xa6, 0x04, 0x2f, + 0x01, 0xa8, 0x04, 0x30, 0x01, 0xaa, 0x04, 0x31, + 0x01, 0xac, 0x04, 0x32, 0x01, 0xae, 0x04, 0x33, + 0x01, 0xb0, 0x04, 0x34, 0x01, 0xb2, 0x04, 0x35, + 0x01, 0xb4, 0x04, 0x36, 0x01, 0xb6, 0x04, 0x37, + 0x01, 0xb8, 0x04, 0x38, 0x01, 0xba, 0x04, 0x39, + 0x01, 0xbc, 0x04, 0x3a, 0x01, 0xbe, 0x04, 0x3b, + 0x01, 0xc0, 0x04, 0x3c, 0x01, 0xc2, 0x04, 0x3d, + 0x01, 0xc4, 0x04, 0x3e, 0x01, 0xc6, 0x04, 0x3f, + 0x01, 0xc8, 0x04, 0x40, 0x01, 0xca, 0x04, 0x41, + 0x01, 0xcc, 0x04, 0x42, 0x01, 0xce, 0x04, 0x43, + 0x01, 0xd0, 0x04, 0x44, 0x01, 0x08, 0xc9, 0x08, + 0x69, 0xb4, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x5f, + 0x15, 0x00, 0xc0, 0x03, 0x5f, 0x16, 0x00, 0xc0, + 0x04, 0x5f, 0x17, 0x00, 0xc0, 0x05, 0x5f, 0x18, + 0x00, 0xc0, 0x06, 0x5f, 0x19, 0x00, 0xc0, 0x07, + 0x5f, 0x1a, 0x00, 0xc0, 0x08, 0x5f, 0x1b, 0x00, + 0xc0, 0x09, 0x5f, 0x1c, 0x00, 0xc0, 0x0a, 0x5f, + 0x1d, 0x00, 0xc0, 0x0b, 0x5f, 0x1e, 0x00, 0xc0, + 0x0c, 0x5f, 0x1f, 0x00, 0xc0, 0x0d, 0x5f, 0x20, + 0x00, 0xc0, 0x0e, 0x5f, 0x21, 0x00, 0xc0, 0x0f, + 0x5f, 0x22, 0x00, 0xc0, 0x10, 0x5f, 0x23, 0x00, + 0xc0, 0x11, 0x5f, 0x24, 0x00, 0xc0, 0x12, 0x5f, + 0x25, 0x00, 0xc0, 0x13, 0x5f, 0x26, 0x00, 0xc0, + 0x14, 0x5f, 0x27, 0x00, 0xc0, 0x15, 0x5f, 0x28, + 0x00, 0xc0, 0x16, 0x5f, 0x29, 0x00, 0xc0, 0x17, + 0x5f, 0x2a, 0x00, 0xc0, 0x18, 0x5f, 0x2b, 0x00, + 0xc0, 0x19, 0x5f, 0x2c, 0x00, 0xc0, 0x1a, 0x5f, + 0x2d, 0x00, 0xc0, 0x1b, 0x5f, 0x2e, 0x00, 0xc0, + 0x1c, 0x5f, 0x2f, 0x00, 0xc0, 0x1d, 0x5f, 0x30, + 0x00, 0xc0, 0x1e, 0x5f, 0x31, 0x00, 0xc0, 0x1f, + 0x5f, 0x32, 0x00, 0xc0, 0x20, 0x5f, 0x33, 0x00, + 0xc0, 0x21, 0x5f, 0x34, 0x00, 0xc0, 0x22, 0x5f, + 0x35, 0x00, 0xc0, 0x23, 0x5f, 0x36, 0x00, 0xc0, + 0x24, 0x5f, 0x37, 0x00, 0x29, 0xc0, 0x00, 0xc5, + 0xef, 0x0e, 0xe0, 0xb5, 0xb6, 0xf0, 0x5f, 0x0a, + 0x00, 0x5e, 0x05, 0x00, 0xb5, 0xb6, 0x26, 0x02, + 0x00, 0xef, 0x5f, 0x0b, 0x00, 0x5e, 0x08, 0x00, + 0x41, 0xf0, 0x00, 0x00, 0x00, 0x5f, 0x0c, 0x00, + 0x38, 0x95, 0x00, 0x00, 0x00, 0x42, 0x68, 0x00, + 0x00, 0x00, 0xc5, 0x04, 0x29, 0x01, 0x00, 0x00, + 0x0b, 0xc0, 0x01, 0x4d, 0x44, 0x00, 0x00, 0x00, + 0x4c, 0x44, 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, + 0x0e, 0xdd, 0x41, 0xf1, 0x00, 0x00, 0x00, 0x5f, + 0x0d, 0x00, 0xdd, 0x41, 0xf2, 0x00, 0x00, 0x00, + 0x5f, 0x0e, 0x00, 0xdd, 0x41, 0xf3, 0x00, 0x00, + 0x00, 0x5f, 0x0f, 0x00, 0xdd, 0x41, 0xf4, 0x00, + 0x00, 0x00, 0x5f, 0x10, 0x00, 0xdd, 0x41, 0xf5, + 0x00, 0x00, 0x00, 0x5f, 0x11, 0x00, 0xdd, 0x41, + 0xf6, 0x00, 0x00, 0x00, 0x5f, 0x12, 0x00, 0xdd, + 0x41, 0x2a, 0x01, 0x00, 0x00, 0x5f, 0x13, 0x00, + 0xdd, 0x41, 0x2b, 0x01, 0x00, 0x00, 0x5f, 0x14, + 0x00, 0x5e, 0x09, 0x00, 0x41, 0x1c, 0x01, 0x00, + 0x00, 0x5f, 0x38, 0x00, 0x5e, 0x09, 0x00, 0x41, + 0x1d, 0x01, 0x00, 0x00, 0x5f, 0x39, 0x00, 0x5e, + 0x09, 0x00, 0x41, 0x1e, 0x01, 0x00, 0x00, 0x5f, + 0x3a, 0x00, 0x5e, 0x09, 0x00, 0x41, 0x1f, 0x01, + 0x00, 0x00, 0x5f, 0x3b, 0x00, 0x5e, 0x09, 0x00, + 0x41, 0x20, 0x01, 0x00, 0x00, 0x5f, 0x3c, 0x00, + 0x5e, 0x09, 0x00, 0x41, 0x21, 0x01, 0x00, 0x00, + 0x5f, 0x3d, 0x00, 0x5e, 0x09, 0x00, 0x41, 0x22, + 0x01, 0x00, 0x00, 0x5f, 0x3e, 0x00, 0x5e, 0x09, + 0x00, 0x41, 0x23, 0x01, 0x00, 0x00, 0x5f, 0x3f, + 0x00, 0x5e, 0x09, 0x00, 0x41, 0x24, 0x01, 0x00, + 0x00, 0x5f, 0x40, 0x00, 0x5e, 0x09, 0x00, 0x41, + 0x25, 0x01, 0x00, 0x00, 0x5f, 0x41, 0x00, 0x5e, + 0x09, 0x00, 0x41, 0x26, 0x01, 0x00, 0x00, 0x5f, + 0x42, 0x00, 0x5e, 0x05, 0x00, 0x41, 0x2c, 0x01, + 0x00, 0x00, 0x5f, 0x43, 0x00, 0xde, 0x41, 0x28, + 0x01, 0x00, 0x00, 0x5f, 0x44, 0x00, 0x29, 0xc6, + 0x03, 0x01, 0x22, 0x0b, 0x00, 0xb6, 0x01, 0x9c, + 0x25, 0x1e, 0x26, 0x3f, 0x3b, 0xaa, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x09, 0xea, + 0x03, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3b, 0x3a, 0x0e, 0x43, 0x06, + 0x01, 0x00, 0x01, 0x46, 0x01, 0x20, 0x18, 0xcd, + 0x01, 0x83, 0x1b, 0x47, 0xe2, 0x01, 0x00, 0x01, + 0x40, 0xda, 0x04, 0x00, 0x00, 0x00, 0xdc, 0x04, + 0x00, 0x01, 0x00, 0xde, 0x04, 0x00, 0x02, 0x40, + 0xe0, 0x04, 0x00, 0x03, 0x40, 0xe2, 0x04, 0x00, + 0x04, 0x40, 0xe4, 0x04, 0x00, 0x05, 0x40, 0xe6, + 0x04, 0x00, 0x06, 0x00, 0xe8, 0x04, 0x00, 0x07, + 0x00, 0xea, 0x04, 0x00, 0x08, 0x00, 0xec, 0x04, + 0x00, 0x09, 0x00, 0xee, 0x04, 0x00, 0x0a, 0x00, + 0xf0, 0x04, 0x00, 0x0b, 0x00, 0xf2, 0x04, 0x00, + 0x0c, 0x00, 0xf4, 0x04, 0x00, 0x0d, 0x00, 0xf6, + 0x04, 0x00, 0x0e, 0x00, 0xf8, 0x04, 0x00, 0x0f, + 0x00, 0xfa, 0x04, 0x00, 0x10, 0x00, 0xfc, 0x04, + 0x00, 0x11, 0x00, 0xfe, 0x04, 0x00, 0x12, 0x00, + 0x80, 0x05, 0x00, 0x13, 0x00, 0x82, 0x05, 0x00, + 0x14, 0x00, 0x84, 0x05, 0x00, 0x15, 0x40, 0x86, + 0x05, 0x00, 0x16, 0x40, 0x88, 0x05, 0x00, 0x17, + 0x00, 0x8a, 0x05, 0x00, 0x18, 0x00, 0x8c, 0x05, + 0x00, 0x19, 0x00, 0x8e, 0x05, 0x00, 0x1a, 0x00, + 0x90, 0x05, 0x00, 0x1b, 0x00, 0x92, 0x05, 0x00, + 0x1c, 0x00, 0x94, 0x05, 0x00, 0x1d, 0x00, 0x96, + 0x05, 0x00, 0x1e, 0x40, 0x98, 0x05, 0x00, 0x1f, + 0x00, 0x9a, 0x05, 0x00, 0x20, 0x00, 0x9c, 0x05, + 0x00, 0x21, 0x40, 0x9e, 0x05, 0x00, 0x22, 0x40, + 0xa0, 0x05, 0x00, 0x23, 0x40, 0xa2, 0x05, 0x00, + 0x24, 0x40, 0xa4, 0x05, 0x00, 0x25, 0x40, 0xa6, + 0x05, 0x00, 0x26, 0x40, 0xa8, 0x05, 0x00, 0x27, + 0x00, 0xaa, 0x05, 0x00, 0x28, 0x00, 0xac, 0x05, + 0x00, 0x29, 0x00, 0xae, 0x05, 0x00, 0x2a, 0x00, + 0xb0, 0x05, 0x00, 0x2b, 0x00, 0xb2, 0x05, 0x00, + 0x2c, 0x00, 0xb4, 0x05, 0x00, 0x2d, 0x40, 0xb6, + 0x05, 0x00, 0x2e, 0x00, 0xb8, 0x05, 0x00, 0x2f, + 0x40, 0xba, 0x05, 0x00, 0x30, 0x00, 0xbc, 0x05, + 0x00, 0x31, 0x00, 0xbe, 0x05, 0x00, 0x32, 0x00, + 0xc0, 0x05, 0x00, 0x33, 0x00, 0xc2, 0x05, 0x00, + 0x34, 0x00, 0xc4, 0x05, 0x00, 0x35, 0x00, 0xc6, + 0x05, 0x00, 0x36, 0x00, 0xc8, 0x05, 0x00, 0x37, + 0x40, 0xca, 0x05, 0x00, 0x38, 0x40, 0xcc, 0x05, + 0x00, 0x39, 0x40, 0xce, 0x05, 0x00, 0x3a, 0x00, + 0xd0, 0x05, 0x00, 0x3b, 0x40, 0xd2, 0x05, 0x00, + 0x3c, 0x00, 0xd4, 0x05, 0x00, 0x3d, 0x00, 0xd6, + 0x05, 0x00, 0x3e, 0x00, 0xd8, 0x05, 0x00, 0x3f, + 0x00, 0xda, 0x05, 0x00, 0x40, 0x00, 0xdc, 0x05, + 0x00, 0x41, 0x40, 0xde, 0x05, 0x00, 0x42, 0x40, + 0xe0, 0x05, 0x00, 0x43, 0x00, 0xe2, 0x05, 0x00, + 0x44, 0x40, 0xe4, 0x05, 0x00, 0x45, 0x00, 0xc8, + 0x03, 0x00, 0x00, 0x88, 0x04, 0x20, 0x00, 0x8a, + 0x04, 0x21, 0x00, 0xd2, 0x03, 0x05, 0x00, 0xd8, + 0x03, 0x08, 0x00, 0xb8, 0x04, 0x38, 0x00, 0xda, + 0x03, 0x09, 0x00, 0xcc, 0x03, 0x02, 0x00, 0xca, + 0x03, 0x01, 0x00, 0xf8, 0x03, 0x18, 0x00, 0xce, + 0x03, 0x03, 0x00, 0xf6, 0x03, 0x17, 0x00, 0x96, + 0x04, 0x27, 0x00, 0x94, 0x04, 0x26, 0x00, 0xa0, + 0x04, 0x2c, 0x00, 0xd0, 0x03, 0x04, 0x00, 0x86, + 0x04, 0x1f, 0x00, 0xde, 0x03, 0x0b, 0x00, 0xd6, + 0x03, 0x07, 0x00, 0xd4, 0x03, 0x06, 0x00, 0xe4, + 0x03, 0x0e, 0x00, 0xf4, 0x03, 0x16, 0x00, 0xf2, + 0x03, 0x15, 0x00, 0xbe, 0x04, 0x3b, 0x00, 0xc0, + 0x00, 0xc9, 0xc0, 0x01, 0xca, 0xc0, 0x02, 0xcb, + 0xc0, 0x03, 0xc3, 0x04, 0xc0, 0x04, 0xc3, 0x05, + 0xc0, 0x18, 0xc3, 0x06, 0xc0, 0x19, 0xc3, 0x07, + 0xc0, 0x1a, 0xc3, 0x08, 0xc0, 0x1b, 0xc3, 0x09, + 0xc0, 0x1c, 0xc3, 0x0a, 0xc0, 0x1d, 0xc3, 0x0b, + 0xc0, 0x1e, 0xc3, 0x0c, 0xc0, 0x1f, 0xc3, 0x0d, + 0xc0, 0x20, 0xc3, 0x0e, 0xc0, 0x21, 0xc3, 0x0f, + 0xc0, 0x22, 0xc3, 0x10, 0xc0, 0x23, 0xc3, 0x11, + 0xc0, 0x24, 0xc3, 0x12, 0xc0, 0x25, 0xc3, 0x13, + 0xc0, 0x26, 0xc3, 0x14, 0xc0, 0x3a, 0xc3, 0x16, + 0xc0, 0x4b, 0xc3, 0x17, 0xc0, 0x4c, 0xc3, 0x18, + 0xc0, 0x4d, 0xc3, 0x19, 0xc0, 0x4e, 0xc3, 0x1a, + 0xc0, 0x4f, 0xc3, 0x1b, 0xc0, 0x5c, 0xc3, 0x1c, + 0xc0, 0x5d, 0xc3, 0x1d, 0xc0, 0x5e, 0xc3, 0x1e, + 0xc0, 0x5f, 0xc3, 0x1f, 0xc0, 0x60, 0xc3, 0x20, + 0xc0, 0x65, 0xc3, 0x21, 0xc0, 0x67, 0xc3, 0x22, + 0xc0, 0x68, 0xc3, 0x23, 0xc0, 0x69, 0xc3, 0x24, + 0xc0, 0x6a, 0xc3, 0x25, 0xc0, 0x74, 0xc3, 0x26, + 0xc0, 0x75, 0xc3, 0x27, 0xc0, 0x76, 0xc3, 0x28, + 0xc0, 0x77, 0xc3, 0x29, 0xc0, 0x78, 0xc3, 0x2a, + 0xc0, 0x79, 0xc3, 0x2b, 0xc0, 0x7a, 0xc3, 0x2c, + 0xc0, 0x82, 0xc3, 0x2d, 0xc0, 0x83, 0xc3, 0x2e, + 0xc0, 0x84, 0xc3, 0x2f, 0xc0, 0x85, 0xc3, 0x30, + 0xc0, 0x86, 0xc3, 0x31, 0xc0, 0x91, 0xc3, 0x32, + 0xc0, 0x92, 0xc3, 0x33, 0xc0, 0x93, 0xc3, 0x34, + 0xc0, 0x94, 0xc3, 0x35, 0xc0, 0x95, 0xc3, 0x36, + 0xc0, 0x99, 0xc3, 0x37, 0xc0, 0x9a, 0xc3, 0x38, + 0xc0, 0x9c, 0xc3, 0x39, 0xc0, 0x9d, 0xc3, 0x3a, + 0xc0, 0x9e, 0xc3, 0x3b, 0xc0, 0x9f, 0xc3, 0x3c, + 0xc0, 0xa0, 0xc3, 0x3d, 0xc0, 0xa1, 0xc3, 0x3e, + 0xc0, 0xbe, 0xc3, 0x3f, 0xc0, 0xbf, 0xc3, 0x40, + 0xc0, 0xc0, 0xc3, 0x41, 0xc0, 0xc1, 0xc3, 0x42, + 0xc0, 0xc2, 0xc3, 0x43, 0xc0, 0xc3, 0xc3, 0x44, + 0xc0, 0xc4, 0xc3, 0x45, 0xd1, 0xd1, 0x41, 0xb2, + 0x00, 0x00, 0x00, 0x43, 0xe4, 0x00, 0x00, 0x00, + 0xd1, 0xd1, 0x41, 0xb3, 0x00, 0x00, 0x00, 0x43, + 0xe5, 0x00, 0x00, 0x00, 0xd1, 0x0a, 0x43, 0x73, + 0x01, 0x00, 0x00, 0xb7, 0xb8, 0xba, 0xbc, 0xbd, + 0x0b, 0xbd, 0x0d, 0xbd, 0x11, 0xbd, 0x13, 0xbd, + 0x17, 0xbd, 0x1d, 0xbd, 0x1f, 0xbd, 0x25, 0xbd, + 0x29, 0xbd, 0x2b, 0xbd, 0x2f, 0xbd, 0x35, 0xbd, + 0x3b, 0xbd, 0x3d, 0xbd, 0x43, 0xbd, 0x47, 0xbd, + 0x49, 0xbd, 0x4f, 0xbd, 0x53, 0xbd, 0x59, 0xbd, + 0x61, 0xbd, 0x65, 0xbd, 0x67, 0xbd, 0x6b, 0xbd, + 0x6d, 0xbd, 0x71, 0xbd, 0x7f, 0xbe, 0x83, 0x00, + 0x26, 0x20, 0x00, 0xbe, 0x89, 0x00, 0x4c, 0x20, + 0x00, 0x00, 0x80, 0xbe, 0x8b, 0x00, 0x4c, 0x21, + 0x00, 0x00, 0x80, 0xbe, 0x95, 0x00, 0x4c, 0x22, + 0x00, 0x00, 0x80, 0xbe, 0x97, 0x00, 0x4c, 0x23, + 0x00, 0x00, 0x80, 0xbe, 0x9d, 0x00, 0x4c, 0x24, + 0x00, 0x00, 0x80, 0xbe, 0xa3, 0x00, 0x4c, 0x25, + 0x00, 0x00, 0x80, 0xbe, 0xa7, 0x00, 0x4c, 0x26, + 0x00, 0x00, 0x80, 0xbe, 0xad, 0x00, 0x4c, 0x27, + 0x00, 0x00, 0x80, 0xbe, 0xb3, 0x00, 0x4c, 0x28, + 0x00, 0x00, 0x80, 0xbe, 0xb5, 0x00, 0x4c, 0x29, + 0x00, 0x00, 0x80, 0xbe, 0xbf, 0x00, 0x4c, 0x2a, + 0x00, 0x00, 0x80, 0xbe, 0xc1, 0x00, 0x4c, 0x2b, + 0x00, 0x00, 0x80, 0xbe, 0xc5, 0x00, 0x4c, 0x2c, + 0x00, 0x00, 0x80, 0xbe, 0xc7, 0x00, 0x4c, 0x2d, + 0x00, 0x00, 0x80, 0xbe, 0xd3, 0x00, 0x4c, 0x2e, + 0x00, 0x00, 0x80, 0xbe, 0xdf, 0x00, 0x4c, 0x2f, + 0x00, 0x00, 0x80, 0xbe, 0xe3, 0x00, 0x4c, 0x30, + 0x00, 0x00, 0x80, 0xbe, 0xe5, 0x00, 0x4c, 0x31, + 0x00, 0x00, 0x80, 0xbe, 0xe9, 0x00, 0x4c, 0x32, + 0x00, 0x00, 0x80, 0xbe, 0xef, 0x00, 0x4c, 0x33, + 0x00, 0x00, 0x80, 0xbe, 0xf1, 0x00, 0x4c, 0x34, + 0x00, 0x00, 0x80, 0xbe, 0xfb, 0x00, 0x4c, 0x35, + 0x00, 0x00, 0x80, 0xbe, 0x01, 0x01, 0x4c, 0x36, + 0x00, 0x00, 0x80, 0xbe, 0x07, 0x01, 0x4c, 0x37, + 0x00, 0x00, 0x80, 0xbe, 0x0d, 0x01, 0x4c, 0x38, + 0x00, 0x00, 0x80, 0xbe, 0x0f, 0x01, 0x4c, 0x39, + 0x00, 0x00, 0x80, 0xbe, 0x15, 0x01, 0x4c, 0x3a, + 0x00, 0x00, 0x80, 0xbe, 0x19, 0x01, 0x4c, 0x3b, + 0x00, 0x00, 0x80, 0xbe, 0x1b, 0x01, 0x4c, 0x3c, + 0x00, 0x00, 0x80, 0xbe, 0x25, 0x01, 0x4c, 0x3d, + 0x00, 0x00, 0x80, 0xbe, 0x33, 0x01, 0x4c, 0x3e, + 0x00, 0x00, 0x80, 0xbe, 0x37, 0x01, 0x4c, 0x3f, + 0x00, 0x00, 0x80, 0xbe, 0x39, 0x01, 0x4c, 0x40, + 0x00, 0x00, 0x80, 0xbe, 0x3d, 0x01, 0x4c, 0x41, + 0x00, 0x00, 0x80, 0xbe, 0x4b, 0x01, 0x4c, 0x42, + 0x00, 0x00, 0x80, 0xbe, 0x51, 0x01, 0x4c, 0x43, + 0x00, 0x00, 0x80, 0xbe, 0x5b, 0x01, 0x4c, 0x44, + 0x00, 0x00, 0x80, 0xbe, 0x5d, 0x01, 0x4c, 0x45, + 0x00, 0x00, 0x80, 0xbe, 0x61, 0x01, 0x4c, 0x46, + 0x00, 0x00, 0x80, 0xbe, 0x67, 0x01, 0x4c, 0x47, + 0x00, 0x00, 0x80, 0xbe, 0x6f, 0x01, 0x4c, 0x48, + 0x00, 0x00, 0x80, 0xbe, 0x75, 0x01, 0x4c, 0x49, + 0x00, 0x00, 0x80, 0xbe, 0x7b, 0x01, 0x4c, 0x4a, + 0x00, 0x00, 0x80, 0xbe, 0x7f, 0x01, 0x4c, 0x4b, + 0x00, 0x00, 0x80, 0xbe, 0x85, 0x01, 0x4c, 0x4c, + 0x00, 0x00, 0x80, 0xbe, 0x8d, 0x01, 0x4c, 0x4d, + 0x00, 0x00, 0x80, 0xbe, 0x91, 0x01, 0x4c, 0x4e, + 0x00, 0x00, 0x80, 0xbe, 0x99, 0x01, 0x4c, 0x4f, + 0x00, 0x00, 0x80, 0xbe, 0xa3, 0x01, 0x4c, 0x50, + 0x00, 0x00, 0x80, 0xbe, 0xa5, 0x01, 0x4c, 0x51, + 0x00, 0x00, 0x80, 0xbe, 0xaf, 0x01, 0x4c, 0x52, + 0x00, 0x00, 0x80, 0xbe, 0xb1, 0x01, 0x4c, 0x53, + 0x00, 0x00, 0x80, 0xbe, 0xb7, 0x01, 0x4c, 0x54, + 0x00, 0x00, 0x80, 0xbe, 0xbb, 0x01, 0x4c, 0x55, + 0x00, 0x00, 0x80, 0xbe, 0xc1, 0x01, 0x4c, 0x56, + 0x00, 0x00, 0x80, 0xbe, 0xc9, 0x01, 0x4c, 0x57, + 0x00, 0x00, 0x80, 0xbe, 0xcd, 0x01, 0x4c, 0x58, + 0x00, 0x00, 0x80, 0xbe, 0xcf, 0x01, 0x4c, 0x59, + 0x00, 0x00, 0x80, 0xbe, 0xd3, 0x01, 0x4c, 0x5a, + 0x00, 0x00, 0x80, 0xbe, 0xdf, 0x01, 0x4c, 0x5b, + 0x00, 0x00, 0x80, 0xbe, 0xe7, 0x01, 0x4c, 0x5c, + 0x00, 0x00, 0x80, 0xbe, 0xeb, 0x01, 0x4c, 0x5d, + 0x00, 0x00, 0x80, 0xbe, 0xf3, 0x01, 0x4c, 0x5e, + 0x00, 0x00, 0x80, 0xcc, 0x38, 0xb7, 0x00, 0x00, + 0x00, 0x42, 0x74, 0x01, 0x00, 0x00, 0x0b, 0xc0, + 0x05, 0x54, 0x75, 0x01, 0x00, 0x00, 0x04, 0xc0, + 0x06, 0x54, 0x76, 0x01, 0x00, 0x00, 0x04, 0x24, + 0x01, 0x00, 0x0e, 0xc5, 0xdd, 0x0b, 0xc0, 0x07, + 0x54, 0x77, 0x01, 0x00, 0x00, 0x04, 0xc0, 0x08, + 0x54, 0xf1, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x09, + 0x54, 0xf2, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x0a, + 0x54, 0xf3, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x0b, + 0x54, 0xf5, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x0c, + 0x54, 0xf4, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x0d, + 0x54, 0x2a, 0x01, 0x00, 0x00, 0x04, 0xc0, 0x0e, + 0x54, 0x2b, 0x01, 0x00, 0x00, 0x04, 0xc0, 0x0f, + 0x54, 0xf6, 0x00, 0x00, 0x00, 0x04, 0xf0, 0x0e, + 0xc5, 0xdd, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, + 0xc0, 0x10, 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x11, 0x54, 0xfb, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x12, 0x54, 0xfc, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x13, 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x14, 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x15, 0x54, 0x04, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0x16, 0x54, 0x05, 0x01, 0x00, 0x00, 0x04, + 0xf0, 0x0e, 0xc0, 0x17, 0x5f, 0x07, 0x00, 0xc6, + 0x5e, 0x07, 0x00, 0x41, 0x3e, 0x00, 0x00, 0x00, + 0x0b, 0xc2, 0x06, 0x4c, 0x78, 0x01, 0x00, 0x00, + 0xc2, 0x07, 0x4c, 0x79, 0x01, 0x00, 0x00, 0xc2, + 0x08, 0x4c, 0x80, 0x00, 0x00, 0x00, 0xc2, 0x09, + 0x4c, 0x75, 0x01, 0x00, 0x00, 0xc2, 0x0a, 0x4c, + 0x7a, 0x01, 0x00, 0x00, 0xc7, 0x4c, 0x76, 0x01, + 0x00, 0x00, 0xc2, 0x0b, 0x4c, 0x7b, 0x01, 0x00, + 0x00, 0xc2, 0x0c, 0x4c, 0x7c, 0x01, 0x00, 0x00, + 0xc0, 0x27, 0x54, 0x7d, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0x28, 0x54, 0x7e, 0x01, 0x00, 0x00, 0x04, + 0x0b, 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, + 0x00, 0x00, 0x00, 0x26, 0x02, 0x00, 0x4c, 0x7f, + 0x01, 0x00, 0x00, 0x38, 0x98, 0x00, 0x00, 0x00, + 0x38, 0xb2, 0x00, 0x00, 0x00, 0x26, 0x02, 0x00, + 0x4c, 0x80, 0x01, 0x00, 0x00, 0xc2, 0x06, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xc2, 0x07, 0x4c, 0x79, + 0x01, 0x00, 0x00, 0xc2, 0x08, 0x4c, 0x80, 0x00, + 0x00, 0x00, 0xc2, 0x09, 0x4c, 0x75, 0x01, 0x00, + 0x00, 0xc2, 0x0a, 0x4c, 0x7a, 0x01, 0x00, 0x00, + 0xc7, 0x4c, 0x76, 0x01, 0x00, 0x00, 0xc2, 0x0b, + 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc2, 0x0c, 0x4c, + 0x7c, 0x01, 0x00, 0x00, 0x0b, 0x5e, 0x08, 0x00, + 0x4c, 0x7f, 0x01, 0x00, 0x00, 0x5e, 0x08, 0x00, + 0x4c, 0x80, 0x01, 0x00, 0x00, 0xc2, 0x0d, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xc2, 0x0e, 0x4c, 0x79, + 0x01, 0x00, 0x00, 0xc2, 0x0f, 0x4c, 0x80, 0x00, + 0x00, 0x00, 0xc2, 0x10, 0x4c, 0x75, 0x01, 0x00, + 0x00, 0xc2, 0x11, 0x4c, 0x7a, 0x01, 0x00, 0x00, + 0xc2, 0x12, 0x4c, 0x76, 0x01, 0x00, 0x00, 0xc2, + 0x13, 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc2, 0x14, + 0x4c, 0x7c, 0x01, 0x00, 0x00, 0x22, 0x04, 0x00, + 0x0e, 0xc5, 0x5e, 0x07, 0x00, 0x0b, 0xc0, 0x29, + 0x54, 0x81, 0x01, 0x00, 0x00, 0x04, 0xf0, 0x0e, + 0xc5, 0x5e, 0x07, 0x00, 0x41, 0x3e, 0x00, 0x00, + 0x00, 0x0b, 0x38, 0x9b, 0x00, 0x00, 0x00, 0x41, + 0x82, 0x01, 0x00, 0x00, 0xc0, 0x2a, 0x55, 0x04, + 0xc0, 0x2b, 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x2c, 0x54, 0x3a, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x2d, 0x54, 0xfb, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x2e, 0x54, 0xfc, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x2f, 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x30, 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x31, 0x54, 0x04, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0x32, 0x54, 0x05, 0x01, 0x00, 0x00, 0x04, + 0xf0, 0x0e, 0xc5, 0x38, 0x98, 0x00, 0x00, 0x00, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc0, 0x33, + 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x34, + 0x54, 0xfb, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x35, + 0x54, 0xfc, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x36, + 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x37, + 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x38, + 0x54, 0x04, 0x01, 0x00, 0x00, 0x04, 0xc0, 0x39, + 0x54, 0x05, 0x01, 0x00, 0x00, 0x04, 0xf0, 0x0e, + 0x26, 0x00, 0x00, 0xc3, 0x15, 0xc5, 0x5e, 0x08, + 0x00, 0x0b, 0xc0, 0x3b, 0x54, 0x83, 0x01, 0x00, + 0x00, 0x04, 0xc0, 0x3c, 0x54, 0x28, 0x01, 0x00, + 0x00, 0x04, 0xc0, 0x3d, 0x54, 0x84, 0x01, 0x00, + 0x00, 0x05, 0xc0, 0x3e, 0x54, 0x85, 0x01, 0x00, + 0x00, 0x05, 0xc0, 0x3f, 0x54, 0x86, 0x01, 0x00, + 0x00, 0x05, 0xc0, 0x40, 0x54, 0x87, 0x01, 0x00, + 0x00, 0x05, 0xc0, 0x41, 0x54, 0x88, 0x01, 0x00, + 0x00, 0x05, 0xc0, 0x42, 0x54, 0x89, 0x01, 0x00, + 0x00, 0x05, 0xf0, 0x0e, 0xc5, 0x5e, 0x08, 0x00, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc0, 0x43, + 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x44, + 0x54, 0xfb, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x45, + 0x54, 0xfc, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x46, + 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x47, + 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x48, + 0x54, 0x04, 0x01, 0x00, 0x00, 0x04, 0xc0, 0x49, + 0x54, 0x05, 0x01, 0x00, 0x00, 0x04, 0xf0, 0x0e, + 0xc0, 0x4a, 0x5f, 0x0a, 0x00, 0xc6, 0x5e, 0x0a, + 0x00, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc2, + 0x17, 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc2, 0x18, + 0x4c, 0x79, 0x01, 0x00, 0x00, 0xc2, 0x19, 0x4c, + 0x80, 0x00, 0x00, 0x00, 0xc2, 0x1a, 0x4c, 0x75, + 0x01, 0x00, 0x00, 0xc7, 0x4c, 0x76, 0x01, 0x00, + 0x00, 0xc2, 0x1b, 0x4c, 0x7b, 0x01, 0x00, 0x00, + 0xc0, 0x50, 0x54, 0x7d, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0x51, 0x54, 0x7e, 0x01, 0x00, 0x00, 0x04, + 0x0b, 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, + 0x00, 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, + 0x00, 0x26, 0x04, 0x00, 0x4c, 0x7f, 0x01, 0x00, + 0x00, 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, + 0x00, 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, + 0x00, 0x26, 0x04, 0x00, 0x4c, 0x80, 0x01, 0x00, + 0x00, 0xc2, 0x17, 0x4c, 0x78, 0x01, 0x00, 0x00, + 0xc2, 0x18, 0x4c, 0x79, 0x01, 0x00, 0x00, 0xc2, + 0x19, 0x4c, 0x80, 0x00, 0x00, 0x00, 0xc2, 0x1a, + 0x4c, 0x75, 0x01, 0x00, 0x00, 0xc7, 0x4c, 0x76, + 0x01, 0x00, 0x00, 0xc2, 0x1b, 0x4c, 0x7b, 0x01, + 0x00, 0x00, 0xf1, 0x0e, 0xc5, 0x5e, 0x0a, 0x00, + 0x0b, 0xc0, 0x52, 0x54, 0x8a, 0x01, 0x00, 0x00, + 0x04, 0xf0, 0x0e, 0xc5, 0x5e, 0x0a, 0x00, 0x41, + 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc0, 0x53, 0x54, + 0xff, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x54, 0x54, + 0x3a, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x55, 0x54, + 0xfb, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x56, 0x54, + 0xfc, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x57, 0x54, + 0xfd, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x58, 0x54, + 0xfe, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x59, 0x54, + 0x04, 0x01, 0x00, 0x00, 0x04, 0xc0, 0x5a, 0x54, + 0x05, 0x01, 0x00, 0x00, 0x04, 0xf0, 0x0e, 0xc0, + 0x5b, 0x5f, 0x0f, 0x00, 0xc6, 0x5e, 0x0f, 0x00, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x1c, + 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc2, 0x1d, 0x4c, + 0x79, 0x01, 0x00, 0x00, 0xc2, 0x1e, 0x4c, 0x80, + 0x00, 0x00, 0x00, 0xc2, 0x1f, 0x4c, 0x75, 0x01, + 0x00, 0x00, 0xc7, 0x4c, 0x76, 0x01, 0x00, 0x00, + 0xc2, 0x20, 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc0, + 0x61, 0x54, 0x7d, 0x01, 0x00, 0x00, 0x04, 0xc0, + 0x62, 0x54, 0x7e, 0x01, 0x00, 0x00, 0x04, 0x0b, + 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, 0x00, + 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, 0x00, + 0x26, 0x04, 0x00, 0x4c, 0x7f, 0x01, 0x00, 0x00, + 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, 0x00, + 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, 0x00, + 0x26, 0x04, 0x00, 0x4c, 0x80, 0x01, 0x00, 0x00, + 0xc2, 0x1c, 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc2, + 0x1d, 0x4c, 0x79, 0x01, 0x00, 0x00, 0xc2, 0x1e, + 0x4c, 0x80, 0x00, 0x00, 0x00, 0xc2, 0x1f, 0x4c, + 0x75, 0x01, 0x00, 0x00, 0xc7, 0x4c, 0x76, 0x01, + 0x00, 0x00, 0xf1, 0x0e, 0xc5, 0x5e, 0x0f, 0x00, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc0, 0x63, + 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x64, + 0x54, 0x3a, 0x00, 0x00, 0x00, 0x04, 0xf0, 0x0e, + 0xc0, 0x66, 0xe4, 0xc5, 0xe0, 0x41, 0x3e, 0x00, + 0x00, 0x00, 0x0b, 0xc0, 0x6b, 0x54, 0x8b, 0x01, + 0x00, 0x00, 0x04, 0xc0, 0x6c, 0x54, 0xfd, 0x00, + 0x00, 0x00, 0x04, 0xc0, 0x6d, 0x54, 0xff, 0x00, + 0x00, 0x00, 0x04, 0xc0, 0x6e, 0x54, 0x3a, 0x00, + 0x00, 0x00, 0x04, 0xc0, 0x6f, 0x54, 0x8c, 0x01, + 0x00, 0x00, 0x04, 0xc0, 0x70, 0x54, 0x5d, 0x00, + 0x00, 0x00, 0x04, 0xc0, 0x71, 0x54, 0xf9, 0x00, + 0x00, 0x00, 0x04, 0xc0, 0x72, 0x54, 0xfa, 0x00, + 0x00, 0x00, 0x04, 0xc0, 0x73, 0x54, 0xfb, 0x00, + 0x00, 0x00, 0x04, 0xf0, 0x0e, 0xc6, 0xe0, 0x41, + 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x26, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xc2, 0x27, 0x4c, 0x79, + 0x01, 0x00, 0x00, 0xc2, 0x28, 0x4c, 0x80, 0x00, + 0x00, 0x00, 0xc2, 0x2a, 0x4c, 0x75, 0x01, 0x00, + 0x00, 0xc7, 0x4c, 0x76, 0x01, 0x00, 0x00, 0xc2, + 0x2c, 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc0, 0x7b, + 0x54, 0x7d, 0x01, 0x00, 0x00, 0x04, 0xc0, 0x7c, + 0x54, 0x7e, 0x01, 0x00, 0x00, 0x04, 0x0b, 0x38, + 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, 0x00, 0x00, + 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, 0x00, 0x5e, + 0x0a, 0x00, 0x5e, 0x0f, 0x00, 0x26, 0x06, 0x00, + 0x4c, 0x7f, 0x01, 0x00, 0x00, 0xc2, 0x26, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xc2, 0x27, 0x4c, 0x79, + 0x01, 0x00, 0x00, 0xc2, 0x28, 0x4c, 0x80, 0x00, + 0x00, 0x00, 0xc2, 0x2a, 0x4c, 0x75, 0x01, 0x00, + 0x00, 0xc7, 0x4c, 0x76, 0x01, 0x00, 0x00, 0x0b, + 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, 0x00, + 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, 0x00, + 0x5e, 0x0a, 0x00, 0x5e, 0x0f, 0x00, 0x26, 0x06, + 0x00, 0x4c, 0x80, 0x01, 0x00, 0x00, 0xc2, 0x26, + 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc2, 0x27, 0x4c, + 0x79, 0x01, 0x00, 0x00, 0xc2, 0x28, 0x4c, 0x80, + 0x00, 0x00, 0x00, 0xc2, 0x29, 0x4c, 0x75, 0x01, + 0x00, 0x00, 0xc7, 0x4c, 0x76, 0x01, 0x00, 0x00, + 0x22, 0x04, 0x00, 0x0e, 0xc5, 0xe0, 0x0b, 0xc0, + 0x7d, 0x54, 0x8d, 0x01, 0x00, 0x00, 0x04, 0xc0, + 0x7e, 0x54, 0xf1, 0x00, 0x00, 0x00, 0x04, 0xc0, + 0x7f, 0x54, 0xf5, 0x00, 0x00, 0x00, 0x04, 0xc0, + 0x80, 0x54, 0x2c, 0x01, 0x00, 0x00, 0x04, 0xf0, + 0x0e, 0xc0, 0x81, 0x5f, 0x13, 0x00, 0xc6, 0x5e, + 0x13, 0x00, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, + 0xc2, 0x2d, 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc2, + 0x2e, 0x4c, 0x79, 0x01, 0x00, 0x00, 0xc2, 0x2f, + 0x4c, 0x80, 0x00, 0x00, 0x00, 0xc2, 0x30, 0x4c, + 0x75, 0x01, 0x00, 0x00, 0xc7, 0x4c, 0x76, 0x01, + 0x00, 0x00, 0xc2, 0x31, 0x4c, 0x7b, 0x01, 0x00, + 0x00, 0xc0, 0x87, 0x54, 0x7d, 0x01, 0x00, 0x00, + 0x04, 0xc0, 0x88, 0x54, 0x7e, 0x01, 0x00, 0x00, + 0x04, 0x0b, 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, + 0xb2, 0x00, 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, + 0x07, 0x00, 0x5e, 0x0a, 0x00, 0x5e, 0x0f, 0x00, + 0xe0, 0x26, 0x07, 0x00, 0x4c, 0x7f, 0x01, 0x00, + 0x00, 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, + 0x00, 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, + 0x00, 0x5e, 0x0a, 0x00, 0x5e, 0x0f, 0x00, 0xe0, + 0x26, 0x07, 0x00, 0x4c, 0x80, 0x01, 0x00, 0x00, + 0xc2, 0x2d, 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc2, + 0x2e, 0x4c, 0x79, 0x01, 0x00, 0x00, 0xc2, 0x2f, + 0x4c, 0x80, 0x00, 0x00, 0x00, 0xc2, 0x30, 0x4c, + 0x75, 0x01, 0x00, 0x00, 0xc7, 0x4c, 0x76, 0x01, + 0x00, 0x00, 0xf1, 0x0e, 0xc5, 0x5e, 0x13, 0x00, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc0, 0x89, + 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x8a, + 0x54, 0x3a, 0x00, 0x00, 0x00, 0x04, 0xf0, 0x0e, + 0xc0, 0x8b, 0x5f, 0x12, 0x00, 0xc5, 0x5e, 0x12, + 0x00, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc0, + 0x8c, 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, 0xc0, + 0x8d, 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, 0xc0, + 0x8e, 0x54, 0x3a, 0x00, 0x00, 0x00, 0x04, 0xc0, + 0x8f, 0x54, 0x5d, 0x00, 0x00, 0x00, 0x04, 0xc0, + 0x90, 0x54, 0xf9, 0x00, 0x00, 0x00, 0x04, 0xf0, + 0x0e, 0xc6, 0x5e, 0x12, 0x00, 0x41, 0x3e, 0x00, + 0x00, 0x00, 0x0b, 0xc2, 0x32, 0x4c, 0x78, 0x01, + 0x00, 0x00, 0xc2, 0x33, 0x4c, 0x79, 0x01, 0x00, + 0x00, 0xc2, 0x34, 0x4c, 0x80, 0x00, 0x00, 0x00, + 0xc2, 0x35, 0x4c, 0x75, 0x01, 0x00, 0x00, 0xc7, + 0x4c, 0x76, 0x01, 0x00, 0x00, 0xc2, 0x36, 0x4c, + 0x7b, 0x01, 0x00, 0x00, 0xc0, 0x96, 0x54, 0x7d, + 0x01, 0x00, 0x00, 0x04, 0xc0, 0x97, 0x54, 0x7e, + 0x01, 0x00, 0x00, 0x04, 0x0b, 0x38, 0x98, 0x00, + 0x00, 0x00, 0x38, 0xb2, 0x00, 0x00, 0x00, 0x5e, + 0x08, 0x00, 0x5e, 0x07, 0x00, 0x5e, 0x0a, 0x00, + 0x5e, 0x0f, 0x00, 0xe0, 0x26, 0x07, 0x00, 0x4c, + 0x7f, 0x01, 0x00, 0x00, 0x38, 0x98, 0x00, 0x00, + 0x00, 0x38, 0xb2, 0x00, 0x00, 0x00, 0x5e, 0x08, + 0x00, 0x5e, 0x07, 0x00, 0x5e, 0x0a, 0x00, 0x5e, + 0x0f, 0x00, 0xe0, 0x26, 0x07, 0x00, 0x4c, 0x80, + 0x01, 0x00, 0x00, 0xc2, 0x32, 0x4c, 0x78, 0x01, + 0x00, 0x00, 0xc2, 0x33, 0x4c, 0x79, 0x01, 0x00, + 0x00, 0xc2, 0x34, 0x4c, 0x80, 0x00, 0x00, 0x00, + 0xc2, 0x35, 0x4c, 0x75, 0x01, 0x00, 0x00, 0xc7, + 0x4c, 0x76, 0x01, 0x00, 0x00, 0xf1, 0x0e, 0xc5, + 0x5e, 0x12, 0x00, 0x0b, 0xc0, 0x98, 0x54, 0x8e, + 0x01, 0x00, 0x00, 0x04, 0xf0, 0x0e, 0xc0, 0x9b, + 0x5f, 0x04, 0x00, 0xc6, 0x5e, 0x04, 0x00, 0x41, + 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x39, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xc2, 0x3a, 0x4c, 0x79, + 0x01, 0x00, 0x00, 0xc2, 0x3b, 0x4c, 0x80, 0x00, + 0x00, 0x00, 0xc2, 0x3c, 0x4c, 0x75, 0x01, 0x00, + 0x00, 0xc2, 0x3d, 0x4c, 0x76, 0x01, 0x00, 0x00, + 0xc2, 0x3e, 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc0, + 0xa2, 0x54, 0x7d, 0x01, 0x00, 0x00, 0x04, 0xc0, + 0xa3, 0x54, 0x7e, 0x01, 0x00, 0x00, 0x04, 0x0b, + 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, 0x00, + 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, 0x00, + 0x5e, 0x0a, 0x00, 0x5e, 0x0f, 0x00, 0xe0, 0x26, + 0x07, 0x00, 0x4c, 0x7f, 0x01, 0x00, 0x00, 0x38, + 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, 0x00, 0x00, + 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, 0x00, 0x5e, + 0x0a, 0x00, 0x5e, 0x0f, 0x00, 0xe0, 0x26, 0x07, + 0x00, 0x4c, 0x80, 0x01, 0x00, 0x00, 0xc2, 0x39, + 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc2, 0x3a, 0x4c, + 0x79, 0x01, 0x00, 0x00, 0xc2, 0x3b, 0x4c, 0x80, + 0x00, 0x00, 0x00, 0xc2, 0x3c, 0x4c, 0x75, 0x01, + 0x00, 0x00, 0xc2, 0x3d, 0x4c, 0x76, 0x01, 0x00, + 0x00, 0xf1, 0x0e, 0xc5, 0x5e, 0x04, 0x00, 0x41, + 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc0, 0xa4, 0x54, + 0xfd, 0x00, 0x00, 0x00, 0x04, 0xc0, 0xa5, 0x54, + 0xff, 0x00, 0x00, 0x00, 0x04, 0xc0, 0xa6, 0x54, + 0x8b, 0x01, 0x00, 0x00, 0x04, 0xc0, 0xa7, 0x54, + 0x3a, 0x00, 0x00, 0x00, 0x04, 0xc0, 0xa8, 0x54, + 0x5d, 0x00, 0x00, 0x00, 0x04, 0xc0, 0xa9, 0x54, + 0xf9, 0x00, 0x00, 0x00, 0x04, 0xc0, 0xaa, 0x54, + 0xfa, 0x00, 0x00, 0x00, 0x04, 0xc0, 0xab, 0x54, + 0x04, 0x01, 0x00, 0x00, 0x04, 0xc0, 0xac, 0x54, + 0x05, 0x01, 0x00, 0x00, 0x04, 0xf0, 0x0e, 0xc5, + 0x5e, 0x04, 0x00, 0x0b, 0xc0, 0xad, 0x54, 0x8f, + 0x01, 0x00, 0x00, 0x04, 0xc0, 0xae, 0x54, 0xf0, + 0x00, 0x00, 0x00, 0x04, 0xf0, 0x0e, 0xc0, 0xaf, + 0x5f, 0x06, 0x00, 0xc5, 0x5e, 0x06, 0x00, 0x0b, + 0xc0, 0xb0, 0x54, 0x1c, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb1, 0x54, 0x1d, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb2, 0x54, 0x90, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb3, 0x54, 0x1e, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb4, 0x54, 0x91, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb5, 0x54, 0x1f, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb6, 0x54, 0x20, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb7, 0x54, 0x21, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb8, 0x54, 0x22, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xb9, 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0xba, 0x54, 0x23, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xbb, 0x54, 0x24, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xbc, 0x54, 0x26, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xbd, 0x54, 0x25, 0x01, 0x00, 0x00, 0x04, + 0xf0, 0x0e, 0xc6, 0x38, 0x96, 0x00, 0x00, 0x00, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x3f, + 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc2, 0x40, 0x4c, + 0x79, 0x01, 0x00, 0x00, 0xc2, 0x42, 0x4c, 0x80, + 0x00, 0x00, 0x00, 0xc2, 0x43, 0x4c, 0x75, 0x01, + 0x00, 0x00, 0xc2, 0x45, 0x4c, 0x7b, 0x01, 0x00, + 0x00, 0xc0, 0xc5, 0x54, 0x7d, 0x01, 0x00, 0x00, + 0x04, 0xc0, 0xc6, 0x54, 0x7e, 0x01, 0x00, 0x00, + 0x04, 0x0b, 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, + 0xb2, 0x00, 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, + 0x07, 0x00, 0x5e, 0x0a, 0x00, 0x5e, 0x0f, 0x00, + 0xe0, 0x5e, 0x13, 0x00, 0x5e, 0x12, 0x00, 0x5e, + 0x04, 0x00, 0x26, 0x0a, 0x00, 0x4c, 0x80, 0x01, + 0x00, 0x00, 0xc2, 0x41, 0x4c, 0x80, 0x00, 0x00, + 0x00, 0xc0, 0xc7, 0x54, 0x75, 0x01, 0x00, 0x00, + 0x04, 0xc7, 0x4c, 0x76, 0x01, 0x00, 0x00, 0x0b, + 0x38, 0x98, 0x00, 0x00, 0x00, 0x38, 0xb2, 0x00, + 0x00, 0x00, 0x5e, 0x08, 0x00, 0x5e, 0x07, 0x00, + 0x5e, 0x0a, 0x00, 0x5e, 0x0f, 0x00, 0xe0, 0x5e, + 0x13, 0x00, 0x5e, 0x12, 0x00, 0x5e, 0x04, 0x00, + 0x26, 0x0a, 0x00, 0x4c, 0x7f, 0x01, 0x00, 0x00, + 0xc0, 0xc8, 0x54, 0x80, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0xc9, 0x54, 0x75, 0x01, 0x00, 0x00, 0x04, + 0x22, 0x04, 0x00, 0x0e, 0xc5, 0x38, 0x96, 0x00, + 0x00, 0x00, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x0b, + 0xc0, 0xca, 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0xcb, 0x54, 0x92, 0x01, 0x00, 0x00, 0x04, + 0xc0, 0xcc, 0x54, 0xff, 0x00, 0x00, 0x00, 0x04, + 0xe0, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x41, 0xfb, + 0x00, 0x00, 0x00, 0x4c, 0xfb, 0x00, 0x00, 0x00, + 0xf0, 0x29, 0xc6, 0x03, 0x1d, 0x9f, 0x04, 0x00, + 0x8d, 0x02, 0x02, 0x3f, 0x3f, 0x00, 0x07, 0xba, + 0x01, 0x00, 0xb9, 0x04, 0x5a, 0x35, 0x00, 0x01, + 0x0e, 0x00, 0x08, 0x0e, 0x2b, 0x18, 0x00, 0x03, + 0x0a, 0x00, 0x08, 0x12, 0x2d, 0x00, 0x08, 0x14, + 0x00, 0x08, 0x2a, 0x00, 0x08, 0x2a, 0x00, 0x08, + 0x34, 0x00, 0x08, 0x16, 0x00, 0x08, 0x50, 0x2b, + 0x0e, 0x2d, 0x2d, 0x00, 0x08, 0x0c, 0x2d, 0x00, + 0x08, 0x0c, 0x00, 0x08, 0x0c, 0x00, 0x08, 0x0c, + 0x2b, 0x00, 0x02, 0x4a, 0x00, 0x05, 0x90, 0x01, + 0x30, 0x08, 0x26, 0x26, 0x26, 0x26, 0x26, 0x21, + 0x26, 0x28, 0x2d, 0x2c, 0x08, 0x5d, 0x5d, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x21, 0x26, 0x27, 0x08, + 0x2b, 0x2b, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x18, 0x00, 0x05, 0x10, 0x2b, 0x0e, + 0x35, 0x00, 0x0a, 0x0c, 0x19, 0x2d, 0x2d, 0x00, + 0x08, 0x0c, 0x2d, 0x00, 0x08, 0x0c, 0x2d, 0x2d, + 0x2b, 0x00, 0x02, 0x08, 0x41, 0x2d, 0x2d, 0x2d, + 0x00, 0x08, 0x0c, 0x2d, 0x00, 0x08, 0x0e, 0x2b, + 0x00, 0x02, 0x08, 0x00, 0x05, 0x36, 0x1e, 0x00, + 0x08, 0x2e, 0x2c, 0x2b, 0x2c, 0x2b, 0x2c, 0x2b, + 0x2b, 0x0e, 0x37, 0x2d, 0x2d, 0x2d, 0x00, 0x08, + 0x0c, 0x2d, 0x00, 0x08, 0x0e, 0x2b, 0x00, 0x02, + 0x24, 0x00, 0x05, 0x3c, 0x30, 0x08, 0x26, 0x26, + 0x26, 0x26, 0x21, 0x28, 0x2d, 0x2c, 0x08, 0x7b, + 0x7b, 0x26, 0x26, 0x26, 0x26, 0x21, 0x26, 0x0e, + 0x00, 0x05, 0x0e, 0x2b, 0x0e, 0x00, 0x0a, 0x08, + 0x00, 0x08, 0x24, 0x2d, 0x2d, 0x2d, 0x2d, 0x00, + 0x08, 0x08, 0x2d, 0x2b, 0x00, 0x02, 0x32, 0x00, + 0x05, 0x58, 0x30, 0x08, 0x26, 0x26, 0x26, 0x26, + 0x21, 0x28, 0x2d, 0x2c, 0x08, 0x7b, 0x7b, 0x26, + 0x26, 0x26, 0x26, 0x21, 0x0e, 0x00, 0x0a, 0x10, + 0x2d, 0x2b, 0x00, 0x02, 0x46, 0x00, 0x03, 0xf0, + 0x01, 0x00, 0x08, 0x10, 0x00, 0x08, 0x12, 0x2d, + 0x00, 0x08, 0x28, 0x00, 0x08, 0x0c, 0x00, 0x08, + 0x14, 0x00, 0x08, 0x1a, 0x00, 0x08, 0x12, 0x00, + 0x08, 0x12, 0x2b, 0x00, 0x02, 0x80, 0x01, 0x26, + 0x08, 0x26, 0x26, 0x26, 0x26, 0x21, 0x28, 0x00, + 0x08, 0x10, 0x2c, 0x08, 0x99, 0x26, 0x26, 0x26, + 0x26, 0x22, 0x08, 0x99, 0x26, 0x26, 0x26, 0x26, + 0x21, 0x18, 0x00, 0x03, 0x36, 0x00, 0x08, 0x14, + 0x00, 0x08, 0x28, 0x2d, 0x2b, 0x00, 0x02, 0x32, + 0x00, 0x05, 0x48, 0x30, 0x08, 0x26, 0x26, 0x26, + 0x26, 0x21, 0x28, 0x2d, 0x2c, 0x08, 0x9e, 0x9e, + 0x26, 0x26, 0x26, 0x26, 0x21, 0x0e, 0x00, 0x0a, + 0x10, 0x2d, 0x2b, 0x00, 0x02, 0x32, 0x1d, 0x37, + 0x2d, 0x00, 0x08, 0x14, 0x2d, 0x00, 0x08, 0x08, + 0x2b, 0x00, 0x02, 0x3a, 0x30, 0x08, 0x26, 0x26, + 0x26, 0x26, 0x21, 0x28, 0x2d, 0x2c, 0x08, 0x9e, + 0x9e, 0x26, 0x26, 0x26, 0x26, 0x21, 0x0e, 0x00, + 0x05, 0x1c, 0x2b, 0x00, 0x02, 0x5a, 0x00, 0x05, + 0xc0, 0x01, 0x30, 0x08, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x28, 0x00, 0x08, 0x12, 0x2c, 0x08, 0x9e, + 0x9e, 0x26, 0x26, 0x26, 0x26, 0x26, 0x0e, 0x00, + 0x0a, 0x12, 0x00, 0x08, 0x20, 0x00, 0x08, 0x1e, + 0x00, 0x08, 0x2c, 0x00, 0x08, 0x1c, 0x00, 0x08, + 0x20, 0x00, 0x08, 0x1c, 0x00, 0x08, 0x22, 0x00, + 0x08, 0x12, 0x2b, 0x0e, 0x00, 0x05, 0x1a, 0x00, + 0x08, 0x2a, 0x2b, 0x00, 0x02, 0x20, 0x1d, 0x00, + 0x05, 0x0e, 0x00, 0x08, 0x10, 0x00, 0x08, 0x14, + 0x00, 0x08, 0x2c, 0x00, 0x08, 0x12, 0x00, 0x08, + 0x12, 0x00, 0x08, 0x22, 0x2d, 0x00, 0x08, 0x44, + 0x00, 0x08, 0x54, 0x00, 0x08, 0x52, 0x00, 0x08, + 0x94, 0x01, 0x00, 0x08, 0x18, 0x00, 0x08, 0x16, + 0x2b, 0x00, 0x02, 0xd2, 0x01, 0x3a, 0x08, 0x26, + 0x26, 0x26, 0x26, 0x28, 0x00, 0x08, 0x10, 0x2c, + 0x08, 0x71, 0x5d, 0x26, 0x2b, 0x22, 0x08, 0x71, + 0x5d, 0x2b, 0x2b, 0x18, 0x00, 0x0c, 0x10, 0x00, + 0x08, 0x18, 0x2d, 0x2b, 0x53, 0x09, 0x0e, 0x43, + 0x06, 0x01, 0xda, 0x04, 0x02, 0x05, 0x02, 0x05, + 0x00, 0x00, 0x77, 0x07, 0xa6, 0x06, 0x00, 0x01, + 0x00, 0xa8, 0x06, 0x00, 0x01, 0x00, 0xaa, 0x06, + 0x00, 0x00, 0x00, 0xac, 0x06, 0x00, 0x01, 0x00, + 0xae, 0x06, 0x00, 0x02, 0x00, 0xb0, 0x06, 0x00, + 0x03, 0x00, 0xb2, 0x06, 0x00, 0x04, 0x00, 0x38, + 0x9a, 0x01, 0x00, 0x00, 0x42, 0x6a, 0x00, 0x00, + 0x00, 0xd2, 0x24, 0x01, 0x00, 0xcc, 0xb5, 0xc9, + 0xc5, 0xc8, 0xe9, 0xa3, 0xea, 0x60, 0xc8, 0xc5, + 0x47, 0xcb, 0x38, 0x95, 0x00, 0x00, 0x00, 0x42, + 0x69, 0x00, 0x00, 0x00, 0xd2, 0xc7, 0x24, 0x02, + 0x00, 0xc4, 0x04, 0x09, 0x43, 0x42, 0x00, 0x00, + 0x00, 0x04, 0x43, 0x00, 0x00, 0x00, 0xc2, 0x04, + 0xa8, 0xea, 0x1d, 0xc2, 0x04, 0x41, 0x43, 0x00, + 0x00, 0x00, 0xf5, 0xeb, 0x11, 0xc2, 0x04, 0x09, + 0x43, 0x41, 0x00, 0x00, 0x00, 0xc2, 0x04, 0x09, + 0x43, 0x40, 0x00, 0x00, 0x00, 0xec, 0x09, 0xc2, + 0x04, 0x09, 0x43, 0x40, 0x00, 0x00, 0x00, 0x38, + 0x95, 0x00, 0x00, 0x00, 0x42, 0x68, 0x00, 0x00, + 0x00, 0xd1, 0xc7, 0xc2, 0x04, 0x24, 0x03, 0x00, + 0x0e, 0x93, 0x00, 0xec, 0x9c, 0x29, 0xc6, 0x03, + 0x23, 0x0e, 0x04, 0x4e, 0x2b, 0x17, 0x58, 0x21, + 0x35, 0x35, 0x2b, 0x2c, 0x0e, 0x2c, 0x5d, 0x17, + 0x0e, 0x41, 0x06, 0x01, 0xdc, 0x04, 0x02, 0x09, + 0x01, 0x07, 0x00, 0x00, 0xfd, 0x01, 0x0b, 0xb6, + 0x06, 0x00, 0x01, 0x00, 0xb8, 0x06, 0x00, 0x01, + 0x00, 0xba, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, + 0x00, 0x01, 0x00, 0xbc, 0x06, 0x00, 0x02, 0x00, + 0xbe, 0x06, 0x00, 0x03, 0x00, 0xc0, 0x06, 0x00, + 0x04, 0x00, 0xc2, 0x06, 0x00, 0x05, 0x00, 0xa6, + 0x06, 0x00, 0x06, 0x00, 0xb0, 0x06, 0x00, 0x07, + 0x00, 0xc4, 0x06, 0x00, 0x08, 0x00, 0x0d, 0x01, + 0x00, 0xd6, 0x04, 0x7f, 0x01, 0x00, 0x00, 0x04, + 0x80, 0x01, 0x00, 0x00, 0x26, 0x02, 0x00, 0xc3, + 0x08, 0x26, 0x00, 0x00, 0xc9, 0xb5, 0xca, 0xc6, + 0xd2, 0xe9, 0xa3, 0x69, 0xb6, 0x00, 0x00, 0x00, + 0xd2, 0xc6, 0x47, 0xcf, 0x41, 0x7f, 0x01, 0x00, + 0x00, 0x11, 0xeb, 0x08, 0x0e, 0xc7, 0x41, 0x80, + 0x01, 0x00, 0x00, 0x69, 0x8e, 0x00, 0x00, 0x00, + 0xc7, 0x41, 0x7f, 0x01, 0x00, 0x00, 0xc7, 0x41, + 0x80, 0x01, 0x00, 0x00, 0x26, 0x02, 0x00, 0xc3, + 0x07, 0xc7, 0x04, 0x7f, 0x01, 0x00, 0x00, 0x98, + 0x0e, 0xc7, 0x04, 0x80, 0x01, 0x00, 0x00, 0x98, + 0x0e, 0xb5, 0xc3, 0x05, 0xc2, 0x05, 0xb7, 0xa3, + 0xea, 0x6c, 0xc2, 0x07, 0xc2, 0x05, 0x47, 0xc4, + 0x06, 0xea, 0x54, 0x38, 0x96, 0x00, 0x00, 0x00, + 0x42, 0xa3, 0x01, 0x00, 0x00, 0xc2, 0x06, 0x24, + 0x01, 0x00, 0x96, 0xea, 0x08, 0xc2, 0x06, 0x26, + 0x01, 0x00, 0xc3, 0x06, 0xb5, 0xcc, 0xc8, 0xc2, + 0x06, 0xe9, 0xa3, 0xea, 0x32, 0x0b, 0xc3, 0x04, + 0x38, 0x95, 0x00, 0x00, 0x00, 0x42, 0xa4, 0x01, + 0x00, 0x00, 0xc2, 0x04, 0xc7, 0x24, 0x02, 0x00, + 0x0e, 0xc2, 0x04, 0xc2, 0x08, 0xc2, 0x05, 0x47, + 0x71, 0xc2, 0x06, 0xc8, 0x47, 0x49, 0xc5, 0x42, + 0xa5, 0x01, 0x00, 0x00, 0xc2, 0x04, 0x24, 0x01, + 0x00, 0x0e, 0x93, 0x03, 0xec, 0xc9, 0x93, 0x05, + 0xec, 0x9b, 0xc5, 0x42, 0xa5, 0x01, 0x00, 0x00, + 0xc7, 0x24, 0x01, 0x00, 0x0e, 0x93, 0x01, 0xed, + 0x47, 0xff, 0xd1, 0x38, 0x9b, 0x00, 0x00, 0x00, + 0x41, 0xa6, 0x01, 0x00, 0x00, 0x71, 0x38, 0xb7, + 0x00, 0x00, 0x00, 0x41, 0xa7, 0x01, 0x00, 0x00, + 0x42, 0xa8, 0x01, 0x00, 0x00, 0x07, 0x26, 0x01, + 0x00, 0xb6, 0xc5, 0x52, 0x0e, 0x18, 0x27, 0x00, + 0x00, 0x49, 0x29, 0xc6, 0x03, 0x3a, 0x19, 0x19, + 0x4e, 0x17, 0x3a, 0x17, 0x67, 0x58, 0x2b, 0x2b, + 0x30, 0x26, 0x0d, 0x5d, 0x27, 0x30, 0x12, 0x58, + 0x44, 0x3f, 0x18, 0x18, 0x3b, 0x1c, 0x3f, 0x8f, + 0x0e, 0x43, 0x06, 0x01, 0xde, 0x04, 0x02, 0x03, + 0x02, 0x04, 0x07, 0x00, 0xa2, 0x01, 0x05, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd2, 0x06, 0x00, 0x00, 0x00, 0xd4, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x02, 0x00, + 0xc8, 0x03, 0x00, 0x00, 0x88, 0x04, 0x01, 0x00, + 0x8a, 0x04, 0x02, 0x00, 0xd2, 0x03, 0x03, 0x00, + 0xd8, 0x03, 0x04, 0x00, 0xb8, 0x04, 0x05, 0x00, + 0xda, 0x03, 0x06, 0x00, 0xdd, 0x42, 0x77, 0x01, + 0x00, 0x00, 0xd2, 0x24, 0x01, 0x00, 0x96, 0xea, + 0x0a, 0xde, 0xdf, 0xd1, 0xef, 0xd2, 0x9a, 0x23, + 0x01, 0x00, 0x38, 0x96, 0x00, 0x00, 0x00, 0x42, + 0xa3, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, + 0xea, 0x23, 0xd1, 0xe0, 0xa7, 0x11, 0xeb, 0x07, + 0x0e, 0xd1, 0x5e, 0x04, 0x00, 0xa7, 0x96, 0xea, + 0x14, 0x5e, 0x05, 0x00, 0x5e, 0x06, 0x00, 0x42, + 0x91, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, + 0xef, 0xc9, 0xec, 0x03, 0xb6, 0xc9, 0xd2, 0xb5, + 0xa9, 0xea, 0x03, 0xc5, 0x28, 0x09, 0xca, 0xd2, + 0xb5, 0xa3, 0xea, 0x06, 0x0a, 0xca, 0xd2, 0x8c, + 0xd6, 0xd1, 0xc9, 0xdd, 0x42, 0xab, 0x01, 0x00, + 0x00, 0xd2, 0x24, 0x01, 0x00, 0xb6, 0x9e, 0xcb, + 0xc7, 0xb5, 0xa6, 0xea, 0x14, 0xc5, 0xc5, 0x9a, + 0xc9, 0xd2, 0xc7, 0xa1, 0xb6, 0xad, 0xea, 0x05, + 0xc5, 0xd1, 0x9a, 0xc9, 0x92, 0x02, 0xec, 0xe9, + 0xc6, 0xea, 0x1a, 0xc5, 0x41, 0xff, 0x00, 0x00, + 0x00, 0xf5, 0xeb, 0x07, 0x04, 0xac, 0x01, 0x00, + 0x00, 0x2f, 0xc5, 0x42, 0xff, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xc9, 0xc5, 0x28, 0xc6, 0x03, + 0x5d, 0x18, 0x04, 0x44, 0x31, 0x76, 0x2b, 0x58, + 0x0d, 0x0e, 0x1c, 0x0d, 0x0d, 0x1c, 0x0d, 0x13, + 0x0d, 0x5d, 0x17, 0x26, 0x17, 0x17, 0x12, 0x30, + 0x21, 0x36, 0x0e, 0x43, 0x06, 0x01, 0xe2, 0x04, + 0x02, 0x06, 0x02, 0x05, 0x02, 0x00, 0x6e, 0x08, + 0xda, 0x06, 0x00, 0x01, 0x00, 0xdc, 0x06, 0x00, + 0x01, 0x00, 0xde, 0x06, 0x00, 0x00, 0x00, 0xd2, + 0x06, 0x00, 0x01, 0x00, 0xe0, 0x06, 0x00, 0x02, + 0x00, 0xaa, 0x06, 0x00, 0x03, 0x00, 0xbe, 0x06, + 0x00, 0x04, 0x00, 0xbc, 0x06, 0x00, 0x05, 0x00, + 0xe0, 0x04, 0x03, 0x01, 0xc8, 0x03, 0x00, 0x00, + 0xd1, 0xb6, 0x9e, 0xc9, 0xb5, 0xcb, 0xc5, 0xb6, + 0xad, 0xb5, 0xa9, 0xea, 0x09, 0xc5, 0xb6, 0xa1, + 0xc9, 0x93, 0x02, 0xec, 0xf2, 0xdd, 0xe9, 0xd2, + 0xa3, 0xea, 0x04, 0xdd, 0xe9, 0xd6, 0xb5, 0xc3, + 0x04, 0xc2, 0x04, 0xd2, 0xa3, 0xea, 0x46, 0xdd, + 0xc2, 0x04, 0x47, 0xc3, 0x05, 0xde, 0x42, 0xf4, + 0x00, 0x00, 0x00, 0xc2, 0x05, 0xc5, 0xd1, 0x24, + 0x03, 0x00, 0xce, 0xb6, 0xa9, 0x11, 0xeb, 0x07, + 0x0e, 0xc6, 0xd1, 0xb6, 0x9e, 0xa9, 0xeb, 0x21, + 0xb6, 0xcc, 0xc8, 0xc7, 0xa3, 0xea, 0x18, 0xc6, + 0xc6, 0x9a, 0xd1, 0x9c, 0xce, 0xb6, 0xa9, 0xea, + 0x03, 0x09, 0x28, 0xc6, 0xd1, 0xb6, 0x9e, 0xa9, + 0xeb, 0x07, 0x93, 0x03, 0xec, 0xe5, 0x09, 0x28, + 0x93, 0x04, 0xec, 0xb6, 0x0a, 0x28, 0xc6, 0x03, + 0x7f, 0x17, 0x04, 0x17, 0x0d, 0x26, 0x17, 0x0d, + 0x0d, 0x21, 0x12, 0x30, 0x21, 0x49, 0x3a, 0x0d, + 0x26, 0x21, 0x17, 0x0d, 0x1c, 0x0d, 0x17, 0x08, + 0x1c, 0x0e, 0x43, 0x06, 0x01, 0xe4, 0x04, 0x02, + 0x02, 0x02, 0x04, 0x01, 0x00, 0x2e, 0x04, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xaa, 0x06, 0x00, 0x00, 0x00, 0xd2, 0x06, + 0x00, 0x01, 0x00, 0xe4, 0x04, 0x05, 0x01, 0xd2, + 0xd1, 0x9e, 0xba, 0xa4, 0xea, 0x16, 0xd1, 0xca, + 0xd1, 0xb6, 0x9d, 0xc9, 0xc5, 0xd2, 0xa4, 0xea, + 0x09, 0xc6, 0xc5, 0x9a, 0xca, 0x93, 0x00, 0xec, + 0xf4, 0xc6, 0x28, 0xd1, 0xd2, 0x9d, 0xb6, 0xa1, + 0xc9, 0xdd, 0xd1, 0xc5, 0xf0, 0xdd, 0xc5, 0xb6, + 0x9d, 0xd2, 0xf0, 0x9a, 0x28, 0xc6, 0x03, 0x9a, + 0x01, 0x08, 0x04, 0x26, 0x0d, 0x30, 0x2b, 0x08, + 0x0a, 0x21, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x02, + 0x00, 0x02, 0x04, 0x02, 0x00, 0x1a, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xcc, 0x03, 0x07, 0x00, 0xca, 0x03, 0x08, + 0x00, 0x38, 0x73, 0x01, 0x00, 0x00, 0xea, 0x0c, + 0xdd, 0x42, 0x81, 0x01, 0x00, 0x00, 0xd1, 0xd2, + 0x25, 0x02, 0x00, 0xde, 0xd1, 0xef, 0xde, 0xd2, + 0xef, 0x9b, 0x28, 0xc6, 0x03, 0xac, 0x01, 0x03, + 0x03, 0x26, 0x3b, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x02, 0x00, 0x02, 0x03, 0x02, 0x00, 0x15, 0x02, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xde, 0x04, 0x02, 0x01, 0xca, 0x03, + 0x08, 0x00, 0x38, 0x73, 0x01, 0x00, 0x00, 0xea, + 0x07, 0xdd, 0xd1, 0xd2, 0x23, 0x02, 0x00, 0xde, + 0xd1, 0xef, 0xde, 0xd2, 0xef, 0x9f, 0x28, 0xc6, + 0x03, 0xb3, 0x01, 0x03, 0x03, 0x26, 0x22, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, + 0x00, 0x00, 0x27, 0x01, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xd1, 0x97, 0x04, 0x8e, 0x00, 0x00, 0x00, + 0xab, 0x11, 0xeb, 0x1c, 0x0e, 0xd1, 0x97, 0x04, + 0x49, 0x00, 0x00, 0x00, 0xab, 0x11, 0xea, 0x10, + 0x0e, 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, 0xb1, + 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0x28, + 0xc6, 0x03, 0xbd, 0x01, 0x02, 0x04, 0x3f, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x02, 0x01, 0x02, 0x02, + 0x00, 0x00, 0x11, 0x03, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd2, 0x06, + 0x00, 0x00, 0x00, 0xd2, 0xb5, 0xaa, 0xea, 0x0b, + 0xd1, 0xd2, 0x9c, 0xc9, 0xd2, 0xd5, 0xc5, 0xd6, + 0xec, 0xf2, 0xd1, 0x28, 0xc6, 0x03, 0xc2, 0x01, + 0x06, 0x04, 0x1c, 0x17, 0x0d, 0x0d, 0x0d, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, + 0x01, 0x00, 0x0c, 0x01, 0xda, 0x06, 0x00, 0x01, + 0x00, 0xe4, 0x04, 0x05, 0x01, 0xd1, 0xb5, 0xa4, + 0xea, 0x03, 0xb6, 0x28, 0xdd, 0xb6, 0xd1, 0xf0, + 0x28, 0xc6, 0x03, 0xcb, 0x01, 0x01, 0x03, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x02, 0x00, 0x02, 0x06, + 0x02, 0x00, 0x35, 0x02, 0xda, 0x06, 0x00, 0x01, + 0x00, 0xc2, 0x06, 0x00, 0x01, 0x00, 0xc8, 0x03, + 0x00, 0x00, 0xe4, 0x04, 0x05, 0x01, 0xd2, 0xb5, + 0xa3, 0x11, 0xeb, 0x05, 0x0e, 0xd2, 0xd1, 0xa5, + 0xea, 0x03, 0xb5, 0x28, 0xd2, 0xd1, 0xd2, 0x9e, + 0xa5, 0xea, 0x05, 0xd1, 0xd2, 0x9e, 0xd6, 0xd2, + 0xb5, 0xa9, 0xea, 0x03, 0xb6, 0x28, 0xdd, 0x42, + 0xb2, 0x01, 0x00, 0x00, 0xde, 0xd1, 0xd2, 0x9e, + 0xb6, 0x9d, 0xd1, 0xf0, 0xde, 0xb6, 0xd2, 0xf0, + 0x25, 0x02, 0x00, 0xc6, 0x03, 0xcf, 0x01, 0x07, + 0x03, 0x3f, 0x0d, 0x26, 0x17, 0x1c, 0x0d, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x02, 0x06, 0x02, 0x04, + 0x01, 0x00, 0x4b, 0x08, 0xe6, 0x06, 0x00, 0x01, + 0x00, 0xe8, 0x06, 0x00, 0x01, 0x00, 0xea, 0x06, + 0x00, 0x00, 0x00, 0xec, 0x06, 0x00, 0x01, 0x00, + 0xee, 0x06, 0x00, 0x02, 0x00, 0xbc, 0x06, 0x00, + 0x03, 0x00, 0xf0, 0x06, 0x00, 0x04, 0x00, 0xdc, + 0x06, 0x00, 0x05, 0x00, 0xc8, 0x03, 0x00, 0x00, + 0xd1, 0xca, 0xd2, 0xcb, 0xb6, 0xc3, 0x04, 0xb5, + 0xcc, 0xc6, 0xb5, 0xaa, 0xea, 0x29, 0xdd, 0x42, + 0xb9, 0x01, 0x00, 0x00, 0xc7, 0xc6, 0x24, 0x02, + 0x00, 0xc4, 0x05, 0xb5, 0x47, 0xc9, 0xc6, 0xcb, + 0xc2, 0x05, 0xb6, 0x47, 0xca, 0xc2, 0x04, 0xc3, + 0x05, 0xc8, 0xc5, 0xc2, 0x04, 0x9a, 0x9e, 0xc3, + 0x04, 0xc2, 0x05, 0xcc, 0xec, 0xd4, 0xc7, 0xb6, + 0xaa, 0xea, 0x0d, 0x38, 0xcd, 0x00, 0x00, 0x00, + 0x04, 0xba, 0x01, 0x00, 0x00, 0xef, 0x2f, 0xc8, + 0xd2, 0x9c, 0x28, 0xc6, 0x03, 0xd9, 0x01, 0x10, + 0x04, 0x0d, 0x0d, 0x12, 0x0d, 0x1c, 0x44, 0x12, + 0x0d, 0x1c, 0x17, 0x2b, 0x12, 0x0e, 0x1c, 0x3f, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x03, 0x01, 0x03, + 0x04, 0x01, 0x00, 0x3a, 0x04, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xf6, + 0x06, 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, 0x00, + 0x00, 0xc8, 0x03, 0x00, 0x00, 0xd2, 0xb5, 0xa9, + 0xea, 0x03, 0xb6, 0x28, 0xd2, 0xb5, 0xa3, 0xea, + 0x10, 0xdd, 0x42, 0xf5, 0x00, 0x00, 0x00, 0xd1, + 0xd3, 0x24, 0x02, 0x00, 0xd5, 0xd2, 0x8c, 0xd6, + 0xb6, 0xc9, 0xd2, 0xb6, 0xad, 0xea, 0x07, 0xc5, + 0xd1, 0x9a, 0xd3, 0x9c, 0xc9, 0xd2, 0xb6, 0xa1, + 0xda, 0xb5, 0xa9, 0xeb, 0x09, 0xd1, 0xd1, 0x9a, + 0xd3, 0x9c, 0xd5, 0xec, 0xe6, 0xc5, 0x28, 0xc6, + 0x03, 0xee, 0x01, 0x0e, 0x04, 0x1c, 0x0d, 0x1c, + 0x3f, 0x13, 0x0e, 0x1c, 0x22, 0x17, 0x0d, 0x0d, + 0x21, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x02, + 0x03, 0x02, 0x03, 0x03, 0x00, 0x5e, 0x05, 0xda, + 0x06, 0x00, 0x01, 0x00, 0xdc, 0x06, 0x00, 0x01, + 0x00, 0xaa, 0x06, 0x00, 0x00, 0x00, 0xde, 0x06, + 0x00, 0x01, 0x00, 0xf8, 0x06, 0x00, 0x02, 0x00, + 0xc8, 0x03, 0x00, 0x00, 0xe0, 0x04, 0x03, 0x01, + 0xe2, 0x04, 0x04, 0x01, 0xdd, 0x42, 0x77, 0x01, + 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0x96, 0xea, + 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0xbd, + 0x01, 0x00, 0x00, 0xef, 0x2f, 0xd1, 0xb6, 0xa4, + 0xea, 0x03, 0x09, 0x28, 0xde, 0xe9, 0xcb, 0xb5, + 0xc9, 0xc5, 0xc7, 0xa3, 0xea, 0x1f, 0xde, 0xc5, + 0x47, 0xce, 0xd1, 0xa9, 0xea, 0x03, 0x0a, 0x28, + 0xc6, 0xd1, 0xa5, 0xea, 0x03, 0x09, 0x28, 0xd1, + 0xc6, 0x9c, 0xb5, 0xa9, 0xea, 0x03, 0x09, 0x28, + 0x93, 0x00, 0xec, 0xde, 0xd1, 0xc6, 0xc6, 0x9a, + 0xa3, 0xea, 0x03, 0x0a, 0x28, 0xd2, 0xf4, 0xea, + 0x04, 0xbd, 0x40, 0xd6, 0xdf, 0xd1, 0xd2, 0x23, + 0x02, 0x00, 0xc6, 0x03, 0x85, 0x02, 0x13, 0x04, + 0x44, 0x3f, 0x1c, 0x0d, 0x13, 0x26, 0x17, 0x17, + 0x0d, 0x1c, 0x0d, 0x26, 0x0d, 0x17, 0x26, 0x0d, + 0x17, 0x12, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x03, 0x01, 0x00, 0x31, 0x01, 0xda, + 0x06, 0x00, 0x01, 0x00, 0xc8, 0x03, 0x00, 0x00, + 0xdd, 0x42, 0x77, 0x01, 0x00, 0x00, 0xd1, 0x24, + 0x01, 0x00, 0x96, 0xea, 0x0d, 0x38, 0xd0, 0x00, + 0x00, 0x00, 0x04, 0xbd, 0x01, 0x00, 0x00, 0xef, + 0x2f, 0xd1, 0xb6, 0xa3, 0xea, 0x03, 0xb6, 0xd5, + 0xd1, 0x8f, 0xd5, 0xdd, 0x42, 0x2a, 0x01, 0x00, + 0x00, 0xd1, 0x24, 0x01, 0x00, 0xea, 0xf2, 0xd1, + 0x28, 0xc6, 0x03, 0x9c, 0x02, 0x08, 0x03, 0x44, + 0x3f, 0x1c, 0x0e, 0x12, 0x3f, 0x08, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x01, 0x02, 0x01, 0x04, 0x02, + 0x00, 0xab, 0x01, 0x03, 0xda, 0x06, 0x00, 0x01, + 0x00, 0xd2, 0x06, 0x00, 0x00, 0x00, 0xde, 0x06, + 0x00, 0x01, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xf8, + 0x03, 0x09, 0x00, 0xdd, 0x42, 0x77, 0x01, 0x00, + 0x00, 0xd1, 0x24, 0x01, 0x00, 0x96, 0xea, 0x0d, + 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0xbd, 0x01, + 0x00, 0x00, 0xef, 0x2f, 0x26, 0x00, 0x00, 0xc9, + 0xde, 0xd1, 0xef, 0xb6, 0xa4, 0xea, 0x0e, 0xc5, + 0x42, 0xa5, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, + 0x00, 0x0e, 0xc5, 0x28, 0xd1, 0xb5, 0xa3, 0xea, + 0x0f, 0xc5, 0x42, 0xa5, 0x01, 0x00, 0x00, 0xb4, + 0x24, 0x01, 0x00, 0x0e, 0xd1, 0x8c, 0xd5, 0xd1, + 0xb7, 0x9c, 0xb5, 0xa9, 0xea, 0x12, 0xd1, 0xb6, + 0xa1, 0xd5, 0xc5, 0x42, 0xa5, 0x01, 0x00, 0x00, + 0xb7, 0x24, 0x01, 0x00, 0x0e, 0xec, 0xe9, 0xb8, + 0xca, 0xd1, 0xb6, 0xaa, 0xea, 0x47, 0xdd, 0x42, + 0x2a, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, + 0xea, 0x0e, 0xc5, 0x42, 0xa5, 0x01, 0x00, 0x00, + 0xd1, 0x24, 0x01, 0x00, 0x0e, 0xec, 0x2e, 0xd1, + 0xc6, 0x9c, 0xb5, 0xa9, 0xeb, 0x06, 0xb7, 0x94, + 0x01, 0xec, 0xf5, 0xc5, 0x42, 0xa5, 0x01, 0x00, + 0x00, 0xc6, 0x24, 0x01, 0x00, 0x0e, 0xdd, 0x42, + 0xb2, 0x01, 0x00, 0x00, 0xd1, 0xc6, 0x24, 0x02, + 0x00, 0xd9, 0xc6, 0x9c, 0xb5, 0xaa, 0xeb, 0x03, + 0xec, 0xe2, 0xec, 0xb6, 0xc5, 0x28, 0xc6, 0x03, + 0xa7, 0x02, 0x20, 0x04, 0x44, 0x3f, 0x17, 0x26, + 0x3a, 0x08, 0x08, 0x1c, 0x3a, 0x14, 0x26, 0x17, + 0x3a, 0x0e, 0x0d, 0x1c, 0x3f, 0x3a, 0x00, 0x02, + 0x08, 0x1c, 0x0d, 0x12, 0x0e, 0x3a, 0x3f, 0x17, + 0x0d, 0x0d, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x06, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xc9, 0xb6, 0xc5, + 0x9b, 0x28, 0xc6, 0x03, 0xd2, 0x02, 0x01, 0x0d, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x06, 0x01, 0x10, 0x00, 0x01, + 0x00, 0x08, 0xc9, 0xc5, 0xc5, 0x9a, 0x28, 0xc6, + 0x03, 0xd5, 0x02, 0x01, 0x0d, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, + 0x0d, 0x02, 0xee, 0x06, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xca, 0xc6, 0xcd, 0xb5, + 0xa3, 0xea, 0x04, 0xc5, 0x8c, 0xc9, 0xc5, 0x28, + 0xc6, 0x03, 0xd8, 0x02, 0x04, 0x0d, 0x08, 0x1c, + 0x12, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, 0x10, 0x00, + 0x01, 0x00, 0x08, 0xc9, 0xc5, 0x28, 0xc6, 0x03, + 0xde, 0x02, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x01, 0x00, 0x10, + 0x01, 0x10, 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, + 0x00, 0x08, 0xc9, 0xc5, 0xb5, 0xa6, 0xea, 0x03, + 0xb5, 0x28, 0xdd, 0x41, 0x29, 0x01, 0x00, 0x00, + 0x28, 0xc6, 0x03, 0xe1, 0x02, 0x04, 0x0d, 0x1c, + 0x08, 0x08, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x03, 0x01, 0x00, 0x13, 0x01, 0x10, + 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, 0x00, 0x08, + 0xc9, 0xc5, 0xb5, 0xa9, 0xea, 0x03, 0xb6, 0x28, + 0xdd, 0x42, 0x04, 0x01, 0x00, 0x00, 0xc5, 0x25, + 0x01, 0x00, 0xc6, 0x03, 0xe7, 0x02, 0x04, 0x0d, + 0x1c, 0x08, 0x08, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x02, 0x01, 0x00, 0x14, 0x01, + 0x10, 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, 0x00, + 0x08, 0xc9, 0xc5, 0xb6, 0xa9, 0xea, 0x03, 0xb5, + 0x28, 0xdd, 0xc5, 0xef, 0x42, 0x05, 0x01, 0x00, + 0x00, 0x25, 0x00, 0x00, 0xc6, 0x03, 0xed, 0x02, + 0x04, 0x0d, 0x1c, 0x08, 0x08, 0x0e, 0x43, 0x06, + 0x01, 0xcc, 0x03, 0x02, 0x05, 0x02, 0x04, 0x01, + 0x00, 0xc0, 0x01, 0x07, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xde, 0x06, + 0x00, 0x00, 0x00, 0xd2, 0x06, 0x00, 0x01, 0x00, + 0xa6, 0x06, 0x00, 0x02, 0x00, 0xe8, 0x01, 0x00, + 0x01, 0x00, 0xcc, 0x03, 0x00, 0x01, 0x14, 0xc8, + 0x03, 0x00, 0x00, 0x0c, 0x03, 0xcc, 0x0c, 0x02, + 0xc3, 0x04, 0xc8, 0xea, 0x0d, 0x38, 0xd0, 0x00, + 0x00, 0x00, 0x04, 0xbe, 0x01, 0x00, 0x00, 0xef, + 0x2f, 0xd1, 0xc2, 0x04, 0xa7, 0xea, 0x03, 0xd1, + 0x28, 0xdd, 0x42, 0x77, 0x01, 0x00, 0x00, 0xd1, + 0x24, 0x01, 0x00, 0x96, 0xea, 0x0d, 0x38, 0xd0, + 0x00, 0x00, 0x00, 0x04, 0xbf, 0x01, 0x00, 0x00, + 0xef, 0x2f, 0xd2, 0xf4, 0xea, 0x05, 0xb6, 0xd6, + 0xec, 0x5e, 0xdd, 0x42, 0x77, 0x01, 0x00, 0x00, + 0xd2, 0x24, 0x01, 0x00, 0x96, 0xea, 0x0d, 0x38, + 0xd0, 0x00, 0x00, 0x00, 0x04, 0xbf, 0x01, 0x00, + 0x00, 0xef, 0x2f, 0xd2, 0xb5, 0xa9, 0xea, 0x0d, + 0x38, 0xcd, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x01, + 0x00, 0x00, 0xef, 0x2f, 0xdd, 0x42, 0xf1, 0x00, + 0x00, 0x00, 0xd1, 0xd2, 0x24, 0x02, 0x00, 0xcd, + 0xb6, 0xaa, 0xea, 0x19, 0xdd, 0x42, 0xb2, 0x01, + 0x00, 0x00, 0xd1, 0xc5, 0x24, 0x02, 0x00, 0xd5, + 0xdd, 0x42, 0xb2, 0x01, 0x00, 0x00, 0xd2, 0xc5, + 0x24, 0x02, 0x00, 0xd6, 0xd2, 0xb5, 0xa3, 0xea, + 0x07, 0xd1, 0x8c, 0xd5, 0xd2, 0x8c, 0xd6, 0x38, + 0x95, 0x00, 0x00, 0x00, 0x42, 0xa7, 0x01, 0x00, + 0x00, 0xc2, 0x04, 0x41, 0x3e, 0x00, 0x00, 0x00, + 0x24, 0x01, 0x00, 0xcf, 0xd1, 0x43, 0xc1, 0x01, + 0x00, 0x00, 0xc7, 0xd2, 0x43, 0xc2, 0x01, 0x00, + 0x00, 0xc7, 0x28, 0xc6, 0x03, 0xf7, 0x02, 0x1c, + 0x00, 0x07, 0x08, 0x12, 0x3f, 0x21, 0x0d, 0x44, + 0x3f, 0x17, 0x0d, 0x0d, 0x44, 0x3f, 0x1c, 0x3f, + 0x3f, 0x17, 0x3f, 0x00, 0x0c, 0x08, 0x1c, 0x12, + 0x14, 0x6c, 0x21, 0x26, 0x0e, 0x43, 0x06, 0x01, + 0xe6, 0x04, 0x02, 0x00, 0x02, 0x05, 0x01, 0x00, + 0x39, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xcc, 0x03, 0x07, 0x00, + 0xdd, 0xd1, 0xef, 0xd5, 0xdd, 0xd2, 0xef, 0xd6, + 0xdd, 0x42, 0x81, 0x01, 0x00, 0x00, 0xd1, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x9a, 0xd1, 0x41, 0xc2, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xc1, 0x01, 0x00, 0x00, 0x9a, + 0x9d, 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xd2, + 0x41, 0xc2, 0x01, 0x00, 0x00, 0x9a, 0x25, 0x02, + 0x00, 0xc6, 0x03, 0x9a, 0x03, 0x03, 0x03, 0x17, + 0x17, 0x0e, 0x43, 0x06, 0x01, 0xe8, 0x04, 0x02, + 0x00, 0x02, 0x05, 0x01, 0x00, 0x39, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xcc, 0x03, 0x07, 0x00, 0xdd, 0xd1, 0xef, + 0xd5, 0xdd, 0xd2, 0xef, 0xd6, 0xdd, 0x42, 0x81, + 0x01, 0x00, 0x00, 0xd1, 0x41, 0xc1, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xc2, 0x01, 0x00, 0x00, 0x9a, + 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xd2, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0x9a, 0x9e, 0xd1, 0x41, + 0xc2, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x9a, 0x25, 0x02, 0x00, 0xc6, 0x03, + 0x9f, 0x03, 0x03, 0x03, 0x17, 0x17, 0x0e, 0x43, + 0x06, 0x01, 0xea, 0x04, 0x02, 0x00, 0x02, 0x05, + 0x01, 0x00, 0x2b, 0x02, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xcc, 0x03, + 0x07, 0x00, 0xdd, 0xd1, 0xef, 0xd5, 0xdd, 0xd2, + 0xef, 0xd6, 0xdd, 0x42, 0x81, 0x01, 0x00, 0x00, + 0xd1, 0x41, 0xc1, 0x01, 0x00, 0x00, 0xd2, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0x9a, 0xd1, 0x41, 0xc2, + 0x01, 0x00, 0x00, 0xd2, 0x41, 0xc2, 0x01, 0x00, + 0x00, 0x9a, 0x25, 0x02, 0x00, 0xc6, 0x03, 0xa4, + 0x03, 0x03, 0x03, 0x17, 0x17, 0x0e, 0x43, 0x06, + 0x01, 0xec, 0x04, 0x02, 0x00, 0x02, 0x05, 0x01, + 0x00, 0x2b, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xcc, 0x03, 0x07, + 0x00, 0xdd, 0xd1, 0xef, 0xd5, 0xdd, 0xd2, 0xef, + 0xd6, 0xdd, 0x42, 0x81, 0x01, 0x00, 0x00, 0xd1, + 0x41, 0xc1, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xc2, + 0x01, 0x00, 0x00, 0x9a, 0xd1, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0xd2, 0x41, 0xc1, 0x01, 0x00, 0x00, + 0x9a, 0x25, 0x02, 0x00, 0xc6, 0x03, 0xa9, 0x03, + 0x03, 0x03, 0x17, 0x17, 0x0e, 0x43, 0x06, 0x01, + 0xee, 0x04, 0x02, 0x02, 0x02, 0x06, 0x02, 0x00, + 0x30, 0x04, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0x86, 0x07, 0x00, 0x00, + 0x00, 0x88, 0x07, 0x00, 0x01, 0x00, 0xcc, 0x03, + 0x07, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xdd, 0xd1, + 0xef, 0xc9, 0xdd, 0xd2, 0xef, 0xca, 0xd1, 0xde, + 0x42, 0xc5, 0x01, 0x00, 0x00, 0xc5, 0x41, 0xc1, + 0x01, 0x00, 0x00, 0xc6, 0x41, 0xc2, 0x01, 0x00, + 0x00, 0x9a, 0xc5, 0x41, 0xc2, 0x01, 0x00, 0x00, + 0xc6, 0x41, 0xc1, 0x01, 0x00, 0x00, 0x9a, 0x24, + 0x02, 0x00, 0xd2, 0x9a, 0x9e, 0x28, 0xc6, 0x03, + 0xae, 0x03, 0x03, 0x03, 0x17, 0x17, 0x0e, 0x43, + 0x06, 0x01, 0xf0, 0x04, 0x02, 0x00, 0x02, 0x02, + 0x01, 0x00, 0x27, 0x02, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xcc, 0x03, + 0x07, 0x00, 0xdd, 0xd1, 0xef, 0xd5, 0xdd, 0xd2, + 0xef, 0xd6, 0xd1, 0x41, 0xc1, 0x01, 0x00, 0x00, + 0xd2, 0x41, 0xc1, 0x01, 0x00, 0x00, 0xa9, 0x11, + 0xea, 0x0f, 0x0e, 0xd1, 0x41, 0xc2, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xa9, + 0x28, 0xc6, 0x03, 0xb3, 0x03, 0x03, 0x03, 0x17, + 0x18, 0x0e, 0x43, 0x06, 0x01, 0xf2, 0x04, 0x02, + 0x00, 0x02, 0x03, 0x01, 0x00, 0x24, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xcc, 0x03, 0x07, 0x00, 0xdd, 0xd1, 0xef, + 0xd5, 0xdd, 0xd2, 0xef, 0xd6, 0xd1, 0x41, 0xc1, + 0x01, 0x00, 0x00, 0xd2, 0x41, 0xc2, 0x01, 0x00, + 0x00, 0x9a, 0xd2, 0x41, 0xc1, 0x01, 0x00, 0x00, + 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, 0x9a, 0xa3, + 0x28, 0xc6, 0x03, 0xb9, 0x03, 0x03, 0x03, 0x17, + 0x17, 0x0e, 0x43, 0x06, 0x01, 0xf4, 0x04, 0x02, + 0x00, 0x02, 0x03, 0x01, 0x00, 0x08, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x08, 0x00, 0xdd, 0xd1, 0xef, + 0xdd, 0xd2, 0xef, 0x9d, 0x28, 0xc6, 0x03, 0xc0, + 0x03, 0x01, 0x03, 0x0e, 0x43, 0x06, 0x01, 0xf6, + 0x04, 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, 0x08, + 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, 0x00, 0xdd, + 0xd1, 0xef, 0xdd, 0xd2, 0xef, 0x9e, 0x28, 0xc6, + 0x03, 0xc3, 0x03, 0x01, 0x03, 0x0e, 0x43, 0x06, + 0x01, 0xf8, 0x04, 0x02, 0x00, 0x02, 0x03, 0x01, + 0x00, 0x08, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, + 0x00, 0xdd, 0xd1, 0xef, 0xdd, 0xd2, 0xef, 0x9a, + 0x28, 0xc6, 0x03, 0xc6, 0x03, 0x01, 0x03, 0x0e, + 0x43, 0x06, 0x01, 0xfa, 0x04, 0x02, 0x00, 0x02, + 0x03, 0x01, 0x00, 0x08, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xca, + 0x03, 0x08, 0x00, 0xdd, 0xd1, 0xef, 0xdd, 0xd2, + 0xef, 0x9b, 0x28, 0xc6, 0x03, 0xc9, 0x03, 0x01, + 0x03, 0x0e, 0x43, 0x06, 0x01, 0xfc, 0x04, 0x02, + 0x00, 0x02, 0x03, 0x01, 0x00, 0x08, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x08, 0x00, 0xdd, 0xd1, 0xef, + 0xdd, 0xd2, 0xef, 0x9c, 0x28, 0xc6, 0x03, 0xcc, + 0x03, 0x01, 0x03, 0x0e, 0x43, 0x06, 0x01, 0xfe, + 0x04, 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, 0x08, + 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, 0x00, 0xdd, + 0xd1, 0xef, 0xdd, 0xd2, 0xef, 0x9f, 0x28, 0xc6, + 0x03, 0xcf, 0x03, 0x01, 0x03, 0x0e, 0x43, 0x06, + 0x01, 0x80, 0x05, 0x02, 0x00, 0x02, 0x03, 0x01, + 0x00, 0x08, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, + 0x00, 0xdd, 0xd1, 0xef, 0xdd, 0xd2, 0xef, 0xab, + 0x28, 0xc6, 0x03, 0xd2, 0x03, 0x01, 0x04, 0x0e, + 0x43, 0x06, 0x01, 0x82, 0x05, 0x02, 0x00, 0x02, + 0x03, 0x01, 0x00, 0x2c, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xca, + 0x03, 0x08, 0x00, 0xdd, 0xd1, 0xef, 0xd5, 0xdd, + 0xd2, 0xef, 0xd6, 0xdd, 0x42, 0xc6, 0x01, 0x00, + 0x00, 0xd1, 0x24, 0x01, 0x00, 0x11, 0xeb, 0x0c, + 0x0e, 0xdd, 0x42, 0xc6, 0x01, 0x00, 0x00, 0xd2, + 0x24, 0x01, 0x00, 0xea, 0x07, 0x38, 0x48, 0x00, + 0x00, 0x00, 0x28, 0xd1, 0xd2, 0xa3, 0x28, 0xc6, + 0x03, 0xd6, 0x03, 0x06, 0x03, 0x17, 0x18, 0x85, + 0x1c, 0x08, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x01, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xd1, 0x28, 0xc6, 0x03, + 0xea, 0x03, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x00, 0x11, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xcc, 0x03, + 0x07, 0x00, 0xdd, 0xd1, 0x41, 0xc1, 0x01, 0x00, + 0x00, 0x8c, 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, + 0x23, 0x02, 0x00, 0xc6, 0x03, 0xed, 0x03, 0x01, + 0x03, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x02, 0x01, + 0x02, 0x03, 0x01, 0x00, 0x1f, 0x03, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xd2, 0x06, 0x00, 0x00, 0x00, 0xcc, 0x03, 0x07, + 0x00, 0xdd, 0xd1, 0xd2, 0xf0, 0xc9, 0x38, 0x73, + 0x01, 0x00, 0x00, 0xea, 0x12, 0xc5, 0x41, 0xc2, + 0x01, 0x00, 0x00, 0xb6, 0xa9, 0xea, 0x08, 0xc5, + 0x41, 0xc1, 0x01, 0x00, 0x00, 0x28, 0xc5, 0x28, + 0xc6, 0x03, 0x8c, 0x04, 0x05, 0x03, 0x1c, 0x58, + 0x21, 0x08, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x02, 0x01, 0x00, 0x24, 0x02, 0x8e, + 0x07, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, + 0xca, 0x03, 0x08, 0x00, 0x08, 0xc9, 0xd1, 0x04, + 0x4b, 0x00, 0x00, 0x00, 0xab, 0xea, 0x0a, 0xc5, + 0x42, 0x3a, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, + 0xdd, 0xc5, 0x41, 0xc1, 0x01, 0x00, 0x00, 0xef, + 0xc5, 0x41, 0xc2, 0x01, 0x00, 0x00, 0x9b, 0x28, + 0xc6, 0x03, 0x96, 0x04, 0x03, 0x0d, 0x30, 0x31, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x03, 0x01, 0x00, 0x12, 0x01, 0x10, 0x00, 0x01, + 0x00, 0xcc, 0x03, 0x07, 0x00, 0x08, 0xc9, 0xdd, + 0xc5, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xc5, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xc6, + 0x03, 0x9d, 0x04, 0x01, 0x0d, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, + 0x16, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xc9, + 0xc5, 0x41, 0xc1, 0x01, 0x00, 0x00, 0x04, 0x75, + 0x01, 0x00, 0x00, 0x9d, 0xc5, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x9d, 0x28, 0xc6, 0x03, 0xa0, 0x04, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x06, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc9, 0xc5, 0xc5, 0x9a, + 0x28, 0xc6, 0x03, 0xa3, 0x04, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x11, 0x01, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xc9, 0xc5, 0x41, 0xc1, 0x01, 0x00, 0x00, + 0xb5, 0xa3, 0xea, 0x04, 0xc5, 0x8c, 0x28, 0xc5, + 0x28, 0xc6, 0x03, 0xa6, 0x04, 0x04, 0x0d, 0x35, + 0x0d, 0x08, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc9, 0xc5, 0x28, 0xc6, + 0x03, 0xac, 0x04, 0x01, 0x0d, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x01, 0x00, + 0x15, 0x01, 0x10, 0x00, 0x01, 0x00, 0xca, 0x03, + 0x08, 0x00, 0x08, 0xc9, 0xc5, 0x41, 0xc1, 0x01, + 0x00, 0x00, 0xb5, 0xa6, 0xea, 0x03, 0xb5, 0x28, + 0xdd, 0x41, 0x29, 0x01, 0x00, 0x00, 0x28, 0xc6, + 0x03, 0xaf, 0x04, 0x04, 0x0d, 0x35, 0x08, 0x08, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x04, 0x01, 0x00, 0x0e, 0x01, 0x10, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x08, 0x00, 0x08, 0xc9, 0xdd, + 0x42, 0x04, 0x01, 0x00, 0x00, 0xdd, 0xc5, 0xef, + 0x25, 0x01, 0x00, 0xc6, 0x03, 0xb5, 0x04, 0x01, + 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x01, 0x00, 0x0d, 0x01, 0x10, 0x00, + 0x01, 0x00, 0xca, 0x03, 0x08, 0x00, 0x08, 0xc9, + 0xdd, 0xc5, 0xef, 0x42, 0x05, 0x01, 0x00, 0x00, + 0x25, 0x00, 0x00, 0xc6, 0x03, 0xb8, 0x04, 0x01, + 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x00, 0x06, 0x01, 0x10, 0x00, + 0x01, 0x00, 0x08, 0xc9, 0xb6, 0xc5, 0x9b, 0x28, + 0xc6, 0x03, 0xc0, 0x04, 0x01, 0x0d, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x06, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xc9, 0xc5, 0xc5, 0x9a, 0x28, 0xc6, 0x03, 0xc3, + 0x04, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x10, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xc9, 0x38, 0x9d, + 0x00, 0x00, 0x00, 0x42, 0xfc, 0x00, 0x00, 0x00, + 0xc5, 0x25, 0x01, 0x00, 0xc6, 0x03, 0xc6, 0x04, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc9, 0xc5, 0x28, 0xc6, + 0x03, 0xc9, 0x04, 0x01, 0x0d, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x01, 0x00, + 0x10, 0x01, 0x10, 0x00, 0x01, 0x00, 0xca, 0x03, + 0x08, 0x00, 0x08, 0xc9, 0xc5, 0xb5, 0xa6, 0xea, + 0x03, 0xb5, 0x28, 0xdd, 0x41, 0x29, 0x01, 0x00, + 0x00, 0x28, 0xc6, 0x03, 0xcc, 0x04, 0x04, 0x0d, + 0x1c, 0x08, 0x08, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x01, 0x00, 0x0c, 0x01, + 0x10, 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, 0x00, + 0x08, 0xc9, 0xdd, 0x42, 0x04, 0x01, 0x00, 0x00, + 0xc5, 0x25, 0x01, 0x00, 0xc6, 0x03, 0xd2, 0x04, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x03, 0x02, 0x00, 0x1c, 0x01, 0x10, + 0x00, 0x01, 0x00, 0xce, 0x03, 0x0a, 0x00, 0xca, + 0x03, 0x08, 0x00, 0x08, 0xc9, 0xc5, 0xb5, 0xa3, + 0xea, 0x0c, 0xdd, 0xc5, 0xef, 0x42, 0x05, 0x01, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xde, 0x42, 0x05, + 0x01, 0x00, 0x00, 0xc5, 0x25, 0x01, 0x00, 0xc6, + 0x03, 0xd5, 0x04, 0x03, 0x0d, 0x1c, 0x3b, 0x0e, + 0x43, 0x06, 0x01, 0x86, 0x05, 0x01, 0x03, 0x01, + 0x05, 0x02, 0x01, 0xb0, 0x01, 0x04, 0xda, 0x06, + 0x00, 0x01, 0x00, 0xdc, 0x06, 0x00, 0x00, 0x00, + 0xf0, 0x06, 0x00, 0x01, 0x00, 0x90, 0x07, 0x00, + 0x02, 0x00, 0x84, 0x05, 0x15, 0x01, 0xca, 0x03, + 0x08, 0x00, 0xdd, 0xd1, 0x47, 0xc9, 0x38, 0xb4, + 0x00, 0x00, 0x00, 0x41, 0xc9, 0x01, 0x00, 0x00, + 0xcb, 0xc5, 0xea, 0x12, 0xc5, 0x41, 0xc9, 0x01, + 0x00, 0x00, 0xc7, 0xa9, 0xea, 0x08, 0xc5, 0x41, + 0x96, 0x01, 0x00, 0x00, 0x28, 0xd1, 0x11, 0xb5, + 0xab, 0xea, 0x0e, 0xde, 0x42, 0x04, 0x01, 0x00, + 0x00, 0xb6, 0x24, 0x01, 0x00, 0xca, 0xec, 0x60, + 0x11, 0xb6, 0xab, 0xea, 0x0f, 0xde, 0x42, 0x05, + 0x01, 0x00, 0x00, 0xbd, 0x0a, 0x24, 0x01, 0x00, + 0xca, 0xec, 0x4d, 0x11, 0xb8, 0xab, 0xea, 0x10, + 0xb6, 0xde, 0x42, 0x05, 0x01, 0x00, 0x00, 0xb7, + 0x24, 0x01, 0x00, 0x9b, 0xca, 0xec, 0x39, 0x11, + 0xb9, 0xab, 0xea, 0x11, 0xb6, 0xde, 0x42, 0x05, + 0x01, 0x00, 0x00, 0xbd, 0x0a, 0x24, 0x01, 0x00, + 0x9b, 0xca, 0xec, 0x24, 0x11, 0xbb, 0xab, 0xea, + 0x0f, 0xde, 0x42, 0x03, 0x01, 0x00, 0x00, 0xbf, + 0x00, 0x24, 0x01, 0x00, 0xca, 0xec, 0x11, 0x11, + 0xbc, 0xab, 0xea, 0x0c, 0xde, 0x42, 0x03, 0x01, + 0x00, 0x00, 0xb7, 0x24, 0x01, 0x00, 0xca, 0x0e, + 0xc7, 0xbe, 0x00, 0x04, 0xa4, 0xea, 0x12, 0xdd, + 0xd1, 0x71, 0x0b, 0xc7, 0x4c, 0xc9, 0x01, 0x00, + 0x00, 0xc6, 0x4c, 0x96, 0x01, 0x00, 0x00, 0x49, + 0xc6, 0x28, 0xc6, 0x03, 0xe3, 0x04, 0x10, 0x04, + 0x17, 0x3a, 0x44, 0x21, 0x08, 0x08, 0x5d, 0x63, + 0x67, 0x6d, 0x62, 0x53, 0x08, 0x26, 0x59, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x15, 0x01, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xd1, 0x97, 0x04, 0x49, 0x00, 0x00, + 0x00, 0xab, 0x11, 0xeb, 0x0a, 0x0e, 0xd1, 0x97, + 0x04, 0x8f, 0x00, 0x00, 0x00, 0xab, 0x28, 0xc6, + 0x03, 0xfc, 0x04, 0x01, 0x03, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x02, 0x07, 0x02, 0x04, 0x03, 0x00, + 0x51, 0x09, 0xec, 0x06, 0x00, 0x01, 0x00, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0x94, 0x07, 0x00, 0x00, + 0x00, 0x96, 0x07, 0x00, 0x01, 0x00, 0x98, 0x07, + 0x00, 0x02, 0x00, 0x9a, 0x07, 0x00, 0x03, 0x00, + 0x82, 0x07, 0x00, 0x04, 0x00, 0x84, 0x07, 0x00, + 0x05, 0x00, 0xda, 0x06, 0x00, 0x06, 0x00, 0xc8, + 0x03, 0x00, 0x00, 0xca, 0x03, 0x08, 0x00, 0xcc, + 0x03, 0x07, 0x00, 0xd2, 0xf4, 0xea, 0x0d, 0x38, + 0xd0, 0x00, 0x00, 0x00, 0x04, 0xce, 0x01, 0x00, + 0x00, 0xef, 0x2f, 0xb6, 0xc9, 0xb5, 0xca, 0xb5, + 0xcb, 0xb6, 0xcc, 0xdd, 0xde, 0x42, 0x01, 0x01, + 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xef, 0xc4, + 0x06, 0xc5, 0x9a, 0xc6, 0x9d, 0xc3, 0x04, 0xc2, + 0x06, 0xc7, 0x9a, 0xc8, 0x9d, 0xc4, 0x05, 0xd2, + 0xa5, 0xeb, 0x14, 0xb6, 0xd1, 0xc2, 0x06, 0x9e, + 0x9b, 0xd5, 0xc5, 0xca, 0xc2, 0x04, 0xc9, 0xc7, + 0xcc, 0xc2, 0x05, 0xcb, 0xec, 0xce, 0xdf, 0xc5, + 0xc7, 0x23, 0x02, 0x00, 0xc6, 0x03, 0xff, 0x04, + 0x12, 0x05, 0x17, 0x3f, 0x0d, 0x0d, 0x0d, 0x0e, + 0x49, 0x21, 0x2b, 0x0d, 0x0d, 0x26, 0x0d, 0x12, + 0x0d, 0x12, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, + 0x86, 0x05, 0x16, 0x01, 0xdd, 0xb5, 0x23, 0x01, + 0x00, 0xc6, 0x03, 0x97, 0x05, 0x00, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, + 0x00, 0x05, 0x00, 0x86, 0x05, 0x16, 0x01, 0xdd, + 0xb6, 0x23, 0x01, 0x00, 0xc6, 0x03, 0x98, 0x05, + 0x00, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, 0x86, 0x05, + 0x16, 0x01, 0xdd, 0xb8, 0x23, 0x01, 0x00, 0xc6, + 0x03, 0x9a, 0x05, 0x00, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, + 0x00, 0x86, 0x05, 0x16, 0x01, 0xdd, 0xb9, 0x23, + 0x01, 0x00, 0xc6, 0x03, 0x9b, 0x05, 0x00, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x05, 0x00, 0x86, 0x05, 0x16, 0x01, + 0xdd, 0xbb, 0x23, 0x01, 0x00, 0xc6, 0x03, 0x9d, + 0x05, 0x00, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, 0x86, + 0x05, 0x16, 0x01, 0xdd, 0xbc, 0x23, 0x01, 0x00, + 0xc6, 0x03, 0x9e, 0x05, 0x00, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, + 0x06, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xc9, + 0xb6, 0xc5, 0x9b, 0x28, 0xc6, 0x03, 0xa2, 0x05, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x06, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc9, 0xc5, 0xc5, 0x9a, + 0x28, 0xc6, 0x03, 0xa5, 0x05, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x03, + 0x01, 0x00, 0x0c, 0x01, 0x10, 0x00, 0x01, 0x00, + 0xca, 0x03, 0x08, 0x00, 0x08, 0xc9, 0xdd, 0x42, + 0xfc, 0x00, 0x00, 0x00, 0xc5, 0x25, 0x01, 0x00, + 0xc6, 0x03, 0xa8, 0x05, 0x01, 0x0d, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x04, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xc9, 0xc5, 0x28, 0xc6, 0x03, 0xab, 0x05, 0x01, + 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x01, 0x00, 0x10, 0x01, 0x10, 0x00, + 0x01, 0x00, 0xca, 0x03, 0x08, 0x00, 0x08, 0xc9, + 0xc5, 0xb5, 0xa6, 0xea, 0x03, 0xb5, 0x28, 0xdd, + 0x41, 0x29, 0x01, 0x00, 0x00, 0x28, 0xc6, 0x03, + 0xae, 0x05, 0x04, 0x0d, 0x1c, 0x08, 0x08, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x03, + 0x01, 0x00, 0x0c, 0x01, 0x10, 0x00, 0x01, 0x00, + 0xca, 0x03, 0x08, 0x00, 0x08, 0xc9, 0xdd, 0x42, + 0x04, 0x01, 0x00, 0x00, 0xc5, 0x25, 0x01, 0x00, + 0xc6, 0x03, 0xb4, 0x05, 0x01, 0x0d, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x03, 0x02, + 0x00, 0x1c, 0x01, 0x10, 0x00, 0x01, 0x00, 0xce, + 0x03, 0x0a, 0x00, 0xca, 0x03, 0x08, 0x00, 0x08, + 0xc9, 0xc5, 0xb5, 0xa3, 0xea, 0x0c, 0xdd, 0xc5, + 0xef, 0x42, 0x05, 0x01, 0x00, 0x00, 0x25, 0x00, + 0x00, 0xde, 0x42, 0x05, 0x01, 0x00, 0x00, 0xc5, + 0x25, 0x01, 0x00, 0xc6, 0x03, 0xb7, 0x05, 0x03, + 0x0d, 0x1c, 0x3b, 0x0e, 0x43, 0x06, 0x01, 0xce, + 0x03, 0x02, 0x03, 0x02, 0x03, 0x00, 0x00, 0x45, + 0x05, 0x9e, 0x07, 0x00, 0x01, 0x00, 0xa0, 0x07, + 0x00, 0x01, 0x00, 0xa6, 0x06, 0x00, 0x00, 0x00, + 0xe8, 0x01, 0x00, 0x01, 0x00, 0xce, 0x03, 0x00, + 0x01, 0x14, 0x0c, 0x03, 0xca, 0x0c, 0x02, 0xcb, + 0xc6, 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, + 0x04, 0xbe, 0x01, 0x00, 0x00, 0xef, 0x2f, 0xd1, + 0xc7, 0xa7, 0xea, 0x03, 0xd1, 0x28, 0xd2, 0xf4, + 0xea, 0x03, 0xb5, 0xd6, 0x38, 0x95, 0x00, 0x00, + 0x00, 0x42, 0xa7, 0x01, 0x00, 0x00, 0xc7, 0x41, + 0x3e, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0xcd, + 0xd1, 0x43, 0xcf, 0x01, 0x00, 0x00, 0xc5, 0xd2, + 0x43, 0xd0, 0x01, 0x00, 0x00, 0xc5, 0x28, 0xc6, + 0x03, 0xc2, 0x05, 0x0a, 0x23, 0x12, 0x3f, 0x1c, + 0x0d, 0x17, 0x0e, 0x67, 0x21, 0x26, 0x0e, 0x43, + 0x06, 0x01, 0x88, 0x05, 0x02, 0x00, 0x02, 0x05, + 0x01, 0x00, 0x2b, 0x02, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xce, 0x03, + 0x0a, 0x00, 0xdd, 0xd1, 0xef, 0xd5, 0xdd, 0xd2, + 0xef, 0xd6, 0xdd, 0x42, 0x8a, 0x01, 0x00, 0x00, + 0xd1, 0x41, 0xcf, 0x01, 0x00, 0x00, 0xd2, 0x41, + 0xcf, 0x01, 0x00, 0x00, 0x9d, 0xd1, 0x41, 0xd0, + 0x01, 0x00, 0x00, 0xd2, 0x41, 0xd0, 0x01, 0x00, + 0x00, 0x9d, 0x25, 0x02, 0x00, 0xc6, 0x03, 0xd3, + 0x05, 0x03, 0x03, 0x17, 0x17, 0x0e, 0x43, 0x06, + 0x01, 0x8a, 0x05, 0x02, 0x00, 0x02, 0x05, 0x01, + 0x00, 0x2b, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xce, 0x03, 0x0a, + 0x00, 0xdd, 0xd1, 0xef, 0xd5, 0xdd, 0xd2, 0xef, + 0xd6, 0xdd, 0x42, 0x8a, 0x01, 0x00, 0x00, 0xd1, + 0x41, 0xcf, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xcf, + 0x01, 0x00, 0x00, 0x9e, 0xd1, 0x41, 0xd0, 0x01, + 0x00, 0x00, 0xd2, 0x41, 0xd0, 0x01, 0x00, 0x00, + 0x9e, 0x25, 0x02, 0x00, 0xc6, 0x03, 0xd8, 0x05, + 0x03, 0x03, 0x17, 0x17, 0x0e, 0x43, 0x06, 0x01, + 0x8c, 0x05, 0x02, 0x00, 0x02, 0x06, 0x01, 0x00, + 0x47, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xce, 0x03, 0x0a, 0x00, + 0xdd, 0xd1, 0xef, 0xd5, 0xdd, 0xd2, 0xef, 0xd6, + 0xdd, 0x42, 0x8a, 0x01, 0x00, 0x00, 0xd1, 0x41, + 0xcf, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xcf, 0x01, + 0x00, 0x00, 0x9a, 0xd1, 0x41, 0xd0, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xd0, 0x01, 0x00, 0x00, 0x9a, + 0x9e, 0xd1, 0x41, 0xcf, 0x01, 0x00, 0x00, 0xd2, + 0x41, 0xd0, 0x01, 0x00, 0x00, 0x9a, 0xd1, 0x41, + 0xd0, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xcf, 0x01, + 0x00, 0x00, 0x9a, 0x9d, 0x25, 0x02, 0x00, 0xc6, + 0x03, 0xdd, 0x05, 0x04, 0x03, 0x17, 0x17, 0xa8, + 0x0e, 0x43, 0x06, 0x01, 0x8e, 0x05, 0x02, 0x00, + 0x02, 0x03, 0x01, 0x00, 0x14, 0x02, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xce, 0x03, 0x0a, 0x00, 0xdd, 0xd1, 0xef, 0xd5, + 0xdd, 0xd2, 0xef, 0xd6, 0xd1, 0xd2, 0x42, 0xff, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9a, 0x28, + 0xc6, 0x03, 0xe3, 0x05, 0x03, 0x03, 0x17, 0x17, + 0x0e, 0x43, 0x06, 0x01, 0x90, 0x05, 0x02, 0x00, + 0x02, 0x02, 0x01, 0x00, 0x27, 0x02, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xce, 0x03, 0x0a, 0x00, 0xdd, 0xd1, 0xef, 0xd5, + 0xdd, 0xd2, 0xef, 0xd6, 0xd1, 0x41, 0xcf, 0x01, + 0x00, 0x00, 0xd2, 0x41, 0xcf, 0x01, 0x00, 0x00, + 0xa9, 0x11, 0xea, 0x0f, 0x0e, 0xd1, 0x41, 0xd0, + 0x01, 0x00, 0x00, 0xd2, 0x41, 0xd0, 0x01, 0x00, + 0x00, 0xa9, 0x28, 0xc6, 0x03, 0xe8, 0x05, 0x03, + 0x03, 0x17, 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x01, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd1, 0x28, 0xc6, + 0x03, 0xf6, 0x05, 0x01, 0x03, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x00, + 0x12, 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xce, + 0x03, 0x0a, 0x00, 0xdd, 0xd1, 0x41, 0xcf, 0x01, + 0x00, 0x00, 0x8c, 0xd1, 0x41, 0xd0, 0x01, 0x00, + 0x00, 0x8c, 0x23, 0x02, 0x00, 0xc6, 0x03, 0xf9, + 0x05, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, 0x14, 0x02, + 0x9e, 0x07, 0x00, 0x01, 0x00, 0xa0, 0x07, 0x00, + 0x01, 0x00, 0xce, 0x03, 0x0a, 0x00, 0x38, 0x73, + 0x01, 0x00, 0x00, 0xea, 0x08, 0xd2, 0xb5, 0xa9, + 0xea, 0x03, 0xd1, 0x28, 0xdd, 0xd1, 0xd2, 0x23, + 0x02, 0x00, 0xc6, 0x03, 0x8a, 0x06, 0x04, 0x03, + 0x3f, 0x08, 0x08, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x02, 0x00, 0x04, 0x01, 0x00, 0x21, 0x02, + 0xf0, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, + 0x00, 0xce, 0x03, 0x0a, 0x00, 0x08, 0xca, 0xc6, + 0x42, 0xfb, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xc9, 0xdd, 0xc6, 0x41, 0xcf, 0x01, 0x00, 0x00, + 0xc5, 0x9b, 0xc6, 0x41, 0xd0, 0x01, 0x00, 0x00, + 0x8c, 0xc5, 0x9b, 0x23, 0x02, 0x00, 0xc6, 0x03, + 0x93, 0x06, 0x02, 0x0d, 0x35, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00, + 0x83, 0x01, 0x04, 0xee, 0x06, 0x00, 0x00, 0x00, + 0xe0, 0x06, 0x00, 0x01, 0x00, 0xbc, 0x06, 0x00, + 0x02, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcc, + 0xc1, 0xca, 0xc8, 0xcf, 0x41, 0xcf, 0x01, 0x00, + 0x00, 0xb5, 0xaa, 0xea, 0x12, 0xc6, 0xc7, 0x41, + 0xcf, 0x01, 0x00, 0x00, 0x42, 0x3a, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x9d, 0xca, 0xc7, 0x41, + 0xd0, 0x01, 0x00, 0x00, 0xb6, 0xa9, 0xea, 0x16, + 0xc6, 0xc1, 0xaa, 0xea, 0x08, 0x04, 0x78, 0x01, + 0x00, 0x00, 0x94, 0x01, 0x04, 0xee, 0x00, 0x00, + 0x00, 0x94, 0x01, 0xec, 0x43, 0xc7, 0x41, 0xd0, + 0x01, 0x00, 0x00, 0xb4, 0xa9, 0xea, 0x0a, 0x04, + 0xd1, 0x01, 0x00, 0x00, 0x94, 0x01, 0xec, 0x30, + 0xc7, 0x41, 0xd0, 0x01, 0x00, 0x00, 0x42, 0x3a, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xcd, 0xb5, + 0x47, 0x04, 0x79, 0x01, 0x00, 0x00, 0xaa, 0xea, + 0x0d, 0xc6, 0xc1, 0xaa, 0xea, 0x08, 0x04, 0x78, + 0x01, 0x00, 0x00, 0x94, 0x01, 0xc6, 0xc5, 0x04, + 0xd2, 0x01, 0x00, 0x00, 0x9d, 0x9d, 0xca, 0xc6, + 0x28, 0xc6, 0x03, 0x97, 0x06, 0x0f, 0x0d, 0x12, + 0x35, 0x58, 0x35, 0x1c, 0x26, 0x26, 0x3f, 0x26, + 0x0d, 0x4e, 0x4e, 0x26, 0x36, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, + 0x1e, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xc9, + 0xc5, 0x41, 0xcf, 0x01, 0x00, 0x00, 0xc5, 0x41, + 0xcf, 0x01, 0x00, 0x00, 0x9a, 0xc5, 0x41, 0xd0, + 0x01, 0x00, 0x00, 0xc5, 0x41, 0xd0, 0x01, 0x00, + 0x00, 0x9a, 0x9d, 0x28, 0xc6, 0x03, 0xa9, 0x06, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x04, 0x02, 0x00, 0x0e, 0x01, 0x10, + 0x00, 0x01, 0x00, 0xca, 0x03, 0x08, 0x00, 0xf6, + 0x03, 0x0b, 0x00, 0x08, 0xc9, 0xdd, 0x42, 0x03, + 0x01, 0x00, 0x00, 0xde, 0xc5, 0xef, 0x25, 0x01, + 0x00, 0xc6, 0x03, 0xac, 0x06, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x03, + 0x01, 0x00, 0x13, 0x01, 0x10, 0x00, 0x01, 0x00, + 0xce, 0x03, 0x0a, 0x00, 0x08, 0xc9, 0xdd, 0xc5, + 0x41, 0xcf, 0x01, 0x00, 0x00, 0xc5, 0x41, 0xd0, + 0x01, 0x00, 0x00, 0x8c, 0x23, 0x02, 0x00, 0xc6, + 0x03, 0xaf, 0x06, 0x01, 0x0d, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x04, 0x01, 0x00, + 0x17, 0x01, 0x10, 0x00, 0x01, 0x00, 0xca, 0x03, + 0x08, 0x00, 0x08, 0xc9, 0xdd, 0x42, 0x10, 0x01, + 0x00, 0x00, 0xc5, 0x41, 0xd0, 0x01, 0x00, 0x00, + 0xc5, 0x41, 0xcf, 0x01, 0x00, 0x00, 0x25, 0x02, + 0x00, 0xc6, 0x03, 0xb2, 0x06, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x00, 0x03, 0x00, 0x05, + 0x03, 0x00, 0x26, 0x03, 0xfc, 0x03, 0x00, 0x00, + 0x00, 0xd2, 0x06, 0x00, 0x01, 0x00, 0x10, 0x00, + 0x01, 0x00, 0xce, 0x03, 0x0a, 0x00, 0x96, 0x04, + 0x0c, 0x00, 0x94, 0x04, 0x0d, 0x00, 0x08, 0xcb, + 0xc7, 0x41, 0xd0, 0x01, 0x00, 0x00, 0xc9, 0xc7, + 0x41, 0xcf, 0x01, 0x00, 0x00, 0x42, 0x04, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xca, 0xdd, 0xc6, + 0xde, 0xc5, 0xef, 0x9a, 0xc6, 0xdf, 0xc5, 0xef, + 0x9a, 0x23, 0x02, 0x00, 0xc6, 0x03, 0xb5, 0x06, + 0x02, 0x0d, 0x71, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x05, 0x03, 0x00, 0x1f, 0x01, + 0x10, 0x00, 0x01, 0x00, 0xce, 0x03, 0x0a, 0x00, + 0xf8, 0x03, 0x09, 0x00, 0xa0, 0x04, 0x0e, 0x00, + 0x08, 0xc9, 0xdd, 0xde, 0xc5, 0xef, 0x42, 0x05, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xdf, 0xc5, + 0x41, 0xd0, 0x01, 0x00, 0x00, 0xc5, 0x41, 0xcf, + 0x01, 0x00, 0x00, 0xf0, 0x23, 0x02, 0x00, 0xc6, + 0x03, 0xb9, 0x06, 0x01, 0x0d, 0x0e, 0x43, 0x06, + 0x01, 0xd0, 0x03, 0x02, 0x04, 0x02, 0x03, 0x02, + 0x00, 0x96, 0x01, 0x06, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xf6, 0x06, 0x00, 0x01, 0x00, 0xa6, 0x06, + 0x00, 0x00, 0x00, 0xdc, 0x06, 0x00, 0x01, 0x00, + 0xe8, 0x01, 0x00, 0x01, 0x00, 0xd0, 0x03, 0x00, + 0x01, 0x14, 0xc8, 0x03, 0x00, 0x00, 0xcc, 0x03, + 0x07, 0x00, 0x0c, 0x03, 0xcb, 0x0c, 0x02, 0xcc, + 0xc7, 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, + 0x04, 0xbe, 0x01, 0x00, 0x00, 0xef, 0x2f, 0x38, + 0x95, 0x00, 0x00, 0x00, 0x42, 0xa7, 0x01, 0x00, + 0x00, 0xc8, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x24, + 0x01, 0x00, 0xc9, 0xdd, 0x42, 0x77, 0x01, 0x00, + 0x00, 0xd2, 0x24, 0x01, 0x00, 0xea, 0x46, 0xd2, + 0xb5, 0xa4, 0xea, 0x0d, 0x38, 0xcd, 0x00, 0x00, + 0x00, 0x04, 0xd3, 0x01, 0x00, 0x00, 0xef, 0x2f, + 0xdd, 0x42, 0x77, 0x01, 0x00, 0x00, 0xd1, 0x24, + 0x01, 0x00, 0xea, 0x07, 0xd1, 0xd2, 0x9c, 0xd5, + 0xec, 0x2f, 0xd1, 0xde, 0xa7, 0xea, 0x12, 0xc8, + 0xd1, 0x41, 0xc1, 0x01, 0x00, 0x00, 0xd2, 0xf0, + 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, 0x9b, 0x28, + 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0xd4, 0x01, + 0x00, 0x00, 0xef, 0x2f, 0x38, 0xd0, 0x00, 0x00, + 0x00, 0x04, 0xd4, 0x01, 0x00, 0x00, 0xef, 0x2f, + 0xc5, 0xd1, 0x43, 0xd5, 0x01, 0x00, 0x00, 0xc5, + 0xd2, 0x43, 0xd6, 0x01, 0x00, 0x00, 0xc5, 0x28, + 0xc6, 0x03, 0xc0, 0x06, 0x12, 0x22, 0x12, 0x3f, + 0x67, 0x3f, 0x1c, 0x3f, 0x3f, 0x17, 0x26, 0x53, + 0x08, 0x3b, 0x08, 0x3a, 0x08, 0x26, 0x26, 0x0e, + 0x43, 0x06, 0x01, 0x92, 0x05, 0x02, 0x00, 0x02, + 0x03, 0x01, 0x00, 0x62, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd0, + 0x03, 0x0f, 0x00, 0xd1, 0xdd, 0xa7, 0x96, 0xea, + 0x13, 0xdd, 0xd1, 0xd2, 0x41, 0xd5, 0x01, 0x00, + 0x00, 0x9d, 0xd2, 0x41, 0xd6, 0x01, 0x00, 0x00, + 0x23, 0x02, 0x00, 0xd2, 0xdd, 0xa7, 0x96, 0xea, + 0x13, 0xdd, 0xd1, 0x41, 0xd5, 0x01, 0x00, 0x00, + 0xd2, 0x9d, 0xd1, 0x41, 0xd6, 0x01, 0x00, 0x00, + 0x23, 0x02, 0x00, 0xd1, 0x41, 0xd6, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xd6, 0x01, 0x00, 0x00, 0xaa, + 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, + 0xd7, 0x01, 0x00, 0x00, 0xef, 0x2f, 0xdd, 0xd1, + 0x41, 0xd5, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xd5, + 0x01, 0x00, 0x00, 0x9d, 0xd1, 0x41, 0xd6, 0x01, + 0x00, 0x00, 0x23, 0x02, 0x00, 0xc6, 0x03, 0xd7, + 0x06, 0x07, 0x03, 0x21, 0x5d, 0x21, 0x5e, 0x4e, + 0x3f, 0x0e, 0x43, 0x06, 0x01, 0x94, 0x05, 0x02, + 0x00, 0x02, 0x03, 0x01, 0x00, 0x62, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd0, 0x03, 0x0f, 0x00, 0xd1, 0xdd, 0xa7, + 0x96, 0xea, 0x13, 0xdd, 0xd1, 0xd2, 0x41, 0xd5, + 0x01, 0x00, 0x00, 0x9e, 0xd2, 0x41, 0xd6, 0x01, + 0x00, 0x00, 0x23, 0x02, 0x00, 0xd2, 0xdd, 0xa7, + 0x96, 0xea, 0x13, 0xdd, 0xd1, 0x41, 0xd5, 0x01, + 0x00, 0x00, 0xd2, 0x9e, 0xd1, 0x41, 0xd6, 0x01, + 0x00, 0x00, 0x23, 0x02, 0x00, 0xd1, 0x41, 0xd6, + 0x01, 0x00, 0x00, 0xd2, 0x41, 0xd6, 0x01, 0x00, + 0x00, 0xaa, 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, + 0x00, 0x04, 0xd7, 0x01, 0x00, 0x00, 0xef, 0x2f, + 0xdd, 0xd1, 0x41, 0xd5, 0x01, 0x00, 0x00, 0xd2, + 0x41, 0xd5, 0x01, 0x00, 0x00, 0x9e, 0xd1, 0x41, + 0xd6, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xc6, + 0x03, 0xe2, 0x06, 0x07, 0x03, 0x21, 0x5d, 0x21, + 0x5e, 0x4e, 0x3f, 0x0e, 0x43, 0x06, 0x01, 0x96, + 0x05, 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, 0x62, + 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xd0, 0x03, 0x0f, 0x00, 0xd1, + 0xdd, 0xa7, 0x96, 0xea, 0x13, 0xdd, 0xd1, 0xd2, + 0x41, 0xd5, 0x01, 0x00, 0x00, 0x9a, 0xd2, 0x41, + 0xd6, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xd2, + 0xdd, 0xa7, 0x96, 0xea, 0x13, 0xdd, 0xd1, 0x41, + 0xd5, 0x01, 0x00, 0x00, 0xd2, 0x9a, 0xd1, 0x41, + 0xd6, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xd1, + 0x41, 0xd6, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xd6, + 0x01, 0x00, 0x00, 0xaa, 0xea, 0x0d, 0x38, 0xd0, + 0x00, 0x00, 0x00, 0x04, 0xd7, 0x01, 0x00, 0x00, + 0xef, 0x2f, 0xdd, 0xd1, 0x41, 0xd5, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xd5, 0x01, 0x00, 0x00, 0x9a, + 0xd1, 0x41, 0xd6, 0x01, 0x00, 0x00, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0xed, 0x06, 0x07, 0x03, 0x21, + 0x5d, 0x21, 0x5e, 0x4e, 0x3f, 0x0e, 0x43, 0x06, + 0x01, 0x98, 0x05, 0x02, 0x00, 0x02, 0x04, 0x02, + 0x00, 0x1e, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd0, 0x03, 0x0f, + 0x00, 0x96, 0x05, 0x1e, 0x01, 0xd2, 0xdd, 0xa7, + 0x96, 0xea, 0x0b, 0xdd, 0xd2, 0xd1, 0x41, 0xd6, + 0x01, 0x00, 0x00, 0xf0, 0xd6, 0xde, 0xd1, 0xd2, + 0x42, 0xff, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x23, 0x02, 0x00, 0xc6, 0x03, 0xf8, 0x06, 0x03, + 0x03, 0x21, 0x35, 0x0e, 0x43, 0x06, 0x01, 0x9a, + 0x05, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x1f, + 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xd1, 0x41, 0xd6, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xd6, 0x01, 0x00, 0x00, 0xa9, + 0x11, 0xea, 0x0f, 0x0e, 0xd1, 0x41, 0xd5, 0x01, + 0x00, 0x00, 0xd2, 0x41, 0xd5, 0x01, 0x00, 0x00, + 0xa9, 0x28, 0xc6, 0x03, 0xfd, 0x06, 0x01, 0x03, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x02, 0x01, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xd1, 0x28, 0xc6, 0x03, 0x89, 0x07, + 0x01, 0x03, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x03, 0x01, 0x00, 0x11, 0x01, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xd0, 0x03, 0x0f, 0x00, + 0xdd, 0xd1, 0x41, 0xd5, 0x01, 0x00, 0x00, 0x8c, + 0xd1, 0x41, 0xd6, 0x01, 0x00, 0x00, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0x8c, 0x07, 0x01, 0x03, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x00, 0x03, 0x00, 0x05, + 0x02, 0x00, 0x37, 0x03, 0xbc, 0x06, 0x00, 0x00, + 0x00, 0xf6, 0x06, 0x00, 0x01, 0x00, 0x10, 0x00, + 0x01, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xd0, 0x03, + 0x0f, 0x00, 0x08, 0xcb, 0xc7, 0xcd, 0x41, 0xd6, + 0x01, 0x00, 0x00, 0xca, 0xdd, 0x42, 0x77, 0x01, + 0x00, 0x00, 0xc6, 0x24, 0x01, 0x00, 0xea, 0x16, + 0xde, 0xdd, 0x42, 0xf5, 0x00, 0x00, 0x00, 0xc5, + 0x41, 0xd5, 0x01, 0x00, 0x00, 0xc6, 0x24, 0x02, + 0x00, 0xc6, 0x23, 0x02, 0x00, 0x38, 0xd0, 0x00, + 0x00, 0x00, 0x04, 0xd8, 0x01, 0x00, 0x00, 0xef, + 0x2f, 0xc6, 0x03, 0x9b, 0x07, 0x04, 0x0d, 0x2b, + 0x3f, 0x6d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x22, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc9, 0x04, 0xd9, 0x01, + 0x00, 0x00, 0xc5, 0x41, 0xd5, 0x01, 0x00, 0x00, + 0x9d, 0x04, 0xda, 0x01, 0x00, 0x00, 0x9d, 0xc5, + 0x41, 0xd6, 0x01, 0x00, 0x00, 0x9d, 0x04, 0xdb, + 0x01, 0x00, 0x00, 0x9d, 0x28, 0xc6, 0x03, 0xa3, + 0x07, 0x01, 0x0d, 0x0e, 0x43, 0x06, 0x01, 0x9c, + 0x05, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xcc, 0x03, + 0x07, 0x00, 0xce, 0x03, 0x0a, 0x00, 0xd0, 0x03, + 0x0f, 0x00, 0xd1, 0x97, 0x04, 0x49, 0x00, 0x00, + 0x00, 0xab, 0x11, 0xeb, 0x16, 0x0e, 0xd1, 0x97, + 0x04, 0x8e, 0x00, 0x00, 0x00, 0xab, 0x11, 0xeb, + 0x0a, 0x0e, 0xd1, 0x97, 0x04, 0x8f, 0x00, 0x00, + 0x00, 0xab, 0xea, 0x03, 0x0a, 0x28, 0xd1, 0xdd, + 0xa7, 0x11, 0xeb, 0x0c, 0x0e, 0xd1, 0xde, 0xa7, + 0x11, 0xeb, 0x05, 0x0e, 0xd1, 0xdf, 0xa7, 0xea, + 0x03, 0x0a, 0x28, 0x09, 0x28, 0xc6, 0x03, 0xaa, + 0x07, 0x09, 0x04, 0x3f, 0x3f, 0x35, 0x0d, 0x26, + 0x26, 0x1c, 0x0d, 0x0e, 0x43, 0x06, 0x01, 0xd2, + 0x03, 0x01, 0x02, 0x01, 0x04, 0x01, 0x00, 0x82, + 0x01, 0x03, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xe8, + 0x01, 0x00, 0x01, 0x00, 0xd2, 0x03, 0x00, 0x01, + 0x14, 0x9c, 0x05, 0x21, 0x01, 0x0c, 0x03, 0xc9, + 0x0c, 0x02, 0xca, 0xc5, 0xea, 0x0d, 0x38, 0xd0, + 0x00, 0x00, 0x00, 0x04, 0xbe, 0x01, 0x00, 0x00, + 0xef, 0x2f, 0xd1, 0xc6, 0xa7, 0xea, 0x03, 0xd1, + 0x28, 0x38, 0x96, 0x00, 0x00, 0x00, 0x42, 0xa3, + 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xea, + 0x2a, 0xd1, 0xe9, 0xb5, 0xa9, 0xea, 0x06, 0xb5, + 0x26, 0x01, 0x00, 0xd5, 0x38, 0x95, 0x00, 0x00, + 0x00, 0x42, 0x63, 0x00, 0x00, 0x00, 0xd1, 0xc6, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, + 0x0e, 0xd1, 0x42, 0x8b, 0x01, 0x00, 0x00, 0x25, + 0x00, 0x00, 0xdd, 0xd1, 0xef, 0xea, 0x1d, 0xd1, + 0x26, 0x01, 0x00, 0xd5, 0x38, 0x95, 0x00, 0x00, + 0x00, 0x42, 0x63, 0x00, 0x00, 0x00, 0xd1, 0xc6, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, + 0x0e, 0xd1, 0x28, 0x38, 0xd0, 0x00, 0x00, 0x00, + 0x04, 0xbd, 0x01, 0x00, 0x00, 0xef, 0x2f, 0xc6, + 0x03, 0xb7, 0x07, 0x0f, 0x22, 0x12, 0x3f, 0x1c, + 0x08, 0x58, 0x21, 0x1c, 0x6c, 0x30, 0x1c, 0x1c, + 0x6c, 0x08, 0x08, 0x0e, 0x43, 0x06, 0x01, 0x9e, + 0x05, 0x01, 0x00, 0x01, 0x03, 0x04, 0x00, 0x34, + 0x01, 0xf0, 0x06, 0x00, 0x01, 0x00, 0xc8, 0x03, + 0x00, 0x00, 0xca, 0x03, 0x08, 0x00, 0xcc, 0x03, + 0x07, 0x00, 0xce, 0x03, 0x0a, 0x00, 0xdd, 0x42, + 0x77, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, + 0x11, 0xeb, 0x26, 0x0e, 0xde, 0x42, 0x83, 0x01, + 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0x11, 0xeb, + 0x18, 0x0e, 0xd1, 0xdf, 0xa7, 0x11, 0xeb, 0x11, + 0x0e, 0xd1, 0xe0, 0xa7, 0x11, 0xea, 0x0a, 0x0e, + 0xd1, 0x41, 0xcf, 0x01, 0x00, 0x00, 0xb5, 0xa9, + 0x96, 0x28, 0xc6, 0x03, 0xcb, 0x07, 0x04, 0x04, + 0x49, 0x49, 0x26, 0x0e, 0x43, 0x06, 0x01, 0xa0, + 0x05, 0x02, 0x01, 0x02, 0x03, 0x01, 0x00, 0x63, + 0x03, 0xf0, 0x06, 0x00, 0x01, 0x00, 0xaa, 0x06, + 0x00, 0x01, 0x00, 0xb8, 0x07, 0x00, 0x00, 0x00, + 0x9e, 0x05, 0x22, 0x01, 0xd2, 0xb5, 0xa9, 0xea, + 0x0d, 0xd1, 0x42, 0x3a, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0xc9, 0xec, 0x51, 0xd1, 0xb6, 0xa9, + 0xea, 0x05, 0xc1, 0xc9, 0xec, 0x32, 0xd1, 0xb4, + 0xa9, 0xea, 0x09, 0x04, 0x79, 0x01, 0x00, 0x00, + 0xc9, 0xec, 0x25, 0xdd, 0xd1, 0xef, 0xea, 0x11, + 0x04, 0xdd, 0x01, 0x00, 0x00, 0xd1, 0x9d, 0x04, + 0xdb, 0x01, 0x00, 0x00, 0x9d, 0xc9, 0xec, 0x09, + 0x38, 0x99, 0x00, 0x00, 0x00, 0xd1, 0xef, 0xc9, + 0x04, 0x80, 0x00, 0x00, 0x00, 0x94, 0x00, 0x04, + 0xef, 0x00, 0x00, 0x00, 0x94, 0x00, 0xd2, 0xb6, + 0xaa, 0xea, 0x0b, 0xc5, 0x04, 0xde, 0x01, 0x00, + 0x00, 0xd2, 0x9d, 0x9d, 0xc9, 0xc5, 0x28, 0xc6, + 0x03, 0xd4, 0x07, 0x11, 0x05, 0x1c, 0x35, 0x0d, + 0x1c, 0x0d, 0x26, 0x21, 0x0d, 0x1c, 0x49, 0x0d, + 0x2c, 0x27, 0x26, 0x1c, 0x37, 0x0e, 0x43, 0x06, + 0x01, 0xa2, 0x05, 0x03, 0x0e, 0x03, 0x03, 0x03, + 0x03, 0x85, 0x02, 0x11, 0x90, 0x07, 0x00, 0x01, + 0x00, 0xbe, 0x07, 0x00, 0x01, 0x00, 0xc0, 0x07, + 0x00, 0x01, 0x00, 0xc2, 0x07, 0x00, 0x00, 0x00, + 0xc4, 0x07, 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, + 0x02, 0x00, 0xc6, 0x07, 0x00, 0x03, 0x00, 0xc8, + 0x07, 0x00, 0x04, 0x00, 0xca, 0x07, 0x00, 0x05, + 0x00, 0xde, 0x06, 0x00, 0x06, 0x00, 0xcc, 0x07, + 0x00, 0x07, 0x00, 0xce, 0x07, 0x00, 0x08, 0x00, + 0xd0, 0x07, 0x00, 0x09, 0x00, 0xd2, 0x07, 0x00, + 0x0a, 0x00, 0xd4, 0x07, 0x00, 0x0b, 0x00, 0xd6, + 0x07, 0x00, 0x0c, 0x00, 0xd8, 0x07, 0x00, 0x0d, + 0x00, 0xf8, 0x03, 0x09, 0x00, 0x86, 0x04, 0x10, + 0x00, 0xf6, 0x03, 0x0b, 0x00, 0xd1, 0x42, 0x8c, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xc4, 0x06, + 0xb6, 0xa9, 0xea, 0x0a, 0xd1, 0xb5, 0x47, 0x8c, + 0xd1, 0xb6, 0x47, 0x9b, 0x28, 0xd1, 0xb5, 0x47, + 0xb5, 0xa9, 0xea, 0x03, 0xb5, 0x28, 0xd1, 0x42, + 0xf9, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xcd, + 0x42, 0xf9, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xca, 0xb5, 0xc3, 0x0c, 0xb5, 0xc3, 0x0d, 0xb5, + 0xcb, 0xc7, 0xd3, 0xa3, 0x69, 0xc3, 0x00, 0x00, + 0x00, 0xd1, 0x42, 0x5d, 0x00, 0x00, 0x00, 0xd2, + 0x24, 0x01, 0x00, 0xd0, 0xb5, 0xa9, 0xea, 0x03, + 0xd2, 0x28, 0xdd, 0xd2, 0xc2, 0x0d, 0x9e, 0xef, + 0xc3, 0x0b, 0xc7, 0xb7, 0xa6, 0xea, 0x2a, 0xc2, + 0x0b, 0xc2, 0x0c, 0xa6, 0xea, 0x23, 0xdd, 0xc2, + 0x0d, 0xef, 0xbf, 0x00, 0xa3, 0xea, 0x0b, 0xc2, + 0x0b, 0xbf, 0x01, 0xa3, 0xea, 0x13, 0xc2, 0x0d, + 0x28, 0xc2, 0x0b, 0xdd, 0xc2, 0x0d, 0xef, 0xbf, + 0x02, 0x9a, 0xa3, 0xea, 0x04, 0xc2, 0x0d, 0x28, + 0xc2, 0x0b, 0xc3, 0x0c, 0xd2, 0xc3, 0x0d, 0xc5, + 0x42, 0x5d, 0x00, 0x00, 0x00, 0xd2, 0x24, 0x01, + 0x00, 0xc3, 0x04, 0xc6, 0x42, 0x5d, 0x00, 0x00, + 0x00, 0xd2, 0x24, 0x01, 0x00, 0xc3, 0x05, 0xc2, + 0x06, 0xb6, 0x9e, 0xc2, 0x04, 0x9a, 0xc4, 0x07, + 0xc2, 0x07, 0x9a, 0xc3, 0x07, 0xc2, 0x06, 0xc2, + 0x06, 0xb6, 0x9e, 0x9a, 0xc8, 0x9a, 0xc2, 0x05, + 0x9a, 0xc3, 0x08, 0xde, 0xc2, 0x07, 0xc2, 0x08, + 0x9e, 0xef, 0xc3, 0x07, 0xc2, 0x04, 0xc2, 0x07, + 0x9d, 0xc3, 0x09, 0xc2, 0x04, 0xc2, 0x07, 0x9e, + 0xc3, 0x0a, 0xdf, 0xc2, 0x0a, 0xef, 0xdf, 0xc2, + 0x09, 0xef, 0xa5, 0xea, 0x05, 0xc2, 0x0a, 0xc3, + 0x09, 0xc2, 0x09, 0xb5, 0xa9, 0xea, 0x03, 0x07, + 0x28, 0xd2, 0xc2, 0x06, 0xc8, 0x9a, 0xc2, 0x09, + 0x9b, 0x9e, 0xd6, 0x93, 0x02, 0xed, 0x3b, 0xff, + 0x07, 0x28, 0xc6, 0x03, 0xf0, 0x07, 0x29, 0x00, + 0x00, 0x08, 0x3a, 0x18, 0x2b, 0x09, 0x26, 0x0e, + 0x35, 0x30, 0x12, 0x12, 0x35, 0x3a, 0x17, 0x0f, + 0x2c, 0x3f, 0x30, 0x26, 0x0d, 0x08, 0x3f, 0x14, + 0x17, 0x13, 0x3f, 0x3f, 0x30, 0x1c, 0x49, 0x30, + 0x26, 0x26, 0x3a, 0x17, 0x21, 0x0d, 0x35, 0x1c, + 0x06, 0x2d, 0x43, 0x1c, 0xeb, 0xe2, 0x36, 0x1a, + 0x3f, 0x06, 0x48, 0xaf, 0xbc, 0x9a, 0xf2, 0xd7, + 0x7a, 0x3e, 0x06, 0xfc, 0xa9, 0xf1, 0xd2, 0x4d, + 0x62, 0x50, 0x3f, 0x0e, 0x43, 0x06, 0x01, 0xa4, + 0x05, 0x01, 0x07, 0x01, 0x05, 0x03, 0x03, 0x92, + 0x01, 0x08, 0x90, 0x07, 0x00, 0x01, 0x00, 0xde, + 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, 0x00, 0x01, + 0x00, 0xd8, 0x04, 0x00, 0x02, 0x00, 0xbe, 0x06, + 0x00, 0x03, 0x00, 0xbe, 0x07, 0x00, 0x04, 0x00, + 0xda, 0x07, 0x00, 0x05, 0x00, 0xdc, 0x07, 0x00, + 0x06, 0x00, 0xd2, 0x03, 0x03, 0x00, 0xa2, 0x05, + 0x24, 0x01, 0xde, 0x03, 0x11, 0x00, 0xbf, 0x00, + 0xbf, 0x01, 0x8c, 0xbf, 0x02, 0x26, 0x03, 0x00, + 0xc3, 0x06, 0xd1, 0xdd, 0xa7, 0x96, 0xea, 0x0d, + 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0xef, 0x01, + 0x00, 0x00, 0xef, 0x2f, 0xd1, 0x42, 0x8c, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xcd, 0xb5, 0xa4, + 0xea, 0x05, 0x26, 0x00, 0x00, 0x28, 0xb7, 0x38, + 0xb4, 0x00, 0x00, 0x00, 0x41, 0xc9, 0x01, 0x00, + 0x00, 0x8c, 0xae, 0xc3, 0x05, 0x26, 0x00, 0x00, + 0xcb, 0xb5, 0xca, 0xc6, 0xc5, 0xa3, 0xea, 0x47, + 0xb5, 0xcc, 0xc8, 0xb8, 0xa3, 0xea, 0x15, 0xde, + 0xd1, 0xc2, 0x06, 0xc8, 0x47, 0xbd, 0x64, 0xf1, + 0xc4, 0x04, 0xf3, 0xeb, 0x03, 0xec, 0x05, 0x93, + 0x03, 0xec, 0xe8, 0xc8, 0xb8, 0xa9, 0xea, 0x0d, + 0x38, 0xcd, 0x00, 0x00, 0x00, 0x04, 0xf0, 0x01, + 0x00, 0x00, 0xef, 0x2f, 0xc7, 0xc6, 0xc2, 0x04, + 0x49, 0xdd, 0x42, 0x8d, 0x01, 0x00, 0x00, 0xd1, + 0xdf, 0xc2, 0x04, 0x9e, 0x24, 0x02, 0x00, 0xb5, + 0x47, 0xd5, 0x93, 0x01, 0xec, 0xb6, 0xc7, 0x28, + 0xc6, 0x03, 0xa6, 0x08, 0x14, 0x05, 0x40, 0x21, + 0x3f, 0x35, 0x17, 0x17, 0x4e, 0x17, 0x27, 0x26, + 0x3a, 0x12, 0x0d, 0x17, 0x1c, 0x3f, 0x1c, 0x58, + 0x17, 0x06, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, + 0xb9, 0x3f, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0xf6, 0x3f, 0x06, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0xfb, 0x3f, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x21, + 0x03, 0xbc, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, + 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xcb, 0xc7, 0xcd, 0xe9, 0xca, 0xc6, 0xb6, 0xa5, + 0xea, 0x0e, 0xc5, 0xc6, 0xb6, 0x9e, 0x47, 0xb5, + 0xa9, 0xea, 0x05, 0x92, 0x01, 0xec, 0xef, 0xc5, + 0xc6, 0x43, 0x32, 0x00, 0x00, 0x00, 0xc5, 0x28, + 0xc6, 0x03, 0xc2, 0x08, 0x06, 0x0d, 0x08, 0x12, + 0x49, 0x17, 0x26, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x05, 0x00, 0x04, 0x01, 0x00, 0x2b, 0x05, + 0xd2, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, 0x00, + 0x01, 0x00, 0xda, 0x06, 0x00, 0x02, 0x00, 0xbc, + 0x06, 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, 0x00, + 0xd2, 0x03, 0x03, 0x00, 0x08, 0xc3, 0x04, 0xc2, + 0x04, 0xd0, 0xe9, 0xcb, 0x26, 0x00, 0x00, 0xc9, + 0xb5, 0xca, 0xc6, 0xc7, 0xa3, 0xea, 0x14, 0xc5, + 0xc6, 0x71, 0xc8, 0xc6, 0x47, 0x42, 0xfd, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x49, 0x93, 0x01, + 0xec, 0xe9, 0xdd, 0xc5, 0x23, 0x01, 0x00, 0xc6, + 0x03, 0xca, 0x08, 0x06, 0x13, 0x12, 0x0d, 0x17, + 0x26, 0x62, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x03, 0x02, 0x00, 0x0d, 0x01, 0x10, + 0x00, 0x01, 0x00, 0xd6, 0x03, 0x12, 0x00, 0xd2, + 0x03, 0x03, 0x00, 0x08, 0xc9, 0xdd, 0xde, 0xb6, + 0x26, 0x01, 0x00, 0xef, 0xc5, 0x23, 0x02, 0x00, + 0xc6, 0x03, 0xd3, 0x08, 0x01, 0x0d, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x00, 0x06, 0x00, 0x03, 0x02, + 0x00, 0x63, 0x06, 0xaa, 0x06, 0x00, 0x00, 0x00, + 0xe2, 0x07, 0x00, 0x01, 0x00, 0xb8, 0x07, 0x00, + 0x02, 0x00, 0xf0, 0x06, 0x00, 0x03, 0x00, 0xbc, + 0x06, 0x00, 0x04, 0x00, 0x10, 0x00, 0x01, 0x00, + 0xd0, 0x03, 0x0f, 0x00, 0xa0, 0x05, 0x23, 0x01, + 0x08, 0xc3, 0x05, 0xc2, 0x05, 0xc4, 0x04, 0xe9, + 0xb6, 0xa9, 0xea, 0x0d, 0xc2, 0x04, 0xb5, 0x47, + 0x42, 0x3a, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, + 0xc1, 0xca, 0xc2, 0x04, 0xe9, 0xb6, 0x9e, 0xc9, + 0xc5, 0xb5, 0xa6, 0xea, 0x3d, 0xc2, 0x04, 0xc5, + 0x47, 0xd0, 0xb5, 0xa9, 0x11, 0xeb, 0x0f, 0x0e, + 0xc8, 0xdd, 0xa7, 0xea, 0x0b, 0xc8, 0x41, 0xd5, + 0x01, 0x00, 0x00, 0xb5, 0xa9, 0xeb, 0x1f, 0xde, + 0xc8, 0xc5, 0xf0, 0xcf, 0xb5, 0x47, 0x04, 0x79, + 0x01, 0x00, 0x00, 0xaa, 0xea, 0x0d, 0xc6, 0xc1, + 0xaa, 0xea, 0x08, 0x04, 0x78, 0x01, 0x00, 0x00, + 0x94, 0x01, 0xc7, 0x94, 0x01, 0x92, 0x00, 0xec, + 0xc0, 0xc6, 0x28, 0xc6, 0x03, 0xd6, 0x08, 0x10, + 0x12, 0x0d, 0x26, 0x40, 0x0d, 0x3a, 0x1c, 0x21, + 0x44, 0x0d, 0x1c, 0x35, 0x1c, 0x27, 0x12, 0x17, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x1b, 0x01, 0x10, 0x00, 0x01, + 0x00, 0x08, 0xc9, 0xc5, 0xe9, 0xb6, 0xa9, 0xea, + 0x0f, 0xc5, 0xb5, 0x47, 0xb5, 0xa9, 0xea, 0x08, + 0x38, 0xf2, 0x01, 0x00, 0x00, 0x8c, 0x28, 0xc5, + 0xe9, 0xb6, 0x9e, 0x28, 0xc6, 0x03, 0xea, 0x08, + 0x04, 0x0d, 0x44, 0x21, 0x08, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x01, 0x05, 0x01, 0x03, 0x00, 0x00, + 0x21, 0x06, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xaa, + 0x06, 0x00, 0x00, 0x00, 0xda, 0x06, 0x00, 0x01, + 0x00, 0xd2, 0x06, 0x00, 0x02, 0x00, 0xbc, 0x06, + 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xc3, 0x04, 0xc2, 0x04, 0xd0, 0xe9, 0xb6, 0x9e, + 0xca, 0xc8, 0xc6, 0x47, 0xcb, 0xc6, 0xb5, 0xa5, + 0xea, 0x0d, 0x92, 0x01, 0xc7, 0xd1, 0x9a, 0xc8, + 0xc6, 0x47, 0x9d, 0xcb, 0xec, 0xf0, 0xc7, 0x28, + 0xc6, 0x03, 0xf0, 0x08, 0x08, 0x12, 0x0d, 0x1c, + 0x17, 0x1c, 0x0d, 0x2b, 0x0d, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, + 0x30, 0x05, 0xbc, 0x06, 0x00, 0x00, 0x00, 0xda, + 0x06, 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, 0x02, + 0x00, 0xaa, 0x06, 0x00, 0x03, 0x00, 0x10, 0x00, + 0x01, 0x00, 0xd2, 0x03, 0x03, 0x00, 0x08, 0xc3, + 0x04, 0xc2, 0x04, 0xcd, 0xe9, 0xce, 0xb6, 0xa9, + 0xea, 0x06, 0xdd, 0xb5, 0x23, 0x01, 0x00, 0x26, + 0x00, 0x00, 0xcb, 0xb6, 0xcc, 0xc8, 0xc6, 0xa3, + 0xea, 0x10, 0xc7, 0xc8, 0xb6, 0x9e, 0x71, 0xc8, + 0xc5, 0xc8, 0x47, 0x9a, 0x49, 0x93, 0x03, 0xec, + 0xed, 0xdd, 0xc7, 0x23, 0x01, 0x00, 0xc6, 0x03, + 0xfa, 0x08, 0x09, 0x12, 0x0d, 0x12, 0x17, 0x1d, + 0x17, 0x26, 0x3a, 0x17, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x2a, + 0x05, 0xbc, 0x06, 0x00, 0x00, 0x00, 0xda, 0x06, + 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, 0x02, 0x00, + 0xaa, 0x06, 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, + 0x00, 0xd2, 0x03, 0x03, 0x00, 0x08, 0xc3, 0x04, + 0xc2, 0x04, 0xcd, 0xe9, 0xca, 0xb5, 0x26, 0x01, + 0x00, 0xcb, 0xb5, 0xcc, 0xc8, 0xc6, 0xa3, 0xea, + 0x12, 0xc7, 0xc8, 0xb6, 0x9d, 0x71, 0xc5, 0xc8, + 0x47, 0xc8, 0xb6, 0x9d, 0x9b, 0x49, 0x93, 0x03, + 0xec, 0xeb, 0xdd, 0xc7, 0x23, 0x01, 0x00, 0xc6, + 0x03, 0x87, 0x09, 0x07, 0x12, 0x0d, 0x12, 0x1c, + 0x26, 0x44, 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x25, 0x05, + 0xbc, 0x06, 0x00, 0x00, 0x00, 0xda, 0x06, 0x00, + 0x01, 0x00, 0xd2, 0x06, 0x00, 0x02, 0x00, 0xaa, + 0x06, 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xc3, 0x04, 0xc2, 0x04, 0xcd, 0xe9, 0xca, + 0xb5, 0xcb, 0xb5, 0xcc, 0xc8, 0xc6, 0xa3, 0xea, + 0x13, 0xc7, 0xc5, 0xc8, 0x47, 0x42, 0xfb, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x9d, 0xcb, 0x93, + 0x03, 0xec, 0xea, 0xc7, 0x28, 0xc6, 0x03, 0x90, + 0x09, 0x07, 0x12, 0x0d, 0x12, 0x0d, 0x26, 0x49, + 0x17, 0x0e, 0x43, 0x06, 0x01, 0xa6, 0x05, 0x02, + 0x05, 0x02, 0x05, 0x01, 0x00, 0x4e, 0x07, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xe6, 0x07, 0x00, 0x00, 0x00, 0xd2, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x02, 0x00, + 0xf8, 0x06, 0x00, 0x03, 0x00, 0xe8, 0x07, 0x00, + 0x04, 0x00, 0xd2, 0x03, 0x03, 0x00, 0xdd, 0xd1, + 0xef, 0xd5, 0xdd, 0xd2, 0xef, 0xd6, 0xd1, 0xe9, + 0xd2, 0xe9, 0xa3, 0xea, 0x07, 0xd1, 0xc9, 0xd2, + 0xd5, 0xc5, 0xd6, 0xd2, 0xe9, 0xcc, 0xd1, 0xe9, + 0xc3, 0x04, 0x26, 0x00, 0x00, 0xca, 0xb5, 0xcb, + 0xc7, 0xc8, 0xa3, 0xea, 0x10, 0xc6, 0xc7, 0x71, + 0xd1, 0xc7, 0x47, 0xd2, 0xc7, 0x47, 0x9d, 0x49, + 0x93, 0x02, 0xec, 0xed, 0xc8, 0xcb, 0xc7, 0xc2, + 0x04, 0xa3, 0xea, 0x0c, 0xc6, 0xc7, 0x71, 0xd1, + 0xc7, 0x47, 0x49, 0x93, 0x02, 0xec, 0xf0, 0xdd, + 0xc6, 0x23, 0x01, 0x00, 0xc6, 0x03, 0x9c, 0x09, + 0x0e, 0x04, 0x17, 0x17, 0x26, 0x0d, 0x0d, 0x0e, + 0x12, 0x17, 0x17, 0x26, 0x4e, 0x2b, 0x3a, 0x0e, + 0x43, 0x06, 0x01, 0xa8, 0x05, 0x02, 0x00, 0x02, + 0x03, 0x01, 0x00, 0x07, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xa6, + 0x05, 0x26, 0x01, 0xdd, 0xd1, 0xd2, 0x8c, 0x23, + 0x02, 0x00, 0xc6, 0x03, 0xae, 0x09, 0x01, 0x03, + 0x0e, 0x43, 0x06, 0x01, 0xaa, 0x05, 0x02, 0x06, + 0x02, 0x06, 0x01, 0x00, 0x58, 0x08, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xaa, 0x06, 0x00, 0x00, 0x00, 0xbe, 0x06, 0x00, + 0x01, 0x00, 0xf8, 0x06, 0x00, 0x02, 0x00, 0xe8, + 0x07, 0x00, 0x03, 0x00, 0xda, 0x06, 0x00, 0x04, + 0x00, 0xd2, 0x06, 0x00, 0x05, 0x00, 0xd2, 0x03, + 0x03, 0x00, 0xdd, 0xd1, 0xef, 0xd5, 0xdd, 0xd2, + 0xef, 0xd6, 0xd1, 0xe9, 0xcb, 0xd2, 0xe9, 0xcc, + 0xc7, 0xc8, 0x9d, 0xb6, 0x9e, 0xc3, 0x04, 0x26, + 0x00, 0x00, 0xc3, 0x05, 0xb5, 0xc9, 0xc5, 0xc2, + 0x04, 0xa3, 0xea, 0x0a, 0xc2, 0x05, 0xc5, 0xb5, + 0x49, 0x93, 0x00, 0xec, 0xf2, 0xb5, 0xc9, 0xc5, + 0xc7, 0xa3, 0xea, 0x21, 0xb5, 0xca, 0xc6, 0xc8, + 0xa3, 0xea, 0x16, 0xc2, 0x05, 0xc5, 0xc6, 0x9d, + 0x71, 0x13, 0x47, 0xd1, 0xc5, 0x47, 0xd2, 0xc6, + 0x47, 0x9a, 0x9d, 0x49, 0x93, 0x01, 0xec, 0xe7, + 0x93, 0x00, 0xec, 0xdc, 0xdd, 0xc2, 0x05, 0x23, + 0x01, 0x00, 0xc6, 0x03, 0xb1, 0x09, 0x0e, 0x04, + 0x17, 0x17, 0x12, 0x12, 0x26, 0x1c, 0x2b, 0x30, + 0x26, 0x26, 0x58, 0x17, 0x17, 0x0e, 0x43, 0x06, + 0x01, 0xac, 0x05, 0x02, 0x00, 0x02, 0x03, 0x00, + 0x00, 0x06, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd1, 0xb6, 0xd2, + 0x9b, 0x9a, 0x28, 0xc6, 0x03, 0xc2, 0x09, 0x01, + 0x03, 0x0e, 0x43, 0x06, 0x01, 0xae, 0x05, 0x02, + 0x00, 0x02, 0x04, 0x02, 0x00, 0x0a, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd6, 0x03, 0x12, 0x00, 0xd2, 0x03, 0x03, + 0x00, 0xdd, 0xde, 0xd1, 0xef, 0xde, 0xd2, 0xef, + 0x23, 0x02, 0x00, 0xc6, 0x03, 0xc5, 0x09, 0x02, + 0x04, 0x17, 0x0e, 0x43, 0x06, 0x01, 0xb0, 0x05, + 0x02, 0x00, 0x02, 0x04, 0x01, 0x00, 0x0e, 0x02, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xd2, 0x03, 0x03, 0x00, 0xdd, 0x42, + 0x8d, 0x01, 0x00, 0x00, 0xd1, 0xd2, 0x24, 0x02, + 0x00, 0xb6, 0x47, 0x28, 0xc6, 0x03, 0xca, 0x09, + 0x01, 0x03, 0x0e, 0x43, 0x06, 0x01, 0xb2, 0x05, + 0x02, 0x02, 0x02, 0x03, 0x00, 0x00, 0x22, 0x04, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xda, 0x06, 0x00, 0x00, 0x00, 0xaa, + 0x06, 0x00, 0x01, 0x00, 0xd1, 0xe9, 0xcd, 0xd2, + 0xe9, 0xaa, 0xea, 0x03, 0x09, 0x28, 0xb5, 0xca, + 0xc6, 0xc5, 0xa3, 0xea, 0x10, 0xd1, 0xc6, 0x47, + 0xd2, 0xc6, 0x47, 0xaa, 0xea, 0x03, 0x09, 0x28, + 0x93, 0x01, 0xec, 0xed, 0x0a, 0x28, 0xc6, 0x03, + 0xcd, 0x09, 0x08, 0x04, 0x12, 0x1c, 0x0d, 0x26, + 0x30, 0x0d, 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x01, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd1, 0x28, 0xc6, + 0x03, 0xe1, 0x09, 0x01, 0x03, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x01, 0x03, 0x01, 0x04, 0x01, 0x00, + 0x1f, 0x04, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd2, + 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, 0x00, 0x01, + 0x00, 0xda, 0x06, 0x00, 0x02, 0x00, 0xd2, 0x03, + 0x03, 0x00, 0xd1, 0xe9, 0xcb, 0x26, 0x00, 0x00, + 0xc9, 0xb5, 0xca, 0xc6, 0xc7, 0xa3, 0xea, 0x0d, + 0xc5, 0xc6, 0x71, 0xd1, 0xc6, 0x47, 0x8c, 0x49, + 0x93, 0x01, 0xec, 0xf0, 0xdd, 0xc5, 0x23, 0x01, + 0x00, 0xc6, 0x03, 0xe4, 0x09, 0x05, 0x04, 0x12, + 0x17, 0x26, 0x3f, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x02, 0x08, 0x02, 0x05, 0x01, 0x00, 0xbc, 0x01, + 0x0a, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xf8, 0x06, 0x00, 0x00, 0x00, + 0xe8, 0x07, 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, + 0x02, 0x00, 0xbe, 0x06, 0x00, 0x03, 0x00, 0xea, + 0x06, 0x00, 0x04, 0x00, 0xd2, 0x06, 0x00, 0x05, + 0x00, 0xda, 0x06, 0x00, 0x06, 0x00, 0xf0, 0x06, + 0x00, 0x07, 0x00, 0xd2, 0x03, 0x03, 0x00, 0xd2, + 0x42, 0x8c, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xb5, 0xa3, 0xea, 0x0d, 0x38, 0xcd, 0x00, 0x00, + 0x00, 0x04, 0xc0, 0x01, 0x00, 0x00, 0xef, 0x2f, + 0xd1, 0xe9, 0xc9, 0xd2, 0xe9, 0xca, 0xc5, 0xc6, + 0xa3, 0xea, 0x0c, 0xdd, 0xb5, 0x26, 0x01, 0x00, + 0xef, 0xd1, 0x26, 0x02, 0x00, 0x28, 0x38, 0x96, + 0x00, 0x00, 0x00, 0x41, 0x3e, 0x00, 0x00, 0x00, + 0x41, 0x92, 0x01, 0x00, 0x00, 0x42, 0xa8, 0x01, + 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xc3, 0x05, + 0x26, 0x00, 0x00, 0xc3, 0x04, 0x92, 0x01, 0xc5, + 0xc6, 0x9e, 0xc3, 0x06, 0xb5, 0xcb, 0xc7, 0xc2, + 0x06, 0xa3, 0xea, 0x0a, 0xc2, 0x04, 0xc7, 0xb5, + 0x49, 0x93, 0x02, 0xec, 0xf2, 0xc2, 0x06, 0xb6, + 0x9e, 0xcb, 0xc7, 0xb5, 0xa6, 0xea, 0x41, 0xc2, + 0x05, 0xc7, 0xc6, 0x9d, 0x47, 0xc4, 0x07, 0xb5, + 0xaa, 0xea, 0x31, 0xc2, 0x07, 0xd2, 0xc6, 0x47, + 0x9b, 0xc3, 0x07, 0xc2, 0x05, 0xc7, 0xc6, 0x9d, + 0xb5, 0x49, 0xb5, 0xcc, 0xc8, 0xc6, 0xa3, 0xea, + 0x15, 0xc2, 0x05, 0xc7, 0xc8, 0x9d, 0x71, 0x13, + 0x47, 0xd2, 0xc8, 0x47, 0xc2, 0x07, 0x9a, 0x9e, + 0x49, 0x93, 0x03, 0xec, 0xe8, 0xc2, 0x04, 0xc7, + 0xc2, 0x07, 0x49, 0x92, 0x02, 0xec, 0xbc, 0xdd, + 0xc2, 0x04, 0xef, 0xdd, 0xc2, 0x05, 0xef, 0x26, + 0x02, 0x00, 0x28, 0xc6, 0x03, 0xff, 0x09, 0x17, + 0x04, 0x44, 0x3f, 0x12, 0x12, 0x1c, 0x3a, 0x85, + 0x1c, 0x0d, 0x1c, 0x2b, 0x30, 0x35, 0x2b, 0x17, + 0x2b, 0x26, 0x26, 0x53, 0x17, 0x22, 0x17, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x02, 0x01, 0x02, 0x04, + 0x01, 0x00, 0x2a, 0x03, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xdc, 0x06, + 0x00, 0x00, 0x00, 0xd2, 0x03, 0x03, 0x00, 0xd2, + 0x42, 0x8c, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xb5, 0xa6, 0xea, 0x15, 0xdd, 0x42, 0x8d, 0x01, + 0x00, 0x00, 0xd1, 0xd2, 0x24, 0x02, 0x00, 0xc9, + 0xd2, 0xd5, 0xc5, 0xb6, 0x47, 0xd6, 0xec, 0xe0, + 0xd1, 0xd1, 0xd1, 0xe9, 0xb6, 0x9e, 0x47, 0x9b, + 0x28, 0xc6, 0x03, 0x9a, 0x0a, 0x06, 0x04, 0x44, + 0x3f, 0x0d, 0x17, 0x0e, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x02, 0x06, 0x02, 0x04, 0x01, 0x00, 0x6f, + 0x08, 0xe6, 0x06, 0x00, 0x01, 0x00, 0xe8, 0x06, + 0x00, 0x01, 0x00, 0xea, 0x06, 0x00, 0x00, 0x00, + 0xec, 0x06, 0x00, 0x01, 0x00, 0xee, 0x06, 0x00, + 0x02, 0x00, 0xbc, 0x06, 0x00, 0x03, 0x00, 0xf0, + 0x06, 0x00, 0x04, 0x00, 0xdc, 0x06, 0x00, 0x05, + 0x00, 0xd2, 0x03, 0x03, 0x00, 0xd1, 0xca, 0xd2, + 0xcb, 0xdd, 0xb6, 0x26, 0x01, 0x00, 0xef, 0xc3, + 0x04, 0xdd, 0xb5, 0x26, 0x01, 0x00, 0xef, 0xcc, + 0xc6, 0x42, 0x8c, 0x01, 0x00, 0x00, 0x24, 0x00, + 0x00, 0xb5, 0xa6, 0xea, 0x29, 0xdd, 0x42, 0x8d, + 0x01, 0x00, 0x00, 0xc7, 0xc6, 0x24, 0x02, 0x00, + 0xc4, 0x05, 0xb5, 0x47, 0xc9, 0xc6, 0xcb, 0xc2, + 0x05, 0xb6, 0x47, 0xca, 0xc2, 0x04, 0xc3, 0x05, + 0xc8, 0xc5, 0xc2, 0x04, 0x9a, 0x9e, 0xc3, 0x04, + 0xc2, 0x05, 0xcc, 0xec, 0xcc, 0xc7, 0x42, 0x8c, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb5, 0xa5, + 0xea, 0x0d, 0x38, 0xcd, 0x00, 0x00, 0x00, 0x04, + 0xba, 0x01, 0x00, 0x00, 0xef, 0x2f, 0xdd, 0x42, + 0x8d, 0x01, 0x00, 0x00, 0xc8, 0xd2, 0x24, 0x02, + 0x00, 0xb6, 0x47, 0x28, 0xc6, 0x03, 0xa4, 0x0a, + 0x10, 0x04, 0x0d, 0x0d, 0x2b, 0x26, 0x44, 0x44, + 0x12, 0x0d, 0x1c, 0x17, 0x2b, 0x12, 0x0e, 0x44, + 0x3f, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x02, 0x01, 0x00, 0x05, 0x01, 0x90, 0x07, + 0x00, 0x01, 0x00, 0xa4, 0x05, 0x25, 0x01, 0xdd, + 0xd1, 0x23, 0x01, 0x00, 0xc6, 0x03, 0xb8, 0x0a, + 0x01, 0x03, 0x0e, 0x43, 0x06, 0x01, 0xd4, 0x03, + 0x02, 0x04, 0x02, 0x04, 0x02, 0x00, 0x8e, 0x01, + 0x06, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xf6, 0x06, + 0x00, 0x01, 0x00, 0xa6, 0x06, 0x00, 0x00, 0x00, + 0xdc, 0x06, 0x00, 0x01, 0x00, 0xe8, 0x01, 0x00, + 0x01, 0x00, 0xd4, 0x03, 0x00, 0x01, 0x14, 0xd2, + 0x03, 0x03, 0x00, 0xd6, 0x03, 0x12, 0x00, 0x0c, + 0x03, 0xcb, 0x0c, 0x02, 0xcc, 0xc7, 0xea, 0x0d, + 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0xbe, 0x01, + 0x00, 0x00, 0xef, 0x2f, 0x38, 0x95, 0x00, 0x00, + 0x00, 0x42, 0xa7, 0x01, 0x00, 0x00, 0xc8, 0x41, + 0x3e, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0xc9, + 0xd2, 0xdd, 0xa7, 0xea, 0x45, 0xd2, 0x42, 0x8c, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb5, 0xa4, + 0xea, 0x0d, 0x38, 0xcd, 0x00, 0x00, 0x00, 0x04, + 0xf5, 0x01, 0x00, 0x00, 0xef, 0x2f, 0xd1, 0xde, + 0xa7, 0xea, 0x12, 0xc8, 0xd1, 0x41, 0xc1, 0x01, + 0x00, 0x00, 0xd2, 0xf0, 0xd1, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x9b, 0x28, 0xdd, 0xd1, 0xef, 0xd5, + 0xdd, 0x42, 0x8d, 0x01, 0x00, 0x00, 0xd1, 0xd2, + 0x24, 0x02, 0x00, 0xce, 0xb6, 0x47, 0xd5, 0xec, + 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0xd4, + 0x01, 0x00, 0x00, 0xef, 0x2f, 0xc5, 0xd1, 0x43, + 0xd5, 0x01, 0x00, 0x00, 0xc5, 0xd2, 0x43, 0xd6, + 0x01, 0x00, 0x00, 0xc5, 0x28, 0xc6, 0x03, 0xbf, + 0x0a, 0x12, 0x22, 0x12, 0x3f, 0x67, 0x1c, 0x44, + 0x3f, 0x1c, 0x53, 0x08, 0x17, 0x3f, 0x13, 0x0d, + 0x3a, 0x08, 0x26, 0x26, 0x0e, 0x43, 0x06, 0x01, + 0xb4, 0x05, 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, + 0x62, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xd4, 0x03, 0x13, 0x00, + 0xd1, 0xdd, 0xa7, 0x96, 0xea, 0x13, 0xdd, 0xd1, + 0xd2, 0x41, 0xd5, 0x01, 0x00, 0x00, 0x9d, 0xd2, + 0x41, 0xd6, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xd2, 0xdd, 0xa7, 0x96, 0xea, 0x13, 0xdd, 0xd1, + 0x41, 0xd5, 0x01, 0x00, 0x00, 0xd2, 0x9d, 0xd1, + 0x41, 0xd6, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xd1, 0x41, 0xd6, 0x01, 0x00, 0x00, 0xd2, 0x41, + 0xd6, 0x01, 0x00, 0x00, 0xaa, 0xea, 0x0d, 0x38, + 0xd0, 0x00, 0x00, 0x00, 0x04, 0xd7, 0x01, 0x00, + 0x00, 0xef, 0x2f, 0xdd, 0xd1, 0x41, 0xd5, 0x01, + 0x00, 0x00, 0xd2, 0x41, 0xd5, 0x01, 0x00, 0x00, + 0x9d, 0xd1, 0x41, 0xd6, 0x01, 0x00, 0x00, 0x23, + 0x02, 0x00, 0xc6, 0x03, 0xd6, 0x0a, 0x07, 0x03, + 0x21, 0x5d, 0x21, 0x5e, 0x4e, 0x3f, 0x0e, 0x43, + 0x06, 0x01, 0xb6, 0x05, 0x02, 0x00, 0x02, 0x03, + 0x01, 0x00, 0x07, 0x02, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xb4, 0x05, + 0x2d, 0x01, 0xdd, 0xd1, 0xd2, 0x8c, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0xe1, 0x0a, 0x01, 0x03, 0x0e, + 0x43, 0x06, 0x01, 0xb8, 0x05, 0x02, 0x00, 0x02, + 0x03, 0x01, 0x00, 0x62, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd4, + 0x03, 0x13, 0x00, 0xd1, 0xdd, 0xa7, 0x96, 0xea, + 0x13, 0xdd, 0xd1, 0xd2, 0x41, 0xd5, 0x01, 0x00, + 0x00, 0x9a, 0xd2, 0x41, 0xd6, 0x01, 0x00, 0x00, + 0x23, 0x02, 0x00, 0xd2, 0xdd, 0xa7, 0x96, 0xea, + 0x13, 0xdd, 0xd1, 0x41, 0xd5, 0x01, 0x00, 0x00, + 0xd2, 0x9a, 0xd1, 0x41, 0xd6, 0x01, 0x00, 0x00, + 0x23, 0x02, 0x00, 0xd1, 0x41, 0xd6, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xd6, 0x01, 0x00, 0x00, 0xaa, + 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, + 0xd7, 0x01, 0x00, 0x00, 0xef, 0x2f, 0xdd, 0xd1, + 0x41, 0xd5, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xd5, + 0x01, 0x00, 0x00, 0x9a, 0xd1, 0x41, 0xd6, 0x01, + 0x00, 0x00, 0x23, 0x02, 0x00, 0xc6, 0x03, 0xe4, + 0x0a, 0x07, 0x03, 0x21, 0x5d, 0x21, 0x5e, 0x4e, + 0x3f, 0x0e, 0x43, 0x06, 0x01, 0xba, 0x05, 0x02, + 0x00, 0x02, 0x04, 0x02, 0x00, 0x1e, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd4, 0x03, 0x13, 0x00, 0xb8, 0x05, 0x2f, + 0x01, 0xd2, 0xdd, 0xa7, 0x96, 0xea, 0x0b, 0xdd, + 0xd2, 0xd1, 0x41, 0xd6, 0x01, 0x00, 0x00, 0xf0, + 0xd6, 0xde, 0xd1, 0xd2, 0x42, 0xff, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x23, 0x02, 0x00, 0xc6, + 0x03, 0xef, 0x0a, 0x03, 0x03, 0x21, 0x35, 0x0e, + 0x43, 0x06, 0x01, 0xbc, 0x05, 0x02, 0x00, 0x02, + 0x02, 0x00, 0x00, 0x1f, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd1, + 0x41, 0xd6, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xd6, + 0x01, 0x00, 0x00, 0xa9, 0x11, 0xea, 0x0f, 0x0e, + 0xd1, 0x41, 0xd5, 0x01, 0x00, 0x00, 0xd2, 0x41, + 0xd5, 0x01, 0x00, 0x00, 0xa9, 0x28, 0xc6, 0x03, + 0xf4, 0x0a, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd1, 0x28, + 0xc6, 0x03, 0x80, 0x0b, 0x01, 0x03, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, + 0x00, 0x11, 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xd4, 0x03, 0x13, 0x00, 0xdd, 0xd1, 0x41, 0xd5, + 0x01, 0x00, 0x00, 0x8c, 0xd1, 0x41, 0xd6, 0x01, + 0x00, 0x00, 0x23, 0x02, 0x00, 0xc6, 0x03, 0x83, + 0x0b, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x03, 0x00, 0x05, 0x02, 0x00, 0x2f, 0x03, + 0xbc, 0x06, 0x00, 0x00, 0x00, 0xf6, 0x06, 0x00, + 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0xd2, 0x03, + 0x03, 0x00, 0xd4, 0x03, 0x13, 0x00, 0x08, 0xcb, + 0xc7, 0xcd, 0x41, 0xd6, 0x01, 0x00, 0x00, 0xce, + 0xdd, 0xa7, 0xea, 0x16, 0xde, 0xdd, 0x42, 0xf5, + 0x00, 0x00, 0x00, 0xc5, 0x41, 0xd5, 0x01, 0x00, + 0x00, 0xc6, 0x24, 0x02, 0x00, 0xc6, 0x23, 0x02, + 0x00, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0xd8, + 0x01, 0x00, 0x00, 0xef, 0x2f, 0xc6, 0x03, 0x92, + 0x0b, 0x04, 0x0d, 0x26, 0x1c, 0x6d, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x22, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xc9, 0x04, 0xf6, 0x01, 0x00, 0x00, 0xc5, 0x41, + 0xd5, 0x01, 0x00, 0x00, 0x9d, 0x04, 0xda, 0x01, + 0x00, 0x00, 0x9d, 0xc5, 0x41, 0xd6, 0x01, 0x00, + 0x00, 0x9d, 0x04, 0xdb, 0x01, 0x00, 0x00, 0x9d, + 0x28, 0xc6, 0x03, 0x9a, 0x0b, 0x01, 0x0d, 0x0e, + 0x43, 0x06, 0x01, 0xd6, 0x03, 0x02, 0x06, 0x02, + 0x04, 0x01, 0x00, 0xa9, 0x01, 0x08, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xdc, 0x06, 0x00, 0x00, 0x00, 0xd2, 0x06, 0x00, + 0x01, 0x00, 0xde, 0x06, 0x00, 0x02, 0x00, 0xa6, + 0x06, 0x00, 0x03, 0x00, 0xe8, 0x01, 0x00, 0x01, + 0x00, 0xd6, 0x03, 0x00, 0x01, 0x14, 0xd2, 0x03, + 0x03, 0x00, 0x0c, 0x03, 0xc3, 0x04, 0x0c, 0x02, + 0xc3, 0x05, 0xc2, 0x04, 0xea, 0x0d, 0x38, 0xd0, + 0x00, 0x00, 0x00, 0x04, 0xbe, 0x01, 0x00, 0x00, + 0xef, 0x2f, 0xd1, 0xdd, 0xa7, 0x96, 0x11, 0xeb, + 0x06, 0x0e, 0xd2, 0xdd, 0xa7, 0x96, 0xea, 0x0d, + 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0xef, 0x01, + 0x00, 0x00, 0xef, 0x2f, 0xdd, 0x42, 0x8d, 0x01, + 0x00, 0x00, 0xd1, 0xd2, 0x24, 0x02, 0x00, 0xcd, + 0xb6, 0x47, 0xce, 0x42, 0x8c, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xb5, 0xa3, 0xea, 0x05, 0xc5, + 0xb5, 0x47, 0x28, 0xdd, 0x42, 0xf1, 0x00, 0x00, + 0x00, 0xd2, 0xc6, 0x24, 0x02, 0x00, 0xcf, 0x42, + 0x8c, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb5, + 0xa5, 0xea, 0x1d, 0xdd, 0x42, 0x8d, 0x01, 0x00, + 0x00, 0xd1, 0xc7, 0x24, 0x02, 0x00, 0xb5, 0x47, + 0xd5, 0xdd, 0x42, 0x8d, 0x01, 0x00, 0x00, 0xd2, + 0xc7, 0x24, 0x02, 0x00, 0xb5, 0x47, 0xd6, 0x38, + 0x95, 0x00, 0x00, 0x00, 0x42, 0xa7, 0x01, 0x00, + 0x00, 0xc2, 0x05, 0x41, 0x3e, 0x00, 0x00, 0x00, + 0x24, 0x01, 0x00, 0xd0, 0xd1, 0x43, 0xc1, 0x01, + 0x00, 0x00, 0xc8, 0xd2, 0x43, 0xc2, 0x01, 0x00, + 0x00, 0xc8, 0x28, 0xc6, 0x03, 0xa1, 0x0b, 0x11, + 0x2d, 0x17, 0x3f, 0x2b, 0x21, 0x3f, 0x3f, 0x12, + 0x3f, 0x17, 0x3f, 0x3f, 0x49, 0x4a, 0x6c, 0x21, + 0x26, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x03, 0x01, 0x00, 0x12, 0x01, 0x10, 0x00, + 0x01, 0x00, 0xd6, 0x03, 0x12, 0x00, 0x08, 0xc9, + 0xdd, 0xc5, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xc5, + 0x41, 0xc1, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xc6, 0x03, 0xb9, 0x0b, 0x01, 0x0d, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x04, 0x01, + 0x00, 0x22, 0x01, 0x10, 0x00, 0x01, 0x00, 0xd6, + 0x03, 0x12, 0x00, 0x08, 0xc9, 0xdd, 0xc5, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0x42, 0xfd, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0xc5, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x42, 0xfd, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x23, 0x02, 0x00, 0xc6, 0x03, 0xbc, + 0x0b, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x02, 0x00, 0x04, 0x01, 0x00, 0x6b, 0x02, + 0xe2, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, + 0x00, 0x9e, 0x05, 0x22, 0x01, 0x08, 0xca, 0xc6, + 0x41, 0xc1, 0x01, 0x00, 0x00, 0x42, 0x8c, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xb5, 0xa4, 0xea, + 0x1f, 0xdd, 0xc6, 0x41, 0xc1, 0x01, 0x00, 0x00, + 0xb5, 0x47, 0xef, 0x96, 0xea, 0x12, 0xc6, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0x42, 0x3a, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0xc9, 0xec, 0x1c, 0x04, + 0xdd, 0x01, 0x00, 0x00, 0xc6, 0x41, 0xc1, 0x01, + 0x00, 0x00, 0x42, 0x3a, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x9d, 0x04, 0xdb, 0x01, 0x00, 0x00, + 0x9d, 0xc9, 0xc5, 0x04, 0xf7, 0x01, 0x00, 0x00, + 0xc6, 0x41, 0xc2, 0x01, 0x00, 0x00, 0x42, 0x3a, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9d, 0x04, + 0xdb, 0x01, 0x00, 0x00, 0x9d, 0x9d, 0xcd, 0x28, + 0xc6, 0x03, 0xbf, 0x0b, 0x06, 0x0e, 0x5d, 0x44, + 0x59, 0x8a, 0x94, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x04, 0x00, 0x00, 0x22, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, + 0x00, 0x08, 0xc9, 0xc5, 0x41, 0xc1, 0x01, 0x00, + 0x00, 0x42, 0x5d, 0x00, 0x00, 0x00, 0xd1, 0x24, + 0x01, 0x00, 0xc5, 0x41, 0xc2, 0x01, 0x00, 0x00, + 0x42, 0x5d, 0x00, 0x00, 0x00, 0xd1, 0x24, 0x01, + 0x00, 0x9b, 0x28, 0xc6, 0x03, 0xc9, 0x0b, 0x01, + 0x0d, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x03, + 0x00, 0x05, 0x01, 0x00, 0x2e, 0x03, 0xda, 0x06, + 0x00, 0x00, 0x00, 0xde, 0x06, 0x00, 0x01, 0x00, + 0x10, 0x00, 0x01, 0x00, 0xd6, 0x03, 0x12, 0x00, + 0x08, 0xcb, 0xc7, 0x41, 0xc1, 0x01, 0x00, 0x00, + 0xc9, 0xc7, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xca, + 0xdd, 0xc5, 0x42, 0xf9, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0xc6, 0x9a, 0xc5, 0xc6, 0x42, 0xf9, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9a, 0x9e, + 0xc6, 0xc6, 0x9a, 0x23, 0x02, 0x00, 0xc6, 0x03, + 0xcc, 0x0b, 0x02, 0x0d, 0x49, 0x0e, 0x43, 0x06, + 0x01, 0xbe, 0x05, 0x02, 0x00, 0x02, 0x04, 0x01, + 0x00, 0x42, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd6, 0x03, 0x12, + 0x00, 0xdd, 0x42, 0x8e, 0x01, 0x00, 0x00, 0xd1, + 0x24, 0x01, 0x00, 0xd5, 0xdd, 0x42, 0x8e, 0x01, + 0x00, 0x00, 0xd2, 0x24, 0x01, 0x00, 0xd6, 0xdd, + 0xd1, 0x41, 0xc1, 0x01, 0x00, 0x00, 0xd2, 0x41, + 0xc2, 0x01, 0x00, 0x00, 0x9a, 0xd1, 0x41, 0xc2, + 0x01, 0x00, 0x00, 0xd2, 0x41, 0xc1, 0x01, 0x00, + 0x00, 0x9a, 0x9d, 0xd1, 0x41, 0xc2, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xc2, 0x01, 0x00, 0x00, 0x9a, + 0x23, 0x02, 0x00, 0xc6, 0x03, 0xd2, 0x0b, 0x03, + 0x03, 0x3a, 0x3a, 0x0e, 0x43, 0x06, 0x01, 0xc0, + 0x05, 0x02, 0x00, 0x02, 0x04, 0x01, 0x00, 0x42, + 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xd6, 0x03, 0x12, 0x00, 0xdd, + 0x42, 0x8e, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, + 0x00, 0xd5, 0xdd, 0x42, 0x8e, 0x01, 0x00, 0x00, + 0xd2, 0x24, 0x01, 0x00, 0xd6, 0xdd, 0xd1, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0xd2, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x9a, 0xd1, 0x41, 0xc2, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xc1, 0x01, 0x00, 0x00, 0x9a, + 0x9e, 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xd2, + 0x41, 0xc2, 0x01, 0x00, 0x00, 0x9a, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0xd7, 0x0b, 0x03, 0x03, 0x3a, + 0x3a, 0x0e, 0x43, 0x06, 0x01, 0xc2, 0x05, 0x02, + 0x00, 0x02, 0x04, 0x01, 0x00, 0x34, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd6, 0x03, 0x12, 0x00, 0xdd, 0x42, 0x8e, + 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xd5, + 0xdd, 0x42, 0x8e, 0x01, 0x00, 0x00, 0xd2, 0x24, + 0x01, 0x00, 0xd6, 0xdd, 0xd1, 0x41, 0xc1, 0x01, + 0x00, 0x00, 0xd2, 0x41, 0xc1, 0x01, 0x00, 0x00, + 0x9a, 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xd2, + 0x41, 0xc2, 0x01, 0x00, 0x00, 0x9a, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0xdc, 0x0b, 0x03, 0x03, 0x3a, + 0x3a, 0x0e, 0x43, 0x06, 0x01, 0xc4, 0x05, 0x02, + 0x00, 0x02, 0x04, 0x01, 0x00, 0x34, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd6, 0x03, 0x12, 0x00, 0xdd, 0x42, 0x8e, + 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xd5, + 0xdd, 0x42, 0x8e, 0x01, 0x00, 0x00, 0xd2, 0x24, + 0x01, 0x00, 0xd6, 0xdd, 0xd1, 0x41, 0xc1, 0x01, + 0x00, 0x00, 0xd2, 0x41, 0xc2, 0x01, 0x00, 0x00, + 0x9a, 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xd2, + 0x41, 0xc1, 0x01, 0x00, 0x00, 0x9a, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0xe1, 0x0b, 0x03, 0x03, 0x3a, + 0x3a, 0x0e, 0x43, 0x06, 0x01, 0xc6, 0x05, 0x02, + 0x00, 0x02, 0x03, 0x01, 0x00, 0x35, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd6, 0x03, 0x12, 0x00, 0xdd, 0x42, 0x8e, + 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xd5, + 0xdd, 0x42, 0x8e, 0x01, 0x00, 0x00, 0xd2, 0x24, + 0x01, 0x00, 0xd6, 0xd1, 0x41, 0xc1, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xc1, 0x01, 0x00, 0x00, 0xa9, + 0x11, 0xea, 0x0f, 0x0e, 0xd1, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0xd2, 0x41, 0xc2, 0x01, 0x00, 0x00, + 0xa9, 0x28, 0xc6, 0x03, 0xe6, 0x0b, 0x03, 0x03, + 0x3a, 0x3b, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x01, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xd1, 0x28, 0xc6, 0x03, + 0xf5, 0x0b, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x01, 0x01, 0x01, 0x03, 0x01, 0x00, 0x13, + 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0x10, 0x00, + 0x01, 0x00, 0xd6, 0x03, 0x12, 0x00, 0x08, 0xc9, + 0xdd, 0xc5, 0x41, 0xc1, 0x01, 0x00, 0x00, 0x8c, + 0xc5, 0x41, 0xc2, 0x01, 0x00, 0x00, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0xf8, 0x0b, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, + 0x02, 0x00, 0x2e, 0x02, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xa6, 0x06, 0x00, 0x00, 0x00, 0xd6, 0x03, + 0x12, 0x00, 0xd2, 0x03, 0x03, 0x00, 0xd1, 0xdd, + 0xa7, 0xea, 0x03, 0xd1, 0x28, 0x38, 0x95, 0x00, + 0x00, 0x00, 0x42, 0xa7, 0x01, 0x00, 0x00, 0xdd, + 0x41, 0x3e, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, + 0xcd, 0xde, 0xd1, 0xef, 0x43, 0xc1, 0x01, 0x00, + 0x00, 0xc5, 0xde, 0xb6, 0xef, 0x43, 0xc2, 0x01, + 0x00, 0x00, 0xc5, 0x28, 0xc6, 0x03, 0x8a, 0x0c, + 0x07, 0x04, 0x1c, 0x08, 0x08, 0x67, 0x2b, 0x30, + 0x0e, 0x43, 0x06, 0x01, 0xc8, 0x05, 0x01, 0x02, + 0x01, 0x02, 0x00, 0x00, 0x19, 0x03, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x00, 0x00, + 0xda, 0x06, 0x00, 0x01, 0x00, 0xd1, 0xe9, 0xca, + 0xb5, 0xc9, 0xc5, 0xc6, 0xa3, 0xea, 0x0e, 0xd1, + 0xc5, 0x47, 0xb5, 0xaa, 0xea, 0x03, 0xc5, 0x28, + 0x93, 0x00, 0xec, 0xef, 0xc6, 0x28, 0xc6, 0x03, + 0x9a, 0x0c, 0x06, 0x04, 0x12, 0x26, 0x26, 0x0d, + 0x17, 0x0e, 0x43, 0x06, 0x01, 0xca, 0x05, 0x01, + 0x00, 0x01, 0x02, 0x02, 0x00, 0x0b, 0x01, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0x9c, 0x05, 0x21, 0x01, + 0xd2, 0x03, 0x03, 0x00, 0xdd, 0xd1, 0xef, 0x11, + 0xeb, 0x05, 0x0e, 0xd1, 0xde, 0xa7, 0x28, 0xc6, + 0x03, 0xa4, 0x0c, 0x02, 0x04, 0x26, 0x0e, 0x43, + 0x06, 0x01, 0xd8, 0x03, 0x02, 0x04, 0x02, 0x05, + 0x04, 0x00, 0x7e, 0x06, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xda, 0x06, 0x00, 0x01, 0x00, 0xf0, 0x07, + 0x00, 0x00, 0x00, 0xd2, 0x06, 0x00, 0x01, 0x00, + 0xaa, 0x06, 0x00, 0x02, 0x00, 0xd8, 0x03, 0x00, + 0x01, 0x14, 0xca, 0x05, 0x38, 0x01, 0xd2, 0x03, + 0x03, 0x00, 0xc8, 0x05, 0x37, 0x01, 0xd6, 0x03, + 0x12, 0x00, 0x0c, 0x02, 0xcc, 0xd1, 0xc8, 0xa7, + 0xea, 0x03, 0xd1, 0x28, 0xdd, 0xd1, 0xef, 0xea, + 0x4e, 0xd2, 0xb5, 0xa4, 0xea, 0x0c, 0xc8, 0x42, + 0x8f, 0x01, 0x00, 0x00, 0xb5, 0xb5, 0x25, 0x02, + 0x00, 0xde, 0xd1, 0xef, 0xd5, 0xdf, 0xd1, 0xef, + 0xc9, 0xc8, 0x42, 0x8f, 0x01, 0x00, 0x00, 0xd2, + 0xc5, 0x24, 0x02, 0x00, 0xca, 0x38, 0x9d, 0x00, + 0x00, 0x00, 0x42, 0xf9, 0x01, 0x00, 0x00, 0xd1, + 0xe9, 0xc5, 0x9e, 0xd2, 0x24, 0x02, 0x00, 0xd6, + 0xb5, 0xcb, 0xc7, 0xd2, 0xa3, 0xea, 0x0e, 0xc6, + 0xc7, 0x71, 0xd1, 0xc7, 0xc5, 0x9d, 0x47, 0x49, + 0x93, 0x02, 0xec, 0xef, 0xc6, 0x28, 0xd1, 0xe0, + 0xa7, 0xea, 0x12, 0xc8, 0xd1, 0x41, 0xc1, 0x01, + 0x00, 0x00, 0xd2, 0xf0, 0xd1, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x9b, 0x28, 0x38, 0xd0, 0x00, 0x00, + 0x00, 0x04, 0xbd, 0x01, 0x00, 0x00, 0xef, 0x2f, + 0xc6, 0x03, 0xab, 0x0c, 0x10, 0x14, 0x1c, 0x08, + 0x21, 0x1d, 0x3b, 0x17, 0x17, 0x3f, 0x62, 0x26, + 0x44, 0x09, 0x21, 0x53, 0x08, 0x0e, 0x43, 0x06, + 0x01, 0xcc, 0x05, 0x02, 0x0a, 0x02, 0x05, 0x05, + 0x00, 0x85, 0x02, 0x0c, 0xf4, 0x07, 0x00, 0x01, + 0x00, 0xf6, 0x07, 0x00, 0x01, 0x00, 0xe6, 0x07, + 0x00, 0x00, 0x00, 0xde, 0x06, 0x00, 0x01, 0x00, + 0xf0, 0x07, 0x00, 0x02, 0x00, 0xda, 0x06, 0x00, + 0x03, 0x00, 0xd2, 0x06, 0x00, 0x04, 0x00, 0xaa, + 0x06, 0x00, 0x05, 0x00, 0xbe, 0x06, 0x00, 0x06, + 0x00, 0xf8, 0x07, 0x00, 0x07, 0x00, 0xfa, 0x07, + 0x00, 0x08, 0x00, 0xfc, 0x07, 0x00, 0x09, 0x00, + 0xd8, 0x03, 0x04, 0x00, 0xca, 0x05, 0x38, 0x01, + 0xd2, 0x03, 0x03, 0x00, 0xd6, 0x03, 0x12, 0x00, + 0xc8, 0x05, 0x37, 0x01, 0xd1, 0xdd, 0xa7, 0x96, + 0xea, 0x07, 0xd1, 0xc9, 0xd2, 0xd5, 0xc5, 0xd6, + 0xd1, 0x41, 0xf8, 0x01, 0x00, 0x00, 0xd1, 0xe9, + 0x9d, 0xca, 0xde, 0xd2, 0xef, 0xea, 0x11, 0xdf, + 0xd2, 0xef, 0xd6, 0xc6, 0xb5, 0xa4, 0xea, 0x03, + 0xd1, 0x28, 0xb5, 0xc3, 0x07, 0xec, 0x52, 0xd2, + 0xe0, 0xa7, 0xea, 0x31, 0x5e, 0x04, 0x00, 0xd2, + 0x41, 0xc1, 0x01, 0x00, 0x00, 0xef, 0x5e, 0x04, + 0x00, 0xd2, 0x41, 0xc2, 0x01, 0x00, 0x00, 0xef, + 0x9e, 0xc3, 0x05, 0xc6, 0xc2, 0x05, 0xa4, 0xea, + 0x03, 0xd1, 0x28, 0xdd, 0xd2, 0xc6, 0xc2, 0x05, + 0x9e, 0xf0, 0xda, 0x41, 0xf8, 0x01, 0x00, 0x00, + 0xc3, 0x07, 0xec, 0x1d, 0xd2, 0x41, 0xf8, 0x01, + 0x00, 0x00, 0xc3, 0x07, 0x38, 0x9d, 0x00, 0x00, + 0x00, 0x42, 0xf9, 0x01, 0x00, 0x00, 0xc6, 0xc2, + 0x07, 0xd2, 0xe9, 0x9d, 0x24, 0x02, 0x00, 0xca, + 0x38, 0x9d, 0x00, 0x00, 0x00, 0x42, 0xf9, 0x01, + 0x00, 0x00, 0xd1, 0x41, 0xf8, 0x01, 0x00, 0x00, + 0xc2, 0x07, 0x24, 0x02, 0x00, 0xcb, 0xc6, 0xc7, + 0x9e, 0xcc, 0xdd, 0x42, 0x8f, 0x01, 0x00, 0x00, + 0xc8, 0xc7, 0x24, 0x02, 0x00, 0xc3, 0x04, 0xc7, + 0xc3, 0x05, 0xc2, 0x05, 0xc6, 0xa3, 0xea, 0x50, + 0xc2, 0x05, 0xd1, 0x41, 0xf8, 0x01, 0x00, 0x00, + 0x9e, 0xc4, 0x06, 0xb5, 0xa6, 0xea, 0x10, 0xc2, + 0x06, 0xd1, 0xe9, 0xa3, 0xea, 0x09, 0xd1, 0xc2, + 0x06, 0x47, 0xc3, 0x08, 0xec, 0x04, 0xb5, 0xc3, + 0x08, 0xc2, 0x05, 0xc2, 0x07, 0x9e, 0xc4, 0x06, + 0xb5, 0xa6, 0xea, 0x10, 0xc2, 0x06, 0xd2, 0xe9, + 0xa3, 0xea, 0x09, 0xd2, 0xc2, 0x06, 0x47, 0xc3, + 0x09, 0xec, 0x04, 0xb5, 0xc3, 0x09, 0xc2, 0x04, + 0xc2, 0x05, 0xc7, 0x9e, 0x71, 0xc2, 0x08, 0xc2, + 0x09, 0x9d, 0x49, 0x93, 0x05, 0xec, 0xac, 0xc2, + 0x04, 0x42, 0x8b, 0x01, 0x00, 0x00, 0x25, 0x00, + 0x00, 0xc6, 0x03, 0xc4, 0x0c, 0x22, 0x04, 0x21, + 0x0d, 0x0d, 0x0e, 0x35, 0x1c, 0x17, 0x1c, 0x0d, + 0x12, 0x27, 0x76, 0x21, 0x0e, 0x2b, 0x26, 0x0d, + 0x2b, 0x68, 0x71, 0x17, 0x45, 0x30, 0x3a, 0x3a, + 0x2c, 0x12, 0x26, 0x3a, 0x2c, 0x12, 0x44, 0x17, + 0x0e, 0x43, 0x06, 0x01, 0xce, 0x05, 0x02, 0x00, + 0x02, 0x03, 0x01, 0x00, 0x07, 0x02, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xcc, 0x05, 0x39, 0x01, 0xdd, 0xd1, 0xd2, 0x8c, + 0x23, 0x02, 0x00, 0xc6, 0x03, 0xf0, 0x0c, 0x01, + 0x03, 0x0e, 0x43, 0x06, 0x01, 0xd0, 0x05, 0x02, + 0x08, 0x02, 0x06, 0x01, 0x00, 0x95, 0x01, 0x0a, + 0xf4, 0x07, 0x00, 0x01, 0x00, 0xf6, 0x07, 0x00, + 0x01, 0x00, 0xda, 0x06, 0x00, 0x00, 0x00, 0xaa, + 0x06, 0x00, 0x01, 0x00, 0xbe, 0x06, 0x00, 0x02, + 0x00, 0xd2, 0x06, 0x00, 0x03, 0x00, 0xf0, 0x07, + 0x00, 0x04, 0x00, 0xf8, 0x06, 0x00, 0x05, 0x00, + 0xe8, 0x07, 0x00, 0x06, 0x00, 0xc2, 0x06, 0x00, + 0x07, 0x00, 0xd8, 0x03, 0x04, 0x00, 0xd1, 0xdd, + 0xa7, 0x96, 0xea, 0x09, 0xdd, 0xd1, 0xd2, 0xe9, + 0xf0, 0xd5, 0xec, 0x0d, 0xd2, 0xdd, 0xa7, 0x96, + 0xea, 0x07, 0xdd, 0xd2, 0xd1, 0xe9, 0xf0, 0xd6, + 0xd1, 0x41, 0xf8, 0x01, 0x00, 0x00, 0xd2, 0x41, + 0xf8, 0x01, 0x00, 0x00, 0x9d, 0xc3, 0x04, 0x38, + 0x9d, 0x00, 0x00, 0x00, 0x42, 0xf9, 0x01, 0x00, + 0x00, 0xd1, 0xe9, 0xd2, 0xe9, 0x24, 0x02, 0x00, + 0xc9, 0xd1, 0xe9, 0xc3, 0x05, 0xd2, 0xe9, 0xc3, + 0x06, 0xdd, 0x42, 0x8f, 0x01, 0x00, 0x00, 0xc5, + 0xc2, 0x04, 0x24, 0x02, 0x00, 0xcc, 0xb5, 0xca, + 0xc6, 0xc2, 0x05, 0xa3, 0xea, 0x35, 0x38, 0x9d, + 0x00, 0x00, 0x00, 0x42, 0xf9, 0x01, 0x00, 0x00, + 0xc2, 0x06, 0xc5, 0xc6, 0x9e, 0x24, 0x02, 0x00, + 0xc3, 0x07, 0xb5, 0xcb, 0xc7, 0xc2, 0x07, 0xa3, + 0xea, 0x15, 0xc8, 0xc6, 0xc7, 0x9d, 0x71, 0x13, + 0x47, 0xd1, 0xc6, 0x47, 0xd2, 0xc7, 0x47, 0x9a, + 0x9d, 0x49, 0x93, 0x02, 0xec, 0xe7, 0x93, 0x01, + 0xec, 0xc7, 0xc8, 0x42, 0x8b, 0x01, 0x00, 0x00, + 0x25, 0x00, 0x00, 0xc6, 0x03, 0xf3, 0x0c, 0x10, + 0x04, 0x21, 0x2b, 0x21, 0x21, 0x4e, 0x5d, 0x17, + 0x17, 0x44, 0x2b, 0x67, 0x2b, 0x53, 0x17, 0x17, + 0x0e, 0x43, 0x06, 0x01, 0xd2, 0x05, 0x02, 0x00, + 0x02, 0x04, 0x02, 0x00, 0x1a, 0x02, 0xf4, 0x07, + 0x00, 0x01, 0x00, 0xf6, 0x07, 0x00, 0x01, 0x00, + 0xd8, 0x03, 0x04, 0x00, 0xd0, 0x05, 0x3b, 0x01, + 0xd2, 0xdd, 0xa7, 0x96, 0xea, 0x07, 0xdd, 0xd2, + 0xd1, 0xe9, 0xf0, 0xd6, 0xde, 0xd1, 0xd2, 0x42, + 0xff, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x23, + 0x02, 0x00, 0xc6, 0x03, 0x86, 0x0d, 0x03, 0x03, + 0x21, 0x21, 0x0e, 0x43, 0x06, 0x01, 0xd4, 0x05, + 0x02, 0x00, 0x02, 0x03, 0x05, 0x00, 0x29, 0x02, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xde, 0x04, + 0x02, 0x01, 0xd8, 0x03, 0x04, 0x00, 0x88, 0x04, + 0x01, 0x00, 0x8a, 0x04, 0x02, 0x00, 0xdd, 0x42, + 0x77, 0x01, 0x00, 0x00, 0xd2, 0x24, 0x01, 0x00, + 0xea, 0x07, 0xde, 0xd1, 0xd2, 0x23, 0x02, 0x00, + 0xd1, 0xdf, 0xa7, 0x96, 0xea, 0x07, 0xdf, 0xd1, + 0xd2, 0xe9, 0xf0, 0xd5, 0xe0, 0x5e, 0x04, 0x00, + 0xd1, 0xef, 0xd2, 0x9a, 0x23, 0x01, 0x00, 0xc6, + 0x03, 0x8b, 0x0d, 0x05, 0x03, 0x3f, 0x22, 0x21, + 0x21, 0x0e, 0x43, 0x06, 0x01, 0xd6, 0x05, 0x02, + 0x02, 0x02, 0x03, 0x00, 0x00, 0x33, 0x04, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xda, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, + 0x00, 0x01, 0x00, 0xd1, 0x41, 0xf8, 0x01, 0x00, + 0x00, 0xd2, 0x41, 0xf8, 0x01, 0x00, 0x00, 0xaa, + 0xea, 0x03, 0x09, 0x28, 0xd1, 0xe9, 0xcd, 0xd2, + 0xe9, 0xaa, 0xea, 0x03, 0x09, 0x28, 0xb5, 0xca, + 0xc6, 0xc5, 0xa3, 0xea, 0x10, 0xd1, 0xc6, 0x47, + 0xd2, 0xc6, 0x47, 0xaa, 0xea, 0x03, 0x09, 0x28, + 0x93, 0x01, 0xec, 0xed, 0x0a, 0x28, 0xc6, 0x03, + 0x94, 0x0d, 0x0a, 0x04, 0x4e, 0x0d, 0x12, 0x1c, + 0x0d, 0x26, 0x30, 0x0d, 0x17, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x02, 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd1, + 0x28, 0xc6, 0x03, 0xaa, 0x0d, 0x01, 0x03, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x01, 0x03, 0x01, 0x04, + 0x01, 0x00, 0x2a, 0x04, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xa6, 0x06, 0x00, 0x00, 0x00, 0xda, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x02, 0x00, + 0xd8, 0x03, 0x04, 0x00, 0xd1, 0xe9, 0xca, 0xdd, + 0x42, 0x8f, 0x01, 0x00, 0x00, 0xd1, 0xe9, 0xd1, + 0x41, 0xf8, 0x01, 0x00, 0x00, 0x24, 0x02, 0x00, + 0xc9, 0xb5, 0xcb, 0xc7, 0xc6, 0xa3, 0xea, 0x0d, + 0xc5, 0xc7, 0x71, 0xd1, 0xc7, 0x47, 0x8c, 0x49, + 0x93, 0x02, 0xec, 0xf0, 0xc5, 0x28, 0xc6, 0x03, + 0xad, 0x0d, 0x06, 0x04, 0x12, 0x5d, 0x26, 0x2b, + 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x04, 0x01, 0x00, 0x33, 0x04, 0xa6, 0x06, + 0x00, 0x00, 0x00, 0xda, 0x06, 0x00, 0x01, 0x00, + 0xaa, 0x06, 0x00, 0x02, 0x00, 0x10, 0x00, 0x01, + 0x00, 0xd8, 0x03, 0x04, 0x00, 0x08, 0xcc, 0xc8, + 0xe9, 0xca, 0xdd, 0x42, 0x8f, 0x01, 0x00, 0x00, + 0xc8, 0xe9, 0xc8, 0x41, 0xf8, 0x01, 0x00, 0x00, + 0x24, 0x02, 0x00, 0xc9, 0xb5, 0xcb, 0xc7, 0xc6, + 0xa3, 0xea, 0x14, 0xc5, 0xc7, 0x71, 0xc8, 0xc7, + 0x47, 0x42, 0xfd, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x49, 0x93, 0x02, 0xec, 0xe9, 0xc5, 0x28, + 0xc6, 0x03, 0xc2, 0x0d, 0x06, 0x0e, 0x12, 0x5d, + 0x26, 0x4e, 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x07, 0x00, 0x05, 0x01, 0x00, 0x6a, 0x07, + 0xd2, 0x06, 0x00, 0x00, 0x00, 0xda, 0x06, 0x00, + 0x01, 0x00, 0xaa, 0x06, 0x00, 0x02, 0x00, 0xbe, + 0x06, 0x00, 0x03, 0x00, 0xfe, 0x07, 0x00, 0x04, + 0x00, 0xf4, 0x07, 0x00, 0x05, 0x00, 0x10, 0x00, + 0x01, 0x00, 0xd8, 0x03, 0x04, 0x00, 0x08, 0xc3, + 0x06, 0xc2, 0x06, 0xc4, 0x05, 0xe9, 0xce, 0xb5, + 0xa9, 0xea, 0x0d, 0x38, 0xcd, 0x00, 0x00, 0x00, + 0x04, 0xc0, 0x01, 0x00, 0x00, 0xef, 0x2f, 0xdd, + 0x42, 0x8f, 0x01, 0x00, 0x00, 0xc6, 0xc2, 0x05, + 0x41, 0xf8, 0x01, 0x00, 0x00, 0x8c, 0x24, 0x02, + 0x00, 0xcd, 0xb5, 0x71, 0xb6, 0xc2, 0x05, 0xb5, + 0x47, 0x9b, 0x49, 0xb6, 0xcb, 0xc7, 0xc6, 0xa3, + 0xea, 0x2d, 0xb5, 0xc3, 0x04, 0xb6, 0xcc, 0xc8, + 0xc7, 0xa4, 0xea, 0x14, 0xc2, 0x04, 0xc2, 0x05, + 0xc8, 0x47, 0xc5, 0xc7, 0xc8, 0x9e, 0x47, 0x9a, + 0x9d, 0xc3, 0x04, 0x93, 0x03, 0xec, 0xe9, 0xc5, + 0xc7, 0x71, 0xc2, 0x04, 0x8c, 0xc5, 0xb5, 0x47, + 0x9a, 0x49, 0x93, 0x02, 0xec, 0xd0, 0xc5, 0x28, + 0xc6, 0x03, 0xcb, 0x0d, 0x0e, 0x12, 0x0d, 0x17, + 0x17, 0x3f, 0x62, 0x30, 0x26, 0x12, 0x26, 0x4e, + 0x17, 0x3a, 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x5a, 0x06, + 0xaa, 0x06, 0x00, 0x00, 0x00, 0xbe, 0x06, 0x00, + 0x01, 0x00, 0xda, 0x06, 0x00, 0x02, 0x00, 0xd2, + 0x06, 0x00, 0x03, 0x00, 0xf4, 0x07, 0x00, 0x04, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xc3, 0x05, + 0xc2, 0x05, 0xc4, 0x04, 0xe9, 0xcb, 0xb5, 0xc9, + 0xc5, 0xc7, 0xa3, 0xea, 0x0d, 0xc2, 0x04, 0xc5, + 0x47, 0xb5, 0xa9, 0xea, 0x05, 0x93, 0x00, 0xec, + 0xf0, 0xc5, 0xb5, 0xa9, 0xea, 0x04, 0xc2, 0x04, + 0x28, 0xc5, 0xca, 0xc6, 0xc7, 0xa3, 0xea, 0x10, + 0xc2, 0x04, 0xc6, 0xc5, 0x9e, 0x71, 0xc2, 0x04, + 0xc6, 0x47, 0x49, 0x93, 0x01, 0xec, 0xed, 0xc2, + 0x04, 0xc7, 0xc5, 0x9e, 0x43, 0x32, 0x00, 0x00, + 0x00, 0xc2, 0x04, 0x41, 0x47, 0x00, 0x00, 0x00, + 0x42, 0xf8, 0x01, 0x00, 0x00, 0xc5, 0x9d, 0x43, + 0xf8, 0x01, 0x00, 0x00, 0xc2, 0x04, 0x28, 0xc6, + 0x03, 0xdc, 0x0d, 0x0c, 0x12, 0x0d, 0x17, 0x0d, + 0x44, 0x17, 0x1c, 0x12, 0x26, 0x4e, 0x35, 0x62, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x09, 0x00, + 0x06, 0x01, 0x00, 0x75, 0x09, 0xaa, 0x06, 0x00, + 0x00, 0x00, 0xbe, 0x06, 0x00, 0x01, 0x00, 0xe2, + 0x07, 0x00, 0x02, 0x00, 0xb8, 0x07, 0x00, 0x03, + 0x00, 0xf0, 0x06, 0x00, 0x04, 0x00, 0xbc, 0x06, + 0x00, 0x05, 0x00, 0xf0, 0x07, 0x00, 0x06, 0x00, + 0xda, 0x06, 0x00, 0x07, 0x00, 0x10, 0x00, 0x01, + 0x00, 0xa0, 0x05, 0x23, 0x01, 0x08, 0xc3, 0x08, + 0xc2, 0x08, 0xc3, 0x05, 0xc1, 0xcb, 0xc2, 0x08, + 0x41, 0xf8, 0x01, 0x00, 0x00, 0xc3, 0x06, 0xc2, + 0x08, 0xe9, 0xc3, 0x07, 0xb5, 0xca, 0xc6, 0xc2, + 0x07, 0xa3, 0xea, 0x33, 0xc6, 0xc2, 0x06, 0x9d, + 0xc9, 0xc2, 0x05, 0xc6, 0x47, 0xc4, 0x04, 0xb5, + 0xaa, 0xea, 0x20, 0xdd, 0xc2, 0x04, 0xc5, 0xf0, + 0xd0, 0xb5, 0x47, 0x04, 0x79, 0x01, 0x00, 0x00, + 0xaa, 0xea, 0x0d, 0xc7, 0xc1, 0xaa, 0xea, 0x08, + 0x04, 0x78, 0x01, 0x00, 0x00, 0x94, 0x02, 0xc8, + 0x94, 0x02, 0x93, 0x01, 0xec, 0xc9, 0xc7, 0xc1, + 0xaa, 0xea, 0x08, 0x04, 0x78, 0x01, 0x00, 0x00, + 0x94, 0x02, 0xc7, 0x04, 0x00, 0x02, 0x00, 0x00, + 0xdd, 0xb6, 0xc2, 0x07, 0xc2, 0x06, 0x9d, 0xf0, + 0x9d, 0x04, 0xdb, 0x01, 0x00, 0x00, 0x9d, 0x9d, + 0xcf, 0x28, 0xc6, 0x03, 0xea, 0x0d, 0x12, 0x12, + 0x17, 0x0d, 0x30, 0x1c, 0x2b, 0x1c, 0x21, 0x17, + 0x21, 0x35, 0x1c, 0x27, 0x13, 0x17, 0x1c, 0x26, + 0x76, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, 0x05, + 0x01, 0x03, 0x00, 0x00, 0x3c, 0x06, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x00, 0x00, + 0xda, 0x06, 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, + 0x02, 0x00, 0xbc, 0x06, 0x00, 0x03, 0x00, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc3, 0x04, 0xc2, 0x04, + 0xd0, 0xe9, 0xce, 0xb5, 0xa9, 0xea, 0x03, 0xb5, + 0x28, 0xc8, 0xc6, 0x8e, 0xce, 0x47, 0xcb, 0xc6, + 0xb5, 0xa5, 0xea, 0x0d, 0x92, 0x01, 0xc7, 0xd1, + 0x9a, 0xc8, 0xc6, 0x47, 0x9d, 0xcb, 0xec, 0xf0, + 0xc8, 0x41, 0xf8, 0x01, 0x00, 0x00, 0xb5, 0xaa, + 0xea, 0x0c, 0xc7, 0xd1, 0xc8, 0x41, 0xf8, 0x01, + 0x00, 0x00, 0xae, 0x9a, 0xcb, 0xc7, 0x28, 0xc6, + 0x03, 0x80, 0x0e, 0x0c, 0x12, 0x0d, 0x12, 0x17, + 0x0d, 0x21, 0x1c, 0x0d, 0x2b, 0x0d, 0x35, 0x3a, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x07, 0x00, + 0x05, 0x01, 0x00, 0x65, 0x07, 0xbc, 0x06, 0x00, + 0x00, 0x00, 0xda, 0x06, 0x00, 0x01, 0x00, 0xf0, + 0x07, 0x00, 0x02, 0x00, 0xd2, 0x06, 0x00, 0x03, + 0x00, 0xaa, 0x06, 0x00, 0x04, 0x00, 0xbe, 0x06, + 0x00, 0x05, 0x00, 0x10, 0x00, 0x01, 0x00, 0xd8, + 0x03, 0x04, 0x00, 0x08, 0xc3, 0x06, 0xc2, 0x06, + 0xcd, 0xe9, 0xca, 0xc5, 0x41, 0xf8, 0x01, 0x00, + 0x00, 0xcb, 0xc6, 0xb5, 0xa9, 0xea, 0x11, 0xc7, + 0xb5, 0xa9, 0xea, 0x0c, 0xdd, 0x42, 0x8f, 0x01, + 0x00, 0x00, 0xb5, 0xb5, 0x25, 0x02, 0x00, 0xdd, + 0x42, 0x8f, 0x01, 0x00, 0x00, 0xc6, 0xc7, 0xb6, + 0x9e, 0x24, 0x02, 0x00, 0xcc, 0xb5, 0xc3, 0x04, + 0xc2, 0x04, 0xc6, 0xa3, 0xea, 0x22, 0xc7, 0xc2, + 0x04, 0x9d, 0xc4, 0x05, 0xb5, 0xa9, 0xea, 0x08, + 0xc8, 0xc2, 0x04, 0xb5, 0x49, 0xec, 0x0d, 0xc8, + 0xc2, 0x04, 0x71, 0xc2, 0x05, 0xc5, 0xc2, 0x04, + 0x47, 0x9a, 0x49, 0x93, 0x04, 0xec, 0xda, 0xc8, + 0x42, 0x8b, 0x01, 0x00, 0x00, 0x25, 0x00, 0x00, + 0xc6, 0x03, 0x8e, 0x0e, 0x0b, 0x12, 0x3f, 0x35, + 0x3b, 0x49, 0x30, 0x21, 0x17, 0x27, 0x3f, 0x17, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x00, 0x07, 0x00, + 0x05, 0x01, 0x00, 0x5c, 0x07, 0xbc, 0x06, 0x00, + 0x00, 0x00, 0xda, 0x06, 0x00, 0x01, 0x00, 0xf0, + 0x07, 0x00, 0x02, 0x00, 0xaa, 0x06, 0x00, 0x03, + 0x00, 0xbe, 0x06, 0x00, 0x04, 0x00, 0xd2, 0x06, + 0x00, 0x05, 0x00, 0x10, 0x00, 0x01, 0x00, 0xd8, + 0x03, 0x04, 0x00, 0x08, 0xc3, 0x06, 0xc2, 0x06, + 0xcd, 0xe9, 0xca, 0xc5, 0x41, 0xf8, 0x01, 0x00, + 0x00, 0xcb, 0xdd, 0x42, 0x8f, 0x01, 0x00, 0x00, + 0xc6, 0xc7, 0xb6, 0x9d, 0x24, 0x02, 0x00, 0xc3, + 0x05, 0xb5, 0xcc, 0xc8, 0xc6, 0xa3, 0xea, 0x2e, + 0xc7, 0xc8, 0x9d, 0xc4, 0x04, 0xb4, 0xa9, 0xea, + 0x14, 0xc5, 0xc8, 0x47, 0xb5, 0xaa, 0xea, 0x1a, + 0x38, 0xcd, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, + 0x00, 0x00, 0xef, 0x2f, 0xc2, 0x05, 0xc8, 0x71, + 0xc5, 0xc8, 0x47, 0xc2, 0x04, 0xb6, 0x9d, 0x9b, + 0x49, 0x93, 0x03, 0xec, 0xcf, 0xc2, 0x05, 0x42, + 0x8b, 0x01, 0x00, 0x00, 0x25, 0x00, 0x00, 0xc6, + 0x03, 0x9e, 0x0e, 0x0b, 0x12, 0x3f, 0x4e, 0x26, + 0x1c, 0x17, 0x26, 0x3a, 0x08, 0x45, 0x17, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x00, 0x06, 0x00, 0x05, + 0x03, 0x00, 0x83, 0x01, 0x06, 0xf0, 0x06, 0x00, + 0x00, 0x00, 0xaa, 0x06, 0x00, 0x01, 0x00, 0xd2, + 0x06, 0x00, 0x02, 0x00, 0xda, 0x06, 0x00, 0x03, + 0x00, 0xbc, 0x06, 0x00, 0x04, 0x00, 0x10, 0x00, + 0x01, 0x00, 0xe2, 0x01, 0x00, 0x03, 0xd8, 0x03, + 0x04, 0x00, 0xe4, 0x03, 0x14, 0x00, 0x08, 0xc3, + 0x05, 0xc2, 0x05, 0xc4, 0x04, 0x41, 0xf8, 0x01, + 0x00, 0x00, 0xb5, 0xa3, 0xea, 0x0d, 0x38, 0xcd, + 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x00, 0x00, + 0xef, 0x2f, 0xc2, 0x04, 0x41, 0xf8, 0x01, 0x00, + 0x00, 0xc2, 0x04, 0xe9, 0x9d, 0xcc, 0xc2, 0x04, + 0x41, 0xf8, 0x01, 0x00, 0x00, 0xb5, 0xa5, 0x11, + 0xeb, 0x08, 0x0e, 0xc2, 0x04, 0xb5, 0x47, 0xb5, + 0xa9, 0xea, 0x05, 0xb6, 0xc9, 0xec, 0x18, 0xdd, + 0x42, 0x04, 0x01, 0x00, 0x00, 0xc2, 0x04, 0xb5, + 0x47, 0x24, 0x01, 0x00, 0xc9, 0xc2, 0x04, 0xc2, + 0x04, 0xb5, 0x47, 0x9e, 0xc3, 0x04, 0xde, 0x42, + 0x8f, 0x01, 0x00, 0x00, 0xc8, 0xb5, 0x24, 0x02, + 0x00, 0xcb, 0xb5, 0xca, 0xc6, 0xc8, 0xa3, 0xea, + 0x0e, 0xc7, 0xc6, 0x71, 0xc5, 0xdf, 0xc6, 0xef, + 0x9b, 0x49, 0x93, 0x01, 0xec, 0xef, 0xc7, 0x42, + 0x5d, 0x00, 0x00, 0x00, 0xc2, 0x04, 0x25, 0x01, + 0x00, 0xc6, 0x03, 0xac, 0x0e, 0x0e, 0x12, 0x0d, + 0x3a, 0x3f, 0x3f, 0x6c, 0x0d, 0x0d, 0x49, 0x31, + 0x3f, 0x26, 0x30, 0x17, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x05, 0x03, 0x00, 0x30, + 0x03, 0xbc, 0x06, 0x00, 0x00, 0x00, 0xd2, 0x06, + 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0xf4, + 0x03, 0x15, 0x00, 0xf2, 0x03, 0x16, 0x00, 0xe2, + 0x01, 0x00, 0x03, 0x08, 0xcb, 0xc7, 0xcd, 0x41, + 0xf8, 0x01, 0x00, 0x00, 0xb5, 0xaa, 0xea, 0x0d, + 0x38, 0xcd, 0x00, 0x00, 0x00, 0x04, 0x03, 0x02, + 0x00, 0x00, 0xef, 0x2f, 0xdd, 0xde, 0xc5, 0xef, + 0xc5, 0x9b, 0xef, 0xce, 0xdf, 0x42, 0x05, 0x01, + 0x00, 0x00, 0xc5, 0xb5, 0x47, 0x24, 0x01, 0x00, + 0x9d, 0xce, 0x28, 0xc6, 0x03, 0xbd, 0x0e, 0x06, + 0x0d, 0x08, 0x35, 0x3f, 0x2c, 0x49, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x02, 0x03, 0x02, 0x04, 0x01, + 0x00, 0x3f, 0x05, 0xda, 0x06, 0x00, 0x01, 0x00, + 0xf0, 0x07, 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, + 0x00, 0x00, 0xaa, 0x06, 0x00, 0x01, 0x00, 0xa6, + 0x06, 0x00, 0x02, 0x00, 0xd8, 0x03, 0x04, 0x00, + 0x26, 0x00, 0x00, 0xc9, 0xb5, 0xca, 0xc6, 0xd1, + 0xa3, 0xea, 0x09, 0xc5, 0xc6, 0xb5, 0x49, 0x93, + 0x01, 0xec, 0xf4, 0x38, 0x95, 0x00, 0x00, 0x00, + 0x42, 0xa7, 0x01, 0x00, 0x00, 0xdd, 0x41, 0x3e, + 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0xcf, 0xd2, + 0x43, 0xf8, 0x01, 0x00, 0x00, 0x38, 0x95, 0x00, + 0x00, 0x00, 0x42, 0x63, 0x00, 0x00, 0x00, 0xc5, + 0xc7, 0x24, 0x02, 0x00, 0x0e, 0xc5, 0x28, 0xc6, + 0x03, 0xca, 0x0e, 0x07, 0x05, 0x17, 0x26, 0x2c, + 0x67, 0x21, 0x53, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x01, 0x02, 0x01, 0x04, 0x04, 0x01, 0x5f, 0x03, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0x88, 0x08, 0x00, + 0x00, 0x00, 0xda, 0x06, 0x00, 0x01, 0x00, 0xca, + 0x05, 0x38, 0x01, 0xd2, 0x03, 0x03, 0x00, 0xd6, + 0x03, 0x12, 0x00, 0xd8, 0x03, 0x04, 0x00, 0xc0, + 0x00, 0xc9, 0xdd, 0xd1, 0xef, 0xea, 0x15, 0xde, + 0xd1, 0xef, 0xd9, 0x42, 0x8c, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xce, 0xb5, 0xa3, 0xea, 0x3c, + 0xc5, 0xee, 0x2f, 0xd1, 0xdf, 0xa7, 0xea, 0x31, + 0xd1, 0x41, 0xc1, 0x01, 0x00, 0x00, 0x42, 0x8c, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb5, 0xaa, + 0xea, 0x04, 0xc5, 0xee, 0x2f, 0xd1, 0x41, 0xc2, + 0x01, 0x00, 0x00, 0x42, 0x8c, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xce, 0xb5, 0xa3, 0xea, 0x04, + 0xc5, 0xee, 0x2f, 0xc6, 0x8c, 0xca, 0xec, 0x04, + 0xc5, 0xee, 0x2f, 0xe0, 0x42, 0x8f, 0x01, 0x00, + 0x00, 0xb5, 0xc6, 0x25, 0x02, 0x00, 0xc6, 0x03, + 0xd6, 0x0e, 0x11, 0x00, 0x03, 0x0a, 0x1c, 0x17, + 0x30, 0x17, 0x0d, 0x21, 0x5d, 0x12, 0x4e, 0x17, + 0x12, 0x12, 0x0d, 0x12, 0x0e, 0x43, 0x06, 0x01, + 0x88, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x0d, 0x00, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, + 0x05, 0x02, 0x00, 0x00, 0x23, 0x01, 0x00, 0xc6, + 0x03, 0xd7, 0x0e, 0x01, 0x03, 0x0e, 0x43, 0x06, + 0x01, 0xda, 0x03, 0x02, 0x04, 0x02, 0x03, 0x00, + 0x00, 0x2e, 0x06, 0x8c, 0x08, 0x00, 0x01, 0x00, + 0x8e, 0x08, 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, + 0x00, 0x00, 0xbe, 0x06, 0x00, 0x01, 0x00, 0xd2, + 0x06, 0x00, 0x02, 0x00, 0x90, 0x08, 0x00, 0x03, + 0x00, 0xd2, 0xf4, 0xea, 0x03, 0xd1, 0xd6, 0x26, + 0x00, 0x00, 0xcb, 0xb5, 0xc9, 0xc5, 0xd1, 0xa3, + 0xea, 0x1c, 0x26, 0x00, 0x00, 0xcc, 0xb5, 0xca, + 0xc6, 0xd2, 0xa3, 0xea, 0x09, 0xc8, 0xc6, 0xb5, + 0x49, 0x93, 0x01, 0xec, 0xf4, 0xc7, 0xc5, 0xc8, + 0x49, 0x93, 0x00, 0xec, 0xe1, 0xc7, 0x28, 0xc6, + 0x03, 0xef, 0x0e, 0x0a, 0x04, 0x17, 0x0d, 0x17, + 0x26, 0x17, 0x26, 0x2b, 0x17, 0x17, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x01, 0x02, 0x01, 0x03, 0x01, + 0x00, 0x18, 0x03, 0xda, 0x06, 0x00, 0x01, 0x00, + 0xd2, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, 0x00, + 0x01, 0x00, 0xda, 0x03, 0x06, 0x00, 0xdd, 0xd1, + 0xd1, 0xf0, 0xc9, 0xb5, 0xca, 0xc6, 0xd1, 0xa3, + 0xea, 0x0b, 0xc5, 0xc6, 0x47, 0xc6, 0xb6, 0x49, + 0x93, 0x01, 0xec, 0xf2, 0xc5, 0x28, 0xc6, 0x03, + 0xfe, 0x0e, 0x04, 0x04, 0x1c, 0x26, 0x35, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x01, 0x03, 0x01, 0x04, + 0x01, 0x00, 0x1e, 0x04, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xd2, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, + 0x00, 0x01, 0x00, 0xda, 0x06, 0x00, 0x02, 0x00, + 0xda, 0x03, 0x06, 0x00, 0xd1, 0xe9, 0xcb, 0xdd, + 0xc7, 0xc7, 0xf0, 0xc9, 0xb5, 0xca, 0xc6, 0xc7, + 0xa3, 0xea, 0x0e, 0xc5, 0xc6, 0x47, 0xc6, 0x71, + 0xd1, 0xc6, 0x47, 0x49, 0x93, 0x01, 0xec, 0xef, + 0xc5, 0x28, 0xc6, 0x03, 0x85, 0x0f, 0x05, 0x04, + 0x12, 0x1c, 0x26, 0x44, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x01, 0x03, 0x01, 0x05, 0x01, 0x00, 0x29, + 0x04, 0xda, 0x06, 0x00, 0x01, 0x00, 0xaa, 0x06, + 0x00, 0x00, 0x00, 0xbe, 0x06, 0x00, 0x01, 0x00, + 0xd2, 0x06, 0x00, 0x02, 0x00, 0xda, 0x03, 0x06, + 0x00, 0xdd, 0xd1, 0xef, 0xcb, 0xb5, 0xc9, 0xc5, + 0xd1, 0xa3, 0xea, 0x1d, 0xb5, 0xca, 0xc6, 0xd1, + 0xa3, 0xea, 0x12, 0xc7, 0xc5, 0x47, 0xc6, 0x71, + 0xb6, 0xb6, 0xc5, 0x9d, 0xc6, 0x9d, 0x9b, 0x49, + 0x93, 0x01, 0xec, 0xeb, 0x93, 0x00, 0xec, 0xe0, + 0xc7, 0x28, 0xc6, 0x03, 0x8d, 0x0f, 0x07, 0x04, + 0x17, 0x26, 0x26, 0x44, 0x17, 0x17, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x01, 0x05, 0x01, 0x04, 0x01, + 0x00, 0x7f, 0x06, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0x8c, 0x08, 0x00, 0x00, 0x00, 0x8e, 0x08, 0x00, + 0x01, 0x00, 0xd2, 0x06, 0x00, 0x02, 0x00, 0xaa, + 0x06, 0x00, 0x03, 0x00, 0xbe, 0x06, 0x00, 0x04, + 0x00, 0xda, 0x03, 0x06, 0x00, 0x38, 0x96, 0x00, + 0x00, 0x00, 0x42, 0xa3, 0x01, 0x00, 0x00, 0xd1, + 0x24, 0x01, 0x00, 0x96, 0xea, 0x0d, 0x38, 0xd0, + 0x00, 0x00, 0x00, 0x04, 0x09, 0x02, 0x00, 0x00, + 0xef, 0x2f, 0xd1, 0xe9, 0xc9, 0x38, 0x96, 0x00, + 0x00, 0x00, 0x42, 0xa3, 0x01, 0x00, 0x00, 0xd1, + 0xb5, 0x47, 0x24, 0x01, 0x00, 0x96, 0xea, 0x1c, + 0xb6, 0xca, 0xdd, 0xc6, 0xc5, 0xf0, 0xcb, 0xb5, + 0xcc, 0xc8, 0xc5, 0xa3, 0xea, 0x3d, 0xc7, 0xb5, + 0x47, 0xc8, 0x71, 0xd1, 0xc8, 0x47, 0x49, 0x93, + 0x03, 0xec, 0xef, 0xd1, 0xb5, 0x47, 0xe9, 0xca, + 0xdd, 0xc6, 0xc5, 0xf0, 0xcb, 0xb5, 0xcc, 0xc8, + 0xc5, 0xa3, 0xea, 0x1f, 0xb5, 0xc3, 0x04, 0xc2, + 0x04, 0xc6, 0xa3, 0xea, 0x12, 0xc7, 0xc2, 0x04, + 0x47, 0xc8, 0x71, 0xd1, 0xc8, 0x47, 0xc2, 0x04, + 0x47, 0x49, 0x93, 0x04, 0xec, 0xea, 0x93, 0x03, + 0xec, 0xde, 0xc7, 0x28, 0xc6, 0x03, 0x97, 0x0f, + 0x11, 0x04, 0x58, 0x3f, 0x12, 0x62, 0x0d, 0x1c, + 0x26, 0x30, 0x18, 0x1c, 0x1c, 0x26, 0x30, 0x44, + 0x17, 0x18, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x04, 0x00, 0x00, 0x4b, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xda, 0x06, 0x00, 0x00, + 0x00, 0x38, 0x96, 0x00, 0x00, 0x00, 0x42, 0xa3, + 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0x96, + 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, + 0x0a, 0x02, 0x00, 0x00, 0xef, 0x2f, 0xd1, 0xe9, + 0xc9, 0x38, 0x96, 0x00, 0x00, 0x00, 0x42, 0xa3, + 0x01, 0x00, 0x00, 0xd1, 0xb5, 0x47, 0x24, 0x01, + 0x00, 0x96, 0x11, 0xeb, 0x08, 0x0e, 0xc5, 0xd1, + 0xb5, 0x47, 0xe9, 0xaa, 0xea, 0x0d, 0x38, 0xd0, + 0x00, 0x00, 0x00, 0x04, 0x0b, 0x02, 0x00, 0x00, + 0xef, 0x2f, 0xc5, 0x28, 0xc6, 0x03, 0xad, 0x0f, + 0x06, 0x04, 0x58, 0x3f, 0x12, 0x94, 0x3f, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x01, 0x03, 0x01, 0x03, + 0x01, 0x00, 0x26, 0x04, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xda, 0x06, 0x00, 0x00, 0x00, 0xd2, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x02, 0x00, + 0xda, 0x03, 0x06, 0x00, 0xdd, 0x42, 0x91, 0x01, + 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xc9, 0xd1, + 0xb5, 0x47, 0xb5, 0x47, 0xca, 0xb6, 0xcb, 0xc7, + 0xc5, 0xa3, 0xea, 0x0d, 0xc6, 0xd1, 0xc7, 0x47, + 0xc7, 0x47, 0x9d, 0xca, 0x93, 0x02, 0xec, 0xf0, + 0xc6, 0x28, 0xc6, 0x03, 0xb6, 0x0f, 0x06, 0x04, + 0x3a, 0x21, 0x26, 0x2b, 0x17, 0x0e, 0x42, 0x07, + 0x01, 0x00, 0x01, 0x06, 0x01, 0x04, 0x03, 0x00, + 0x70, 0x07, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xda, + 0x06, 0x00, 0x00, 0x00, 0x90, 0x07, 0x00, 0x01, + 0x00, 0xf0, 0x06, 0x00, 0x02, 0x00, 0xaa, 0x06, + 0x00, 0x03, 0x00, 0xbe, 0x06, 0x00, 0x04, 0x00, + 0x98, 0x08, 0x00, 0x05, 0x00, 0xda, 0x03, 0x06, + 0x00, 0xbe, 0x04, 0x17, 0x00, 0xd2, 0x03, 0x03, + 0x00, 0xdd, 0x42, 0x91, 0x01, 0x00, 0x00, 0xd1, + 0x24, 0x01, 0x00, 0xc9, 0x26, 0x00, 0x00, 0xca, + 0xb5, 0xcc, 0xc8, 0xc5, 0xb6, 0x9d, 0xa3, 0xea, + 0x09, 0xc6, 0xc8, 0xb5, 0x49, 0x93, 0x03, 0xec, + 0xf2, 0xc6, 0xc5, 0xb6, 0x49, 0xdd, 0x42, 0x1c, + 0x01, 0x00, 0x00, 0xc5, 0x24, 0x01, 0x00, 0xcb, + 0xb5, 0xcc, 0xc8, 0xc5, 0xa3, 0xea, 0x36, 0xc7, + 0xd1, 0x9a, 0xcb, 0xde, 0xc7, 0xef, 0x8c, 0xc8, + 0xb6, 0x9d, 0x9b, 0xc3, 0x05, 0xc6, 0xc5, 0xc8, + 0x9e, 0xb6, 0x9e, 0xc2, 0x05, 0x49, 0xb5, 0xc3, + 0x04, 0xc2, 0x04, 0xc5, 0xa3, 0xea, 0x12, 0xc7, + 0xc2, 0x04, 0x47, 0xc2, 0x04, 0x71, 0x13, 0x47, + 0xc2, 0x05, 0x9d, 0x49, 0x93, 0x04, 0xec, 0xea, + 0x93, 0x03, 0xec, 0xc7, 0xdf, 0xc6, 0x23, 0x01, + 0x00, 0xc6, 0x03, 0xbf, 0x0f, 0x0e, 0x04, 0x3a, + 0x17, 0x30, 0x2b, 0x17, 0x3a, 0x26, 0x17, 0x35, + 0x30, 0x30, 0x58, 0x17, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x05, 0x02, 0x00, 0x13, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd2, 0x03, + 0x03, 0x00, 0xda, 0x03, 0x06, 0x00, 0xdd, 0x42, + 0x2c, 0x01, 0x00, 0x00, 0xde, 0x42, 0x20, 0x01, + 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0x25, 0x01, + 0x00, 0xc6, 0x03, 0xd0, 0x0f, 0x01, 0x03, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x01, 0x08, 0x01, 0x05, + 0x01, 0x00, 0xd9, 0x01, 0x09, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xda, 0x06, 0x00, 0x00, 0x00, 0xaa, + 0x06, 0x00, 0x01, 0x00, 0xbe, 0x06, 0x00, 0x02, + 0x00, 0xc2, 0x06, 0x00, 0x03, 0x00, 0xe0, 0x06, + 0x00, 0x04, 0x00, 0x9a, 0x08, 0x00, 0x05, 0x00, + 0xee, 0x06, 0x00, 0x06, 0x00, 0xf0, 0x06, 0x00, + 0x07, 0x00, 0xda, 0x03, 0x06, 0x00, 0xdd, 0x42, + 0x91, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, + 0xc9, 0xb6, 0xc3, 0x04, 0xd1, 0x42, 0x92, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xc3, 0x05, 0xb5, + 0xca, 0xc6, 0xc5, 0xa3, 0x69, 0x9d, 0x00, 0x00, + 0x00, 0xc6, 0xcb, 0xc7, 0xc5, 0xa3, 0xea, 0x0f, + 0xc2, 0x05, 0xc7, 0x47, 0xc6, 0x47, 0xb5, 0xaa, + 0xeb, 0x05, 0x93, 0x02, 0xec, 0xee, 0xc7, 0xc5, + 0xa9, 0xea, 0x03, 0xb5, 0x28, 0xc7, 0xc6, 0xaa, + 0xea, 0x2e, 0xb5, 0xcc, 0xc8, 0xc5, 0xa3, 0xea, + 0x22, 0xc2, 0x05, 0xc7, 0x47, 0xc8, 0x47, 0xc3, + 0x06, 0xc2, 0x05, 0xc7, 0x47, 0xc8, 0x71, 0xc2, + 0x05, 0xc6, 0x47, 0xc8, 0x47, 0x49, 0xc2, 0x05, + 0xc6, 0x47, 0xc8, 0xc2, 0x06, 0x49, 0x93, 0x03, + 0xec, 0xdb, 0xc2, 0x04, 0x8c, 0xc3, 0x04, 0xc2, + 0x05, 0xc6, 0x47, 0xc6, 0x47, 0x42, 0xff, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xc3, 0x07, 0xc6, + 0xb6, 0x9d, 0xcb, 0xc7, 0xc5, 0xa3, 0xea, 0x2e, + 0xc2, 0x07, 0xc2, 0x05, 0xc7, 0x47, 0xc6, 0x47, + 0x9a, 0xc3, 0x06, 0xb5, 0xcc, 0xc8, 0xc5, 0xa3, + 0xea, 0x18, 0xc2, 0x05, 0xc7, 0x47, 0xc8, 0x71, + 0x13, 0x47, 0xc2, 0x05, 0xc6, 0x47, 0xc8, 0x47, + 0xc2, 0x06, 0x9a, 0x9e, 0x49, 0x93, 0x03, 0xec, + 0xe5, 0x93, 0x02, 0xec, 0xcf, 0x93, 0x01, 0xed, + 0x61, 0xff, 0xc2, 0x04, 0xc3, 0x07, 0xb5, 0xca, + 0xc6, 0xc5, 0xa3, 0xea, 0x10, 0xc2, 0x07, 0xc2, + 0x05, 0xc6, 0x47, 0xc6, 0x47, 0x9a, 0xc3, 0x07, + 0x93, 0x01, 0xec, 0xed, 0xc2, 0x07, 0x28, 0xc6, + 0x03, 0xd3, 0x0f, 0x1d, 0x05, 0x3a, 0x12, 0x3a, + 0x35, 0x26, 0x2b, 0x0d, 0x17, 0x1c, 0x0d, 0x1c, + 0x26, 0x2b, 0x44, 0x2b, 0x17, 0x1d, 0x53, 0x30, + 0x3a, 0x26, 0x62, 0x17, 0x17, 0x1c, 0x17, 0x26, + 0x4e, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, 0x0a, + 0x01, 0x05, 0x01, 0x00, 0x97, 0x02, 0x0b, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xda, 0x06, 0x00, 0x00, + 0x00, 0x9c, 0x08, 0x00, 0x01, 0x00, 0x9a, 0x08, + 0x00, 0x02, 0x00, 0xaa, 0x06, 0x00, 0x03, 0x00, + 0xbe, 0x06, 0x00, 0x04, 0x00, 0xc2, 0x06, 0x00, + 0x05, 0x00, 0xe8, 0x07, 0x00, 0x06, 0x00, 0xd2, + 0x06, 0x00, 0x07, 0x00, 0xf0, 0x06, 0x00, 0x08, + 0x00, 0xee, 0x06, 0x00, 0x09, 0x00, 0xda, 0x03, + 0x06, 0x00, 0xdd, 0x42, 0x91, 0x01, 0x00, 0x00, + 0xd1, 0x24, 0x01, 0x00, 0xc9, 0xd1, 0x42, 0x92, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xcb, 0xdd, + 0x42, 0x1c, 0x01, 0x00, 0x00, 0xc5, 0x24, 0x01, + 0x00, 0xca, 0xb5, 0xcc, 0xc8, 0xc5, 0xa3, 0x69, + 0xef, 0x00, 0x00, 0x00, 0xc8, 0xc3, 0x04, 0xc2, + 0x04, 0xc5, 0xa3, 0xea, 0x0f, 0xc7, 0xc2, 0x04, + 0x47, 0xc8, 0x47, 0xb5, 0xaa, 0xeb, 0x05, 0x93, + 0x04, 0xec, 0xed, 0xc2, 0x04, 0xc5, 0xa9, 0xea, + 0x0d, 0x38, 0xcd, 0x00, 0x00, 0x00, 0x04, 0x0f, + 0x02, 0x00, 0x00, 0xef, 0x2f, 0xc2, 0x04, 0xc8, + 0xaa, 0xea, 0x27, 0xc7, 0xc2, 0x04, 0x47, 0xc3, + 0x09, 0xc7, 0xc2, 0x04, 0x71, 0xc7, 0xc8, 0x47, + 0x49, 0xc7, 0xc8, 0xc2, 0x09, 0x49, 0xc6, 0xc2, + 0x04, 0x47, 0xc3, 0x09, 0xc6, 0xc2, 0x04, 0x71, + 0xc6, 0xc8, 0x47, 0x49, 0xc6, 0xc8, 0xc2, 0x09, + 0x49, 0xc7, 0xc8, 0x47, 0xc8, 0x47, 0x42, 0xff, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xc3, 0x08, + 0xb5, 0xc3, 0x05, 0xc2, 0x05, 0xc5, 0xa3, 0xea, + 0x1d, 0xc7, 0xc8, 0x47, 0xc2, 0x05, 0x71, 0x13, + 0x47, 0xc2, 0x08, 0x9a, 0x49, 0xc6, 0xc8, 0x47, + 0xc2, 0x05, 0x71, 0x13, 0x47, 0xc2, 0x08, 0x9a, + 0x49, 0x93, 0x05, 0xec, 0xdf, 0xb5, 0xc3, 0x04, + 0xc2, 0x04, 0xc5, 0xa3, 0xea, 0x55, 0xc2, 0x04, + 0xc8, 0xaa, 0xea, 0x4b, 0xc7, 0xc2, 0x04, 0x47, + 0xc8, 0x47, 0xc3, 0x08, 0xc8, 0xc3, 0x05, 0xc2, + 0x05, 0xc5, 0xa3, 0xea, 0x19, 0xc7, 0xc2, 0x04, + 0x47, 0xc2, 0x05, 0x71, 0x13, 0x47, 0xc7, 0xc8, + 0x47, 0xc2, 0x05, 0x47, 0xc2, 0x08, 0x9a, 0x9e, + 0x49, 0x93, 0x05, 0xec, 0xe3, 0xb5, 0xc3, 0x05, + 0xc2, 0x05, 0xc5, 0xa3, 0xea, 0x19, 0xc6, 0xc2, + 0x04, 0x47, 0xc2, 0x05, 0x71, 0x13, 0x47, 0xc6, + 0xc8, 0x47, 0xc2, 0x05, 0x47, 0xc2, 0x08, 0x9a, + 0x9e, 0x49, 0x93, 0x05, 0xec, 0xe3, 0x93, 0x04, + 0xec, 0xa7, 0x93, 0x03, 0xed, 0x0f, 0xff, 0xc6, + 0x28, 0xc6, 0x03, 0xf5, 0x0f, 0x22, 0x04, 0x3a, + 0x35, 0x3a, 0x35, 0x30, 0x2b, 0x0d, 0x17, 0x21, + 0x3f, 0x22, 0x21, 0x2b, 0x1c, 0x21, 0x2b, 0x1e, + 0x4e, 0x30, 0x3f, 0x3f, 0x18, 0x30, 0x21, 0x2b, + 0x30, 0x67, 0x17, 0x30, 0x67, 0x18, 0x17, 0x1c, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, 0x08, 0x01, + 0x05, 0x00, 0x00, 0x92, 0x02, 0x09, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0x9a, 0x08, 0x00, 0x00, 0x00, + 0xaa, 0x06, 0x00, 0x01, 0x00, 0xbe, 0x06, 0x00, + 0x02, 0x00, 0xc2, 0x06, 0x00, 0x03, 0x00, 0x8e, + 0x08, 0x00, 0x04, 0x00, 0x8c, 0x08, 0x00, 0x05, + 0x00, 0xa0, 0x08, 0x00, 0x06, 0x00, 0xf0, 0x06, + 0x00, 0x07, 0x00, 0x38, 0x96, 0x00, 0x00, 0x00, + 0x42, 0xa3, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, + 0x00, 0x96, 0x11, 0xeb, 0x13, 0x0e, 0x38, 0x96, + 0x00, 0x00, 0x00, 0x42, 0xa3, 0x01, 0x00, 0x00, + 0xd1, 0xb5, 0x47, 0x24, 0x01, 0x00, 0x96, 0xea, + 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0x09, + 0x02, 0x00, 0x00, 0xef, 0x2f, 0xd1, 0xe9, 0xc3, + 0x05, 0xd1, 0xb5, 0x47, 0xe9, 0xc3, 0x04, 0xd1, + 0x42, 0x92, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xc9, 0xb5, 0xc3, 0x06, 0xb5, 0xca, 0xc6, 0xc2, + 0x04, 0xa3, 0x69, 0xbf, 0x00, 0x00, 0x00, 0xc2, + 0x06, 0xcb, 0xc7, 0xc2, 0x05, 0xa3, 0xea, 0x0e, + 0xc5, 0xc7, 0x47, 0xc6, 0x47, 0xb5, 0xaa, 0xeb, + 0x05, 0x93, 0x02, 0xec, 0xee, 0xc7, 0xc2, 0x05, + 0xa9, 0x6a, 0x9b, 0x00, 0x00, 0x00, 0xc7, 0xc2, + 0x06, 0xaa, 0xea, 0x34, 0xb5, 0xcc, 0xc8, 0xc2, + 0x04, 0xa3, 0xea, 0x2c, 0x36, 0xb7, 0x01, 0x00, + 0x00, 0xc5, 0xc7, 0x47, 0xc8, 0x47, 0x3b, 0xb7, + 0x01, 0x00, 0x00, 0xc5, 0xc7, 0x47, 0xc8, 0x71, + 0xc5, 0xc2, 0x06, 0x47, 0xc8, 0x47, 0x49, 0xc5, + 0xc2, 0x06, 0x47, 0xc8, 0x71, 0x38, 0xb7, 0x01, + 0x00, 0x00, 0x49, 0x93, 0x03, 0xec, 0xd0, 0xc5, + 0xc2, 0x06, 0x47, 0xc6, 0x47, 0x42, 0xff, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xc3, 0x07, 0xb5, + 0xcc, 0xc8, 0xc2, 0x04, 0xa3, 0xea, 0x11, 0xc5, + 0xc2, 0x06, 0x47, 0xc8, 0x71, 0x13, 0x47, 0xc2, + 0x07, 0x9a, 0x49, 0x93, 0x03, 0xec, 0xeb, 0xc2, + 0x06, 0xb6, 0x9d, 0xcb, 0xc7, 0xc2, 0x05, 0xa3, + 0xea, 0x2a, 0xc5, 0xc7, 0x47, 0xc6, 0x47, 0xc3, + 0x07, 0xc6, 0xcc, 0xc8, 0xc2, 0x04, 0xa3, 0xea, + 0x17, 0xc5, 0xc7, 0x47, 0xc8, 0x71, 0x13, 0x47, + 0xc5, 0xc2, 0x06, 0x47, 0xc8, 0x47, 0xc2, 0x07, + 0x9a, 0x9e, 0x49, 0x93, 0x03, 0xec, 0xe5, 0x93, + 0x02, 0xec, 0xd2, 0x93, 0x06, 0x93, 0x01, 0xed, + 0x3e, 0xff, 0xc2, 0x06, 0x28, 0xc6, 0x03, 0x9f, + 0x10, 0x21, 0x05, 0x62, 0x62, 0x3f, 0x17, 0x21, + 0x35, 0x12, 0x3a, 0x30, 0x26, 0x0d, 0x17, 0x17, + 0x1c, 0x22, 0x2b, 0x4e, 0x3f, 0x3f, 0x19, 0x53, + 0x2b, 0x3f, 0x18, 0x3a, 0x26, 0x2b, 0x5d, 0x17, + 0x17, 0x0d, 0x1c, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x01, 0x0c, 0x01, 0x05, 0x01, 0x00, 0x8c, 0x03, + 0x0d, 0xbc, 0x06, 0x00, 0x01, 0x00, 0x9a, 0x08, + 0x00, 0x00, 0x00, 0xaa, 0x06, 0x00, 0x01, 0x00, + 0xbe, 0x06, 0x00, 0x02, 0x00, 0xc2, 0x06, 0x00, + 0x03, 0x00, 0x8e, 0x08, 0x00, 0x04, 0x00, 0x8c, + 0x08, 0x00, 0x05, 0x00, 0xa0, 0x08, 0x00, 0x06, + 0x00, 0xf6, 0x06, 0x00, 0x07, 0x00, 0xd2, 0x06, + 0x00, 0x08, 0x00, 0xa2, 0x08, 0x00, 0x09, 0x00, + 0xa4, 0x08, 0x00, 0x0a, 0x00, 0xf0, 0x06, 0x00, + 0x0b, 0x00, 0xda, 0x03, 0x06, 0x00, 0x38, 0x96, + 0x00, 0x00, 0x00, 0x42, 0xa3, 0x01, 0x00, 0x00, + 0xd1, 0x24, 0x01, 0x00, 0x96, 0x11, 0xeb, 0x13, + 0x0e, 0x38, 0x96, 0x00, 0x00, 0x00, 0x42, 0xa3, + 0x01, 0x00, 0x00, 0xd1, 0xb5, 0x47, 0x24, 0x01, + 0x00, 0x96, 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, + 0x00, 0x04, 0x09, 0x02, 0x00, 0x00, 0xef, 0x2f, + 0xd1, 0xe9, 0xc3, 0x05, 0xd1, 0xb5, 0x47, 0xe9, + 0xc3, 0x04, 0xd1, 0x42, 0x92, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xc9, 0x26, 0x00, 0x00, 0xc3, + 0x09, 0xb5, 0xc3, 0x06, 0xb5, 0xca, 0xc6, 0xc2, + 0x04, 0xa3, 0x69, 0xcc, 0x00, 0x00, 0x00, 0xc2, + 0x09, 0xc6, 0x09, 0x49, 0xc2, 0x06, 0xcb, 0xc7, + 0xc2, 0x05, 0xa3, 0xea, 0x0e, 0xc5, 0xc7, 0x47, + 0xc6, 0x47, 0xb5, 0xaa, 0xeb, 0x05, 0x93, 0x02, + 0xec, 0xee, 0xc7, 0xc2, 0x05, 0xa9, 0x6a, 0xa3, + 0x00, 0x00, 0x00, 0xc2, 0x09, 0xc6, 0x0a, 0x49, + 0xc7, 0xc2, 0x06, 0xaa, 0xea, 0x34, 0xb5, 0xcc, + 0xc8, 0xc2, 0x04, 0xa3, 0xea, 0x2c, 0x36, 0xb7, + 0x01, 0x00, 0x00, 0xc5, 0xc7, 0x47, 0xc8, 0x47, + 0x3b, 0xb7, 0x01, 0x00, 0x00, 0xc5, 0xc7, 0x47, + 0xc8, 0x71, 0xc5, 0xc2, 0x06, 0x47, 0xc8, 0x47, + 0x49, 0xc5, 0xc2, 0x06, 0x47, 0xc8, 0x71, 0x38, + 0xb7, 0x01, 0x00, 0x00, 0x49, 0x93, 0x03, 0xec, + 0xd0, 0xc5, 0xc2, 0x06, 0x47, 0xc6, 0x47, 0x42, + 0xff, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xc3, + 0x0b, 0xb5, 0xcc, 0xc8, 0xc2, 0x04, 0xa3, 0xea, + 0x11, 0xc5, 0xc2, 0x06, 0x47, 0xc8, 0x71, 0x13, + 0x47, 0xc2, 0x0b, 0x9a, 0x49, 0x93, 0x03, 0xec, + 0xeb, 0xb5, 0xcb, 0xc7, 0xc2, 0x05, 0xa3, 0xea, + 0x30, 0xc7, 0xc2, 0x06, 0xaa, 0xea, 0x26, 0xc5, + 0xc7, 0x47, 0xc6, 0x47, 0xc3, 0x0b, 0xc6, 0xcc, + 0xc8, 0xc2, 0x04, 0xa3, 0xea, 0x17, 0xc5, 0xc7, + 0x47, 0xc8, 0x71, 0x13, 0x47, 0xc5, 0xc2, 0x06, + 0x47, 0xc8, 0x47, 0xc2, 0x0b, 0x9a, 0x9e, 0x49, + 0x93, 0x03, 0xec, 0xe5, 0x93, 0x02, 0xec, 0xcc, + 0x93, 0x06, 0x93, 0x01, 0xed, 0x31, 0xff, 0xc2, + 0x04, 0xc2, 0x06, 0x9e, 0xc3, 0x0a, 0xdd, 0xc2, + 0x04, 0xc2, 0x0a, 0xf0, 0xc3, 0x08, 0xb5, 0xcc, + 0xb5, 0xca, 0xc6, 0xc2, 0x04, 0xa3, 0xea, 0x50, + 0xc2, 0x09, 0xc6, 0x47, 0x96, 0xea, 0x45, 0xb5, + 0xc3, 0x06, 0xb5, 0xc3, 0x07, 0xb5, 0xcb, 0xc7, + 0xc2, 0x04, 0xa3, 0xea, 0x35, 0xc2, 0x09, 0xc7, + 0x47, 0xea, 0x13, 0xc2, 0x08, 0xc7, 0x47, 0xc8, + 0x71, 0xc5, 0xc2, 0x07, 0x47, 0xc6, 0x47, 0x8c, + 0x49, 0x93, 0x07, 0xec, 0x19, 0xc2, 0x06, 0xc8, + 0xa9, 0xea, 0x0a, 0xc2, 0x08, 0xc7, 0x47, 0xc8, + 0xb6, 0x49, 0xec, 0x08, 0xc2, 0x08, 0xc7, 0x47, + 0xc8, 0xb5, 0x49, 0x93, 0x06, 0x93, 0x02, 0xec, + 0xc7, 0x93, 0x03, 0x93, 0x01, 0xec, 0xac, 0xc2, + 0x08, 0x28, 0xc6, 0x03, 0xc8, 0x10, 0x3b, 0x05, + 0x62, 0x62, 0x3f, 0x17, 0x21, 0x35, 0x1c, 0x12, + 0x3a, 0x1c, 0x30, 0x26, 0x0d, 0x17, 0x17, 0x1c, + 0x1c, 0x22, 0x2b, 0x4e, 0x3f, 0x3f, 0x19, 0x53, + 0x2b, 0x3f, 0x18, 0x2b, 0x21, 0x26, 0x2b, 0x5d, + 0x18, 0x17, 0x0e, 0x00, 0x05, 0x08, 0x26, 0x2b, + 0x0d, 0x2b, 0x27, 0x12, 0x12, 0x2b, 0x21, 0x49, + 0x0d, 0x0d, 0x21, 0x26, 0x0d, 0x27, 0x0e, 0x17, + 0x0e, 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x02, + 0x03, 0x02, 0x04, 0x00, 0x00, 0x2d, 0x05, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xaa, 0x06, 0x00, 0x00, 0x00, 0xda, 0x06, + 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, 0x02, 0x00, + 0xd1, 0xe9, 0xce, 0xd2, 0xe9, 0xaa, 0xea, 0x0d, + 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0x13, 0x02, + 0x00, 0x00, 0xef, 0x2f, 0xb5, 0xcb, 0xb5, 0xc9, + 0xc5, 0xc6, 0xa3, 0xea, 0x0f, 0xc7, 0xd1, 0xc5, + 0x47, 0xd2, 0xc5, 0x47, 0x9a, 0x9d, 0xcb, 0x93, + 0x00, 0xec, 0xee, 0xc7, 0x28, 0xc6, 0x03, 0x92, + 0x11, 0x08, 0x04, 0x12, 0x1c, 0x40, 0x0d, 0x26, + 0x35, 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x02, + 0x01, 0x02, 0x06, 0x00, 0x00, 0x58, 0x03, 0xf4, + 0x07, 0x00, 0x01, 0x00, 0xf6, 0x07, 0x00, 0x01, + 0x00, 0xd2, 0x06, 0x00, 0x00, 0x00, 0xd1, 0xe9, + 0xb8, 0xaa, 0x11, 0xeb, 0x06, 0x0e, 0xd2, 0xe9, + 0xb8, 0xaa, 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, + 0x00, 0x04, 0x14, 0x02, 0x00, 0x00, 0xef, 0x2f, + 0x26, 0x00, 0x00, 0xcd, 0xb5, 0x71, 0xd1, 0xb6, + 0x47, 0xd2, 0xb7, 0x47, 0x9a, 0xd1, 0xb7, 0x47, + 0xd2, 0xb6, 0x47, 0x9a, 0x9e, 0x49, 0xc5, 0xb6, + 0x71, 0xd1, 0xb7, 0x47, 0xd2, 0xb5, 0x47, 0x9a, + 0xd1, 0xb5, 0x47, 0xd2, 0xb7, 0x47, 0x9a, 0x9e, + 0x49, 0xc5, 0xb7, 0x71, 0xd1, 0xb5, 0x47, 0xd2, + 0xb6, 0x47, 0x9a, 0xd1, 0xb6, 0x47, 0xd2, 0xb5, + 0x47, 0x9a, 0x9e, 0x49, 0xc5, 0x28, 0xc6, 0x03, + 0x9f, 0x11, 0x07, 0x04, 0x49, 0x3f, 0x17, 0x5d, + 0x62, 0x62, 0x0e, 0x43, 0x06, 0x01, 0xd8, 0x05, + 0x02, 0x03, 0x02, 0x05, 0x00, 0x00, 0x30, 0x05, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xd2, 0x06, 0x00, 0x00, 0x00, 0xaa, + 0x06, 0x00, 0x01, 0x00, 0xda, 0x06, 0x00, 0x02, + 0x00, 0xd1, 0xe9, 0xcf, 0xd2, 0xe9, 0xaa, 0xea, + 0x0d, 0x38, 0xd0, 0x00, 0x00, 0x00, 0x04, 0x15, + 0x02, 0x00, 0x00, 0xef, 0x2f, 0x26, 0x00, 0x00, + 0xc9, 0xb5, 0xca, 0xc6, 0xc7, 0xa3, 0xea, 0x10, + 0xc5, 0xc6, 0x71, 0xd1, 0xc6, 0x47, 0xd2, 0xc6, + 0x47, 0x9d, 0x49, 0x93, 0x01, 0xec, 0xed, 0xc5, + 0x28, 0xc6, 0x03, 0xab, 0x11, 0x07, 0x04, 0x12, + 0x1c, 0x3f, 0x17, 0x26, 0x4e, 0x0e, 0x43, 0x06, + 0x01, 0xda, 0x05, 0x02, 0x03, 0x02, 0x05, 0x00, + 0x00, 0x30, 0x05, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, + 0x00, 0x00, 0xaa, 0x06, 0x00, 0x01, 0x00, 0xda, + 0x06, 0x00, 0x02, 0x00, 0xd1, 0xe9, 0xcf, 0xd2, + 0xe9, 0xaa, 0xea, 0x0d, 0x38, 0xd0, 0x00, 0x00, + 0x00, 0x04, 0x15, 0x02, 0x00, 0x00, 0xef, 0x2f, + 0x26, 0x00, 0x00, 0xc9, 0xb5, 0xca, 0xc6, 0xc7, + 0xa3, 0xea, 0x10, 0xc5, 0xc6, 0x71, 0xd1, 0xc6, + 0x47, 0xd2, 0xc6, 0x47, 0x9e, 0x49, 0x93, 0x01, + 0xec, 0xed, 0xc5, 0x28, 0xc6, 0x03, 0xb5, 0x11, + 0x07, 0x04, 0x12, 0x1c, 0x3f, 0x17, 0x26, 0x4e, + 0x0e, 0x43, 0x06, 0x01, 0xdc, 0x05, 0x02, 0x03, + 0x02, 0x04, 0x00, 0x00, 0x1d, 0x05, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xd2, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, 0x00, + 0x01, 0x00, 0xda, 0x06, 0x00, 0x02, 0x00, 0xd1, + 0xe9, 0xcb, 0x26, 0x00, 0x00, 0xc9, 0xb5, 0xca, + 0xc6, 0xc7, 0xa3, 0xea, 0x0e, 0xc5, 0xc6, 0x71, + 0xd1, 0xc6, 0x47, 0xd2, 0x9a, 0x49, 0x93, 0x01, + 0xec, 0xef, 0xc5, 0x28, 0xc6, 0x03, 0xbf, 0x11, + 0x05, 0x04, 0x12, 0x17, 0x26, 0x44, 0x0e, 0x43, + 0x06, 0x01, 0xde, 0x05, 0x02, 0x0b, 0x02, 0x05, + 0x00, 0x00, 0xbf, 0x02, 0x0d, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0x8c, + 0x08, 0x00, 0x00, 0x00, 0x8e, 0x08, 0x00, 0x01, + 0x00, 0xa0, 0x08, 0x00, 0x02, 0x00, 0xaa, 0x06, + 0x00, 0x03, 0x00, 0xbe, 0x06, 0x00, 0x04, 0x00, + 0xc2, 0x06, 0x00, 0x05, 0x00, 0xd2, 0x06, 0x00, + 0x06, 0x00, 0x90, 0x08, 0x00, 0x07, 0x00, 0xfe, + 0x07, 0x00, 0x08, 0x00, 0xac, 0x08, 0x00, 0x09, + 0x00, 0xae, 0x08, 0x00, 0x0a, 0x00, 0xd1, 0xe9, + 0xc9, 0x38, 0x96, 0x00, 0x00, 0x00, 0x42, 0xa3, + 0x01, 0x00, 0x00, 0xd1, 0xb5, 0x47, 0x24, 0x01, + 0x00, 0xc4, 0x09, 0xea, 0x08, 0xd1, 0xb5, 0x47, + 0xe9, 0xcb, 0xec, 0x03, 0xb6, 0xcb, 0xc7, 0xd2, + 0xe9, 0xaa, 0xea, 0x0d, 0x38, 0xcd, 0x00, 0x00, + 0x00, 0x04, 0x18, 0x02, 0x00, 0x00, 0xef, 0x2f, + 0x38, 0x96, 0x00, 0x00, 0x00, 0x42, 0xa3, 0x01, + 0x00, 0x00, 0xd2, 0xb5, 0x47, 0x24, 0x01, 0x00, + 0xc4, 0x0a, 0xea, 0x08, 0xd2, 0xb5, 0x47, 0xe9, + 0xca, 0xec, 0x03, 0xb6, 0xca, 0x26, 0x00, 0x00, + 0xc3, 0x06, 0xc2, 0x09, 0xea, 0x55, 0xc2, 0x0a, + 0xea, 0x51, 0xb5, 0xcc, 0xc8, 0xc5, 0xa3, 0x69, + 0xda, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0xc3, + 0x07, 0xb5, 0xc3, 0x04, 0xc2, 0x04, 0xc6, 0xa3, + 0xea, 0x2f, 0xb5, 0xc3, 0x08, 0xb5, 0xc3, 0x05, + 0xc2, 0x05, 0xc7, 0xa3, 0xea, 0x18, 0xc2, 0x08, + 0xd1, 0xc8, 0x47, 0xc2, 0x05, 0x47, 0xd2, 0xc2, + 0x05, 0x47, 0xc2, 0x04, 0x47, 0x9a, 0x9d, 0xc3, + 0x08, 0x93, 0x05, 0xec, 0xe4, 0xc2, 0x07, 0xc2, + 0x04, 0xc2, 0x08, 0x49, 0x93, 0x04, 0xec, 0xcd, + 0xc2, 0x06, 0xc8, 0xc2, 0x07, 0x49, 0x93, 0x03, + 0xec, 0xb3, 0xc2, 0x09, 0xea, 0x3a, 0xc2, 0x0a, + 0x96, 0xea, 0x35, 0xb5, 0xcc, 0xc8, 0xc5, 0xa3, + 0x69, 0x81, 0x00, 0x00, 0x00, 0xb5, 0xc3, 0x08, + 0xb5, 0xc3, 0x05, 0xc2, 0x05, 0xc7, 0xa3, 0xea, + 0x15, 0xc2, 0x08, 0xd1, 0xc8, 0x47, 0xc2, 0x05, + 0x47, 0xd2, 0xc2, 0x05, 0x47, 0x9a, 0x9d, 0xc3, + 0x08, 0x93, 0x05, 0xec, 0xe7, 0xc2, 0x06, 0xc8, + 0xc2, 0x08, 0x49, 0x93, 0x03, 0xec, 0xcf, 0xc2, + 0x09, 0x96, 0xea, 0x38, 0xc2, 0x0a, 0xea, 0x34, + 0xb5, 0xcc, 0xc8, 0xc5, 0xa3, 0xea, 0x44, 0x26, + 0x00, 0x00, 0xc3, 0x07, 0xb5, 0xc3, 0x04, 0xc2, + 0x04, 0xc6, 0xa3, 0xea, 0x15, 0xc2, 0x07, 0xc2, + 0x04, 0x71, 0xd1, 0xc8, 0x47, 0xd2, 0xb5, 0x47, + 0xc2, 0x04, 0x47, 0x9a, 0x49, 0x93, 0x04, 0xec, + 0xe7, 0xc2, 0x06, 0xc8, 0xc2, 0x07, 0x49, 0x93, + 0x03, 0xec, 0xd0, 0xb5, 0xcc, 0xc8, 0xc5, 0xa3, + 0xea, 0x11, 0xc2, 0x06, 0xc8, 0x71, 0xd1, 0xc8, + 0x47, 0xd2, 0xb5, 0x47, 0x9a, 0x49, 0x93, 0x03, + 0xec, 0xec, 0xc2, 0x06, 0x28, 0xc6, 0x03, 0xc7, + 0x11, 0x2d, 0x04, 0x12, 0x5d, 0x0d, 0x1c, 0x0d, + 0x0e, 0x21, 0x3f, 0x5d, 0x0d, 0x27, 0x0d, 0x1c, + 0x2b, 0x35, 0x1c, 0x30, 0x12, 0x30, 0x62, 0x17, + 0x26, 0x17, 0x21, 0x17, 0x30, 0x35, 0x12, 0x30, + 0x53, 0x17, 0x21, 0x17, 0x30, 0x26, 0x1c, 0x30, + 0x53, 0x17, 0x21, 0x18, 0x26, 0x3f, 0x18, 0x0e, + 0x43, 0x06, 0x01, 0xe0, 0x05, 0x02, 0x00, 0x02, + 0x04, 0x01, 0x00, 0x0e, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xde, + 0x05, 0x42, 0x01, 0xdd, 0xd1, 0xd2, 0x42, 0xff, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0xfb, 0x11, 0x01, 0x03, 0x0e, + 0x43, 0x06, 0x01, 0xe2, 0x05, 0x01, 0x03, 0x01, + 0x04, 0x00, 0x00, 0x23, 0x04, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xd2, 0x06, 0x00, 0x00, 0x00, 0xaa, + 0x06, 0x00, 0x01, 0x00, 0xda, 0x06, 0x00, 0x02, + 0x00, 0xd1, 0xe9, 0xcb, 0x26, 0x00, 0x00, 0xc9, + 0xb5, 0xca, 0xc6, 0xc7, 0xa3, 0xea, 0x14, 0xc5, + 0xc6, 0x71, 0xd1, 0xc6, 0x47, 0x42, 0xff, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x49, 0x93, 0x01, + 0xec, 0xe9, 0xc5, 0x28, 0xc6, 0x03, 0xfe, 0x11, + 0x05, 0x04, 0x12, 0x17, 0x26, 0x62, 0x0e, 0x43, + 0x06, 0x01, 0xe4, 0x05, 0x02, 0x02, 0x02, 0x03, + 0x00, 0x00, 0x22, 0x04, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xda, 0x06, + 0x00, 0x00, 0x00, 0xaa, 0x06, 0x00, 0x01, 0x00, + 0xd1, 0xe9, 0xcd, 0xd2, 0xe9, 0xaa, 0xea, 0x03, + 0x09, 0x28, 0xb5, 0xca, 0xc6, 0xc5, 0xa3, 0xea, + 0x10, 0xd1, 0xc6, 0x47, 0xd2, 0xc6, 0x47, 0xaa, + 0xea, 0x03, 0x09, 0x28, 0x93, 0x01, 0xec, 0xed, + 0x0a, 0x28, 0xc6, 0x03, 0x86, 0x12, 0x08, 0x04, + 0x12, 0x1c, 0x0d, 0x26, 0x30, 0x0d, 0x17, 0x0e, + 0x42, 0x07, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x02, 0x01, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xd1, 0x28, 0xc6, 0x03, 0x99, 0x12, 0x01, + 0x03, 0x0e, 0x42, 0x07, 0x01, 0x00, 0x01, 0x03, + 0x01, 0x04, 0x00, 0x00, 0x1c, 0x04, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x00, 0x00, + 0xda, 0x06, 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, + 0x02, 0x00, 0xd1, 0xe9, 0xca, 0x26, 0x00, 0x00, + 0xcb, 0xb5, 0xc9, 0xc5, 0xc6, 0xa3, 0xea, 0x0d, + 0xc7, 0xc5, 0x71, 0xd1, 0xc5, 0x47, 0x8c, 0x49, + 0x93, 0x00, 0xec, 0xf0, 0xc7, 0x28, 0xc6, 0x03, + 0x9c, 0x12, 0x05, 0x04, 0x12, 0x17, 0x26, 0x3f, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x02, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x0c, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd1, + 0xd2, 0x42, 0xff, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x9a, 0x28, 0xc6, 0x03, 0xa9, 0x12, 0x00, + 0x0e, 0x42, 0x07, 0x01, 0x00, 0x02, 0x00, 0x02, + 0x03, 0x01, 0x00, 0x06, 0x02, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xdc, + 0x05, 0x41, 0x01, 0xdd, 0xd2, 0xd1, 0x23, 0x02, + 0x00, 0xc6, 0x03, 0xaf, 0x12, 0x00, 0x0e, 0x42, + 0x07, 0x01, 0x00, 0x02, 0x00, 0x02, 0x03, 0x01, + 0x00, 0x06, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xe2, 0x05, 0x44, + 0x01, 0xd1, 0xdd, 0xd2, 0xef, 0x9a, 0x28, 0xc6, + 0x03, 0xb0, 0x12, 0x00, 0x0e, 0x42, 0x07, 0x01, + 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x25, + 0x04, 0xaa, 0x06, 0x00, 0x00, 0x00, 0xda, 0x06, + 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, 0x02, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcc, 0xc8, 0xe9, + 0xca, 0x26, 0x00, 0x00, 0xcb, 0xb5, 0xc9, 0xc5, + 0xc6, 0xa3, 0xea, 0x14, 0xc7, 0xc5, 0x71, 0xc8, + 0xc5, 0x47, 0x42, 0xfd, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x49, 0x93, 0x00, 0xec, 0xe9, 0xc7, + 0x28, 0xc6, 0x03, 0xb4, 0x12, 0x05, 0x0e, 0x12, + 0x17, 0x26, 0x62, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, 0x3f, 0x06, + 0xd2, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x06, 0x00, + 0x01, 0x00, 0xda, 0x06, 0x00, 0x02, 0x00, 0xd6, + 0x07, 0x00, 0x03, 0x00, 0xbc, 0x06, 0x00, 0x04, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xc3, 0x05, + 0xc2, 0x05, 0xc3, 0x04, 0x26, 0x00, 0x00, 0xc9, + 0xc2, 0x04, 0xe9, 0xcb, 0xb5, 0xca, 0xc6, 0xc7, + 0xa3, 0xea, 0x28, 0xc2, 0x04, 0xc6, 0x47, 0xcc, + 0x38, 0x96, 0x00, 0x00, 0x00, 0x42, 0xa3, 0x01, + 0x00, 0x00, 0xc8, 0x24, 0x01, 0x00, 0xea, 0x0b, + 0xc8, 0x42, 0x92, 0x01, 0x00, 0x00, 0x24, 0x00, + 0x00, 0xcc, 0xc5, 0xc6, 0xc8, 0x49, 0x93, 0x01, + 0xec, 0xd5, 0xc5, 0x28, 0xc6, 0x03, 0xbc, 0x12, + 0x0a, 0x12, 0x17, 0x17, 0x17, 0x26, 0x1c, 0x53, + 0x35, 0x17, 0x17, 0x0e, 0x42, 0x07, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x01, 0x00, 0x0c, 0x01, + 0x10, 0x00, 0x01, 0x00, 0xda, 0x03, 0x06, 0x00, + 0x08, 0xc9, 0xdd, 0x42, 0xff, 0x00, 0x00, 0x00, + 0xc5, 0x25, 0x01, 0x00, 0xc6, 0x03, 0xc8, 0x12, + 0x01, 0x0d, 0x0e, 0x43, 0x06, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x07, 0x00, 0xca, + 0x03, 0x01, 0x00, 0xdd, 0x41, 0x29, 0x01, 0x00, + 0x00, 0x28, 0xc6, 0x03, 0xd5, 0x12, 0x00, 0x0e, + 0x43, 0x06, 0x01, 0xf2, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x09, 0x01, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xd1, 0x42, 0xf9, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0xc6, 0x03, 0xe1, 0x12, 0x01, + 0x04, 0x0e, 0x43, 0x06, 0x01, 0xf4, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, 0x01, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xd1, 0x42, 0xfa, 0x00, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xc6, 0x03, 0xe6, + 0x12, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, 0xf6, + 0x03, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd1, 0x42, + 0xfb, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0xc6, + 0x03, 0xeb, 0x12, 0x01, 0x04, 0x0e, 0x43, 0x06, + 0x01, 0xf8, 0x03, 0x01, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x09, 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xd1, 0x42, 0xfc, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0xc6, 0x03, 0xf0, 0x12, 0x01, 0x04, 0x0e, + 0x43, 0x06, 0x01, 0xfa, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x09, 0x01, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xd1, 0x42, 0xfd, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0xc6, 0x03, 0xf5, 0x12, 0x01, + 0x04, 0x0e, 0x43, 0x06, 0x01, 0xfc, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, 0x01, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xd1, 0x42, 0xfe, 0x00, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xc6, 0x03, 0xfa, + 0x12, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, 0xfe, + 0x03, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd1, 0x42, + 0xff, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0xc6, + 0x03, 0xff, 0x12, 0x01, 0x04, 0x0e, 0x43, 0x06, + 0x01, 0x80, 0x04, 0x01, 0x00, 0x01, 0x04, 0x05, + 0x00, 0x58, 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc8, 0x03, 0x00, 0x00, 0xcc, 0x03, 0x02, 0x00, + 0xd2, 0x03, 0x05, 0x00, 0xd6, 0x03, 0x07, 0x00, + 0xca, 0x03, 0x01, 0x00, 0xdd, 0x42, 0x77, 0x01, + 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xea, 0x03, + 0xd1, 0x28, 0xd1, 0xde, 0xa7, 0xea, 0x16, 0xdd, + 0x42, 0xb2, 0x01, 0x00, 0x00, 0xd1, 0x41, 0xc1, + 0x01, 0x00, 0x00, 0xd1, 0x41, 0xc2, 0x01, 0x00, + 0x00, 0x25, 0x02, 0x00, 0xd1, 0xdf, 0xa7, 0xea, + 0x03, 0xd1, 0x28, 0xd1, 0xe0, 0xa7, 0xea, 0x19, + 0xdf, 0x42, 0x8d, 0x01, 0x00, 0x00, 0xd1, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0xd1, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x24, 0x02, 0x00, 0xb5, 0x47, 0x28, + 0x5e, 0x04, 0x00, 0x42, 0x02, 0x01, 0x00, 0x00, + 0xd1, 0x25, 0x01, 0x00, 0xc6, 0x03, 0x84, 0x13, + 0x0a, 0x04, 0x3f, 0x08, 0x21, 0x6c, 0x1c, 0x08, + 0x21, 0x76, 0x08, 0x0e, 0x43, 0x06, 0x01, 0x82, + 0x04, 0x01, 0x00, 0x01, 0x04, 0x03, 0x00, 0x32, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc8, 0x03, + 0x00, 0x00, 0xcc, 0x03, 0x02, 0x00, 0xca, 0x03, + 0x01, 0x00, 0xdd, 0x42, 0x77, 0x01, 0x00, 0x00, + 0xd1, 0x24, 0x01, 0x00, 0xea, 0x03, 0xd1, 0x28, + 0xd1, 0xde, 0xa7, 0xea, 0x16, 0xdd, 0x42, 0x19, + 0x02, 0x00, 0x00, 0xd1, 0x41, 0xc1, 0x01, 0x00, + 0x00, 0xd1, 0x41, 0xc2, 0x01, 0x00, 0x00, 0x25, + 0x02, 0x00, 0xdf, 0x42, 0x01, 0x01, 0x00, 0x00, + 0xd1, 0x25, 0x01, 0x00, 0xc6, 0x03, 0x93, 0x13, + 0x05, 0x04, 0x3f, 0x08, 0x21, 0x6d, 0x0e, 0x43, + 0x06, 0x01, 0x84, 0x04, 0x01, 0x00, 0x01, 0x04, + 0x03, 0x00, 0x32, 0x01, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xc8, 0x03, 0x00, 0x00, 0xcc, 0x03, 0x02, + 0x00, 0xca, 0x03, 0x01, 0x00, 0xdd, 0x42, 0x77, + 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xea, + 0x03, 0xd1, 0x28, 0xd1, 0xde, 0xa7, 0xea, 0x16, + 0xdd, 0x42, 0x1a, 0x02, 0x00, 0x00, 0xd1, 0x41, + 0xc1, 0x01, 0x00, 0x00, 0xd1, 0x41, 0xc2, 0x01, + 0x00, 0x00, 0x25, 0x02, 0x00, 0xdf, 0x42, 0x02, + 0x01, 0x00, 0x00, 0xd1, 0x25, 0x01, 0x00, 0xc6, + 0x03, 0x9e, 0x13, 0x05, 0x04, 0x3f, 0x08, 0x21, + 0x6d, 0x0e, 0x43, 0x06, 0x01, 0x86, 0x04, 0x01, + 0x04, 0x01, 0x05, 0x05, 0x00, 0x6b, 0x05, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xdc, 0x06, 0x00, 0x00, + 0x00, 0xec, 0x06, 0x00, 0x01, 0x00, 0x9e, 0x07, + 0x00, 0x02, 0x00, 0xa0, 0x07, 0x00, 0x03, 0x00, + 0xd8, 0x03, 0x08, 0x00, 0xce, 0x03, 0x03, 0x00, + 0xf8, 0x03, 0x18, 0x00, 0x86, 0x04, 0x1f, 0x00, + 0xca, 0x03, 0x01, 0x00, 0xd1, 0xdd, 0xa7, 0xea, + 0x07, 0xd1, 0xb6, 0xb7, 0x9b, 0xae, 0x28, 0xd1, + 0xde, 0xa7, 0xea, 0x34, 0xdf, 0xd1, 0xef, 0xc9, + 0xd1, 0x41, 0xcf, 0x01, 0x00, 0x00, 0xca, 0xe0, + 0xc5, 0xc6, 0x9d, 0xb7, 0x9b, 0xef, 0xcb, 0xe0, + 0xc5, 0xc6, 0x9e, 0xb7, 0x9b, 0xef, 0xcc, 0xd1, + 0x41, 0xd0, 0x01, 0x00, 0x00, 0xb5, 0xa3, 0xea, + 0x04, 0xc8, 0x8c, 0xcc, 0xde, 0x42, 0x8a, 0x01, + 0x00, 0x00, 0xc7, 0xc8, 0x25, 0x02, 0x00, 0x5e, + 0x04, 0x00, 0xd1, 0xef, 0xd9, 0xb5, 0xa3, 0xea, + 0x13, 0xde, 0xb5, 0x5e, 0x04, 0x00, 0x42, 0x03, + 0x01, 0x00, 0x00, 0xd1, 0x8c, 0x24, 0x01, 0x00, + 0x23, 0x02, 0x00, 0x5e, 0x04, 0x00, 0x42, 0x03, + 0x01, 0x00, 0x00, 0xd1, 0x25, 0x01, 0x00, 0xc6, + 0x03, 0xa9, 0x13, 0x0e, 0x05, 0x1c, 0x1c, 0x21, + 0x17, 0x26, 0x2b, 0x2b, 0x35, 0x12, 0x3b, 0x21, + 0x17, 0x5e, 0x0e, 0x43, 0x06, 0x01, 0x88, 0x04, + 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, 0x01, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd1, 0x42, 0x04, + 0x01, 0x00, 0x00, 0x25, 0x00, 0x00, 0xc6, 0x03, + 0xc0, 0x13, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, + 0x8a, 0x04, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, + 0x09, 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd1, + 0x42, 0x05, 0x01, 0x00, 0x00, 0x25, 0x00, 0x00, + 0xc6, 0x03, 0xc5, 0x13, 0x01, 0x04, 0x0e, 0x43, + 0x06, 0x01, 0x8c, 0x04, 0x01, 0x00, 0x01, 0x02, + 0x02, 0x00, 0x0b, 0x01, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0x8a, 0x04, 0x21, 0x00, 0xca, 0x03, 0x01, + 0x00, 0xdd, 0xd1, 0xef, 0xde, 0x41, 0x86, 0x01, + 0x00, 0x00, 0x9a, 0x28, 0xc6, 0x03, 0xca, 0x13, + 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, 0x8e, 0x04, + 0x01, 0x00, 0x01, 0x02, 0x02, 0x00, 0x0b, 0x01, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0x8a, 0x04, 0x21, + 0x00, 0xca, 0x03, 0x01, 0x00, 0xdd, 0xd1, 0xef, + 0xde, 0x41, 0x87, 0x01, 0x00, 0x00, 0x9a, 0x28, + 0xc6, 0x03, 0xcf, 0x13, 0x01, 0x04, 0x0e, 0x43, + 0x06, 0x01, 0x90, 0x04, 0x01, 0x00, 0x01, 0x02, + 0x01, 0x00, 0x07, 0x01, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0x8e, 0x04, 0x23, 0x00, 0xdd, 0xd1, 0xef, + 0xbd, 0x0a, 0x9a, 0x28, 0xc6, 0x03, 0xd4, 0x13, + 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, 0x92, 0x04, + 0x01, 0x00, 0x01, 0x03, 0x00, 0x00, 0x08, 0x01, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xbd, 0x0a, 0xd1, + 0xbd, 0x0a, 0x9b, 0xae, 0x28, 0xc6, 0x03, 0xd9, + 0x13, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, 0x94, + 0x04, 0x01, 0x01, 0x01, 0x04, 0x05, 0x00, 0x2b, + 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xdc, 0x06, + 0x00, 0x00, 0x00, 0xce, 0x03, 0x03, 0x00, 0xd8, + 0x03, 0x08, 0x00, 0x88, 0x04, 0x20, 0x00, 0xdc, + 0x03, 0x0a, 0x00, 0xca, 0x03, 0x01, 0x00, 0xd1, + 0xdd, 0xa7, 0x11, 0xeb, 0x05, 0x0e, 0xd1, 0xde, + 0xa7, 0xea, 0x10, 0xdf, 0xd1, 0xe0, 0x9a, 0xef, + 0xcd, 0xb6, 0xc5, 0x9b, 0x9e, 0xb7, 0xe0, 0x9a, + 0x9b, 0x28, 0x5e, 0x04, 0x00, 0x42, 0x0a, 0x01, + 0x00, 0x00, 0x5e, 0x04, 0x00, 0xd1, 0xef, 0x25, + 0x01, 0x00, 0xc6, 0x03, 0xde, 0x13, 0x05, 0x05, + 0x3f, 0x21, 0x2b, 0x08, 0x0e, 0x43, 0x06, 0x01, + 0x96, 0x04, 0x01, 0x01, 0x01, 0x04, 0x05, 0x00, + 0x29, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xdc, + 0x06, 0x00, 0x00, 0x00, 0xce, 0x03, 0x03, 0x00, + 0xd8, 0x03, 0x08, 0x00, 0x88, 0x04, 0x20, 0x00, + 0xdc, 0x03, 0x0a, 0x00, 0xca, 0x03, 0x01, 0x00, + 0xd1, 0xdd, 0xa7, 0x11, 0xeb, 0x05, 0x0e, 0xd1, + 0xde, 0xa7, 0xea, 0x0e, 0xdf, 0xd1, 0xe0, 0x9a, + 0xef, 0xcd, 0xb6, 0xc5, 0x9b, 0x9d, 0xb7, 0x9b, + 0x28, 0x5e, 0x04, 0x00, 0x42, 0x0b, 0x01, 0x00, + 0x00, 0x5e, 0x04, 0x00, 0xd1, 0xef, 0x25, 0x01, + 0x00, 0xc6, 0x03, 0xe9, 0x13, 0x05, 0x05, 0x3f, + 0x21, 0x21, 0x08, 0x0e, 0x43, 0x06, 0x01, 0x98, + 0x04, 0x01, 0x00, 0x01, 0x04, 0x05, 0x00, 0x24, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xce, 0x03, + 0x03, 0x00, 0xd8, 0x03, 0x08, 0x00, 0x94, 0x04, + 0x26, 0x00, 0x96, 0x04, 0x27, 0x00, 0xca, 0x03, + 0x01, 0x00, 0xd1, 0xdd, 0xa7, 0x11, 0xeb, 0x05, + 0x0e, 0xd1, 0xde, 0xa7, 0xea, 0x09, 0xdf, 0xd1, + 0xef, 0xe0, 0xd1, 0xef, 0x9b, 0x28, 0x5e, 0x04, + 0x00, 0x42, 0x0c, 0x01, 0x00, 0x00, 0x5e, 0x04, + 0x00, 0xd1, 0xef, 0x25, 0x01, 0x00, 0xc6, 0x03, + 0xf4, 0x13, 0x04, 0x04, 0x3f, 0x26, 0x08, 0x0e, + 0x43, 0x06, 0x01, 0x9a, 0x04, 0x01, 0x00, 0x01, + 0x04, 0x01, 0x00, 0x0c, 0x01, 0xbc, 0x06, 0x00, + 0x01, 0x00, 0xca, 0x03, 0x01, 0x00, 0xdd, 0x42, + 0x0d, 0x01, 0x00, 0x00, 0xdd, 0xd1, 0xef, 0x25, + 0x01, 0x00, 0xc6, 0x03, 0xfd, 0x13, 0x01, 0x04, + 0x0e, 0x43, 0x06, 0x01, 0x9c, 0x04, 0x01, 0x00, + 0x01, 0x04, 0x01, 0x00, 0x0c, 0x01, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xca, 0x03, 0x01, 0x00, 0xdd, + 0x42, 0x0e, 0x01, 0x00, 0x00, 0xdd, 0xd1, 0xef, + 0x25, 0x01, 0x00, 0xc6, 0x03, 0x82, 0x14, 0x01, + 0x04, 0x0e, 0x43, 0x06, 0x01, 0x9e, 0x04, 0x01, + 0x00, 0x01, 0x04, 0x01, 0x00, 0x0c, 0x01, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xca, 0x03, 0x01, 0x00, + 0xdd, 0x42, 0x0f, 0x01, 0x00, 0x00, 0xdd, 0xd1, + 0xef, 0x25, 0x01, 0x00, 0xc6, 0x03, 0x87, 0x14, + 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, 0xa0, 0x04, + 0x02, 0x00, 0x02, 0x05, 0x01, 0x00, 0x0f, 0x02, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xca, 0x03, 0x01, 0x00, 0xdd, 0x42, + 0x10, 0x01, 0x00, 0x00, 0xdd, 0xd1, 0xef, 0xdd, + 0xd2, 0xef, 0x25, 0x02, 0x00, 0xc6, 0x03, 0x8c, + 0x14, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, 0xa2, + 0x04, 0x01, 0x00, 0x01, 0x02, 0x02, 0x00, 0x16, + 0x01, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xca, 0x03, + 0x01, 0x00, 0x94, 0x04, 0x26, 0x00, 0xd1, 0xb5, + 0xa9, 0xea, 0x03, 0xb6, 0x28, 0xd1, 0xdd, 0x41, + 0x29, 0x01, 0x00, 0x00, 0x9a, 0xd5, 0xde, 0xd1, + 0xef, 0xd1, 0x9b, 0x28, 0xc6, 0x03, 0x91, 0x14, + 0x05, 0x04, 0x1c, 0x08, 0x08, 0x30, 0x0e, 0x43, + 0x06, 0x01, 0xa4, 0x04, 0x01, 0x00, 0x01, 0x02, + 0x01, 0x00, 0x0d, 0x01, 0xbc, 0x06, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x01, 0x00, 0xd1, 0xbe, 0xb4, + 0x00, 0x9a, 0xdd, 0x41, 0x29, 0x01, 0x00, 0x00, + 0x9b, 0x28, 0xc6, 0x03, 0x9b, 0x14, 0x01, 0x04, + 0x0e, 0x43, 0x06, 0x01, 0xa6, 0x04, 0x01, 0x00, + 0x01, 0x02, 0x01, 0x00, 0x0d, 0x01, 0xbc, 0x06, + 0x00, 0x01, 0x00, 0xca, 0x03, 0x01, 0x00, 0xd1, + 0xdd, 0x41, 0x29, 0x01, 0x00, 0x00, 0x9a, 0xbe, + 0xb4, 0x00, 0x9b, 0x28, 0xc6, 0x03, 0xa0, 0x14, + 0x01, 0x04, 0x0e, 0x43, 0x06, 0x01, 0xa8, 0x04, + 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x15, 0x02, + 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd4, 0x07, 0x00, + 0x00, 0x00, 0xca, 0x03, 0x01, 0x00, 0xdd, 0x42, + 0x04, 0x01, 0x00, 0x00, 0xdd, 0xd1, 0xef, 0x24, + 0x01, 0x00, 0xcd, 0xb6, 0xc5, 0x9b, 0x9e, 0xbf, + 0x00, 0x9a, 0x28, 0xc6, 0x03, 0xa5, 0x14, 0x02, + 0x04, 0x3f, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x3f, 0x0e, 0x43, 0x06, 0x01, 0xaa, + 0x04, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x15, + 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd4, 0x07, + 0x00, 0x00, 0x00, 0xca, 0x03, 0x01, 0x00, 0xdd, + 0x42, 0x04, 0x01, 0x00, 0x00, 0xdd, 0xd1, 0xef, + 0x24, 0x01, 0x00, 0xcd, 0xb6, 0xc5, 0x9b, 0x9d, + 0xbf, 0x00, 0x9a, 0x28, 0xc6, 0x03, 0xab, 0x14, + 0x02, 0x04, 0x3f, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x3f, 0x0e, 0x43, 0x06, 0x01, + 0xac, 0x04, 0x01, 0x01, 0x01, 0x04, 0x01, 0x00, + 0x16, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, 0xd4, + 0x07, 0x00, 0x00, 0x00, 0xca, 0x03, 0x01, 0x00, + 0xdd, 0x42, 0x04, 0x01, 0x00, 0x00, 0xdd, 0xd1, + 0xef, 0xb7, 0x9a, 0x24, 0x01, 0x00, 0xcd, 0xb6, + 0x9e, 0xc5, 0xb6, 0x9d, 0x9b, 0x28, 0xc6, 0x03, + 0xb1, 0x14, 0x02, 0x04, 0x49, 0x0e, 0x43, 0x06, + 0x01, 0xae, 0x04, 0x01, 0x01, 0x01, 0x04, 0x03, + 0x00, 0x11, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xe6, 0x06, 0x00, 0x00, 0x00, 0xca, 0x03, 0x01, + 0x00, 0x8a, 0x04, 0x21, 0x00, 0x86, 0x04, 0x1f, + 0x00, 0xdd, 0xd1, 0xef, 0xc9, 0xde, 0xdf, 0xc5, + 0xc5, 0x9a, 0xb6, 0x9d, 0xef, 0xc5, 0x9d, 0x23, + 0x01, 0x00, 0xc6, 0x03, 0xb7, 0x14, 0x02, 0x04, + 0x17, 0x0e, 0x43, 0x06, 0x01, 0xb0, 0x04, 0x01, + 0x01, 0x01, 0x04, 0x03, 0x00, 0x11, 0x02, 0xbc, + 0x06, 0x00, 0x01, 0x00, 0xe6, 0x06, 0x00, 0x00, + 0x00, 0xca, 0x03, 0x01, 0x00, 0x8a, 0x04, 0x21, + 0x00, 0x86, 0x04, 0x1f, 0x00, 0xdd, 0xd1, 0xef, + 0xc9, 0xde, 0xdf, 0xc5, 0xc5, 0x9a, 0xb6, 0x9e, + 0xef, 0xc5, 0x9d, 0x23, 0x01, 0x00, 0xc6, 0x03, + 0xbd, 0x14, 0x02, 0x04, 0x17, 0x0e, 0x43, 0x06, + 0x01, 0xb2, 0x04, 0x01, 0x01, 0x01, 0x05, 0x02, + 0x01, 0x11, 0x02, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xe6, 0x06, 0x00, 0x00, 0x00, 0xca, 0x03, 0x01, + 0x00, 0x8a, 0x04, 0x21, 0x00, 0xdd, 0xd1, 0xef, + 0xc9, 0xbf, 0x00, 0xde, 0xb6, 0xc5, 0x9d, 0xb6, + 0xc5, 0x9e, 0x9b, 0xef, 0x9a, 0x28, 0xc6, 0x03, + 0xc3, 0x14, 0x02, 0x04, 0x17, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x0e, 0x43, + 0x06, 0x01, 0xb4, 0x04, 0x01, 0x00, 0x01, 0x04, + 0x02, 0x00, 0x0d, 0x01, 0xe6, 0x06, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x01, 0x00, 0x88, 0x04, 0x20, + 0x00, 0xdd, 0xd1, 0xef, 0xd5, 0xb6, 0xb6, 0xde, + 0xd1, 0x8c, 0xef, 0x9d, 0x9b, 0x28, 0xc6, 0x03, + 0xc9, 0x14, 0x02, 0x04, 0x17, 0x0e, 0x43, 0x06, + 0x01, 0xb6, 0x04, 0x03, 0x00, 0x03, 0x03, 0x00, + 0x00, 0x08, 0x03, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xdc, 0x06, 0x00, + 0x01, 0x00, 0xd1, 0xd2, 0xd1, 0x9e, 0xd3, 0x9a, + 0x9d, 0x28, 0xc6, 0x03, 0xcf, 0x14, 0x01, 0x04, +}; + diff --git a/qjscalc.js b/qjscalc.js index 493869e30..b1ad1e895 100644 --- a/qjscalc.js +++ b/qjscalc.js @@ -2299,8 +2299,13 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio function array_div(a, b) { return array_mul(a, b.inverse()); } - function array_scalar_div(a, b) { - return a * b.inverse(); + function array_element_wise_inverse(a) { + var r, i, n; + n = a.length; + r = []; + for(i = 0; i < n; i++) + r[i] = a[i].inverse(); + return r; } function array_eq(a, b) { var n, i; @@ -2337,14 +2342,14 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series], "*": array_scalar_mul, - "/": array_scalar_div, + "/"(a, b) { return a * b.inverse(); }, "**": generic_pow, /* XXX: only for integer */ }, { left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series], "*"(a, b) { return array_scalar_mul(b, a); }, - "/"(a, b) { return array_scalar_div(b, a); }, + "/"(a, b) { return a * array_element_wise_inverse(b); }, }); add_props(Array.prototype, { @@ -2625,6 +2630,17 @@ function atanh(a) return 0.5 * log((1 + x) / (1 - x)); } +function sigmoid(x) +{ + x = Float(x); + return 1 / (1 + exp(-x)); +} + +function lerp(a, b, t) +{ + return a + (b - a) * t; +} + var idn = Matrix.idn; var diag = Matrix.diag; var trans = Matrix.trans; diff --git a/quickjs-atom.h b/quickjs-atom.h index a353ad442..1a899a46c 100644 --- a/quickjs-atom.h +++ b/quickjs-atom.h @@ -55,6 +55,8 @@ DEF(finally, "finally") DEF(function, "function") DEF(debugger, "debugger") DEF(with, "with") +DEF(__file__, "__FILE__") +DEF(__dir__, "__DIR__") /* FutureReservedWord */ DEF(class, "class") DEF(const, "const") @@ -79,6 +81,7 @@ DEF(await, "await") DEF(empty_string, "") /* identifiers */ DEF(length, "length") +DEF(tag, "tag") DEF(fileName, "fileName") DEF(lineNumber, "lineNumber") DEF(message, "message") @@ -113,6 +116,7 @@ DEF(caller, "caller") DEF(_eval_, "") DEF(_ret_, "") DEF(_var_, "") +DEF(_arg_var_, "") DEF(_with_, "") DEF(lastIndex, "lastIndex") DEF(target, "target") @@ -223,6 +227,9 @@ DEF(BigDecimal, "BigDecimal") DEF(OperatorSet, "OperatorSet") DEF(Operators, "Operators") #endif +#ifdef CONFIG_JSX +DEF(JSX, "JSX") +#endif DEF(Map, "Map") DEF(Set, "Set") /* Map + 1 */ DEF(WeakMap, "WeakMap") /* Map + 2 */ @@ -269,4 +276,7 @@ DEF(Symbol_asyncIterator, "Symbol.asyncIterator") DEF(Symbol_operatorSet, "Symbol.operatorSet") #endif +DEF(Symbol_tag, "Symbol.tag") + + #endif /* DEF */ diff --git a/quickjs-bjson.c b/quickjs-bjson.c new file mode 100644 index 000000000..724210493 --- /dev/null +++ b/quickjs-bjson.c @@ -0,0 +1,124 @@ +/* + * QuickJS: binary JSON module (test only) + * + * Copyright (c) 2017-2019 Fabrice Bellard + * + * 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 "quickjs-libc.h" +#include "cutils.h" + +static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + uint64_t pos = 0, len = 0; + JSValue obj; + JSValue cb = JS_UNINITIALIZED; + size_t size; + int flags; + + if (argc > 1) { + if (JS_IsFunction(ctx, argv[1])) + cb = argv[1]; + else if (JS_ToIndex(ctx, &pos, argv[1])) + return JS_EXCEPTION; + if (argc > 2) { + if (JS_ToIndex(ctx, &len, argv[2])) + return JS_EXCEPTION; + } + } + buf = JS_GetArrayBuffer(ctx, &size, argv[0]); + if (!buf) + return JS_EXCEPTION; + + if (len == 0) + len = size - pos; + + if (pos + len > size) + return JS_ThrowRangeError(ctx, "array buffer overflow"); + flags = 0; + if (argc > 3 && JS_ToBool(ctx, argv[3])) + flags |= JS_READ_OBJ_REFERENCE; + + if (cb != JS_UNINITIALIZED) { + cb = JS_DupValue(ctx,cb); + size_t rest = 0; + uint8_t *sbuf = buf; + uint64_t slen = len; + uint8_t *send = buf + len; + do { + obj = JS_ReadObject2(ctx, sbuf, slen, flags, &rest); + sbuf = send - rest; + slen = rest; + JSValue rv = JS_Call(ctx, cb, JS_UNDEFINED, 1, &obj); + JS_FreeValue(ctx, obj); + if (JS_IsException(rv)) { + JS_FreeValue(ctx, cb); + return rv; + } + if (rv == JS_FALSE) + break; + } while (rest); + JS_FreeValue(ctx, cb); + return JS_NewInt64(ctx, rest); + } + else + obj = JS_ReadObject(ctx, buf + pos, len, flags); + return obj; +} + +static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + size_t len; + uint8_t *buf; + JSValue array; + int flags; + + flags = 0; + if (JS_ToBool(ctx, argv[1])) + flags |= JS_WRITE_OBJ_REFERENCE; + buf = JS_WriteObject(ctx, &len, argv[0], flags); + if (!buf) + return JS_EXCEPTION; + array = JS_NewArrayBufferCopy(ctx, buf, len); + js_free(ctx, buf); + return array; +} + +static const JSCFunctionListEntry js_bjson_funcs[] = { + JS_CFUNC_DEF("read", 4, js_bjson_read), + JS_CFUNC_DEF("write", 2, js_bjson_write), +}; + +static int js_bjson_init(JSContext *ctx, JSModuleDef *m) +{ + return JS_SetModuleExportList(ctx, m, js_bjson_funcs, + countof(js_bjson_funcs)); +} + +JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_bjson_init); + if (!m) return NULL; + JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs)); + return m; +} diff --git a/quickjs-jsx.h b/quickjs-jsx.h new file mode 100644 index 000000000..1a3f1ef49 --- /dev/null +++ b/quickjs-jsx.h @@ -0,0 +1,368 @@ + +/* JSX translates XML literals like this + * + * var jsx =

some text
; + * + * into calls of "JSX driver function": + * + * __jsx__("div", {foo:"bar"}, ["some text"]); + * + * note: + * a) the call always have 3 arguments: string, object|null, array|null + * b) __jsx__ can be redefined, e.g. for https://mithril.js.org it will be just + * + * __jsx__ = m; // using mithril as JSX driver + */ + +static __exception int next_web_token(JSParseState *s) { + s->allow_web_name_token = 1; + int r = next_token(s); + s->allow_web_name_token = 0; + return r; +} + +static int is_non_space_run(const uint8_t* start, const uint8_t* end) { + for (; start < end; ++start) if (!lre_is_space(*start)) break; + for (; end > start; --end) if (!lre_is_space(*(end-1))) break; + return end - start; +} + +static int invalid_name_token(int t) { + //return t != TOK_IDENT && !(t >= TOK_IF && t <= TOK_OF); + return !token_is_ident(t); +} + +static int js_parse_jsx_expr(JSParseState *s, int level) +{ + int atts_count = 0; + int kids_count = 0; + JSAtom tag_atom = JS_ATOM_NULL; + JSValue tag = JS_UNINITIALIZED; + JSAtom attr_name = JS_ATOM_NULL; + JSValue attr_value = JS_UNINITIALIZED; + int token_read = 0; + int is_bodyless = 0; + + const char* errmsg = "invalid JSX expression"; + char msg_buffer[512] = { 0 }; +#if defined(CONFIG_JSX_SCITER) // HTML shortcuts used by Sciter + char class_buffer[512] = { 0 }; +#endif + + // NOTE: caller already consumed '<' + if (next_web_token(s)) goto fail; + if (invalid_name_token(s->token.val)) { + errmsg = "Expecting tag name"; + goto fail; + } + + //tag + tag_atom = JS_DupAtom(s->ctx,s->token.u.ident.atom); + tag = JS_AtomToString(s->ctx,tag_atom); + + // load JSX function - driver of JSX expressions: +#if 1 // load it as a global function + emit_op(s, OP_get_var); + emit_atom(s, JS_ATOM_JSX); +#else // load it as a local/scope function - do we need that? + emit_op(s, OP_scope_get_var); + emit_atom(s, JS_ATOM_JSX); + emit_u16(s, s->cur_func->scope_level); +#endif + + // #0 #1 #2 + // JSX(tag, atts ,kids); where + // - atts - object {...}, can be empty + // - kids - array [...], can be empty + + char buf[ATOM_GET_STR_BUF_SIZE]; + const char* tag_chars = JS_AtomGetStr(s->ctx, buf, countof(buf), tag_atom); + + // check for tag name starting from capital letter + uint32_t res[3] = {0}; + lre_case_conv(res, tag_chars[0], 1); + + if (res[0] != tag_chars[0]) { // tag name starts from upper case. + // ReactJS convention, if tag started from capital letter - it is either class or function + // Fetch it here, so the tag in JSX call can be reference to class(constructor) or a function + emit_op(s, OP_scope_get_var); + emit_atom(s, tag_atom); + emit_u16(s, s->cur_func->scope_level); + } + else { + if (emit_push_const(s, tag, 0)) + goto fail; + } + + // parse attributes + + if (next_web_token(s)) goto fail; + + emit_op(s, OP_object); + + while (s->token.val != '>') { + + if (s->token.val == '/') { + if (next_token(s)) + goto fail; + //json_parse_expect(s, '>'); + if (s->token.val != '>') { + errmsg = "expecting '>'"; + goto fail; + } + //goto GENERATE_KIDS; + is_bodyless = 1; + break; + } +#if defined(CONFIG_JSX_SCITER) // HTML shortcuts used by Sciter + if (s->token.val == '#') { //
->
+ if (next_web_token(s)) goto fail; + if (invalid_name_token(s->token.val)) { + errmsg = "expecting identifier"; + goto fail; + } + attr_name = JS_NewAtom(s->ctx,"id"); + attr_value = JS_AtomToString(s->ctx, s->token.u.ident.atom); + goto PUSH_ATTR_VALUE; + } + if (s->token.val == '|') { // -> + if (next_web_token(s)) goto fail; + if (invalid_name_token(s->token.val)) { + errmsg = "expecting identifier"; + goto fail; + } + attr_name = JS_NewAtom(s->ctx, "type"); + attr_value = JS_AtomToString(s->ctx, s->token.u.ident.atom); + goto PUSH_ATTR_VALUE; + } + if (s->token.val == '(') { // -> + if (next_web_token(s)) goto fail; + if (invalid_name_token(s->token.val)) { + errmsg = "expecting identifier"; + goto fail; + } + attr_name = JS_NewAtom(s->ctx, "name"); + attr_value = JS_AtomToString(s->ctx, s->token.u.ident.atom); + if (next_token(s)) goto fail; + if (s->token.val != ')') { + errmsg = "expecting identifier"; + goto fail; + } + goto PUSH_ATTR_VALUE; + } + if (s->token.val == '.') { // ->
+ if (next_web_token(s)) goto fail; + if (invalid_name_token(s->token.val)) { + errmsg = "expecting identifier"; + goto fail; + } + char cls1[256]; + const char *name = JS_AtomGetStr(s->ctx, cls1, countof(cls1), s->token.u.ident.atom); + if (strlen(class_buffer) + strlen(name) + 2 < countof(class_buffer)) { + if(class_buffer[0]) strcat(class_buffer, " "); + strcat(class_buffer, name); + } + if (next_web_token(s)) goto fail; + continue; + } +#endif + + if (s->token.val == '{') // foo + { + if (next_token(s)) + goto fail; + if (js_parse_assign_expr(s)) + goto fail; + if (s->token.val != '}') { + errmsg = "expecting '}'"; + goto fail; + } + //attr_name = JS_NewAtomUInt32(s->ctx, unnamed_atts_count++); + emit_op(s, OP_null); /* dummy excludeList */ + emit_op(s, OP_copy_data_properties); + emit_u8(s, 2 | (1 << 2) | (0 << 5)); + emit_op(s, OP_drop); /* pop excludeList */ + emit_op(s, OP_drop); /* pop src object */ + + if (next_web_token(s)) + goto fail; + + continue; + } + else if (token_is_ident(s->token.val)) + { + /* keywords and reserved words have a valid atom */ + attr_name = JS_DupAtom(s->ctx, s->token.u.ident.atom); + if (next_token(s)) + goto fail; + } + + if (s->token.val != '=') { + token_read = 1; + attr_value = JS_AtomToString(s->ctx, JS_ATOM_empty_string); + goto PUSH_ATTR_VALUE; + } + else { + token_read = 0; + if (next_token(s)) // eat `=` + goto fail; + } + + if (s->token.val == TOK_STRING) { + attr_value = JS_DupValue(s->ctx, s->token.u.str.str); + PUSH_ATTR_VALUE: + if (emit_push_const(s, attr_value, 0)) + goto fail; + JS_FreeValue(s->ctx, attr_value); + } + else if (s->token.val == TOK_TEMPLATE) { + if (js_parse_template(s, 0, NULL)) + goto fail; + token_read = 1; + } + else if (s->token.val == '{') + { + if (next_token(s)) + goto fail; + if (js_parse_assign_expr(s)) + goto fail; + if (s->token.val != '}') { + errmsg = "expecting '}'"; + goto fail; + } + } + else if(s->token.val == TOK_NUMBER) { + attr_value = JS_DupValue(s->ctx,s->token.u.num.val); + goto PUSH_ATTR_VALUE; + } + else if (s->token.val == TOK_FALSE) { + emit_op(s, OP_push_false); + } + else if (s->token.val == TOK_TRUE) { + emit_op(s, OP_push_true); + } + else if (s->token.val == TOK_NULL) { + emit_op(s, OP_null); + } + else { + errmsg = "bad attribute value"; + goto fail; + } + + set_object_name(s, attr_name); + emit_op(s, OP_define_field); + emit_atom(s, attr_name); + JS_FreeAtom(s->ctx, attr_name); + + if (!token_read) { + if (next_web_token(s)) + goto fail; + } + } + +#if defined(CONFIG_JSX_SCITER) // HTML shortcuts used by Sciter + if (class_buffer[0]) { // add remaining classes + attr_value = JS_NewString(s->ctx, class_buffer); + int r = emit_push_const(s,attr_value, 0); + JS_FreeValue(s->ctx, attr_value); + if (r < 0) goto fail; + attr_name = JS_NewAtom(s->ctx, "class"); + set_object_name(s, attr_name); + emit_op(s, OP_define_field); + emit_atom(s, attr_name); + JS_FreeAtom(s->ctx, attr_name); + } +#endif + + // parse content of the element + + while(!is_bodyless) + { + const uint8_t *p; + p = s->last_ptr = s->buf_ptr; + s->last_line_num = s->token.line_num; + if (js_parse_string(s, '<', TRUE, p, &s->token, &p)) + goto fail; + if (s->buf_ptr != p) { + const uint8_t *start = s->buf_ptr; + s->buf_ptr = p; + if (is_non_space_run(start, p)) { + JSValue str = JS_NewStringLen(s->ctx, start, p - start); + if(str == JS_EXCEPTION) + goto fail; + if (emit_push_const(s,str, 1)) { + JS_FreeValue(s->ctx, str); + goto fail; + } + JS_FreeValue(s->ctx, str); + ++kids_count; + } + } + if (next_token(s)) + goto fail; + + if (s->token.val == '<') { + if (*s->buf_ptr == '/') { + if (next_token(s)) // skip '/' + goto fail; + if (next_web_token(s)) // get tail tag name + goto fail; + if (token_is_ident(s->token.val)) { /* keywords and reserved words have a valid atom */ + if (s->token.u.ident.atom != tag_atom) { + char atail[64]; + char ahead[64]; + snprintf(msg_buffer, countof(msg_buffer), "head <%s> and tail tags do not match", + JS_AtomGetStr(s->ctx, ahead, countof(ahead), tag_atom), + JS_AtomGetStr(s->ctx, atail, countof(atail), s->token.u.ident.atom)); + errmsg = msg_buffer; + goto fail; + } + if (next_token(s)) + goto fail; + if (s->token.val != '>') { + errmsg = "expecting '>' in tail tag"; + goto fail; + } + break; + } + } + else { + js_parse_jsx_expr(s, level + 1); + ++kids_count; + } + } + else if (s->token.val == '{') { + if (next_token(s)) + goto fail; + if (js_parse_assign_expr(s)) + goto fail; + if (s->token.val != '}') { + errmsg = "expected '}'"; + goto fail; + } + ++kids_count; + } + } + +//GENERATE_KIDS: + emit_op(s, OP_array_from); + emit_u16(s, kids_count); + + emit_op(s, OP_call); + emit_u16(s, 3); + + if (level == 0) { + if (next_token(s)) + goto fail; + } + + JS_FreeValue(s->ctx, tag); + JS_FreeAtom(s->ctx, tag_atom); + + return 0; +fail: + JS_FreeValue(s->ctx, tag); + JS_FreeAtom(s->ctx, tag_atom); + return js_parse_error(s, errmsg); +} + diff --git a/quickjs-libc.c b/quickjs-libc.c index 00a7536d7..4e785835d 100644 --- a/quickjs-libc.c +++ b/quickjs-libc.c @@ -28,20 +28,33 @@ #include #include #include -#include #include #include -#include #include #include #include #include -#include #if defined(_WIN32) -#include -#include -#include + #if defined(__MINGW32__) + #include + #endif + #include + #include + #include + #include + #include + #include + #include + #include "win/dirent.h" + #ifndef PATH_MAX + #define PATH_MAX MAX_PATH + #endif + #define popen _popen + #define pclose _pclose #else + #include + #include + #include #include #include #include @@ -453,12 +466,12 @@ typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx, const char *module_name); -#if defined(_WIN32) +#if defined(_MSC_VER) static JSModuleDef *js_module_loader_so(JSContext *ctx, const char *module_name) { JS_ThrowReferenceError(ctx, "shared library modules are not supported yet"); - return NULL; + return NULL; } #else static JSModuleDef *js_module_loader_so(JSContext *ctx, @@ -569,7 +582,7 @@ JSModuleDef *js_module_loader(JSContext *ctx, { JSModuleDef *m; - if (has_suffix(module_name, ".so")) { + if (has_suffix(module_name, NATIVE_MODULE_SUFFIX)) { m = js_module_loader_so(ctx, module_name); } else { size_t buf_len; @@ -623,6 +636,97 @@ static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val, return JS_NewString(ctx, str); } +#if defined(_WIN32) +static void setenv(const char *name, const char *value, int overwrite) +{ + char *str; + size_t name_len, value_len; + name_len = strlen(name); + value_len = strlen(value); + str = malloc(name_len + 1 + value_len + 1); + memcpy(str, name, name_len); + str[name_len] = '='; + memcpy(str + name_len + 1, value, value_len); + str[name_len + 1 + value_len] = '\0'; + _putenv(str); + free(str); +} + +static void unsetenv(const char *name) +{ + setenv(name, "", TRUE); +} +#endif /* _WIN32 */ + +static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *name, *value; + name = JS_ToCString(ctx, argv[0]); + if (!name) + return JS_EXCEPTION; + value = JS_ToCString(ctx, argv[1]); + if (!value) { + JS_FreeCString(ctx, name); + return JS_EXCEPTION; + } + setenv(name, value, TRUE); + JS_FreeCString(ctx, name); + JS_FreeCString(ctx, value); + return JS_UNDEFINED; +} + +static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *name; + name = JS_ToCString(ctx, argv[0]); + if (!name) + return JS_EXCEPTION; + unsetenv(name); + JS_FreeCString(ctx, name); + return JS_UNDEFINED; +} + +/* return an object containing the list of the available environment + variables. */ +static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + char **envp; + const char *name, *p, *value; + JSValue obj; + uint32_t idx; + size_t name_len; + JSAtom atom; + int ret; + + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) + return JS_EXCEPTION; + envp = environ; + for(idx = 0; envp[idx] != NULL; idx++) { + name = envp[idx]; + p = strchr(name, '='); + name_len = p - name; + if (!p) + continue; + value = p + 1; + atom = JS_NewAtomLen(ctx, name, name_len); + if (atom == JS_ATOM_NULL) + goto fail; + ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value), + JS_PROP_C_W_E); + JS_FreeAtom(ctx, atom); + if (ret < 0) + goto fail; + } + return obj; + fail: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -1395,6 +1499,9 @@ static const JSCFunctionListEntry js_std_funcs[] = { JS_CFUNC_DEF("evalScript", 1, js_evalScript ), JS_CFUNC_DEF("loadScript", 1, js_loadScript ), JS_CFUNC_DEF("getenv", 1, js_std_getenv ), + JS_CFUNC_DEF("setenv", 1, js_std_setenv ), + JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ), + JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ), JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ), JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ), JS_CFUNC_DEF("strerror", 1, js_std_strerror ), @@ -1412,7 +1519,6 @@ static const JSCFunctionListEntry js_std_funcs[] = { JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ), JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ), JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE), - /* setenv, ... */ }; static const JSCFunctionListEntry js_std_file_proto_funcs[] = { @@ -1570,7 +1676,7 @@ static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val, int fd; if (JS_ToInt32(ctx, &fd, argv[0])) return JS_EXCEPTION; - return JS_NewBool(ctx, isatty(fd) == 1); + return JS_NewBool(ctx, (isatty(fd) != 0)); } #if defined(_WIN32) @@ -1596,6 +1702,10 @@ static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, return obj; } +/* Windows 10 built-in VT100 emulation */ +#define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 + static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -1605,8 +1715,12 @@ static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, if (JS_ToInt32(ctx, &fd, argv[0])) return JS_EXCEPTION; handle = (HANDLE)_get_osfhandle(fd); - - SetConsoleMode(handle, ENABLE_WINDOW_INPUT); + SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT); + _setmode(fd, _O_BINARY); + if (fd == 0) { + handle = (HANDLE)_get_osfhandle(1); /* corresponding output */ + SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING); + } return JS_UNDEFINED; } #else @@ -1679,7 +1793,19 @@ static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val, filename = JS_ToCString(ctx, argv[0]); if (!filename) return JS_EXCEPTION; - ret = js_get_errno(remove(filename)); +#if defined(_WIN32) + { + struct stat st; + if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode)) { + ret = rmdir(filename); + } else { + ret = unlink(filename); + } + } +#else + ret = remove(filename); +#endif + ret = js_get_errno(ret); JS_FreeCString(ctx, filename); return JS_NewInt32(ctx, ret); } @@ -2439,6 +2565,16 @@ static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val, JS_DefinePropertyValueStr(ctx, obj, "ctime", JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)), JS_PROP_C_W_E); +#elif defined(ANDROID) + JS_DefinePropertyValueStr(ctx, obj, "atime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_atime)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mtime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_mtime)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ctime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_ctime)), + JS_PROP_C_W_E); #else JS_DefinePropertyValueStr(ctx, obj, "atime", JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)), @@ -2495,7 +2631,47 @@ static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val, return JS_NewInt32(ctx, ret); } -#if !defined(_WIN32) +/* sleep(delay_ms) */ +static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int64_t delay; + int ret; + + if (JS_ToInt64(ctx, &delay, argv[0])) + return JS_EXCEPTION; + if (delay < 0) + delay = 0; +#if defined(_WIN32) + { + if (delay > INT32_MAX) + delay = INT32_MAX; + Sleep(delay); + ret = 0; + } +#else + { + struct timespec ts; + + ts.tv_sec = delay / 1000; + ts.tv_nsec = (delay % 1000) * 1000000; + ret = js_get_errno(nanosleep(&ts, NULL)); + } +#endif + return JS_NewInt32(ctx, ret); +} + +#if defined(_WIN32) +static char *realpath(const char *path, char *buf) +{ + if (!_fullpath(buf, path, PATH_MAX)) { + errno = ENOENT; + return NULL; + } else { + return buf; + } +} +#endif /* return [path, errorcode] */ static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val, @@ -2519,6 +2695,7 @@ static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val, return make_string_error(ctx, buf, err); } +#if !defined(_WIN32) static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -2939,7 +3116,7 @@ static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val, } /* sleep(delay_ms) */ -static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val, +/*static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { int64_t delay; @@ -2952,7 +3129,7 @@ static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val, ts.tv_nsec = (delay % 1000) * 1000000; ret = js_get_errno(nanosleep(&ts, NULL)); return JS_NewInt32(ctx, ret); -} +}*/ /* dup(fd) */ static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val, @@ -3505,9 +3682,10 @@ static const JSCFunctionListEntry js_os_funcs[] = { #endif JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ), JS_CFUNC_DEF("utimes", 3, js_os_utimes ), + JS_CFUNC_DEF("sleep", 1, js_os_sleep ), + JS_CFUNC_DEF("realpath", 1, js_os_realpath ), #if !defined(_WIN32) JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ), - JS_CFUNC_DEF("realpath", 1, js_os_realpath ), JS_CFUNC_DEF("symlink", 2, js_os_symlink ), JS_CFUNC_DEF("readlink", 1, js_os_readlink ), JS_CFUNC_DEF("exec", 1, js_os_exec ), @@ -3515,7 +3693,6 @@ static const JSCFunctionListEntry js_os_funcs[] = { OS_FLAG(WNOHANG), JS_CFUNC_DEF("pipe", 0, js_os_pipe ), JS_CFUNC_DEF("kill", 2, js_os_kill ), - JS_CFUNC_DEF("sleep", 1, js_os_sleep ), JS_CFUNC_DEF("dup", 1, js_os_dup ), JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), #endif diff --git a/quickjs-opcode.h b/quickjs-opcode.h index 387363c37..a0919b654 100644 --- a/quickjs-opcode.h +++ b/quickjs-opcode.h @@ -114,7 +114,7 @@ DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */ DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */ DEF( return_async, 1, 1, 0, none) DEF( throw, 1, 1, 0, none) -DEF( throw_var, 6, 0, 0, atom_u8) +DEF( throw_error, 6, 0, 0, atom_u8) DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a @@ -205,16 +205,15 @@ DEF( for_of_start, 1, 1, 3, none) DEF(for_await_of_start, 1, 1, 3, none) DEF( for_in_next, 1, 1, 3, none) DEF( for_of_next, 2, 3, 5, u8) -DEF(for_await_of_next, 1, 3, 4, none) +DEF(iterator_check_object, 1, 1, 1, none) DEF(iterator_get_value_done, 1, 1, 2, none) DEF( iterator_close, 1, 3, 0, none) DEF(iterator_close_return, 1, 4, 4, none) -DEF(async_iterator_close, 1, 3, 2, none) -DEF(async_iterator_next, 1, 4, 4, none) -DEF(async_iterator_get, 2, 4, 5, u8) +DEF( iterator_next, 1, 4, 4, none) +DEF( iterator_call, 2, 4, 5, u8) DEF( initial_yield, 1, 0, 0, none) DEF( yield, 1, 1, 2, none) -DEF( yield_star, 1, 2, 2, none) +DEF( yield_star, 1, 1, 2, none) DEF(async_yield_star, 1, 1, 2, none) DEF( await, 1, 1, 1, none) @@ -261,13 +260,14 @@ DEF(is_undefined_or_null, 1, 1, 1, none) DEF( mul_pow10, 1, 2, 1, none) DEF( math_mod, 1, 2, 1, none) #endif +#ifdef CONFIG_DEBUGGER +DEF(line_num, 5, 0, 0, u32) /* emitted in phase 1 and kept if running under debugger */ +#endif /* must be the last non short and non temporary opcode */ DEF( nop, 1, 0, 0, none) /* temporary opcodes: never emitted in the final bytecode */ -def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */ - def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ @@ -286,7 +286,9 @@ def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phas def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ +#ifndef CONFIG_DEBUGGER def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ +#endif #if SHORT_OPCODES DEF( push_minus1, 1, 0, 1, none_int) diff --git a/quickjs-version.h b/quickjs-version.h new file mode 100644 index 000000000..77be63903 --- /dev/null +++ b/quickjs-version.h @@ -0,0 +1 @@ +#define QUICKJS_VERSION "2021-03-27" \ No newline at end of file diff --git a/quickjs.c b/quickjs.c index efc1d54aa..10daf7939 100644 --- a/quickjs.c +++ b/quickjs.c @@ -1,6 +1,6 @@ /* * QuickJS Javascript Engine - * + * * Copyright (c) 2017-2020 Fabrice Bellard * Copyright (c) 2017-2020 Charlie Gordon * @@ -28,14 +28,20 @@ #include #include #include -#include #include #include #include -#if defined(__APPLE__) +#if defined(_WIN32) +#include +#elif defined(__APPLE__) #include +#include #elif defined(__linux__) #include +#include +#elif defined(__FreeBSD__) +#include +#include #endif #include "cutils.h" @@ -48,7 +54,7 @@ #define OPTIMIZE 1 #define SHORT_OPCODES 1 -#if defined(EMSCRIPTEN) +#if defined(EMSCRIPTEN) || defined(_MSC_VER) #define DIRECT_DISPATCH 0 #else #define DIRECT_DISPATCH 1 @@ -67,11 +73,11 @@ /* define to include Atomics.* operations which depend on the OS threads */ -#if !defined(EMSCRIPTEN) +#if !defined(EMSCRIPTEN) && !defined(_MSC_VER) #define CONFIG_ATOMICS #endif -#if !defined(EMSCRIPTEN) +#if !defined(EMSCRIPTEN) && !defined(_MSC_VER) /* enable stack limitation */ #define CONFIG_STACK_CHECK #endif @@ -194,12 +200,12 @@ typedef enum JSErrorEnum { JS_URI_ERROR, JS_INTERNAL_ERROR, JS_AGGREGATE_ERROR, - + JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */ } JSErrorEnum; #define JS_MAX_LOCAL_VARS 65536 -#define JS_STACK_SIZE_MAX 65536 +#define JS_STACK_SIZE_MAX 65534 #define JS_STRING_LEN_MAX ((1 << 30) - 1) #define __exception __attribute__((warn_unused_result)) @@ -257,7 +263,7 @@ struct JSRuntime { by the garbage collector) */ struct list_head gc_obj_list; /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */ - struct list_head gc_zero_ref_count_list; + struct list_head gc_zero_ref_count_list; struct list_head tmp_obj_list; /* used during GC */ JSGCPhaseEnum gc_phase : 8; size_t malloc_gc_threshold; @@ -265,8 +271,9 @@ struct JSRuntime { struct list_head string_list; /* list of JSString.link */ #endif /* stack limitation */ - const uint8_t *stack_top; - size_t stack_size; /* in bytes */ + uintptr_t stack_size; /* in bytes, 0 if no limit */ + uintptr_t stack_top; + uintptr_t stack_limit; /* lower stack limit */ JSValue current_exception; /* true if inside an out of memory error, to avoid recursing */ @@ -279,7 +286,7 @@ struct JSRuntime { JSHostPromiseRejectionTracker *host_promise_rejection_tracker; void *host_promise_rejection_tracker_opaque; - + struct list_head job_list; /* list of JSJobEntry.link */ JSModuleNormalizeFunc *module_normalize_func; @@ -289,7 +296,7 @@ struct JSRuntime { BOOL can_block : 8; /* TRUE if Atomics.wait can block */ /* used to allocate, free and clone SharedArrayBuffers */ JSSharedArrayBufferFunctions sab_funcs; - + /* Shape hash table */ int shape_hash_bits; int shape_hash_size; @@ -330,8 +337,12 @@ typedef struct JSStackFrame { int arg_count; int js_mode; /* 0 or JS_MODE_MATH for C functions */ /* only used in generators. Current stack pointer value. NULL if - the function is running. */ + the function is running. */ JSValue *cur_sp; +#ifdef CONFIG_DEBUGGER + JSValue* pthis; /* reference to this value, needed by debugger to report 'this' */ +#endif // CONFIG_DEBUGGER + } JSStackFrame; typedef enum { @@ -364,9 +375,9 @@ typedef struct JSVarRef { /* 0 : the JSVarRef is on the stack. header.link is an element of JSStackFrame.var_ref_list. - 1 : the JSVarRef is detached. header.link has the normal meanning + 1 : the JSVarRef is detached. header.link has the normal meanning */ - uint8_t is_detached : 1; + uint8_t is_detached : 1; uint8_t is_arg : 1; uint16_t var_idx; /* index of the corresponding function variable on the stack */ @@ -452,7 +463,12 @@ struct JSContext { /* if NULL, eval is not supported */ JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, - const char *filename, int flags, int scope_idx); + const char *filename, int flags, int scope_idx, int line_no); +#ifdef CONFIG_DEBUGGER + JSDebuggerCheckLineNoF* debugger_check_line_no; + BOOL debugger_enabled; +#endif + void *user_opaque; }; @@ -506,14 +522,17 @@ typedef struct JSClosureVar { uint8_t is_arg : 1; uint8_t is_const : 1; uint8_t is_lexical : 1; - uint8_t var_kind : 3; /* see JSVarKindEnum */ - /* 9 bits available */ + uint8_t var_kind : 4; /* see JSVarKindEnum */ + /* 8 bits available */ uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the parent function. otherwise: index to a closure variable of the parent function */ JSAtom var_name; } JSClosureVar; +#define ARG_SCOPE_INDEX 1 +#define ARG_SCOPE_END (-2) + typedef struct JSVarScope { int parent; /* index into fd->scopes of the enclosing scope */ int first; /* index into fd->vars of the last variable in this scope */ @@ -526,6 +545,7 @@ typedef enum { JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator function declaration */ JS_VAR_CATCH, + JS_VAR_FUNCTION_NAME, /* function expression name */ JS_VAR_PRIVATE_FIELD, JS_VAR_PRIVATE_METHOD, JS_VAR_PRIVATE_GETTER, @@ -533,12 +553,21 @@ typedef enum { JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */ } JSVarKindEnum; +/* XXX: could use a different structure in bytecode functions to save + memory */ typedef struct JSVarDef { JSAtom var_name; - int scope_level; /* index into fd->scopes of this variable lexical scope */ - int scope_next; /* index into fd->vars of the next variable in the - * same or enclosing lexical scope */ - uint8_t is_func_var : 1; /* used for the function self reference */ + /* index into fd->scopes of this variable lexical scope */ + int scope_level; + /* during compilation: + - if scope_level = 0: scope in which the variable is defined + - if scope_level != 0: index into fd->vars of the next + variable in the same or enclosing lexical scope + in a bytecode function: + index into fd->vars of the next + variable in the same or enclosing lexical scope + */ + int scope_next; uint8_t is_const : 1; uint8_t is_lexical : 1; uint8_t is_captured : 1; @@ -548,7 +577,9 @@ typedef struct JSVarDef { JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of the definition of the 'var' variables (they have scope_level = 0) */ - int func_pool_or_scope_idx : 24; /* only used during compilation */ + int func_pool_idx : 24; /* only used during compilation : index in + the constant pool for hoisted function + definition */ } JSVarDef; /* for the encoding of the pc2line table */ @@ -783,7 +814,7 @@ struct JSModuleDef { BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */ /* true if evaluation yielded an exception. It is saved in eval_exception */ - BOOL eval_has_exception : 8; + BOOL eval_has_exception : 8; JSValue eval_exception; JSValue meta_obj; /* for import.meta */ }; @@ -845,17 +876,56 @@ struct JSShape { JSShapeProperty prop[0]; /* prop_size elements */ }; +#ifdef CONFIG_STORAGE + +struct JSStorage; +struct JSPersitentBlock { + struct JSStorage* storage; + uint32_t oid; /* dybase object id */ + JS_PERSISTENT_STATUS status; +}; + +int js_load_persistent_object(JSContext *ctx, JSValueConst obj); +int js_free_persistent_object(JSRuntime *rt, JSValueConst obj); + +#define MARK_MODIFIED_OBJ(p) \ + if (p->persistent) \ + p->persistent->status = JS_PERSISTENT_MODIFIED; + +#define MARK_MODIFIED_VALUE(obj) \ + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { \ + JSObject *p = JS_VALUE_GET_OBJ(obj); \ + MARK_MODIFIED_OBJ(p); \ + } + +#define PRELOAD_PERSISTENT_OBJ(p) \ + if (p->persistent && (p->persistent->status == JS_PERSISTENT_DORMANT)) \ + js_load_persistent_object(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + +#define PRELOAD_PERSISTENT_VALUE(obj) \ + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { \ + JSObject *p = JS_VALUE_GET_OBJ(obj); \ + PRELOAD_PERSISTENT_OBJ(p); \ + } + +#else +#define MARK_MODIFIED_OBJ(p); +#define MARK_MODIFIED_VALUE(obj); +#define PRELOAD_PERSISTENT_OBJ(p); +#define PRELOAD_PERSISTENT_VALUE(p); +#endif // CONFIG_STORAGE + struct JSObject { union { JSGCObjectHeader header; struct { int __gc_ref_count; /* corresponds to header.ref_count */ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ - + uint8_t extensible : 1; uint8_t free_mark : 1; /* only used when freeing objects with cycles */ uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */ - uint8_t fast_array : 1; /* TRUE if u.array is used for get/put */ + uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */ uint8_t is_constructor : 1; /* TRUE if object is a constructor function */ uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */ uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */ @@ -911,7 +981,7 @@ struct JSObject { struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ } u1; union { - JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ + JSValue *values; /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ void *ptr; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */ int8_t *int8_ptr; /* JS_CLASS_INT8_ARRAY */ uint8_t *uint8_ptr; /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */ @@ -930,6 +1000,10 @@ struct JSObject { JSValue object_data; /* for JS_SetObjectData(): 8/16/16 bytes */ } u; /* byte sizes: 40/48/72 */ +#ifdef CONFIG_STORAGE + struct JSPersitentBlock* persistent; /* persistence data, used only for JS_CLASS_OBJECT */ +#endif + }; enum { __JS_ATOM_NULL = JS_ATOM_NULL, @@ -1000,10 +1074,10 @@ static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_o static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, int argc, JSValueConst *argv); static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, - JSValue val); + JSValue val, BOOL is_array_ctor); static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, JSValueConst val, int flags, int scope_idx); -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); +JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); static __maybe_unused void JS_DumpAtoms(JSRuntime *rt); static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p); @@ -1169,7 +1243,7 @@ static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, - const char *filename, int flags, int scope_idx); + const char *filename, int flags, int scope_idx, int line_no); static void js_free_module_def(JSContext *ctx, JSModuleDef *m); static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkFunc *mark_func); @@ -1226,10 +1300,10 @@ static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, JSGCObjectTypeEnum type); static void remove_gc_object(JSGCObjectHeader *h); static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s); -static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); -static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, +static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); +static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); -static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p, +static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag); @@ -1554,9 +1628,9 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops) #if !defined(CONFIG_STACK_CHECK) /* no stack limitation */ -static inline uint8_t *js_get_stack_pointer(void) +static inline uintptr_t js_get_stack_pointer(void) { - return NULL; + return 0; } static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) @@ -1565,16 +1639,16 @@ static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) } #else /* Note: OS and CPU dependent */ -static inline uint8_t *js_get_stack_pointer(void) +static inline uintptr_t js_get_stack_pointer(void) { - return __builtin_frame_address(0); + return (uintptr_t)__builtin_frame_address(0); } static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) { - size_t size; - size = rt->stack_top - js_get_stack_pointer(); - return unlikely((size + alloca_size) > rt->stack_size); + uintptr_t sp; + sp = js_get_stack_pointer() - alloca_size; + return unlikely(sp < rt->stack_limit); } #endif @@ -1610,7 +1684,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) init_list_head(&rt->gc_obj_list); init_list_head(&rt->gc_zero_ref_count_list); rt->gc_phase = JS_GC_PHASE_NONE; - + #ifdef DUMP_LEAKS init_list_head(&rt->string_list); #endif @@ -1634,8 +1708,9 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) if (init_shape_hash(rt)) goto fail; - rt->stack_top = js_get_stack_pointer(); rt->stack_size = JS_DEFAULT_STACK_SIZE; + JS_UpdateStackTop(rt); + rt->current_exception = JS_NULL; return rt; @@ -2186,6 +2261,13 @@ JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id) return JS_DupValue(ctx, ctx->class_proto[class_id]); } +JSValue JS_GetClassName(JSContext *ctx, JSClassID class_id) +{ + JSRuntime *rt = ctx->rt; + assert(class_id < rt->class_count); + return JS_AtomToString(ctx,rt->class_array[class_id].class_name); +} + typedef enum JSFreeModuleEnum { JS_FREE_MODULE_ALL, JS_FREE_MODULE_NOT_RESOLVED, @@ -2259,7 +2341,7 @@ void JS_FreeContext(JSContext *ctx) if (--ctx->header.ref_count > 0) return; assert(ctx->header.ref_count == 0); - + #ifdef DUMP_ATOMS JS_DumpAtoms(ctx->rt); #endif @@ -2323,9 +2405,25 @@ JSRuntime *JS_GetRuntime(JSContext *ctx) return ctx->rt; } +static void update_stack_limit(JSRuntime *rt) +{ + if (rt->stack_size == 0) { + rt->stack_limit = 0; /* no limit */ + } else { + rt->stack_limit = rt->stack_top - rt->stack_size; + } +} + void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size) { rt->stack_size = stack_size; + update_stack_limit(rt); +} + +void JS_UpdateStackTop(JSRuntime *rt) +{ + rt->stack_top = js_get_stack_pointer(); + update_stack_limit(rt); } static inline BOOL is_strict_mode(JSContext *ctx) @@ -2461,25 +2559,25 @@ static __maybe_unused void JS_DumpString(JSRuntime *rt, } printf("%d", p->header.ref_count); sep = (p->header.ref_count == 1) ? '\"' : '\''; - putchar(sep); + printf("%c",sep); for(i = 0; i < p->len; i++) { if (p->is_wide_char) c = p->u.str16[i]; else c = p->u.str8[i]; if (c == sep || c == '\\') { - putchar('\\'); - putchar(c); + printf("%c", '\\'); + printf("%c",c); } else if (c >= ' ' && c <= 126) { - putchar(c); + printf("%c", c); } else if (c == '\n') { - putchar('\\'); - putchar('n'); + printf("%c", '\\'); + printf("%c", 'n'); } else { printf("\\u%04x", c); } } - putchar(sep); + printf("%c", sep); } static __maybe_unused void JS_DumpAtoms(JSRuntime *rt) @@ -2576,7 +2674,7 @@ static int JS_InitAtoms(JSRuntime *rt) return 0; } -static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v) +JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v) { JSAtomStruct *p; @@ -2600,7 +2698,7 @@ JSAtom JS_DupAtom(JSContext *ctx, JSAtom v) return v; } -static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v) +JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v) { JSRuntime *rt; JSAtomStruct *p; @@ -2820,6 +2918,18 @@ static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len, return __JS_NewAtom(rt, p, atom_type); } +JSAtom JS_NewAtomLenRT(JSRuntime *rt, const char *str, int len) +{ + return __JS_NewAtomInit(rt, str, len, JS_ATOM_TYPE_STRING); +} + +JSAtom JS_NewAtomSymbolLenRT(JSRuntime *rt, const char *str, int len) +{ + return __JS_NewAtomInit(rt, str, len, JS_ATOM_TYPE_SYMBOL); +} + + + static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len, int atom_type) { @@ -2994,8 +3104,8 @@ static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr, #define ATOM_GET_STR_BUF_SIZE 64 /* Should only be used for debug. */ -static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, - JSAtom atom) +const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, + JSAtom atom) { if (__JS_AtomIsTaggedInt(atom)) { snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom)); @@ -3043,7 +3153,7 @@ static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, return buf; } -static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom) +const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom) { return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom); } @@ -3087,7 +3197,7 @@ JSValue JS_AtomToString(JSContext *ctx, JSAtom atom) /* return TRUE if the atom is an array index (i.e. 0 <= index <= 2^32-2 and return its value */ -static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) +JS_BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) { if (__JS_AtomIsTaggedInt(atom)) { *pval = __JS_AtomToUInt32(atom); @@ -3110,6 +3220,23 @@ static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom) } } +JS_BOOL JS_AtomIsSymbol(JSContext *ctx,JSAtom atom) +{ + if (__JS_AtomIsTaggedInt(atom)) { + return FALSE; + } + else { + JSRuntime *rt = ctx->rt; + JSAtomStruct *p; + uint32_t val; + + assert(atom < rt->atom_size); + p = rt->atom_array[atom]; + return p->atom_type != JS_ATOM_TYPE_STRING; + } +} + + /* This test must be fast if atom is not a numeric index (e.g. a method name). Return JS_UNDEFINED if not a numeric index. JS_EXCEPTION can also be returned. */ @@ -3295,7 +3422,7 @@ static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1) const char *cstr; char *cstr2; size_t len, len1; - + str = JS_AtomToString(ctx, name); if (JS_IsException(str)) return JS_ATOM_NULL; @@ -3362,6 +3489,8 @@ static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, JSClass *cl, *new_class_array; struct list_head *el; + if (class_id >= (1 << 16)) + return -1; if (class_id < rt->class_count && rt->class_array[class_id].class_id != 0) return -1; @@ -3831,7 +3960,7 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len) uint32_t c; StringBuffer b_s, *b = &b_s; size_t len1; - + p_start = (const uint8_t *)buf; p_end = p_start + buf_len; p = p_start; @@ -4323,7 +4452,7 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, sh->prop_size = prop_size; sh->prop_count = 0; sh->deleted_prop_count = 0; - + /* insert in the hash table */ sh->hash = shape_initial_hash(proto); sh->is_hashed = TRUE; @@ -4483,7 +4612,7 @@ static int compact_properties(JSContext *ctx, JSObject *p) uint32_t new_hash_size, i, j, new_hash_mask, new_size; JSShapeProperty *old_pr, *pr; JSProperty *prop, *new_prop; - + sh = p->shape; assert(!sh->is_hashed); @@ -4505,7 +4634,7 @@ static int compact_properties(JSContext *ctx, JSObject *p) list_del(&old_sh->header.link); memcpy(sh, old_sh, sizeof(JSShape)); list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); - + memset(prop_hash_end(sh) - new_hash_size, 0, sizeof(prop_hash_end(sh)[0]) * new_hash_size); @@ -4534,7 +4663,7 @@ static int compact_properties(JSContext *ctx, JSObject *p) p->shape = sh; js_free(ctx, get_alloc_from_shape(old_sh)); - + /* reduce the size of the object properties */ new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size); if (new_prop) @@ -4661,7 +4790,7 @@ static __maybe_unused void JS_DumpShapes(JSRuntime *rt) struct list_head *el; JSObject *p; JSGCObjectHeader *gp; - + printf("JSShapes: {\n"); printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS"); for(i = 0; i < rt->shape_hash_size; i++) { @@ -4703,6 +4832,9 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas p->first_weak_ref = NULL; p->u.opaque = NULL; p->shape = sh; +#ifdef CONFIG_STORAGE + p->persistent = NULL; +#endif // CONFIG_STORAGE p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size); if (unlikely(!p->prop)) { js_free(ctx, p); @@ -4868,6 +5000,19 @@ static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val) return -1; } +__exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val); + +JS_BOOL JS_IsDate(JSContext *ctx, JSValueConst obj, double* ms_since_1970) { + if (JS_GetClassID(obj, NULL) != JS_CLASS_DATE) + return 0; + double v; + if (JS_ThisTimeValue(ctx, &v, obj)) + return 0; + if (ms_since_1970) + *ms_since_1970 = v; + return 1; +} + JSValue JS_NewObjectClass(JSContext *ctx, int class_id) { return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id); @@ -4989,7 +5134,7 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, JSValue func_obj; JSObject *p; JSAtom name_atom; - + func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION); if (JS_IsException(func_obj)) return func_obj; @@ -5362,6 +5507,11 @@ static void free_object(JSRuntime *rt, JSObject *p) JSShape *sh; JSShapeProperty *pr; +#ifdef CONFIG_STORAGE + if (p->persistent) + js_free_persistent_object(rt, JS_MKPTR(JS_TAG_OBJECT, p)); +#endif + p->free_mark = 1; /* used to tell the object is invalid when freeing cycles */ /* free all the fields */ @@ -5420,7 +5570,7 @@ static void free_zero_refcount(JSRuntime *rt) { struct list_head *el; JSGCObjectHeader *p; - + rt->gc_phase = JS_GC_PHASE_DECREF; for(;;) { el = rt->gc_zero_ref_count_list.next; @@ -5652,7 +5802,7 @@ static void gc_decref(JSRuntime *rt) { struct list_head *el, *el1; JSGCObjectHeader *p; - + init_list_head(&rt->tmp_obj_list); /* decrement the refcount of all the children of all the GC @@ -5699,7 +5849,7 @@ static void gc_scan(JSRuntime *rt) p->mark = 0; /* reset the mark for the next GC call */ mark_children(rt, p, gc_scan_incref_child); } - + /* restore the refcount of the objects to be deleted. */ list_for_each(el, &rt->tmp_obj_list) { p = list_entry(el, JSGCObjectHeader, link); @@ -5745,7 +5895,7 @@ static void gc_free_cycles(JSRuntime *rt) } } rt->gc_phase = JS_GC_PHASE_NONE; - + list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) { p = list_entry(el, JSGCObjectHeader, link); assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || @@ -6157,7 +6307,7 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) #ifdef CONFIG_BIGNUM "BigNum " #endif - CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n", + QUICKJS_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n", (int)sizeof(void *) * 8, (int64_t)(ssize_t)s->malloc_limit); #if 1 if (rt) { @@ -6412,7 +6562,7 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func) JSProperty *pr; JSShapeProperty *prs; JSValueConst val; - + if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT) return NULL; prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name); @@ -6443,7 +6593,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, const char *str1; JSObject *p; BOOL backtrace_barrier; - + js_dbuf_init(ctx, &dbuf); if (filename) { dbuf_printf(&dbuf, " at %s", filename); @@ -6567,7 +6717,7 @@ static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace); } -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...) +JSValue __js_printf_like(2,3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; @@ -6578,7 +6728,7 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx return val; } -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...) +JSValue __js_printf_like(2,3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; @@ -6589,7 +6739,7 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, return val; } -static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...) +static int __js_printf_like(3,4) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...) { va_list ap; @@ -6605,7 +6755,7 @@ static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSCont } /* never use it directly */ -static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) +static JSValue __js_printf_like(3,4) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) { char buf[ATOM_GET_STR_BUF_SIZE]; return JS_ThrowTypeError(ctx, fmt, @@ -6613,7 +6763,7 @@ static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSC } /* never use it directly */ -static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) +static JSValue __js_printf_like(3,4) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...) { char buf[ATOM_GET_STR_BUF_SIZE]; return JS_ThrowSyntaxError(ctx, fmt, @@ -6636,7 +6786,7 @@ static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom) } } -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...) +JSValue __js_printf_like(2,3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; @@ -6647,7 +6797,7 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext * return val; } -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...) +JSValue __js_printf_like(2,3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; @@ -6658,7 +6808,7 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, return val; } -JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...) +JSValue __js_printf_like(2,3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...) { JSValue val; va_list ap; @@ -6710,6 +6860,21 @@ static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name) JS_AtomGetStr(ctx, buf, sizeof(buf), name)); } +static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx, + JSFunctionBytecode *b, + int idx, BOOL is_ref) +{ + JSAtom atom = JS_ATOM_NULL; + if (is_ref) { + atom = b->closure_var[idx].var_name; + } else { + /* not present if the function is stripped and contains no eval() */ + if (b->vardefs) + atom = b->vardefs[b->arg_count + idx].var_name; + } + return JS_ThrowReferenceErrorUninitialized(ctx, atom); +} + static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id) { JSRuntime *rt = ctx->rt; @@ -6857,6 +7022,10 @@ static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) return val; } +JSValue JS_GetPrototypeOfDate(JSContext *ctx) { + return JS_DupValue(ctx, ctx->class_proto[JS_CLASS_DATE]); +} + /* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */ JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj) { @@ -6986,25 +7155,37 @@ int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj) return JS_OrdinaryIsInstanceOf(ctx, val, obj); } -typedef int JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); +/* return the value associated to the autoinit property or an exception */ +typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSAutoInitFunc *js_autoinit_func_table[] = { js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */ js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */ - JS_InstantiateFunctionListItem, /* JS_AUTOINIT_ID_PROP */ + JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */ }; +/* warning: 'prs' is reallocated after it */ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, - JSProperty *pr) + JSProperty *pr, JSShapeProperty *prs) { - int ret; + JSValue val; JSContext *realm; JSAutoInitFunc *func; - + + if (js_shape_prepare_update(ctx, p, &prs)) + return -1; + realm = js_autoinit_get_realm(pr); func = js_autoinit_func_table[js_autoinit_get_id(pr)]; - ret = func(realm, p, prop, pr->u.init.opaque); - return ret; + /* 'func' shall not modify the object properties 'pr' */ + val = func(realm, p, prop, pr->u.init.opaque); + js_autoinit_free(ctx->rt, pr); + prs->flags &= ~JS_PROP_TMASK; + pr->u.value = JS_UNDEFINED; + if (JS_IsException(val)) + return -1; + pr->u.value = val; + return 0; } JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, @@ -7054,6 +7235,8 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, p = JS_VALUE_GET_OBJ(obj); } + PRELOAD_PERSISTENT_OBJ(p); + for(;;) { prs = find_own_property(&pr, p, prop); if (prs) { @@ -7075,7 +7258,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, return JS_DupValue(ctx, val); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry */ - if (JS_AutoInitProperty(ctx, p, prop, pr)) + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) return JS_EXCEPTION; continue; } @@ -7093,7 +7276,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - goto typed_array_oob; + return JS_UNDEFINED; } } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) { @@ -7102,9 +7285,6 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, if (ret != 0) { if (ret < 0) return JS_EXCEPTION; - typed_array_oob: - if (typed_array_is_detached(ctx, p)) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); return JS_UNDEFINED; } } @@ -7259,7 +7439,7 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) JSProperty *pr; JSValue brand; JSAtom brand_atom; - + if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) { JS_ThrowTypeErrorNotAnObject(ctx); return -1; @@ -7281,7 +7461,7 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) brand = JS_DupValue(ctx, pr->u.value); } brand_atom = js_symbol_to_atom(ctx, brand); - + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { JS_ThrowTypeErrorNotAnObject(ctx); JS_FreeAtom(ctx, brand_atom); @@ -7302,7 +7482,7 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) JSShapeProperty *prs; JSProperty *pr; JSValueConst brand; - + /* get the home object of 'func' */ if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) { not_obj: @@ -7324,7 +7504,7 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) /* safety check */ if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL)) goto not_obj; - + /* get the brand array of 'obj' */ if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) goto not_obj; @@ -7337,6 +7517,22 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) return 0; } +static uint32_t js_string_obj_get_length(JSContext *ctx, + JSValueConst obj) +{ + JSObject *p; + JSString *p1; + uint32_t len = 0; + + /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ + p = JS_VALUE_GET_OBJ(obj); + if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) { + p1 = JS_VALUE_GET_STRING(p->u.object_data); + len = p1->len; + } + return len; +} + static int num_keys_cmp(const void *p1, const void *p2, void *opaque) { JSContext *ctx = opaque; @@ -7356,7 +7552,7 @@ static int num_keys_cmp(const void *p1, const void *p2, void *opaque) return 1; } -static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len) +void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len) { uint32_t i; if (tab) { @@ -7379,11 +7575,11 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, JSPropertyEnum *tab_atom, *tab_exotic; JSAtom atom; uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count; - uint32_t num_index, str_index, sym_index, exotic_count; + uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count; BOOL is_enumerable, num_sorted; uint32_t num_key; JSAtomKindEnum kind; - + /* clear pointer for consistency in case of failure */ *ptab = NULL; *plen = 0; @@ -7392,8 +7588,13 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, num_keys_count = 0; str_keys_count = 0; sym_keys_count = 0; + exotic_keys_count = 0; exotic_count = 0; tab_exotic = NULL; + + PRELOAD_PERSISTENT_OBJ(p); + + sh = p->shape; for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { atom = prs->atom; @@ -7425,19 +7626,13 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, if (p->is_exotic) { if (p->fast_array) { - /* the implicit GetOwnProperty raises an exception if the - typed array is detached */ - if ((flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) && - (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) && - typed_array_is_detached(ctx, p) && - typed_array_get_length(ctx, p) != 0) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - return -1; - } if (flags & JS_GPN_STRING_MASK) { num_keys_count += p->u.array.count; } + } else if (p->class_id == JS_CLASS_STRING) { + if (flags & JS_GPN_STRING_MASK) { + num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + } } else { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em && em->get_own_property_names) { @@ -7466,13 +7661,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, tab_exotic[i].is_enumerable = is_enumerable; } if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) { - if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { - num_keys_count++; - } else if (kind == JS_ATOM_KIND_STRING) { - str_keys_count++; - } else { - sym_keys_count++; - } + exotic_keys_count++; } } } @@ -7482,7 +7671,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, /* fill them */ - atom_count = num_keys_count + str_keys_count + sym_keys_count; + atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count; /* avoid allocating 0 bytes */ tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1)); if (!tab_atom) { @@ -7518,12 +7707,19 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, } if (p->is_exotic) { + int len; if (p->fast_array) { if (flags & JS_GPN_STRING_MASK) { - for(i = 0; i < p->u.array.count; i++) { + len = p->u.array.count; + goto add_array_keys; + } + } else if (p->class_id == JS_CLASS_STRING) { + if (flags & JS_GPN_STRING_MASK) { + len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); + add_array_keys: + for(i = 0; i < len; i++) { tab_atom[num_index].atom = __JS_AtomFromUInt32(i); if (tab_atom[num_index].atom == JS_ATOM_NULL) { - js_free_prop_enum(ctx, tab_exotic, exotic_count); js_free_prop_enum(ctx, tab_atom, num_index); return -1; } @@ -7531,31 +7727,24 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, num_index++; } } - } - if (exotic_count > 0) { + } else { + /* Note: exotic keys are not reordered and comes after the object own properties. */ for(i = 0; i < exotic_count; i++) { atom = tab_exotic[i].atom; is_enumerable = tab_exotic[i].is_enumerable; kind = JS_AtomGetKind(ctx, atom); if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && ((flags >> kind) & 1) != 0) { - if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) { - j = num_index++; - num_sorted = FALSE; - } else if (kind == JS_ATOM_KIND_STRING) { - j = str_index++; - } else { - j = sym_index++; - } - tab_atom[j].atom = atom; - tab_atom[j].is_enumerable = is_enumerable; + tab_atom[sym_index].atom = atom; + tab_atom[sym_index].is_enumerable = is_enumerable; + sym_index++; } else { JS_FreeAtom(ctx, atom); } } - } js_free(ctx, tab_exotic); } + } assert(num_index == num_keys_count); assert(str_index == num_keys_count + str_keys_count); @@ -7590,6 +7779,8 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, JSShapeProperty *prs; JSProperty *pr; + PRELOAD_PERSISTENT_OBJ(p); + retry: prs = find_own_property(&pr, p, prop); if (prs) { @@ -7614,7 +7805,7 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, desc->value = JS_DupValue(ctx, val); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry */ - if (JS_AutoInitProperty(ctx, p, prop, pr)) + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) return -1; goto retry; } @@ -7642,10 +7833,8 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, idx = __JS_AtomToUInt32(prop); if (idx < p->u.array.count) { if (desc) { - desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE; - if (p->class_id == JS_CLASS_ARRAY || - p->class_id == JS_CLASS_ARGUMENTS) - desc->flags |= JS_PROP_CONFIGURABLE; + desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | + JS_PROP_CONFIGURABLE; desc->getter = JS_UNDEFINED; desc->setter = JS_UNDEFINED; desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx); @@ -7653,19 +7842,6 @@ static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, return TRUE; } } - if (p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) { - int ret; - ret = JS_AtomIsNumericIndex(ctx, prop); - if (ret != 0) { - if (ret < 0) - return -1; - if (typed_array_is_detached(ctx, p)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - return -1; - } - } - } } else { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em && em->get_own_property) { @@ -7733,6 +7909,7 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); ret = em->has_property(ctx, obj1, prop); JS_FreeValue(ctx, obj1); + if(ret != JS_PROCEED_WITH_DEFAULT) return ret; } } @@ -7748,8 +7925,6 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) if (ret != 0) { if (ret < 0) return -1; - /* the detached array test was done in - JS_GetOwnPropertyInternal() */ return FALSE; } } @@ -8074,7 +8249,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) return -1; goto redo; } else { - return FALSE; /* not configurable */ + return FALSE; } } } else { @@ -8114,15 +8289,19 @@ static int call_setter(JSContext *ctx, JSObject *setter, } /* set the array length and remove the array elements if necessary. */ -static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, int flags) +static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, + int flags) { uint32_t len, idx, cur_len; int i, ret; /* Note: this call can reallocate the properties of 'p' */ - ret = JS_ToArrayLengthFree(ctx, &len, val); + ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE); if (ret) return -1; + /* JS_ToArrayLengthFree() must be done before the read-only test */ + if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE))) + return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length); if (likely(p->fast_array)) { uint32_t old_len = p->u.array.count; @@ -8200,6 +8379,23 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, int flags) return TRUE; } +/* return -1 if exception */ +static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len) +{ + uint32_t new_size; + size_t slack; + JSValue *new_array_prop; + /* XXX: potential arithmetic overflow */ + new_size = max_int(new_len, p->u.array.u1.size * 3 / 2); + new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack); + if (!new_array_prop) + return -1; + new_size += slack / sizeof(*new_array_prop); + p->u.array.u.values = new_array_prop; + p->u.array.u1.size = new_size; + return 0; +} + /* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array = TRUE and p->extensible = TRUE */ static int add_fast_array_element(JSContext *ctx, JSObject *p, @@ -8222,19 +8418,10 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p, } } if (unlikely(new_len > p->u.array.u1.size)) { - uint32_t new_size; - size_t slack; - JSValue *new_array_prop; - /* XXX: potential arithmetic overflow */ - new_size = max_int(new_len, p->u.array.u1.size * 3 / 2); - new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack); - if (!new_array_prop) { + if (expand_fast_array(ctx, p, new_len)) { JS_FreeValue(ctx, val); return -1; } - new_size += slack / sizeof(*new_array_prop); - p->u.array.u.values = new_array_prop; - p->u.array.u1.size = new_size; } p->u.array.u.values[new_len - 1] = val; p->u.array.count = new_len; @@ -8248,22 +8435,24 @@ static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) JS_FreeValue(ctx, desc->value); } -/* generic (and slower) version of JS_SetProperty() for Reflect.set() */ +/* generic (and slower) version of JS_SetProperty() for + * Reflect.set(). 'obj' must be an object. */ static int JS_SetPropertyGeneric(JSContext *ctx, - JSObject *p, JSAtom prop, + JSValueConst obj, JSAtom prop, JSValue val, JSValueConst this_obj, int flags) { int ret; JSPropertyDescriptor desc; + JSValue obj1; + JSObject *p; - while (p != NULL) { + obj1 = JS_DupValue(ctx, obj); + for(;;) { + p = JS_VALUE_GET_OBJ(obj1); if (p->is_exotic) { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em && em->set_property) { - JSValue obj1; - /* set_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); ret = em->set_property(ctx, obj1, prop, val, this_obj, flags); JS_FreeValue(ctx, obj1); @@ -8273,8 +8462,11 @@ static int JS_SetPropertyGeneric(JSContext *ctx, } ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (ret < 0) + if (ret < 0) { + JS_FreeValue(ctx, obj1); + JS_FreeValue(ctx, val); return ret; + } if (ret) { if (desc.flags & JS_PROP_GETSET) { JSObject *setter; @@ -8285,27 +8477,38 @@ static int JS_SetPropertyGeneric(JSContext *ctx, ret = call_setter(ctx, setter, this_obj, val, flags); JS_FreeValue(ctx, desc.getter); JS_FreeValue(ctx, desc.setter); + JS_FreeValue(ctx, obj1); return ret; } else { JS_FreeValue(ctx, desc.value); if (!(desc.flags & JS_PROP_WRITABLE)) { + JS_FreeValue(ctx, obj1); goto read_only_error; } } break; } - p = p->shape->proto; + /* Note: at this point 'obj1' cannot be a proxy. XXX: may have + to check recursion */ + obj1 = JS_GetPrototypeFree(ctx, obj1); + if (JS_IsNull(obj1)) + break; } + JS_FreeValue(ctx, obj1); - if (!JS_IsObject(this_obj)) + if (!JS_IsObject(this_obj)) { + JS_FreeValue(ctx, val); return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object"); + } p = JS_VALUE_GET_OBJ(this_obj); /* modify the property in this_obj if it already exists */ ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (ret < 0) + if (ret < 0) { + JS_FreeValue(ctx, val); return ret; + } if (ret) { if (desc.flags & JS_PROP_GETSET) { JS_FreeValue(ctx, desc.getter); @@ -8374,6 +8577,8 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, } } p = JS_VALUE_GET_OBJ(this_obj); + MARK_MODIFIED_OBJ(p); + retry: prs = find_own_property(&pr, p, prop); if (prs) { @@ -8382,8 +8587,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, /* fast case */ set_value(ctx, &pr->u.value, val); return TRUE; - } else if ((prs->flags & (JS_PROP_LENGTH | JS_PROP_WRITABLE)) == - (JS_PROP_LENGTH | JS_PROP_WRITABLE)) { + } else if (prs->flags & JS_PROP_LENGTH) { assert(p->class_id == JS_CLASS_ARRAY); assert(prop == JS_ATOM_length); return set_array_length(ctx, p, val, flags); @@ -8399,7 +8603,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return TRUE; } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry (potentially useless) */ - if (JS_AutoInitProperty(ctx, p, prop, pr)) { + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) { JS_FreeValue(ctx, val); return -1; } @@ -8437,10 +8641,6 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JS_FreeValue(ctx, val); if (JS_IsException(val)) return -1; - if (typed_array_is_detached(ctx, p1)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - return -1; - } return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); } } @@ -8509,7 +8709,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { /* Instantiate property and retry (potentially useless) */ - if (JS_AutoInitProperty(ctx, p1, prop, pr)) + if (JS_AutoInitProperty(ctx, p1, prop, pr, prs)) return -1; goto retry2; } else if (!(prs->flags & JS_PROP_WRITABLE)) { @@ -8677,13 +8877,8 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) { ta_out_of_bound: - if (typed_array_is_detached(ctx, p)) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - return -1; - } else { return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); } - } p->u.array.u.double_ptr[idx] = d; break; default: @@ -8821,8 +9016,10 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p, const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em) { if (em->define_own_property) { - return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), + int r = em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), prop, val, getter, setter, flags); + if (r != JS_PROCEED_WITH_DEFAULT) + return r; } ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); if (ret < 0) @@ -8967,13 +9164,32 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, redo_prop_update: prs = find_own_property(&pr, p, prop); if (prs) { + /* the range of the Array length property is always tested before */ + if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) { + uint32_t array_length; + if (JS_ToArrayLengthFree(ctx, &array_length, + JS_DupValue(ctx, val), FALSE)) { + return -1; + } + /* this code relies on the fact that Uint32 are never allocated */ + val = (JSValueConst)JS_NewUint32(ctx, array_length); + /* prs may have been modified */ + prs = find_own_property(&pr, p, prop); + assert(prs != NULL); + } /* property already exists */ if (!check_define_prop_flags(prs->flags, flags)) { not_configurable: return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable"); } - retry: + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { + /* Instantiate property and retry */ + if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) + return -1; + goto redo_prop_update; + } + if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) { @@ -8996,14 +9212,6 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, /* convert to getset */ if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { free_var_ref(ctx->rt, pr->u.var_ref); - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* clear property and update */ - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - js_autoinit_free(ctx->rt, pr); - prs->flags &= ~JS_PROP_TMASK; - pr->u.value = JS_UNDEFINED; - goto retry; } else { JS_FreeValue(ctx, pr->u.value); } @@ -9051,39 +9259,17 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, pr->u.value = JS_UNDEFINED; } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { /* Note: JS_PROP_VARREF is always writable */ - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* clear property and update */ - if (js_shape_prepare_update(ctx, p, &prs)) - return -1; - js_autoinit_free(ctx->rt, pr); - prs->flags &= ~JS_PROP_TMASK; - pr->u.value = JS_UNDEFINED; } else { if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 && - (flags & JS_PROP_HAS_VALUE) && - !js_same_value(ctx, val, pr->u.value)) { + (flags & JS_PROP_HAS_VALUE)) { + if (!js_same_value(ctx, val, pr->u.value)) { goto not_configurable; - } - } - if (prs->flags & JS_PROP_LENGTH) { - if (flags & JS_PROP_HAS_VALUE) { - res = set_array_length(ctx, p, JS_DupValue(ctx, val), - flags); } else { - res = TRUE; + return TRUE; } - /* still need to reset the writable flag if needed. - The JS_PROP_LENGTH is reset to have the correct - read-only behavior in JS_SetProperty(). */ - if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == - JS_PROP_HAS_WRITABLE) { - prs = get_shape_prop(p->shape); - if (js_update_property_flags(ctx, p, &prs, - prs->flags & ~(JS_PROP_WRITABLE | JS_PROP_LENGTH))) - return -1; } - return res; - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { + } + if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { if (flags & JS_PROP_HAS_VALUE) { if (p->class_id == JS_CLASS_MODULE_NS) { /* JS_PROP_WRITABLE is always true for variable @@ -9107,9 +9293,27 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, pr->u.value = val1; prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE); } - } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { - /* XXX: should never happen, type was reset above */ - abort(); + } else if (prs->flags & JS_PROP_LENGTH) { + if (flags & JS_PROP_HAS_VALUE) { + /* Note: no JS code is executable because + 'val' is guaranted to be a Uint32 */ + res = set_array_length(ctx, p, JS_DupValue(ctx, val), + flags); + } else { + res = TRUE; + } + /* still need to reset the writable flag if + needed. The JS_PROP_LENGTH is kept because the + Uint32 test is still done if the length + property is read-only. */ + if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == + JS_PROP_HAS_WRITABLE) { + prs = get_shape_prop(p->shape); + if (js_update_property_flags(ctx, p, &prs, + prs->flags & ~JS_PROP_WRITABLE)) + return -1; + } + return res; } else { if (flags & JS_PROP_HAS_VALUE) { JS_FreeValue(ctx, pr->u.value); @@ -9194,9 +9398,9 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, typed_array_oob: return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array"); } - prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE); + prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) || - prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE)) { + prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) { return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags"); } if (flags & JS_PROP_HAS_VALUE) { @@ -9322,7 +9526,7 @@ static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj) JSShapeProperty *prs; JSValueConst val; JSString *p; - + prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name); if (!prs) return FALSE; @@ -9581,9 +9785,8 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, set_value(ctx, &pr->u.value, val); return 0; } - flags = JS_PROP_THROW_STRICT; - if (flag != 2 && is_strict_mode(ctx)) + if (is_strict_mode(ctx)) flags |= JS_PROP_NO_ADD; return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags); } @@ -9596,7 +9799,7 @@ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags) JSValue obj1; JSObject *p; int res; - + obj1 = JS_ToObject(ctx, obj); if (JS_IsException(obj1)) return -1; @@ -9630,6 +9833,23 @@ int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int fl return res; } +BOOL JS_IsFunctionOfThisRealm(JSContext *ctx, JSValueConst val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) + return FALSE; + p = JS_VALUE_GET_OBJ(val); + switch (p->class_id) { + case JS_CLASS_BYTECODE_FUNCTION: + return p->u.func.function_bytecode->realm == ctx; + case JS_CLASS_C_FUNCTION: + return p->u.cfunc.realm == ctx; + default: + return FALSE; + } +} + + BOOL JS_IsFunction(JSContext *ctx, JSValueConst val) { JSObject *p; @@ -9741,6 +9961,16 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id) return p; } +JSClassID JS_GetClassID(JSValueConst obj, void** ppopaque) { + JSObject *p; + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + return 0; + p = JS_VALUE_GET_OBJ(obj); + if(ppopaque) + *ppopaque = p->u.opaque; + return p->class_id; +} + #define HINT_STRING 0 #define HINT_NUMBER 1 #define HINT_NONE 2 @@ -9843,7 +10073,7 @@ static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) p = JS_VALUE_GET_OBJ(obj); return p->is_HTMLDDA; } - + static int JS_ToBoolFree(JSContext *ctx, JSValue val) { uint32_t tag = JS_VALUE_GET_TAG(val); @@ -9945,11 +10175,11 @@ static double js_strtod(const char *p, int radix, BOOL is_float) { double d; int c; - + if (!is_float || radix != 10) { uint64_t n_max, n; int int_exp, is_neg; - + is_neg = 0; if (*p == '-') { is_neg = 1; @@ -9997,7 +10227,7 @@ static double js_strtod(const char *p, int radix, BOOL is_float) /* accept _ between digits as a digit separator */ #define ATOD_ACCEPT_UNDERSCORES (1 << 5) /* allow a suffix to override the type */ -#define ATOD_ACCEPT_SUFFIX (1 << 6) +#define ATOD_ACCEPT_SUFFIX (1 << 6) /* default type */ #define ATOD_TYPE_MASK (3 << 7) #define ATOD_TYPE_FLOAT64 (0 << 7) @@ -10006,7 +10236,7 @@ static double js_strtod(const char *p, int radix, BOOL is_float) #define ATOD_TYPE_BIG_DECIMAL (3 << 7) /* assume bigint mode: floats are parsed as integers if no decimal point nor exponent */ -#define ATOD_MODE_BIGINT (1 << 9) +#define ATOD_MODE_BIGINT (1 << 9) /* accept -0x1 */ #define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10) @@ -10036,7 +10266,7 @@ static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, bf_t *a; int ret; JSValue val; - + val = JS_NewBigFloat(ctx); if (JS_IsException(val)) return val; @@ -10062,7 +10292,7 @@ static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf, bfdec_t *a; int ret; JSValue val; - + val = JS_NewBigDecimal(ctx); if (JS_IsException(val)) return val; @@ -10096,11 +10326,11 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, int i, j, len; BOOL buf_allocated = FALSE; JSValue val; - + /* optional separator between digits */ sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256; has_legacy_octal = FALSE; - + p = str; p_start = p; is_neg = 0; @@ -10164,7 +10394,11 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, } else #endif { +#ifdef _MSC_VER + double d = INFINITY; +#else double d = 1.0 / 0.0; +#endif if (is_neg) d = -d; val = JS_NewFloat64(ctx, d); @@ -10305,7 +10539,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, val = JS_NewFloat64(ctx, d); } #endif - + done: if (buf_allocated) js_free_rt(ctx->rt, buf); @@ -10387,7 +10621,7 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, const char *str; const char *p; size_t len; - + str = JS_ToCStringLen(ctx, &len, val); JS_FreeValue(ctx, val); if (!str) @@ -10918,11 +11152,10 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val) } static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, - JSValue val) + JSValue val, BOOL is_array_ctor) { uint32_t tag, len; - redo: tag = JS_VALUE_GET_TAG(val); switch(tag) { case JS_TAG_INT: @@ -10959,16 +11192,36 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, double d; d = JS_VALUE_GET_FLOAT64(val); len = (uint32_t)d; - if (len != d) { - fail: - JS_ThrowRangeError(ctx, "invalid array length"); + if (len != d) + goto fail; + } else { + uint32_t len1; + + if (is_array_ctor) { + val = JS_ToNumberFree(ctx, val); + if (JS_IsException(val)) + return -1; + /* cannot recurse because val is a number */ + if (JS_ToArrayLengthFree(ctx, &len, val, TRUE)) return -1; - } } else { + /* legacy behavior: must do the conversion twice and compare */ + if (JS_ToUint32(ctx, &len, val)) { + JS_FreeValue(ctx, val); + return -1; + } val = JS_ToNumberFree(ctx, val); if (JS_IsException(val)) return -1; - goto redo; + /* cannot recurse because val is a number */ + if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE)) + return -1; + if (len1 != len) { + fail: + JS_ThrowRangeError(ctx, "invalid array length"); + return -1; + } + } } break; } @@ -11701,7 +11954,7 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) } printf(" }"); } - + if (js_class_has_bytecode(p->class_id)) { JSFunctionBytecode *b = p->u.func.function_bytecode; JSVarRef **var_refs; @@ -11888,6 +12141,39 @@ int JS_IsArray(JSContext *ctx, JSValueConst val) } } +int JS_IsTuple(JSContext *ctx, JSValueConst val) { + /* isArray and has tag property */ + int ret; + ret = JS_IsArray(ctx, val); + if (ret < 0) + return -1; + else if (ret > 0) + return JS_HasProperty(ctx, val, JS_ATOM_tag); + return FALSE; +} + +JSValue JS_GetTupleTag(JSContext *ctx, JSValueConst this_obj) +{ + return JS_GetProperty(ctx, this_obj, JS_ATOM_tag); +} + +/* return -1 if exception (proxy case) or TRUE/FALSE */ +int JS_IsObjectPlain(JSContext *ctx, JSValueConst val) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) { + p = JS_VALUE_GET_OBJ(val); + if (unlikely(p->class_id == JS_CLASS_PROXY)) + return !js_proxy_isArray(ctx, val); + else + return p->class_id == JS_CLASS_OBJECT; + } + else { + return FALSE; + } +} + + static double js_pow(double a, double b) { if (unlikely(!isfinite(b)) && fabs(a) == 1) { @@ -11993,7 +12279,7 @@ static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val) uint32_t tag; JSBigDecimal *p; bfdec_t *r; - + tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_BIG_DECIMAL: @@ -12014,7 +12300,7 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) const char *str, *p; size_t len; int flags; - + str = JS_ToCStringLen(ctx, &len, val); JS_FreeValue(ctx, val); if (!str) @@ -12130,7 +12416,7 @@ static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val) } else { bf_t a_s, *a, *r; int ret; - JSValue res; + JSValue res; res = JS_NewBigInt(ctx); if (JS_IsException(res)) @@ -12232,7 +12518,7 @@ static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, { int64_t v; bf_t *a; - + if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT) return val; /* fail safe */ a = JS_GetBigInt(val); @@ -12360,10 +12646,10 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx, JSOverloadableOperatorEnum ovop; JSObject *p; JSValueConst args[2]; - + if (!ctx->allow_operator_overloading) return 0; - + opset2_obj = JS_UNDEFINED; opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset1_obj)) @@ -12392,7 +12678,7 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx, } ovop = get_ovop_from_opcode(op); - + if (opset1->operator_counter == opset2->operator_counter) { p = opset1->self_ops[ovop]; } else if (opset1->operator_counter > opset2->operator_counter) { @@ -12417,7 +12703,7 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx, } else { new_op1 = JS_DupValue(ctx, op1); } - + if (opset2->is_primitive) { if (is_numeric) { new_op2 = JS_ToNumeric(ctx, op2); @@ -12434,7 +12720,7 @@ static __exception int js_call_binary_op_fallback(JSContext *ctx, /* XXX: could apply JS_ToPrimitive() if primitive type so that the operator function does not get a value object */ - + method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) { args[0] = new_op2; @@ -12545,7 +12831,7 @@ static __exception int js_call_unary_op_fallback(JSContext *ctx, if (!ctx->allow_operator_overloading) return 0; - + opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset1_obj)) goto exception; @@ -12601,7 +12887,7 @@ static int js_unary_arith_bigint(JSContext *ctx, bf_t a_s, *r, *a; int ret, v; JSValue res; - + if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigint argument with unary +"); JS_FreeValue(ctx, op1); @@ -12653,7 +12939,7 @@ static int js_unary_arith_bigfloat(JSContext *ctx, bf_t a_s, *r, *a; int ret, v; JSValue res; - + if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigfloat argument with unary +"); JS_FreeValue(ctx, op1); @@ -12702,7 +12988,7 @@ static int js_unary_arith_bigdecimal(JSContext *ctx, bfdec_t *r, *a; int ret, v; JSValue res; - + if (op == OP_plus && !is_math_mode(ctx)) { JS_ThrowTypeError(ctx, "bigdecimal argument with unary +"); JS_FreeValue(ctx, op1); @@ -12862,7 +13148,7 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) { JSValue op1, val; int ret; - + op1 = sp[-1]; if (JS_IsObject(op1)) { ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not); @@ -12899,7 +13185,7 @@ static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, bf_t a_s, b_s, *r, *a, *b; int ret; JSValue res; - + res = JS_NewBigFloat(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); @@ -12960,7 +13246,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, bf_t a_s, b_s, *r, *a, *b; int ret; JSValue res; - + res = JS_NewBigInt(ctx); if (JS_IsException(res)) goto fail; @@ -13147,7 +13433,7 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, if (JS_IsException(res)) goto fail; r = JS_GetBigDecimal(res); - + a = JS_ToBigDecimal(ctx, op1); if (!a) goto fail; @@ -13574,7 +13860,7 @@ static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op, { bf_t a_s, b_s, *a, *b; int res; - + a = JS_ToBigFloat(ctx, &a_s, op1); if (!a) { JS_FreeValue(ctx, op2); @@ -13636,7 +13922,7 @@ static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, } a = JS_ToBigDecimal(ctx, op1); b = JS_ToBigDecimal(ctx, op2); - + switch(op) { case OP_lt: res = bfdec_cmp_lt(a, b); /* if NaN return false */ @@ -14025,7 +14311,7 @@ static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, bf_t r_s, *r = &r_s; double d; int ret; - + /* always convert to Float64 */ bf_init(ctx->bf_ctx, r); ret = bf_mul_pow_radix(r, a, 10, exponent, @@ -14747,7 +15033,7 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) { JSObject *p; p = JS_VALUE_GET_OBJ(op1); - if (unlikely(p->is_HTMLDDA)) + if (unlikely(p->is_HTMLDDA)) atom = JS_ATOM_undefined; else if (JS_IsFunction(ctx, op1)) atom = JS_ATOM_function; @@ -14895,6 +15181,50 @@ static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv) return val; } +/**/ +JSValue JS_NewFastArray(JSContext *ctx, int argc, JSValueConst *argv) +{ + JSValue val, *tab; + JSProperty *pr; + JSObject *p; + int i; + + val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_ARRAY); + if (JS_IsException(val)) + return val; + p = JS_VALUE_GET_OBJ(val); + + /* add the length field (cannot fail) */ + pr = add_property(ctx, p, JS_ATOM_length, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + pr->u.value = JS_NewInt32(ctx, argc); + + /* initialize the fast array part */ + tab = NULL; + if (argc > 0) { + tab = js_malloc(ctx, sizeof(tab[0]) * argc); + if (!tab) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } + for (i = 0; i < argc; i++) { + tab[i] = JS_DupValue(ctx, argv[i]); + } + } + p->u.array.u.values = tab; + p->u.array.count = argc; + + JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, + JS_DupValue(ctx, ctx->array_proto_values), + JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE); + return val; +} + +BOOL JS_GetFastArray(JSContext *ctx, JSValueConst obj, JSValue **arrpp, uint32_t *countp) { + return js_get_fast_array(ctx, obj, arrpp, countp); +} + + #define GLOBAL_VAR_OFFSET 0x40000000 #define ARGUMENT_VAR_OFFSET 0x20000000 @@ -14976,10 +15306,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst * static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) { - JSObject *p, *p1; + JSObject *p; JSPropertyEnum *tab_atom; int i; - JSValue enum_obj; + JSValue enum_obj, obj1; JSForInIterator *it; uint32_t tag, tab_atom_count; @@ -15008,20 +15338,34 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) return enum_obj; - p = JS_VALUE_GET_OBJ(obj); - /* fast path: assume no enumerable properties in the prototype chain */ - p1 = p->shape->proto; - while (p1 != NULL) { - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p1, - JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) + obj1 = JS_DupValue(ctx, obj); + for(;;) { + obj1 = JS_GetPrototypeFree(ctx, obj1); + if (JS_IsNull(obj1)) + break; + if (JS_IsException(obj1)) goto fail; + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, + JS_VALUE_GET_OBJ(obj1), + JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) { + JS_FreeValue(ctx, obj1); + goto fail; + } js_free_prop_enum(ctx, tab_atom, tab_atom_count); if (tab_atom_count != 0) { + JS_FreeValue(ctx, obj1); goto slow_path; } - p1 = p1->shape->proto; + /* must check for timeout to avoid infinite loop */ + if (js_poll_interrupts(ctx)) { + JS_FreeValue(ctx, obj1); + goto fail; + } } + + p = JS_VALUE_GET_OBJ(obj); + if (p->fast_array) { JSShape *sh; JSShapeProperty *prs; @@ -15031,15 +15375,6 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) if (prs->flags & JS_PROP_ENUMERABLE) goto normal_case; } - /* the implicit GetOwnProperty raises an exception if the - typed array is detached */ - if ((p->class_id >= JS_CLASS_UINT8C_ARRAY && - p->class_id <= JS_CLASS_FLOAT64_ARRAY) && - typed_array_is_detached(ctx, p) && - typed_array_get_length(ctx, p) != 0) { - JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - goto fail; - } /* for fast arrays, we only store the number of elements */ it->is_array = TRUE; it->array_length = p->u.array.count; @@ -15058,17 +15393,30 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) slow_path: /* non enumerable properties hide the enumerables ones in the prototype chain */ - while (p != NULL) { - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, - JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) + obj1 = JS_DupValue(ctx, obj); + for(;;) { + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, + JS_VALUE_GET_OBJ(obj1), + JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { + JS_FreeValue(ctx, obj1); goto fail; + } for(i = 0; i < tab_atom_count; i++) { JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL, (tab_atom[i].is_enumerable ? JS_PROP_ENUMERABLE : 0)); } js_free_prop_enum(ctx, tab_atom, tab_atom_count); - p = p->shape->proto; + obj1 = JS_GetPrototypeFree(ctx, obj1); + if (JS_IsNull(obj1)) + break; + if (JS_IsException(obj1)) + goto fail; + /* must check for timeout to avoid infinite loop */ + if (js_poll_interrupts(ctx)) { + JS_FreeValue(ctx, obj1); + goto fail; + } } return enum_obj; @@ -15349,16 +15697,6 @@ static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) return 0; } -static __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp) -{ - JSValue result; - result = JS_Call(ctx, sp[-2], sp[-3], 0, NULL); - if (JS_IsException(result)) - return -1; - sp[0] = result; - return 0; -} - static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj, BOOL *pdone) { @@ -15460,7 +15798,7 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) int is_array_iterator; JSValue *arrp; uint32_t i, count32, pos; - + if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) { JS_ThrowInternalError(ctx, "invalid index for append"); return -1; @@ -15534,7 +15872,7 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) return -1; } -static __exception int JS_CopyDataProperties(JSContext *ctx, +__exception int JS_CopyDataProperties(JSContext *ctx, JSValueConst target, JSValueConst source, JSValueConst excluded, @@ -15545,7 +15883,9 @@ static __exception int JS_CopyDataProperties(JSContext *ctx, uint32_t i, tab_atom_count; JSObject *p; JSObject *pexcl = NULL; - int ret = 0, flags; + int ret, gpn_flags; + JSPropertyDescriptor desc; + BOOL is_enumerable; if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT) return 0; @@ -15554,37 +15894,57 @@ static __exception int JS_CopyDataProperties(JSContext *ctx, pexcl = JS_VALUE_GET_OBJ(excluded); p = JS_VALUE_GET_OBJ(source); + + gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY; + if (p->is_exotic) { + const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; + /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it + introduces a visible change */ + if (em && em->get_own_property_names) { + gpn_flags &= ~JS_GPN_ENUM_ONLY; + } + } if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, - JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | - JS_GPN_ENUM_ONLY)) + gpn_flags)) return -1; - flags = JS_PROP_C_W_E; - for (i = 0; i < tab_atom_count; i++) { if (pexcl) { ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom); if (ret) { if (ret < 0) - break; - ret = 0; + goto exception; continue; } } - ret = -1; + if (!(gpn_flags & JS_GPN_ENUM_ONLY)) { + /* test if the property is enumerable */ + ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom); + if (ret < 0) + goto exception; + if (!ret) + continue; + is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0; + js_free_desc(ctx, &desc); + if (!is_enumerable) + continue; + } val = JS_GetProperty(ctx, source, tab_atom[i].atom); if (JS_IsException(val)) - break; + goto exception; if (setprop) ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val); else - ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, flags); + ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, + JS_PROP_C_W_E); if (ret < 0) - break; - ret = 0; + goto exception; } js_free_prop_enum(ctx, tab_atom, tab_atom_count); - return ret; + return 0; + exception: + js_free_prop_enum(ctx, tab_atom, tab_atom_count); + return -1; } /* only valid inside C functions */ @@ -15663,7 +16023,7 @@ static JSValue js_closure2(JSContext *ctx, JSValue func_obj, return JS_EXCEPTION; } -static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) +static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) { JSValue obj, this_val; int ret; @@ -15671,15 +16031,17 @@ static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, vo this_val = JS_MKPTR(JS_TAG_OBJECT, p); obj = JS_NewObject(ctx); if (JS_IsException(obj)) - return -1; + return JS_EXCEPTION; set_cycle_flag(ctx, obj); set_cycle_flag(ctx, this_val); ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor, JS_DupValue(ctx, this_val), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (JS_DefinePropertyValue(ctx, this_val, atom, obj, JS_PROP_WRITABLE) < 0 || ret < 0) - return -1; - return 0; + if (ret < 0) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + return obj; } static const uint16_t func_kind_to_class_id[] = { @@ -15908,7 +16270,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, sf->prev_frame = prev_sf; rt->current_stack_frame = sf; ctx = p->u.cfunc.realm; /* change the current realm */ - + #ifdef CONFIG_BIGNUM /* we only propagate the bignum mode as some runtime functions test it */ @@ -16055,6 +16417,16 @@ static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, } } +JS_BOOL JS_AreFunctionsOfSameOrigin(JSContext *ctx, JSValue f1, JSValue f2) { + if (!JS_IsFunction(ctx, f1)) return 0; + if (!JS_IsFunction(ctx, f2)) return 0; + + JSObject *p1 = JS_VALUE_GET_OBJ(f1); + JSObject *p2 = JS_VALUE_GET_OBJ(f2); + + return p1->u.func.function_bytecode == p2->u.func.function_bytecode; /* what about native functions ? */ +} + /* argument of OP_special_object */ typedef enum { OP_SPECIAL_OBJECT_ARGUMENTS, @@ -16086,6 +16458,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSVarRef **var_refs; size_t alloca_size; +#ifdef CONFIG_DEBUGGER + sf->pthis = &this_obj; +#endif + #if !DIRECT_DISPATCH #define SWITCH(pc) switch (opcode = *pc++) #define CASE(op) case op @@ -16096,7 +16472,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, #define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id, #if SHORT_OPCODES #define def(id, size, n_pop, n_push, f) -#else +#else #define def(id, size, n_pop, n_push, f) && case_default, #endif #include "quickjs-opcode.h" @@ -16190,7 +16566,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sf->prev_frame = rt->current_stack_frame; rt->current_stack_frame = sf; ctx = b->realm; /* set the current realm */ - + restart: for(;;) { int call_argc; @@ -16625,7 +17001,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, BREAK; CASE(OP_check_ctor): if (JS_IsUndefined(new_target)) { - JS_ThrowTypeError(caller_ctx, "class constructors must be invoked with 'new'"); + JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'"); goto exception; } BREAK; @@ -16640,16 +17016,17 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JS_FreeValue(ctx, sp[-1]); sp -= 2; BREAK; - + CASE(OP_throw): JS_Throw(ctx, *--sp); goto exception; - CASE(OP_throw_var): + CASE(OP_throw_error): #define JS_THROW_VAR_RO 0 #define JS_THROW_VAR_REDECL 1 #define JS_THROW_VAR_UNINITIALIZED 2 -#define JS_THROW_VAR_DELETE_SUPER 3 +#define JS_THROW_ERROR_DELETE_SUPER 3 +#define JS_THROW_ERROR_ITERATOR_THROW 4 { JSAtom atom; int type; @@ -16665,8 +17042,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (type == JS_THROW_VAR_UNINITIALIZED) JS_ThrowReferenceErrorUninitialized(ctx, atom); else - if (type == JS_THROW_VAR_DELETE_SUPER) + if (type == JS_THROW_ERROR_DELETE_SUPER) JS_ThrowReferenceError(ctx, "unsupported reference to 'super'"); + else + if (type == JS_THROW_ERROR_ITERATOR_THROW) + JS_ThrowTypeError(ctx, "iterator does not have a throw method"); else JS_ThrowInternalError(ctx, "invalid throw var type %d", type); } @@ -16995,7 +17375,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, pc += 2; val = *var_refs[idx]->pvalue; if (unlikely(JS_IsUninitialized(val))) { - JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL); + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); goto exception; } sp[0] = JS_DupValue(ctx, val); @@ -17008,7 +17388,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) { - JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL); + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); goto exception; } set_value(ctx, var_refs[idx]->pvalue, sp[-1]); @@ -17021,7 +17401,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, idx = get_u16(pc); pc += 2; if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) { - JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL); + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE); goto exception; } set_value(ctx, var_refs[idx]->pvalue, sp[-1]); @@ -17042,7 +17422,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL); + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); goto exception; } sp[0] = JS_DupValue(ctx, var_buf[idx]); @@ -17055,7 +17435,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, idx = get_u16(pc); pc += 2; if (unlikely(JS_IsUninitialized(var_buf[idx]))) { - JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL); + JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE); goto exception; } set_value(ctx, &var_buf[idx], sp[-1]); @@ -17294,16 +17674,17 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sp += 1; *sp++ = JS_NewCatchOffset(ctx, 0); BREAK; - CASE(OP_for_await_of_next): - if (js_for_await_of_next(ctx, sp)) - goto exception; - sp += 1; - BREAK; CASE(OP_iterator_get_value_done): if (js_iterator_get_value_done(ctx, sp)) goto exception; sp += 1; BREAK; + CASE(OP_iterator_check_object): + if (unlikely(!JS_IsObject(sp[-1]))) { + JS_ThrowTypeError(ctx, "iterator must return an object"); + goto exception; + } + BREAK; CASE(OP_iterator_close): /* iter_obj next catch_offset -> */ @@ -17340,37 +17721,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } BREAK; - CASE(OP_async_iterator_close): - /* iter_obj next catch_offset -> value flag */ - { - JSValue ret, method; - int ret_flag; - sp--; /* remove the catch offset */ - method = JS_GetProperty(ctx, sp[-2], JS_ATOM_return); - if (JS_IsException(method)) - goto exception; - if (JS_IsUndefined(method) || JS_IsNull(method)) { - ret = JS_UNDEFINED; - ret_flag = TRUE; - } else { - ret = JS_CallFree(ctx, method, sp[-2], 0, NULL); - if (JS_IsException(ret)) - goto exception; - if (!JS_IsObject(ret)) { - JS_FreeValue(ctx, ret); - JS_ThrowTypeErrorNotAnObject(ctx); - goto exception; - } - ret_flag = FALSE; - } - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-1]); - sp[-2] = ret; - sp[-1] = JS_NewBool(ctx, ret_flag); - } - BREAK; - - CASE(OP_async_iterator_next): + CASE(OP_iterator_next): /* stack: iter_obj next catch_offset val */ { JSValue ret; @@ -17383,26 +17734,28 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } BREAK; - CASE(OP_async_iterator_get): + CASE(OP_iterator_call): /* stack: iter_obj next catch_offset val */ { JSValue method, ret; BOOL ret_flag; int flags; flags = *pc++; - /* XXX: use another opcode such as OP_throw_var */ - if (flags == 2) { - JS_ThrowTypeError(ctx, "iterator does not have a throw method"); - goto exception; - } - method = JS_GetProperty(ctx, sp[-4], flags ? JS_ATOM_throw : JS_ATOM_return); + method = JS_GetProperty(ctx, sp[-4], (flags & 1) ? + JS_ATOM_throw : JS_ATOM_return); if (JS_IsException(method)) goto exception; if (JS_IsUndefined(method) || JS_IsNull(method)) { ret_flag = TRUE; } else { + if (flags & 2) { + /* no argument */ + ret = JS_CallFree(ctx, method, sp[-4], + 0, NULL); + } else { ret = JS_CallFree(ctx, method, sp[-4], 1, (JSValueConst *)(sp - 1)); + } if (JS_IsException(ret)) goto exception; JS_FreeValue(ctx, sp[-1]); @@ -17478,7 +17831,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSAtom atom; JSValue val; - + atom = get_u32(pc); pc += 4; val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE); @@ -17487,7 +17840,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, *sp++ = val; } BREAK; - + CASE(OP_get_private_field): { JSValue val; @@ -17640,7 +17993,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { int class_flags; JSAtom atom; - + atom = get_u32(pc); class_flags = pc[4]; pc += 5; @@ -17728,7 +18081,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_put_ref_value): { - int ret; + int ret, flags; + flags = JS_PROP_THROW_STRICT; if (unlikely(JS_IsUndefined(sp[-3]))) { if (is_strict_mode(ctx)) { JSAtom atom = JS_ValueToAtom(ctx, sp[-2]); @@ -17740,8 +18094,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } else { sp[-3] = JS_DupValue(ctx, ctx->global_obj); } + } else { + if (is_strict_mode(ctx)) + flags |= JS_PROP_NO_ADD; } - ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT); + ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags); JS_FreeValue(ctx, sp[-3]); sp -= 3; if (unlikely(ret < 0)) @@ -17760,8 +18117,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = JS_ValueToAtom(ctx, sp[-2]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; - ret = JS_SetPropertyGeneric(ctx, JS_VALUE_GET_OBJ(sp[-3]), - atom, sp[-1], sp[-4], + ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4], JS_PROP_THROW_STRICT); JS_FreeAtom(ctx, atom); JS_FreeValue(ctx, sp[-4]); @@ -18084,8 +18440,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, var_buf[idx] = JS_NewInt32(ctx, val + 1); } else { inc_loc_slow: - if (js_unary_arith_slow(ctx, var_buf + idx + 1, OP_inc)) + /* must duplicate otherwise the variable value may + be destroyed before JS code accesses it */ + op1 = JS_DupValue(ctx, op1); + if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc)) goto exception; + set_value(ctx, &var_buf[idx], op1); } } BREAK; @@ -18105,8 +18465,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, var_buf[idx] = JS_NewInt32(ctx, val - 1); } else { dec_loc_slow: - if (js_unary_arith_slow(ctx, var_buf + idx + 1, OP_dec)) + /* must duplicate otherwise the variable value may + be destroyed before JS code accesses it */ + op1 = JS_DupValue(ctx, op1); + if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec)) goto exception; + set_value(ctx, &var_buf[idx], op1); } } BREAK; @@ -18432,6 +18796,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, set_value(ctx, &sp[-1], val); break; case OP_with_put_var: + /* XXX: check if strict mode */ ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-1]); @@ -18494,6 +18859,17 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_nop): BREAK; + +#ifdef CONFIG_DEBUGGER + CASE(OP_line_num) : { + uint32_t line_num = get_u32(pc); + pc += 4; + if (caller_ctx == ctx && caller_ctx->debugger_check_line_no && b->has_debug && b->debug.filename) { + caller_ctx->debugger_check_line_no(caller_ctx, b->debug.filename, line_num, pc); + } + } + BREAK; +#endif CASE(OP_is_undefined_or_null): if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED || JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) { @@ -18618,7 +18994,7 @@ static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj) { JSObject *p; JSContext *realm; - + if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT) return ctx; p = JS_VALUE_GET_OBJ(func_obj); @@ -18667,7 +19043,7 @@ static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor, { JSValue proto, obj; JSContext *realm; - + if (JS_IsUndefined(ctor)) { proto = JS_DupValue(ctx, ctx->class_proto[class_id]); } else { @@ -18834,7 +19210,7 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) /* close the closure variables. */ close_var_refs(rt, sf); - + if (sf->arg_buf) { /* cannot free the function if it is running */ assert(sf->cur_sp != NULL); @@ -18922,13 +19298,11 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR); JSStackFrame *sf; JSValue ret, func_ret; - JSValueConst iter_args[1]; *pdone = TRUE; if (!s) return JS_ThrowTypeError(ctx, "not a generator"); sf = &s->func_state.frame; - redo: switch(s->state) { default: case JS_GENERATOR_STATE_SUSPENDED_START: @@ -18940,85 +19314,16 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, } break; case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR: - { - int done; - JSValue method, iter_obj; - - iter_obj = sf->cur_sp[-2]; - if (magic == GEN_MAGIC_NEXT) { - method = JS_DupValue(ctx, sf->cur_sp[-1]); - } else { - method = JS_GetProperty(ctx, iter_obj, - magic == GEN_MAGIC_RETURN ? - JS_ATOM_return : JS_ATOM_throw); - if (JS_IsException(method)) - goto iter_exception; - } - if (magic != GEN_MAGIC_NEXT && - (JS_IsUndefined(method) || JS_IsNull(method))) { - /* default action */ - if (magic == GEN_MAGIC_RETURN) { - ret = JS_DupValue(ctx, argv[0]); - goto iter_done; - } else { - if (JS_IteratorClose(ctx, iter_obj, FALSE)) - goto iter_exception; - JS_ThrowTypeError(ctx, "iterator does not have a throw method"); - goto iter_exception; - } - } - ret = JS_IteratorNext2(ctx, iter_obj, method, argc, argv, &done); - JS_FreeValue(ctx, method); - if (JS_IsException(ret)) { - iter_exception: - goto exec_throw; - } - /* if not done, the iterator returns the exact object - returned by 'method' */ - if (done == 2) { - JSValue done_val, value; - done_val = JS_GetProperty(ctx, ret, JS_ATOM_done); - if (JS_IsException(done_val)) { - JS_FreeValue(ctx, ret); - goto iter_exception; - } - done = JS_ToBoolFree(ctx, done_val); - if (done) { - value = JS_GetProperty(ctx, ret, JS_ATOM_value); - JS_FreeValue(ctx, ret); - if (JS_IsException(value)) - goto iter_exception; - ret = value; - goto iter_done; - } else { - *pdone = 2; - } - } else { - if (done) { - /* 'yield *' returns the value associated to done = true */ - iter_done: - JS_FreeValue(ctx, sf->cur_sp[-2]); - JS_FreeValue(ctx, sf->cur_sp[-1]); - sf->cur_sp--; - goto exec_arg; - } else { - *pdone = FALSE; - } - } - break; - } - break; case JS_GENERATOR_STATE_SUSPENDED_YIELD: /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */ ret = JS_DupValue(ctx, argv[0]); - if (magic == GEN_MAGIC_THROW) { + if (magic == GEN_MAGIC_THROW && + s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, ret); - exec_throw: s->func_state.throw_flag = TRUE; } else { - exec_arg: sf->cur_sp[-1] = ret; - sf->cur_sp[0] = JS_NewBool(ctx, (magic == GEN_MAGIC_RETURN)); + sf->cur_sp[0] = JS_NewInt32(ctx, magic); sf->cur_sp++; exec_no_arg: s->func_state.throw_flag = FALSE; @@ -19032,17 +19337,14 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, return func_ret; } if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) { + /* get the returned yield value at the top of the stack */ + ret = sf->cur_sp[-1]; + sf->cur_sp[-1] = JS_UNDEFINED; if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) { - /* 'yield *' */ s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR; - iter_args[0] = JS_UNDEFINED; - argc = 1; - argv = iter_args; - goto redo; + /* return (value, done) object */ + *pdone = 2; } else { - /* get the return the yield value at the top of the stack */ - ret = sf->cur_sp[-1]; - sf->cur_sp[-1] = JS_UNDEFINED; *pdone = FALSE; } } else { @@ -19810,6 +20112,8 @@ enum { TOK_FUNCTION, TOK_DEBUGGER, TOK_WITH, + TOK___FILE__, + TOK___DIR__, /* FutureReservedWord */ TOK_CLASS, TOK_CONST, @@ -19853,15 +20157,15 @@ typedef struct BlockEnv { int has_iterator; } BlockEnv; -typedef struct JSHoistedDef { - int cpool_idx; /* -1 means variable global definition */ - uint8_t force_init : 1; /* initialize to undefined */ +typedef struct JSGlobalVar { + int cpool_idx; /* if >= 0, index in the constant pool for hoisted + function defintion*/ + uint8_t force_init : 1; /* force initialization to undefined */ uint8_t is_lexical : 1; /* global let/const definition */ uint8_t is_const : 1; /* const definition */ - int var_idx; /* function object index if cpool_idx >= 0 */ int scope_level; /* scope of definition */ - JSAtom var_name; /* variable name if cpool_idx < 0 */ -} JSHoistedDef; + JSAtom var_name; /* variable name */ +} JSGlobalVar; typedef struct RelocEntry { struct RelocEntry *next; @@ -19924,6 +20228,7 @@ typedef struct JSFunctionDef { BOOL has_home_object; /* TRUE if the home object is available */ BOOL has_prototype; /* true if a prototype field is necessary */ BOOL has_simple_parameter_list; + BOOL has_parameter_expressions; /* if true, an argument scope is created */ BOOL has_use_strict; /* to reject directive in special cases */ BOOL has_eval_call; /* true if the function contains a call to eval() */ BOOL has_arguments_binding; /* true if the 'arguments' binding is @@ -19951,7 +20256,10 @@ typedef struct JSFunctionDef { int arg_count; /* number of arguments */ int defined_arg_count; int var_object_idx; /* -1 if none */ + int arg_var_object_idx; /* -1 if none (var object for the argument scope) */ int arguments_var_idx; /* -1 if none */ + int arguments_arg_idx; /* argument variable definition in argument scope, + -1 if none */ int func_var_idx; /* variable containing the current function (-1 if none, only used if is_func_expr is true) */ int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */ @@ -19960,23 +20268,24 @@ typedef struct JSFunctionDef { int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */ int home_object_var_idx; BOOL need_home_object; - + int scope_level; /* index into fd->scopes if the current lexical scope */ int scope_first; /* index into vd->vars of first lexically scoped variable */ int scope_size; /* allocated size of fd->scopes array */ int scope_count; /* number of entries used in the fd->scopes array */ JSVarScope *scopes; JSVarScope def_scope_array[4]; + int body_scope; /* scope of the body of the function or eval */ - int hoisted_def_count; - int hoisted_def_size; - JSHoistedDef *hoisted_def; + int global_var_count; + int global_var_size; + JSGlobalVar *global_vars; DynBuf byte_code; int last_opcode_pos; /* -1 if no last opcode */ int last_opcode_line_num; BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */ - + LabelSlot *label_slots; int label_size; /* allocated size for label_slots[] */ int label_count; @@ -20056,6 +20365,9 @@ typedef struct JSParseState { BOOL is_module; /* parsing a module */ BOOL allow_html_comments; BOOL ext_json; /* true if accepting JSON superset */ +#ifdef CONFIG_JSX + BOOL allow_web_name_token; /* HTML and CSS tokens that accept '-' as part of the nmtoken */ +#endif } JSParseState; typedef struct JSOpCode { @@ -20186,12 +20498,12 @@ static void __attribute((unused)) dump_token(JSParseState *s, } } -int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...) +int __js_printf_like(2,3) js_parse_error(JSParseState *s, const char *fmt, ...) { JSContext *ctx = s->ctx; va_list ap; int backtrace_flags; - + va_start(ap, fmt); JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE); va_end(ap); @@ -20301,6 +20613,13 @@ static __exception int js_parse_string(JSParseState *s, int sep, uint32_t c; StringBuffer b_s, *b = &b_s; + int multiline_str = +#ifdef CONFIG_JSX + sep == '`' || sep == '<'; +#else + sep == '`'; +#endif + /* string */ if (string_buffer_init(s->ctx, b, 32)) goto fail; @@ -20314,19 +20633,31 @@ static __exception int js_parse_string(JSParseState *s, int sep, js_parse_error(s, "invalid character in a JSON string"); goto fail; } - if (sep == '`') { + if (multiline_str) { if (c == '\r') { if (p[1] == '\n') p++; c = '\n'; } +#ifdef CONFIG_JSX + if(c == '\n' && sep == '<') + s->line_num++; +#endif /* do not update s->line_num */ } else if (c == '\n' || c == '\r') goto invalid_char; } p++; +#ifdef CONFIG_JSX + if ((c == '{' || c == '<') && sep == '<') { + /* expr start */ + --p; + break; + } else +#endif if (c == sep) - break; + break; + if (c == '$' && *p == '{' && sep == '`') { /* template start or middle part */ p++; @@ -20541,7 +20872,7 @@ static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize, { char *buf, *new_buf; size_t size, new_size; - + buf = *pbuf; size = *psize; if (size >= (SIZE_MAX / 3) * 2) @@ -20571,7 +20902,7 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, char ident_buf[128], *buf; size_t ident_size, ident_pos; JSAtom atom; - + p = *pp; buf = ident_buf; ident_size = sizeof(ident_buf); @@ -20580,7 +20911,7 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, buf[ident_pos++] = '#'; for(;;) { p1 = p; - + if (c < 128) { buf[ident_pos++] = c; } else { @@ -20593,6 +20924,9 @@ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, } else if (c >= 128) { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); } +#ifdef CONFIG_JSX + if (c == '-' && s->allow_web_name_token) {;} else +#endif if (!lre_js_is_ident_next(c)) break; p = p1; @@ -20618,11 +20952,11 @@ static __exception int next_token(JSParseState *s) int c; BOOL ident_has_escape; JSAtom atom; - + if (js_check_stack_overflow(s->ctx->rt, 0)) { return js_parse_error(s, "stack overflow"); } - + free_token(s, &s->token); p = s->last_ptr = s->buf_ptr; @@ -20749,14 +21083,14 @@ static __exception int next_token(JSParseState *s) case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': + case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': + case 'Y': case 'Z': case '_': case '$': /* identifier */ @@ -20795,6 +21129,10 @@ static __exception int next_token(JSParseState *s) } break; case '#': +#ifdef CONFIG_JSX + if (s->allow_web_name_token) goto def_token; +#endif // CONFIG_JSX + /* private name */ { const uint8_t *p1; @@ -20840,7 +21178,7 @@ static __exception int next_token(JSParseState *s) goto parse_number; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': - case '9': + case '9': /* number */ parse_number: { @@ -21098,7 +21436,7 @@ static __exception int next_token(JSParseState *s) case CP_LS: /* XXX: should avoid incrementing line_number, but needed to handle HTML comments */ - goto line_terminator; + goto line_terminator; default: if (lre_is_space(c)) { goto redo; @@ -21133,7 +21471,7 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) char ident_buf[128], *buf; size_t ident_size, ident_pos; JSAtom atom; - + p = *pp; buf = ident_buf; ident_size = sizeof(ident_buf); @@ -21165,11 +21503,11 @@ static __exception int json_next_token(JSParseState *s) const uint8_t *p; int c; JSAtom atom; - + if (js_check_stack_overflow(s->ctx->rt, 0)) { return js_parse_error(s, "stack overflow"); } - + free_token(s, &s->token); p = s->last_ptr = s->buf_ptr; @@ -21279,14 +21617,14 @@ static __exception int json_next_token(JSParseState *s) case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': - case 'y': case 'z': + case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': - case 'Y': case 'Z': + case 'Y': case 'Z': case '_': case '$': /* identifier : only pure ascii characters are accepted */ @@ -21313,7 +21651,7 @@ static __exception int json_next_token(JSParseState *s) goto parse_number; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': - case '9': + case '9': /* number */ parse_number: { @@ -21361,7 +21699,7 @@ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator) { const uint8_t *p; uint32_t c; - + /* skip spaces and comments */ p = *pp; for (;;) { @@ -21475,7 +21813,7 @@ static BOOL js_is_live_code(JSParseState *s) { case OP_return_undef: case OP_return_async: case OP_throw: - case OP_throw_var: + case OP_throw_error: case OP_goto: #if SHORT_OPCODES case OP_goto8: @@ -21592,7 +21930,7 @@ static int emit_goto(JSParseState *s, int opcode, int label) static int cpool_add(JSParseState *s, JSValue val) { JSFunctionDef *fd = s->cur_func; - + if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]), &fd->cpool_size, fd->cpool_count + 1)) return -1; @@ -21647,6 +21985,21 @@ static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) return find_arg(ctx, fd, name); } +/* find a variable declaration in a given scope */ +static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd, + JSAtom name, int scope_level) +{ + int scope_idx; + for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0; + scope_idx = fd->vars[scope_idx].scope_next) { + if (fd->vars[scope_idx].scope_level != scope_level) + break; + if (fd->vars[scope_idx].var_name == name) + return scope_idx; + } + return -1; +} + /* return true if scope == parent_scope or if scope is a child of parent_scope */ static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd, @@ -21668,7 +22021,7 @@ static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd, for(i = 0; i < fd->var_count; i++) { JSVarDef *vd = &fd->vars[i]; if (vd->var_name == name && vd->scope_level == 0) { - if (is_child_scope(ctx, fd, vd->func_pool_or_scope_idx, + if (is_child_scope(ctx, fd, vd->scope_next, scope_level)) return i; } @@ -21677,11 +22030,11 @@ static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd, } -static JSHoistedDef *find_hoisted_def(JSFunctionDef *fd, JSAtom name) +static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name) { int i; - for(i = 0; i < fd->hoisted_def_count; i++) { - JSHoistedDef *hf = &fd->hoisted_def[i]; + for(i = 0; i < fd->global_var_count; i++) { + JSGlobalVar *hf = &fd->global_vars[i]; if (hf->var_name == name) return hf; } @@ -21689,9 +22042,9 @@ static JSHoistedDef *find_hoisted_def(JSFunctionDef *fd, JSAtom name) } -static JSHoistedDef *find_lexical_hoisted_def(JSFunctionDef *fd, JSAtom name) +static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name) { - JSHoistedDef *hf = find_hoisted_def(fd, name); + JSGlobalVar *hf = find_global_var(fd, name); if (hf && hf->is_lexical) return hf; else @@ -21711,7 +22064,7 @@ static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name, } if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) { - if (find_lexical_hoisted_def(fd, name)) + if (find_lexical_global_var(fd, name)) return GLOBAL_VAR_OFFSET; } return -1; @@ -21800,6 +22153,7 @@ static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) vd = &fd->vars[fd->var_count++]; memset(vd, 0, sizeof(*vd)); vd->var_name = JS_DupAtom(ctx, name); + vd->func_pool_idx = -1; return fd->var_count - 1; } @@ -21823,22 +22177,47 @@ static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) int idx = fd->func_var_idx; if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) { fd->func_var_idx = idx; - fd->vars[idx].is_func_var = TRUE; + fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME; if (fd->js_mode & JS_MODE_STRICT) fd->vars[idx].is_const = TRUE; } return idx; } -static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) +static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd) { int idx = fd->arguments_var_idx; - if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) { + if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) { fd->arguments_var_idx = idx; } return idx; } +/* add an argument definition in the argument scope. Only needed when + "eval()" may be called in the argument scope. Return 0 if OK. */ +static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd) +{ + int idx; + if (fd->arguments_arg_idx < 0) { + idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX); + if (idx < 0) { + /* XXX: the scope links are not fully updated. May be an + issue if there are child scopes of the argument + scope */ + idx = add_var(ctx, fd, JS_ATOM_arguments); + if (idx < 0) + return -1; + fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first; + fd->scopes[ARG_SCOPE_INDEX].first = idx; + fd->vars[idx].scope_level = ARG_SCOPE_INDEX; + fd->vars[idx].is_lexical = TRUE; + + fd->arguments_arg_idx = idx; + } + } + return 0; +} + static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) { JSVarDef *vd; @@ -21854,32 +22233,27 @@ static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) vd = &fd->args[fd->arg_count++]; memset(vd, 0, sizeof(*vd)); vd->var_name = JS_DupAtom(ctx, name); + vd->func_pool_idx = -1; return fd->arg_count - 1; } -/* add a Hoisted definition for a function (cpool_idx >= 0) or a - global variable (cpool_idx = -1) */ -static JSHoistedDef *add_hoisted_def(JSContext *ctx, - JSFunctionDef *s, int cpool_idx, - JSAtom name, int var_idx, BOOL is_lexical) +/* add a global variable definition */ +static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s, + JSAtom name) { - JSHoistedDef *hf; + JSGlobalVar *hf; - if (js_resize_array(ctx, (void **)&s->hoisted_def, - sizeof(s->hoisted_def[0]), - &s->hoisted_def_size, s->hoisted_def_count + 1)) + if (js_resize_array(ctx, (void **)&s->global_vars, + sizeof(s->global_vars[0]), + &s->global_var_size, s->global_var_count + 1)) return NULL; - hf = &s->hoisted_def[s->hoisted_def_count++]; - hf->cpool_idx = cpool_idx; - hf->force_init = 0; - hf->is_lexical = is_lexical; + hf = &s->global_vars[s->global_var_count++]; + hf->cpool_idx = -1; + hf->force_init = FALSE; + hf->is_lexical = FALSE; hf->is_const = FALSE; - hf->var_idx = var_idx; hf->scope_level = s->scope_level; - hf->var_name = JS_ATOM_NULL; - if (name != JS_ATOM_NULL) { hf->var_name = JS_DupAtom(ctx, name); - } return hf; } @@ -21924,7 +22298,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, goto redef_lex_error; } } else { - if (fd->scope_level == 1) { + if (fd->scope_level == fd->body_scope) { redef_lex_error: /* redefining a scoped var in the same scope: error */ return js_parse_error(s, "invalid redefinition of lexical identifier"); @@ -21933,7 +22307,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, } if (var_def_type != JS_VAR_DEF_FUNCTION_DECL && var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL && - fd->scope_level == 1 && + fd->scope_level == fd->body_scope && find_arg(ctx, fd, name) >= 0) { /* lexical variable redefines a parameter name */ return js_parse_error(s, "invalid redefinition of parameter name"); @@ -21942,24 +22316,25 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) { return js_parse_error(s, "invalid redefinition of a variable"); } - + if (fd->is_global_var) { - JSHoistedDef *hf; - hf = find_hoisted_def(fd, name); + JSGlobalVar *hf; + hf = find_global_var(fd, name); if (hf && is_child_scope(ctx, fd, hf->scope_level, fd->scope_level)) { return js_parse_error(s, "invalid redefinition of global identifier"); } } - + if (fd->is_eval && (fd->eval_type == JS_EVAL_TYPE_GLOBAL || fd->eval_type == JS_EVAL_TYPE_MODULE) && - fd->scope_level == 1) { - JSHoistedDef *hf; - hf = add_hoisted_def(s->ctx, fd, -1, name, -1, TRUE); + fd->scope_level == fd->body_scope) { + JSGlobalVar *hf; + hf = add_global_var(s->ctx, fd, name); if (!hf) return -1; + hf->is_lexical = TRUE; hf->is_const = (var_def_type == JS_VAR_DEF_CONST); idx = GLOBAL_VAR_OFFSET; } else { @@ -21991,13 +22366,13 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, return js_parse_error(s, "invalid redefinition of lexical identifier"); } if (fd->is_global_var) { - JSHoistedDef *hf; - hf = find_hoisted_def(fd, name); + JSGlobalVar *hf; + hf = find_global_var(fd, name); if (hf && hf->is_lexical && hf->scope_level == fd->scope_level && fd->eval_type == JS_EVAL_TYPE_MODULE) { goto invalid_lexical_redefinition; } - hf = add_hoisted_def(s->ctx, fd, -1, name, -1, FALSE); + hf = add_global_var(s->ctx, fd, name); if (!hf) return -1; idx = GLOBAL_VAR_OFFSET; @@ -22010,7 +22385,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, if (idx >= 0) { if (name == JS_ATOM_arguments && fd->has_arguments_binding) fd->arguments_var_idx = idx; - fd->vars[idx].func_pool_or_scope_idx = fd->scope_level; + fd->vars[idx].scope_next = fd->scope_level; } } break; @@ -22052,8 +22427,9 @@ static __exception int js_parse_function_decl2(JSParseState *s, int function_line_num, JSParseExportEnum export_flag, JSFunctionDef **pfd); -static __exception int js_parse_assign_expr(JSParseState *s, int in_accepted); -static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag); +static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags); +static __exception int js_parse_assign_expr(JSParseState *s); +static __exception int js_parse_unary(JSParseState *s, int parse_flags); static void push_break_entry(JSFunctionDef *fd, BlockEnv *be, JSAtom label_name, int label_break, int label_cont, @@ -22220,7 +22596,7 @@ static int __exception js_parse_property_name(JSParseState *s, BOOL is_non_reserved_ident; JSAtom name; int prop_type; - + prop_type = PROP_TYPE_IDENT; if (allow_method) { if (token_is_pseudo_keyword(s, JS_ATOM_get) @@ -22387,6 +22763,7 @@ static BOOL is_regexp_allowed(int tok) #define SKIP_HAS_SEMI (1 << 0) #define SKIP_HAS_ELLIPSIS (1 << 1) +#define SKIP_HAS_ASSIGNMENT (1 << 2) /* XXX: improve speed with early bailout */ /* XXX: no longer works if regexps are present. Could use previous @@ -22445,7 +22822,7 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_ if (level >= sizeof(state)) goto done; state[level++] = '`'; - } + } break; case TOK_EOF: goto done; @@ -22459,6 +22836,9 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_ bits |= SKIP_HAS_ELLIPSIS; } break; + case '=': + bits |= SKIP_HAS_ASSIGNMENT; + break; case TOK_DIV_ASSIGN: tok_len = 2; @@ -22574,7 +22954,7 @@ static __exception int js_parse_object_literal(JSParseState *s) if (s->token.val == TOK_ELLIPSIS) { if (next_token(s)) return -1; - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; emit_op(s, OP_null); /* dummy excludeList */ emit_op(s, OP_copy_data_properties); @@ -22633,7 +23013,7 @@ static __exception int js_parse_object_literal(JSParseState *s) } else { if (js_parse_expect(s, ':')) goto fail; - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) goto fail; if (name == JS_ATOM_NULL) { set_object_name_computed(s); @@ -22668,10 +23048,30 @@ static __exception int js_parse_object_literal(JSParseState *s) return -1; } -static __exception int js_parse_postfix_expr(JSParseState *s, - BOOL accept_lparen); +/* allow the 'in' binary operator */ +#define PF_IN_ACCEPTED (1 << 0) +/* allow function calls parsing in js_parse_postfix_expr() */ +#define PF_POSTFIX_CALL (1 << 1) +/* allow arrow functions parsing in js_parse_postfix_expr() */ +#define PF_ARROW_FUNC (1 << 2) +/* allow the exponentiation operator in js_parse_unary() */ +#define PF_POW_ALLOWED (1 << 3) +/* forbid the exponentiation operator in js_parse_unary() */ +#define PF_POW_FORBIDDEN (1 << 4) -/* XXX: is there is nicer solution ? */ +#ifdef CONFIG_OBJECT_LITERAL_CALL +#define PF_ACCEPT_LCURLY (1 << 5) +#endif + + +static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags); + +static __exception int js_parse_left_hand_side_expr(JSParseState *s) +{ + return js_parse_postfix_expr(s, PF_POSTFIX_CALL); +} + +/* XXX: could generate specific bytecode */ static __exception int js_parse_class_default_ctor(JSParseState *s, BOOL has_super, JSFunctionDef **pfd) @@ -22681,10 +23081,11 @@ static __exception int js_parse_class_default_ctor(JSParseState *s, int ret, line_num; JSParseFunctionEnum func_type; const uint8_t *saved_buf_end; - + js_parse_get_pos(s, &pos); if (has_super) { - str = "(...a){super(...a);}"; + /* spec change: no argument evaluation */ + str = "(){super(...arguments);}"; func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR; } else { str = "(){}"; @@ -22727,7 +23128,7 @@ static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd, static void emit_class_field_init(JSParseState *s) { int label_next; - + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_class_fields_init); emit_u16(s, s->cur_func->scope_level); @@ -22735,13 +23136,13 @@ static void emit_class_field_init(JSParseState *s) /* no need to call the class field initializer if not defined */ emit_op(s, OP_dup); label_next = emit_goto(s, OP_if_false, -1); - + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_this); emit_u16(s, 0); - + emit_op(s, OP_swap); - + emit_op(s, OP_call_method); emit_u16(s, 0); @@ -22766,29 +23167,29 @@ static __exception int emit_class_init_start(JSParseState *s, ClassFieldsDef *cf) { int label_add_brand; - + cf->fields_init_fd = js_parse_function_class_fields_init(s); if (!cf->fields_init_fd) return -1; s->cur_func = cf->fields_init_fd; - + /* XXX: would be better to add the code only if needed, maybe in a later pass */ emit_op(s, OP_push_false); /* will be patched later */ cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos; label_add_brand = emit_goto(s, OP_if_false, -1); - + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_this); emit_u16(s, 0); - + emit_op(s, OP_scope_get_var); emit_atom(s, JS_ATOM_home_object); emit_u16(s, 0); - + emit_op(s, OP_add_brand); - + emit_label(s, label_add_brand); s->cur_func = s->cur_func->parent; @@ -22805,7 +23206,7 @@ static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf) } /* patch the start of the function to enable the OP_add_brand code */ cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true; - + cf->has_brand = TRUE; } return 0; @@ -22814,11 +23215,11 @@ static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf) static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf) { int cpool_idx; - + s->cur_func = cf->fields_init_fd; emit_op(s, OP_return_undef); s->cur_func = s->cur_func->parent; - + cpool_idx = cpool_add(s, JS_NULL); cf->fields_init_fd->parent_cpool_idx = cpool_idx; emit_op(s, OP_fclosure); @@ -22841,7 +23242,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, const uint8_t *class_start_ptr = s->token.ptr; const uint8_t *start_ptr; ClassFieldsDef class_fields[2]; - + /* classes are parsed and executed in strict mode */ saved_js_mode = fd->js_mode; fd->js_mode |= JS_MODE_STRICT; @@ -22873,8 +23274,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, class_flags = JS_DEFINE_CLASS_HAS_HERITAGE; if (next_token(s)) goto fail; - /* XXX: the grammar only allows LeftHandSideExpression */ - if (js_parse_postfix_expr(s, TRUE)) + if (js_parse_left_hand_side_expr(s)) goto fail; } else { emit_op(s, OP_undefined); @@ -22905,7 +23305,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } else { class_name1 = class_name; } - + emit_op(s, OP_define_class); emit_atom(s, class_name1); emit_u8(s, class_flags); @@ -22917,7 +23317,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, cf->computed_fields_count = 0; cf->has_brand = FALSE; } - + ctor_fd = NULL; while (s->token.val != '}') { if (s->token.val == ';') { @@ -22947,7 +23347,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } is_private = prop_type & PROP_TYPE_PRIVATE; prop_type &= ~PROP_TYPE_PRIVATE; - + if ((name == JS_ATOM_constructor && !is_static && prop_type != PROP_TYPE_IDENT) || (name == JS_ATOM_prototype && is_static) || @@ -22993,7 +23393,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, if (is_set) { JSAtom setter_name; int ret; - + setter_name = get_private_setter_name(ctx, name); if (setter_name == JS_ATOM_NULL) goto fail; @@ -23019,7 +23419,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') { ClassFieldsDef *cf = &class_fields[is_static]; JSAtom field_var_name = JS_ATOM_NULL; - + /* class field */ /* XXX: spec: not consistent with method name checks */ @@ -23027,7 +23427,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, js_parse_error(s, "invalid field name"); goto fail; } - + if (is_private) { if (find_private_class_field(ctx, fd, name, fd->scope_level) >= 0) { @@ -23077,11 +23477,11 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_atom(s, name); emit_u16(s, s->cur_func->scope_level); } - + if (s->token.val == '=') { if (next_token(s)) goto fail; - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) goto fail; } else { emit_op(s, OP_undefined); @@ -23104,7 +23504,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, } else { JSParseFunctionEnum func_type; JSFunctionKindEnum func_kind; - + func_type = JS_PARSE_FUNC_METHOD; func_kind = JS_FUNC_NORMAL; if (prop_type == PROP_TYPE_STAR) { @@ -23196,7 +23596,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, { ClassFieldsDef *cf = &class_fields[0]; int var_idx; - + var_idx = define_var(s, fd, JS_ATOM_class_fields_init, JS_VAR_DEF_CONST); if (var_idx < 0) @@ -23223,7 +23623,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_u16(s, 0); emit_op(s, OP_drop); } - + if (class_name != JS_ATOM_NULL) { /* store the class name in the scoped class name variable (it is independent from the class statement variable @@ -23273,6 +23673,8 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, return -1; } +static BOOL is_label(JSParseState *s); + static __exception int js_parse_array_literal(JSParseState *s) { uint32_t idx; @@ -23282,10 +23684,21 @@ static __exception int js_parse_array_literal(JSParseState *s) return -1; /* small regular arrays are created on the stack */ idx = 0; + + JSValue tag = JS_UNINITIALIZED; + + if (s->token.val == TOK_IDENT && is_label(s)) { + tag = JS_AtomToString(s->ctx, s->token.u.ident.atom); + if (next_token(s)) + return -1; + if (next_token(s)) + return -1; + } + while (s->token.val != ']' && idx < 32) { if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS) break; - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; idx++; /* accept trailing comma */ @@ -23306,7 +23719,7 @@ static __exception int js_parse_array_literal(JSParseState *s) break; need_length = TRUE; if (s->token.val != ',') { - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; emit_op(s, OP_define_field); emit_u32(s, __JS_AtomFromUInt32(idx)); @@ -23341,7 +23754,7 @@ static __exception int js_parse_array_literal(JSParseState *s) if (s->token.val == TOK_ELLIPSIS) { if (next_token(s)) return -1; - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; #if 1 emit_op(s, OP_append); @@ -23373,7 +23786,7 @@ static __exception int js_parse_array_literal(JSParseState *s) } else { need_length = TRUE; if (s->token.val != ',') { - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; /* a idx val */ emit_op(s, OP_define_array_el); @@ -23395,7 +23808,13 @@ static __exception int js_parse_array_literal(JSParseState *s) } else { emit_op(s, OP_drop); /* array length - array */ } -done: + done: + if (!JS_IsUninitialized(tag)) { + emit_push_const(s, tag, 0); + JS_FreeValue(s->ctx, tag); + emit_op(s, OP_define_field); + emit_atom(s, JS_ATOM_tag); + } return js_parse_expect(s, ']'); } @@ -23627,7 +24046,7 @@ static void put_lvalue(JSParseState *s, int opcode, int scope, default: break; } - + switch(opcode) { case OP_scope_get_var: /* val -- */ assert(special == PUT_LVALUE_NOKEEP || @@ -23681,7 +24100,7 @@ static __exception int js_define_var(JSParseState *s, JSAtom name, int tok) { JSFunctionDef *fd = s->cur_func; JSVarDefEnum var_def_type; - + if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) { return js_parse_error(s, "yield is a reserved identifier"); } @@ -23781,6 +24200,8 @@ static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg) return JS_ATOM_NULL; } +/* Return -1 if error, 0 if no initializer, 1 if an initializer is + present at the top level. */ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, int hasval, int has_ellipsis, BOOL allow_initializer) @@ -23789,6 +24210,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, int start_addr, assign_addr; JSAtom prop_name, var_name; int opcode, scope, tok1, skip_bits; + BOOL has_initializer; if (has_ellipsis < 0) { /* pre-parse destructuration target for spread detection */ @@ -23842,7 +24264,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, label_lvalue = -1; depth_lvalue = 0; } else { - if (js_parse_postfix_expr(s, TRUE)) + if (js_parse_left_hand_side_expr(s)) return -1; if (get_lvalue(s, &opcode, &scope, &var_name, @@ -23898,7 +24320,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, emit_op(s, OP_get_field2); emit_u32(s, prop_name); } - if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE)) + if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0) return -1; if (s->token.val == '}') break; @@ -23935,7 +24357,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, if (var_name == JS_ATOM_NULL) goto prop_error; } else { - if (js_parse_postfix_expr(s, TRUE)) + if (js_parse_left_hand_side_expr(s)) goto prop_error; lvalue: if (get_lvalue(s, &opcode, &scope, &var_name, @@ -24033,7 +24455,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, if (next_token(s)) goto var_error; emit_op(s, OP_drop); - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) goto var_error; if (opcode == OP_scope_get_var || opcode == OP_get_ref_value) set_object_name(s, var_name); @@ -24097,7 +24519,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, emit_u8(s, 0); emit_op(s, OP_drop); } - if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE)) + if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0) return -1; } else { var_name = JS_ATOM_NULL; @@ -24110,8 +24532,10 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, goto var_error; opcode = OP_scope_get_var; scope = s->cur_func->scope_level; + label_lvalue = -1; + depth_lvalue = 0; } else { - if (js_parse_postfix_expr(s, TRUE)) + if (js_parse_left_hand_side_expr(s)) return -1; if (get_lvalue(s, &opcode, &scope, &var_name, &label_lvalue, &enum_depth, FALSE, '[')) { @@ -24135,7 +24559,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, if (next_token(s)) goto var_error; emit_op(s, OP_drop); - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) goto var_error; if (opcode == OP_scope_get_var || opcode == OP_get_ref_value) set_object_name(s, var_name); @@ -24170,10 +24594,11 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, emit_label(s, label_parse); if (hasval) emit_op(s, OP_drop); - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; emit_goto(s, OP_goto, label_assign); emit_label(s, label_done); + has_initializer = TRUE; } else { /* normally hasval is true except if js_parse_skip_parens_token() was wrong in the parsing */ @@ -24186,8 +24611,9 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, memset(s->cur_func->byte_code.buf + start_addr, OP_nop, assign_addr - start_addr); s->cur_func->label_slots[label_parse].ref_count--; + has_initializer = FALSE; } - return 0; + return has_initializer; prop_error: JS_FreeAtom(s->ctx, prop_name); @@ -24220,11 +24646,17 @@ static void optional_chain_test(JSParseState *s, int *poptional_chaining_label, emit_label(s, label_next); } -static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen) +#ifdef CONFIG_JSX +#include "quickjs-jsx.h" +#endif + +/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */ +static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) { FuncCallType call_type; int optional_chaining_label; - + BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0; + call_type = FUNC_CALL_NORMAL; switch(s->token.val) { case TOK_NUMBER: @@ -24280,7 +24712,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen if (next_token(s)) return -1; break; - + case TOK_DIV_ASSIGN: s->buf_ptr -= 2; goto parse_regexp; @@ -24321,7 +24753,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen } break; case '(': - if (js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) { + if ((parse_flags & PF_ARROW_FUNC) && + js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) { if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, JS_FUNC_NORMAL, JS_ATOM_NULL, s->token.ptr, s->token.line_num)) @@ -24363,13 +24796,41 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen return -1; emit_op(s, OP_push_true); break; + case TOK___FILE__: + if (next_token(s)) + return -1; + { + JSValue filename = JS_NewString(s->ctx, s->filename); + emit_push_const(s, filename, 0); + JS_FreeValue(s->ctx, filename); + } + break; + case TOK___DIR__: + if (next_token(s)) + return -1; + { + int n = 0; + const char* pc = s->filename; + for (int i = 0; *pc; ++i, ++pc) { + if (*pc == '/') { n = i; } +#ifdef _WIN32 + else if (*pc == '\\') { n = i; } +#endif // _WIN32 + else if (*pc == '?' || *pc == '#') break; + } + JSValue dir = JS_NewStringLen(s->ctx, s->filename, n + 1); + emit_push_const(s, dir, 0); + JS_FreeValue(s->ctx, dir); + } + break; case TOK_IDENT: { JSAtom name; if (s->token.u.ident.is_reserved) { return js_parse_error_reserved_identifier(s); } - if (peek_token(s, TRUE) == TOK_ARROW) { + if ((parse_flags & PF_ARROW_FUNC) && + peek_token(s, TRUE) == TOK_ARROW) { if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, JS_FUNC_NORMAL, JS_ATOM_NULL, s->token.ptr, s->token.line_num)) @@ -24388,10 +24849,11 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen JS_FUNC_ASYNC, JS_ATOM_NULL, source_ptr, source_line_num)) return -1; - } else if ((s->token.val == '(' && + } else if ((parse_flags & PF_ARROW_FUNC) && + ((s->token.val == '(' && js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) || (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved && - peek_token(s, TRUE) == TOK_ARROW)) { + peek_token(s, TRUE) == TOK_ARROW))) { if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW, JS_FUNC_ASYNC, JS_ATOM_NULL, source_ptr, source_line_num)) @@ -24421,7 +24883,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen { int skip_bits; if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') { - if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE)) + if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0) return -1; } else { if (s->token.val == '{') { @@ -24434,6 +24896,12 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen } } break; +#ifdef CONFIG_JSX + case '<': + if (js_parse_jsx_expr(s,0)) + return -1; + break; +#endif case TOK_NEW: if (next_token(s)) return -1; @@ -24450,7 +24918,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen emit_atom(s, JS_ATOM_new_target); emit_u16(s, 0); } else { - if (js_parse_postfix_expr(s, FALSE)) + if (js_parse_postfix_expr(s, 0)) return -1; accept_lparen = TRUE; if (s->token.val != '(') { @@ -24503,7 +24971,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen return -1; if (!accept_lparen) return js_parse_error(s, "invalid use of 'import()'"); - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; if (js_parse_expect(s, ')')) return -1; @@ -24519,7 +24987,10 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen for(;;) { JSFunctionDef *fd = s->cur_func; BOOL has_optional_chain = FALSE; - +#ifdef CONFIG_OBJECT_LITERAL_CALL + BOOL object_literal_call = FALSE; +#endif + if (s->token.val == TOK_QUESTION_MARK_DOT) { /* optional chaining */ if (next_token(s)) @@ -24539,9 +25010,15 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen } call_type = FUNC_CALL_TEMPLATE; goto parse_func_call2; - } else if (s->token.val == '(' && accept_lparen) { + } +#ifdef CONFIG_OBJECT_LITERAL_CALL + else if (s->token.val == '{' && (parse_flags & PF_ACCEPT_LCURLY)) { + object_literal_call = TRUE; + goto parse_func_call2; + } +#endif + else if (s->token.val == '(' && accept_lparen) { int opcode, arg_count, drop_count; - /* function call */ parse_func_call: if (next_token(s)) @@ -24636,11 +25113,15 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen } if (s->token.val == TOK_ELLIPSIS) break; - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; arg_count++; if (s->token.val == ')') - break; + break; +#ifdef CONFIG_OBJECT_LITERAL_CALL + if (object_literal_call) + break; /* foo {bar:1} - "object literal call" */ +#endif /* accept a trailing comma before the ')' */ if (js_parse_expect(s, ',')) return -1; @@ -24656,7 +25137,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen if (s->token.val == TOK_ELLIPSIS) { if (next_token(s)) return -1; - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; #if 1 /* XXX: could pass is_last indicator? */ @@ -24687,7 +25168,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen emit_op(s, OP_nip1); #endif } else { - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; /* array idx val */ emit_op(s, OP_define_array_el); @@ -24789,16 +25270,19 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen } else if (s->token.val == '.') { if (next_token(s)) return -1; + parse_property: if (s->token.val == TOK_PRIVATE_NAME) { /* private class field */ if (get_prev_opcode(fd) == OP_get_super) { return js_parse_error(s, "private class field forbidden after super"); } + if (has_optional_chain) { + optional_chain_test(s, &optional_chaining_label, 1); + } emit_op(s, OP_scope_get_private_field); emit_atom(s, s->token.u.ident.atom); emit_u16(s, s->cur_func->scope_level); } else { - parse_property: if (!token_is_ident(s->token.val)) { return js_parse_error(s, "expecting field name"); } @@ -24857,7 +25341,7 @@ static __exception int js_parse_delete(JSParseState *s) if (next_token(s)) return -1; - if (js_parse_unary(s, -1)) + if (js_parse_unary(s, PF_POW_FORBIDDEN)) return -1; switch(opcode = get_prev_opcode(fd)) { case OP_get_field: @@ -24896,9 +25380,9 @@ static __exception int js_parse_delete(JSParseState *s) case OP_scope_get_private_field: return js_parse_error(s, "cannot delete a private class field"); case OP_get_super_value: - emit_op(s, OP_throw_var); + emit_op(s, OP_throw_error); emit_atom(s, JS_ATOM_NULL); - emit_u8(s, JS_THROW_VAR_DELETE_SUPER); + emit_u8(s, JS_THROW_ERROR_DELETE_SUPER); break; default: ret_true: @@ -24909,7 +25393,8 @@ static __exception int js_parse_delete(JSParseState *s) return 0; } -static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) +/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */ +static __exception int js_parse_unary(JSParseState *s, int parse_flags) { int op; @@ -24922,7 +25407,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) op = s->token.val; if (next_token(s)) return -1; - if (js_parse_unary(s, -1)) + if (js_parse_unary(s, PF_POW_FORBIDDEN)) return -1; switch(op) { case '-': @@ -24944,7 +25429,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) default: abort(); } - exponentiation_flag = 0; + parse_flags = 0; break; case TOK_DEC: case TOK_INC: @@ -24954,7 +25439,6 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) op = s->token.val; if (next_token(s)) return -1; - /* XXX: should parse LeftHandSideExpression */ if (js_parse_unary(s, 0)) return -1; if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op)) @@ -24969,7 +25453,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) JSFunctionDef *fd; if (next_token(s)) return -1; - if (js_parse_unary(s, -1)) + if (js_parse_unary(s, PF_POW_FORBIDDEN)) return -1; /* reference access should not return an exception, so we patch the get_var */ @@ -24978,13 +25462,13 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef; } emit_op(s, OP_typeof); - exponentiation_flag = 0; + parse_flags = 0; } break; case TOK_DELETE: if (js_parse_delete(s)) return -1; - exponentiation_flag = 0; + parse_flags = 0; break; case TOK_AWAIT: if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) @@ -24993,13 +25477,18 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) return js_parse_error(s, "await in default expression"); if (next_token(s)) return -1; - if (js_parse_unary(s, -1)) + if (js_parse_unary(s, PF_POW_FORBIDDEN)) return -1; emit_op(s, OP_await); - exponentiation_flag = 0; + parse_flags = 0; break; default: - if (js_parse_postfix_expr(s, TRUE)) + if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) + | PF_POSTFIX_CALL +#ifdef CONFIG_OBJECT_LITERAL_CALL + | PF_ACCEPT_LCURLY +#endif + )) return -1; if (!s->got_lf && (s->token.val == TOK_DEC || s->token.val == TOK_INC)) { @@ -25012,25 +25501,25 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND, FALSE); if (next_token(s)) - return -1; + return -1; } break; } - if (exponentiation_flag) { + if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) { #ifdef CONFIG_BIGNUM if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) { /* Extended exponentiation syntax rules: we extend the ES7 grammar in order to have more intuitive semantics: -2**2 evaluates to -4. */ if (!(s->cur_func->js_mode & JS_MODE_MATH)) { - if (exponentiation_flag < 0) { + if (parse_flags & PF_POW_FORBIDDEN) { JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'"); return -1; } } if (next_token(s)) return -1; - if (js_parse_unary(s, 1)) + if (js_parse_unary(s, PF_POW_ALLOWED)) return -1; emit_op(s, OP_pow); } @@ -25041,13 +25530,13 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) regarding the precedence of prefix operators and the postifx exponential, ES7 specifies that -2**2 is a syntax error. */ - if (exponentiation_flag < 0) { + if (parse_flags & PF_POW_FORBIDDEN) { JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'"); return -1; } if (next_token(s)) return -1; - if (js_parse_unary(s, 1)) + if (js_parse_unary(s, PF_POW_ALLOWED)) return -1; emit_op(s, OP_pow); } @@ -25056,15 +25545,17 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) return 0; } +/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */ static __exception int js_parse_expr_binary(JSParseState *s, int level, - BOOL in_accepted) + int parse_flags) { int op, opcode; if (level == 0) { - return js_parse_unary(s, 1); + return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) | + PF_POW_ALLOWED); } - if (js_parse_expr_binary(s, level - 1, in_accepted)) + if (js_parse_expr_binary(s, level - 1, parse_flags)) return -1; for(;;) { op = s->token.val; @@ -25134,7 +25625,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, opcode = OP_instanceof; break; case TOK_IN: - if (in_accepted) { + if (parse_flags & PF_IN_ACCEPTED) { opcode = OP_in; } else { return 0; @@ -25194,23 +25685,24 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, } if (next_token(s)) return -1; - if (js_parse_expr_binary(s, level - 1, in_accepted)) + if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC)) return -1; emit_op(s, opcode); } return 0; } +/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */ static __exception int js_parse_logical_and_or(JSParseState *s, int op, - BOOL in_accepted) + int parse_flags) { int label1; if (op == TOK_LAND) { - if (js_parse_expr_binary(s, 8, in_accepted)) + if (js_parse_expr_binary(s, 8, parse_flags)) return -1; } else { - if (js_parse_logical_and_or(s, TOK_LAND, in_accepted)) + if (js_parse_logical_and_or(s, TOK_LAND, parse_flags)) return -1; } if (s->token.val == op) { @@ -25224,10 +25716,11 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op, emit_op(s, OP_drop); if (op == TOK_LAND) { - if (js_parse_expr_binary(s, 8, in_accepted)) + if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC)) return -1; } else { - if (js_parse_logical_and_or(s, TOK_LAND, in_accepted)) + if (js_parse_logical_and_or(s, TOK_LAND, + parse_flags & ~PF_ARROW_FUNC)) return -1; } if (s->token.val != op) { @@ -25242,24 +25735,24 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op, return 0; } -static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted) +static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags) { int label1; - - if (js_parse_logical_and_or(s, TOK_LOR, in_accepted)) + + if (js_parse_logical_and_or(s, TOK_LOR, parse_flags)) return -1; if (s->token.val == TOK_DOUBLE_QUESTION_MARK) { label1 = new_label(s); for(;;) { if (next_token(s)) return -1; - + emit_op(s, OP_dup); emit_op(s, OP_is_undefined_or_null); emit_goto(s, OP_if_false, label1); emit_op(s, OP_drop); - - if (js_parse_expr_binary(s, 8, in_accepted)) + + if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC)) return -1; if (s->token.val != TOK_DOUBLE_QUESTION_MARK) break; @@ -25269,18 +25762,19 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted) return 0; } -static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted) +/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */ +static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags) { int label1, label2; - if (js_parse_coalesce_expr(s, in_accepted)) + if (js_parse_coalesce_expr(s, parse_flags)) return -1; if (s->token.val == '?') { if (next_token(s)) return -1; label1 = emit_goto(s, OP_if_false, -1); - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; if (js_parse_expect(s, ':')) return -1; @@ -25289,7 +25783,7 @@ static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted) emit_label(s, label1); - if (js_parse_assign_expr(s, in_accepted)) + if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED)) return -1; emit_label(s, label2); @@ -25299,14 +25793,16 @@ static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted) static void emit_return(JSParseState *s, BOOL hasval); -static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) +/* allowed parse_flags: PF_IN_ACCEPTED */ +static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) { int opcode, op, scope; JSAtom name0 = JS_ATOM_NULL; JSAtom name; if (s->token.val == TOK_YIELD) { - BOOL is_star = FALSE; + BOOL is_star = FALSE, is_async; + if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR)) return js_parse_error(s, "unexpected 'yield' keyword"); if (!s->cur_func->in_function_body) @@ -25323,21 +25819,22 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) if (next_token(s)) return -1; } - if (js_parse_assign_expr(s, in_accepted)) + if (js_parse_assign_expr2(s, parse_flags)) return -1; } else { emit_op(s, OP_undefined); } - if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { + is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR); + + if (is_star) { int label_loop, label_return, label_next; int label_return1, label_yield, label_throw, label_throw1; int label_throw2; - if (is_star) { label_loop = new_label(s); label_yield = new_label(s); - emit_op(s, OP_for_await_of_start); + emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start); /* remove the catch offset (XXX: could avoid pushing back undefined) */ @@ -25347,13 +25844,24 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) emit_op(s, OP_undefined); /* initial value */ emit_label(s, label_loop); - emit_op(s, OP_async_iterator_next); + emit_op(s, OP_iterator_next); + if (is_async) emit_op(s, OP_await); - emit_op(s, OP_iterator_get_value_done); + emit_op(s, OP_iterator_check_object); + emit_op(s, OP_get_field2); + emit_atom(s, JS_ATOM_done); label_next = emit_goto(s, OP_if_true, -1); /* end of loop */ - emit_op(s, OP_await); emit_label(s, label_yield); + if (is_async) { + /* OP_async_yield_star takes the value as parameter */ + emit_op(s, OP_get_field); + emit_atom(s, JS_ATOM_value); + emit_op(s, OP_await); emit_op(s, OP_async_yield_star); + } else { + /* OP_yield_star takes (value, done) as parameter */ + emit_op(s, OP_yield_star); + } emit_op(s, OP_dup); label_return = emit_goto(s, OP_if_true, -1); emit_op(s, OP_drop); @@ -25366,16 +25874,21 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) label_throw = emit_goto(s, OP_if_true, -1); /* return handling */ + if (is_async) emit_op(s, OP_await); - emit_op(s, OP_async_iterator_get); + emit_op(s, OP_iterator_call); emit_u8(s, 0); label_return1 = emit_goto(s, OP_if_true, -1); + if (is_async) emit_op(s, OP_await); - emit_op(s, OP_iterator_get_value_done); - /* XXX: the spec does not indicate that an await should be - performed in case done = true, but the tests assume it */ + emit_op(s, OP_iterator_check_object); + emit_op(s, OP_get_field2); + emit_atom(s, JS_ATOM_done); emit_goto(s, OP_if_false, label_yield); + emit_op(s, OP_get_field); + emit_atom(s, JS_ATOM_value); + emit_label(s, label_return1); emit_op(s, OP_nip); emit_op(s, OP_nip); @@ -25384,48 +25897,42 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) /* throw handling */ emit_label(s, label_throw); - emit_op(s, OP_async_iterator_get); + emit_op(s, OP_iterator_call); emit_u8(s, 1); label_throw1 = emit_goto(s, OP_if_true, -1); + if (is_async) emit_op(s, OP_await); - emit_op(s, OP_iterator_get_value_done); + emit_op(s, OP_iterator_check_object); + emit_op(s, OP_get_field2); + emit_atom(s, JS_ATOM_done); emit_goto(s, OP_if_false, label_yield); - /* XXX: the spec does not indicate that an await should be - performed in case done = true, but the tests assume it */ - emit_op(s, OP_await); emit_goto(s, OP_goto, label_next); /* close the iterator and throw a type error exception */ emit_label(s, label_throw1); - emit_op(s, OP_async_iterator_get); - emit_u8(s, 0); + emit_op(s, OP_iterator_call); + emit_u8(s, 2); label_throw2 = emit_goto(s, OP_if_true, -1); + if (is_async) emit_op(s, OP_await); emit_label(s, label_throw2); - emit_op(s, OP_async_iterator_get); - emit_u8(s, 2); /* throw the type error exception */ - emit_op(s, OP_drop); /* never reached */ + + emit_op(s, OP_throw_error); + emit_atom(s, JS_ATOM_NULL); + emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW); emit_label(s, label_next); + emit_op(s, OP_get_field); + emit_atom(s, JS_ATOM_value); emit_op(s, OP_nip); /* keep the value associated with done = true */ emit_op(s, OP_nip); emit_op(s, OP_nip); } else { - emit_op(s, OP_await); - emit_op(s, OP_yield); - label_next = emit_goto(s, OP_if_false, -1); - emit_return(s, TRUE); - emit_label(s, label_next); - } - } else { int label_next; - if (is_star) { - emit_op(s, OP_for_of_start); - emit_op(s, OP_drop); /* drop the catch offset */ - emit_op(s, OP_yield_star); - } else { + + if (is_async) + emit_op(s, OP_await); emit_op(s, OP_yield); - } label_next = emit_goto(s, OP_if_false, -1); emit_return(s, TRUE); emit_label(s, label_next); @@ -25436,7 +25943,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) /* name0 is used to check for OP_set_name pattern, not duplicated */ name0 = s->token.u.ident.atom; } - if (js_parse_cond_expr(s, in_accepted)) + if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC)) return -1; op = s->token.val; @@ -25447,7 +25954,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0) return -1; - if (js_parse_assign_expr(s, in_accepted)) { + if (js_parse_assign_expr2(s, parse_flags)) { JS_FreeAtom(s->ctx, name); return -1; } @@ -25477,7 +25984,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE); } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) { int label, label1, depth_lvalue, label2; - + if (next_token(s)) return -1; if (get_lvalue(s, &opcode, &scope, &name, &label, @@ -25490,8 +25997,8 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false, -1); emit_op(s, OP_drop); - - if (js_parse_assign_expr(s, in_accepted)) { + + if (js_parse_assign_expr2(s, parse_flags)) { JS_FreeAtom(s->ctx, name); return -1; } @@ -25499,7 +26006,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) if (opcode == OP_get_ref_value && name == name0) { set_object_name(s, name); } - + switch(depth_lvalue) { case 1: emit_op(s, OP_insert2); @@ -25519,7 +26026,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH, FALSE); label2 = emit_goto(s, OP_goto, -1); - + emit_label(s, label1); /* remove the lvalue stack entries */ @@ -25533,11 +26040,17 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) return 0; } -static __exception int js_parse_expr2(JSParseState *s, BOOL in_accepted) +static __exception int js_parse_assign_expr(JSParseState *s) +{ + return js_parse_assign_expr2(s, PF_IN_ACCEPTED); +} + +/* allowed parse_flags: PF_IN_ACCEPTED */ +static __exception int js_parse_expr2(JSParseState *s, int parse_flags) { BOOL comma = FALSE; for(;;) { - if (js_parse_assign_expr(s, in_accepted)) + if (js_parse_assign_expr2(s, parse_flags)) return -1; if (comma) { /* prevent get_lvalue from using the last expression @@ -25559,7 +26072,7 @@ static __exception int js_parse_expr2(JSParseState *s, BOOL in_accepted) static __exception int js_parse_expr(JSParseState *s) { - return js_parse_expr2(s, TRUE); + return js_parse_expr2(s, PF_IN_ACCEPTED); } static void push_break_entry(JSFunctionDef *fd, BlockEnv *be, @@ -25655,12 +26168,25 @@ static void emit_return(JSParseState *s, BOOL hasval) } emit_op(s, OP_iterator_close_return); if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { - int label_next; - emit_op(s, OP_async_iterator_close); + int label_next, label_next2; + + emit_op(s, OP_drop); /* catch offset */ + emit_op(s, OP_drop); /* next */ + emit_op(s, OP_get_field2); + emit_atom(s, JS_ATOM_return); + /* stack: iter_obj return_func */ + emit_op(s, OP_dup); + emit_op(s, OP_is_undefined_or_null); label_next = emit_goto(s, OP_if_true, -1); + emit_op(s, OP_call_method); + emit_u16(s, 0); + emit_op(s, OP_iterator_check_object); emit_op(s, OP_await); + label_next2 = emit_goto(s, OP_goto, -1); emit_label(s, label_next); emit_op(s, OP_drop); + emit_label(s, label_next2); + emit_op(s, OP_drop); } else { emit_op(s, OP_iterator_close); } @@ -25748,7 +26274,8 @@ static __exception int js_parse_block(JSParseState *s) return 0; } -static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok, +/* allowed parse_flags: PF_IN_ACCEPTED */ +static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok, BOOL export_flag) { JSContext *ctx = s->ctx; @@ -25788,7 +26315,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok, emit_u16(s, fd->scope_level); if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0) goto var_error; - if (js_parse_assign_expr(s, in_accepted)) { + if (js_parse_assign_expr2(s, parse_flags)) { JS_FreeAtom(ctx, name1); goto var_error; } @@ -25796,7 +26323,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok, put_lvalue(s, opcode, scope, name1, label, PUT_LVALUE_NOKEEP, FALSE); } else { - if (js_parse_assign_expr(s, in_accepted)) + if (js_parse_assign_expr2(s, parse_flags)) goto var_error; set_object_name(s, name); emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ? @@ -25823,7 +26350,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok, if ((s->token.val == '[' || s->token.val == '{') && js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') { emit_op(s, OP_undefined); - if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE)) + if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0) return -1; } else { return js_parse_error(s, "variable name expected"); @@ -25952,7 +26479,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) { if (s->token.val == '[' || s->token.val == '{') { - if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE)) + if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0) return -1; has_destructuring = TRUE; } else { @@ -25978,11 +26505,11 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, int skip_bits; if ((s->token.val == '[' || s->token.val == '{') && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) { - if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE)) + if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0) return -1; } else { int lvalue_label; - if (js_parse_postfix_expr(s, TRUE)) + if (js_parse_left_hand_side_expr(s)) return -1; if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label, NULL, FALSE, TOK_FOR)) @@ -26002,7 +26529,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, /* parse and evaluate initializer prior to evaluating the object (only used with "for in" with a non lexical variable in non strict mode */ - if (next_token(s) || js_parse_assign_expr(s, FALSE)) { + if (next_token(s) || js_parse_assign_expr2(s, 0)) { JS_FreeAtom(ctx, var_name); return -1; } @@ -26035,7 +26562,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, if (next_token(s)) return -1; if (is_for_of) { - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; } else { if (js_parse_expr(s)) @@ -26088,7 +26615,11 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, if (is_for_of) { if (is_async) { /* call the next method */ - emit_op(s, OP_for_await_of_next); + /* stack: iter_obj next catch_offset */ + emit_op(s, OP_dup3); + emit_op(s, OP_drop); + emit_op(s, OP_call_method); + emit_u16(s, 0); /* get the result of the promise */ emit_op(s, OP_await); /* unwrap the value and done values */ @@ -26646,7 +27177,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) { if (s->token.val == '[' || s->token.val == '{') { /* XXX: TOK_LET is not completely correct */ - if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE)) + if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0) goto fail; } else { js_parse_error(s, "identifier expected"); @@ -26712,18 +27243,37 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, } emit_label(s, label_finally); if (s->token.val == TOK_FINALLY) { - int saved_eval_ret_idx; + int saved_eval_ret_idx = 0; /* avoid warning */ + if (next_token(s)) goto fail; /* on the stack: ret_value gosub_ret_value */ push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL, -1, -1, 2); - saved_eval_ret_idx = s->cur_func->eval_ret_idx; - s->cur_func->eval_ret_idx = -1; - /* 'finally' does not update eval_ret */ + + if (s->cur_func->eval_ret_idx >= 0) { + /* 'finally' updates eval_ret only if not a normal + termination */ + saved_eval_ret_idx = + add_var(s->ctx, s->cur_func, JS_ATOM__ret_); + if (saved_eval_ret_idx < 0) + goto fail; + emit_op(s, OP_get_loc); + emit_u16(s, s->cur_func->eval_ret_idx); + emit_op(s, OP_put_loc); + emit_u16(s, saved_eval_ret_idx); + set_eval_ret_undefined(s); + } + if (js_parse_block(s)) goto fail; - s->cur_func->eval_ret_idx = saved_eval_ret_idx; + + if (s->cur_func->eval_ret_idx >= 0) { + emit_op(s, OP_get_loc); + emit_u16(s, saved_eval_ret_idx); + emit_op(s, OP_put_loc); + emit_u16(s, s->cur_func->eval_ret_idx); + } pop_break_entry(s->cur_func); } emit_op(s, OP_ret); @@ -26819,7 +27369,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, if (js_parse_expect_semi(s)) goto fail; break; - + case TOK_ENUM: case TOK_EXPORT: case TOK_EXTENDS: @@ -27136,7 +27686,7 @@ static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name) { struct list_head *el; JSModuleDef *m; - + /* first look at the loaded modules */ list_for_each(el, &ctx->loaded_modules) { m = list_entry(el, JSModuleDef, link); @@ -27201,7 +27751,7 @@ static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx, { const char *base_cname, *cname; JSModuleDef *m; - + base_cname = JS_AtomToCString(ctx, base_module_name); if (!base_cname) return NULL; @@ -27511,19 +28061,11 @@ static int exported_names_cmp(const void *p1, const void *p2, void *opaque) static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m); -static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, +static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) { JSModuleDef *m = opaque; - JSValue val, this_val = JS_MKPTR(JS_TAG_OBJECT, p); - - val = js_get_module_ns(ctx, m); - if (JS_IsException(val)) - return -1; - if (JS_DefinePropertyValue(ctx, this_val, atom, val, - JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0) - return -1; - return 0; + return js_get_module_ns(ctx, m); } static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m) @@ -27741,13 +28283,13 @@ static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m) return -1; } -/* must be done before js_instantiate_module() because of cyclic references */ +/* must be done before js_link_module() because of cyclic references */ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) { BOOL is_c_module; int i; JSVarRef *var_ref; - + if (m->func_created) return 0; @@ -27771,7 +28313,7 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) m->func_created = TRUE; /* do it on the dependencies */ - + for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; if (js_create_module_function(ctx, rme->module) < 0) @@ -27779,12 +28321,12 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) } return 0; -} +} + - /* Prepare a module to be executed by resolving all the imported variables. */ -static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) +static int js_link_module(JSContext *ctx, JSModuleDef *m) { int i; JSImportEntry *mi; @@ -27792,6 +28334,7 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) JSVarRef **var_refs, *var_ref; JSObject *p; BOOL is_c_module; + JSValue ret_val; if (m->instantiated) return 0; @@ -27806,7 +28349,7 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; - if (js_instantiate_module(ctx, rme->module) < 0) + if (js_link_module(ctx, rme->module) < 0) goto fail; } @@ -27925,6 +28468,12 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) me->u.local.var_ref = var_ref; } } + + /* initialize the global variables */ + ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL); + if (JS_IsException(ret_val)) + goto fail; + JS_FreeValue(ctx, ret_val); } #ifdef DUMP_MODULE_RESOLVE @@ -27987,7 +28536,7 @@ static JSValue js_import_meta(JSContext *ctx) { JSAtom filename; JSModuleDef *m; - + filename = JS_GetScriptOrModuleName(ctx, 0); if (filename == JS_ATOM_NULL) goto fail; @@ -28010,11 +28559,11 @@ JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, { JSModuleDef *m; JSValue ret, func_obj; - + m = js_host_resolve_imported_module(ctx, basename, filename); if (!m) return NULL; - + if (js_resolve_module(ctx, m) < 0) { js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); return NULL; @@ -28029,6 +28578,28 @@ JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, return m; } +JSValue JS_GetModuleExportItem(JSContext *ctx, JSModuleDef *m, JSAtom atom) +{ + JSValue rv = JS_UNDEFINED; + for (int n = 0; n < m->export_entries_count; ++n) + { + JSExportEntry *me = &m->export_entries[n]; + if (me->local_name == atom && me->export_type == JS_EXPORT_TYPE_LOCAL /*???*/) { + rv = me->u.local.var_ref->value; + break; + } + } + return JS_DupValue(ctx, rv); +} + +JSValue JS_GetModuleExportItemStr(JSContext *ctx, JSModuleDef *m, const char *name) +{ + JSAtom atom = JS_NewAtom(ctx, name); + JSValue rv = JS_GetModuleExportItem(ctx, m, atom); + JS_FreeAtom(ctx, atom); + return rv; +} + static JSValue js_dynamic_import_job(JSContext *ctx, int argc, JSValueConst *argv) { @@ -28050,7 +28621,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx, filename = JS_ToCString(ctx, specifier); if (!filename) goto exception; - + m = JS_RunModule(ctx, basename, filename); JS_FreeCString(ctx, filename); if (!m) @@ -28092,7 +28663,7 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) JS_FreeAtom(ctx, basename); if (JS_IsException(basename_val)) return basename_val; - + promise = JS_NewPromiseCapability(ctx, resolving_funcs); if (JS_IsException(promise)) { JS_FreeValue(ctx, basename_val); @@ -28103,7 +28674,7 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) args[1] = resolving_funcs[1]; args[2] = basename_val; args[3] = specifier; - + JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args); JS_FreeValue(ctx, basename_val); @@ -28324,7 +28895,7 @@ static __exception int js_parse_export(JSParseState *s) s->token.ptr, s->token.line_num, JS_PARSE_EXPORT_DEFAULT, NULL); } else { - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) return -1; } /* set the name of anonymous functions */ @@ -28513,7 +29084,7 @@ static __exception int js_parse_source_element(JSParseState *s) { JSFunctionDef *fd = s->cur_func; int tok; - + if (s->token.val == TOK_FUNCTION || (token_is_pseudo_keyword(s, JS_ATOM_async) && peek_token(s, TRUE) == TOK_FUNCTION)) { @@ -28567,7 +29138,9 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx, fd->last_opcode_pos = -1; fd->func_name = JS_ATOM_NULL; fd->var_object_idx = -1; + fd->arg_var_object_idx = -1; fd->arguments_var_idx = -1; + fd->arguments_arg_idx = -1; fd->func_var_idx = -1; fd->eval_ret_idx = -1; fd->this_var_idx = -1; @@ -28576,13 +29149,14 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx, fd->home_object_var_idx = -1; /* XXX: should distinguish arg, var and var object and body scopes */ - fd->scope_level = 0; /* 0: var/arg scope, 1:body scope */ - fd->scope_first = -1; fd->scopes = fd->def_scope_array; fd->scope_size = countof(fd->def_scope_array); fd->scope_count = 1; fd->scopes[0].first = -1; fd->scopes[0].parent = -1; + fd->scope_level = 0; /* 0: var/arg scope */ + fd->scope_first = -1; + fd->body_scope = -1; fd->filename = JS_NewAtom(ctx, filename); fd->line_num = line_num; @@ -28602,7 +29176,7 @@ static void free_bytecode_atoms(JSRuntime *rt, int pos, len, op; JSAtom atom; const JSOpCode *oi; - + pos = 0; while (pos < bc_len) { op = bc_buf[pos]; @@ -28610,7 +29184,7 @@ static void free_bytecode_atoms(JSRuntime *rt, oi = &short_opcode_info(op); else oi = &opcode_info[op]; - + len = oi->size; switch(oi->fmt) { case OP_FMT_atom: @@ -28663,10 +29237,10 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) } js_free(ctx, fd->args); - for(i = 0; i < fd->hoisted_def_count; i++) { - JS_FreeAtom(ctx, fd->hoisted_def[i].var_name); + for(i = 0; i < fd->global_var_count; i++) { + JS_FreeAtom(ctx, fd->global_vars[i].var_name); } - js_free(ctx, fd->hoisted_def); + js_free(ctx, fd->global_vars); for(i = 0; i < fd->closure_var_count; i++) { JSClosureVar *cv = &fd->closure_var[i]; @@ -29350,19 +29924,27 @@ static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s, switch(var_name) { case JS_ATOM_home_object: /* 'home_object' pseudo variable */ - var_idx = s->home_object_var_idx = add_var(ctx, s, var_name); + if (s->home_object_var_idx < 0) + s->home_object_var_idx = add_var(ctx, s, var_name); + var_idx = s->home_object_var_idx; break; case JS_ATOM_this_active_func: /* 'this.active_func' pseudo variable */ - var_idx = s->this_active_func_var_idx = add_var(ctx, s, var_name); + if (s->this_active_func_var_idx < 0) + s->this_active_func_var_idx = add_var(ctx, s, var_name); + var_idx = s->this_active_func_var_idx; break; case JS_ATOM_new_target: /* 'new.target' pseudo variable */ - var_idx = s->new_target_var_idx = add_var(ctx, s, var_name); + if (s->new_target_var_idx < 0) + s->new_target_var_idx = add_var(ctx, s, var_name); + var_idx = s->new_target_var_idx; break; case JS_ATOM_this: /* 'this' pseudo variable */ - var_idx = s->this_var_idx = add_var_this(ctx, s); + if (s->this_var_idx < 0) + s->this_var_idx = add_var_this(ctx, s); + var_idx = s->this_var_idx; break; default: var_idx = -1; @@ -29371,18 +29953,32 @@ static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s, return var_idx; } +/* test if 'var_name' is in the variable object on the stack. If is it + the case, handle it and jump to 'label_done' */ +static void var_object_test(JSContext *ctx, JSFunctionDef *s, + JSAtom var_name, int op, DynBuf *bc, + int *plabel_done, BOOL is_with) +{ + dbuf_putc(bc, get_with_scope_opcode(op)); + dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); + *plabel_done = new_label_fd(s, *plabel_done); + dbuf_put_u32(bc, *plabel_done); + dbuf_putc(bc, is_with); + update_label(s, *plabel_done, 1); + s->jump_size++; +} + /* return the position of the next opcode */ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, JSAtom var_name, int scope_level, int op, DynBuf *bc, uint8_t *bc_buf, - LabelSlot *ls, int pos_next, int arg_valid) + LabelSlot *ls, int pos_next) { int idx, var_idx, is_put; int label_done; - BOOL is_func_var = FALSE; JSFunctionDef *fd; JSVarDef *vd; - BOOL is_pseudo_var; + BOOL is_pseudo_var, is_arg_scope; label_done = -1; @@ -29400,12 +29996,11 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, if (vd->var_name == var_name) { if (op == OP_scope_put_var || op == OP_scope_make_ref) { if (vd->is_const) { - dbuf_putc(bc, OP_throw_var); + dbuf_putc(bc, OP_throw_error); dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); dbuf_putc(bc, JS_THROW_VAR_RO); goto done; } - is_func_var = vd->is_func_var; } var_idx = idx; break; @@ -29413,33 +30008,16 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) { dbuf_putc(bc, OP_get_loc); dbuf_put_u16(bc, idx); - dbuf_putc(bc, get_with_scope_opcode(op)); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - label_done = new_label_fd(s, label_done); - dbuf_put_u32(bc, label_done); - dbuf_putc(bc, 1); - update_label(s, label_done, 1); - s->jump_size++; + var_object_test(ctx, s, var_name, op, bc, &label_done, 1); } idx = vd->scope_next; } + is_arg_scope = (idx == ARG_SCOPE_END); if (var_idx < 0) { - /* XXX: scoping issues: - should not resolve vars from the function body during argument parse, - `arguments` and function-name should not be hidden by later vars. - */ + /* argument scope: variables are not visible but pseudo + variables are visible */ + if (!is_arg_scope) { var_idx = find_var(ctx, s, var_name); - if (var_idx >= 0) { - if (scope_level == 0 - && (var_idx & ARGUMENT_VAR_OFFSET) - && (var_idx - ARGUMENT_VAR_OFFSET) >= arg_valid) { - /* referring to an uninitialized argument */ - dbuf_putc(bc, OP_throw_var); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - dbuf_putc(bc, JS_THROW_VAR_UNINITIALIZED); - } - if (!(var_idx & ARGUMENT_VAR_OFFSET)) - is_func_var = s->vars[var_idx].is_func_var; } if (var_idx < 0 && is_pseudo_var) @@ -29448,21 +30026,31 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, if (var_idx < 0 && var_name == JS_ATOM_arguments && s->has_arguments_binding) { /* 'arguments' pseudo variable */ - var_idx = add_arguments_var(ctx, s, var_name); + var_idx = add_arguments_var(ctx, s); } if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) { /* add a new variable with the function name */ var_idx = add_func_var(ctx, s, var_name); - is_func_var = TRUE; } } if (var_idx >= 0) { + if ((op == OP_scope_put_var || op == OP_scope_make_ref) && + !(var_idx & ARGUMENT_VAR_OFFSET) && + s->vars[var_idx].is_const) { + /* only happens when assigning a function expression name + in strict mode */ + dbuf_putc(bc, OP_throw_error); + dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); + dbuf_putc(bc, JS_THROW_VAR_RO); + goto done; + } /* OP_scope_put_var_init is only used to initialize a lexical variable, so it is never used in a with or var object. It can be used with a closure (module global variable case). */ switch (op) { case OP_scope_make_ref: - if (is_func_var) { + if (!(var_idx & ARGUMENT_VAR_OFFSET) && + s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) { /* Create a dummy object reference for the func_var */ dbuf_putc(bc, OP_object); dbuf_putc(bc, OP_get_loc); @@ -29510,7 +30098,6 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, if (var_idx & ARGUMENT_VAR_OFFSET) { dbuf_putc(bc, OP_get_arg + is_put); dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET); - /* XXX: should test if argument reference needs TDZ check */ } else { if (is_put) { if (s->vars[var_idx].is_lexical) { @@ -29543,41 +30130,32 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, goto done; } /* check eval object */ - if (s->var_object_idx >= 0 && !is_pseudo_var) { + if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) { dbuf_putc(bc, OP_get_loc); dbuf_put_u16(bc, s->var_object_idx); - dbuf_putc(bc, get_with_scope_opcode(op)); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - label_done = new_label_fd(s, label_done); - dbuf_put_u32(bc, label_done); - dbuf_putc(bc, 0); - update_label(s, label_done, 1); - s->jump_size++; + var_object_test(ctx, s, var_name, op, bc, &label_done, 0); + } + /* check eval object in argument scope */ + if (s->arg_var_object_idx >= 0 && !is_pseudo_var) { + dbuf_putc(bc, OP_get_loc); + dbuf_put_u16(bc, s->arg_var_object_idx); + var_object_test(ctx, s, var_name, op, bc, &label_done, 0); } + /* check parent scopes */ for (fd = s; fd->parent;) { scope_level = fd->parent_scope_level; fd = fd->parent; - if (scope_level == 0) { - /* function is defined as part of the argument parsing: hide vars - from the function body. - XXX: variables created from argument destructuring might need - to be visible, should refine this method. - */ - var_idx = find_arg(ctx, fd, var_name); - goto check_idx; - } for (idx = fd->scopes[scope_level].first; idx >= 0;) { vd = &fd->vars[idx]; if (vd->var_name == var_name) { if (op == OP_scope_put_var || op == OP_scope_make_ref) { if (vd->is_const) { - dbuf_putc(bc, OP_throw_var); + dbuf_putc(bc, OP_throw_error); dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); dbuf_putc(bc, JS_THROW_VAR_RO); goto done; } - is_func_var = vd->is_func_var; } var_idx = idx; break; @@ -29587,25 +30165,18 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, if (idx >= 0) { dbuf_putc(bc, OP_get_var_ref); dbuf_put_u16(bc, idx); - dbuf_putc(bc, get_with_scope_opcode(op)); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - label_done = new_label_fd(s, label_done); - dbuf_put_u32(bc, label_done); - dbuf_putc(bc, 1); - update_label(s, label_done, 1); - s->jump_size++; + var_object_test(ctx, s, var_name, op, bc, &label_done, 1); } } idx = vd->scope_next; } + is_arg_scope = (idx == ARG_SCOPE_END); if (var_idx >= 0) break; + if (!is_arg_scope) { var_idx = find_var(ctx, fd, var_name); - check_idx: - if (var_idx >= 0) { - if (!(var_idx & ARGUMENT_VAR_OFFSET)) - is_func_var = fd->vars[var_idx].is_func_var; + if (var_idx >= 0) break; } if (is_pseudo_var) { @@ -29614,31 +30185,37 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, break; } if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) { - var_idx = add_arguments_var(ctx, fd, var_name); + var_idx = add_arguments_var(ctx, fd); break; } if (fd->is_func_expr && fd->func_name == var_name) { /* add a new variable with the function name */ var_idx = add_func_var(ctx, fd, var_name); - is_func_var = TRUE; break; } /* check eval object */ - if (fd->var_object_idx >= 0 && !is_pseudo_var) { - fd->vars[fd->var_object_idx].is_captured = 1; + if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) { + vd = &fd->vars[fd->var_object_idx]; + vd->is_captured = 1; idx = get_closure_var(ctx, s, fd, FALSE, - fd->var_object_idx, JS_ATOM__var_, + fd->var_object_idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL); dbuf_putc(bc, OP_get_var_ref); dbuf_put_u16(bc, idx); - dbuf_putc(bc, get_with_scope_opcode(op)); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - label_done = new_label_fd(s, label_done); - dbuf_put_u32(bc, label_done); - dbuf_putc(bc, 0); - update_label(s, label_done, 1); - s->jump_size++; + var_object_test(ctx, s, var_name, op, bc, &label_done, 0); + } + + /* check eval object in argument scope */ + if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) { + vd = &fd->vars[fd->arg_var_object_idx]; + vd->is_captured = 1; + idx = get_closure_var(ctx, s, fd, FALSE, + fd->arg_var_object_idx, vd->var_name, + FALSE, FALSE, JS_VAR_NORMAL); + dbuf_putc(bc, OP_get_var_ref); + dbuf_put_u16(bc, idx); + var_object_test(ctx, s, var_name, op, bc, &label_done, 0); } if (fd->is_eval) @@ -29665,6 +30242,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, } goto has_idx; } else if ((cv->var_name == JS_ATOM__var_ || + cv->var_name == JS_ATOM__arg_var_ || cv->var_name == JS_ATOM__with_) && !is_pseudo_var) { int is_with = (cv->var_name == JS_ATOM__with_); if (fd != s) { @@ -29678,13 +30256,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, } dbuf_putc(bc, OP_get_var_ref); dbuf_put_u16(bc, idx); - dbuf_putc(bc, get_with_scope_opcode(op)); - dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); - label_done = new_label_fd(s, label_done); - dbuf_put_u32(bc, label_done); - dbuf_putc(bc, is_with); - update_label(s, label_done, 1); - s->jump_size++; + var_object_test(ctx, s, var_name, op, bc, &label_done, is_with); } } } @@ -29709,14 +30281,14 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, has_idx: if ((op == OP_scope_put_var || op == OP_scope_make_ref) && s->closure_var[idx].is_const) { - dbuf_putc(bc, OP_throw_var); + dbuf_putc(bc, OP_throw_error); dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); dbuf_putc(bc, JS_THROW_VAR_RO); goto done; } switch (op) { case OP_scope_make_ref: - if (is_func_var) { + if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) { /* Create a dummy object reference for the func_var */ dbuf_putc(bc, OP_object); dbuf_putc(bc, OP_get_var_ref); @@ -29848,7 +30420,7 @@ static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx) { /* if the field is not initialized, the error is catched when accessing it */ - if (is_ref) + if (is_ref) dbuf_putc(bc, OP_get_var_ref); else dbuf_putc(bc, OP_get_loc); @@ -29863,7 +30435,7 @@ static int resolve_scope_private_field1(JSContext *ctx, int idx, var_kind; JSFunctionDef *fd; BOOL is_ref; - + fd = s; is_ref = FALSE; for(;;) { @@ -29956,7 +30528,7 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s, break; case JS_VAR_PRIVATE_SETTER: /* XXX: add clearer error message */ - dbuf_putc(bc, OP_throw_var); + dbuf_putc(bc, OP_throw_error); dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); dbuf_putc(bc, JS_THROW_VAR_RO); break; @@ -29973,7 +30545,7 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s, case JS_VAR_PRIVATE_METHOD: case JS_VAR_PRIVATE_GETTER: /* XXX: add clearer error message */ - dbuf_putc(bc, OP_throw_var); + dbuf_putc(bc, OP_throw_error); dbuf_put_u32(bc, JS_DupAtom(ctx, var_name)); dbuf_putc(bc, JS_THROW_VAR_RO); break; @@ -30025,17 +30597,33 @@ static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s, } } +/* XXX: should handle the argument scope generically */ +static BOOL is_var_in_arg_scope(const JSVarDef *vd) +{ + return (vd->var_name == JS_ATOM_home_object || + vd->var_name == JS_ATOM_this_active_func || + vd->var_name == JS_ATOM_new_target || + vd->var_name == JS_ATOM_this || + vd->var_name == JS_ATOM__arg_var_ || + vd->var_kind == JS_VAR_FUNCTION_NAME); +} + static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) { JSFunctionDef *fd; JSVarDef *vd; int i, scope_level, scope_idx; - BOOL has_arguments_binding, has_this_binding; + BOOL has_arguments_binding, has_this_binding, is_arg_scope; /* in non strict mode, variables are created in the caller's environment object */ if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) { s->var_object_idx = add_var(ctx, s, JS_ATOM__var_); + if (s->has_parameter_expressions) { + /* an additional variable object is needed for the + argument scope */ + s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_); + } } /* eval can potentially use 'arguments' so we must define it */ @@ -30051,8 +30639,14 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object); } has_arguments_binding = s->has_arguments_binding; - if (has_arguments_binding) - add_arguments_var(ctx, s, JS_ATOM_arguments); + if (has_arguments_binding) { + add_arguments_var(ctx, s); + /* also add an arguments binding in the argument scope to + raise an error if a direct eval in the argument scope tries + to redefine it */ + if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT)) + add_arguments_arg(ctx, s); + } if (s->is_func_expr && s->func_name != JS_ATOM_NULL) add_func_var(ctx, s, s->func_name); @@ -30069,7 +30663,6 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) fd = fd->parent; if (!fd) break; - scope_idx = fd->scopes[scope_level].first; /* add 'this' if it was not previously added */ if (!has_this_binding && fd->has_this_binding) { if (fd->this_var_idx < 0) @@ -30084,7 +30677,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) } /* add 'arguments' if it was not previously added */ if (!has_arguments_binding && fd->has_arguments_binding) { - add_arguments_var(ctx, fd, JS_ATOM_arguments); + add_arguments_var(ctx, fd); has_arguments_binding = TRUE; } /* add function name */ @@ -30092,6 +30685,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) add_func_var(ctx, fd, fd->func_name); /* add lexical variables */ + scope_idx = fd->scopes[scope_level].first; while (scope_idx >= 0) { vd = &fd->vars[scope_idx]; vd->is_captured = 1; @@ -30099,6 +30693,8 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind); scope_idx = vd->scope_next; } + is_arg_scope = (scope_idx == ARG_SCOPE_END); + if (!is_arg_scope) { /* add unscoped variables */ for(i = 0; i < fd->arg_count; i++) { vd = &fd->args[i]; @@ -30119,6 +30715,17 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) JS_VAR_NORMAL); } } + } else { + for(i = 0; i < fd->var_count; i++) { + vd = &fd->vars[i]; + /* do not close top level last result */ + if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) { + get_closure_var(ctx, s, fd, + FALSE, i, vd->var_name, FALSE, FALSE, + JS_VAR_NORMAL); + } + } + } if (fd->is_eval) { int idx; /* add direct eval variables (we are necessarily at the @@ -30134,6 +30741,18 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) } } +static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv, + JSVarDef *vd, int var_idx) +{ + cv->is_local = TRUE; + cv->is_arg = FALSE; + cv->is_const = vd->is_const; + cv->is_lexical = vd->is_lexical; + cv->var_kind = vd->var_kind; + cv->var_idx = var_idx; + cv->var_name = JS_DupAtom(ctx, vd->var_name); +} + /* for direct eval compilation: add references to the variables of the calling function */ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, @@ -30141,6 +30760,7 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, { int i, count; JSVarDef *vd; + BOOL is_arg_scope; count = b->arg_count + b->var_count + b->closure_var_count; s->closure_var = NULL; @@ -30156,16 +30776,12 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, vd = &b->vardefs[b->arg_count + i]; if (vd->scope_level > 0) { JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; - cv->is_local = TRUE; - cv->is_arg = FALSE; - cv->is_const = vd->is_const; - cv->is_lexical = vd->is_lexical; - cv->var_kind = vd->var_kind; - cv->var_idx = i; - cv->var_name = JS_DupAtom(ctx, vd->var_name); + set_closure_from_var(ctx, cv, vd, i); } i = vd->scope_next; } + is_arg_scope = (i == ARG_SCOPE_END); + if (!is_arg_scope) { /* Add argument variables */ for(i = 0; i < b->arg_count; i++) { JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; @@ -30183,13 +30799,17 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s, vd = &b->vardefs[b->arg_count + i]; if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) { JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; - cv->is_local = TRUE; - cv->is_arg = FALSE; - cv->is_const = FALSE; - cv->is_lexical = FALSE; - cv->var_kind = JS_VAR_NORMAL; - cv->var_idx = i; - cv->var_name = JS_DupAtom(ctx, vd->var_name); + set_closure_from_var(ctx, cv, vd, i); + } + } + } else { + /* only add pseudo variables */ + for(i = 0; i < b->var_count; i++) { + vd = &b->vardefs[b->arg_count + i]; + if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) { + JSClosureVar *cv = &s->closure_var[s->closure_var_count++]; + set_closure_from_var(ctx, cv, vd, i); + } } } for(i = 0; i < b->closure_var_count; i++) { @@ -30348,14 +30968,48 @@ static BOOL code_match(CodeContext *s, int pos, ...) static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc) { - int i, idx, var_idx; + int i, idx, label_next = -1; - /* add the hoisted functions and variables */ - for(i = 0; i < s->hoisted_def_count; i++) { - JSHoistedDef *hf = &s->hoisted_def[i]; + /* add the hoisted functions in arguments and local variables */ + for(i = 0; i < s->arg_count; i++) { + JSVarDef *vd = &s->args[i]; + if (vd->func_pool_idx >= 0) { + dbuf_putc(bc, OP_fclosure); + dbuf_put_u32(bc, vd->func_pool_idx); + dbuf_putc(bc, OP_put_arg); + dbuf_put_u16(bc, i); + } + } + for(i = 0; i < s->var_count; i++) { + JSVarDef *vd = &s->vars[i]; + if (vd->scope_level == 0 && vd->func_pool_idx >= 0) { + dbuf_putc(bc, OP_fclosure); + dbuf_put_u32(bc, vd->func_pool_idx); + dbuf_putc(bc, OP_put_loc); + dbuf_put_u16(bc, i); + } + } + + /* the module global variables must be initialized before + evaluating the module so that the exported functions are + visible if there are cyclic module references */ + if (s->module) { + label_next = new_label_fd(s, -1); + + /* if 'this' is true, initialize the global variables and return */ + dbuf_putc(bc, OP_push_this); + dbuf_putc(bc, OP_if_false); + dbuf_put_u32(bc, label_next); + update_label(s, label_next, 1); + s->jump_size++; + } + + /* add the global variables (only happens if s->is_global_var is + true) */ + for(i = 0; i < s->global_var_count; i++) { + JSGlobalVar *hf = &s->global_vars[i]; int has_closure = 0; BOOL force_init = hf->force_init; - if (s->is_global_var && hf->var_name != JS_ATOM_NULL) { /* we are in an eval, so the closure contains all the enclosing variables */ /* If the outer function has a variable environment, @@ -30367,7 +31021,8 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy force_init = FALSE; break; } - if (cv->var_name == JS_ATOM__var_) { + if (cv->var_name == JS_ATOM__var_ || + cv->var_name == JS_ATOM__arg_var_) { dbuf_putc(bc, OP_get_var_ref); dbuf_put_u16(bc, idx); has_closure = 1; @@ -30390,7 +31045,7 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name)); dbuf_putc(bc, flags); - goto done_hoisted_def; + goto done_global_var; } else { if (hf->is_lexical) { flags |= DEFINE_GLOBAL_LEX_VAR; @@ -30402,7 +31057,6 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy dbuf_putc(bc, flags); } } - } if (hf->cpool_idx >= 0 || force_init) { if (hf->cpool_idx >= 0) { dbuf_putc(bc, OP_fclosure); @@ -30415,7 +31069,6 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy } else { dbuf_putc(bc, OP_undefined); } - if (s->is_global_var) { if (has_closure == 2) { dbuf_putc(bc, OP_put_var_ref); dbuf_put_u16(bc, idx); @@ -30428,24 +31081,23 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy dbuf_putc(bc, OP_put_var); dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name)); } - } else { - var_idx = hf->var_idx; - if (var_idx & ARGUMENT_VAR_OFFSET) { - dbuf_putc(bc, OP_put_arg); - dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET); - } else { - dbuf_putc(bc, OP_put_loc); - dbuf_put_u16(bc, var_idx); - } } - } - done_hoisted_def: + done_global_var: JS_FreeAtom(ctx, hf->var_name); } - js_free(ctx, s->hoisted_def); - s->hoisted_def = NULL; - s->hoisted_def_count = 0; - s->hoisted_def_size = 0; + + if (s->module) { + dbuf_putc(bc, OP_return_undef); + + dbuf_putc(bc, OP_label); + dbuf_put_u32(bc, label_next); + s->label_slots[label_next].pos2 = bc->size; + } + + js_free(ctx, s->global_vars); + s->global_vars = NULL; + s->global_var_count = 0; + s->global_var_size = 0; } static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len, @@ -30525,7 +31177,7 @@ static int get_label_pos(JSFunctionDef *s, int label) variables when necessary */ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) { - int pos, pos_next, bc_len, op, len, i, idx, arg_valid, line_num; + int pos, pos_next, bc_len, op, len, i, idx, line_num; uint8_t *bc_buf; JSAtom var_name; DynBuf bc_out; @@ -30538,12 +31190,10 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) /* first pass for runtime checks (must be done before the variables are created) */ - if (s->is_global_var) { - for(i = 0; i < s->hoisted_def_count; i++) { - JSHoistedDef *hf = &s->hoisted_def[i]; + for(i = 0; i < s->global_var_count; i++) { + JSGlobalVar *hf = &s->global_vars[i]; int flags; - if (hf->var_name != JS_ATOM_NULL) { /* check if global variable (XXX: simplify) */ for(idx = 0; idx < s->closure_var_count; idx++) { JSClosureVar *cv = &s->closure_var[idx]; @@ -30555,13 +31205,14 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) compilation here, but for consistency with the other checks, we delay the error generation. */ - dbuf_putc(&bc_out, OP_throw_var); + dbuf_putc(&bc_out, OP_throw_error); dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name)); dbuf_putc(&bc_out, JS_THROW_VAR_REDECL); } goto next; } - if (cv->var_name == JS_ATOM__var_) + if (cv->var_name == JS_ATOM__var_ || + cv->var_name == JS_ATOM__arg_var_) goto next; } @@ -30573,12 +31224,9 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) if (hf->cpool_idx >= 0) flags |= DEFINE_GLOBAL_FUNC_VAR; dbuf_putc(&bc_out, flags); - } next: ; } - } - arg_valid = 0; line_num = 0; /* avoid warning */ for (pos = 0; pos < bc_len; pos = pos_next) { op = bc_buf[pos]; @@ -30590,9 +31238,6 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) s->line_number_size++; goto no_change; - case OP_set_arg_valid_upto: - arg_valid = get_u16(bc_buf + pos + 1); - break; case OP_eval: /* convert scope index to adjusted variable index */ { int call_argc = get_u16(bc_buf + pos + 1); @@ -30618,7 +31263,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) var_name = get_u32(bc_buf + pos + 1); scope = get_u16(bc_buf + pos + 5); pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out, - NULL, NULL, pos_next, arg_valid); + NULL, NULL, pos_next); JS_FreeAtom(ctx, var_name); break; case OP_scope_make_ref: @@ -30631,7 +31276,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) ls = &s->label_slots[label]; ls->ref_count--; /* always remove label reference */ pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out, - bc_buf, ls, pos_next, arg_valid); + bc_buf, ls, pos_next); JS_FreeAtom(ctx, var_name); } break; @@ -30712,7 +31357,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) case OP_return: case OP_return_undef: case OP_throw: - case OP_throw_var: + case OP_throw_error: case OP_ret: if (OPTIMIZE) { /* remove dead code */ @@ -30746,18 +31391,19 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) { int scope_idx, scope = get_u16(bc_buf + pos + 1); - if (scope == 1) { + if (scope == s->body_scope) { instantiate_hoisted_definitions(ctx, s, &bc_out); } for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) { JSVarDef *vd = &s->vars[scope_idx]; if (vd->scope_level == scope) { + if (scope_idx != s->arguments_arg_idx) { if (vd->var_kind == JS_VAR_FUNCTION_DECL || vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) { /* Initialize lexical variable upon entering scope */ dbuf_putc(&bc_out, OP_fclosure); - dbuf_put_u32(&bc_out, vd->func_pool_or_scope_idx); + dbuf_put_u32(&bc_out, vd->func_pool_idx); dbuf_putc(&bc_out, OP_put_loc); dbuf_put_u16(&bc_out, scope_idx); } else { @@ -30766,6 +31412,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) dbuf_putc(&bc_out, OP_set_loc_uninitialized); dbuf_put_u16(&bc_out, scope_idx); } + } scope_idx = vd->scope_next; } else { break; @@ -30847,7 +31494,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) case OP_set_class_name: /* only used during parsing */ break; - + default: no_change: dbuf_put(&bc_out, bc_buf + pos, len); @@ -31167,6 +31814,8 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) dbuf_putc(&bc_out, OP_special_object); dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS); } + if (s->arguments_arg_idx >= 0) + put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx); put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx); } /* initialize a reference to the current function if needed */ @@ -31181,6 +31830,11 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT); put_short_code(&bc_out, OP_put_loc, s->var_object_idx); } + if (s->arg_var_object_idx >= 0) { + dbuf_putc(&bc_out, OP_special_object); + dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT); + put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx); + } for (pos = 0; pos < bc_len; pos = pos_next) { int val; @@ -31189,11 +31843,19 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) pos_next = pos + len; switch(op) { case OP_line_num: + + line_num = get_u32(bc_buf + pos + 1); +#ifdef CONFIG_DEBUGGER + if (ctx->debugger_enabled) /* under the debugger */ + goto no_change; /* emit OP_line_num BC for the debugger's "break on line functionality" */ + else + break; /* remove OP_line_num from BCs */ +#else /* line number info (for debug). We put it in a separate compressed table to reduce memory usage and get better performance */ - line_num = get_u32(bc_buf + pos + 1); break; +#endif case OP_label: { @@ -31248,7 +31910,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) case OP_return_undef: case OP_return_async: case OP_throw: - case OP_throw_var: + case OP_throw_error: pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num); goto no_change; @@ -31969,32 +32631,29 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) /* compute the maximum stack size needed by the function */ typedef struct StackSizeState { + int bc_len; int stack_len_max; uint16_t *stack_level_tab; + int *pc_stack; + int pc_stack_len; + int pc_stack_size; } StackSizeState; -static __exception int compute_stack_size_rec(JSContext *ctx, - JSFunctionDef *fd, - StackSizeState *s, +/* 'op' is only used for error indication */ +static __exception int ss_check(JSContext *ctx, StackSizeState *s, int pos, int op, int stack_len) { - int bc_len, diff, n_pop, pos_next; - const JSOpCode *oi; - const uint8_t *bc_buf; - + if ((unsigned)pos >= s->bc_len) { + JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos); + return -1; + } if (stack_len > s->stack_len_max) { s->stack_len_max = stack_len; - if (s->stack_len_max > JS_STACK_SIZE_MAX) - goto stack_overflow; + if (s->stack_len_max > JS_STACK_SIZE_MAX) { + JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos); + return -1; + } } - bc_buf = fd->byte_code.buf; - bc_len = fd->byte_code.size; - for(;;) { - if ((unsigned)pos >= bc_len) - goto buf_overflow; -#if 0 - printf("%5d: %d\n", pos, stack_len); -#endif if (s->stack_level_tab[pos] != 0xffff) { /* already explored: check that the stack size is consistent */ if (s->stack_level_tab[pos] != stack_len) { @@ -32004,21 +32663,59 @@ static __exception int compute_stack_size_rec(JSContext *ctx, } else { return 0; } - } else { - s->stack_level_tab[pos] = stack_len; } + /* mark as explored and store the stack size */ + s->stack_level_tab[pos] = stack_len; + + /* queue the new PC to explore */ + if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]), + &s->pc_stack_size, s->pc_stack_len + 1)) + return -1; + s->pc_stack[s->pc_stack_len++] = pos; + return 0; +} + +static __exception int compute_stack_size(JSContext *ctx, + JSFunctionDef *fd, + int *pstack_size) +{ + StackSizeState s_s, *s = &s_s; + int i, diff, n_pop, pos_next, stack_len, pos, op; + const JSOpCode *oi; + const uint8_t *bc_buf; + + bc_buf = fd->byte_code.buf; + s->bc_len = fd->byte_code.size; + /* bc_len > 0 */ + s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) * + s->bc_len); + if (!s->stack_level_tab) + return -1; + for(i = 0; i < s->bc_len; i++) + s->stack_level_tab[i] = 0xffff; + s->stack_len_max = 0; + s->pc_stack = NULL; + s->pc_stack_len = 0; + s->pc_stack_size = 0; + + /* breadth-first graph exploration */ + if (ss_check(ctx, s, 0, OP_invalid, 0)) + goto fail; + + while (s->pc_stack_len > 0) { + pos = s->pc_stack[--s->pc_stack_len]; + stack_len = s->stack_level_tab[pos]; op = bc_buf[pos]; if (op == 0 || op >= OP_COUNT) { JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos); - return -1; + goto fail; } oi = &short_opcode_info(op); pos_next = pos + oi->size; - if (pos_next > bc_len) { - buf_overflow: + if (pos_next > s->bc_len) { JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos); - return -1; + goto fail; } n_pop = oi->n_pop; /* call pops a variable number of arguments */ @@ -32034,13 +32731,15 @@ static __exception int compute_stack_size_rec(JSContext *ctx, if (stack_len < n_pop) { JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos); - return -1; + goto fail; } stack_len += oi->n_push - n_pop; if (stack_len > s->stack_len_max) { s->stack_len_max = stack_len; - if (s->stack_len_max > JS_STACK_SIZE_MAX) - goto stack_overflow; + if (s->stack_len_max > JS_STACK_SIZE_MAX) { + JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos); + goto fail; + } } switch(op) { case OP_tail_call: @@ -32049,9 +32748,9 @@ static __exception int compute_stack_size_rec(JSContext *ctx, case OP_return_undef: case OP_return_async: case OP_throw: - case OP_throw_var: + case OP_throw_error: case OP_ret: - goto done; + goto done_insn; case OP_goto: diff = get_u32(bc_buf + pos + 1); pos_next = pos + 1 + diff; @@ -32068,73 +32767,57 @@ static __exception int compute_stack_size_rec(JSContext *ctx, case OP_if_true8: case OP_if_false8: diff = (int8_t)bc_buf[pos + 1]; - if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len)) - return -1; + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len)) + goto fail; break; #endif case OP_if_true: case OP_if_false: case OP_catch: diff = get_u32(bc_buf + pos + 1); - if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len)) - return -1; + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len)) + goto fail; break; case OP_gosub: diff = get_u32(bc_buf + pos + 1); - if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len + 1)) - return -1; + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1)) + goto fail; break; case OP_with_get_var: case OP_with_delete_var: diff = get_u32(bc_buf + pos + 5); - if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len + 1)) - return -1; + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1)) + goto fail; break; case OP_with_make_ref: case OP_with_get_ref: case OP_with_get_ref_undef: diff = get_u32(bc_buf + pos + 5); - if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len + 2)) - return -1; + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2)) + goto fail; break; case OP_with_put_var: diff = get_u32(bc_buf + pos + 5); - if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len - 1)) - return -1; + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1)) + goto fail; break; default: break; } - pos = pos_next; + if (ss_check(ctx, s, pos_next, op, stack_len)) + goto fail; + done_insn: ; } - done: - return 0; - - stack_overflow: - JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos); - return -1; -} - -static __exception int compute_stack_size(JSContext *ctx, - JSFunctionDef *fd, - int *pstack_size) -{ - StackSizeState s_s, *s = &s_s; - int bc_len, i, ret; - - bc_len = fd->byte_code.size; - /* bc_len > 0 */ - s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) * bc_len); - if (!s->stack_level_tab) - return -1; - for(i = 0; i < bc_len; i++) - s->stack_level_tab[i] = 0xffff; - s->stack_len_max = 0; - ret = compute_stack_size_rec(ctx, fd, s, 0, OP_invalid, 0); js_free(ctx, s->stack_level_tab); + js_free(ctx, s->pc_stack); *pstack_size = s->stack_len_max; - return ret; + return 0; + fail: + js_free(ctx, s->stack_level_tab); + js_free(ctx, s->pc_stack); + *pstack_size = 0; + return -1; } static int add_module_variables(JSContext *ctx, JSFunctionDef *fd) @@ -32142,14 +32825,14 @@ static int add_module_variables(JSContext *ctx, JSFunctionDef *fd) int i, idx; JSModuleDef *m = fd->module; JSExportEntry *me; - JSHoistedDef *hf; + JSGlobalVar *hf; /* The imported global variables were added as closure variables in js_parse_import(). We add here the module global variables. */ - for(i = 0; i < fd->hoisted_def_count; i++) { - hf = &fd->hoisted_def[i]; + for(i = 0; i < fd->global_var_count; i++) { + hf = &fd->global_vars[i]; if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const, hf->is_lexical, FALSE) < 0) return -1; @@ -32187,6 +32870,10 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) for (scope = 0; scope < fd->scope_count; scope++) { fd->scopes[scope].first = -1; } + if (fd->has_parameter_expressions) { + /* special end of variable list marker for the argument scope */ + fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END; + } for (idx = 0; idx < fd->var_count; idx++) { JSVarDef *vd = &fd->vars[idx]; vd->scope_next = fd->scopes[vd->scope_level].first; @@ -32194,12 +32881,12 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) } for (scope = 2; scope < fd->scope_count; scope++) { JSVarScope *sd = &fd->scopes[scope]; - if (sd->first == -1) + if (sd->first < 0) sd->first = fd->scopes[sd->parent].first; } for (idx = 0; idx < fd->var_count; idx++) { JSVarDef *vd = &fd->vars[idx]; - if (vd->scope_next == -1 && vd->scope_level > 1) { + if (vd->scope_next < 0 && vd->scope_level > 1) { scope = fd->scopes[vd->scope_level].parent; vd->scope_next = fd->scopes[scope].first; } @@ -32376,7 +33063,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->realm = JS_DupContext(ctx); add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); - + #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1) if (!(fd->js_mode & JS_MODE_STRIP)) { js_dump_function_bytecode(ctx, b); @@ -32571,7 +33258,8 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd, /* Check if argument name duplicates a destructuring parameter */ /* XXX: should have a flag for such variables */ for (i = 0; i < fd->var_count; i++) { - if (fd->vars[i].var_name == name) + if (fd->vars[i].var_name == name && + fd->vars[i].scope_level == 0) goto duplicate; } } @@ -32587,7 +33275,7 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd, static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s) { JSFunctionDef *fd; - + fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE, s->filename, 0); if (!fd) @@ -32595,7 +33283,7 @@ static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s) fd->func_name = JS_ATOM_NULL; fd->has_prototype = FALSE; fd->has_home_object = TRUE; - + fd->has_arguments_binding = FALSE; fd->has_this_binding = TRUE; fd->is_derived_class_constructor = FALSE; @@ -32603,7 +33291,7 @@ static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s) fd->super_call_allowed = FALSE; fd->super_allowed = fd->has_home_object; fd->arguments_allowed = FALSE; - + fd->func_kind = JS_FUNC_NORMAL; fd->func_type = JS_PARSE_FUNC_METHOD; return fd; @@ -32680,8 +33368,8 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE && (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) { - JSHoistedDef *hf; - hf = find_hoisted_def(fd, func_name); + JSGlobalVar *hf; + hf = find_global_var(fd, func_name); /* XXX: should check scope chain */ if (hf && hf->scope_level == fd->scope_level) { js_parse_error(s, "invalid redefinition of global identifier in module code"); @@ -32691,21 +33379,23 @@ static __exception int js_parse_function_decl2(JSParseState *s, } if (func_type == JS_PARSE_FUNC_VAR) { - /* Create lexical name here so function closure contains it */ if (!(fd->js_mode & JS_MODE_STRICT) + && func_kind == JS_FUNC_NORMAL && find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0 && !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET)) && !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) { create_func_var = TRUE; } + /* Create the lexical name here so that the function closure + contains it */ if (fd->is_eval && (fd->eval_type == JS_EVAL_TYPE_GLOBAL || fd->eval_type == JS_EVAL_TYPE_MODULE) && - fd->scope_level == 1) { + fd->scope_level == fd->body_scope) { /* avoid creating a lexical variable in the global scope. XXX: check annex B */ - JSHoistedDef *hf; - hf = find_hoisted_def(fd, func_name); + JSGlobalVar *hf; + hf = find_global_var(fd, func_name); /* XXX: should check scope chain */ if (hf && hf->scope_level == fd->scope_level) { js_parse_error(s, "invalid redefinition of global identifier"); @@ -32777,9 +33467,10 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) { emit_class_field_init(s); } - + /* parse arguments */ fd->has_simple_parameter_list = TRUE; + fd->has_parameter_expressions = FALSE; has_opt_arg = FALSE; if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) { JSAtom name; @@ -32792,13 +33483,30 @@ static __exception int js_parse_function_decl2(JSParseState *s, goto fail; fd->defined_arg_count = 1; } else { + if (s->token.val == '(') { + int skip_bits; + /* if there is an '=' inside the parameter list, we + consider there is a parameter expression inside */ + js_parse_skip_parens_token(s, &skip_bits, FALSE); + if (skip_bits & SKIP_HAS_ASSIGNMENT) + fd->has_parameter_expressions = TRUE; + if (next_token(s)) + goto fail; + } else { if (js_parse_expect(s, '(')) goto fail; + } + + if (fd->has_parameter_expressions) { + fd->scope_level = -1; /* force no parent scope */ + if (push_scope(s) < 0) + return -1; + } while (s->token.val != ')') { JSAtom name; BOOL rest = FALSE; - int idx; + int idx, has_initializer; if (s->token.val == TOK_ELLIPSIS) { fd->has_simple_parameter_list = FALSE; @@ -32817,8 +33525,13 @@ static __exception int js_parse_function_decl2(JSParseState *s, emit_op(s, OP_get_arg); emit_u16(s, idx); } - if (js_parse_destructuring_element(s, TOK_VAR, 1, TRUE, -1, TRUE)) + has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE); + if (has_initializer < 0) goto fail; + if (has_initializer) + has_opt_arg = TRUE; + if (!has_opt_arg) + fd->defined_arg_count++; } else if (s->token.val == TOK_IDENT) { if (s->token.u.ident.is_reserved) { js_parse_error_reserved_identifier(s); @@ -32829,6 +33542,11 @@ static __exception int js_parse_function_decl2(JSParseState *s, js_parse_error_reserved_identifier(s); goto fail; } + if (fd->has_parameter_expressions) { + if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0) + goto fail; + } + /* XXX: could avoid allocating an argument if rest is true */ idx = add_arg(ctx, fd, name); if (idx < 0) goto fail; @@ -32837,71 +33555,56 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (rest) { emit_op(s, OP_rest); emit_u16(s, idx); + if (fd->has_parameter_expressions) { + emit_op(s, OP_dup); + emit_op(s, OP_scope_put_var_init); + emit_atom(s, name); + emit_u16(s, fd->scope_level); + } emit_op(s, OP_put_arg); emit_u16(s, idx); fd->has_simple_parameter_list = FALSE; has_opt_arg = TRUE; } else if (s->token.val == '=') { + int label; + fd->has_simple_parameter_list = FALSE; has_opt_arg = TRUE; if (next_token(s)) goto fail; - /* optimize `x = void 0` default value: no code needed */ - if (s->token.val == TOK_VOID) { - JSParsePos pos; - js_parse_get_pos(s, &pos); - if (next_token(s)) - goto fail; - if (s->token.val == TOK_NUMBER) { - if (next_token(s)) - goto fail; - if (s->token.val == ',') { - if (next_token(s)) - goto fail; - continue; - } - if (s->token.val == ')') { - continue; - } - } - if (js_parse_seek_token(s, &pos)) - goto fail; - } -#if 0 - /* XXX: not correct for eval code */ - /* Check for a default value of `undefined` - to omit default argument processing */ - if (s->token.val == TOK_IDENT && - s->token.u.ident.atom == JS_ATOM_undefined && - fd->parent == NULL && - ((tok = peek_token(s, FALSE)) == ',' || tok == ')')) { - if (next_token(s)) /* ignore undefined token */ - goto fail; - } else -#endif - { - int label = new_label(s); - if (idx > 0) { - emit_op(s, OP_set_arg_valid_upto); - emit_u16(s, idx); - } + label = new_label(s); emit_op(s, OP_get_arg); emit_u16(s, idx); + emit_op(s, OP_dup); emit_op(s, OP_undefined); emit_op(s, OP_strict_eq); emit_goto(s, OP_if_false, label); - if (js_parse_assign_expr(s, TRUE)) + emit_op(s, OP_drop); + if (js_parse_assign_expr(s)) goto fail; set_object_name(s, name); + emit_op(s, OP_dup); emit_op(s, OP_put_arg); emit_u16(s, idx); emit_label(s, label); - } - } else if (!has_opt_arg) { + emit_op(s, OP_scope_put_var_init); + emit_atom(s, name); + emit_u16(s, fd->scope_level); + } else { + if (!has_opt_arg) { fd->defined_arg_count++; } + if (fd->has_parameter_expressions) { + /* copy the argument to the argument scope */ + emit_op(s, OP_get_arg); + emit_u16(s, idx); + emit_op(s, OP_scope_put_var_init); + emit_atom(s, name); + emit_u16(s, fd->scope_level); + } + } } else { js_parse_error(s, "missing formal parameter"); goto fail; @@ -32922,6 +33625,41 @@ static __exception int js_parse_function_decl2(JSParseState *s, } } + if (fd->has_parameter_expressions) { + int idx; + + /* Copy the variables in the argument scope to the variable + scope (see FunctionDeclarationInstantiation() in spec). The + normal arguments are already present, so no need to copy + them. */ + idx = fd->scopes[fd->scope_level].first; + while (idx >= 0) { + JSVarDef *vd = &fd->vars[idx]; + if (vd->scope_level != fd->scope_level) + break; + if (find_var(ctx, fd, vd->var_name) < 0) { + if (add_var(ctx, fd, vd->var_name) < 0) + goto fail; + vd = &fd->vars[idx]; /* fd->vars may have been reallocated */ + emit_op(s, OP_scope_get_var); + emit_atom(s, vd->var_name); + emit_u16(s, fd->scope_level); + emit_op(s, OP_scope_put_var); + emit_atom(s, vd->var_name); + emit_u16(s, 0); + } + idx = vd->scope_next; + } + + /* the argument scope has no parent, hence we don't use pop_scope(s) */ + emit_op(s, OP_leave_scope); + emit_u16(s, fd->scope_level); + + /* set the variable scope as the current scope */ + fd->scope_level = 0; + fd->scope_first = fd->scopes[fd->scope_level].first; + } + if (next_token(s)) goto fail; @@ -32933,7 +33671,8 @@ static __exception int js_parse_function_decl2(JSParseState *s, /* in generators, yield expression is forbidden during the parsing of the arguments */ fd->in_function_body = TRUE; - push_scope(s); /* enter body scope: fd->scope_level = 1 */ + push_scope(s); /* enter body scope */ + fd->body_scope = fd->scope_level; if (s->token.val == TOK_ARROW) { if (next_token(s)) @@ -32943,7 +33682,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (js_parse_function_check_names(s, fd, func_name)) goto fail; - if (js_parse_assign_expr(s, TRUE)) + if (js_parse_assign_expr(s)) goto fail; if (func_kind != JS_FUNC_NORMAL) @@ -33025,16 +33764,16 @@ static __exception int js_parse_function_decl2(JSParseState *s, emit_u32(s, idx); if (create_func_var) { if (s->cur_func->is_global_var) { - JSHoistedDef *hf; + JSGlobalVar *hf; /* the global variable must be defined at the start of the function */ - hf = add_hoisted_def(ctx, s->cur_func, -1, func_name, -1, FALSE); + hf = add_global_var(ctx, s->cur_func, func_name); if (!hf) goto fail; /* it is considered as defined at the top level (needed for annex B.3.3.4 and B.3.3.5 checks) */ - hf->scope_level = 0; + hf->scope_level = 0; hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0); /* store directly into global var, bypass lexical scope */ emit_op(s, OP_dup); @@ -33058,7 +33797,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, } if (lexical_func_idx >= 0) { /* lexical variable will be initialized upon entering scope */ - s->cur_func->vars[lexical_func_idx].func_pool_or_scope_idx = idx; + s->cur_func->vars[lexical_func_idx].func_pool_idx = idx; emit_op(s, OP_drop); } else { /* store function object into its lexical name */ @@ -33074,17 +33813,23 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (var_idx < 0) goto fail; /* the variable will be assigned at the top of the function */ - if (!add_hoisted_def(ctx, s->cur_func, idx, JS_ATOM_NULL, var_idx, FALSE)) - goto fail; + if (var_idx & ARGUMENT_VAR_OFFSET) { + s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx; + } else { + s->cur_func->vars[var_idx].func_pool_idx = idx; + } } else { JSAtom func_var_name; + JSGlobalVar *hf; if (func_name == JS_ATOM_NULL) func_var_name = JS_ATOM__default_; /* export default */ else func_var_name = func_name; /* the variable will be assigned at the top of the function */ - if (!add_hoisted_def(ctx, s->cur_func, idx, func_var_name, -1, FALSE)) + hf = add_global_var(ctx, s->cur_func, func_var_name); + if (!hf) goto fail; + hf->cpool_idx = idx; if (export_flag != JS_PARSE_EXPORT_NONE) { if (!add_export_entry(s, s->cur_func->module, func_var_name, export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL)) @@ -33156,16 +33901,16 @@ static __exception int js_parse_program(JSParseState *s) static void js_parse_init(JSContext *ctx, JSParseState *s, const char *input, size_t input_len, - const char *filename) + const char *filename, int line_no) { memset(s, 0, sizeof(*s)); s->ctx = ctx; s->filename = filename; - s->line_num = 1; + s->line_num = line_no; s->buf_ptr = (const uint8_t *)input; s->buf_end = s->buf_ptr + input_len; s->token.val = ' '; - s->token.line_num = 1; + s->token.line_num = line_no; } static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, @@ -33186,7 +33931,7 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, JS_FreeValue(ctx, fun_obj); if (js_create_module_function(ctx, m) < 0) goto fail; - if (js_instantiate_module(ctx, m) < 0) + if (js_link_module(ctx, m) < 0) goto fail; ret_val = js_evaluate_module(ctx, m); if (JS_IsException(ret_val)) { @@ -33234,7 +33979,7 @@ static void skip_shebang(JSParseState *s) /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, - const char *filename, int flags, int scope_idx) + const char *filename, int flags, int scope_idx, int line_no) { JSParseState s1, *s = &s1; int err, js_mode, eval_type; @@ -33245,7 +33990,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, JSFunctionDef *fd; JSModuleDef *m; - js_parse_init(ctx, s, input, input_len, filename); + js_parse_init(ctx, s, input, input_len, filename, line_no); skip_shebang(s); eval_type = flags & JS_EVAL_TYPE_MASK; @@ -33308,6 +34053,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, s->allow_html_comments = !s->is_module; push_scope(s); /* body scope */ + fd->body_scope = fd->scope_level; err = js_parse_program(s); if (err) { @@ -33344,13 +34090,13 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, /* the indirection is needed to make 'eval' optional */ static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, - const char *filename, int flags, int scope_idx) + const char *filename, int flags, int scope_idx, int line_no) { if (unlikely(!ctx->eval_internal)) { return JS_ThrowTypeError(ctx, "eval is not supported"); } return ctx->eval_internal(ctx, this_obj, input, input_len, filename, - flags, scope_idx); + flags, scope_idx, line_no); } static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, @@ -33365,12 +34111,26 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj, str = JS_ToCStringLen(ctx, &len, val); if (!str) return JS_EXCEPTION; - ret = JS_EvalInternal(ctx, this_obj, str, len, "", flags, scope_idx); + ret = JS_EvalInternal(ctx, this_obj, str, len, "", flags, scope_idx, 1); JS_FreeCString(ctx, str); return ret; } +JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, + const char *input, size_t input_len, + const char *filename, int eval_flags) +{ + int eval_type = eval_flags & JS_EVAL_TYPE_MASK; + JSValue ret; + + assert(eval_type == JS_EVAL_TYPE_GLOBAL || + eval_type == JS_EVAL_TYPE_MODULE); + ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename, + eval_flags, -1,1); + return ret; +} + JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags) { @@ -33380,10 +34140,24 @@ JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, assert(eval_type == JS_EVAL_TYPE_GLOBAL || eval_type == JS_EVAL_TYPE_MODULE); ret = JS_EvalInternal(ctx, ctx->global_obj, input, input_len, filename, - eval_flags, -1); + eval_flags, -1, 1); return ret; } +JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len, + const char *filename, int eval_flags, int line_no) +{ + int eval_type = eval_flags & JS_EVAL_TYPE_MASK; + JSValue ret; + + assert(eval_type == JS_EVAL_TYPE_GLOBAL || + eval_type == JS_EVAL_TYPE_MODULE); + ret = JS_EvalInternal(ctx, ctx->global_obj, input, input_len, filename, + eval_flags, -1, line_no); + return ret; +} + + int JS_ResolveModule(JSContext *ctx, JSValueConst obj) { if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { @@ -33435,13 +34209,13 @@ static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s, js_free(ctx, s->hash_table); s->hash_table = new_hash_table; s->hash_size = new_hash_size; - + for(i = 0; i < s->hash_size; i++) { s->hash_table[i] = -1; } for(i = 0; i < s->object_count; i++) { e = &s->object_tab[i]; - h = js_object_list_get_hash(e->obj, s->hash_size); + h = js_object_list_get_hash(e->obj, s->hash_size); e->hash_next = s->hash_table[h]; s->hash_table[h] = i; } @@ -33454,7 +34228,7 @@ static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj) { JSObjectListEntry *e; uint32_t h, new_hash_size; - + if (js_resize_array(ctx, (void *)&s->object_tab, sizeof(s->object_tab[0]), &s->object_size, s->object_count + 1)) @@ -33467,7 +34241,7 @@ static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj) return -1; } e = &s->object_tab[s->object_count++]; - h = js_object_list_get_hash(obj, s->hash_size); + h = js_object_list_get_hash(obj, s->hash_size); e->obj = obj; e->hash_next = s->hash_table[h]; s->hash_table[h] = s->object_count - 1; @@ -33483,7 +34257,7 @@ static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj) /* must test empty size because there is no hash table */ if (s->object_count == 0) return -1; - h = js_object_list_get_hash(obj, s->hash_size); + h = js_object_list_get_hash(obj, s->hash_size); p = s->hash_table[h]; while (p != -1) { e = &s->object_tab[p]; @@ -33887,7 +34661,7 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) int bpos, d; uint8_t v8; size_t i0; - + /* little endian BCD */ i = 0; while (i < a->len && a->tab[i] == 0) @@ -33907,7 +34681,7 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) return -1; } bc_put_leb128(s, len); - + bpos = 0; v8 = 0; i0 = i; @@ -33945,7 +34719,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj); uint32_t flags; int idx, i; - + bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE); flags = idx = 0; bc_set_flags(&flags, &idx, b->has_prototype, 1); @@ -33963,7 +34737,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_put_u16(s, flags); bc_put_u8(s, b->js_mode); bc_put_atom(s, b->func_name); - + bc_put_leb128(s, b->arg_count); bc_put_leb128(s, b->var_count); bc_put_leb128(s, b->defined_arg_count); @@ -33972,6 +34746,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_put_leb128(s, b->cpool_count); bc_put_leb128(s, b->byte_code_len); if (b->vardefs) { + /* XXX: this field is redundant */ bc_put_leb128(s, b->arg_count + b->var_count); for(i = 0; i < b->arg_count + b->var_count; i++) { JSVarDef *vd = &b->vardefs[i]; @@ -33980,7 +34755,6 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_put_leb128(s, vd->scope_next + 1); flags = idx = 0; bc_set_flags(&flags, &idx, vd->var_kind, 4); - bc_set_flags(&flags, &idx, vd->is_func_var, 1); bc_set_flags(&flags, &idx, vd->is_const, 1); bc_set_flags(&flags, &idx, vd->is_lexical, 1); bc_set_flags(&flags, &idx, vd->is_captured, 1); @@ -33990,7 +34764,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) } else { bc_put_leb128(s, 0); } - + for(i = 0; i < b->closure_var_count; i++) { JSClosureVar *cv = &b->closure_var[i]; bc_put_atom(s, cv->var_name); @@ -34004,17 +34778,17 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) assert(idx <= 8); bc_put_u8(s, flags); } - + if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len)) goto fail; - + if (b->has_debug) { bc_put_atom(s, b->debug.filename); bc_put_leb128(s, b->debug.line_num); bc_put_leb128(s, b->debug.pc2line_len); dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len); } - + for(i = 0; i < b->cpool_count; i++) { if (JS_WriteObjectRec(s, b->cpool[i])) goto fail; @@ -34028,16 +34802,16 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) { JSModuleDef *m = JS_VALUE_GET_PTR(obj); int i; - + bc_put_u8(s, BC_TAG_MODULE); bc_put_atom(s, m->module_name); - + bc_put_leb128(s, m->req_module_entries_count); for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; bc_put_atom(s, rme->module_name); } - + bc_put_leb128(s, m->export_entries_count); for(i = 0; i < m->export_entries_count; i++) { JSExportEntry *me = &m->export_entries[i]; @@ -34050,13 +34824,13 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) } bc_put_atom(s, me->export_name); } - + bc_put_leb128(s, m->star_export_entries_count); for(i = 0; i < m->star_export_entries_count; i++) { JSStarExportEntry *se = &m->star_export_entries[i]; bc_put_leb128(s, se->req_module_idx); } - + bc_put_leb128(s, m->import_entries_count); for(i = 0; i < m->import_entries_count; i++) { JSImportEntry *mi = &m->import_entries[i]; @@ -34064,7 +34838,7 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) bc_put_atom(s, mi->import_name); bc_put_leb128(s, mi->req_module_idx); } - + if (JS_WriteObjectRec(s, m->func_obj)) goto fail; return 0; @@ -34079,7 +34853,7 @@ static int JS_WriteArray(BCWriterState *s, JSValueConst obj) JSValue val; int ret; BOOL is_template; - + if (s->allow_bytecode && !p->extensible) { /* not extensible array: we consider it is a template when we are saving bytecode */ @@ -34253,7 +35027,7 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) { JSObject *p = JS_VALUE_GET_OBJ(obj); int ret, idx; - + if (s->allow_reference) { idx = js_object_list_find(s->ctx, &s->object_list, p); if (idx >= 0) { @@ -34394,7 +35168,7 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, s->first_atom = 1; js_dbuf_init(ctx, &s->dbuf); js_object_list_init(&s->object_list); - + if (JS_WriteObjectRec(s, obj)) goto fail; if (JS_WriteObjectAtoms(s)) @@ -34442,7 +35216,7 @@ typedef struct BCReaderState { JSObject **objects; int objects_count; int objects_size; - + #ifdef DUMP_READ_OBJECT const uint8_t *ptr_last; int level; @@ -34450,7 +35224,7 @@ typedef struct BCReaderState { } BCReaderState; #ifdef DUMP_READ_OBJECT -static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) { +static void __js_printf_like(2,3) bc_read_trace(BCReaderState *s, const char *fmt, ...) { va_list ap; int i, n, n0; @@ -34727,7 +35501,7 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) limb_t v; bf_t *a; int bpos, d; - + p = js_new_bf(s->ctx); if (!p) goto fail; @@ -34939,11 +35713,21 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) b = js_mallocz(ctx, function_size); if (!b) return JS_EXCEPTION; - + memcpy(b, &bc, offsetof(JSFunctionBytecode, debug)); b->header.ref_count = 1; + if (local_count != 0) { + b->vardefs = (void *)((uint8_t*)b + vardefs_offset); + } + if (b->closure_var_count != 0) { + b->closure_var = (void *)((uint8_t*)b + closure_var_offset); + } + if (b->cpool_count != 0) { + b->cpool = (void *)((uint8_t*)b + cpool_offset); + } + add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); - + obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b); #ifdef DUMP_READ_OBJECT @@ -34957,7 +35741,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) if (local_count != 0) { bc_read_trace(s, "vars {\n"); - b->vardefs = (void *)((uint8_t*)b + vardefs_offset); for(i = 0; i < local_count; i++) { JSVarDef *vd = &b->vardefs[i]; if (bc_get_atom(s, &vd->var_name)) @@ -34971,7 +35754,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) goto fail; idx = 0; vd->var_kind = bc_get_flags(v8, &idx, 4); - vd->is_func_var = bc_get_flags(v8, &idx, 1); vd->is_const = bc_get_flags(v8, &idx, 1); vd->is_lexical = bc_get_flags(v8, &idx, 1); vd->is_captured = bc_get_flags(v8, &idx, 1); @@ -34983,7 +35765,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) } if (b->closure_var_count != 0) { bc_read_trace(s, "closure vars {\n"); - b->closure_var = (void *)((uint8_t*)b + closure_var_offset); for(i = 0; i < b->closure_var_count; i++) { JSClosureVar *cv = &b->closure_var[i]; int var_idx; @@ -35035,7 +35816,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) } if (b->cpool_count != 0) { bc_read_trace(s, "cpool {\n"); - b->cpool = (void *)((uint8_t*)b + cpool_offset); for(i = 0; i < b->cpool_count; i++) { JSValue val; val = JS_ReadObjectRec(s); @@ -35060,7 +35840,7 @@ static JSValue JS_ReadModule(BCReaderState *s) JSAtom module_name; int i; uint8_t v8; - + if (bc_get_atom(s, &module_name)) goto fail; #ifdef DUMP_READ_OBJECT @@ -35161,7 +35941,7 @@ static JSValue JS_ReadObjectTag(BCReaderState *s) JSAtom atom; JSValue val; int ret; - + obj = JS_NewObject(ctx); if (BC_add_object_ref(s, obj)) goto fail; @@ -35241,7 +36021,7 @@ static JSValue JS_ReadTypedArray(BCReaderState *s) uint8_t array_tag; JSValueConst args[3]; uint32_t offset, len, idx; - + if (bc_get_u8(s, &array_tag)) return JS_EXCEPTION; if (array_tag >= JS_TYPED_ARRAY_COUNT) @@ -35286,7 +36066,7 @@ static JSValue JS_ReadArrayBuffer(BCReaderState *s) JSContext *ctx = s->ctx; uint32_t byte_length; JSValue obj; - + if (bc_get_leb128(s, &byte_length)) return JS_EXCEPTION; if (unlikely(s->buf_end - s->ptr < byte_length)) { @@ -35312,7 +36092,7 @@ static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s) uint8_t *data_ptr; JSValue obj; uint64_t u64; - + if (bc_get_leb128(s, &byte_length)) return JS_EXCEPTION; if (bc_get_u64(s, &u64)) @@ -35359,6 +36139,13 @@ static JSValue JS_ReadDate(BCReaderState *s) return JS_EXCEPTION; } +JSValue JS_NewDate(JSContext* ctx, double ms_1970) { + JSValue obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE], JS_CLASS_DATE); + if (!JS_IsException(obj)) + JS_SetObjectData(ctx, obj, JS_NewFloat64(ctx,ms_1970)); + return obj; +} + static JSValue JS_ReadObjectValue(BCReaderState *s) { JSContext *ctx = s->ctx; @@ -35550,8 +36337,8 @@ static void bc_reader_free(BCReaderState *s) js_free(s->ctx, s->objects); } -JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int flags) +JSValue JS_ReadObject2(JSContext *ctx, const uint8_t *buf, size_t buf_len, + int flags, size_t* premnants_len) { BCReaderState ss, *s = &ss; JSValue obj; @@ -35577,10 +36364,19 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, } else { obj = JS_ReadObjectRec(s); } + *premnants_len = s->buf_end - s->ptr; bc_reader_free(s); return obj; } +JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, + int flags) +{ + size_t dummy; + return JS_ReadObject2(ctx, buf, buf_len, flags, &dummy); +} + + /*******************************************************************/ /* runtime functions & objects */ @@ -35628,16 +36424,39 @@ static JSAtom find_atom(JSContext *ctx, const char *name) return atom; } -static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p, +static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) { const JSCFunctionListEntry *e = opaque; - JSValueConst obj = JS_MKPTR(JS_TAG_OBJECT, p); + JSValue val; + + switch(e->def_type) { + case JS_DEF_CFUNC: + val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic, + e->name, e->u.func.length, e->u.func.cproto, e->magic); + break; + case JS_DEF_PROP_STRING: + val = JS_NewAtomString(ctx, e->u.str); + break; + case JS_DEF_OBJECT: + val = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len); + break; + default: + abort(); + } + return val; +} + +static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj, + JSAtom atom, + const JSCFunctionListEntry *e) +{ JSValue val; int prop_flags = e->prop_flags; switch(e->def_type) { - case JS_DEF_ALIAS: + case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */ { JSAtom atom1 = find_atom(ctx, e->u.alias.name); switch (e->u.alias.base) { @@ -35654,12 +36473,16 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p, abort(); } JS_FreeAtom(ctx, atom1); - goto setval; + if (atom == JS_ATOM_Symbol_toPrimitive) { + /* Symbol.toPrimitive functions are not writable */ + prop_flags = JS_PROP_CONFIGURABLE; + } else if (atom == JS_ATOM_Symbol_hasInstance) { + /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */ + prop_flags = 0; } + } + break; case JS_DEF_CFUNC: - val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic, - e->name, e->u.func.length, e->u.func.cproto, e->magic); - setval: if (atom == JS_ATOM_Symbol_toPrimitive) { /* Symbol.toPrimitive functions are not writable */ prop_flags = JS_PROP_CONFIGURABLE; @@ -35667,8 +36490,10 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p, /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */ prop_flags = 0; } - break; - case JS_DEF_CGETSET: + JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP, + (void *)e, prop_flags); + return 0; + case JS_DEF_CGETSET: /* XXX: use autoinit again ? */ case JS_DEF_CGETSET_MAGIC: { JSValue getter, setter; @@ -35692,9 +36517,6 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p, return 0; } break; - case JS_DEF_PROP_STRING: - val = JS_NewAtomString(ctx, e->u.str); - break; case JS_DEF_PROP_INT32: val = JS_NewInt32(ctx, e->u.i32); break; @@ -35707,10 +36529,11 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p, case JS_DEF_PROP_UNDEFINED: val = JS_UNDEFINED; break; + case JS_DEF_PROP_STRING: case JS_DEF_OBJECT: - val = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len); - break; + JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP, + (void *)e, prop_flags); + return 0; default: abort(); } @@ -35721,36 +36544,12 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p, void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, const JSCFunctionListEntry *tab, int len) { - int i, prop_flags; + int i; for (i = 0; i < len; i++) { const JSCFunctionListEntry *e = &tab[i]; JSAtom atom = find_atom(ctx, e->name); - - switch (e->def_type) { - case JS_DEF_CFUNC: - case JS_DEF_CGETSET: - case JS_DEF_CGETSET_MAGIC: - case JS_DEF_PROP_STRING: - case JS_DEF_ALIAS: - case JS_DEF_OBJECT: - prop_flags = JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE | (e->prop_flags & JS_PROP_ENUMERABLE); - JS_DefineAutoInitProperty(ctx, obj, atom, - JS_AUTOINIT_ID_PROP, - (void *)e, prop_flags); - break; - case JS_DEF_PROP_INT32: - case JS_DEF_PROP_INT64: - case JS_DEF_PROP_DOUBLE: - case JS_DEF_PROP_UNDEFINED: - { - JSObject *p = JS_VALUE_GET_OBJ(obj); - JS_InstantiateFunctionListItem(ctx, p, atom, (void *)e); - } - break; - default: - abort(); - } + JS_InstantiateFunctionListItem(ctx, obj, atom, e); JS_FreeAtom(ctx, atom); } } @@ -35819,7 +36618,7 @@ static void JS_SetConstructor2(JSContext *ctx, set_cycle_flag(ctx, proto); } -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, +void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, JSValueConst proto) { JS_SetConstructor2(ctx, func_obj, proto, @@ -36636,7 +37435,7 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, if (!res) { return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false"); } - + p = JS_VALUE_GET_OBJ(obj); flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK; if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags)) @@ -36677,7 +37476,7 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, JSPropertyEnum *props; uint32_t len, i; int flags, res; - + if (!JS_IsObject(obj)) return JS_TRUE; @@ -36706,7 +37505,7 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, if (res < 0) return JS_EXCEPTION; res ^= 1; -done: +done: js_free_prop_enum(ctx, props, len); return JS_NewBool(ctx, res); @@ -36729,14 +37528,14 @@ static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, obj = JS_NewObject(ctx); if (JS_IsException(obj)) return obj; - + iter = JS_GetIterator(ctx, iterable, FALSE); if (JS_IsException(iter)) goto fail; next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); if (JS_IsException(next_method)) goto fail; - + for(;;) { JSValue key, value, item; item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); @@ -36746,7 +37545,7 @@ static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, item); break; } - + key = JS_UNDEFINED; value = JS_UNDEFINED; if (!JS_IsObject(item)) { @@ -37130,7 +37929,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, string_buffer_init(ctx, b, 0); string_buffer_putc8(b, '('); - + if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) { string_buffer_puts8(b, "async "); } @@ -37214,6 +38013,12 @@ static __exception int js_get_length64(JSContext *ctx, int64_t *pres, return JS_ToLengthFree(ctx, pres, len_val); } +int JS_GetPropertyLength(JSContext *ctx, int64_t *pres, JSValueConst obj) +{ + return js_get_length64(ctx, pres, obj); +} + + static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len) { uint32_t i; @@ -37237,6 +38042,10 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, } if (js_get_length32(ctx, &len, array_arg)) return NULL; + if (len > JS_MAX_LOCAL_VARS) { + JS_ThrowInternalError(ctx, "too many arguments"); + return NULL; + } /* avoid allocating 0 bytes */ tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len)); if (!tab) @@ -37262,6 +38071,8 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen, return tab; } +/* magic value: 0 = normal apply, 1 = apply for constructor, 2 = + Reflect.apply */ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) { @@ -37273,14 +38084,14 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; this_arg = argv[0]; array_arg = argv[1]; - if (JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED || - JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) { + if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED || + JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) { return JS_Call(ctx, this_val, this_arg, 0, NULL); } tab = build_arg_list(ctx, &len, array_arg); if (!tab) return JS_EXCEPTION; - if (magic) { + if (magic & 1) { ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab); } else { ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab); @@ -37457,7 +38268,7 @@ static JSValue iterator_to_array(JSContext *ctx, JSValueConst items) JSValue v, r = JS_UNDEFINED; int64_t k; BOOL done; - + iter = JS_GetIterator(ctx, items, FALSE); if (JS_IsException(iter)) goto exception; @@ -37503,7 +38314,7 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, if (!JS_IsObject(proto)) { JSContext *realm; JSValueConst proto1; - + JS_FreeValue(ctx, proto); realm = JS_GetFunctionRealm(ctx, new_target); if (!realm) @@ -37591,7 +38402,7 @@ static JSValue js_aggregate_error_constructor(JSContext *ctx, JSValueConst errors) { JSValue obj; - + obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[JS_AGGREGATE_ERROR], JS_CLASS_ERROR); @@ -37650,7 +38461,7 @@ static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target, return obj; if (argc == 1 && JS_IsNumber(argv[0])) { uint32_t len; - if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]))) + if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE)) goto fail; if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0) goto fail; @@ -37818,6 +38629,18 @@ static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val, return JS_NewBool(ctx, ret); } +static JSValue js_array_isTuple(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + /* isArray and has tag property */ + int ret; + ret = JS_IsTuple(ctx, argv[0]); + if (ret < 0) + return JS_EXCEPTION; + else + return JS_NewBool(ctx, ret); +} + static JSValue js_get_this(JSContext *ctx, JSValueConst this_val) { @@ -37830,7 +38653,7 @@ static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj, JSValue ctor, ret, species; int res; JSContext *realm; - + res = JS_IsArray(ctx, obj); if (res < 0) return JS_EXCEPTION; @@ -37872,6 +38695,7 @@ static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj, static const JSCFunctionListEntry js_array_funcs[] = { JS_CFUNC_DEF("isArray", 1, js_array_isArray ), + JS_CFUNC_DEF("isTuple", 1, js_array_isTuple), JS_CFUNC_DEF("from", 1, js_array_from ), JS_CFUNC_DEF("of", 0, js_array_of ), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), @@ -37995,7 +38819,7 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, this_arg = JS_UNDEFINED; if (argc > 1) this_arg = argv[1]; - + if (check_function(ctx, func)) goto exception; @@ -38035,9 +38859,16 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val, n = 0; for(k = 0; k < len; k++) { + if (special & special_TA) { + val = JS_GetPropertyInt64(ctx, obj, k); + if (JS_IsException(val)) + goto exception; + present = TRUE; + } else { present = JS_TryGetPropertyInt64(ctx, obj, k, &val); if (present < 0) goto exception; + } if (present) { index_val = JS_NewInt64(ctx, k); if (JS_IsException(index_val)) @@ -38155,6 +38986,12 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, } k1 = (special & special_reduceRight) ? len - k - 1 : k; k++; + if (special & special_TA) { + acc = JS_GetPropertyInt64(ctx, obj, k1); + if (JS_IsException(acc)) + goto exception; + break; + } else { present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc); if (present < 0) goto exception; @@ -38162,11 +38999,19 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val, break; } } + } for (; k < len; k++) { k1 = (special & special_reduceRight) ? len - k - 1 : k; + if (special & special_TA) { + val = JS_GetPropertyInt64(ctx, obj, k1); + if (JS_IsException(val)) + goto exception; + present = TRUE; + } else { present = JS_TryGetPropertyInt64(ctx, obj, k1, &val); if (present < 0) goto exception; + } if (present) { index_val = JS_NewInt64(ctx, k1); if (JS_IsException(index_val)) @@ -38518,9 +39363,12 @@ static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val, JSValue *arrp; uint32_t count32; + MARK_MODIFIED_VALUE(this_val); + obj = JS_ToObject(ctx, this_val); if (js_get_length64(ctx, &len, obj)) goto exception; + newLen = 0; if (len > 0) { newLen = len - 1; @@ -38571,6 +39419,46 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val, int64_t len, from, newLen; obj = JS_ToObject(ctx, this_val); + + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { + JSObject *p = JS_VALUE_GET_OBJ(obj); + + MARK_MODIFIED_OBJ(p); + + if (p->class_id != JS_CLASS_ARRAY || + !p->fast_array || !p->extensible) + goto generic_case; + /* length must be writable */ + if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) + goto generic_case; + /* check the length */ + if (unlikely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT)) + goto generic_case; + len = JS_VALUE_GET_INT(p->prop[0].u.value); + /* we don't support holes */ + if (unlikely(len != p->u.array.count)) + goto generic_case; + newLen = len + argc; + if (unlikely(newLen > INT32_MAX)) + goto generic_case; + if (newLen > p->u.array.u1.size) { + if (expand_fast_array(ctx, p, newLen)) + goto exception; + } + if (unshift && argc > 0) { + memmove(p->u.array.u.values + argc, p->u.array.u.values, + len * sizeof(p->u.array.u.values[0])); + from = 0; + } else { + from = len; + } + for(i = 0; i < argc; i++) { + p->u.array.u.values[from + i] = JS_DupValue(ctx, argv[i]); + } + p->u.array.count = newLen; + p->prop[0].u.value = JS_NewInt32(ctx, newLen); + } else { + generic_case: if (js_get_length64(ctx, &len, obj)) goto exception; newLen = len + argc; @@ -38591,7 +39479,7 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val, } if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0) goto exception; - + } JS_FreeValue(ctx, obj); return JS_NewInt64(ctx, newLen); @@ -38609,6 +39497,8 @@ static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val, int l_present, h_present; uint32_t count32; + MARK_MODIFIED_VALUE(this_val); + lval = JS_UNDEFINED; obj = JS_ToObject(ctx, this_val); if (js_get_length64(ctx, &len, obj)) @@ -38687,6 +39577,7 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, goto exception; if (splice) { + MARK_MODIFIED_VALUE(obj); if (argc == 0) { item_count = 0; del_count = 0; @@ -38782,6 +39673,8 @@ static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val, JSValue obj; int64_t len, from, to, final, count; + MARK_MODIFIED_VALUE(this_val); + obj = JS_ToObject(ctx, this_val); if (js_get_length64(ctx, &len, obj)) goto exception; @@ -38821,6 +39714,11 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target, int64_t sourceIndex, elementLen; int present, is_array; + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } + for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) { present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element); if (present < 0) @@ -38998,6 +39896,8 @@ static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val, int64_t i, len, undefined_count = 0; int present; + MARK_MODIFIED_VALUE(this_val); + if (!JS_IsUndefined(asc.method)) { if (check_function(ctx, asc.method)) goto exception; @@ -39659,46 +40559,6 @@ static int js_string_get_own_property(JSContext *ctx, return FALSE; } -static uint32_t js_string_obj_get_length(JSContext *ctx, - JSValueConst obj) -{ - JSObject *p; - JSString *p1; - uint32_t len = 0; - - /* This is a class exotic method: obj class_id is JS_CLASS_STRING */ - p = JS_VALUE_GET_OBJ(obj); - if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) { - p1 = JS_VALUE_GET_STRING(p->u.object_data); - len = p1->len; - } - return len; -} - -static int js_string_get_own_property_names(JSContext *ctx, - JSPropertyEnum **ptab, - uint32_t *plen, - JSValueConst obj) -{ - JSPropertyEnum *tab; - uint32_t len, i; - - len = js_string_obj_get_length(ctx, obj); - tab = NULL; - if (len > 0) { - /* do not allocate 0 bytes */ - tab = js_malloc(ctx, sizeof(JSPropertyEnum) * len); - if (!tab) - return -1; - for(i = 0; i < len; i++) { - tab[i].atom = __JS_AtomFromUInt32(i); - } - } - *ptab = tab; - *plen = len; - return 0; -} - static int js_string_define_own_property(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, @@ -39708,7 +40568,7 @@ static int js_string_define_own_property(JSContext *ctx, uint32_t idx; JSObject *p; JSString *p1, *p2; - + if (__JS_AtomIsTaggedInt(prop)) { idx = __JS_AtomToUInt32(prop); p = JS_VALUE_GET_OBJ(this_obj); @@ -39755,7 +40615,6 @@ static int js_string_delete_property(JSContext *ctx, static const JSClassExoticMethods js_string_exotic_methods = { .get_own_property = js_string_get_own_property, - .get_own_property_names = js_string_get_own_property_names, .define_own_property = js_string_define_own_property, .delete_property = js_string_delete_property, }; @@ -39875,7 +40734,7 @@ static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val, goto exception; if (js_get_length64(ctx, &n, raw) < 0) goto exception; - + for (i = 0; i < n; i++) { val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i)); if (JS_IsException(val)) @@ -40228,7 +41087,7 @@ static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp) { int ret; JSValue flags; - + ret = js_is_regexp(ctx, regexp); if (ret < 0) return -1; @@ -40359,6 +41218,7 @@ static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val string_buffer_concat(b, sp, position + matched_len, sp->len); } else if (c >= '0' && c <= '9') { k = c - '0'; + if (j < len) { c1 = string_get(rp, j); if (c1 >= '0' && c1 <= '9') { /* This behavior is specified in ES6 and refined in ECMA 2019 */ @@ -40370,6 +41230,7 @@ static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val j++; } } + } if (k >= 1 && k < captures_len) { s = JS_GetPropertyInt64(ctx, captures, k); if (JS_IsException(s)) @@ -40500,7 +41361,7 @@ static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val, } if (JS_IsException(repl_str)) goto exception; - + string_buffer_concat(b, sp, endOfLastMatch, pos); string_buffer_concat_value_free(b, repl_str); endOfLastMatch = pos + searchp->len; @@ -41178,7 +42039,7 @@ static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val, static struct { const char *tag, *attr; } const defs[] = { { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL }, { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL }, - { "a", "href" }, { "small", NULL }, { "strike", NULL }, + { "a", "href" }, { "small", NULL }, { "strike", NULL }, { "sub", NULL }, { "sup", NULL }, }; @@ -41345,7 +42206,7 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val, uint32_t tag; if (unlikely(argc == 0)) { - return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0); + return __JS_NewFloat64(ctx, is_max ? -INFINITY : INFINITY); } tag = JS_VALUE_GET_TAG(argv[0]); @@ -41517,12 +42378,15 @@ static JSValue js_math_random(JSContext *ctx, JSValueConst this_val, return __JS_NewFloat64(ctx, u.d - 1.0); } +static double js_math_floor(double x) { return floor(x); } +static double js_math_ceil(double x) { return ceil(x); } + static const JSCFunctionListEntry js_math_funcs[] = { JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ), JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ), JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ), - JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ), - JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ), + JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, js_math_floor), + JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, js_math_ceil ), JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ), JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ), @@ -41597,11 +42461,22 @@ static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val, } /* OS dependent. d = argv[0] is in ms from 1970. Return the difference - between local time and UTC time 'd' in minutes */ + between UTC time and local time 'd' in minutes */ static int getTimezoneOffset(int64_t time) { #if defined(_WIN32) - /* XXX: TODO */ - return 0; + TIME_ZONE_INFORMATION tzi; + memset(&tzi, 0, sizeof(tzi)); + DWORD ctz = GetTimeZoneInformation(&tzi); + int r = tzi.Bias; // in minutes + switch (ctz) { + case TIME_ZONE_ID_STANDARD: + r += tzi.StandardBias; + break; + case TIME_ZONE_ID_DAYLIGHT: + r += tzi.DaylightBias; + break; + } + return r; #else time_t ti; struct tm tm; @@ -41978,7 +42853,7 @@ static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val) if (p->len == 0) { empty_regex: return JS_NewString(ctx, "(?:)"); - } + } string_buffer_init2(ctx, b, p->len, p->is_wide_char); /* Escape '/' and newline sequences as needed */ @@ -42037,7 +42912,7 @@ static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mas else return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP); } - + flags = lre_get_flags(re->bytecode->u.str8); return JS_NewBool(ctx, (flags & mask) != 0); } @@ -42564,7 +43439,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, JSString *strp; int64_t lastIndex; JSRegExpStringIteratorData *it; - + if (!JS_IsObject(R)) return JS_ThrowTypeErrorNotAnObject(ctx); @@ -42572,7 +43447,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, flags = JS_UNDEFINED; matcher = JS_UNDEFINED; iter = JS_UNDEFINED; - + S = JS_ToString(ctx, argv[0]); if (JS_IsException(S)) goto exception; @@ -42593,7 +43468,7 @@ static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex, JS_NewInt64(ctx, lastIndex)) < 0) goto exception; - + iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR); if (JS_IsException(iter)) goto exception; @@ -42731,7 +43606,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, str = JS_ToString(ctx, argv[0]); if (JS_IsException(str)) goto exception; - + sp = JS_VALUE_GET_STRING(str); rp = NULL; functionalReplace = JS_IsFunction(ctx, rep); @@ -42805,7 +43680,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, tab = JS_NewArray(ctx); if (JS_IsException(tab)) goto exception; - if (JS_SetPropertyInt64(ctx, tab, 0, JS_DupValue(ctx, matched)) < 0) + if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched), + JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; for(n = 1; n < nCaptures; n++) { JSValue capN; @@ -42817,7 +43693,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, if (JS_IsException(capN)) goto exception; } - if (JS_SetPropertyInt64(ctx, tab, n, capN) < 0) + if (JS_DefinePropertyValueInt64(ctx, tab, n, capN, + JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; } JS_FreeValue(ctx, namedCaptures); @@ -42825,12 +43702,12 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, if (JS_IsException(namedCaptures)) goto exception; if (functionalReplace) { - if (JS_SetPropertyInt64(ctx, tab, n++, JS_NewInt32(ctx, position)) < 0) + if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; - if (JS_SetPropertyInt64(ctx, tab, n++, JS_DupValue(ctx, str)) < 0) + if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; if (!JS_IsUndefined(namedCaptures)) { - if (JS_SetPropertyInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures)) < 0) + if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; } args[0] = JS_UNDEFINED; @@ -42917,9 +43794,11 @@ static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val, if (js_same_value(ctx, currentLastIndex, previousLastIndex)) { JS_FreeValue(ctx, previousLastIndex); } else { - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) + if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) { + previousLastIndex = JS_UNDEFINED; goto exception; } + } JS_FreeValue(ctx, str); JS_FreeValue(ctx, currentLastIndex); @@ -43006,7 +43885,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, while (q < size) { if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0) goto exception; - JS_FreeValue(ctx, z); + JS_FreeValue(ctx, z); z = JS_RegExpExec(ctx, splitter, str); if (JS_IsException(z)) goto exception; @@ -43023,7 +43902,8 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, sub = js_sub_string(ctx, strp, p, q); if (JS_IsException(sub)) goto exception; - if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0) + if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, + JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; if (lengthA == lim) goto done; @@ -43034,7 +43914,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i)); if (JS_IsException(sub)) goto exception; - if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0) + if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; if (lengthA == lim) goto done; @@ -43049,7 +43929,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, sub = js_sub_string(ctx, strp, p, size); if (JS_IsException(sub)) goto exception; - if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0) + if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0) goto exception; goto done; exception: @@ -43060,7 +43940,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, ctor); JS_FreeValue(ctx, splitter); JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, z); + JS_FreeValue(ctx, z); return A; } @@ -43145,7 +44025,7 @@ static JSValue json_parse_value(JSParseState *s) { JSValue prop_val; JSAtom prop_name; - + if (json_next_token(s)) goto fail; val = JS_NewObject(ctx); @@ -43267,7 +44147,7 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, JSParseState s1, *s = &s1; JSValue val = JS_UNDEFINED; - js_parse_init(ctx, s, buf, buf_len, filename); + js_parse_init(ctx, s, buf, buf_len, filename, 1); s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0); if (json_next_token(s)) goto fail; @@ -43288,7 +44168,7 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len, JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, const char *filename) { - return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); + return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); } static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder, @@ -43481,7 +44361,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, int64_t i, len; int cl, ret; BOOL has_content; - + indent1 = JS_UNDEFINED; sep = JS_UNDEFINED; sep1 = JS_UNDEFINED; @@ -43656,7 +44536,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, JS_FreeValue(ctx, val); return 0; } - + exception: JS_FreeValue(ctx, val); JS_FreeValue(ctx, tab); @@ -43774,7 +44654,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0) goto exception; val = JS_DupValue(ctx, obj); - + val = js_json_check(ctx, jsc, wrapper, val, jsc->empty); if (JS_IsException(val)) goto exception; @@ -43829,7 +44709,7 @@ void JS_AddIntrinsicJSON(JSContext *ctx) static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 0); + return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2); } static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val, @@ -43941,7 +44821,7 @@ static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val, atom = JS_ValueToAtom(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; - ret = JS_SetPropertyGeneric(ctx, JS_VALUE_GET_OBJ(obj), atom, + ret = JS_SetPropertyGeneric(ctx, obj, atom, JS_DupValue(ctx, val), receiver, 0); JS_FreeAtom(ctx, atom); if (ret < 0) @@ -44030,7 +44910,7 @@ static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod, JS_ThrowStackOverflow(ctx); return NULL; } - + /* 's' should never be NULL */ if (s->is_revoked) { JS_ThrowTypeErrorRevokedProxy(ctx); @@ -44289,7 +45169,7 @@ static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom, if (!s) return -1; if (JS_IsUndefined(method)) { - return JS_SetPropertyGeneric(ctx, JS_VALUE_GET_OBJ(s->target), atom, + return JS_SetPropertyGeneric(ctx, s->target, atom, JS_DupValue(ctx, value), receiver, flags); } @@ -44429,7 +45309,7 @@ static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc JS_FreeValue(ctx, trap_result_obj); if (res < 0) return -1; - + if (target_desc_ret) { /* convert result_desc.flags to defineProperty flags */ flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE; @@ -44794,7 +45674,7 @@ static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj, if (flags & JS_CALL_FLAG_CONSTRUCTOR) return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv); - + s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply); if (!s) return JS_EXCEPTION; @@ -45379,7 +46259,7 @@ static void reset_weak_ref(JSRuntime *rt, JSObject *p) { JSMapRecord *mr, *mr_next; JSMapState *s; - + /* first pass to remove the records from the WeakMap/WeakSet lists */ for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) { @@ -45389,7 +46269,7 @@ static void reset_weak_ref(JSRuntime *rt, JSObject *p) list_del(&mr->hash_link); list_del(&mr->link); } - + /* second pass to free the values to avoid modifying the weak reference list while traversing it. */ for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) { @@ -46388,7 +47268,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, JSValueConst resolve_element_env = func_data[4]; JSValue ret, obj; int is_zero, index; - + if (JS_ToInt32(ctx, &index, func_data[1])) return JS_EXCEPTION; if (alreadyCalled) @@ -46397,7 +47277,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, if (resolve_type == PROMISE_MAGIC_allSettled) { JSValue str; - + obj = JS_NewObject(ctx); if (JS_IsException(obj)) return JS_EXCEPTION; @@ -46422,7 +47302,7 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, if (JS_DefinePropertyValueUint32(ctx, values, index, obj, JS_PROP_C_W_E) < 0) return JS_EXCEPTION; - + is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1); if (is_zero < 0) return JS_EXCEPTION; @@ -46455,7 +47335,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, JSValueConst then_args[2], resolve_element_data[5]; BOOL done; int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any); - + if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); @@ -46491,7 +47371,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, JS_NewInt32(ctx, 1), JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0) goto fail_reject; - + index = 0; for(;;) { /* XXX: conformance: should close the iterator if error on 'done' @@ -46501,7 +47381,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, goto fail_reject; if (done) break; - next_promise = JS_Call(ctx, promise_resolve, + next_promise = JS_Call(ctx, promise_resolve, this_val, 1, (JSValueConst *)&item); JS_FreeValue(ctx, item); if (JS_IsException(next_promise)) { @@ -46521,7 +47401,7 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, next_promise); goto fail_reject1; } - + if (magic == PROMISE_MAGIC_allSettled) { reject_element = JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1, @@ -46772,26 +47652,15 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va { JSValueConst ctor = func_data[0]; JSValueConst onFinally = func_data[1]; - JSValue res, promise, resolving_funcs[2], ret, then_func; + JSValue res, promise, ret, then_func; res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL); if (JS_IsException(res)) return res; - promise = js_new_promise_capability(ctx, resolving_funcs, ctor); - if (JS_IsException(promise)) { - JS_FreeValue(ctx, res); - return JS_EXCEPTION; - } - ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, - 1, (JSValueConst*)&res); + promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0); JS_FreeValue(ctx, res); - JS_FreeValue(ctx, resolving_funcs[0]); - JS_FreeValue(ctx, resolving_funcs[1]); - if (JS_IsException(ret)) { - JS_FreeValue(ctx, promise); - return ret; - } - JS_FreeValue(ctx, ret); + if (JS_IsException(promise)) + return promise; if (magic == 0) { then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0, 0, 1, argv); @@ -47185,7 +48054,7 @@ static int isURIReserved(int c) { return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL; } -static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...) +static int __js_printf_like(2,3) js_throw_URIError(JSContext *ctx, const char *fmt, ...) { va_list ap; @@ -47458,7 +48327,7 @@ static const JSCFunctionListEntry js_global_funcs[] = { JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ), JS_CFUNC_DEF("escape", 1, js_global_escape ), JS_CFUNC_DEF("unescape", 1, js_global_unescape ), - JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ), + JS_PROP_DOUBLE_DEF("Infinity", INFINITY, 0 ), JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ), JS_PROP_UNDEFINED_DEF("undefined", 0 ), @@ -47486,7 +48355,7 @@ static int64_t floor_div(int64_t a, int64_t b) { static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); -static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val) +__exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val) { if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) { JSObject *p = JS_VALUE_GET_OBJ(this_val); @@ -47503,7 +48372,7 @@ static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double JSObject *p = JS_VALUE_GET_OBJ(this_val); if (p->class_id == JS_CLASS_DATE) { JS_FreeValue(ctx, p->u.object_data); - p->u.object_data = __JS_NewFloat64(ctx, v); + p->u.object_data = JS_NewFloat64(ctx, v); return JS_DupValue(ctx, p->u.object_data); } } @@ -47547,7 +48416,7 @@ static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; static char const day_names[] = "SunMonTueWedThuFriSat"; static __exception int get_date_fields(JSContext *ctx, JSValueConst obj, - int64_t fields[9], int is_local, int force) + double fields[9], int is_local, int force) { double dval; int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0; @@ -47606,12 +48475,18 @@ static double time_clip(double t) { return NAN; } -static double set_date_fields(int64_t fields[], int is_local) { - int64_t days, y, m, md, h, d, i; +/* The spec mandates the use of 'double' and it fixes the order + of the operations */ +static double set_date_fields(double fields[], int is_local) { + int64_t y; + double days, d, h, m1; + int i, m, md; - i = fields[1]; - m = math_mod(i, 12); - y = fields[0] + (i - m) / 12; + m1 = fields[1]; + m = fmod(m1, 12); + if (m < 0) + m += 12; + y = (int64_t)(fields[0] + floor(m1 / 12)); days = days_from_year(y); for(i = 0; i < m; i++) { @@ -47621,7 +48496,8 @@ static double set_date_fields(int64_t fields[], int is_local) { days += md; } days += fields[2] - 1; - h = ((fields[3] * 60 + fields[4]) * 60 + fields[5]) * 1000 + fields[6]; + h = fields[3] * 3600000 + fields[4] * 60000 + + fields[5] * 1000 + fields[6]; d = days * 86400000 + h; if (is_local) d += getTimezoneOffset(d) * 60000; @@ -47632,7 +48508,7 @@ static JSValue get_date_field(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) { // get_date_field(obj, n, is_local) - int64_t fields[9]; + double fields[9]; int res, n, is_local; is_local = magic & 0x0F; @@ -47646,14 +48522,14 @@ static JSValue get_date_field(JSContext *ctx, JSValueConst this_val, if (magic & 0x100) { // getYear fields[0] -= 1900; } - return JS_NewInt64(ctx, fields[n]); + return JS_NewFloat64(ctx, fields[n]); } static JSValue set_date_field(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) { // _field(obj, first_field, end_field, args, is_local) - int64_t fields[9]; + double fields[9]; int res, first_field, end_field, is_local, i, n; double d, a; @@ -47695,7 +48571,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, { // _string(obj, fmt, part) char buf[64]; - int64_t fields[9]; + double fields[9]; int res, fmt, part, pos; int y, mon, d, h, m, s, ms, wd, tz; @@ -47843,7 +48719,7 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target, } val = time_clip(val); } else { - int64_t fields[] = { 0, 0, 1, 0, 0, 0, 0 }; + double fields[] = { 0, 0, 1, 0, 0, 0, 0 }; if (n > 7) n = 7; for(i = 0; i < n; i++) { @@ -47862,12 +48738,12 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target, JSValueConst args[3]; args[0] = new_target; args[1] = ctx->class_proto[JS_CLASS_DATE]; - args[2] = __JS_NewFloat64(ctx, val); + args[2] = JS_NewFloat64(ctx, val); rv = js___date_create(ctx, JS_UNDEFINED, 3, args); #else rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE); if (!JS_IsException(rv)) - JS_SetObjectData(ctx, rv, __JS_NewFloat64(ctx, val)); + JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val)); #endif if (!JS_IsException(rv) && JS_IsUndefined(new_target)) { /* invoked as a function, return (new Date()).toString(); */ @@ -47883,7 +48759,7 @@ static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { // UTC(y, mon, d, h, m, s, ms) - int64_t fields[] = { 0, 0, 1, 0, 0, 0, 0 }; + double fields[] = { 0, 0, 1, 0, 0, 0, 0 }; int i, n; double a; @@ -47901,7 +48777,7 @@ static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val, if (i == 0 && fields[0] >= 0 && fields[0] < 100) fields[0] += 1900; } - return __JS_NewFloat64(ctx, set_date_fields(fields, 0)); + return JS_NewFloat64(ctx, set_date_fields(fields, 0)); } static void string_skip_spaces(JSString *sp, int *pp) { @@ -47914,24 +48790,22 @@ static void string_skip_non_spaces(JSString *sp, int *pp) { *pp += 1; } -/* parse a numeric field */ -static int string_get_field(JSString *sp, int *pp, int64_t *pval) { +/* parse a numeric field with an optional sign if accept_sign is TRUE */ +static int string_get_digits(JSString *sp, int *pp, int64_t *pval) { int64_t v = 0; - int c, p = *pp; + int c, p = *pp, p_start; - /* skip non digits, should only skip spaces? */ - while (p < sp->len) { - c = string_get(sp, p); - if (c >= '0' && c <= '9') - break; - p++; - } if (p >= sp->len) return -1; + p_start = p; while (p < sp->len) { c = string_get(sp, p); - if (!(c >= '0' && c <= '9')) + if (!(c >= '0' && c <= '9')) { + if (p == p_start) + return -1; + else break; + } v = v * 10 + c - '0'; p++; } @@ -47940,8 +48814,25 @@ static int string_get_field(JSString *sp, int *pp, int64_t *pval) { return 0; } +static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) { + int res, sgn, p = *pp; + + if (p >= sp->len) + return -1; + + sgn = string_get(sp, p); + if (sgn == '-' || sgn == '+') + p++; + + res = string_get_digits(sp, &p, pval); + if (res == 0 && sgn == '-') + *pval = -*pval; + *pp = p; + return res; +} + /* parse a fixed width numeric field */ -static int string_get_digits(JSString *sp, int *pp, int n, int64_t *pval) { +static int string_get_fixed_width_digits(JSString *sp, int *pp, int n, int64_t *pval) { int64_t v = 0; int i, c, p = *pp; @@ -47959,23 +48850,32 @@ static int string_get_digits(JSString *sp, int *pp, int n, int64_t *pval) { return 0; } -/* parse a signed numeric field */ -static int string_get_signed_field(JSString *sp, int *pp, int64_t *pval) { - int sgn, res; - - if (*pp >= sp->len) +static int string_get_milliseconds(JSString *sp, int *pp, int64_t *pval) { + /* parse milliseconds as a fractional part, round to nearest */ + /* XXX: the spec does not indicate which rounding should be used */ + int mul = 1000, ms = 0, p = *pp, c, p_start; + if (p >= sp->len) return -1; - - sgn = string_get(sp, *pp); - if (sgn == '-' || sgn == '+') - *pp += 1; - - res = string_get_field(sp, pp, pval); - if (res == 0 && sgn == '-') - *pval = -*pval; - return res; + p_start = p; + while (p < sp->len) { + c = string_get(sp, p); + if (!(c >= '0' && c <= '9')) { + if (p == p_start) + return -1; + else + break; + } + if (mul == 1 && c >= '5') + ms += 1; + ms += (c - '0') * (mul /= 10); + p++; + } + *pval = ms; + *pp = p; + return 0; } + static int find_abbrev(JSString *sp, int p, const char *list, int count) { int n, i; @@ -48011,67 +48911,92 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, // parse(s) JSValue s, rv; int64_t fields[] = { 0, 1, 1, 0, 0, 0, 0 }; + double fields1[7]; int64_t tz, hh, mm; double d; - int p, i, c, sgn; + int p, i, c, sgn, l; JSString *sp; BOOL is_local; - + rv = JS_NAN; s = JS_ToString(ctx, argv[0]); if (JS_IsException(s)) return JS_EXCEPTION; - + sp = JS_VALUE_GET_STRING(s); p = 0; if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) { /* ISO format */ /* year field can be negative */ - /* XXX: could be stricter */ - if (string_get_signed_field(sp, &p, &fields[0])) + if (string_get_signed_digits(sp, &p, &fields[0])) goto done; - is_local = TRUE; - for (i = 1; i < 6; i++) { - if (string_get_field(sp, &p, &fields[i])) + for (i = 1; i < 7; i++) { + if (p >= sp->len) + break; + switch(i) { + case 1: + case 2: + c = '-'; + break; + case 3: + c = 'T'; + break; + case 4: + case 5: + c = ':'; + break; + case 6: + c = '.'; break; } - if (i <= 3) { - /* no time: UTC by default */ - is_local = FALSE; - } else if (i == 6 && p < sp->len && string_get(sp, p) == '.') { - /* parse milliseconds as a fractional part, round to nearest */ - /* XXX: the spec does not indicate which rounding should be used */ - int mul = 1000, ms = 0; - while (++p < sp->len) { - int c = string_get(sp, p); - if (!(c >= '0' && c <= '9')) + if (string_get(sp, p) != c) break; - if (mul == 1 && c >= '5') - ms += 1; - ms += (c - '0') * (mul /= 10); + p++; + if (i == 6) { + if (string_get_milliseconds(sp, &p, &fields[i])) + goto done; + } else { + if (string_get_digits(sp, &p, &fields[i])) + goto done; } - fields[6] = ms; } + /* no time: UTC by default */ + is_local = (i > 3); fields[1] -= 1; - /* parse the time zone offset if present: [+-]HH:mm */ + /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */ tz = 0; if (p < sp->len) { sgn = string_get(sp, p); if (sgn == '+' || sgn == '-') { - if (string_get_field(sp, &p, &hh)) + p++; + l = sp->len - p; + if (l != 4 && l != 5) goto done; - if (string_get_field(sp, &p, &mm)) + if (string_get_fixed_width_digits(sp, &p, 2, &hh)) + goto done; + if (l == 5) { + if (string_get(sp, p) != ':') + goto done; + p++; + } + if (string_get_fixed_width_digits(sp, &p, 2, &mm)) goto done; tz = hh * 60 + mm; if (sgn == '-') tz = -tz; is_local = FALSE; } else if (sgn == 'Z') { + p++; is_local = FALSE; + } else { + goto done; } + /* error if extraneous characters */ + if (p != sp->len) + goto done; } } else { /* toString or toUTCString format */ @@ -48083,7 +49008,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, c = string_get(sp, p); if (c >= '0' && c <= '9') { /* day of month first */ - if (string_get_field(sp, &p, &fields[2])) + if (string_get_digits(sp, &p, &fields[2])) goto done; if (string_get_month(sp, &p, &fields[1])) goto done; @@ -48091,16 +49016,26 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, /* month first */ if (string_get_month(sp, &p, &fields[1])) goto done; - if (string_get_field(sp, &p, &fields[2])) + string_skip_spaces(sp, &p); + if (string_get_digits(sp, &p, &fields[2])) goto done; } + /* year */ string_skip_spaces(sp, &p); - if (string_get_signed_field(sp, &p, &fields[0])) + if (string_get_signed_digits(sp, &p, &fields[0])) goto done; /* hour, min, seconds */ + string_skip_spaces(sp, &p); for(i = 0; i < 3; i++) { - if (string_get_field(sp, &p, &fields[3 + i])) + if (i == 1 || i == 2) { + if (p >= sp->len) + goto done; + if (string_get(sp, p) != ':') + goto done; + p++; + } + if (string_get_digits(sp, &p, &fields[3 + i])) goto done; } // XXX: parse optional milliseconds? @@ -48112,9 +49047,9 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, sgn = string_get(sp, p); if (sgn == '+' || sgn == '-') { p++; - if (string_get_digits(sp, &p, 2, &hh)) + if (string_get_fixed_width_digits(sp, &p, 2, &hh)) goto done; - if (string_get_digits(sp, &p, 2, &mm)) + if (string_get_fixed_width_digits(sp, &p, 2, &mm)) goto done; tz = hh * 60 + mm; if (sgn == '-') @@ -48123,8 +49058,10 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val, } } } - d = set_date_fields(fields, is_local) - tz * 60000; - rv = __JS_NewFloat64(ctx, d); + for(i = 0; i < 7; i++) + fields1[i] = fields[i]; + d = set_date_fields(fields1, is_local) - tz * 60000; + rv = JS_NewFloat64(ctx, d); done: JS_FreeValue(ctx, s); @@ -48194,7 +49131,7 @@ static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val, if (JS_ThisTimeValue(ctx, &v, this_val)) return JS_EXCEPTION; - return __JS_NewFloat64(ctx, v); + return JS_NewFloat64(ctx, v); } static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val, @@ -48223,7 +49160,7 @@ static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val, if (y >= 0 && y < 100) y += 1900; } - args[0] = __JS_NewFloat64(ctx, y); + args[0] = JS_NewFloat64(ctx, y); return set_date_field(ctx, this_val, 1, args, 0x011); } @@ -48350,7 +49287,7 @@ static void js_operator_set_finalizer(JSRuntime *rt, JSValue val) JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET); int i, j; JSBinaryOperatorDefEntry *ent; - + if (opset) { for(i = 0; i < JS_OVOP_COUNT; i++) { if (opset->self_ops[i]) @@ -48382,7 +49319,7 @@ static void js_operator_set_mark(JSRuntime *rt, JSValueConst val, JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET); int i, j; JSBinaryOperatorDefEntry *ent; - + if (opset) { for(i = 0; i < JS_OVOP_COUNT; i++) { if (opset->self_ops[i]) @@ -48482,7 +49419,7 @@ static JSValue js_operators_create_internal(JSContext *ctx, } op_count = opset1->operator_counter; JS_FreeValue(ctx, prop); - + /* we assume there are few entries */ new_tab = js_realloc(ctx, def->tab, (def->count + 1) * sizeof(def->tab[0])); @@ -48493,7 +49430,7 @@ static JSValue js_operators_create_internal(JSContext *ctx, ent = def->tab + def->count - 1; memset(ent, 0, sizeof(def->tab[0])); ent->operator_index = op_count; - + for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) { prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]); @@ -48530,7 +49467,7 @@ static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst t const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW }; JSOverloadableOperatorEnum op; int i; - + opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT], JS_ATOM_Symbol_operatorSet); if (JS_IsException(opset_obj)) @@ -48660,7 +49597,7 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) case JS_TAG_BIG_FLOAT: { bf_t *a, a_s; - + a = JS_ToBigFloat(ctx, &a_s, val); if (!bf_is_finite(a)) { JS_FreeValue(ctx, val); @@ -48714,9 +49651,11 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) } static JSValue js_bigint_constructor(JSContext *ctx, - JSValueConst this_val, + JSValueConst new_target, int argc, JSValueConst *argv) { + if (!JS_IsUndefined(new_target)) + return JS_ThrowTypeError(ctx, "not a constructor"); return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0])); } @@ -48773,7 +49712,7 @@ static JSValue js_bigint_div(JSContext *ctx, bf_t a_s, b_s, *a, *b, *r, *q; int status; JSValue q_val, r_val; - + q_val = JS_NewBigInt(ctx); if (JS_IsException(q_val)) return JS_EXCEPTION; @@ -48824,7 +49763,7 @@ static JSValue js_bigint_sqrt(JSContext *ctx, bf_t a_s, *a, *r, *rem; int status; JSValue r_val, rem_val; - + r_val = JS_NewBigInt(ctx); if (JS_IsException(r_val)) return JS_EXCEPTION; @@ -48902,7 +49841,7 @@ static JSValue js_bigint_asUintN(JSContext *ctx, uint64_t bits; bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s; JSValue res; - + if (JS_ToIndex(ctx, &bits, argv[0])) return JS_EXCEPTION; res = JS_NewBigInt(ctx); @@ -48962,20 +49901,19 @@ static const JSCFunctionListEntry js_bigint_proto_funcs[] = { void JS_AddIntrinsicBigInt(JSContext *ctx) { JSRuntime *rt = ctx->rt; - JSValue obj1; + JSValueConst obj1; rt->bigint_ops.to_string = js_bigint_to_string; rt->bigint_ops.from_string = js_string_to_bigint; rt->bigint_ops.unary_arith = js_unary_arith_bigint; rt->bigint_ops.binary_arith = js_binary_arith_bigint; rt->bigint_ops.compare = js_compare_bigfloat; - + ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT], js_bigint_proto_funcs, countof(js_bigint_proto_funcs)); - obj1 = JS_NewCFunction(ctx, js_bigint_constructor, "BigInt", 1); - JS_NewGlobalCConstructor2(ctx, obj1, "BigInt", + obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1, ctx->class_proto[JS_CLASS_BIG_INT]); JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs, countof(js_bigint_funcs)); @@ -49194,10 +50132,12 @@ static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = { }; static JSValue js_bigfloat_constructor(JSContext *ctx, - JSValueConst this_val, + JSValueConst new_target, int argc, JSValueConst *argv) { JSValue val; + if (!JS_IsUndefined(new_target)) + return JS_ThrowTypeError(ctx, "not a constructor"); if (argc == 0) { bf_t *r; val = JS_NewBigFloat(ctx); @@ -49393,7 +50333,7 @@ static JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val, { JSValueConst val = argv[0]; JSBigFloat *p; - + if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT) return JS_FALSE; p = JS_VALUE_GET_PTR(val); @@ -49405,7 +50345,7 @@ static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val, { JSValueConst val = argv[0]; JSBigFloat *p; - + if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT) return JS_FALSE; p = JS_VALUE_GET_PTR(val); @@ -49858,9 +50798,8 @@ static const JSCFunctionListEntry js_float_env_proto_funcs[] = { void JS_AddIntrinsicBigFloat(JSContext *ctx) { JSRuntime *rt = ctx->rt; - JSValue obj1; - JSValueConst obj2; - + JSValueConst obj1; + rt->bigfloat_ops.to_string = js_bigfloat_to_string; rt->bigfloat_ops.from_string = js_string_to_bigfloat; rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat; @@ -49868,13 +50807,12 @@ void JS_AddIntrinsicBigFloat(JSContext *ctx) rt->bigfloat_ops.compare = js_compare_bigfloat; rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64; rt->bigfloat_ops.mul_pow10 = js_mul_pow10; - + ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT], js_bigfloat_proto_funcs, countof(js_bigfloat_proto_funcs)); - obj1 = JS_NewCFunction(ctx, js_bigfloat_constructor, "BigFloat", 1); - JS_NewGlobalCConstructor2(ctx, obj1, "BigFloat", + obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1, ctx->class_proto[JS_CLASS_BIG_FLOAT]); JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs, countof(js_bigfloat_funcs)); @@ -49883,10 +50821,10 @@ void JS_AddIntrinsicBigFloat(JSContext *ctx) JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV], js_float_env_proto_funcs, countof(js_float_env_proto_funcs)); - obj2 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv", + obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv", js_float_env_constructor, 1, ctx->class_proto[JS_CLASS_FLOAT_ENV]); - JS_SetPropertyFunctionList(ctx, obj2, js_float_env_funcs, + JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs, countof(js_float_env_funcs)); } @@ -49989,10 +50927,12 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, } static JSValue js_bigdecimal_constructor(JSContext *ctx, - JSValueConst this_val, + JSValueConst new_target, int argc, JSValueConst *argv) { JSValue val; + if (!JS_IsUndefined(new_target)) + return JS_ThrowTypeError(ctx, "not a constructor"); if (argc == 0) { bfdec_t *r; val = JS_NewBigDecimal(ctx); @@ -50043,7 +50983,7 @@ static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj) const char *str; size_t size; int rnd_mode; - + str = JS_ToCStringLen(ctx, &size, obj); if (!str) return -1; @@ -50083,7 +51023,7 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, int64_t val; BOOL has_prec; int rnd_mode; - + if (!JS_IsObject(obj)) { JS_ThrowTypeErrorNotAnObject(ctx); return -1; @@ -50096,7 +51036,7 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe, if (rnd_mode < 0) return -1; fe->flags = rnd_mode; - + prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits); if (JS_IsException(prop)) return -1; @@ -50151,7 +51091,7 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val, op_count = 1; else op_count = 2; - + op1 = JS_ToNumeric(ctx, argv[0]); if (JS_IsException(op1)) return op1; @@ -50348,7 +51288,7 @@ static const JSCFunctionListEntry js_bigdecimal_funcs[] = { void JS_AddIntrinsicBigDecimal(JSContext *ctx) { JSRuntime *rt = ctx->rt; - JSValue obj1; + JSValueConst obj1; rt->bigdecimal_ops.to_string = js_bigdecimal_to_string; rt->bigdecimal_ops.from_string = js_string_to_bigdecimal; @@ -50360,8 +51300,8 @@ void JS_AddIntrinsicBigDecimal(JSContext *ctx) JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL], js_bigdecimal_proto_funcs, countof(js_bigdecimal_proto_funcs)); - obj1 = JS_NewCFunction(ctx, js_bigdecimal_constructor, "BigDecimal", 1); - JS_NewGlobalCConstructor2(ctx, obj1, "BigDecimal", + obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal", + js_bigdecimal_constructor, 1, ctx->class_proto[JS_CLASS_BIG_DECIMAL]); JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs, countof(js_bigdecimal_funcs)); @@ -50818,8 +51758,7 @@ static JSValue js_array_buffer_get_byteLength(JSContext *ctx, JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id); if (!abuf) return JS_EXCEPTION; - if (abuf->detached) - return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + /* return 0 if detached */ return JS_NewUint32(ctx, abuf->byte_length); } @@ -50950,9 +51889,35 @@ static JSValue js_array_buffer_slice(JSContext *ctx, return JS_EXCEPTION; } +static JSValue js_array_buffer_compare(JSContext *ctx, + JSValueConst this_val, + int argc, JSValueConst *argv) +{ + if (argc == 0) { + TYPE_ERROR: + JS_ThrowTypeError(ctx, "ArrayBuffer expected"); + return JS_EXCEPTION; + } + + size_t sizet; + uint8_t *pt = JS_GetArrayBuffer(ctx, &sizet, this_val); + if (!pt) goto TYPE_ERROR; + + size_t size; + uint8_t *p = JS_GetArrayBuffer(ctx, &size, argv[0]); + if (!p) goto TYPE_ERROR; + + if (sizet < size) return JS_NewInt32(ctx, -1); + if (sizet > size) return JS_NewInt32(ctx, 1); + + return JS_NewInt32(ctx, memcmp(pt, p, size)); + +} + static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = { JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ), JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ), + JS_CFUNC_DEF("compare", 1, js_array_buffer_compare), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ), }; @@ -51109,7 +52074,7 @@ JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, } return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); } - + static JSValue js_typed_array_get_toStringTag(JSContext *ctx, JSValueConst this_val) { @@ -51529,7 +52494,7 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, if (typed_array_is_detached(ctx, p)) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); - + shift = typed_array_size_log2(p->class_id); switch(shift) { case 0: @@ -51661,9 +52626,15 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, inc = 1; } - if (validate_typed_array(ctx, this_val)) - goto exception; p = JS_VALUE_GET_OBJ(this_val); + /* if the array was detached, no need to go further (but no + exception is raised) */ + if (typed_array_is_detached(ctx, p)) { + /* "includes" scans all the properties, so "undefined" can match */ + if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0) + res = 0; + goto done; + } is_bigint = 0; is_int = 0; /* avoid warning */ @@ -51682,7 +52653,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, #ifdef CONFIG_BIGNUM if (tag == JS_TAG_BIG_INT) { JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]); - + if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) { if (bf_get_int64(&v64, &p1->num, 0) != 0) goto done; @@ -51700,7 +52671,6 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, goto done; } - p = JS_VALUE_GET_OBJ(this_val); switch (p->class_id) { case JS_CLASS_INT8_ARRAY: if (is_int && (int8_t)v64 == v64) @@ -51889,6 +52859,8 @@ static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val, } } el = JS_GetPropertyUint32(ctx, this_val, i); + /* Can return undefined for example if the typed array is detached */ + if (!JS_IsNull(el) && !JS_IsUndefined(el)) { if (JS_IsException(el)) goto fail; if (toLocaleString) { @@ -51897,6 +52869,7 @@ static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val, if (string_buffer_concat_value_free(b, el)) goto fail; } + } JS_FreeValue(ctx, sep); return string_buffer_end(b); @@ -52313,7 +53286,7 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, uint32_t *array_idx; void *array_tmp; size_t i, j; - + /* XXX: a stable sort would use less memory */ array_idx = js_malloc(ctx, len * sizeof(array_idx[0])); if (!array_idx) @@ -53127,7 +54100,7 @@ static JSValue js_atomics_op(JSContext *ctx, } switch(op | (size_log2 << 3)) { - + #ifdef CONFIG_BIGNUM #define OP(op_name, func_name) \ case ATOMICS_OP_ ## op_name | (0 << 3): \ @@ -53176,7 +54149,7 @@ static JSValue js_atomics_op(JSContext *ctx, a = atomic_load((_Atomic(uint64_t) *)ptr); break; #endif - + case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3): { uint8_t v1 = v; @@ -53351,7 +54324,7 @@ static JSValue js_atomics_wait(JSContext *ctx, return JS_EXCEPTION; } else #endif - { + { if (JS_ToInt32(ctx, &v32, argv[2])) return JS_EXCEPTION; v = v32; @@ -53573,3 +54546,295 @@ void JS_AddIntrinsicTypedArrays(JSContext *ctx) JS_AddIntrinsicAtomics(ctx); #endif } + +#ifdef CONFIG_DEBUGGER + +void* js_debugger_get_object_id(JSValue val) { + JSObject *p = JS_VALUE_GET_OBJ(val); + return p; +} + +JSValue js_debugger_local_variables(JSContext *ctx, int stack_index) +{ + JSValue ret = JS_NewObject(ctx); + + // put exceptions on the top stack frame + if (stack_index == 0 && !JS_IsNull(ctx->rt->current_exception) && !JS_IsUndefined(ctx->rt->current_exception)) + JS_SetPropertyStr(ctx, ret, "", JS_DupValue(ctx, ctx->rt->current_exception)); + + JSStackFrame *sf; + int cur_index = 0; + + for (sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) { + // this val is one frame up + + if (cur_index < stack_index) { + cur_index++; + continue; + } + + JSObject *f = JS_VALUE_GET_OBJ(sf->cur_func); + if (!f || !js_class_has_bytecode(f->class_id)) + goto done; + + if (JS_VALUE_GET_OBJ(*sf->pthis) != JS_VALUE_GET_OBJ(ctx->global_obj)) + JS_SetPropertyStr(ctx, ret, "this", JS_DupValue(ctx, *sf->pthis)); + + JSFunctionBytecode *b = f->u.func.function_bytecode; + + for (uint32_t i = 0; i < b->arg_count + b->var_count; i++) { + JSValue var_val; + if (i < b->arg_count) + var_val = sf->arg_buf[i]; + else + var_val = sf->var_buf[i - b->arg_count]; + + if (JS_IsUninitialized(var_val)) + continue; + + JSVarDef *vd = b->vardefs + i; + JS_SetProperty(ctx, ret, vd->var_name, JS_DupValue(ctx, var_val)); + } + + break; + } + +done: + return ret; +} + +JSValue js_debugger_closure_variables(JSContext *ctx, int stack_index) { + JSValue ret = JS_NewObject(ctx); + + JSStackFrame *sf; + int cur_index = 0; + for (sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) { + if (cur_index < stack_index) { + cur_index++; + continue; + } + + JSObject *f = JS_VALUE_GET_OBJ(sf->cur_func); + if (!f || !js_class_has_bytecode(f->class_id)) + goto done; + + JSFunctionBytecode *b = f->u.func.function_bytecode; + + for (uint32_t i = 0; i < b->closure_var_count; i++) { + JSClosureVar *cvar = b->closure_var + i; + JSValue var_val; + JSVarRef *var_ref = NULL; + if (f->u.func.var_refs) + var_ref = f->u.func.var_refs[i]; + if (!var_ref || !var_ref->pvalue) + continue; + var_val = *var_ref->pvalue; + + if (JS_IsUninitialized(var_val)) + continue; + + JS_SetProperty(ctx, ret, cvar->var_name, JS_DupValue(ctx, var_val)); + } + + break; + } + +done: + return ret; +} + +JSValue js_debugger_build_backtrace(JSContext *ctx, const uint8_t *cur_pc) +{ + JSStackFrame *sf; + const char *func_name_str; + JSObject *p; + JSValue ret = JS_NewArray(ctx); + uint32_t stack_index = 0; + + for (sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) { + JSValue current_frame = JS_NewObject(ctx); + + uint32_t id = stack_index++; + JS_SetPropertyStr(ctx, current_frame, "id", JS_NewUint32(ctx, id)); + + func_name_str = get_func_name(ctx, sf->cur_func); + if (!func_name_str || func_name_str[0] == '\0') + JS_SetPropertyStr(ctx, current_frame, "name", JS_NewString(ctx, "")); + else + JS_SetPropertyStr(ctx, current_frame, "name", JS_NewString(ctx, func_name_str)); + JS_FreeCString(ctx, func_name_str); + + p = JS_VALUE_GET_OBJ(sf->cur_func); + if (p && js_class_has_bytecode(p->class_id)) { + JSFunctionBytecode *b; + int line_num1; + + b = p->u.func.function_bytecode; + if (b->has_debug) { + const uint8_t *pc = sf != ctx->rt->current_stack_frame || !cur_pc ? sf->cur_pc : cur_pc; + line_num1 = find_line_num(ctx, b, pc - b->byte_code_buf - 1); + JS_SetPropertyStr(ctx, current_frame, "filename", JS_AtomToString(ctx, b->debug.filename)); + if (line_num1 != -1) + JS_SetPropertyStr(ctx, current_frame, "lineno", JS_NewUint32(ctx, line_num1)); + } + } + else { + JS_SetPropertyStr(ctx, current_frame, "name", JS_NewString(ctx, "(native)")); + } + JS_SetPropertyUint32(ctx, ret, id, current_frame); + } + return ret; +} + +uint32_t js_debugger_stack_depth(JSContext *ctx) { + uint32_t stack_index = 0; + JSStackFrame *sf = ctx->rt->current_stack_frame; + while (sf != NULL) { + sf = sf->prev_frame; + stack_index++; + } + return stack_index; +} + + +void JS_SetBreakpointHandler(JSContext *ctx, JSDebuggerCheckLineNoF* debugger_check_line_no) +{ + ctx->debugger_check_line_no = debugger_check_line_no; +} + +void JS_SetDebuggerMode(JSContext *ctx, int onoff) +{ + ctx->debugger_enabled = onoff; +} + +#endif // CONFIG_DEBUGGER + +#ifdef CONFIG_STORAGE + +/* get name of user's class. For this obj: + + class Account {} + var obj = new Account(); + + it will return "Account" */ + +JSValue JS_GetObjectClassName(JSContext *ctx, JSValueConst obj) +{ + JSValue ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor); + + JSObject *p; + if (JS_VALUE_GET_TAG(ctor) != JS_TAG_OBJECT) + goto fail; + p = JS_VALUE_GET_OBJ(ctor); + if (p->class_id != JS_CLASS_BYTECODE_FUNCTION) + goto fail; + + JSValue name = JS_GetProperty(ctx, ctor, JS_ATOM_name); + JS_FreeValue(ctx, ctor); + return name; + +fail: + JS_FreeValue(ctx, ctor); + return JS_UNDEFINED; +} + +/* get value defined in local call frames/namespaces */ + +JSValue JS_GetLocalValue(JSContext *ctx, JSAtom name) +{ + for (JSStackFrame *sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) { + + JSObject *f = JS_VALUE_GET_OBJ(sf->cur_func); + if (!f || !js_class_has_bytecode(f->class_id)) + break; + + JSFunctionBytecode *b = f->u.func.function_bytecode; + + for (uint32_t i = 0; i < b->arg_count + b->var_count; i++) { + JSValue var_val; + if (i < b->arg_count) + var_val = sf->arg_buf[i]; + else + var_val = sf->var_buf[i - b->arg_count]; + + if (JS_IsUninitialized(var_val)) + continue; + + JSVarDef *vd = b->vardefs + i; + if(name == vd->var_name) + return JS_DupValue(ctx, var_val); + } + } + return JS_UNDEFINED; +} + +JS_BOOL js_is_persitable(JSValue val); + +JS_BOOL js_set_persistent_rt(JSRuntime* rt, JSValue val, struct JSStorage* pst, uint32_t oid, JS_PERSISTENT_STATUS status) { + + assert(js_is_persitable(val)); + + JSObject* po = JS_VALUE_GET_OBJ(val); + + if (status == JS_NOT_PERSISTENT) { + if (po->persistent) { + js_free_rt(rt,po->persistent); + po->persistent = NULL; + } + return 0; + } + + if (!po->persistent) { + po->persistent = js_malloc_rt(rt, sizeof(struct JSPersitentBlock)); + if (!po->persistent) + return 0; + } + + po->persistent->status = status; // loaded, modified, etc. + po->persistent->oid = oid; + po->persistent->storage = pst; + + return 1; +} + +JS_BOOL js_set_persistent(JSContext* ctx, JSValue val, struct JSStorage* pst, uint32_t oid, JS_PERSISTENT_STATUS status) { + return js_set_persistent_rt(JS_GetRuntime(ctx), val, pst, oid, status); +} + +void js_set_persistent_status(JSValue val, JS_PERSISTENT_STATUS status) { + assert(js_is_persitable(val)); + JSObject* po = JS_VALUE_GET_OBJ(val); + assert(po->persistent); + assert(status); + po->persistent->status = status; +} + +JS_PERSISTENT_STATUS js_is_persistent(JSValue val, struct JSStorage** pstor, uint32_t* poid) +{ + if(!js_is_persitable(val)) + return JS_NOT_PERSISTENT; + + JSObject* po = JS_VALUE_GET_OBJ(val); + + if (!po->persistent) + return JS_NOT_PERSISTENT; + + if (poid) + *poid = po->persistent->oid; + if (pstor) + *pstor = po->persistent->storage; + + return po->persistent->status; +} + +uint32_t* js_get_persistent_oid_ref(JSValue val) +{ + assert(js_is_persitable(val)); + + JSObject* po = JS_VALUE_GET_OBJ(val); + assert(po->persistent); + + return &po->persistent->oid; +} + +#endif diff --git a/quickjs.h b/quickjs.h index bb84829b9..c972c594a 100644 --- a/quickjs.h +++ b/quickjs.h @@ -27,21 +27,32 @@ #include #include - +#include +#include "quickjs-version.h" + +#if defined(_WIN32) + #define NATIVE_MODULE_SUFFIX ".dll" +#elif defined(__APPLE__) + #define NATIVE_NATIVE_MODULE_SUFFIX ".dylib" +#else + #define NATIVE_MODULE_SUFFIX ".so" +#endif + #ifdef __cplusplus extern "C" { #endif #if defined(__GNUC__) || defined(__clang__) -#define js_likely(x) __builtin_expect(!!(x), 1) -#define js_unlikely(x) __builtin_expect(!!(x), 0) -#define js_force_inline inline __attribute__((always_inline)) -#define __js_printf_like(f, a) __attribute__((format(printf, f, a))) + #define js_likely(x) __builtin_expect(!!(x), 1) + #define js_unlikely(x) __builtin_expect(!!(x), 0) + #define js_force_inline inline __attribute__((always_inline)) + //#define __js_printf_like(A, B) __attribute__((format(printf, (A), (B)))) + #define __js_printf_like(A, B) /*doesn't work, why?*/ #else -#define js_likely(x) (x) -#define js_unlikely(x) (x) -#define js_force_inline inline -#define __js_printf_like(a, b) + #define js_likely(x) (x) + #define js_unlikely(x) (x) + #define js_force_inline __forceinline + #define __js_printf_like(A, B) /* */ #endif #define JS_BOOL int @@ -53,6 +64,15 @@ typedef struct JSClass JSClass; typedef uint32_t JSClassID; typedef uint32_t JSAtom; +#ifdef CONFIG_STORAGE +typedef enum JS_PERSISTENT_STATUS { + JS_NOT_PERSISTENT = 0, + JS_PERSISTENT_DORMANT = 1, + JS_PERSISTENT_LOADED = 2, + JS_PERSISTENT_MODIFIED = 3 +} JS_PERSISTENT_STATUS; +#endif + #if INTPTR_MAX >= INT64_MAX #define JS_PTR64 #define JS_PTR64_DEF(a) a @@ -64,6 +84,123 @@ typedef uint32_t JSAtom; #define JS_NAN_BOXING #endif +typedef struct JSRefCountHeader { + int ref_count; +} JSRefCountHeader; + +#define JS_FLOAT64_NAN NAN + +#if defined(JS_STRICT_NAN_BOXING) + + // This schema defines strict NAN boxing for both 32 and 64 versions + + // This is a method of storing values in the IEEE 754 double-precision + // floating-point number. double type is 64-bit, comprised of 1 sign bit, 11 + // exponent bits and 52 mantissa bits: + // 7 6 5 4 3 2 1 0 + // seeeeeee|eeeemmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm + // + + // s0000000|0000tttt|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv + // NaN marker |tag| 48-bit placeholder for values: pointers, strings + // all bits 0 | 4 | + // for non float|bit| + + // Doubles contain non-zero in NaN marker field and are stored with bits inversed + + // JS_UNINITIALIZED is strictly uint64_t(0) + + enum { + + JS_TAG_UNINITIALIZED = 0, + JS_TAG_INT = 1, + JS_TAG_BOOL = 2, + JS_TAG_NULL = 3, + JS_TAG_UNDEFINED = 4, + JS_TAG_CATCH_OFFSET = 5, + JS_TAG_EXCEPTION = 6, + JS_TAG_FLOAT64 = 7, + + /* all tags with a reference count have 0b1000 bit */ + JS_TAG_OBJECT = 8, + JS_TAG_FUNCTION_BYTECODE = 9, /* used internally */ + JS_TAG_MODULE = 10, /* used internally */ + JS_TAG_STRING = 11, + JS_TAG_SYMBOL = 12, + JS_TAG_BIG_FLOAT = 13, + JS_TAG_BIG_INT = 14, + JS_TAG_BIG_DECIMAL = 15, + + }; + + typedef uint64_t JSValue; + + #define JSValueConst JSValue + + #define JS_VALUE_GET_TAG(v) (((v)>0xFFFFFFFFFFFFFull)? (unsigned)JS_TAG_FLOAT64 : (unsigned)((v) >> 48)) + + #define JS_VALUE_GET_INT(v) (int)(v) + #define JS_VALUE_GET_BOOL(v) (int)(v) + #ifdef JS_PTR64 + #define JS_VALUE_GET_PTR(v) ((void *)((intptr_t)(v) & 0x0000FFFFFFFFFFFFull)) + #else + #define JS_VALUE_GET_PTR(v) ((void *)(intptr_t)(v)) + #endif + + #define JS_MKVAL(tag, val) (((uint64_t)(0xF & tag) << 48) | (uint32_t)(val)) + #define JS_MKPTR(tag, ptr) (((uint64_t)(0xF & tag) << 48) | ((uint64_t)(ptr) & 0x0000FFFFFFFFFFFFull)) + + #define JS_NAN JS_MKVAL(JS_TAG_FLOAT64,0) + #define JS_INFINITY_NEGATIVE JS_MKVAL(JS_TAG_FLOAT64,1) + #define JS_INFINITY_POSITIVE JS_MKVAL(JS_TAG_FLOAT64,2) + + static inline double JS_VALUE_GET_FLOAT64(JSValue v) + { + if (v > 0xFFFFFFFFFFFFFull) { + union { JSValue v; double d; } u; + u.v = ~v; + return u.d; + } + else if (v == JS_NAN) + return JS_FLOAT64_NAN; + else if (v == JS_INFINITY_POSITIVE) + return INFINITY; + else + return -INFINITY; + } + + static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) + { + union { double d; uint64_t u64; } u; + JSValue v; + u.d = d; + /* normalize NaN */ + if (js_unlikely((u.u64 & 0x7ff0000000000000) == 0x7ff0000000000000)) { + if( isnan(d)) + v = JS_NAN; + else if (d < 0.0) + v = JS_INFINITY_NEGATIVE; + else + v = JS_INFINITY_POSITIVE; + } + else + v = ~u.u64; + return v; + } + + //#define JS_TAG_IS_FLOAT64(tag) ((tag & 0x7ff0) != 0) + #define JS_TAG_IS_FLOAT64(tag) (tag == JS_TAG_FLOAT64) + + /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ + /* Note: JS_VALUE_GET_TAG already normalized in this packaging schema*/ + #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) + + #define JS_VALUE_IS_NAN(v) (v == JS_NAN) + + #define JS_VALUE_HAS_REF_COUNT(v) ((JS_VALUE_GET_TAG(v) & 0xFFF8) == 0x8) + +#else // !JS_STRICT_NAN_BOXING + enum { /* all tags with a reference count are negative */ JS_TAG_FIRST = -11, /* first negative tag */ @@ -87,12 +224,6 @@ enum { /* any larger tag is FLOAT64 if JS_NAN_BOXING */ }; -typedef struct JSRefCountHeader { - int ref_count; -} JSRefCountHeader; - -#define JS_FLOAT64_NAN NAN - #ifdef CONFIG_CHECK_JSVALUE /* JSValue consistency : it is not possible to run the code in this mode, but it is useful to detect simple reference counting @@ -244,12 +375,16 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) #endif /* !JS_NAN_BOXING */ + #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) + +#endif /* !JS_STRICT_NAN_BOXING */ + #define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0) #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) #define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) -#define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) + /* special values */ #define JS_NULL JS_MKVAL(JS_TAG_NULL, 0) @@ -333,7 +468,11 @@ JSRuntime *JS_NewRuntime(void); void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); +/* use 0 to disable maximum stack size check */ void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); +/* should be called when changing thread to update the stack top value + used to check stack overflow. */ +void JS_UpdateStackTop(JSRuntime *rt); JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); void JS_FreeRuntime(JSRuntime *rt); void *JS_GetRuntimeOpaque(JSRuntime *rt); @@ -351,6 +490,8 @@ void JS_SetContextOpaque(JSContext *ctx, void *opaque); JSRuntime *JS_GetRuntime(JSContext *ctx); void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); +JSValue JS_GetClassName(JSContext *ctx, JSClassID class_id); + /* the following functions are used to select the intrinsic object to save memory */ @@ -417,13 +558,19 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); JSAtom JS_NewAtom(JSContext *ctx, const char *str); JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); +JSAtom JS_NewAtomLenRT(JSRuntime *rt, const char *str, int len); +JSAtom JS_NewAtomSymbolLenRT(JSRuntime *rt, const char *str, int len); +const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom); +const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size, JSAtom atom); JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); +JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v); void JS_FreeAtom(JSContext *ctx, JSAtom v); void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val); +int JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom); /* object class support */ @@ -432,6 +579,8 @@ typedef struct JSPropertyEnum { JSAtom atom; } JSPropertyEnum; +void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len); + typedef struct JSPropertyDescriptor { int flags; JSValue value; @@ -439,6 +588,8 @@ typedef struct JSPropertyDescriptor { JSValue setter; } JSPropertyDescriptor; +#define JS_PROCEED_WITH_DEFAULT 12345 + typedef struct JSClassExoticMethods { /* Return -1 if exception (can only happen in case of Proxy object), FALSE if the property does not exists, TRUE if it exists. If 1 is @@ -460,7 +611,7 @@ typedef struct JSClassExoticMethods { int flags); /* The following methods can be emulated with the previous ones, so they are usually not needed */ - /* return < 0 if exception or TRUE/FALSE */ + /* return < 0 if exception or TRUE/FALSE or JS_PROCEED_WITH_DEFAULT */ int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, JSValueConst receiver); @@ -517,9 +668,9 @@ static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val) { JSValue v; if (val == (int32_t)val) { - v = JS_NewInt32(ctx, val); + v = JS_NewInt32(ctx, (int32_t)val); } else { - v = __JS_NewFloat64(ctx, val); + v = __JS_NewFloat64(ctx, (double)val); } return v; } @@ -559,6 +710,9 @@ static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d) return v; } +JSValue JS_NewDate(JSContext* ctx, double ms_1970); +JS_BOOL JS_IsDate(JSContext *ctx, JSValueConst obj, double* ms_since_1970); + static inline JS_BOOL JS_IsNumber(JSValueConst v) { int tag = JS_VALUE_GET_TAG(v); @@ -623,6 +777,8 @@ static inline JS_BOOL JS_IsObject(JSValueConst v) return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; } +int JS_IsObjectPlain(JSContext *ctx, JSValueConst val); /* plain JS object, that is not function nor array nor anything else */ + JSValue JS_Throw(JSContext *ctx, JSValue obj); JSValue JS_GetException(JSContext *ctx); JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); @@ -712,9 +868,21 @@ JSValue JS_NewObject(JSContext *ctx); JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val); +JS_BOOL JS_IsFunctionOfThisRealm(JSContext *ctx, JSValueConst val); + +JS_BOOL JS_AreFunctionsOfSameOrigin(JSContext *ctx, JSValue f1, JSValue f2); + +JSValue JS_GetUserClassName(JSContext *ctx, JSValueConst obj); JSValue JS_NewArray(JSContext *ctx); int JS_IsArray(JSContext *ctx, JSValueConst val); +/* isArray and has 'tag' property */ +int JS_IsTuple(JSContext *ctx, JSValueConst val); +JSValue JS_GetTupleTag(JSContext *ctx, JSValueConst val); + +JSValue JS_NewFastArray(JSContext *ctx, int argc, JSValueConst *argv); +/* Access an Array's internal JSValue array if available */ +int JS_GetFastArray(JSContext *ctx, JSValueConst obj, JSValue **arrpp, uint32_t *countp); JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst receiver, @@ -729,6 +897,9 @@ JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx); +/* get .length property */ +int JS_GetPropertyLength(JSContext *ctx, int64_t *plength, JSValueConst obj); + int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags); @@ -749,6 +920,9 @@ int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val); +JSValue JS_GetPrototypeOfDate(JSContext *ctx); + +int JS_CopyDataProperties(JSContext *ctx, JSValueConst target, JSValueConst source, JSValueConst excluded, int setprop); #define JS_GPN_STRING_MASK (1 << 0) #define JS_GPN_SYMBOL_MASK (1 << 1) @@ -776,7 +950,14 @@ JS_BOOL JS_DetectModule(const char *input, size_t input_len); /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags); +JSValue JS_Eval2(JSContext *ctx, const char *input, size_t input_len, + const char *filename, int eval_flags, int line_no); + JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj); +/* same as JS_Eval() but with an explicit 'this_obj' parameter */ +JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, + const char *input, size_t input_len, + const char *filename, int eval_flags); JSValue JS_GetGlobalObject(JSContext *ctx); int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj); int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, @@ -794,6 +975,7 @@ int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, void JS_SetOpaque(JSValue obj, void *opaque); void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); +JSClassID JS_GetClassID(JSValueConst obj, void** ppopaque); /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, @@ -883,8 +1065,8 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, #define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ #define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */ -JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, - int flags); +JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags); +JSValue JS_ReadObject2(JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags, size_t* remnants_len); /* load the dependencies of the module 'obj'. Useful when JS_ReadObject() returns a module. */ @@ -896,6 +1078,9 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, const char *filename); +JSValue JS_GetModuleExportItemStr(JSContext *ctx, JSModuleDef *m, const char *name); +JSValue JS_GetModuleExportItem(JSContext *ctx, JSModuleDef *m, JSAtom atom); + /* C function definition */ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ JS_CFUNC_generic, @@ -1030,6 +1215,22 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, const JSCFunctionListEntry *tab, int len); +#ifdef CONFIG_DEBUGGER + +typedef JS_BOOL JSDebuggerCheckLineNoF(JSContext *ctx, JSAtom file_name, uint32_t line_no, const uint8_t *pc); + +void JS_SetBreakpointHandler(JSContext *ctx, JSDebuggerCheckLineNoF* line_hit_handler); +void JS_SetDebuggerMode(JSContext *ctx, int onoff); + +uint32_t js_debugger_stack_depth(JSContext *ctx); +JSValue js_debugger_build_backtrace(JSContext *ctx, const uint8_t *cur_pc); +JSValue js_debugger_closure_variables(JSContext *ctx, int stack_index); +JSValue js_debugger_local_variables(JSContext *ctx, int stack_index); + +#endif + +void* js_debugger_get_object_id(JSValue val); + #undef js_unlikely #undef js_force_inline diff --git a/release.sh b/release.sh index a0bd6ebfd..26fba1b03 100755 --- a/release.sh +++ b/release.sh @@ -6,30 +6,23 @@ set -e version=`cat VERSION` if [ "$1" = "-h" ] ; then - echo "release.sh [all]" + echo "release.sh [release_list]" echo "" - echo "all: build all the archives. Otherwise only build the quickjs source archive." + echo "release_list: extras binary win_binary quickjs" + exit 1 fi -extras="no" -binary="no" -quickjs="no" - -if [ "$1" = "all" ] ; then - extras="yes" - binary="yes" - quickjs="yes" -elif [ "$1" = "binary" ] ; then - binary="yes" -else - quickjs="yes" +release_list="extras binary win_binary quickjs" + +if [ "$1" != "" ] ; then + release_list="$1" fi #################################################" # extras -if [ "$extras" = "yes" ] ; then +if echo $release_list | grep -w -q extras ; then d="quickjs-${version}" name="quickjs-extras-${version}" @@ -46,10 +39,58 @@ cp -a tests/bench-v8 $outdir/tests fi #################################################" -# binary release +# Windows binary release + +if echo $release_list | grep -w -q win_binary ; then + +# win64 + +dlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin +cross_prefix="x86_64-w64-mingw32-" +d="quickjs-win-x86_64-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir + +make CONFIG_WIN32=y qjs.exe +cp qjs.exe $outdir +${cross_prefix}strip $outdir/qjs.exe +cp $dlldir/libwinpthread-1.dll $outdir + +( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . ) + +make CONFIG_WIN32=y clean + +# win32 + +dlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin +cross_prefix="i686-w64-mingw32-" +d="quickjs-win-i686-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir + +make clean +make CONFIG_WIN32=y clean + +make CONFIG_WIN32=y CONFIG_M32=y qjs.exe +cp qjs.exe $outdir +${cross_prefix}strip $outdir/qjs.exe +cp $dlldir/libwinpthread-1.dll $outdir + +( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . ) + +fi + +#################################################" +# Linux binary release -if [ "$binary" = "yes" ] ; then +if echo $release_list | grep -w -q binary ; then +make clean +make CONFIG_WIN32=y clean make -j4 qjs run-test262 make -j4 CONFIG_M32=y qjs32 run-test262-32 strip qjs run-test262 qjs32 run-test262-32 @@ -80,7 +121,7 @@ fi #################################################" # quickjs -if [ "$quickjs" = "yes" ] ; then +if echo $release_list | grep -w -q quickjs ; then make build_doc @@ -90,7 +131,8 @@ outdir="/tmp/${d}" rm -rf $outdir mkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples -cp Makefile VERSION TODO Changelog readme.txt release.sh unicode_download.sh \ +cp Makefile VERSION TODO Changelog readme.txt LICENSE \ + release.sh unicode_download.sh \ qjs.c qjsc.c qjscalc.js repl.js \ quickjs.c quickjs.h quickjs-atom.h \ quickjs-libc.c quickjs-libc.h quickjs-opcode.h \ @@ -98,7 +140,7 @@ cp Makefile VERSION TODO Changelog readme.txt release.sh unicode_download.sh \ libregexp.c libregexp.h libregexp-opcode.h \ libunicode.c libunicode.h libunicode-table.h \ libbf.c libbf.h \ - jscompress.c unicode_gen.c unicode_gen_def.h \ + unicode_gen.c unicode_gen_def.h \ run-test262.c test262o.conf test262.conf \ test262o_errors.txt test262_errors.txt \ $outdir diff --git a/repl.c b/repl.c new file mode 100644 index 000000000..ee4e5aadd --- /dev/null +++ b/repl.c @@ -0,0 +1,2021 @@ +/* File generated automatically by the QuickJS compiler. */ + +#include + +const uint32_t qjsc_repl_size = 16092; + +const uint8_t qjsc_repl[16092] = { + 0x02, 0xa1, 0x03, 0x1a, 0x2e, 0x2e, 0x2f, 0x2e, + 0x2e, 0x2f, 0x72, 0x65, 0x70, 0x6c, 0x2e, 0x6a, + 0x73, 0x06, 0x73, 0x74, 0x64, 0x04, 0x6f, 0x73, + 0x10, 0x69, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x74, + 0x65, 0x14, 0x70, 0x61, 0x72, 0x73, 0x65, 0x46, + 0x6c, 0x6f, 0x61, 0x74, 0x08, 0x6f, 0x70, 0x65, + 0x6e, 0x10, 0x46, 0x72, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x08, 0x1b, 0x5b, 0x30, 0x6d, 0x08, + 0x6e, 0x6f, 0x6e, 0x65, 0x0a, 0x1b, 0x5b, 0x33, + 0x30, 0x6d, 0x0a, 0x62, 0x6c, 0x61, 0x63, 0x6b, + 0x0a, 0x1b, 0x5b, 0x33, 0x31, 0x6d, 0x06, 0x72, + 0x65, 0x64, 0x0a, 0x1b, 0x5b, 0x33, 0x32, 0x6d, + 0x0a, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x0a, 0x1b, + 0x5b, 0x33, 0x33, 0x6d, 0x0c, 0x79, 0x65, 0x6c, + 0x6c, 0x6f, 0x77, 0x0a, 0x1b, 0x5b, 0x33, 0x34, + 0x6d, 0x08, 0x62, 0x6c, 0x75, 0x65, 0x0a, 0x1b, + 0x5b, 0x33, 0x35, 0x6d, 0x0e, 0x6d, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x61, 0x0a, 0x1b, 0x5b, 0x33, + 0x36, 0x6d, 0x08, 0x63, 0x79, 0x61, 0x6e, 0x0a, + 0x1b, 0x5b, 0x33, 0x37, 0x6d, 0x0a, 0x77, 0x68, + 0x69, 0x74, 0x65, 0x0e, 0x1b, 0x5b, 0x33, 0x30, + 0x3b, 0x31, 0x6d, 0x08, 0x67, 0x72, 0x61, 0x79, + 0x08, 0x67, 0x72, 0x65, 0x79, 0x0e, 0x1b, 0x5b, + 0x33, 0x31, 0x3b, 0x31, 0x6d, 0x14, 0x62, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x5f, 0x72, 0x65, 0x64, + 0x0e, 0x1b, 0x5b, 0x33, 0x32, 0x3b, 0x31, 0x6d, + 0x18, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, + 0x67, 0x72, 0x65, 0x65, 0x6e, 0x0e, 0x1b, 0x5b, + 0x33, 0x33, 0x3b, 0x31, 0x6d, 0x1a, 0x62, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x5f, 0x79, 0x65, 0x6c, + 0x6c, 0x6f, 0x77, 0x0e, 0x1b, 0x5b, 0x33, 0x34, + 0x3b, 0x31, 0x6d, 0x16, 0x62, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x5f, 0x62, 0x6c, 0x75, 0x65, 0x0e, + 0x1b, 0x5b, 0x33, 0x35, 0x3b, 0x31, 0x6d, 0x1c, + 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6d, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x61, 0x0e, 0x1b, + 0x5b, 0x33, 0x36, 0x3b, 0x31, 0x6d, 0x16, 0x62, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x63, 0x79, + 0x61, 0x6e, 0x0e, 0x1b, 0x5b, 0x33, 0x37, 0x3b, + 0x31, 0x6d, 0x18, 0x62, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x5f, 0x77, 0x68, 0x69, 0x74, 0x65, 0x0e, + 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0a, + 0x72, 0x65, 0x67, 0x65, 0x78, 0x0e, 0x6b, 0x65, + 0x79, 0x77, 0x6f, 0x72, 0x64, 0x08, 0x74, 0x79, + 0x70, 0x65, 0x14, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x0a, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x0c, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x5f, 0x6d, 0x73, 0x67, 0x04, 0x3e, 0x20, 0x0c, + 0x71, 0x6a, 0x73, 0x20, 0x3e, 0x20, 0x0c, 0x20, + 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x02, 0x01, 0x02, + 0x02, 0x02, 0x03, 0x02, 0x04, 0x02, 0x05, 0x02, + 0x06, 0x02, 0x07, 0x02, 0x08, 0x02, 0x09, 0x02, + 0x0a, 0x02, 0x0b, 0x02, 0x0d, 0x02, 0x0e, 0x02, + 0x10, 0x02, 0x11, 0x02, 0x12, 0x02, 0x13, 0x02, + 0x14, 0x02, 0x18, 0x02, 0x19, 0x06, 0x1b, 0x4f, + 0x41, 0x06, 0x1b, 0x4f, 0x42, 0x06, 0x1b, 0x4f, + 0x43, 0x06, 0x1b, 0x4f, 0x44, 0x06, 0x1b, 0x4f, + 0x46, 0x06, 0x1b, 0x4f, 0x48, 0x0c, 0x1b, 0x5b, + 0x31, 0x3b, 0x35, 0x43, 0x0c, 0x1b, 0x5b, 0x31, + 0x3b, 0x35, 0x44, 0x08, 0x1b, 0x5b, 0x31, 0x7e, + 0x08, 0x1b, 0x5b, 0x33, 0x7e, 0x08, 0x1b, 0x5b, + 0x34, 0x7e, 0x08, 0x1b, 0x5b, 0x35, 0x7e, 0x08, + 0x1b, 0x5b, 0x36, 0x7e, 0x06, 0x1b, 0x5b, 0x41, + 0x06, 0x1b, 0x5b, 0x42, 0x06, 0x1b, 0x5b, 0x43, + 0x06, 0x1b, 0x5b, 0x44, 0x06, 0x1b, 0x5b, 0x46, + 0x06, 0x1b, 0x5b, 0x48, 0x04, 0x1b, 0x7f, 0x04, + 0x1b, 0x62, 0x04, 0x1b, 0x64, 0x04, 0x1b, 0x66, + 0x04, 0x1b, 0x6b, 0x04, 0x1b, 0x6c, 0x04, 0x1b, + 0x74, 0x04, 0x1b, 0x75, 0x02, 0x7f, 0x0e, 0x65, + 0x78, 0x65, 0x63, 0x43, 0x6d, 0x64, 0x10, 0x74, + 0x65, 0x72, 0x6d, 0x49, 0x6e, 0x69, 0x74, 0x0c, + 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x6f, 0x0c, 0x69, + 0x73, 0x61, 0x74, 0x74, 0x79, 0x1a, 0x74, 0x74, + 0x79, 0x47, 0x65, 0x74, 0x57, 0x69, 0x6e, 0x53, + 0x69, 0x7a, 0x65, 0x12, 0x74, 0x74, 0x79, 0x53, + 0x65, 0x74, 0x52, 0x61, 0x77, 0x0c, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x0c, 0x53, 0x49, 0x47, + 0x49, 0x4e, 0x54, 0x1c, 0x73, 0x65, 0x74, 0x52, + 0x65, 0x61, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x72, 0x1c, 0x73, 0x69, 0x67, 0x69, 0x6e, + 0x74, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x72, 0x16, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x22, 0x74, 0x65, + 0x72, 0x6d, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, + 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x08, + 0x72, 0x65, 0x61, 0x64, 0x0c, 0x62, 0x75, 0x66, + 0x66, 0x65, 0x72, 0x10, 0x69, 0x73, 0x5f, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x02, 0x41, 0x02, 0x5a, + 0x02, 0x61, 0x02, 0x7a, 0x10, 0x69, 0x73, 0x5f, + 0x64, 0x69, 0x67, 0x69, 0x74, 0x0e, 0x69, 0x73, + 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x02, 0x5f, 0x02, + 0x24, 0x14, 0x75, 0x63, 0x73, 0x5f, 0x6c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x14, 0x63, 0x68, 0x61, + 0x72, 0x43, 0x6f, 0x64, 0x65, 0x41, 0x74, 0x2a, + 0x69, 0x73, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6c, + 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x75, 0x72, 0x72, + 0x6f, 0x67, 0x61, 0x74, 0x65, 0x16, 0x63, 0x6f, + 0x64, 0x65, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x41, + 0x74, 0x16, 0x69, 0x73, 0x5f, 0x62, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x64, 0x04, 0x28, 0x29, + 0x04, 0x5b, 0x5d, 0x04, 0x7b, 0x7d, 0x20, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6c, + 0x6f, 0x72, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x08, + 0x70, 0x75, 0x74, 0x73, 0x12, 0x73, 0x75, 0x62, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x63, 0x73, 0x69, + 0x04, 0x1b, 0x5b, 0x16, 0x6d, 0x6f, 0x76, 0x65, + 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x06, + 0x6d, 0x69, 0x6e, 0x02, 0x43, 0x02, 0x44, 0x0c, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x04, 0x20, + 0x08, 0x06, 0x1b, 0x5b, 0x4a, 0x06, 0x6f, 0x75, + 0x74, 0x0a, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x0c, + 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x1a, 0x71, + 0x75, 0x6f, 0x74, 0x65, 0x64, 0x5f, 0x69, 0x6e, + 0x73, 0x65, 0x72, 0x74, 0x14, 0x71, 0x75, 0x6f, + 0x74, 0x65, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x0a, + 0x61, 0x62, 0x6f, 0x72, 0x74, 0x06, 0x63, 0x6d, + 0x64, 0x14, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, + 0x5f, 0x70, 0x6f, 0x73, 0x0a, 0x61, 0x6c, 0x65, + 0x72, 0x74, 0x22, 0x62, 0x65, 0x67, 0x69, 0x6e, + 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x66, 0x5f, + 0x6c, 0x69, 0x6e, 0x65, 0x16, 0x65, 0x6e, 0x64, + 0x5f, 0x6f, 0x66, 0x5f, 0x6c, 0x69, 0x6e, 0x65, + 0x18, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x5f, 0x63, 0x68, 0x61, 0x72, 0x0c, 0x63, 0x68, + 0x61, 0x72, 0x41, 0x74, 0x1a, 0x62, 0x61, 0x63, + 0x6b, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x68, + 0x61, 0x72, 0x22, 0x73, 0x6b, 0x69, 0x70, 0x5f, + 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x66, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x24, 0x73, 0x6b, 0x69, + 0x70, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x62, + 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, 0x64, 0x18, + 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, + 0x77, 0x6f, 0x72, 0x64, 0x1a, 0x62, 0x61, 0x63, + 0x6b, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x77, 0x6f, + 0x72, 0x64, 0x16, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x16, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x61, + 0x64, 0x64, 0x08, 0x70, 0x75, 0x73, 0x68, 0x20, + 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, + 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x1a, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x0e, 0x68, + 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x6e, + 0x65, 0x78, 0x74, 0x5f, 0x68, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x1c, 0x68, 0x69, 0x73, 0x74, + 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x2e, 0x68, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, + 0x72, 0x64, 0x2c, 0x68, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x1e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x5f, 0x63, 0x68, 0x61, 0x72, 0x5f, 0x64, 0x69, + 0x72, 0x16, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x5f, 0x63, 0x68, 0x61, 0x72, 0x12, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x64, 0x28, + 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, 0x64, + 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, + 0x63, 0x68, 0x61, 0x72, 0x1e, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x5f, 0x63, + 0x68, 0x61, 0x72, 0x73, 0x1e, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x5f, 0x77, + 0x6f, 0x72, 0x64, 0x73, 0x16, 0x75, 0x70, 0x63, + 0x61, 0x73, 0x65, 0x5f, 0x77, 0x6f, 0x72, 0x64, + 0x16, 0x74, 0x6f, 0x55, 0x70, 0x70, 0x65, 0x72, + 0x43, 0x61, 0x73, 0x65, 0x1a, 0x64, 0x6f, 0x77, + 0x6e, 0x63, 0x61, 0x73, 0x65, 0x5f, 0x77, 0x6f, + 0x72, 0x64, 0x16, 0x74, 0x6f, 0x4c, 0x6f, 0x77, + 0x65, 0x72, 0x43, 0x61, 0x73, 0x65, 0x16, 0x6b, + 0x69, 0x6c, 0x6c, 0x5f, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x12, 0x6b, 0x69, 0x6c, 0x6c, 0x5f, + 0x6c, 0x69, 0x6e, 0x65, 0x24, 0x62, 0x61, 0x63, + 0x6b, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x6b, 0x69, + 0x6c, 0x6c, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x12, + 0x6b, 0x69, 0x6c, 0x6c, 0x5f, 0x77, 0x6f, 0x72, + 0x64, 0x24, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, + 0x72, 0x64, 0x5f, 0x6b, 0x69, 0x6c, 0x6c, 0x5f, + 0x77, 0x6f, 0x72, 0x64, 0x08, 0x79, 0x61, 0x6e, + 0x6b, 0x14, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x12, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x63, 0x10, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x66, 0x75, 0x6e, 0x2a, + 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, + 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x70, + 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x08, 0x65, 0x78, + 0x69, 0x74, 0x3c, 0x0a, 0x28, 0x50, 0x72, 0x65, + 0x73, 0x73, 0x20, 0x43, 0x74, 0x72, 0x6c, 0x2d, + 0x43, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x20, + 0x74, 0x6f, 0x20, 0x71, 0x75, 0x69, 0x74, 0x29, + 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x65, 0x74, 0x20, + 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x5f, 0x77, 0x6f, 0x72, 0x64, + 0x24, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x5f, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x08, 0x6c, 0x69, 0x6e, 0x65, + 0x06, 0x70, 0x6f, 0x73, 0x06, 0x6f, 0x62, 0x6a, + 0x08, 0x62, 0x61, 0x73, 0x65, 0x02, 0x63, 0x02, + 0x67, 0x1c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x5f, 0x6e, 0x75, 0x6d, 0x63, 0x61, 0x6c, 0x63, + 0x14, 0x68, 0x61, 0x73, 0x5f, 0x6a, 0x73, 0x63, + 0x61, 0x6c, 0x63, 0x14, 0x68, 0x61, 0x73, 0x5f, + 0x62, 0x69, 0x67, 0x6e, 0x75, 0x6d, 0x0c, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x0c, 0x73, 0x74, + 0x79, 0x6c, 0x65, 0x73, 0x08, 0x70, 0x72, 0x65, + 0x63, 0x0e, 0x65, 0x78, 0x70, 0x42, 0x69, 0x74, + 0x73, 0x0e, 0x6c, 0x6f, 0x67, 0x32, 0x5f, 0x31, + 0x30, 0x0c, 0x70, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x0c, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x08, + 0x70, 0x6c, 0x65, 0x6e, 0x06, 0x70, 0x73, 0x31, + 0x06, 0x70, 0x73, 0x32, 0x08, 0x75, 0x74, 0x66, + 0x38, 0x12, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x16, 0x73, 0x68, 0x6f, 0x77, + 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x12, + 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x0a, 0x6d, 0x65, 0x78, 0x70, 0x72, 0x0a, + 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x10, 0x6c, 0x61, + 0x73, 0x74, 0x5f, 0x63, 0x6d, 0x64, 0x1e, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x63, 0x75, 0x72, 0x73, + 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x73, 0x10, 0x74, + 0x68, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x6e, 0x14, + 0x75, 0x74, 0x66, 0x38, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x10, 0x75, 0x74, 0x66, 0x38, 0x5f, + 0x76, 0x61, 0x6c, 0x0e, 0x74, 0x65, 0x72, 0x6d, + 0x5f, 0x66, 0x64, 0x1a, 0x74, 0x65, 0x72, 0x6d, + 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x62, 0x75, + 0x66, 0x14, 0x74, 0x65, 0x72, 0x6d, 0x5f, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x1a, 0x74, 0x65, 0x72, + 0x6d, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, + 0x5f, 0x78, 0x1e, 0x67, 0x65, 0x74, 0x5f, 0x63, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x14, 0x63, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x0c, 0x64, + 0x75, 0x70, 0x73, 0x74, 0x72, 0x1a, 0x72, 0x65, + 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6b, + 0x65, 0x79, 0x73, 0x1c, 0x72, 0x65, 0x61, 0x64, + 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x16, 0x72, 0x65, 0x61, 0x64, 0x6c, + 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x62, 0x1c, 0x72, + 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x16, 0x68, 0x61, + 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x63, 0x68, 0x61, + 0x72, 0x14, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x5f, 0x6b, 0x65, 0x79, 0x10, 0x68, 0x65, 0x78, + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x65, 0x76, + 0x61, 0x6c, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x20, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x74, + 0x6f, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x24, 0x62, 0x69, 0x67, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x20, 0x62, 0x69, 0x67, 0x69, + 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x0a, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x22, 0x65, 0x78, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x20, 0x68, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x08, 0x68, 0x65, + 0x6c, 0x70, 0x1c, 0x65, 0x76, 0x61, 0x6c, 0x5f, + 0x61, 0x6e, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x12, 0x63, 0x6d, 0x64, 0x5f, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x24, 0x63, 0x6d, 0x64, 0x5f, + 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, + 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x26, 0x72, + 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x63, + 0x6d, 0x64, 0x14, 0x68, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x5f, 0x63, 0x6d, 0x64, 0x16, 0x63, 0x6f, + 0x6c, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x6a, + 0x73, 0x2a, 0x20, 0x7e, 0x21, 0x25, 0x5e, 0x26, + 0x2a, 0x28, 0x2d, 0x2b, 0x3d, 0x7b, 0x5b, 0x7c, + 0x3a, 0x3b, 0x2c, 0x3c, 0x3e, 0x3f, 0x2f, 0x0e, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x02, + 0x2e, 0x02, 0x27, 0x02, 0x22, 0x02, 0x5d, 0x02, + 0x7d, 0x02, 0x2f, 0x10, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x73, 0x0a, 0x69, 0x73, 0x4e, + 0x61, 0x4e, 0x26, 0x67, 0x65, 0x74, 0x4f, 0x77, + 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x14, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x73, 0x57, 0x69, 0x74, + 0x68, 0x08, 0x73, 0x6f, 0x72, 0x74, 0x06, 0x74, + 0x61, 0x62, 0x06, 0x63, 0x74, 0x78, 0x0c, 0x73, + 0x79, 0x6d, 0x63, 0x6d, 0x70, 0x02, 0x28, 0x02, + 0x29, 0x06, 0x6d, 0x61, 0x78, 0x0a, 0x66, 0x6c, + 0x6f, 0x6f, 0x72, 0x08, 0x63, 0x65, 0x69, 0x6c, + 0x0c, 0x70, 0x61, 0x64, 0x45, 0x6e, 0x64, 0x02, + 0x20, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x1a, + 0x66, 0x72, 0x6f, 0x6d, 0x43, 0x6f, 0x64, 0x65, + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x02, 0x1b, 0x02, + 0x5b, 0x02, 0x4f, 0x02, 0x3b, 0x04, 0x2d, 0x30, + 0x02, 0x2d, 0x04, 0x30, 0x78, 0x08, 0x6d, 0x61, + 0x74, 0x68, 0x12, 0x42, 0x69, 0x67, 0x46, 0x6c, + 0x6f, 0x61, 0x74, 0x28, 0x02, 0x6c, 0x02, 0x70, + 0x02, 0x65, 0x04, 0x2e, 0x30, 0x02, 0x6e, 0x12, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x72, 0x65, + 0x63, 0x14, 0x5b, 0x63, 0x69, 0x72, 0x63, 0x75, + 0x6c, 0x61, 0x72, 0x5d, 0x0e, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x78, 0x06, 0x4d, 0x6f, 0x64, + 0x14, 0x50, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, + 0x69, 0x61, 0x6c, 0x0e, 0x50, 0x6f, 0x6c, 0x79, + 0x4d, 0x6f, 0x64, 0x20, 0x52, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x0c, 0x53, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x0e, 0x69, 0x73, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x04, 0x5b, 0x20, 0x04, 0x2c, + 0x20, 0x0e, 0x3c, 0x65, 0x6d, 0x70, 0x74, 0x79, + 0x3e, 0x06, 0x2e, 0x2e, 0x2e, 0x04, 0x20, 0x5d, + 0x14, 0x5f, 0x5f, 0x67, 0x65, 0x74, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x08, 0x6b, 0x65, 0x79, 0x73, + 0x04, 0x7b, 0x20, 0x04, 0x3a, 0x20, 0x04, 0x20, + 0x7d, 0x06, 0x70, 0x6f, 0x70, 0x0e, 0x5f, 0x5f, + 0x71, 0x75, 0x6f, 0x74, 0x65, 0x08, 0x2e, 0x2e, + 0x2e, 0x22, 0x02, 0x6d, 0x12, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x02, 0x5c, + 0x02, 0x68, 0x02, 0x3f, 0x08, 0x6c, 0x6f, 0x61, + 0x64, 0x08, 0x74, 0x72, 0x69, 0x6d, 0x16, 0x6c, + 0x61, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x4f, 0x66, 0x06, 0x2e, 0x6a, 0x73, 0x14, 0x6c, + 0x6f, 0x61, 0x64, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x02, 0x78, 0x02, 0x64, 0x02, 0x74, 0x26, + 0x42, 0x69, 0x67, 0x46, 0x6c, 0x6f, 0x61, 0x74, + 0x20, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x3d, 0x10, 0x20, 0x62, 0x69, 0x74, + 0x73, 0x20, 0x28, 0x7e, 0x30, 0x20, 0x64, 0x69, + 0x67, 0x69, 0x74, 0x73, 0x29, 0x2c, 0x20, 0x65, + 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, + 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x0c, 0x20, 0x62, + 0x69, 0x74, 0x73, 0x0a, 0x06, 0x66, 0x31, 0x36, + 0x06, 0x66, 0x33, 0x32, 0x06, 0x66, 0x36, 0x34, + 0x08, 0x66, 0x31, 0x32, 0x38, 0x10, 0x70, 0x61, + 0x72, 0x73, 0x65, 0x49, 0x6e, 0x74, 0x14, 0x65, + 0x78, 0x70, 0x42, 0x69, 0x74, 0x73, 0x4d, 0x61, + 0x78, 0x0e, 0x70, 0x72, 0x65, 0x63, 0x4d, 0x69, + 0x6e, 0x0e, 0x70, 0x72, 0x65, 0x63, 0x4d, 0x61, + 0x78, 0x24, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x20, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x0a, 0x14, 0x65, 0x78, 0x70, + 0x42, 0x69, 0x74, 0x73, 0x4d, 0x69, 0x6e, 0x2c, + 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, + 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x20, 0x62, 0x69, 0x74, 0x73, 0x0a, 0x0c, 0x64, + 0x69, 0x67, 0x69, 0x74, 0x73, 0x08, 0x6d, 0x6f, + 0x64, 0x65, 0x1a, 0x52, 0x75, 0x6e, 0x6e, 0x69, + 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x3d, + 0x1a, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x0a, 0x0a, 0x63, + 0x6c, 0x65, 0x61, 0x72, 0x0c, 0x1b, 0x5b, 0x48, + 0x1b, 0x5b, 0x4a, 0x02, 0x71, 0x1a, 0x61, 0x6c, + 0x67, 0x65, 0x62, 0x72, 0x61, 0x69, 0x63, 0x4d, + 0x6f, 0x64, 0x65, 0x26, 0x55, 0x6e, 0x6b, 0x6e, + 0x6f, 0x77, 0x6e, 0x20, 0x64, 0x69, 0x72, 0x65, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x3a, 0x20, 0x06, + 0x64, 0x65, 0x63, 0x06, 0x68, 0x65, 0x78, 0x06, + 0x6e, 0x75, 0x6d, 0x06, 0x61, 0x6c, 0x67, 0x2c, + 0x5c, 0x68, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x68, 0x65, 0x6c, 0x70, 0x0a, 0x16, 0x5c, + 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x36, 0x68, 0x65, 0x78, 0x61, 0x64, + 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x0a, 0x16, 0x5c, + 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x2e, 0x64, 0x65, 0x63, 0x69, 0x6d, + 0x61, 0x6c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x0a, 0x16, 0x5c, 0x74, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2c, 0x74, + 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x20, 0x74, 0x69, + 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x0a, 0x3e, 0x5c, 0x63, + 0x6c, 0x65, 0x61, 0x72, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x6c, 0x0a, 0x16, 0x5c, 0x61, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x1e, 0x61, 0x6c, 0x67, 0x65, 0x62, 0x72, + 0x61, 0x69, 0x63, 0x20, 0x6d, 0x6f, 0x64, 0x65, + 0x0a, 0x16, 0x5c, 0x6e, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x1a, 0x6e, 0x75, + 0x6d, 0x65, 0x72, 0x69, 0x63, 0x20, 0x6d, 0x6f, + 0x64, 0x65, 0x0a, 0x66, 0x5c, 0x70, 0x20, 0x5b, + 0x6d, 0x20, 0x5b, 0x65, 0x5d, 0x5d, 0x20, 0x20, + 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x42, 0x69, 0x67, 0x46, 0x6c, 0x6f, 0x61, 0x74, + 0x20, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x27, 0x6d, + 0x27, 0x20, 0x62, 0x69, 0x74, 0x73, 0x0a, 0x84, + 0x01, 0x5c, 0x64, 0x69, 0x67, 0x69, 0x74, 0x73, + 0x20, 0x6e, 0x20, 0x20, 0x20, 0x73, 0x65, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x42, 0x69, 0x67, + 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x70, 0x72, + 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x74, 0x6f, 0x20, 0x27, 0x63, 0x65, 0x69, 0x6c, + 0x28, 0x6e, 0x2a, 0x6c, 0x6f, 0x67, 0x32, 0x28, + 0x31, 0x30, 0x29, 0x29, 0x27, 0x20, 0x62, 0x69, + 0x74, 0x73, 0x0a, 0x68, 0x5c, 0x6d, 0x6f, 0x64, + 0x65, 0x20, 0x5b, 0x73, 0x74, 0x64, 0x7c, 0x6d, + 0x61, 0x74, 0x68, 0x5d, 0x20, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, + 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x28, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, + 0x04, 0x29, 0x0a, 0x22, 0x5c, 0x71, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x78, 0x69, 0x74, 0x0a, 0x06, 0x73, 0x65, + 0x6c, 0x26, 0x22, 0x75, 0x73, 0x65, 0x20, 0x6d, + 0x61, 0x74, 0x68, 0x22, 0x3b, 0x20, 0x76, 0x6f, + 0x69, 0x64, 0x20, 0x30, 0x3b, 0x0e, 0x67, 0x65, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x14, 0x65, 0x76, + 0x61, 0x6c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x22, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, + 0x63, 0x65, 0x5f, 0x62, 0x61, 0x72, 0x72, 0x69, + 0x65, 0x72, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, + 0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x0e, 0x54, + 0x68, 0x72, 0x6f, 0x77, 0x3a, 0x20, 0x3a, 0x51, + 0x4a, 0x53, 0x43, 0x61, 0x6c, 0x63, 0x20, 0x2d, + 0x20, 0x54, 0x79, 0x70, 0x65, 0x20, 0x22, 0x5c, + 0x68, 0x22, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, + 0x65, 0x6c, 0x70, 0x0a, 0x3a, 0x51, 0x75, 0x69, + 0x63, 0x6b, 0x4a, 0x53, 0x20, 0x2d, 0x20, 0x54, + 0x79, 0x70, 0x65, 0x20, 0x22, 0x5c, 0x68, 0x22, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, 0x65, 0x6c, + 0x70, 0x0a, 0x08, 0x20, 0x20, 0x20, 0x20, 0x0e, + 0x73, 0x65, 0x74, 0x50, 0x72, 0x65, 0x63, 0x08, + 0x62, 0x69, 0x6e, 0x64, 0x04, 0x67, 0x63, 0x02, + 0x7c, 0x6a, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x7c, + 0x63, 0x61, 0x73, 0x65, 0x7c, 0x63, 0x61, 0x74, + 0x63, 0x68, 0x7c, 0x63, 0x6f, 0x6e, 0x74, 0x69, + 0x6e, 0x75, 0x65, 0x7c, 0x64, 0x65, 0x62, 0x75, + 0x67, 0x67, 0x65, 0x72, 0x7c, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x7c, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x7c, 0x64, 0x6f, 0x7c, 0x5e, + 0x65, 0x6c, 0x73, 0x65, 0x7c, 0x66, 0x69, 0x6e, + 0x61, 0x6c, 0x6c, 0x79, 0x7c, 0x66, 0x6f, 0x72, + 0x7c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x7c, 0x69, 0x66, 0x7c, 0x69, 0x6e, 0x7c, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x6f, 0x66, 0x7c, 0x6e, 0x65, 0x77, 0x7c, 0x5e, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x7c, 0x73, + 0x77, 0x69, 0x74, 0x63, 0x68, 0x7c, 0x74, 0x68, + 0x69, 0x73, 0x7c, 0x74, 0x68, 0x72, 0x6f, 0x77, + 0x7c, 0x74, 0x72, 0x79, 0x7c, 0x74, 0x79, 0x70, + 0x65, 0x6f, 0x66, 0x7c, 0x77, 0x68, 0x69, 0x6c, + 0x65, 0x7c, 0x77, 0x69, 0x74, 0x68, 0x7c, 0x5a, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x7c, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x7c, 0x65, 0x6e, 0x75, 0x6d, + 0x7c, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7c, + 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x7c, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x73, 0x7c, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x7c, 0x66, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x7c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x7c, 0x6c, 0x65, 0x74, 0x7c, 0x70, + 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x7c, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x7c, 0x70, + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x7c, 0x28, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x7c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x7c, + 0x79, 0x69, 0x65, 0x6c, 0x64, 0x7c, 0x4e, 0x75, + 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, + 0x7c, 0x6e, 0x75, 0x6c, 0x6c, 0x7c, 0x74, 0x72, + 0x75, 0x65, 0x7c, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x7c, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x79, 0x7c, 0x4e, 0x61, 0x4e, 0x7c, 0x1e, 0x65, + 0x76, 0x61, 0x6c, 0x7c, 0x61, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x7c, 0x0c, 0x61, + 0x77, 0x61, 0x69, 0x74, 0x7c, 0x7a, 0x7c, 0x74, + 0x68, 0x69, 0x73, 0x7c, 0x73, 0x75, 0x70, 0x65, + 0x72, 0x7c, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x65, 0x64, 0x7c, 0x6e, 0x75, 0x6c, 0x6c, + 0x7c, 0x74, 0x72, 0x75, 0x65, 0x7c, 0x66, 0x61, + 0x6c, 0x73, 0x65, 0x7c, 0x49, 0x6e, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x79, 0x7c, 0x4e, 0x61, 0x4e, + 0x7c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x7c, 0x14, 0x7c, 0x76, 0x6f, 0x69, + 0x64, 0x7c, 0x76, 0x61, 0x72, 0x7c, 0x02, 0x2b, + 0x02, 0x60, 0x02, 0x7b, 0x14, 0x70, 0x75, 0x73, + 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x14, + 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x70, 0x6f, 0x70, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x26, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, + 0x0a, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x02, 0x69, + 0x06, 0x73, 0x74, 0x72, 0x24, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, + 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x16, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, + 0x18, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x70, 0x61, + 0x72, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x73, + 0x65, 0x74, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, + 0x0f, 0xc6, 0x03, 0x02, 0xc8, 0x03, 0xca, 0x03, + 0x00, 0x00, 0x02, 0x00, 0x80, 0x02, 0x00, 0x01, + 0x80, 0x02, 0x01, 0x0e, 0x00, 0x02, 0x03, 0xa6, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x01, 0x0d, + 0x00, 0xc8, 0x03, 0x00, 0x0d, 0xca, 0x03, 0x01, + 0x0d, 0x08, 0xea, 0x02, 0x29, 0xc0, 0x00, 0x38, + 0x8d, 0x00, 0x00, 0x00, 0xef, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0x00, 0x01, 0x77, 0x01, 0x02, 0x02, + 0x48, 0xf7, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x01, 0x0c, 0xc0, 0x00, 0xc3, 0x2a, 0xc0, 0x01, + 0xc3, 0x2b, 0xc0, 0x02, 0xc3, 0x2c, 0xc0, 0x03, + 0xc3, 0x2d, 0xc0, 0x04, 0xc3, 0x2e, 0xc0, 0x05, + 0xc3, 0x2f, 0xc0, 0x06, 0xc3, 0x30, 0xc0, 0x07, + 0xc3, 0x31, 0xc0, 0x08, 0xc3, 0x32, 0xc0, 0x09, + 0xc3, 0x33, 0xc0, 0x0a, 0xc3, 0x34, 0xc0, 0x0b, + 0xc3, 0x35, 0xc0, 0x0c, 0xc3, 0x36, 0xc0, 0x0d, + 0xc3, 0x37, 0xc0, 0x0e, 0xc3, 0x38, 0xc0, 0x0f, + 0xc3, 0x39, 0xc0, 0x10, 0xc3, 0x3a, 0xc0, 0x11, + 0xc3, 0x3b, 0xc0, 0x12, 0xc3, 0x3c, 0xc0, 0x13, + 0xc3, 0x3d, 0xc0, 0x14, 0xc3, 0x3e, 0xc0, 0x15, + 0xc3, 0x3f, 0xc0, 0x16, 0xc3, 0x40, 0xc0, 0x17, + 0xc3, 0x41, 0xc0, 0x18, 0xc3, 0x42, 0xc0, 0x19, + 0xc3, 0x43, 0xc0, 0x1a, 0xc3, 0x44, 0xc0, 0x1b, + 0xc3, 0x45, 0xc0, 0x1c, 0xc3, 0x46, 0xc0, 0x1d, + 0xc3, 0x47, 0xc0, 0x1e, 0xc3, 0x48, 0xc0, 0x1f, + 0xc3, 0x49, 0xc0, 0x20, 0xc3, 0x4a, 0xc0, 0x21, + 0xc3, 0x4b, 0xc0, 0x22, 0xc3, 0x4c, 0xc0, 0x23, + 0xc3, 0x4d, 0xc0, 0x24, 0xc3, 0x4e, 0xc0, 0x25, + 0xc3, 0x4f, 0xc0, 0x26, 0xc3, 0x50, 0xc0, 0x27, + 0xc3, 0x51, 0xc0, 0x28, 0xc3, 0x52, 0xc0, 0x29, + 0xc3, 0x53, 0xc0, 0x2a, 0xc3, 0x54, 0xc0, 0x2b, + 0xc3, 0x55, 0xc0, 0x2c, 0xc3, 0x56, 0xc0, 0x2d, + 0xc3, 0x57, 0xc0, 0x2e, 0xc3, 0x58, 0xc0, 0x2f, + 0xc3, 0x59, 0xc0, 0x30, 0xc3, 0x5a, 0xc0, 0x31, + 0xc3, 0x5b, 0xc0, 0x32, 0xc3, 0x5c, 0xc0, 0x33, + 0xc3, 0x5d, 0xc0, 0x34, 0xc3, 0x5e, 0xc0, 0x35, + 0xc3, 0x60, 0xc0, 0x36, 0xc3, 0x64, 0xc0, 0x37, + 0xc3, 0x65, 0xc0, 0x38, 0xc3, 0x66, 0xc0, 0x39, + 0xc3, 0x67, 0xc0, 0x3a, 0xc3, 0x6a, 0xc0, 0x3b, + 0xc3, 0x6b, 0xc0, 0x3c, 0xc3, 0x6c, 0xc0, 0x3d, + 0xc3, 0x6d, 0xc0, 0x3e, 0xc3, 0x6e, 0xc0, 0x3f, + 0xc3, 0x6f, 0xc0, 0x41, 0xc3, 0x70, 0xc0, 0x42, + 0xc3, 0x71, 0xc0, 0x43, 0xc3, 0x72, 0xc0, 0x44, + 0xc3, 0x73, 0xc0, 0x45, 0xc3, 0x74, 0xc0, 0x46, + 0xc3, 0x75, 0xc0, 0x47, 0xc3, 0x76, 0xd1, 0x65, + 0x01, 0x00, 0x43, 0xe5, 0x00, 0x00, 0x00, 0xd1, + 0x65, 0x00, 0x00, 0x43, 0xe4, 0x00, 0x00, 0x00, + 0xd1, 0x41, 0x95, 0x00, 0x00, 0x00, 0xc9, 0xd1, + 0x41, 0x99, 0x00, 0x00, 0x00, 0xca, 0xd1, 0x41, + 0x96, 0x00, 0x00, 0x00, 0xcb, 0xd1, 0x41, 0x9f, + 0x00, 0x00, 0x00, 0xcc, 0xd1, 0x41, 0x9d, 0x00, + 0x00, 0x00, 0xc3, 0x04, 0xd1, 0x41, 0xe6, 0x00, + 0x00, 0x00, 0xc3, 0x05, 0xd1, 0x41, 0xe7, 0x00, + 0x00, 0x00, 0xc3, 0x06, 0x65, 0x01, 0x00, 0x41, + 0xe8, 0x00, 0x00, 0x00, 0xf4, 0xc3, 0x07, 0x37, + 0xe9, 0x00, 0x00, 0x00, 0xf5, 0xc3, 0x08, 0x37, + 0xb3, 0x00, 0x00, 0x00, 0xf5, 0xc3, 0x09, 0x0b, + 0x04, 0xea, 0x00, 0x00, 0x00, 0x4c, 0xeb, 0x00, + 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x00, 0x4c, + 0xed, 0x00, 0x00, 0x00, 0x04, 0xee, 0x00, 0x00, + 0x00, 0x4c, 0xef, 0x00, 0x00, 0x00, 0x04, 0xf0, + 0x00, 0x00, 0x00, 0x4c, 0xf1, 0x00, 0x00, 0x00, + 0x04, 0xf2, 0x00, 0x00, 0x00, 0x4c, 0xf3, 0x00, + 0x00, 0x00, 0x04, 0xf4, 0x00, 0x00, 0x00, 0x4c, + 0xf5, 0x00, 0x00, 0x00, 0x04, 0xf6, 0x00, 0x00, + 0x00, 0x4c, 0xf7, 0x00, 0x00, 0x00, 0x04, 0xf8, + 0x00, 0x00, 0x00, 0x4c, 0xf9, 0x00, 0x00, 0x00, + 0x04, 0xfa, 0x00, 0x00, 0x00, 0x4c, 0xfb, 0x00, + 0x00, 0x00, 0x04, 0xfc, 0x00, 0x00, 0x00, 0x4c, + 0xfd, 0x00, 0x00, 0x00, 0x04, 0xfc, 0x00, 0x00, + 0x00, 0x4c, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xff, + 0x00, 0x00, 0x00, 0x4c, 0x00, 0x01, 0x00, 0x00, + 0x04, 0x01, 0x01, 0x00, 0x00, 0x4c, 0x02, 0x01, + 0x00, 0x00, 0x04, 0x03, 0x01, 0x00, 0x00, 0x4c, + 0x04, 0x01, 0x00, 0x00, 0x04, 0x05, 0x01, 0x00, + 0x00, 0x4c, 0x06, 0x01, 0x00, 0x00, 0x04, 0x07, + 0x01, 0x00, 0x00, 0x4c, 0x08, 0x01, 0x00, 0x00, + 0x04, 0x09, 0x01, 0x00, 0x00, 0x4c, 0x0a, 0x01, + 0x00, 0x00, 0x04, 0x0b, 0x01, 0x00, 0x00, 0x4c, + 0x0c, 0x01, 0x00, 0x00, 0xc3, 0x0a, 0xc2, 0x07, + 0xea, 0x7e, 0x0b, 0x04, 0xed, 0x00, 0x00, 0x00, + 0x4c, 0x16, 0x00, 0x00, 0x00, 0x04, 0xfb, 0x00, + 0x00, 0x00, 0x4c, 0x0d, 0x01, 0x00, 0x00, 0x04, + 0xf1, 0x00, 0x00, 0x00, 0x4c, 0x4b, 0x00, 0x00, + 0x00, 0x04, 0xf9, 0x00, 0x00, 0x00, 0x4c, 0x0e, + 0x01, 0x00, 0x00, 0x04, 0xf1, 0x00, 0x00, 0x00, + 0x4c, 0x49, 0x00, 0x00, 0x00, 0x04, 0xf5, 0x00, + 0x00, 0x00, 0x4c, 0x0f, 0x01, 0x00, 0x00, 0x04, + 0xfd, 0x00, 0x00, 0x00, 0x4c, 0x1b, 0x00, 0x00, + 0x00, 0x04, 0x08, 0x01, 0x00, 0x00, 0x4c, 0x10, + 0x01, 0x00, 0x00, 0x04, 0xf3, 0x00, 0x00, 0x00, + 0x4c, 0x11, 0x01, 0x00, 0x00, 0x04, 0x00, 0x01, + 0x00, 0x00, 0x4c, 0x12, 0x01, 0x00, 0x00, 0x04, + 0xed, 0x00, 0x00, 0x00, 0x4c, 0x13, 0x01, 0x00, + 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x4c, 0x14, + 0x01, 0x00, 0x00, 0xc3, 0x0b, 0xec, 0x7c, 0x0b, + 0x04, 0x02, 0x01, 0x00, 0x00, 0x4c, 0x16, 0x00, + 0x00, 0x00, 0x04, 0xfb, 0x00, 0x00, 0x00, 0x4c, + 0x0d, 0x01, 0x00, 0x00, 0x04, 0x0a, 0x01, 0x00, + 0x00, 0x4c, 0x4b, 0x00, 0x00, 0x00, 0x04, 0xf9, + 0x00, 0x00, 0x00, 0x4c, 0x0e, 0x01, 0x00, 0x00, + 0x04, 0xf1, 0x00, 0x00, 0x00, 0x4c, 0x49, 0x00, + 0x00, 0x00, 0x04, 0x0c, 0x01, 0x00, 0x00, 0x4c, + 0x0f, 0x01, 0x00, 0x00, 0x04, 0x04, 0x01, 0x00, + 0x00, 0x4c, 0x1b, 0x00, 0x00, 0x00, 0x04, 0x08, + 0x01, 0x00, 0x00, 0x4c, 0x10, 0x01, 0x00, 0x00, + 0x04, 0x02, 0x01, 0x00, 0x00, 0x4c, 0x11, 0x01, + 0x00, 0x00, 0x04, 0xef, 0x00, 0x00, 0x00, 0x4c, + 0x12, 0x01, 0x00, 0x00, 0x04, 0x0c, 0x01, 0x00, + 0x00, 0x4c, 0x13, 0x01, 0x00, 0x00, 0x04, 0x00, + 0x01, 0x00, 0x00, 0x4c, 0x14, 0x01, 0x00, 0x00, + 0xc3, 0x0b, 0x26, 0x00, 0x00, 0xc3, 0x0c, 0xc1, + 0xc3, 0x0d, 0xc1, 0xc3, 0x11, 0xc1, 0xc3, 0x12, + 0xb5, 0xc3, 0x13, 0xc2, 0x07, 0xea, 0x0a, 0x04, + 0x15, 0x01, 0x00, 0x00, 0xc3, 0x14, 0xec, 0x08, + 0x04, 0x16, 0x01, 0x00, 0x00, 0xc3, 0x14, 0x04, + 0x17, 0x01, 0x00, 0x00, 0xc3, 0x15, 0x0a, 0xc3, + 0x16, 0x09, 0xc3, 0x17, 0x0a, 0xc3, 0x18, 0xb5, + 0xc3, 0x19, 0xc1, 0xc3, 0x1a, 0xb5, 0xc3, 0x1b, + 0xc1, 0xc3, 0x1c, 0xb5, 0xc3, 0x1d, 0xc1, 0xc3, + 0x1e, 0xb5, 0xc3, 0x1f, 0x09, 0xc3, 0x23, 0xb5, + 0xc3, 0x24, 0xb5, 0xc3, 0x25, 0xb5, 0xc3, 0x29, + 0x0b, 0xc2, 0x3c, 0x4c, 0x18, 0x01, 0x00, 0x00, + 0xc2, 0x3f, 0x4c, 0x19, 0x01, 0x00, 0x00, 0xc2, + 0x59, 0x4c, 0x1a, 0x01, 0x00, 0x00, 0xc2, 0x4d, + 0x4c, 0x1b, 0x01, 0x00, 0x00, 0xc2, 0x3d, 0x4c, + 0x1c, 0x01, 0x00, 0x00, 0xc2, 0x3e, 0x4c, 0x1d, + 0x01, 0x00, 0x00, 0xc2, 0x3a, 0x4c, 0x1e, 0x01, + 0x00, 0x00, 0xc2, 0x4e, 0x4c, 0x1f, 0x01, 0x00, + 0x00, 0xc2, 0x5e, 0x4c, 0x20, 0x01, 0x00, 0x00, + 0xc2, 0x44, 0x4c, 0x21, 0x01, 0x00, 0x00, 0xc2, + 0x54, 0x4c, 0x22, 0x01, 0x00, 0x00, 0xc2, 0x44, + 0x4c, 0x23, 0x01, 0x00, 0x00, 0xc2, 0x47, 0x4c, + 0x24, 0x01, 0x00, 0x00, 0xc2, 0x46, 0x4c, 0x25, + 0x01, 0x00, 0x00, 0xc2, 0x39, 0x4c, 0x26, 0x01, + 0x00, 0x00, 0xc2, 0x3b, 0x4c, 0x27, 0x01, 0x00, + 0x00, 0xc2, 0x3b, 0x4c, 0x28, 0x01, 0x00, 0x00, + 0xc2, 0x4f, 0x4c, 0x29, 0x01, 0x00, 0x00, 0xc2, + 0x5a, 0x4c, 0x2a, 0x01, 0x00, 0x00, 0xc2, 0x58, + 0x4c, 0x2b, 0x01, 0x00, 0x00, 0xc2, 0x46, 0x4c, + 0x2c, 0x01, 0x00, 0x00, 0xc2, 0x47, 0x4c, 0x2d, + 0x01, 0x00, 0x00, 0xc2, 0x3e, 0x4c, 0x2e, 0x01, + 0x00, 0x00, 0xc2, 0x3f, 0x4c, 0x2f, 0x01, 0x00, + 0x00, 0xc2, 0x42, 0x4c, 0x30, 0x01, 0x00, 0x00, + 0xc2, 0x43, 0x4c, 0x31, 0x01, 0x00, 0x00, 0xc2, + 0x42, 0x4c, 0x32, 0x01, 0x00, 0x00, 0xc2, 0x43, + 0x4c, 0x33, 0x01, 0x00, 0x00, 0xc2, 0x3c, 0x4c, + 0x34, 0x01, 0x00, 0x00, 0xc2, 0x4c, 0x4c, 0x35, + 0x01, 0x00, 0x00, 0xc2, 0x3d, 0x4c, 0x36, 0x01, + 0x00, 0x00, 0xc2, 0x49, 0x4c, 0x37, 0x01, 0x00, + 0x00, 0xc2, 0x4a, 0x4c, 0x38, 0x01, 0x00, 0x00, + 0xc2, 0x46, 0x4c, 0x39, 0x01, 0x00, 0x00, 0xc2, + 0x47, 0x4c, 0x3a, 0x01, 0x00, 0x00, 0xc2, 0x3e, + 0x4c, 0x3b, 0x01, 0x00, 0x00, 0xc2, 0x3f, 0x4c, + 0x3c, 0x01, 0x00, 0x00, 0xc2, 0x3d, 0x4c, 0x3d, + 0x01, 0x00, 0x00, 0xc2, 0x3c, 0x4c, 0x3e, 0x01, + 0x00, 0x00, 0xc2, 0x57, 0x4c, 0x3f, 0x01, 0x00, + 0x00, 0xc2, 0x43, 0x4c, 0x40, 0x01, 0x00, 0x00, + 0xc2, 0x56, 0x4c, 0x41, 0x01, 0x00, 0x00, 0xc2, + 0x42, 0x4c, 0x42, 0x01, 0x00, 0x00, 0xc2, 0x55, + 0x4c, 0x43, 0x01, 0x00, 0x00, 0xc2, 0x52, 0x4c, + 0x44, 0x01, 0x00, 0x00, 0xc2, 0x50, 0x4c, 0x45, + 0x01, 0x00, 0x00, 0xc2, 0x51, 0x4c, 0x46, 0x01, + 0x00, 0x00, 0xc2, 0x4e, 0x4c, 0x47, 0x01, 0x00, + 0x00, 0xc3, 0x5f, 0x09, 0xc3, 0x68, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0xc3, 0x69, 0xc2, 0x07, 0xea, + 0x09, 0xd1, 0xc0, 0x40, 0x43, 0x48, 0x01, 0x00, + 0x00, 0xc2, 0x2a, 0xee, 0x0e, 0xc2, 0x72, 0xee, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0x92, 0x05, 0x00, + 0x01, 0x00, 0x04, 0x07, 0x00, 0x8b, 0x01, 0x00, + 0x00, 0x26, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x28, + 0x01, 0x00, 0x01, 0x0c, 0x00, 0x2b, 0x01, 0x00, + 0x27, 0x01, 0x00, 0x2c, 0x01, 0x65, 0x01, 0x00, + 0x41, 0x0d, 0x00, 0x00, 0x00, 0x42, 0x4a, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xe1, 0xbd, 0x50, + 0xe3, 0x65, 0x03, 0x00, 0x42, 0x4b, 0x01, 0x00, + 0x00, 0xdd, 0x24, 0x01, 0x00, 0xea, 0x35, 0x65, + 0x03, 0x00, 0x41, 0x4c, 0x01, 0x00, 0x00, 0xea, + 0x14, 0x65, 0x03, 0x00, 0x42, 0x4c, 0x01, 0x00, + 0x00, 0xdd, 0x24, 0x01, 0x00, 0xcd, 0xea, 0x05, + 0xc5, 0xb5, 0x47, 0xe3, 0x65, 0x03, 0x00, 0x41, + 0x4d, 0x01, 0x00, 0x00, 0xea, 0x0e, 0x65, 0x03, + 0x00, 0x42, 0x4d, 0x01, 0x00, 0x00, 0xdd, 0x24, + 0x01, 0x00, 0x0e, 0x65, 0x03, 0x00, 0x42, 0x4e, + 0x01, 0x00, 0x00, 0x65, 0x03, 0x00, 0x41, 0x4f, + 0x01, 0x00, 0x00, 0x5e, 0x04, 0x00, 0x24, 0x02, + 0x00, 0x0e, 0x38, 0xa8, 0x00, 0x00, 0x00, 0x11, + 0xbd, 0x40, 0x21, 0x01, 0x00, 0x5f, 0x05, 0x00, + 0x65, 0x03, 0x00, 0x42, 0x50, 0x01, 0x00, 0x00, + 0xdd, 0x5e, 0x06, 0x00, 0x24, 0x02, 0x00, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xa2, 0x05, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0xa4, 0x05, + 0x2d, 0x01, 0xdd, 0xb8, 0xef, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xa6, 0x05, 0x00, 0x02, 0x00, 0x06, + 0x04, 0x00, 0x28, 0x00, 0x00, 0x01, 0x0c, 0x00, + 0x26, 0x01, 0x00, 0x27, 0x01, 0x00, 0x2d, 0x01, + 0x65, 0x00, 0x00, 0x42, 0x54, 0x01, 0x00, 0x00, + 0xde, 0xdf, 0x41, 0x55, 0x01, 0x00, 0x00, 0xb5, + 0xdf, 0xe9, 0x24, 0x04, 0x00, 0xc9, 0xb5, 0xca, + 0xc6, 0xc5, 0xa3, 0xea, 0x0b, 0xe0, 0xdf, 0xc6, + 0x47, 0xef, 0x0e, 0x93, 0x01, 0xec, 0xf2, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xa4, 0x05, 0x01, 0x00, + 0x01, 0x04, 0x04, 0x00, 0x5f, 0x00, 0x00, 0x16, + 0x01, 0x00, 0x66, 0x01, 0x00, 0x24, 0x01, 0x00, + 0x25, 0x01, 0xdd, 0x96, 0xea, 0x06, 0xde, 0xd1, + 0xef, 0x0e, 0x29, 0xdf, 0xb5, 0xac, 0xea, 0x24, + 0xd1, 0xbe, 0x80, 0x00, 0xa6, 0xea, 0x1d, 0xd1, + 0xbe, 0xc0, 0x00, 0xa3, 0xea, 0x16, 0xe0, 0xbb, + 0xa0, 0xd1, 0xbd, 0x3f, 0xad, 0xaf, 0xe4, 0xdf, + 0x8e, 0xe7, 0xb5, 0xab, 0xea, 0x33, 0xde, 0xe0, + 0xef, 0x0e, 0x29, 0xd1, 0xbe, 0xc0, 0x00, 0xa6, + 0xea, 0x21, 0xd1, 0xbe, 0xf8, 0x00, 0xa3, 0xea, + 0x1a, 0xb6, 0xd1, 0xbe, 0xe0, 0x00, 0xa6, 0x9d, + 0xd1, 0xbe, 0xf0, 0x00, 0xa6, 0x9d, 0xe3, 0xd1, + 0xb6, 0xbb, 0xdf, 0x9e, 0xa0, 0xb6, 0x9e, 0xad, + 0xe4, 0x29, 0xb5, 0xe3, 0xde, 0xd1, 0xef, 0x0e, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xac, 0x05, 0x01, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x35, 0x00, 0xd1, + 0x97, 0x04, 0x4b, 0x00, 0x00, 0x00, 0xab, 0x11, + 0xea, 0x2a, 0x0e, 0xd1, 0x04, 0x57, 0x01, 0x00, + 0x00, 0xa6, 0x11, 0xea, 0x09, 0x0e, 0xd1, 0x04, + 0x58, 0x01, 0x00, 0x00, 0xa4, 0x11, 0xeb, 0x14, + 0x0e, 0xd1, 0x04, 0x59, 0x01, 0x00, 0x00, 0xa6, + 0x11, 0xea, 0x09, 0x0e, 0xd1, 0x04, 0x5a, 0x01, + 0x00, 0x00, 0xa4, 0x28, 0x0e, 0x43, 0x02, 0x03, + 0xb6, 0x05, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, + 0x19, 0x00, 0xd1, 0x97, 0x04, 0x4b, 0x00, 0x00, + 0x00, 0xab, 0x11, 0xea, 0x0e, 0x0e, 0xd1, 0xbf, + 0x00, 0xa6, 0x11, 0xea, 0x06, 0x0e, 0xd1, 0xbf, + 0x01, 0xa4, 0x28, 0x07, 0x02, 0x30, 0x07, 0x02, + 0x39, 0x0e, 0x43, 0x02, 0x03, 0xb8, 0x05, 0x01, + 0x00, 0x01, 0x02, 0x02, 0x00, 0x2d, 0x00, 0x00, + 0x2e, 0x01, 0x00, 0x2f, 0x01, 0xd1, 0x97, 0x04, + 0x4b, 0x00, 0x00, 0x00, 0xab, 0x11, 0xea, 0x22, + 0x0e, 0xdd, 0xd1, 0xef, 0x11, 0xeb, 0x1b, 0x0e, + 0xde, 0xd1, 0xef, 0x11, 0xeb, 0x14, 0x0e, 0xd1, + 0x04, 0x5d, 0x01, 0x00, 0x00, 0xa9, 0x11, 0xeb, + 0x09, 0x0e, 0xd1, 0x04, 0x5e, 0x01, 0x00, 0x00, + 0xa9, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xbe, 0x05, + 0x01, 0x04, 0x01, 0x03, 0x00, 0x00, 0x32, 0x00, + 0xd1, 0xe9, 0xcc, 0xb5, 0xc9, 0xb5, 0xcb, 0xc7, + 0xc8, 0xa3, 0xea, 0x25, 0xd1, 0x42, 0x60, 0x01, + 0x00, 0x00, 0xc7, 0x24, 0x01, 0x00, 0xce, 0x01, + 0x00, 0xdc, 0x00, 0x00, 0xa3, 0x11, 0xeb, 0x09, + 0x0e, 0xc6, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xa6, + 0xea, 0x03, 0x93, 0x00, 0x93, 0x02, 0xec, 0xd8, + 0xc5, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xc2, 0x05, + 0x01, 0x01, 0x01, 0x03, 0x00, 0x00, 0x29, 0x00, + 0xd1, 0x97, 0x04, 0x4b, 0x00, 0x00, 0x00, 0xac, + 0xea, 0x03, 0x09, 0x28, 0xd1, 0x42, 0x62, 0x01, + 0x00, 0x00, 0xb5, 0x24, 0x01, 0x00, 0xcd, 0x01, + 0x00, 0xdc, 0x00, 0x00, 0xa6, 0x11, 0xea, 0x09, + 0x0e, 0xc5, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xa3, + 0x28, 0x0e, 0x43, 0x02, 0x03, 0xc6, 0x05, 0x02, + 0x00, 0x02, 0x03, 0x00, 0x00, 0x23, 0x00, 0xd1, + 0xd2, 0x9d, 0x11, 0x04, 0x64, 0x01, 0x00, 0x00, + 0xab, 0xeb, 0x13, 0x11, 0x04, 0x65, 0x01, 0x00, + 0x00, 0xab, 0xeb, 0x0a, 0x11, 0x04, 0x66, 0x01, + 0x00, 0x00, 0xab, 0xea, 0x03, 0x0a, 0x28, 0x0e, + 0x09, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xce, 0x05, + 0x03, 0x03, 0x03, 0x06, 0x03, 0x00, 0x63, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x0a, 0x01, 0x00, 0x0b, + 0x01, 0xd2, 0xca, 0xc6, 0xd1, 0xe9, 0xa3, 0xea, + 0x5b, 0xd3, 0xc6, 0xcd, 0x47, 0xcb, 0xc6, 0x8f, + 0xce, 0xd1, 0xe9, 0xa3, 0xea, 0x08, 0xd3, 0xc6, + 0x47, 0xc7, 0xa9, 0xeb, 0xf2, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0xde, 0xdf, 0xc7, + 0x47, 0x11, 0xeb, 0x07, 0x0e, 0x04, 0x16, 0x00, + 0x00, 0x00, 0x47, 0x24, 0x01, 0x00, 0x0e, 0x65, + 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0xd1, + 0x42, 0x69, 0x01, 0x00, 0x00, 0xc5, 0xc6, 0x24, + 0x02, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x65, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0xde, 0x04, + 0xeb, 0x00, 0x00, 0x00, 0x47, 0x24, 0x01, 0x00, + 0x0e, 0xec, 0xa1, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xd4, 0x05, 0x02, 0x00, 0x02, 0x05, 0x01, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x0c, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x6b, 0x01, + 0x00, 0x00, 0xd1, 0xb6, 0xaa, 0xea, 0x04, 0xd1, + 0xec, 0x02, 0xc1, 0x9d, 0xd2, 0x9d, 0x24, 0x01, + 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xd8, 0x05, + 0x01, 0x02, 0x01, 0x04, 0x05, 0x00, 0xa1, 0x01, + 0x00, 0x00, 0x29, 0x01, 0x00, 0x28, 0x01, 0x00, + 0x00, 0x0c, 0x00, 0x04, 0x01, 0x00, 0x35, 0x01, + 0xd1, 0xb5, 0xa5, 0xea, 0x4d, 0xd1, 0xb5, 0xaa, + 0x69, 0x97, 0x00, 0x00, 0x00, 0xdd, 0xde, 0xb6, + 0x9e, 0xa9, 0xea, 0x19, 0x65, 0x02, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x21, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xb5, 0xe1, 0xd1, + 0x8e, 0xd5, 0xec, 0xda, 0xe0, 0x42, 0x6d, 0x01, + 0x00, 0x00, 0xde, 0xb6, 0x9e, 0xdd, 0x9e, 0xd1, + 0x24, 0x02, 0x00, 0xca, 0x5e, 0x04, 0x00, 0xc6, + 0x04, 0x6e, 0x01, 0x00, 0x00, 0xf0, 0x0e, 0xd1, + 0xc6, 0x9e, 0xd5, 0xdd, 0xc6, 0x9d, 0xe1, 0xec, + 0xb5, 0xd1, 0x8c, 0xd5, 0xd1, 0xb5, 0xaa, 0xea, + 0x48, 0xdd, 0xb5, 0xa9, 0xea, 0x22, 0x5e, 0x04, + 0x00, 0xb6, 0x04, 0x57, 0x01, 0x00, 0x00, 0xf0, + 0x0e, 0x5e, 0x04, 0x00, 0xde, 0xb6, 0x9e, 0x04, + 0x6e, 0x01, 0x00, 0x00, 0xf0, 0x0e, 0xd1, 0x8e, + 0xd5, 0xde, 0xb6, 0x9e, 0xe1, 0xec, 0xd6, 0xe0, + 0x42, 0x6d, 0x01, 0x00, 0x00, 0xd1, 0xdd, 0x24, + 0x02, 0x00, 0xca, 0x5e, 0x04, 0x00, 0xc6, 0x04, + 0x6f, 0x01, 0x00, 0x00, 0xf0, 0x0e, 0xd1, 0xc6, + 0x9e, 0xd5, 0xdd, 0xc6, 0x9e, 0xe1, 0xec, 0xb5, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xe0, 0x05, 0x00, + 0x05, 0x00, 0x06, 0x0d, 0x00, 0x9c, 0x02, 0x00, + 0x00, 0x1c, 0x01, 0x00, 0x1e, 0x01, 0x00, 0x18, + 0x01, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x0c, 0x00, + 0x36, 0x01, 0x00, 0x31, 0x01, 0x00, 0x1a, 0x01, + 0x00, 0x76, 0x01, 0x00, 0x34, 0x01, 0x00, 0x29, + 0x01, 0x00, 0x28, 0x01, 0x00, 0x1d, 0x01, 0xdd, + 0xde, 0xaa, 0x69, 0xc6, 0x00, 0x00, 0x00, 0xdf, + 0x96, 0xea, 0x32, 0xde, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xb5, 0xe0, 0x24, 0x02, 0x00, 0xdd, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xb5, 0xe0, 0x24, 0x02, + 0x00, 0xa9, 0xea, 0x19, 0x65, 0x04, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xdd, 0x42, 0x69, 0x01, + 0x00, 0x00, 0xe0, 0x24, 0x01, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xec, 0x53, 0x5e, 0x05, 0x00, 0x5e, + 0x06, 0x00, 0xde, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb5, 0xe0, 0x24, 0x02, 0x00, 0xef, 0x8c, 0xef, + 0x0e, 0xdf, 0xea, 0x2e, 0x5e, 0x07, 0x00, 0xea, + 0x0e, 0x5e, 0x07, 0x00, 0x04, 0x21, 0x01, 0x00, + 0x00, 0x9d, 0xdd, 0x9d, 0xec, 0x02, 0xdd, 0xcf, + 0xe9, 0xdd, 0xe9, 0x9e, 0xcc, 0x5e, 0x08, 0x00, + 0xc7, 0xef, 0xc3, 0x04, 0x5e, 0x09, 0x00, 0xc7, + 0xc8, 0xc2, 0x04, 0xb7, 0x47, 0xf1, 0x0e, 0xec, + 0x0e, 0x65, 0x04, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0xdd, 0x24, 0x01, 0x00, 0x0e, 0x5e, 0x0a, + 0x00, 0x5e, 0x06, 0x00, 0xdd, 0xef, 0x9d, 0x5e, + 0x0b, 0x00, 0x9c, 0x60, 0x0a, 0x00, 0xb5, 0xa9, + 0xea, 0x12, 0x65, 0x04, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x71, 0x01, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0x65, 0x04, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x72, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xdd, 0xe2, 0xdd, 0xe9, + 0xe4, 0x5e, 0x0c, 0x00, 0xe0, 0xa5, 0xea, 0x19, + 0x5e, 0x05, 0x00, 0x5e, 0x06, 0x00, 0xdd, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xe0, 0x5e, 0x0c, 0x00, + 0x24, 0x02, 0x00, 0xef, 0xef, 0x0e, 0xec, 0x1f, + 0x5e, 0x0c, 0x00, 0xe0, 0xa3, 0xea, 0x18, 0x5e, + 0x05, 0x00, 0x5e, 0x06, 0x00, 0xdd, 0x42, 0x69, + 0x01, 0x00, 0x00, 0x5e, 0x0c, 0x00, 0xe0, 0x24, + 0x02, 0x00, 0xef, 0x8c, 0xef, 0x0e, 0x5e, 0x0c, + 0x00, 0xe4, 0x65, 0x04, 0x00, 0x41, 0x73, 0x01, + 0x00, 0x00, 0x42, 0x74, 0x01, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xea, + 0x05, 0x01, 0x00, 0x01, 0x04, 0x02, 0x00, 0x22, + 0x00, 0x00, 0x1c, 0x01, 0x00, 0x1d, 0x01, 0xd1, + 0xea, 0x1f, 0xdd, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb5, 0xde, 0x24, 0x02, 0x00, 0xd1, 0x9d, 0xdd, + 0x42, 0x69, 0x01, 0x00, 0x00, 0xde, 0x24, 0x01, + 0x00, 0x9d, 0xe1, 0xde, 0xd1, 0xe9, 0x9d, 0xe2, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xec, 0x05, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0xee, + 0x05, 0x23, 0x01, 0x0a, 0xe1, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xf0, 0x05, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x07, 0x00, 0xf2, 0x05, 0x1c, 0x01, + 0xf4, 0x05, 0x1d, 0x01, 0xc1, 0xe1, 0xb5, 0xe2, + 0xbd, 0xfe, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xf6, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xf8, 0x05, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, + 0xf4, 0x05, 0x1d, 0x01, 0xb5, 0xe1, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xfa, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x04, 0x00, 0xf4, 0x05, 0x1d, + 0x01, 0xf2, 0x05, 0x1c, 0x01, 0xde, 0xe9, 0xe1, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xfc, 0x05, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x1d, 0x00, 0xf4, + 0x05, 0x1d, 0x01, 0xf2, 0x05, 0x1c, 0x01, 0xc2, + 0x05, 0x32, 0x01, 0xdd, 0xde, 0xe9, 0xa3, 0xea, + 0x17, 0xdd, 0x8f, 0xe1, 0xdf, 0xde, 0x42, 0x7f, + 0x01, 0x00, 0x00, 0xdd, 0x24, 0x01, 0x00, 0xef, + 0xea, 0x06, 0xdd, 0x8f, 0xe1, 0xec, 0xee, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0x80, 0x06, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x1c, 0x00, 0xf4, 0x05, + 0x1d, 0x01, 0xc2, 0x05, 0x32, 0x01, 0xf2, 0x05, + 0x1c, 0x01, 0xdd, 0xb5, 0xa5, 0xea, 0x17, 0xdd, + 0x8e, 0xe1, 0xde, 0xdf, 0x42, 0x7f, 0x01, 0x00, + 0x00, 0xdd, 0x24, 0x01, 0x00, 0xef, 0xea, 0x06, + 0xdd, 0x8e, 0xe1, 0xec, 0xee, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0x82, 0x06, 0x01, 0x00, 0x01, 0x04, + 0x02, 0x00, 0x35, 0x00, 0x00, 0x1c, 0x01, 0x00, + 0x30, 0x01, 0xd1, 0xdd, 0xe9, 0xa3, 0xea, 0x15, + 0xde, 0xdd, 0x42, 0x7f, 0x01, 0x00, 0x00, 0xd1, + 0x24, 0x01, 0x00, 0xef, 0x96, 0xea, 0x06, 0xd1, + 0x8f, 0xd5, 0xec, 0xe7, 0xd1, 0xdd, 0xe9, 0xa3, + 0xea, 0x14, 0xde, 0xdd, 0x42, 0x7f, 0x01, 0x00, + 0x00, 0xd1, 0x24, 0x01, 0x00, 0xef, 0xea, 0x06, + 0xd1, 0x8f, 0xd5, 0xec, 0xe8, 0xd1, 0x28, 0x0e, + 0x43, 0x02, 0x03, 0x84, 0x06, 0x01, 0x00, 0x01, + 0x05, 0x02, 0x00, 0x37, 0x00, 0x00, 0x30, 0x01, + 0x00, 0x1c, 0x01, 0xd1, 0xb5, 0xa5, 0xea, 0x17, + 0xdd, 0xde, 0x42, 0x7f, 0x01, 0x00, 0x00, 0xd1, + 0xb6, 0x9e, 0x24, 0x01, 0x00, 0xef, 0x96, 0xea, + 0x06, 0xd1, 0x8e, 0xd5, 0xec, 0xe6, 0xd1, 0xb5, + 0xa5, 0xea, 0x16, 0xdd, 0xde, 0x42, 0x7f, 0x01, + 0x00, 0x00, 0xd1, 0xb6, 0x9e, 0x24, 0x01, 0x00, + 0xef, 0xea, 0x06, 0xd1, 0x8e, 0xd5, 0xec, 0xe7, + 0xd1, 0x28, 0x0e, 0x43, 0x02, 0x03, 0x86, 0x06, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x05, 0x00, + 0xf4, 0x05, 0x1d, 0x01, 0x82, 0x06, 0x40, 0x01, + 0xde, 0xdd, 0xef, 0xe1, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0x88, 0x06, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x00, 0x05, 0x00, 0xf4, 0x05, 0x1d, 0x01, 0x84, + 0x06, 0x41, 0x01, 0xde, 0xdd, 0xef, 0xe1, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0x8a, 0x06, 0x00, 0x00, + 0x00, 0x03, 0x03, 0x00, 0x17, 0x00, 0xc8, 0x03, + 0x00, 0x0c, 0x8c, 0x06, 0x45, 0x01, 0xf2, 0x05, + 0x1c, 0x01, 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0xde, 0xdf, 0xef, 0x0e, 0xb4, + 0x28, 0x0e, 0x43, 0x02, 0x03, 0x8c, 0x06, 0x01, + 0x00, 0x01, 0x03, 0x02, 0x00, 0x12, 0x00, 0x00, + 0x0c, 0x01, 0x00, 0x20, 0x01, 0xd1, 0xea, 0x0c, + 0xdd, 0x42, 0x87, 0x01, 0x00, 0x00, 0xd1, 0x24, + 0x01, 0x00, 0x0e, 0xdd, 0xe9, 0xe2, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0x90, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x04, 0x00, 0x20, 0x00, 0x92, 0x06, 0x20, + 0x01, 0x94, 0x06, 0x0c, 0x01, 0xf2, 0x05, 0x1c, + 0x01, 0xf4, 0x05, 0x1d, 0x01, 0xdd, 0xb5, 0xa5, + 0xea, 0x1b, 0xdd, 0xde, 0xe9, 0xa9, 0xea, 0x0c, + 0xde, 0x42, 0x87, 0x01, 0x00, 0x00, 0xdf, 0x24, + 0x01, 0x00, 0x0e, 0xdd, 0x8e, 0xe1, 0xde, 0xdd, + 0x47, 0xe7, 0xe9, 0xe4, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0x96, 0x06, 0x00, 0x00, 0x00, 0x03, 0x04, + 0x00, 0x12, 0x00, 0x92, 0x06, 0x20, 0x01, 0x94, + 0x06, 0x0c, 0x01, 0xf2, 0x05, 0x1c, 0x01, 0xf4, + 0x05, 0x1d, 0x01, 0xdd, 0xde, 0xe9, 0xb6, 0x9e, + 0xa3, 0xea, 0x0a, 0xdd, 0x8f, 0xe1, 0xde, 0xdd, + 0x47, 0xe7, 0xe9, 0xe4, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0x98, 0x06, 0x01, 0x03, 0x01, 0x05, 0x04, + 0x00, 0x3d, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x0c, + 0x01, 0x00, 0x20, 0x01, 0x00, 0x1c, 0x01, 0xdd, + 0xc9, 0xb6, 0xca, 0xc6, 0xde, 0xe9, 0xa4, 0xea, + 0x33, 0xde, 0xe9, 0xc6, 0xd1, 0x9a, 0x9d, 0xdf, + 0x9d, 0xde, 0xe9, 0x9c, 0xcb, 0xde, 0xc7, 0x47, + 0x42, 0x69, 0x01, 0x00, 0x00, 0xb5, 0xc5, 0x24, + 0x02, 0x00, 0xe0, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb5, 0xc5, 0x24, 0x02, 0x00, 0xa9, 0xea, 0x08, + 0xc7, 0xe3, 0xde, 0xc7, 0x47, 0xe4, 0x29, 0x93, + 0x01, 0xec, 0xc9, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0x9a, 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, + 0x05, 0x00, 0x98, 0x06, 0x48, 0x01, 0xdd, 0xb4, + 0x23, 0x01, 0x00, 0x0e, 0x43, 0x02, 0x03, 0x9c, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, + 0x00, 0x98, 0x06, 0x48, 0x01, 0xdd, 0xb6, 0x23, + 0x01, 0x00, 0x0e, 0x43, 0x02, 0x03, 0x9e, 0x06, + 0x01, 0x02, 0x01, 0x04, 0x05, 0x00, 0x66, 0x00, + 0x00, 0x1d, 0x01, 0x00, 0x32, 0x01, 0x00, 0x1c, + 0x01, 0x00, 0x22, 0x01, 0x00, 0x53, 0x01, 0xdd, + 0xc9, 0xd1, 0xb5, 0xa3, 0xea, 0x15, 0x92, 0x00, + 0xde, 0xdf, 0x42, 0x7f, 0x01, 0x00, 0x00, 0xc5, + 0x24, 0x01, 0x00, 0xef, 0xea, 0x05, 0x92, 0x00, + 0xec, 0xef, 0xc5, 0xb6, 0x9d, 0xca, 0xde, 0xdf, + 0x42, 0x7f, 0x01, 0x00, 0x00, 0xc6, 0x24, 0x01, + 0x00, 0xef, 0xea, 0x05, 0x93, 0x01, 0xec, 0xef, + 0xc5, 0xb5, 0xa6, 0xea, 0x30, 0xc5, 0xdf, 0xe9, + 0xa3, 0xea, 0x2a, 0xe0, 0x5e, 0x04, 0x00, 0xab, + 0xea, 0x0a, 0x5e, 0x04, 0x00, 0xc5, 0xc6, 0xd1, + 0xf1, 0x0e, 0x29, 0xdf, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xb5, 0xc5, 0x24, 0x02, 0x00, 0xdf, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xc6, 0x24, 0x01, 0x00, + 0x9d, 0xe3, 0xc5, 0xe1, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xa0, 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, + 0x00, 0x04, 0x00, 0x9e, 0x06, 0x4b, 0x01, 0xdd, + 0xb6, 0xef, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xa2, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x1f, + 0x00, 0xf2, 0x05, 0x1c, 0x01, 0xc8, 0x03, 0x00, + 0x0c, 0x9e, 0x06, 0x4b, 0x01, 0xdd, 0xe9, 0xb5, + 0xa9, 0xea, 0x15, 0x65, 0x01, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xbd, 0xfd, 0x28, 0xdf, + 0xb6, 0xef, 0x0e, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xa4, 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, + 0x04, 0x00, 0x9e, 0x06, 0x4b, 0x01, 0xdd, 0xb4, + 0xef, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xa6, 0x06, + 0x00, 0x01, 0x00, 0x06, 0x02, 0x00, 0x51, 0x00, + 0x00, 0x1d, 0x01, 0x00, 0x1c, 0x01, 0xdd, 0xc9, + 0xde, 0xe9, 0xb6, 0xa5, 0xea, 0x49, 0xc5, 0xb5, + 0xa5, 0xea, 0x44, 0xc5, 0xde, 0xe9, 0xa9, 0xea, + 0x03, 0x92, 0x00, 0xde, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xb5, 0xc5, 0xb6, 0x9e, 0x24, 0x02, 0x00, + 0xde, 0x42, 0x69, 0x01, 0x00, 0x00, 0xc5, 0xc5, + 0xb6, 0x9d, 0x24, 0x02, 0x00, 0x9d, 0xde, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xc5, 0xb6, 0x9e, 0xc5, + 0x24, 0x02, 0x00, 0x9d, 0xde, 0x42, 0x69, 0x01, + 0x00, 0x00, 0xc5, 0xb6, 0x9d, 0x24, 0x01, 0x00, + 0x9d, 0xe2, 0xc5, 0xb6, 0x9d, 0xe1, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xa8, 0x06, 0x00, 0x04, 0x00, + 0x05, 0x04, 0x00, 0x57, 0x00, 0x00, 0x41, 0x01, + 0x00, 0x1d, 0x01, 0x00, 0x40, 0x01, 0x00, 0x1c, + 0x01, 0xdd, 0xde, 0xef, 0xc9, 0xdf, 0xc5, 0xef, + 0xca, 0xdf, 0xde, 0xef, 0xcb, 0xdd, 0xc7, 0xef, + 0xcc, 0xc5, 0xc6, 0xa3, 0xea, 0x42, 0xc6, 0xde, + 0xa4, 0xea, 0x3d, 0xde, 0xc8, 0xa4, 0xea, 0x38, + 0xc8, 0xc7, 0xa3, 0xea, 0x33, 0xe0, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xb5, 0xc5, 0x24, 0x02, 0x00, + 0xe0, 0x42, 0x69, 0x01, 0x00, 0x00, 0xc8, 0xc7, + 0x24, 0x02, 0x00, 0x9d, 0xe0, 0x42, 0x69, 0x01, + 0x00, 0x00, 0xc6, 0xc8, 0x24, 0x02, 0x00, 0x9d, + 0xe0, 0x42, 0x69, 0x01, 0x00, 0x00, 0xc5, 0xc6, + 0x24, 0x02, 0x00, 0x9d, 0xe4, 0xc7, 0xe2, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xaa, 0x06, 0x00, 0x01, + 0x00, 0x05, 0x03, 0x00, 0x30, 0x00, 0x00, 0x40, + 0x01, 0x00, 0x1d, 0x01, 0x00, 0x1c, 0x01, 0xdd, + 0xde, 0xef, 0xc9, 0xdf, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xb5, 0xde, 0x24, 0x02, 0x00, 0xdf, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xde, 0xc5, 0x24, 0x02, + 0x00, 0x42, 0x96, 0x01, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x9d, 0xdf, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xc5, 0x24, 0x01, 0x00, 0x9d, 0xe3, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xae, 0x06, 0x00, 0x01, 0x00, + 0x05, 0x03, 0x00, 0x30, 0x00, 0x00, 0x40, 0x01, + 0x00, 0x1d, 0x01, 0x00, 0x1c, 0x01, 0xdd, 0xde, + 0xef, 0xc9, 0xdf, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb5, 0xde, 0x24, 0x02, 0x00, 0xdf, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xde, 0xc5, 0x24, 0x02, 0x00, + 0x42, 0x98, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x9d, 0xdf, 0x42, 0x69, 0x01, 0x00, 0x00, 0xc5, + 0x24, 0x01, 0x00, 0x9d, 0xe3, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xb2, 0x06, 0x03, 0x01, 0x03, 0x04, + 0x06, 0x00, 0x5e, 0x00, 0x00, 0x1c, 0x01, 0x00, + 0x22, 0x01, 0x00, 0x53, 0x01, 0x00, 0x0d, 0x01, + 0x00, 0x1d, 0x01, 0x00, 0x21, 0x01, 0xdd, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xd1, 0xd2, 0x24, 0x02, + 0x00, 0xc9, 0xde, 0xdf, 0xac, 0xea, 0x05, 0xc5, + 0xe4, 0xec, 0x10, 0xd3, 0xb5, 0xa3, 0xea, 0x07, + 0xc5, 0xe0, 0x9d, 0xe4, 0xec, 0x05, 0xe0, 0xc5, + 0x9d, 0xe4, 0xdd, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb5, 0xd1, 0x24, 0x02, 0x00, 0xdd, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xd2, 0x24, 0x01, 0x00, 0x9d, + 0xe1, 0x5e, 0x04, 0x00, 0xd2, 0xa5, 0xea, 0x0d, + 0x5e, 0x04, 0x00, 0xd2, 0xd1, 0x9e, 0x9e, 0x5f, + 0x04, 0x00, 0xec, 0x0c, 0x5e, 0x04, 0x00, 0xd1, + 0xa5, 0xea, 0x05, 0xd1, 0x5f, 0x04, 0x00, 0xdf, + 0x5f, 0x05, 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xb4, 0x06, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, + 0x07, 0x00, 0xb2, 0x06, 0x53, 0x01, 0xf4, 0x05, + 0x1d, 0x01, 0xf2, 0x05, 0x1c, 0x01, 0xdd, 0xde, + 0xdf, 0xe9, 0xb6, 0xf1, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xb6, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, + 0x00, 0x06, 0x00, 0xb2, 0x06, 0x53, 0x01, 0xf4, + 0x05, 0x1d, 0x01, 0xdd, 0xb5, 0xde, 0xb4, 0xf1, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xb8, 0x06, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x08, 0x00, 0xb2, + 0x06, 0x53, 0x01, 0xf4, 0x05, 0x1d, 0x01, 0x82, + 0x06, 0x40, 0x01, 0xdd, 0xde, 0xdf, 0xde, 0xef, + 0xb6, 0xf1, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xba, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x08, + 0x00, 0xb2, 0x06, 0x53, 0x01, 0x84, 0x06, 0x41, + 0x01, 0xf4, 0x05, 0x1d, 0x01, 0xdd, 0xde, 0xdf, + 0xef, 0xdf, 0xb4, 0xf1, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xbc, 0x06, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x00, 0x04, 0x00, 0xea, 0x05, 0x38, 0x01, 0xbe, + 0x06, 0x0d, 0x01, 0xdd, 0xde, 0xef, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xc0, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x04, 0x00, 0x39, 0x00, 0xc2, 0x06, 0x22, + 0x01, 0xc0, 0x06, 0x59, 0x01, 0xc8, 0x03, 0x00, + 0x0c, 0xc4, 0x06, 0x64, 0x01, 0xdd, 0xde, 0xab, + 0xea, 0x20, 0x65, 0x02, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0x65, 0x02, 0x00, 0x42, 0xa3, + 0x01, 0x00, 0x00, 0xb5, 0x24, 0x01, 0x00, 0x0e, + 0x29, 0x65, 0x02, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0xa4, 0x01, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xe0, 0xee, 0x0e, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xca, 0x06, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x05, 0x00, 0xf2, 0x05, 0x1c, 0x01, + 0xf4, 0x05, 0x1d, 0x01, 0xc1, 0xe1, 0xb5, 0xe2, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xcc, 0x06, 0x02, + 0x01, 0x02, 0x04, 0x01, 0x00, 0x1d, 0x00, 0x00, + 0x30, 0x01, 0xc1, 0xc9, 0xd2, 0xb5, 0xa5, 0xea, + 0x15, 0xdd, 0xd1, 0xd2, 0xb6, 0x9e, 0x47, 0xef, + 0xea, 0x0c, 0xd2, 0x8e, 0xd6, 0xd1, 0xd2, 0x47, + 0xc5, 0x9d, 0xc9, 0xec, 0xe8, 0xc5, 0x28, 0x0e, + 0x43, 0x02, 0x03, 0xce, 0x06, 0x02, 0x06, 0x02, + 0x05, 0x7a, 0x02, 0x87, 0x02, 0x08, 0xd0, 0x06, + 0x00, 0x01, 0x00, 0xd2, 0x06, 0x00, 0x01, 0x00, + 0xd4, 0x06, 0x00, 0x00, 0x00, 0xd6, 0x06, 0x00, + 0x01, 0x00, 0xd8, 0x06, 0x00, 0x02, 0x00, 0x10, + 0x00, 0x01, 0x00, 0xe8, 0x01, 0x00, 0x01, 0x00, + 0xa0, 0x01, 0x00, 0x01, 0x00, 0xda, 0x06, 0x00, + 0x03, 0xaa, 0x02, 0x00, 0x01, 0xb2, 0x02, 0x01, + 0x01, 0xac, 0x02, 0x02, 0x01, 0xbe, 0x02, 0x03, + 0x01, 0xba, 0x02, 0x04, 0x01, 0xcc, 0x03, 0x05, + 0x01, 0xce, 0x03, 0x06, 0x01, 0xdc, 0x06, 0x07, + 0x01, 0xde, 0x06, 0x08, 0x01, 0xe0, 0x06, 0x09, + 0x01, 0xe2, 0x06, 0x0a, 0x01, 0xe4, 0x06, 0x0b, + 0x01, 0x94, 0x06, 0x0c, 0x01, 0xbe, 0x06, 0x0d, + 0x01, 0xe6, 0x06, 0x0e, 0x01, 0xe8, 0x06, 0x0f, + 0x01, 0xea, 0x06, 0x10, 0x01, 0xec, 0x06, 0x11, + 0x01, 0xee, 0x06, 0x12, 0x01, 0xf0, 0x06, 0x13, + 0x01, 0xf2, 0x06, 0x14, 0x01, 0xf4, 0x06, 0x15, + 0x01, 0xf6, 0x06, 0x16, 0x01, 0xf8, 0x06, 0x17, + 0x01, 0xfa, 0x06, 0x18, 0x01, 0xfc, 0x06, 0x19, + 0x01, 0xfe, 0x06, 0x1a, 0x01, 0x80, 0x07, 0x1b, + 0x01, 0xf2, 0x05, 0x1c, 0x01, 0xf4, 0x05, 0x1d, + 0x01, 0x82, 0x07, 0x1e, 0x01, 0x84, 0x07, 0x1f, + 0x01, 0x92, 0x06, 0x20, 0x01, 0x86, 0x07, 0x21, + 0x01, 0xc2, 0x06, 0x22, 0x01, 0xee, 0x05, 0x23, + 0x01, 0x88, 0x07, 0x24, 0x01, 0x8a, 0x07, 0x25, + 0x01, 0x8c, 0x07, 0x26, 0x01, 0x8e, 0x07, 0x27, + 0x01, 0x90, 0x07, 0x28, 0x01, 0x92, 0x07, 0x29, + 0x01, 0x92, 0x05, 0x2a, 0x01, 0xa2, 0x05, 0x2b, + 0x01, 0xa6, 0x05, 0x2c, 0x01, 0xa4, 0x05, 0x2d, + 0x01, 0xac, 0x05, 0x2e, 0x01, 0xb6, 0x05, 0x2f, + 0x01, 0xb8, 0x05, 0x30, 0x01, 0xbe, 0x05, 0x31, + 0x01, 0xc2, 0x05, 0x32, 0x01, 0xc6, 0x05, 0x33, + 0x01, 0xce, 0x05, 0x34, 0x01, 0xd4, 0x05, 0x35, + 0x01, 0xd8, 0x05, 0x36, 0x01, 0xe0, 0x05, 0x37, + 0x01, 0xea, 0x05, 0x38, 0x01, 0xec, 0x05, 0x39, + 0x01, 0xf0, 0x05, 0x3a, 0x01, 0xf6, 0x05, 0x3b, + 0x01, 0xf8, 0x05, 0x3c, 0x01, 0xfa, 0x05, 0x3d, + 0x01, 0xfc, 0x05, 0x3e, 0x01, 0x80, 0x06, 0x3f, + 0x01, 0x82, 0x06, 0x40, 0x01, 0x84, 0x06, 0x41, + 0x01, 0x86, 0x06, 0x42, 0x01, 0x88, 0x06, 0x43, + 0x01, 0x8a, 0x06, 0x44, 0x01, 0x8c, 0x06, 0x45, + 0x01, 0x90, 0x06, 0x46, 0x01, 0x96, 0x06, 0x47, + 0x01, 0x98, 0x06, 0x48, 0x01, 0x9a, 0x06, 0x49, + 0x01, 0x9c, 0x06, 0x4a, 0x01, 0x9e, 0x06, 0x4b, + 0x01, 0xa0, 0x06, 0x4c, 0x01, 0xa2, 0x06, 0x4d, + 0x01, 0xa4, 0x06, 0x4e, 0x01, 0xa6, 0x06, 0x4f, + 0x01, 0xa8, 0x06, 0x50, 0x01, 0xaa, 0x06, 0x51, + 0x01, 0xae, 0x06, 0x52, 0x01, 0xb2, 0x06, 0x53, + 0x01, 0xb4, 0x06, 0x54, 0x01, 0xb6, 0x06, 0x55, + 0x01, 0xb8, 0x06, 0x56, 0x01, 0xba, 0x06, 0x57, + 0x01, 0xbc, 0x06, 0x58, 0x01, 0xc0, 0x06, 0x59, + 0x01, 0xca, 0x06, 0x5a, 0x01, 0xcc, 0x06, 0x5b, + 0x01, 0xce, 0x06, 0x5c, 0x01, 0x94, 0x07, 0x5d, + 0x01, 0x96, 0x07, 0x5e, 0x01, 0x98, 0x07, 0x5f, + 0x01, 0x9a, 0x07, 0x60, 0x01, 0x9c, 0x07, 0x61, + 0x01, 0x9e, 0x07, 0x62, 0x01, 0xa0, 0x07, 0x63, + 0x01, 0xc4, 0x06, 0x64, 0x01, 0xa2, 0x07, 0x65, + 0x01, 0xa4, 0x07, 0x66, 0x01, 0xa6, 0x07, 0x67, + 0x01, 0xa8, 0x07, 0x68, 0x01, 0xaa, 0x07, 0x69, + 0x01, 0xac, 0x07, 0x6a, 0x01, 0xae, 0x07, 0x6b, + 0x01, 0xb0, 0x07, 0x6c, 0x01, 0xb2, 0x07, 0x6d, + 0x01, 0xb4, 0x07, 0x6e, 0x01, 0xb6, 0x07, 0x6f, + 0x01, 0xb8, 0x07, 0x70, 0x01, 0xba, 0x07, 0x71, + 0x01, 0xbc, 0x07, 0x72, 0x01, 0xbe, 0x07, 0x73, + 0x01, 0xc0, 0x07, 0x74, 0x01, 0xc2, 0x07, 0x75, + 0x01, 0xc4, 0x07, 0x76, 0x01, 0xc8, 0x03, 0x00, + 0x0c, 0xca, 0x03, 0x01, 0x0c, 0x0c, 0x03, 0xc3, + 0x04, 0x08, 0xcc, 0x0c, 0x00, 0xc3, 0x05, 0xd2, + 0xb5, 0xa4, 0x11, 0xeb, 0x16, 0x0e, 0x04, 0xe3, + 0x01, 0x00, 0x00, 0x42, 0xe4, 0x01, 0x00, 0x00, + 0xd1, 0xd2, 0xb6, 0x9e, 0x47, 0x24, 0x01, 0x00, + 0xb5, 0xa6, 0xea, 0x03, 0xdd, 0x28, 0xd2, 0xb7, + 0xa6, 0x69, 0xd9, 0x00, 0x00, 0x00, 0xd1, 0xd2, + 0xb6, 0x9e, 0x47, 0x04, 0xe5, 0x01, 0x00, 0x00, + 0xab, 0x69, 0xc9, 0x00, 0x00, 0x00, 0xd2, 0x8e, + 0xd6, 0x0b, 0xc9, 0xd1, 0xd2, 0xb6, 0x9e, 0x47, + 0xcf, 0x11, 0x04, 0xe6, 0x01, 0x00, 0x00, 0xab, + 0xeb, 0x0a, 0x11, 0x04, 0xe7, 0x01, 0x00, 0x00, + 0xab, 0xea, 0x07, 0x04, 0x59, 0x01, 0x00, 0x00, + 0x28, 0x11, 0x04, 0xe8, 0x01, 0x00, 0x00, 0xab, + 0xea, 0x05, 0x26, 0x00, 0x00, 0x28, 0x11, 0x04, + 0xe9, 0x01, 0x00, 0x00, 0xab, 0xea, 0x03, 0x0b, + 0x28, 0x11, 0x04, 0xea, 0x01, 0x00, 0x00, 0xab, + 0xea, 0x07, 0xbf, 0x00, 0xbf, 0x01, 0x33, 0x28, + 0x5e, 0x31, 0x00, 0xc7, 0xef, 0xea, 0x73, 0x5e, + 0x5c, 0x00, 0xd1, 0xd2, 0xf0, 0xca, 0x04, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, + 0x04, 0x01, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, + 0x00, 0x00, 0x26, 0x04, 0x00, 0x42, 0xeb, 0x01, + 0x00, 0x00, 0xc6, 0x24, 0x01, 0x00, 0x11, 0xeb, + 0x0b, 0x0e, 0x38, 0xec, 0x01, 0x00, 0x00, 0xc6, + 0x8d, 0xef, 0x96, 0xea, 0x0d, 0x38, 0x3d, 0x00, + 0x00, 0x00, 0xc6, 0x31, 0x01, 0x00, 0x00, 0x00, + 0x28, 0x5e, 0x5d, 0x00, 0xd1, 0xd2, 0xc6, 0xe9, + 0x9e, 0xf0, 0xcd, 0xf3, 0x11, 0xeb, 0x04, 0x0e, + 0xc5, 0xf2, 0xea, 0x03, 0xc5, 0x28, 0xc5, 0xdd, + 0xab, 0xea, 0x13, 0xc5, 0xc6, 0x47, 0xf2, 0xea, + 0x0d, 0x38, 0x3d, 0x00, 0x00, 0x00, 0xc6, 0x31, + 0x01, 0x00, 0x00, 0x00, 0x28, 0xc5, 0xc6, 0x47, + 0x28, 0x0b, 0x28, 0x29, 0x07, 0x02, 0x20, 0x07, + 0x34, 0x00, 0x01, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x04, 0x07, 0xf5, + 0xff, 0xff, 0xff, 0x0b, 0x00, 0x01, 0x20, 0x00, + 0x0c, 0x00, 0x0a, 0x0e, 0x43, 0x02, 0x03, 0x94, + 0x07, 0x02, 0x0a, 0x02, 0x04, 0x03, 0x01, 0xe3, + 0x01, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x5c, 0x01, + 0x00, 0x00, 0x01, 0xdd, 0xd1, 0xd2, 0xf0, 0xc9, + 0xde, 0xd1, 0xd2, 0xc5, 0xe9, 0x9e, 0xf0, 0xcb, + 0x26, 0x00, 0x00, 0xcc, 0xb5, 0xc3, 0x04, 0xc7, + 0xca, 0xc2, 0x04, 0xbd, 0x0a, 0xa3, 0xea, 0x67, + 0xc6, 0xf3, 0xeb, 0x63, 0xc6, 0x06, 0xac, 0xea, + 0x5e, 0xdf, 0x42, 0xed, 0x01, 0x00, 0x00, 0xc6, + 0x24, 0x01, 0x00, 0xc3, 0x07, 0xb5, 0xc3, 0x05, + 0xc2, 0x05, 0xc2, 0x07, 0xe9, 0xa3, 0xea, 0x38, + 0xc2, 0x07, 0xc2, 0x05, 0x47, 0xc4, 0x08, 0x97, + 0x04, 0x4b, 0x00, 0x00, 0x00, 0xa9, 0xea, 0x24, + 0xc1, 0xc2, 0x08, 0x8d, 0x9d, 0xc2, 0x08, 0xaa, + 0xea, 0x1a, 0xc2, 0x08, 0x42, 0xee, 0x01, 0x00, + 0x00, 0xc5, 0x24, 0x01, 0x00, 0xea, 0x0d, 0xc8, + 0x42, 0x87, 0x01, 0x00, 0x00, 0xc2, 0x08, 0x24, + 0x01, 0x00, 0x0e, 0x93, 0x05, 0xec, 0xc2, 0xdf, + 0x42, 0x62, 0x00, 0x00, 0x00, 0xc6, 0x24, 0x01, + 0x00, 0xca, 0x93, 0x04, 0xec, 0x94, 0xc8, 0xe9, + 0xb6, 0xa5, 0xea, 0x46, 0xc0, 0x00, 0xc3, 0x09, + 0xc0, 0x00, 0x0e, 0xc8, 0x42, 0xef, 0x01, 0x00, + 0x00, 0x62, 0x09, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0xb6, 0xc4, 0x05, 0xc3, 0x04, 0xc2, 0x04, 0xc8, + 0xe9, 0xa3, 0xea, 0x1e, 0xc8, 0xc2, 0x04, 0x47, + 0xc8, 0xc2, 0x04, 0xb6, 0x9e, 0x47, 0xaa, 0xea, + 0x0d, 0xc8, 0xc2, 0x05, 0x91, 0xc3, 0x05, 0x71, + 0xc8, 0xc2, 0x04, 0x47, 0x49, 0x93, 0x04, 0xec, + 0xdd, 0xc8, 0xc2, 0x05, 0x43, 0x32, 0x00, 0x00, + 0x00, 0x0b, 0xc8, 0x4c, 0xf0, 0x01, 0x00, 0x00, + 0xc5, 0xe9, 0x4c, 0xa9, 0x01, 0x00, 0x00, 0xc7, + 0x4c, 0xf1, 0x01, 0x00, 0x00, 0x28, 0x0e, 0x43, + 0x02, 0x03, 0xe4, 0x07, 0x02, 0x00, 0x02, 0x03, + 0x00, 0x00, 0x34, 0x00, 0xd1, 0xb5, 0x47, 0xd2, + 0xb5, 0x47, 0xaa, 0xea, 0x1b, 0xd1, 0xb5, 0x47, + 0x04, 0x5d, 0x01, 0x00, 0x00, 0xa9, 0xea, 0x03, + 0xb6, 0x28, 0xd2, 0xb5, 0x47, 0x04, 0x5d, 0x01, + 0x00, 0x00, 0xa9, 0xea, 0x03, 0xb4, 0x28, 0xd1, + 0xd2, 0xa3, 0xea, 0x03, 0xb4, 0x28, 0xd1, 0xd2, + 0xa5, 0xea, 0x04, 0xb6, 0x8d, 0x28, 0xb5, 0x28, + 0x0e, 0x43, 0x02, 0x03, 0x96, 0x07, 0x00, 0x0d, + 0x00, 0x07, 0x0a, 0x00, 0x8f, 0x03, 0x00, 0x00, + 0x5d, 0x01, 0x00, 0x1c, 0x01, 0x00, 0x1d, 0x01, + 0x00, 0x38, 0x01, 0x00, 0x22, 0x01, 0x00, 0x5e, + 0x01, 0x00, 0x04, 0x01, 0x00, 0x28, 0x01, 0x00, + 0x00, 0x0c, 0x00, 0x64, 0x01, 0xdd, 0xde, 0xdf, + 0xf0, 0xce, 0x41, 0xf0, 0x01, 0x00, 0x00, 0xcd, + 0xe9, 0xb5, 0xab, 0xea, 0x02, 0x29, 0xc5, 0xb5, + 0x47, 0xcf, 0xe9, 0xc3, 0x05, 0xb6, 0xcc, 0xc8, + 0xc5, 0xe9, 0xa3, 0xea, 0x2a, 0xc5, 0xc8, 0x47, + 0xc3, 0x06, 0xb5, 0xc3, 0x04, 0xc2, 0x04, 0xc2, + 0x05, 0xa3, 0xea, 0x17, 0xc2, 0x06, 0xc2, 0x04, + 0x47, 0xc7, 0xc2, 0x04, 0x47, 0xac, 0xea, 0x07, + 0xc2, 0x04, 0xc3, 0x05, 0xec, 0x05, 0x93, 0x04, + 0xec, 0xe4, 0x93, 0x03, 0xec, 0xd2, 0xc6, 0x41, + 0xa9, 0x01, 0x00, 0x00, 0xcc, 0xc8, 0xc2, 0x05, + 0xa3, 0xea, 0x0b, 0xe0, 0xc7, 0xc8, 0x47, 0xef, + 0x0e, 0x93, 0x03, 0xec, 0xf1, 0x5e, 0x04, 0x00, + 0x5e, 0x05, 0x00, 0xab, 0xea, 0x42, 0xc5, 0xe9, + 0xb6, 0xa9, 0xea, 0x3c, 0xc6, 0x41, 0xf1, 0x01, + 0x00, 0x00, 0xc5, 0xb5, 0x47, 0x47, 0xc4, 0x0c, + 0xf5, 0xea, 0x1a, 0xe0, 0x04, 0xf3, 0x01, 0x00, + 0x00, 0xef, 0x0e, 0xc2, 0x0c, 0xe9, 0xb5, 0xa9, + 0xea, 0x1e, 0xe0, 0x04, 0xf4, 0x01, 0x00, 0x00, + 0xef, 0x0e, 0xec, 0x14, 0xc2, 0x0c, 0x97, 0x04, + 0x4c, 0x00, 0x00, 0x00, 0xa9, 0xea, 0x09, 0xe0, + 0x04, 0xe5, 0x01, 0x00, 0x00, 0xef, 0x0e, 0x5e, + 0x04, 0x00, 0x5e, 0x05, 0x00, 0xab, 0x69, 0xdc, + 0x00, 0x00, 0x00, 0xc5, 0xe9, 0xb7, 0xa6, 0x69, + 0xd3, 0x00, 0x00, 0x00, 0xb5, 0xc3, 0x07, 0xb5, + 0xcc, 0xc8, 0xc5, 0xe9, 0xa3, 0xea, 0x18, 0x5e, + 0x06, 0x00, 0x42, 0xf5, 0x01, 0x00, 0x00, 0xc2, + 0x07, 0xc5, 0xc8, 0x47, 0xe9, 0x24, 0x02, 0x00, + 0xc3, 0x07, 0x93, 0x03, 0xec, 0xe4, 0xb7, 0x94, + 0x07, 0x5e, 0x06, 0x00, 0x42, 0xf5, 0x01, 0x00, + 0x00, 0xb6, 0x5e, 0x06, 0x00, 0x42, 0xf6, 0x01, + 0x00, 0x00, 0x5e, 0x07, 0x00, 0xb6, 0x9d, 0xc2, + 0x07, 0x9b, 0x24, 0x01, 0x00, 0x24, 0x02, 0x00, + 0xc3, 0x09, 0x5e, 0x06, 0x00, 0x42, 0xf7, 0x01, + 0x00, 0x00, 0xc5, 0xe9, 0xc2, 0x09, 0x9b, 0x24, + 0x01, 0x00, 0xc3, 0x0b, 0x65, 0x08, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x21, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xb5, 0xc3, 0x0a, + 0xc2, 0x0a, 0xc2, 0x0b, 0xa3, 0xea, 0x58, 0xb5, + 0xc3, 0x08, 0xc2, 0x08, 0xc2, 0x09, 0xa3, 0xea, + 0x39, 0xc2, 0x08, 0xc2, 0x0b, 0x9a, 0xc2, 0x0a, + 0x9d, 0xd0, 0xc5, 0xe9, 0xa6, 0xeb, 0x2b, 0xc5, + 0xc8, 0x47, 0xcb, 0xc2, 0x08, 0xc2, 0x09, 0xb6, + 0x9e, 0xaa, 0xea, 0x0d, 0xc7, 0x42, 0xf8, 0x01, + 0x00, 0x00, 0xc2, 0x07, 0x24, 0x01, 0x00, 0xcb, + 0x65, 0x08, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0xc7, 0x24, 0x01, 0x00, 0x0e, 0x93, 0x08, 0xec, + 0xc2, 0x65, 0x08, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0x93, 0x0a, 0xec, 0xa3, 0x5e, 0x09, + 0x00, 0xee, 0x0e, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0x9a, 0x07, 0x02, 0x01, 0x02, 0x02, 0x00, 0x00, + 0x10, 0x00, 0xc1, 0xc9, 0xd2, 0x90, 0xd6, 0xb5, + 0xa5, 0xea, 0x06, 0xd1, 0x94, 0x00, 0xec, 0xf5, + 0xc5, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xc4, 0x06, + 0x00, 0x00, 0x00, 0x03, 0x07, 0x00, 0x1e, 0x00, + 0xc8, 0x03, 0x00, 0x0c, 0xee, 0x06, 0x12, 0x01, + 0x92, 0x07, 0x29, 0x01, 0xbe, 0x05, 0x31, 0x01, + 0x90, 0x07, 0x28, 0x01, 0x82, 0x07, 0x1e, 0x01, + 0x84, 0x07, 0x1f, 0x01, 0x65, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xde, 0x24, 0x01, 0x00, + 0x0e, 0xe0, 0xde, 0xef, 0x5e, 0x04, 0x00, 0x9c, + 0xe3, 0xc1, 0x5f, 0x05, 0x00, 0xb5, 0x5f, 0x06, + 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xa2, 0x07, + 0x02, 0x01, 0x02, 0x06, 0x12, 0x01, 0xb0, 0x01, + 0x00, 0x00, 0x1c, 0x01, 0x00, 0x1d, 0x01, 0x00, + 0x20, 0x01, 0x00, 0x0c, 0x01, 0x00, 0x63, 0x01, + 0x00, 0x12, 0x01, 0x00, 0x11, 0x01, 0x00, 0x1a, + 0x01, 0x00, 0x60, 0x01, 0x00, 0x13, 0x01, 0x00, + 0x15, 0x01, 0x00, 0x17, 0x01, 0x00, 0x04, 0x01, + 0x00, 0x19, 0x01, 0x00, 0x14, 0x01, 0x00, 0x64, + 0x01, 0x00, 0x37, 0x01, 0x00, 0x62, 0x01, 0xd1, + 0x11, 0xeb, 0x03, 0x0e, 0xc1, 0xe5, 0xe9, 0xe2, + 0xe0, 0xe9, 0xe3, 0xd2, 0x5f, 0x04, 0x00, 0x5e, + 0x06, 0x00, 0x5f, 0x05, 0x00, 0x5e, 0x07, 0x00, + 0xea, 0x22, 0x5e, 0x05, 0x00, 0x5e, 0x08, 0x00, + 0x04, 0xf9, 0x01, 0x00, 0x00, 0x5e, 0x09, 0x00, + 0x5e, 0x05, 0x00, 0xe9, 0x9e, 0xf0, 0x9d, 0x60, + 0x05, 0x00, 0x5e, 0x0a, 0x00, 0x9d, 0x5f, 0x05, + 0x00, 0xec, 0x66, 0x5e, 0x0b, 0x00, 0xea, 0x50, + 0x5e, 0x0c, 0x00, 0x42, 0xfa, 0x01, 0x00, 0x00, + 0x5e, 0x0d, 0x00, 0x24, 0x01, 0x00, 0x04, 0xf9, + 0x01, 0x00, 0x00, 0x9d, 0xc9, 0xb5, 0x5f, 0x0d, + 0x00, 0x5e, 0x08, 0x00, 0xbf, 0x00, 0xba, 0xc5, + 0xe9, 0x9e, 0xf0, 0xc5, 0x9d, 0xc9, 0x5e, 0x05, + 0x00, 0xc5, 0x42, 0x69, 0x01, 0x00, 0x00, 0xb5, + 0xc5, 0xe9, 0xb9, 0x9e, 0x24, 0x02, 0x00, 0x04, + 0xe5, 0x01, 0x00, 0x00, 0x9d, 0xc5, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xc5, 0xe9, 0xb9, 0x9e, 0x24, + 0x01, 0x00, 0x9d, 0x9d, 0x5f, 0x05, 0x00, 0x5e, + 0x05, 0x00, 0xe9, 0x5f, 0x09, 0x00, 0x5e, 0x05, + 0x00, 0x5e, 0x0e, 0x00, 0x9d, 0x5f, 0x05, 0x00, + 0x5e, 0x0f, 0x00, 0xee, 0x0e, 0x5e, 0x10, 0x00, + 0xee, 0x0e, 0xb5, 0x5f, 0x11, 0x00, 0x29, 0x07, + 0x02, 0x30, 0x0e, 0x43, 0x02, 0x03, 0xa4, 0x07, + 0x01, 0x01, 0x01, 0x03, 0x04, 0x02, 0x8c, 0x01, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x62, 0x01, 0x00, + 0x61, 0x01, 0x00, 0x67, 0x01, 0xdd, 0x42, 0xfb, + 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xc9, + 0xde, 0x11, 0xb5, 0xab, 0xea, 0x16, 0xc5, 0x04, + 0xfc, 0x01, 0x00, 0x00, 0xa9, 0xea, 0x07, 0xc5, + 0xe3, 0xb6, 0xe2, 0xec, 0x6c, 0xe0, 0xc5, 0xef, + 0x0e, 0xec, 0x66, 0x11, 0xb6, 0xab, 0xea, 0x27, + 0xdf, 0xc5, 0x9d, 0xe3, 0xc5, 0x04, 0xfd, 0x01, + 0x00, 0x00, 0xa9, 0xea, 0x05, 0xb7, 0xe2, 0xec, + 0x50, 0xc5, 0x04, 0xfe, 0x01, 0x00, 0x00, 0xa9, + 0xea, 0x05, 0xb8, 0xe2, 0xec, 0x43, 0xe0, 0xdf, + 0xef, 0x0e, 0xb5, 0xe2, 0xec, 0x3b, 0x11, 0xb7, + 0xab, 0xea, 0x27, 0xdf, 0xc5, 0x9d, 0xe3, 0xc5, + 0x04, 0xff, 0x01, 0x00, 0x00, 0xa9, 0x11, 0xeb, + 0x0e, 0x0e, 0xc5, 0xbf, 0x00, 0xa6, 0x11, 0xea, + 0x06, 0x0e, 0xc5, 0xbf, 0x01, 0xa4, 0x96, 0xea, + 0x18, 0xe0, 0xdf, 0xef, 0x0e, 0xb5, 0xe2, 0xec, + 0x10, 0x11, 0xb8, 0xab, 0xea, 0x0b, 0xdf, 0xc5, + 0x9d, 0xe3, 0xe0, 0xdf, 0xef, 0x0e, 0xb5, 0xe2, + 0x29, 0x07, 0x02, 0x30, 0x07, 0x02, 0x39, 0x0e, + 0x43, 0x02, 0x03, 0xa6, 0x07, 0x01, 0x01, 0x01, + 0x05, 0x0d, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x23, + 0x01, 0x00, 0x31, 0x01, 0x00, 0x38, 0x01, 0x00, + 0x5f, 0x01, 0x00, 0x21, 0x01, 0x00, 0x63, 0x01, + 0x00, 0x1c, 0x01, 0x00, 0x01, 0x0c, 0x00, 0x26, + 0x01, 0x00, 0x22, 0x01, 0x00, 0x3b, 0x01, 0x00, + 0x1d, 0x01, 0x00, 0x37, 0x01, 0xdd, 0xea, 0x10, + 0xde, 0xd1, 0xef, 0xb6, 0xab, 0xea, 0x05, 0xdf, + 0xd1, 0xef, 0x0e, 0x09, 0xe1, 0xec, 0x7a, 0xe0, + 0xd1, 0x47, 0xcd, 0xea, 0x55, 0xc5, 0x5f, 0x04, + 0x00, 0xc5, 0xd1, 0xef, 0x11, 0xb4, 0xab, 0xea, + 0x09, 0x5e, 0x05, 0x00, 0x5e, 0x06, 0x00, 0xef, + 0x29, 0x11, 0xbd, 0xfe, 0xab, 0xea, 0x07, 0x5e, + 0x05, 0x00, 0x07, 0xef, 0x29, 0x11, 0xbd, 0xfd, + 0xab, 0xea, 0x26, 0x65, 0x07, 0x00, 0x42, 0x4e, + 0x01, 0x00, 0x00, 0x65, 0x07, 0x00, 0x41, 0x4f, + 0x01, 0x00, 0x00, 0x07, 0x24, 0x02, 0x00, 0x0e, + 0x65, 0x07, 0x00, 0x42, 0x50, 0x01, 0x00, 0x00, + 0x5e, 0x08, 0x00, 0x07, 0x24, 0x02, 0x00, 0x29, + 0x0e, 0x5e, 0x04, 0x00, 0x5f, 0x09, 0x00, 0xec, + 0x20, 0xde, 0xd1, 0xef, 0xb6, 0xab, 0xea, 0x14, + 0xd1, 0x04, 0xf9, 0x01, 0x00, 0x00, 0xa6, 0xea, + 0x0b, 0xdf, 0xd1, 0xef, 0x0e, 0xdf, 0x5f, 0x09, + 0x00, 0xec, 0x06, 0x5e, 0x0a, 0x00, 0xee, 0x0e, + 0x5e, 0x0b, 0x00, 0xb5, 0xa3, 0xea, 0x04, 0xb5, + 0xec, 0x14, 0x5e, 0x0b, 0x00, 0x5e, 0x06, 0x00, + 0xe9, 0xa5, 0xea, 0x07, 0x5e, 0x06, 0x00, 0xe9, + 0xec, 0x04, 0x5e, 0x0b, 0x00, 0x5f, 0x0b, 0x00, + 0x5e, 0x0c, 0x00, 0xee, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xac, 0x07, 0x02, 0x01, 0x02, 0x05, 0x02, + 0x01, 0x70, 0x00, 0x00, 0x05, 0x01, 0x00, 0x04, + 0x01, 0xdd, 0xd1, 0xef, 0x96, 0xea, 0x0a, 0xd1, + 0x42, 0x3a, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, + 0xd1, 0xb5, 0xa9, 0xea, 0x15, 0xb6, 0xd1, 0x9b, + 0xb5, 0xa3, 0xea, 0x09, 0x04, 0x00, 0x02, 0x00, + 0x00, 0xc9, 0xec, 0x4c, 0xbf, 0x00, 0xc9, 0xec, + 0x47, 0xd2, 0xbd, 0x10, 0xa9, 0xea, 0x37, 0xd1, + 0xde, 0x42, 0xf6, 0x01, 0x00, 0x00, 0xd1, 0x24, + 0x01, 0x00, 0xab, 0xea, 0x29, 0xd1, 0xb5, 0xa3, + 0xea, 0x0c, 0xd1, 0x8c, 0xd5, 0x04, 0x01, 0x02, + 0x00, 0x00, 0xc9, 0xec, 0x03, 0xc1, 0xc9, 0xc5, + 0x04, 0x02, 0x02, 0x00, 0x00, 0xd1, 0x42, 0x3a, + 0x00, 0x00, 0x00, 0xbd, 0x10, 0x24, 0x01, 0x00, + 0x9d, 0x9d, 0xc9, 0xec, 0x0b, 0xd1, 0x42, 0x3a, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xc9, 0xc5, + 0x28, 0x07, 0x02, 0x30, 0x0e, 0x43, 0x02, 0x03, + 0xae, 0x07, 0x02, 0x01, 0x02, 0x05, 0x01, 0x01, + 0xfe, 0x01, 0x00, 0x00, 0x69, 0x01, 0x38, 0xb3, + 0x00, 0x00, 0x00, 0x42, 0xe6, 0x00, 0x00, 0x00, + 0xd1, 0x24, 0x01, 0x00, 0x96, 0xea, 0x29, 0xdd, + 0x04, 0x03, 0x02, 0x00, 0x00, 0xac, 0xea, 0x17, + 0x04, 0x04, 0x02, 0x00, 0x00, 0xd1, 0x42, 0x3a, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9d, 0x04, + 0xf4, 0x01, 0x00, 0x00, 0x9d, 0x28, 0xd1, 0x42, + 0x3a, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0xd1, + 0xb5, 0xa9, 0xea, 0x15, 0xb6, 0xd1, 0x9b, 0xb5, + 0xa3, 0xea, 0x09, 0x04, 0x00, 0x02, 0x00, 0x00, + 0xc9, 0xec, 0x3e, 0xbf, 0x00, 0xc9, 0xec, 0x39, + 0xd2, 0xbd, 0x10, 0xa9, 0xea, 0x29, 0xd1, 0xb5, + 0xa3, 0xea, 0x0c, 0xd1, 0x8c, 0xd5, 0x04, 0x01, + 0x02, 0x00, 0x00, 0xc9, 0xec, 0x03, 0xc1, 0xc9, + 0xc5, 0x04, 0x02, 0x02, 0x00, 0x00, 0xd1, 0x42, + 0x3a, 0x00, 0x00, 0x00, 0xbd, 0x10, 0x24, 0x01, + 0x00, 0x9d, 0x9d, 0xc9, 0xec, 0x0b, 0xd1, 0x42, + 0x3a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xc9, + 0xd1, 0x97, 0x04, 0x8f, 0x00, 0x00, 0x00, 0xab, + 0xea, 0x13, 0xdd, 0x04, 0x03, 0x02, 0x00, 0x00, + 0xac, 0xea, 0x0a, 0x04, 0x05, 0x02, 0x00, 0x00, + 0x94, 0x00, 0xec, 0x57, 0xdd, 0x04, 0xe4, 0x00, + 0x00, 0x00, 0xac, 0xea, 0x4e, 0xc5, 0x42, 0xe4, + 0x01, 0x00, 0x00, 0x04, 0xe5, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0xb5, 0xa3, 0xea, 0x3c, 0xd2, + 0xbd, 0x10, 0xa9, 0x11, 0xea, 0x12, 0x0e, 0xc5, + 0x42, 0xe4, 0x01, 0x00, 0x00, 0x04, 0x06, 0x02, + 0x00, 0x00, 0x24, 0x01, 0x00, 0xb5, 0xa3, 0x11, + 0xeb, 0x18, 0x0e, 0xd2, 0xbd, 0x0a, 0xa9, 0xea, + 0x1a, 0xc5, 0x42, 0xe4, 0x01, 0x00, 0x00, 0x04, + 0x07, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0xb5, + 0xa3, 0xea, 0x08, 0x04, 0x08, 0x02, 0x00, 0x00, + 0x94, 0x00, 0xc5, 0x28, 0x07, 0x02, 0x30, 0x0e, + 0x43, 0x02, 0x03, 0xb0, 0x07, 0x02, 0x01, 0x02, + 0x05, 0x01, 0x00, 0x4a, 0x00, 0x00, 0x69, 0x01, + 0xd2, 0xbd, 0x10, 0xa9, 0xea, 0x29, 0xd1, 0xb5, + 0xa3, 0xea, 0x0c, 0xd1, 0x8c, 0xd5, 0x04, 0x01, + 0x02, 0x00, 0x00, 0xc9, 0xec, 0x03, 0xc1, 0xc9, + 0xc5, 0x04, 0x02, 0x02, 0x00, 0x00, 0xd1, 0x42, + 0x3a, 0x00, 0x00, 0x00, 0xbd, 0x10, 0x24, 0x01, + 0x00, 0x9d, 0x9d, 0xc9, 0xec, 0x0b, 0xd1, 0x42, + 0x3a, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xc9, + 0xdd, 0x04, 0xe4, 0x00, 0x00, 0x00, 0xab, 0xea, + 0x08, 0x04, 0x09, 0x02, 0x00, 0x00, 0x94, 0x00, + 0xc5, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xb2, 0x07, + 0x01, 0x02, 0x01, 0x02, 0x09, 0x01, 0x0b, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x08, 0x01, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x6a, 0x01, 0x00, + 0x68, 0x01, 0x00, 0x6c, 0x01, 0x00, 0x6b, 0x01, + 0x00, 0x01, 0x01, 0xc0, 0x00, 0xca, 0x26, 0x00, + 0x00, 0xc9, 0xc6, 0xd1, 0xef, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0x94, 0x08, 0x01, 0x06, 0x01, 0x05, + 0x0b, 0x00, 0x95, 0x06, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x08, 0x00, 0xd1, 0x97, + 0xc4, 0x04, 0x04, 0x4c, 0x00, 0x00, 0x00, 0xab, + 0x69, 0xdd, 0x01, 0x00, 0x00, 0xd1, 0xf3, 0xea, + 0x0f, 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0xd1, 0x24, 0x01, 0x00, 0x0e, 0x29, 0xde, + 0x42, 0xe4, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, + 0x00, 0xb5, 0xa6, 0xea, 0x13, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x0b, 0x02, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x29, 0xdf, + 0xea, 0x62, 0xd1, 0x38, 0xe9, 0x00, 0x00, 0x00, + 0xa7, 0x11, 0xeb, 0x40, 0x0e, 0xd1, 0x38, 0x0c, + 0x02, 0x00, 0x00, 0xa7, 0x11, 0xeb, 0x35, 0x0e, + 0xd1, 0x38, 0x0d, 0x02, 0x00, 0x00, 0xa7, 0x11, + 0xeb, 0x2a, 0x0e, 0xd1, 0x38, 0x0e, 0x02, 0x00, + 0x00, 0xa7, 0x11, 0xeb, 0x1f, 0x0e, 0xd1, 0x38, + 0x0f, 0x02, 0x00, 0x00, 0xa7, 0x11, 0xeb, 0x14, + 0x0e, 0xd1, 0x38, 0x10, 0x02, 0x00, 0x00, 0xa7, + 0x11, 0xeb, 0x09, 0x0e, 0xd1, 0x38, 0x11, 0x02, + 0x00, 0x00, 0xa7, 0xea, 0x17, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0xd1, 0x42, 0x3a, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0x29, 0xde, 0x42, 0x87, 0x01, 0x00, + 0x00, 0xd1, 0x24, 0x01, 0x00, 0x0e, 0xe0, 0x42, + 0x12, 0x02, 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, + 0x69, 0x86, 0x00, 0x00, 0x00, 0xd1, 0xe9, 0xc9, + 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x04, 0x13, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0xb5, 0xca, 0xc6, 0xc5, 0xa3, 0xea, 0x54, + 0xc6, 0xb5, 0xac, 0xea, 0x12, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x14, 0x02, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xc6, 0xd1, + 0xa8, 0xea, 0x0b, 0x5e, 0x04, 0x00, 0xd1, 0xc6, + 0x47, 0xef, 0x0e, 0xec, 0x12, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x15, 0x02, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xc6, 0xbd, + 0x14, 0xa5, 0xea, 0x14, 0x65, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x16, 0x02, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xec, 0x05, 0x93, + 0x01, 0xec, 0xa9, 0x65, 0x00, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x17, 0x02, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xed, 0x9d, 0x00, 0x5e, + 0x05, 0x00, 0x42, 0x18, 0x02, 0x00, 0x00, 0xd1, + 0x24, 0x01, 0x00, 0x04, 0xa3, 0x00, 0x00, 0x00, + 0xab, 0xea, 0x18, 0x65, 0x00, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0xd1, 0x42, 0x3a, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0xec, 0x71, 0x5e, 0x05, 0x00, 0x42, 0x19, 0x02, + 0x00, 0x00, 0xd1, 0x24, 0x01, 0x00, 0xcf, 0xe9, + 0xc9, 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x1a, 0x02, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xb5, 0xca, 0xc6, 0xc5, 0xa3, 0xea, + 0x39, 0xc6, 0xb5, 0xac, 0xea, 0x12, 0x65, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x14, + 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xc7, + 0xc6, 0x47, 0xcc, 0x65, 0x00, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0xc8, 0x04, 0x1b, 0x02, 0x00, + 0x00, 0x24, 0x02, 0x00, 0x0e, 0x5e, 0x04, 0x00, + 0xd1, 0xc8, 0x47, 0xef, 0x0e, 0x93, 0x01, 0xec, + 0xc4, 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x1c, 0x02, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xde, 0x42, 0x1d, 0x02, 0x00, 0x00, + 0xd1, 0x24, 0x01, 0x00, 0x0e, 0x29, 0xc2, 0x04, + 0x04, 0x4b, 0x00, 0x00, 0x00, 0xab, 0xea, 0x36, + 0xd1, 0x42, 0x1e, 0x02, 0x00, 0x00, 0x24, 0x00, + 0x00, 0xc4, 0x05, 0xe9, 0xbd, 0x4f, 0xa5, 0xea, + 0x16, 0xc2, 0x05, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb5, 0xbd, 0x4b, 0x24, 0x02, 0x00, 0x04, 0x1f, + 0x02, 0x00, 0x00, 0x9d, 0xc3, 0x05, 0x65, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0xc2, 0x05, + 0x24, 0x01, 0x00, 0x0e, 0x29, 0xc2, 0x04, 0x04, + 0x49, 0x00, 0x00, 0x00, 0xab, 0xea, 0x1e, 0x65, + 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x5e, + 0x06, 0x00, 0xd1, 0x5e, 0x07, 0x00, 0xea, 0x05, + 0xbd, 0x10, 0xec, 0x03, 0xbd, 0x0a, 0xf0, 0x24, + 0x01, 0x00, 0x0e, 0x29, 0xc2, 0x04, 0x04, 0x8e, + 0x00, 0x00, 0x00, 0xab, 0xea, 0x1e, 0x65, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x5e, 0x08, + 0x00, 0xd1, 0x5e, 0x07, 0x00, 0xea, 0x05, 0xbd, + 0x10, 0xec, 0x03, 0xbd, 0x0a, 0xf0, 0x24, 0x01, + 0x00, 0x0e, 0x29, 0xc2, 0x04, 0x04, 0x8f, 0x00, + 0x00, 0x00, 0xab, 0xea, 0x1e, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0x5e, 0x09, 0x00, + 0xd1, 0x5e, 0x07, 0x00, 0xea, 0x05, 0xbd, 0x10, + 0xec, 0x03, 0xbd, 0x0a, 0xf0, 0x24, 0x01, 0x00, + 0x0e, 0x29, 0xc2, 0x04, 0x04, 0x90, 0x00, 0x00, + 0x00, 0xab, 0xea, 0x1d, 0x65, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xd1, 0x42, 0x3a, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x04, 0x20, 0x02, + 0x00, 0x00, 0x9d, 0x24, 0x01, 0x00, 0x0e, 0x29, + 0xc2, 0x04, 0x04, 0x4d, 0x00, 0x00, 0x00, 0xab, + 0xea, 0x13, 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x5e, 0x0a, 0x00, 0xd1, 0xef, 0x24, + 0x01, 0x00, 0x0e, 0x29, 0xc2, 0x04, 0x04, 0x1b, + 0x00, 0x00, 0x00, 0xab, 0xea, 0x20, 0x65, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x21, + 0x02, 0x00, 0x00, 0xd1, 0x41, 0x39, 0x00, 0x00, + 0x00, 0x9d, 0x04, 0x64, 0x01, 0x00, 0x00, 0x9d, + 0x24, 0x01, 0x00, 0x0e, 0x29, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, + 0x00, 0x0e, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xb4, + 0x07, 0x01, 0x01, 0x01, 0x04, 0x01, 0x00, 0x2c, + 0x00, 0x00, 0x2e, 0x01, 0xd1, 0xb5, 0x47, 0x04, + 0x22, 0x02, 0x00, 0x00, 0xac, 0xea, 0x03, 0xc1, + 0x28, 0xb6, 0xc9, 0xc5, 0xd1, 0xe9, 0xa3, 0xea, + 0x0d, 0xdd, 0xd1, 0xc5, 0x47, 0xef, 0x96, 0xeb, + 0x05, 0x93, 0x00, 0xec, 0xef, 0xd1, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xb6, 0xc5, 0x25, 0x02, 0x00, + 0x0e, 0x43, 0x02, 0x03, 0xb6, 0x07, 0x02, 0x04, + 0x02, 0x07, 0x0c, 0x00, 0xb2, 0x07, 0x00, 0x00, + 0x70, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x68, 0x01, + 0x00, 0x17, 0x01, 0x00, 0x09, 0x01, 0x00, 0x0e, + 0x01, 0x00, 0x04, 0x01, 0x00, 0x10, 0x01, 0x00, + 0x0f, 0x01, 0x00, 0x06, 0x01, 0x00, 0x69, 0x01, + 0x00, 0x08, 0x01, 0xd1, 0x04, 0x23, 0x02, 0x00, + 0x00, 0xab, 0x11, 0xeb, 0x14, 0x0e, 0xd1, 0x04, + 0x24, 0x02, 0x00, 0x00, 0xab, 0x11, 0xeb, 0x09, + 0x0e, 0xd1, 0x04, 0xdc, 0x01, 0x00, 0x00, 0xa9, + 0xea, 0x07, 0xdd, 0xee, 0x0e, 0xed, 0x8d, 0x03, + 0xd1, 0x04, 0x25, 0x02, 0x00, 0x00, 0xab, 0xea, + 0x4b, 0xd2, 0x42, 0x69, 0x01, 0x00, 0x00, 0xd1, + 0xe9, 0xb6, 0x9d, 0x24, 0x01, 0x00, 0x42, 0x26, + 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, 0xd0, 0x42, + 0x27, 0x02, 0x00, 0x00, 0x04, 0xe5, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0xc8, 0x42, 0x27, 0x02, + 0x00, 0x00, 0x04, 0xea, 0x01, 0x00, 0x00, 0x24, + 0x01, 0x00, 0xa4, 0xea, 0x08, 0x04, 0x28, 0x02, + 0x00, 0x00, 0x94, 0x03, 0x65, 0x01, 0x00, 0x42, + 0x29, 0x02, 0x00, 0x00, 0xc8, 0x24, 0x01, 0x00, + 0x0e, 0x09, 0x28, 0xd1, 0x04, 0x2a, 0x02, 0x00, + 0x00, 0xab, 0xea, 0x06, 0x0a, 0xe3, 0xed, 0x2c, + 0x03, 0xd1, 0x04, 0x2b, 0x02, 0x00, 0x00, 0xab, + 0xea, 0x06, 0x09, 0xe3, 0xed, 0x1e, 0x03, 0xd1, + 0x04, 0x2c, 0x02, 0x00, 0x00, 0xab, 0xea, 0x07, + 0xe0, 0x96, 0xe4, 0xed, 0x0f, 0x03, 0x5e, 0x04, + 0x00, 0x69, 0x96, 0x01, 0x00, 0x00, 0xd1, 0x04, + 0x06, 0x02, 0x00, 0x00, 0xab, 0x69, 0x8a, 0x01, + 0x00, 0x00, 0xd2, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xd1, 0xe9, 0xb6, 0x9d, 0x24, 0x01, 0x00, 0x42, + 0x26, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, 0x42, + 0x60, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0xcd, 0xe9, 0xb6, 0xab, + 0xea, 0x49, 0xc5, 0xb5, 0x47, 0xc1, 0xab, 0xea, + 0x42, 0x65, 0x01, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x2d, 0x02, 0x00, 0x00, 0x5e, 0x05, + 0x00, 0x9d, 0x04, 0x2e, 0x02, 0x00, 0x00, 0x9d, + 0x5e, 0x06, 0x00, 0x42, 0xf6, 0x01, 0x00, 0x00, + 0x5e, 0x05, 0x00, 0x5e, 0x07, 0x00, 0x9b, 0x24, + 0x01, 0x00, 0x9d, 0x04, 0x2f, 0x02, 0x00, 0x00, + 0x9d, 0x5e, 0x08, 0x00, 0x9d, 0x04, 0x30, 0x02, + 0x00, 0x00, 0x9d, 0x24, 0x01, 0x00, 0x0e, 0xed, + 0x16, 0x01, 0xc5, 0xb5, 0x47, 0x04, 0x31, 0x02, + 0x00, 0x00, 0xab, 0xea, 0x0d, 0xbd, 0x0b, 0x5f, + 0x05, 0x00, 0xba, 0x5f, 0x08, 0x00, 0xed, 0xff, + 0x00, 0xc5, 0xb5, 0x47, 0x04, 0x32, 0x02, 0x00, + 0x00, 0xab, 0xea, 0x0e, 0xbd, 0x18, 0x5f, 0x05, + 0x00, 0xbd, 0x08, 0x5f, 0x08, 0x00, 0xed, 0xe7, + 0x00, 0xc5, 0xb5, 0x47, 0x04, 0x33, 0x02, 0x00, + 0x00, 0xab, 0xea, 0x0e, 0xbd, 0x35, 0x5f, 0x05, + 0x00, 0xbd, 0x0b, 0x5f, 0x08, 0x00, 0xed, 0xcf, + 0x00, 0xc5, 0xb5, 0x47, 0x04, 0x34, 0x02, 0x00, + 0x00, 0xab, 0xea, 0x0e, 0xbd, 0x71, 0x5f, 0x05, + 0x00, 0xbd, 0x0f, 0x5f, 0x08, 0x00, 0xed, 0xb7, + 0x00, 0x38, 0x35, 0x02, 0x00, 0x00, 0xc5, 0xb5, + 0x47, 0xef, 0xca, 0xc5, 0xe9, 0xb7, 0xa6, 0xea, + 0x0d, 0x38, 0x35, 0x02, 0x00, 0x00, 0xc5, 0xb6, + 0x47, 0xef, 0xcb, 0xec, 0x0c, 0x38, 0xb4, 0x00, + 0x00, 0x00, 0x41, 0x36, 0x02, 0x00, 0x00, 0xcb, + 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, 0xec, 0x01, + 0x00, 0x00, 0xc6, 0x24, 0x01, 0x00, 0x11, 0xeb, + 0x1e, 0x0e, 0xc6, 0x38, 0xb4, 0x00, 0x00, 0x00, + 0x41, 0x37, 0x02, 0x00, 0x00, 0xa3, 0x11, 0xeb, + 0x0e, 0x0e, 0xc6, 0x38, 0xb4, 0x00, 0x00, 0x00, + 0x41, 0x38, 0x02, 0x00, 0x00, 0xa5, 0xea, 0x14, + 0x65, 0x01, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x04, 0x39, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0x09, 0x28, 0x38, 0x98, 0x00, 0x00, 0x00, + 0x42, 0xec, 0x01, 0x00, 0x00, 0xc7, 0x24, 0x01, + 0x00, 0x11, 0xeb, 0x1e, 0x0e, 0xc7, 0x38, 0xb4, + 0x00, 0x00, 0x00, 0x41, 0x3a, 0x02, 0x00, 0x00, + 0xa3, 0x11, 0xeb, 0x0e, 0x0e, 0xc7, 0x38, 0xb4, + 0x00, 0x00, 0x00, 0x41, 0x36, 0x02, 0x00, 0x00, + 0xa5, 0xea, 0x14, 0x65, 0x01, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x3b, 0x02, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0x09, 0x28, 0xc6, 0x5f, + 0x05, 0x00, 0xc7, 0x5f, 0x08, 0x00, 0x09, 0x28, + 0x5e, 0x04, 0x00, 0xea, 0x78, 0xd1, 0x04, 0x3c, + 0x02, 0x00, 0x00, 0xab, 0xea, 0x6f, 0xd2, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xd1, 0xe9, 0xb6, 0x9d, + 0x24, 0x01, 0x00, 0x42, 0x26, 0x02, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xc9, 0x5e, 0x06, 0x00, 0x42, + 0xf7, 0x01, 0x00, 0x00, 0x5e, 0x09, 0x00, 0xc5, + 0xef, 0x5e, 0x07, 0x00, 0x9a, 0x24, 0x01, 0x00, + 0xce, 0x38, 0xb4, 0x00, 0x00, 0x00, 0x41, 0x37, + 0x02, 0x00, 0x00, 0xa3, 0x11, 0xeb, 0x0e, 0x0e, + 0xc6, 0x38, 0xb4, 0x00, 0x00, 0x00, 0x41, 0x38, + 0x02, 0x00, 0x00, 0xa5, 0xea, 0x14, 0x65, 0x01, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x39, + 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x09, + 0x28, 0xc6, 0x5f, 0x05, 0x00, 0x38, 0xb4, 0x00, + 0x00, 0x00, 0x41, 0x36, 0x02, 0x00, 0x00, 0x5f, + 0x08, 0x00, 0x09, 0x28, 0x5e, 0x04, 0x00, 0xea, + 0x6e, 0xd1, 0x04, 0x3d, 0x02, 0x00, 0x00, 0xab, + 0xea, 0x65, 0xd2, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xd1, 0xe9, 0xb6, 0x9d, 0x24, 0x01, 0x00, 0x42, + 0x26, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, 0xcd, + 0xc1, 0xab, 0xea, 0x1e, 0x65, 0x01, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x3e, 0x02, 0x00, + 0x00, 0x5e, 0x0a, 0x00, 0x9d, 0x04, 0x21, 0x01, + 0x00, 0x00, 0x9d, 0x24, 0x01, 0x00, 0x0e, 0xec, + 0x2c, 0xc5, 0x04, 0xe4, 0x00, 0x00, 0x00, 0xab, + 0x11, 0xeb, 0x09, 0x0e, 0xc5, 0x04, 0x03, 0x02, + 0x00, 0x00, 0xab, 0xea, 0x07, 0xc5, 0x5f, 0x0a, + 0x00, 0xec, 0x12, 0x65, 0x01, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x3f, 0x02, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0x09, 0x28, 0xd1, 0x04, + 0x40, 0x02, 0x00, 0x00, 0xab, 0xea, 0x14, 0x65, + 0x01, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, + 0x41, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0xec, 0x6a, 0xd1, 0x04, 0x42, 0x02, 0x00, 0x00, + 0xab, 0xea, 0x10, 0x65, 0x01, 0x00, 0x42, 0xa3, + 0x01, 0x00, 0x00, 0xb5, 0x24, 0x01, 0x00, 0x0e, + 0xec, 0x52, 0x5e, 0x0b, 0x00, 0xea, 0x17, 0xd1, + 0x04, 0x59, 0x01, 0x00, 0x00, 0xab, 0xea, 0x0e, + 0x36, 0x43, 0x02, 0x00, 0x00, 0x0a, 0x3b, 0x43, + 0x02, 0x00, 0x00, 0xec, 0x37, 0x5e, 0x0b, 0x00, + 0xea, 0x17, 0xd1, 0x04, 0x09, 0x02, 0x00, 0x00, + 0xab, 0xea, 0x0e, 0x36, 0x43, 0x02, 0x00, 0x00, + 0x09, 0x3b, 0x43, 0x02, 0x00, 0x00, 0xec, 0x1c, + 0x65, 0x01, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x04, 0x44, 0x02, 0x00, 0x00, 0xd1, 0x9d, 0x04, + 0x21, 0x01, 0x00, 0x00, 0x9d, 0x24, 0x01, 0x00, + 0x0e, 0x09, 0x28, 0x0a, 0x28, 0x0e, 0x43, 0x02, + 0x03, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x00, + 0x46, 0x00, 0x00, 0x68, 0x01, 0xd1, 0x11, 0x04, + 0x45, 0x02, 0x00, 0x00, 0xab, 0xea, 0x05, 0x09, + 0xe1, 0xec, 0x38, 0x11, 0x04, 0x46, 0x02, 0x00, + 0x00, 0xab, 0xea, 0x05, 0x0a, 0xe1, 0xec, 0x2b, + 0x11, 0x04, 0x47, 0x02, 0x00, 0x00, 0xab, 0xea, + 0x0e, 0x36, 0x43, 0x02, 0x00, 0x00, 0x09, 0x3b, + 0x43, 0x02, 0x00, 0x00, 0xec, 0x15, 0x11, 0x04, + 0x48, 0x02, 0x00, 0x00, 0xab, 0xea, 0x0c, 0x36, + 0x43, 0x02, 0x00, 0x00, 0x0a, 0x3b, 0x43, 0x02, + 0x00, 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xb8, + 0x07, 0x00, 0x01, 0x00, 0x05, 0x07, 0x01, 0xd5, + 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x68, 0x01, + 0x00, 0x17, 0x01, 0x00, 0x08, 0x01, 0x00, 0x09, + 0x01, 0x00, 0x69, 0x01, 0x00, 0x07, 0x01, 0xc0, + 0x00, 0xc9, 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x49, 0x02, 0x00, 0x00, 0x04, + 0x4a, 0x02, 0x00, 0x00, 0x9d, 0xc5, 0xde, 0xef, + 0x9d, 0x04, 0x4b, 0x02, 0x00, 0x00, 0x9d, 0x04, + 0x4c, 0x02, 0x00, 0x00, 0x9d, 0xc5, 0xde, 0x96, + 0xef, 0x9d, 0x04, 0x4d, 0x02, 0x00, 0x00, 0x9d, + 0x04, 0x4e, 0x02, 0x00, 0x00, 0x9d, 0xc5, 0xdf, + 0xef, 0x9d, 0x04, 0x4f, 0x02, 0x00, 0x00, 0x9d, + 0x04, 0x50, 0x02, 0x00, 0x00, 0x9d, 0x24, 0x01, + 0x00, 0x0e, 0xe0, 0xea, 0x35, 0x65, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x51, 0x02, + 0x00, 0x00, 0xc5, 0x38, 0x43, 0x02, 0x00, 0x00, + 0xef, 0x9d, 0x04, 0x52, 0x02, 0x00, 0x00, 0x9d, + 0x04, 0x53, 0x02, 0x00, 0x00, 0x9d, 0xc5, 0x38, + 0x43, 0x02, 0x00, 0x00, 0x96, 0xef, 0x9d, 0x04, + 0x54, 0x02, 0x00, 0x00, 0x9d, 0x24, 0x01, 0x00, + 0x0e, 0x5e, 0x04, 0x00, 0xea, 0x37, 0x65, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x55, + 0x02, 0x00, 0x00, 0x04, 0x56, 0x02, 0x00, 0x00, + 0x9d, 0x24, 0x01, 0x00, 0x0e, 0xe0, 0x96, 0xea, + 0x1c, 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x57, 0x02, 0x00, 0x00, 0x5e, 0x05, + 0x00, 0x9d, 0x04, 0x58, 0x02, 0x00, 0x00, 0x9d, + 0x24, 0x01, 0x00, 0x0e, 0x5e, 0x06, 0x00, 0x96, + 0xea, 0x12, 0x65, 0x00, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x59, 0x02, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xb4, 0x09, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x0f, 0x00, 0xd1, 0xea, 0x07, 0x04, 0x80, 0x00, + 0x00, 0x00, 0x28, 0x04, 0xf9, 0x01, 0x00, 0x00, + 0x28, 0x0e, 0x43, 0x02, 0x03, 0xba, 0x07, 0x01, + 0x03, 0x01, 0x06, 0x08, 0x00, 0x9f, 0x02, 0x00, + 0x00, 0x69, 0x01, 0x00, 0x03, 0x01, 0x00, 0x00, + 0x0c, 0x00, 0x19, 0x01, 0x00, 0x0a, 0x01, 0x00, + 0x0b, 0x01, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x03, + 0x6c, 0x95, 0x00, 0x00, 0x00, 0xdd, 0x04, 0x03, + 0x02, 0x00, 0x00, 0xab, 0xea, 0x09, 0x04, 0x5b, + 0x02, 0x00, 0x00, 0xd1, 0x9d, 0xd5, 0xde, 0x11, + 0x21, 0x00, 0x00, 0x42, 0x5c, 0x02, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xca, 0x65, 0x02, 0x00, 0x42, + 0x5d, 0x02, 0x00, 0x00, 0xd1, 0x0b, 0x0a, 0x4c, + 0x5e, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0xc9, + 0xde, 0x11, 0x21, 0x00, 0x00, 0x42, 0x5c, 0x02, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xc6, 0x9e, 0xe4, + 0x65, 0x02, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x5e, 0x04, 0x00, 0x5e, 0x05, 0x00, 0x41, 0x13, + 0x01, 0x00, 0x00, 0x47, 0x24, 0x01, 0x00, 0x0e, + 0x5e, 0x06, 0x00, 0xc5, 0xef, 0x0e, 0x65, 0x02, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x21, + 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x65, + 0x02, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x5e, + 0x04, 0x00, 0x41, 0xeb, 0x00, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0x5e, 0x07, 0x00, 0xc5, 0x43, + 0x5d, 0x01, 0x00, 0x00, 0x0e, 0x29, 0xcb, 0x6c, + 0x86, 0x00, 0x00, 0x00, 0x65, 0x02, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x5e, 0x04, 0x00, 0x5e, + 0x05, 0x00, 0x41, 0x14, 0x01, 0x00, 0x00, 0x47, + 0x24, 0x01, 0x00, 0x0e, 0xc7, 0x38, 0x97, 0x00, + 0x00, 0x00, 0xa7, 0xea, 0x2c, 0x38, 0x5f, 0x02, + 0x00, 0x00, 0x42, 0x60, 0x02, 0x00, 0x00, 0xc7, + 0x24, 0x01, 0x00, 0x0e, 0xc7, 0x41, 0x38, 0x00, + 0x00, 0x00, 0xea, 0x35, 0x65, 0x02, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xc7, 0x41, 0x38, 0x00, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xec, 0x21, + 0x65, 0x02, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x04, 0x61, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0x38, 0x5f, 0x02, 0x00, 0x00, 0x42, 0x60, + 0x02, 0x00, 0x00, 0xc7, 0x24, 0x01, 0x00, 0x0e, + 0x65, 0x02, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x5e, 0x04, 0x00, 0x41, 0xeb, 0x00, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0x0e, 0x29, 0x2f, 0x0e, + 0x43, 0x02, 0x03, 0xbc, 0x07, 0x00, 0x00, 0x00, + 0x04, 0x0b, 0x00, 0x6e, 0x00, 0xdc, 0x06, 0x07, + 0x01, 0xde, 0x06, 0x08, 0x01, 0xc8, 0x03, 0x00, + 0x0c, 0xe0, 0x06, 0x09, 0x01, 0xea, 0x06, 0x10, + 0x01, 0xba, 0x02, 0x04, 0x01, 0xe6, 0x06, 0x0e, + 0x01, 0xe8, 0x06, 0x0f, 0x01, 0xaa, 0x07, 0x69, + 0x01, 0xda, 0x06, 0x00, 0x03, 0xbe, 0x07, 0x73, + 0x01, 0xdd, 0x96, 0xea, 0x28, 0xde, 0xea, 0x14, + 0x65, 0x02, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x04, 0x62, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0xec, 0x12, 0x65, 0x02, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x63, 0x02, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xe0, 0xea, 0x3c, 0x5e, + 0x05, 0x00, 0x42, 0x60, 0x02, 0x00, 0x00, 0xbd, + 0x0a, 0x24, 0x01, 0x00, 0x5e, 0x05, 0x00, 0x42, + 0x60, 0x02, 0x00, 0x00, 0xb7, 0x24, 0x01, 0x00, + 0x9b, 0x5f, 0x04, 0x00, 0xbd, 0x71, 0x5f, 0x06, + 0x00, 0xbd, 0x0f, 0x5f, 0x07, 0x00, 0xde, 0xea, + 0x12, 0x04, 0x03, 0x02, 0x00, 0x00, 0x5f, 0x08, + 0x00, 0x5e, 0x09, 0x00, 0xdd, 0x43, 0x43, 0x02, + 0x00, 0x00, 0x5e, 0x0a, 0x00, 0xee, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xbe, 0x07, 0x00, 0x00, 0x00, + 0x04, 0x04, 0x00, 0x0c, 0x00, 0xa2, 0x07, 0x65, + 0x01, 0x9a, 0x07, 0x60, 0x01, 0x80, 0x07, 0x1b, + 0x01, 0xc0, 0x07, 0x74, 0x01, 0xdd, 0xde, 0x04, + 0x64, 0x02, 0x00, 0x00, 0xdf, 0xf0, 0xe0, 0xf0, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xc0, 0x07, 0x01, + 0x00, 0x01, 0x02, 0x02, 0x00, 0x07, 0x00, 0x00, + 0x75, 0x01, 0x00, 0x73, 0x01, 0xdd, 0xd1, 0xef, + 0x0e, 0xde, 0xee, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xc2, 0x07, 0x01, 0x02, 0x01, 0x06, 0x0c, 0x00, + 0x9e, 0x01, 0x00, 0x00, 0x70, 0x01, 0x00, 0x6e, + 0x01, 0x00, 0x6f, 0x01, 0x00, 0x1a, 0x01, 0x00, + 0x76, 0x01, 0x00, 0x11, 0x01, 0x00, 0x1b, 0x01, + 0x00, 0x09, 0x01, 0x00, 0x71, 0x01, 0x00, 0x0e, + 0x01, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x0c, 0xd1, + 0xf3, 0xea, 0x04, 0xc1, 0xd5, 0x29, 0xd1, 0x04, + 0x24, 0x02, 0x00, 0x00, 0xab, 0xea, 0x04, 0xdd, + 0xee, 0x29, 0xde, 0xd1, 0xef, 0xce, 0xe9, 0xb5, + 0xa5, 0xea, 0x17, 0xdf, 0xc6, 0xd1, 0xf0, 0x96, + 0xea, 0x02, 0x29, 0xd1, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xc6, 0xe9, 0xb6, 0x9d, 0x24, 0x01, 0x00, + 0xd5, 0xd1, 0xc1, 0xab, 0xea, 0x02, 0x29, 0xe0, + 0xea, 0x0b, 0xe0, 0x04, 0x21, 0x01, 0x00, 0x00, + 0x9d, 0xd1, 0x9d, 0xd5, 0x5e, 0x04, 0x00, 0xd1, + 0xef, 0xcd, 0xb5, 0x47, 0x5f, 0x05, 0x00, 0xc5, + 0xb6, 0x47, 0x5f, 0x06, 0x00, 0x5e, 0x05, 0x00, + 0xea, 0x04, 0xd1, 0xe4, 0x29, 0xc1, 0xe4, 0x5e, + 0x07, 0x00, 0xea, 0x24, 0x38, 0xb4, 0x00, 0x00, + 0x00, 0x42, 0x65, 0x02, 0x00, 0x00, 0x5e, 0x08, + 0x00, 0x42, 0x66, 0x02, 0x00, 0x00, 0x07, 0xd1, + 0x24, 0x02, 0x00, 0x5e, 0x09, 0x00, 0x5e, 0x0a, + 0x00, 0x24, 0x03, 0x00, 0x0e, 0xec, 0x07, 0x5e, + 0x08, 0x00, 0xd1, 0xef, 0x0e, 0xb5, 0x5f, 0x06, + 0x00, 0x65, 0x0b, 0x00, 0x42, 0x67, 0x02, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xc4, 0x07, 0x01, 0x17, 0x01, 0x04, 0x03, + 0x0a, 0x8f, 0x04, 0x00, 0x00, 0x30, 0x01, 0x00, + 0x33, 0x01, 0x00, 0x2f, 0x01, 0xc0, 0x00, 0xc3, + 0x0a, 0xc0, 0x01, 0xc3, 0x0b, 0xc0, 0x02, 0xc3, + 0x0c, 0xc0, 0x03, 0xc3, 0x0d, 0xc0, 0x04, 0xc3, + 0x0e, 0xc0, 0x05, 0xc3, 0x0f, 0xc0, 0x06, 0xc3, + 0x10, 0xc0, 0x07, 0xc3, 0x11, 0xc0, 0x08, 0xc3, + 0x15, 0xc0, 0x09, 0xc3, 0x16, 0xd1, 0xe9, 0xcc, + 0xc1, 0xc3, 0x05, 0xb5, 0xc3, 0x06, 0xb6, 0xc3, + 0x08, 0x26, 0x00, 0x00, 0xc3, 0x09, 0x04, 0x68, + 0x02, 0x00, 0x00, 0x04, 0x69, 0x02, 0x00, 0x00, + 0x9d, 0x04, 0x6a, 0x02, 0x00, 0x00, 0x9d, 0x04, + 0x6b, 0x02, 0x00, 0x00, 0x9d, 0x04, 0x6c, 0x02, + 0x00, 0x00, 0x9d, 0x04, 0x6d, 0x02, 0x00, 0x00, + 0x9d, 0x04, 0x6e, 0x02, 0x00, 0x00, 0x9d, 0x04, + 0x6f, 0x02, 0x00, 0x00, 0x9d, 0x04, 0x70, 0x02, + 0x00, 0x00, 0x9d, 0x04, 0x71, 0x02, 0x00, 0x00, + 0x9d, 0xc3, 0x12, 0x04, 0x72, 0x02, 0x00, 0x00, + 0xc3, 0x13, 0x04, 0x73, 0x02, 0x00, 0x00, 0xc3, + 0x14, 0xb5, 0xc9, 0xc5, 0xc8, 0xa3, 0x69, 0x75, + 0x01, 0x00, 0x00, 0x07, 0xc3, 0x04, 0xc5, 0xcb, + 0xd1, 0xc5, 0x91, 0xc9, 0x47, 0xce, 0x11, 0x04, + 0xf9, 0x01, 0x00, 0x00, 0xab, 0xeb, 0x1c, 0x11, + 0x04, 0x20, 0x01, 0x00, 0x00, 0xab, 0xeb, 0x13, + 0x11, 0x04, 0x23, 0x01, 0x00, 0x00, 0xab, 0xeb, + 0x0a, 0x11, 0x04, 0x21, 0x01, 0x00, 0x00, 0xab, + 0xea, 0x04, 0x0e, 0xec, 0xc7, 0x11, 0x04, 0x74, + 0x02, 0x00, 0x00, 0xab, 0xeb, 0x0a, 0x11, 0x04, + 0x01, 0x02, 0x00, 0x00, 0xab, 0xea, 0x18, 0xc5, + 0xc8, 0xa3, 0xea, 0x0d, 0xd1, 0xc5, 0x47, 0xc6, + 0xa9, 0xea, 0x06, 0x93, 0x00, 0x0e, 0xec, 0xa4, + 0xb6, 0xc3, 0x08, 0x0e, 0xec, 0x9e, 0x11, 0x04, + 0xea, 0x01, 0x00, 0x00, 0xab, 0xea, 0x44, 0xc5, + 0xc8, 0xa3, 0xea, 0x13, 0xd1, 0xc5, 0x47, 0x04, + 0x80, 0x00, 0x00, 0x00, 0xa9, 0xea, 0x08, 0xc2, + 0x0d, 0xee, 0x0e, 0xed, 0xe7, 0x00, 0xc5, 0xc8, + 0xa3, 0xea, 0x13, 0xd1, 0xc5, 0x47, 0x04, 0xea, + 0x01, 0x00, 0x00, 0xa9, 0xea, 0x08, 0xc2, 0x0e, + 0xee, 0x0e, 0xed, 0xd0, 0x00, 0xc2, 0x08, 0xea, + 0x0b, 0xc2, 0x10, 0xee, 0x0e, 0xb5, 0xc3, 0x08, + 0xed, 0xc2, 0x00, 0xb6, 0xc3, 0x08, 0x0e, 0xed, + 0x53, 0xff, 0x11, 0x04, 0xe6, 0x01, 0x00, 0x00, + 0xab, 0xeb, 0x13, 0x11, 0x04, 0xe7, 0x01, 0x00, + 0x00, 0xab, 0xeb, 0x0a, 0x11, 0x04, 0x75, 0x02, + 0x00, 0x00, 0xab, 0xea, 0x0c, 0xc2, 0x0f, 0xc6, + 0xef, 0x0e, 0xb5, 0xc3, 0x08, 0xed, 0x95, 0x00, + 0x11, 0x04, 0xf3, 0x01, 0x00, 0x00, 0xab, 0xeb, + 0x13, 0x11, 0x04, 0xfd, 0x01, 0x00, 0x00, 0xab, + 0xeb, 0x0a, 0x11, 0x04, 0x76, 0x02, 0x00, 0x00, + 0xab, 0xea, 0x0f, 0xb6, 0xc3, 0x08, 0x93, 0x06, + 0xc2, 0x0a, 0xc6, 0xef, 0x0e, 0x0e, 0xed, 0x04, + 0xff, 0x11, 0x04, 0xf4, 0x01, 0x00, 0x00, 0xab, + 0xeb, 0x13, 0x11, 0x04, 0xe8, 0x01, 0x00, 0x00, + 0xab, 0xeb, 0x0a, 0x11, 0x04, 0xe9, 0x01, 0x00, + 0x00, 0xab, 0xea, 0x25, 0xb5, 0xc3, 0x08, 0xc2, + 0x06, 0xb5, 0xa5, 0xea, 0x13, 0xde, 0xc2, 0x0b, + 0xee, 0xc6, 0xf0, 0xea, 0x0b, 0x92, 0x06, 0xc2, + 0x0c, 0xee, 0x0e, 0x0e, 0xed, 0xce, 0xfe, 0x04, + 0x12, 0x01, 0x00, 0x00, 0xc3, 0x04, 0xec, 0x2c, + 0xdf, 0xc6, 0xef, 0xea, 0x0a, 0xc2, 0x11, 0xee, + 0x0e, 0xb5, 0xc3, 0x08, 0xec, 0x1e, 0xdd, 0xc6, + 0xef, 0x11, 0xeb, 0x09, 0x0e, 0xc6, 0x04, 0x5e, + 0x01, 0x00, 0x00, 0xa9, 0xea, 0x07, 0xc2, 0x15, + 0xee, 0x0e, 0xec, 0x08, 0xb6, 0xc3, 0x08, 0x0e, + 0xed, 0x9a, 0xfe, 0x0e, 0xc2, 0x04, 0x69, 0x94, + 0xfe, 0xff, 0xff, 0xc2, 0x16, 0xc7, 0xc5, 0xf0, + 0x0e, 0xed, 0x89, 0xfe, 0xc2, 0x16, 0xc8, 0xc8, + 0xf0, 0x0e, 0xc2, 0x05, 0xc2, 0x06, 0xc2, 0x09, + 0x26, 0x03, 0x00, 0x28, 0x0e, 0x43, 0x02, 0x03, + 0xee, 0x09, 0x01, 0x00, 0x01, 0x02, 0x01, 0x00, + 0x05, 0x00, 0x00, 0x05, 0x01, 0xdd, 0xd1, 0x9d, + 0xe1, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xf0, 0x09, + 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x0d, 0x00, + 0x00, 0x05, 0x01, 0xdd, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xdd, 0xe9, 0xb6, 0x9e, 0x25, 0x01, 0x00, + 0x0e, 0x43, 0x02, 0x03, 0xf2, 0x09, 0x01, 0x00, + 0x01, 0x05, 0x02, 0x00, 0x14, 0x00, 0x00, 0x0b, + 0x01, 0x00, 0x05, 0x01, 0xdd, 0xee, 0xd5, 0xde, + 0x42, 0x69, 0x01, 0x00, 0x00, 0xb5, 0xde, 0xe9, + 0xb6, 0x9e, 0x24, 0x02, 0x00, 0xe2, 0xd1, 0x28, + 0x0e, 0x43, 0x02, 0x03, 0xf4, 0x09, 0x00, 0x00, + 0x00, 0x03, 0x06, 0x00, 0x49, 0x00, 0xf6, 0x09, + 0x04, 0x01, 0xee, 0x09, 0x0a, 0x01, 0xf8, 0x09, + 0x00, 0x01, 0x92, 0x08, 0x03, 0x01, 0xfa, 0x09, + 0x00, 0x03, 0xf2, 0x09, 0x0c, 0x01, 0x04, 0x0d, + 0x01, 0x00, 0x00, 0xe1, 0xde, 0x04, 0xea, 0x01, + 0x00, 0x00, 0xef, 0x0e, 0xdf, 0x8f, 0xe3, 0xdf, + 0xe0, 0xb6, 0x9e, 0xa3, 0xea, 0x31, 0x5e, 0x04, + 0x00, 0xdf, 0x47, 0x04, 0x80, 0x00, 0x00, 0x00, + 0xa9, 0xea, 0x1f, 0x5e, 0x04, 0x00, 0xdf, 0xb6, + 0x9d, 0x47, 0x04, 0xea, 0x01, 0x00, 0x00, 0xa9, + 0xea, 0x10, 0xdf, 0xb7, 0x9d, 0xe3, 0x5e, 0x05, + 0x00, 0x04, 0xea, 0x01, 0x00, 0x00, 0xef, 0x0e, + 0x29, 0xdf, 0x8f, 0xe3, 0xec, 0xca, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xfc, 0x09, 0x00, 0x00, 0x00, + 0x02, 0x04, 0x00, 0x1f, 0x00, 0xf6, 0x09, 0x04, + 0x01, 0xf8, 0x09, 0x00, 0x01, 0x92, 0x08, 0x03, + 0x01, 0xfa, 0x09, 0x00, 0x03, 0x04, 0x0d, 0x01, + 0x00, 0x00, 0xe1, 0xde, 0x8f, 0xe2, 0xde, 0xdf, + 0xa3, 0xea, 0x11, 0xe0, 0xde, 0x47, 0x04, 0x21, + 0x01, 0x00, 0x00, 0xa9, 0xeb, 0x06, 0xde, 0x8f, + 0xe2, 0xec, 0xec, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xfe, 0x09, 0x01, 0x00, 0x01, 0x03, 0x07, 0x00, + 0x4c, 0x00, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x01, 0x04, + 0x4b, 0x00, 0x00, 0x00, 0xe1, 0xde, 0xd1, 0xef, + 0x0e, 0xdf, 0xe0, 0xa3, 0xea, 0x3d, 0x5e, 0x05, + 0x00, 0xdf, 0x91, 0xe3, 0x47, 0x60, 0x04, 0x00, + 0x04, 0x21, 0x01, 0x00, 0x00, 0xa9, 0xea, 0x09, + 0x04, 0x12, 0x01, 0x00, 0x00, 0xe1, 0xec, 0xe2, + 0x5e, 0x04, 0x00, 0x04, 0x22, 0x02, 0x00, 0x00, + 0xa9, 0xea, 0x0b, 0xdf, 0xe0, 0xa6, 0xeb, 0x13, + 0xdf, 0x8f, 0xe3, 0xec, 0xcd, 0x5e, 0x04, 0x00, + 0xd1, 0xa9, 0xea, 0xc6, 0x5e, 0x06, 0x00, 0xee, + 0x0e, 0x29, 0x29, 0x0e, 0x43, 0x02, 0x03, 0x80, + 0x0a, 0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0xc4, + 0x01, 0x00, 0xf6, 0x09, 0x04, 0x01, 0xee, 0x09, + 0x0a, 0x01, 0xf8, 0x09, 0x00, 0x01, 0x92, 0x08, + 0x03, 0x01, 0xd8, 0x06, 0x01, 0x01, 0xfa, 0x09, + 0x00, 0x03, 0xf0, 0x09, 0x0b, 0x01, 0xf2, 0x09, + 0x0c, 0x01, 0xb8, 0x05, 0x00, 0x00, 0x04, 0x0e, + 0x01, 0x00, 0x00, 0xe1, 0xde, 0x04, 0xea, 0x01, + 0x00, 0x00, 0xef, 0x0e, 0xdf, 0xe0, 0xa3, 0x69, + 0xb1, 0x00, 0x00, 0x00, 0x5e, 0x05, 0x00, 0xdf, + 0x91, 0xe3, 0x47, 0x60, 0x04, 0x00, 0x04, 0x21, + 0x01, 0x00, 0x00, 0xa9, 0xea, 0x09, 0x04, 0x12, + 0x01, 0x00, 0x00, 0xe1, 0xec, 0xdf, 0x5e, 0x04, + 0x00, 0x04, 0x22, 0x02, 0x00, 0x00, 0xa9, 0xea, + 0x0b, 0xdf, 0xe0, 0xa3, 0xea, 0xcf, 0xdf, 0x8f, + 0xe3, 0xec, 0xca, 0x5e, 0x06, 0x00, 0xee, 0x04, + 0xfd, 0x01, 0x00, 0x00, 0xa9, 0xea, 0x13, 0x5e, + 0x04, 0x00, 0x04, 0xe8, 0x01, 0x00, 0x00, 0xa9, + 0xea, 0xb3, 0x5e, 0x07, 0x00, 0xee, 0x0e, 0xec, + 0xac, 0x5e, 0x04, 0x00, 0x04, 0xfd, 0x01, 0x00, + 0x00, 0xa9, 0xea, 0x2e, 0xde, 0x04, 0xfd, 0x01, + 0x00, 0x00, 0xef, 0x0e, 0x5e, 0x05, 0x00, 0xdf, + 0x47, 0x04, 0xfd, 0x01, 0x00, 0x00, 0xa9, 0x11, + 0xeb, 0x0d, 0x0e, 0x5e, 0x05, 0x00, 0xdf, 0x47, + 0x04, 0xe8, 0x01, 0x00, 0x00, 0xa9, 0x69, 0x7d, + 0xff, 0xff, 0xff, 0xdf, 0x8f, 0xe3, 0xed, 0x75, + 0xff, 0x5e, 0x04, 0x00, 0x04, 0xea, 0x01, 0x00, + 0x00, 0xa9, 0x69, 0x69, 0xff, 0xff, 0xff, 0x5e, + 0x07, 0x00, 0xee, 0x0e, 0xdf, 0xe0, 0xa3, 0xea, + 0x11, 0x5e, 0x08, 0x00, 0x5e, 0x05, 0x00, 0xdf, + 0x47, 0xef, 0xea, 0x06, 0xdf, 0x8f, 0xe3, 0xec, + 0xec, 0x29, 0x0e, 0x43, 0x02, 0x03, 0x82, 0x0a, + 0x00, 0x00, 0x00, 0x03, 0x05, 0x00, 0x41, 0x00, + 0xf6, 0x09, 0x04, 0x01, 0xf8, 0x09, 0x00, 0x01, + 0x92, 0x08, 0x03, 0x01, 0xb8, 0x05, 0x00, 0x00, + 0xfa, 0x09, 0x00, 0x03, 0x04, 0x49, 0x00, 0x00, + 0x00, 0xe1, 0xde, 0xdf, 0xa3, 0xea, 0x36, 0xe0, + 0x5e, 0x04, 0x00, 0xde, 0x47, 0xef, 0x11, 0xeb, + 0x25, 0x0e, 0x5e, 0x04, 0x00, 0xde, 0x47, 0x04, + 0xe5, 0x01, 0x00, 0x00, 0xa9, 0xea, 0x1e, 0xde, + 0xdf, 0xb6, 0x9e, 0xa9, 0x11, 0xeb, 0x0f, 0x0e, + 0x5e, 0x04, 0x00, 0xde, 0xb6, 0x9d, 0x47, 0x04, + 0xe5, 0x01, 0x00, 0x00, 0xaa, 0xea, 0x06, 0xde, + 0x8f, 0xe2, 0xec, 0xc7, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0x84, 0x0a, 0x00, 0x02, 0x00, 0x05, 0x0a, + 0x00, 0xb3, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x02, 0x01, 0x00, 0x12, + 0x01, 0x00, 0x04, 0x01, 0x00, 0x13, 0x01, 0x00, + 0x14, 0x01, 0xb6, 0xe1, 0xde, 0xdf, 0xa3, 0xea, + 0x0f, 0xe0, 0x5e, 0x04, 0x00, 0xde, 0x47, 0xef, + 0xea, 0x06, 0xde, 0x8f, 0xe2, 0xec, 0xee, 0x04, + 0x68, 0x02, 0x00, 0x00, 0x5e, 0x04, 0x00, 0x42, + 0x69, 0x01, 0x00, 0x00, 0x5e, 0x05, 0x00, 0xde, + 0x24, 0x02, 0x00, 0x9d, 0x04, 0x68, 0x02, 0x00, + 0x00, 0x9d, 0xc9, 0x5e, 0x06, 0x00, 0x42, 0xe4, + 0x01, 0x00, 0x00, 0xc5, 0x24, 0x01, 0x00, 0xb5, + 0xa6, 0xea, 0x1c, 0x04, 0x0f, 0x01, 0x00, 0x00, + 0x5f, 0x07, 0x00, 0x5e, 0x08, 0x00, 0x42, 0xe4, + 0x01, 0x00, 0x00, 0xc5, 0x24, 0x01, 0x00, 0xb5, + 0xa6, 0xea, 0x03, 0xb5, 0xe1, 0x29, 0xde, 0xca, + 0xc6, 0xdf, 0xa3, 0xea, 0x12, 0x5e, 0x04, 0x00, + 0xc6, 0x47, 0x04, 0xf9, 0x01, 0x00, 0x00, 0xa9, + 0xea, 0x05, 0x93, 0x01, 0xec, 0xeb, 0xc6, 0xdf, + 0xa3, 0xea, 0x17, 0x5e, 0x04, 0x00, 0xc6, 0x47, + 0x04, 0xf3, 0x01, 0x00, 0x00, 0xa9, 0xea, 0x0a, + 0x04, 0x1b, 0x00, 0x00, 0x00, 0x5f, 0x07, 0x00, + 0x29, 0x5e, 0x09, 0x00, 0x42, 0xe4, 0x01, 0x00, + 0x00, 0xc5, 0x24, 0x01, 0x00, 0xb5, 0xa6, 0xea, + 0x0a, 0x04, 0x10, 0x01, 0x00, 0x00, 0x5f, 0x07, + 0x00, 0x29, 0x04, 0x11, 0x01, 0x00, 0x00, 0x5f, + 0x07, 0x00, 0xb5, 0xe1, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0x86, 0x0a, 0x02, 0x00, 0x02, 0x03, 0x02, + 0x00, 0x2b, 0x00, 0x00, 0x09, 0x01, 0x00, 0x04, + 0x01, 0xdd, 0xe9, 0xd1, 0xa3, 0xea, 0x12, 0xdd, + 0x42, 0x87, 0x01, 0x00, 0x00, 0x04, 0x16, 0x00, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xec, 0xea, + 0xdd, 0xe9, 0xd2, 0xa3, 0xea, 0x0e, 0xdd, 0x42, + 0x87, 0x01, 0x00, 0x00, 0xde, 0x24, 0x01, 0x00, + 0x0e, 0xec, 0xee, 0x29, +}; + diff --git a/run-test262.c b/run-test262.c index c860dbbcc..2092cacaf 100644 --- a/run-test262.c +++ b/run-test262.c @@ -1,8 +1,8 @@ /* * ECMA Test 262 Runner for QuickJS * - * Copyright (c) 2017-2020 Fabrice Bellard - * Copyright (c) 2017-2020 Charlie Gordon + * Copyright (c) 2017-2021 Fabrice Bellard + * Copyright (c) 2017-2021 Charlie Gordon * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/storage/doc/README.md b/storage/doc/README.md new file mode 100644 index 000000000..5c743d263 --- /dev/null +++ b/storage/doc/README.md @@ -0,0 +1,15 @@ +# module storage + +This module provides built-in data persistence - transparent data storage and retrieval using just JavaScript means. + +[Introduction](introduction.md) and usage manual. + +[Architecture](architecture.md) explained. + +Documentation: + + * class [Storage](Storage.md); + * class [Storage.Index](Storage.Index.md); + + + diff --git a/storage/doc/Storage.Index.md b/storage/doc/Storage.Index.md new file mode 100644 index 000000000..c80f7b7ae --- /dev/null +++ b/storage/doc/Storage.Index.md @@ -0,0 +1,50 @@ +# Index class + +Index object in persistent storage. + +## Properties + +* ```index.length``` - integer, read-only, length of an index, number of objects associated represented by the index. +* ```index.unique``` - boolean, read-only, true if the index was declared as unique. +* ```index.type``` - string, read-only, key type as it was declared at creation time. Read-only property. + +## Enumeration + +Indexes support ```for(of)``` enumeration style: + +```JavaScript: +// log all objects in the index +for( var obj in index ) + console.log(obj); +``` + + +## Methods + +* ```index.set( key, obj [, replace: true|false ] ) : true|false``` + + Inserts *obj* object into the index and associates it with the *key* value. Optionally, in-case of non-unique index, replaces it with existing object if such key is already present in the index. + +* ```index.get( key ) returns: object | [objects...]``` + + Returns object at the *key* position or null. *key* has to be of the same type as the type of the index object. If the index was created as non unique then the return value is an array - list of items under the key. + +* ```index.delete( key [,obj] ) returns: true | false``` + + Method removes object *obj* by key from the index. Method returns true on success, otherwise false. If the index is unique, obj is optional. + +* ```index.select( minKey, maxKey [, ascending [, startInclusive [, endInclusive]]] ) returns: Iterator.``` + + Returns selection in the Index based on criteria min-key, max-key, ascent or descent order, start-inclusive, end-inclusive. Default values: ```ascending:true```, ```startInclusive:true``` and ```endInclusive:true```. + + The method is intendeded to be used in ```for(of)``` enumerations: + + ```JavaScript: + for( var obj in index.select(minVal, maxVal) ) { ... } + ``` + + Either minKey or maxKey can be *null* that means search from very first or very last key in the index. + +* ```index.clear()``` + + Removes all items from the index object - makes it empty. \ No newline at end of file diff --git a/storage/doc/Storage.md b/storage/doc/Storage.md new file mode 100644 index 000000000..fc41a1d97 --- /dev/null +++ b/storage/doc/Storage.md @@ -0,0 +1,27 @@ + +# Storage class + +Represents persistent storage. + +## Properties + +* ```root``` - object, root object in the storage. Read/write property. + +## Methods + + +* ```Storage.open(filename : string [,allowWrite: true] ) : storage | null``` + + Static method. Opens the storage and returns an instance of Storage object. If *allowWrite* is *false* then storage is opened in read-only mode. + +* ```storage.close()``` + + Closes underlying Storage object. Commits all data before cloasing. After closing the storage all persistent objects that are still in use are set to non-persistent state. + +* ```storage.commit()``` + + Commits (writes) all persistent objects reachable from its root into storage. + +* ```storage.createIndex(type : string [, unique: bool]) returns: Index | null``` + + Creates an index of given type and returns the index object. Index can have unique or duplicated keys depending on unique argument. Default value for *unique* is *true*. Supported types: "integer", "long", "float", "date" and "string". diff --git a/storage/doc/architecture.md b/storage/doc/architecture.md new file mode 100644 index 000000000..06a3a0133 --- /dev/null +++ b/storage/doc/architecture.md @@ -0,0 +1,75 @@ +# Architecture of Storage Module + +The module uses modified [DyBase Engine of Konstantin Knizhnik](http://www.garret.ru/dybase.html) and +minimal changes in QuickJS core to support persistence in JS. + +With enabled CONFIG_STORAGE flag existing ```struct JSObject``` gets additional pointer field: + +```C +struct JSObject { + ... + JSPersistentBlock* persistent; +}; +``` + +Where JSPersistentBlock defines storage wireing fields. This makes any JS object to be persistable. For now only pure Objects and Arrays are persistable. + + +Each persistent JS object and array can be in one of four states: + +* ```JS_NOT_PERSISTENT``` - not persistent at the moment +* ```JS_PERSISTENT_DORMANT``` - object is persistent but is "dormant", it holds just a reference - item ID in terms of DyBase (dybase_oid_t). Object in this state has no properties or elements loaded into it - it is a {proxy-ref}erence. +* ```JS_PERSISTENT_LOADED``` - the object has its properties and data loaded from DB; +* ```JS_PERSISTENT_MODIFIED``` - the object is loaded from DB and is modified by script - ready to be commited to DB. + +## Data life cycle – how persistent mechanism works + +Script runtime provides root object when we open existing storage: + +```JavaScript +var storage = Storage.open("path/to/data/file.db"); +var root = storage.root; // root data object +``` + +Main idea is that the root object will be loaded in half-baked way – all sub-collections in that object will have just persistent proxies instead – things that represent references to corresponding data items in DB: + +![Storage schema](images/storage-schema.png) + +So immediately after loading root object will look as: + +``` +storage.root -> { + version: 1, + parent: /*proxy-ref*/ + children: /*proxy-ref*/ +} +``` + +Those special proxy-references are internal entities – not discoverable by the script. + +Instead, when we will need to access those sub-objects, script runtime will fetch them from DB transparently for script code. So when we will need to get some property of sub-object like this: + +```JavaScript +console.log(root.parent.name); +``` + +the runtime will fetch needed object from the DB into VM’s heap (memory) and the root will look like this: + +``` +storage.root -> { + version: 1, + parent: { name: "John the Magnificent", nickname: "Smith" }, + children: /*array-proxy-ref - not accessed yet*/ +} +``` + +Therefore to get data from the DB we will just need to access elements of collections in DB by standard script means – using obj.prop property accessor or array[index] accessors. + +But what will happen with large DB and our code that may walk through all collections inside it? Will whole database be loaded into the heap as a result of visiting all persistent entities? + +The answer is “no”. At some point, when runtime will detect that heap is full, garbage collection will be triggered and all persistent entities will be replaced by their proxies. This will free heap from directly unreferenced persistent data. If any of such data contains changes they will be committed (saved) to the database before their removal from the heap. + +Therefore data commits (saving data to physical storage) are managed by script runtime automatically: at GC time and when storage gets closed. Script cannot prevent GC to happen nor it cannot force actual GC so data will be auto-commited. But if needed (e.g. after critical data changes), we can call synchronous ```storage.commit()``` method to force changed data to be saved at particular moment of time. + +Such mechanism allows script to handle potentially large data sets: maximum number of persistent entities is 2^32 and each persistent item can be a string or a byte array (a.k.a. blob, ArrayBuffer) of size 2^32 bytes. + diff --git a/storage/doc/images/storage-schema.png b/storage/doc/images/storage-schema.png new file mode 100644 index 000000000..df31b1a88 Binary files /dev/null and b/storage/doc/images/storage-schema.png differ diff --git a/storage/doc/introduction.md b/storage/doc/introduction.md new file mode 100644 index 000000000..30f6d7a14 --- /dev/null +++ b/storage/doc/introduction.md @@ -0,0 +1,230 @@ +## Introduction + +This module provides built-in data persistence - data storage and retrieval. + +“Built-in” here means that there is no special entity like Database Access Client or Database Driver in the language to access persistent data – it is rather that objects in storage (database file) are ordinary script entities: objects (key/value maps), arrays (lists of values), and primitive types (string, integer, long (a.k.a. BigInt), float, date, byte-vectors (ArrayBuffer), boolean and null). + +You can think of QuickJS+persistence as a script with built-in NoSQL database mechanism where access to data in DB is provided by standard language means: get/set properties of stored objects or get/set elements of stored arrays and indexes. + +To support persistence this module introduces two helper classes: Storage and Index. + +## Storage + +Storage object represents database file in script. It is used as to create databases as to open existing databases to get access to data stored in them. + +To create or open existing database you will use ```Storage.open(path)``` method. On success this method returns instance of Storage class that has few properties and methods, the most interesting of them is ```storage.root``` property: + +### ```storage.root``` + +```storage.root``` property is a reference to stored root object (or array). + +> **All objects accessible from (contained in) the ```storage.root``` object are automatically persistent – stored in the DB.** + +As simple as that. ```storage.root``` is ordinary script object that can be used by standard script means to access and/or modify data in storage. + +When you will make any change in any object or collection under that root object it will be stored to the database (a.k.a. persisted) without need to send that data anywhere or call any method explicitly. + +#### Example #1, storage opening and its structure initialization: + +Idiomatic code to open or create database looks like this: + +```JavaScript +import * as Storage from "storage"; // or "@storage" if Sciter.JS + +var storage = Storage.open("path/to/data/file.db"); +var root = storage.root || initDb(storage); // get root data object or initialize DB +``` + +where ```initDb(storage)``` is called only when storage was just created and so is empty – its root is null in this case. That function may look like as: + +```JavaScript +function initDb(storage) { + storage.root = { + version: 1, // integer property ("integer field" in DB terms) + meta: {}, // sub-object + children: [] // sub-array, empty initially + }; + return storage.root; +} +``` + + +#### Example #2, accessing and populating persistent data: + +Having the ```root``` variable containing persistent root object, we can access and populate the data in it as we normally do – no other special mechanism is required: + +```JavaScript +// printout elements of root.children collection (array) + + let root = storage.root; + for( let child of root.children ) + console.log(child.name, child.nickname); +} +``` + +In the same way, to populate the data in storage we use standard JavaScript means: + +```JavaScript +var collection = root.children; // plain JS array + collection.push( { name: "Mikky", age: 7 } ); // calling Array's method push() to add + collection.push( { name: "Olly", age: 6 } ); // objects to the collection + collection.push( { name: "Linus", age: 5 } ); +} +``` + +Nothing special as you see – the code is not anyhow different from ordinary script code accessing and populating any data in script heap. + +## Index + +By default JavaScript supports collections of these built-in types: + +* objects – unordered name/value maps and +* arrays – ordered lists of values with access by index (some integer). +* auxiliary collections - [Weak]Map and [Weak]Set. + +These collections allow to organize data in various ways but sometimes these are not enough. We may need something in between of them – collections that are a) ordered but b) allow to access elements by keys at the same time. Example: we may need collection of objects that is ordered by their time of creation so we can present the collection to the user in data “freshness” order. + +To support such use cases the module introduces Index objects. + +> **Index is a keyed persistent collection that can be assigned to properties of other persistent objects or placed into arrays. Indexes provide effective access and ordering of potentially large data sets.** + +Indexes support string, integer, long (BigInt), float and date keys and contain objects as index elements (a.k.a. records). + +### Defining and populating indexes + +Indexes are created by ```storage.createIndex(type[,unique]) : Index``` method, where + +* *type* defines type of keys in the index. It can be "string", "integer", "long", "float" or "date". +* *unique* is either + * *true* if the index support only unique keys, or + * *false* if records with the same key values are allowed in the index. + +#### Example #3: creating indexes, simple storage of notes: + +To open storage database we can reuse code above, but storage initialization routine will look different this time: + +```JavaScript +function initNotesDb(storage) { + storage.root = { + version: 1, + notesByDate: storage.createIndex("date",false), // list of notes indexed by date of creation + notesById: storage.createIndex("string",true) // list of notes indexed by their UID + } + return storage.root; +} +``` + +As you see the storage contains two indexes: one will list notes by their date of creation and other will contain the same notes but ordered by unique ID. + +Having such setup, adding notes to DB is trivial: + +```JavaScript +function addNote(storage, noteText) { + var note = { + id : UUID.create(), // generate UID + date : new Date(), + text : noteText + }; + storage.root.notesByDate.set(note.date, note); // adding the note + storage.root.notesById.set(note.id, note); // to indexes + return note; // returns constructed note object to the caller +} +``` + +We use here ```index.set(key,value)``` method to add items. + +### Index selection – traversal and retrieval of index items + +Getting elements of unique indexes is trivial – we use ```index.get(key)``` method similar to methods of standard Map or Set collections: + +```JavaScript +function getNoteById(noteId) { + return storage.root.notesById.get(noteId); // returns the note or undefined +} +``` + +To get items from non-unique indexes we need pair of keys to get items in range between keys by using ```index.select()``` method: + +```JavaScript +function getTodayNotes() { + let now = new Date(); + let yesterday = new Date(now.year,now.month,now.day-1); + var notes = []; + for(let note of storage.root.select(yesterday,now)) // get range of notes from the index + notes.push(note); + return notes; +} +``` + +## Persistence of objects of custom classes + +So far we were dealing with plain objects and arrays, but the Storage allows to store objects of custom classes too. This can be useful if your data objects have specific methods. Let’s refactor our notes storage to use it in OOP way: + + +```JavaScript +// module NotesDB.js + +import * as Storage from "storage"; // or "@storage" if Sciter.JS + +const storage = ... open DB and optionally initialize the DB ... + +class Note { + + constructor(text, date = undefined, id = undefined) { + this.id = id || UUID.create(); + this.date = date || new Date(); + this.text = text; + + // adding it to storage + let root = storage.root; + root.notesByDate.set(this.date, this); + root.notesById.set(this.id, this); + } + + remove() { + let root = storage.root; + root.notesByDate.delete(this.date, this); // need 'this' here as index is not unique + root.notesById.delete(this.id); + } + + static getById(id) { + return storage.root.notesById.get(id); // will fetch object from DB and do + // Object.setPrototypeOf(note,Note.prototype) + } +} +``` + +Technical details: while storing objects of customs classes, the Storage will store just name of object’s class. Database cannot contain neither classes themselves nor any functions – just pure data. On loading objects of custom classes, the runtime will try to bind classes from current scopes with instances of objects by updating prototype field of such objects. + +## As an afterword + +[Sciter Notes](https://notes.sciter.com/) application is a practical example of Storage use. + +That particular application uses Sciter/TIScript but principles are the same. You can see it’s [database handling routines on GitHub](https://github.com/c-smile/sciter-sdk/tree/master/notes/res/db), in particular its DB initialization may look in JS as: + +```JavaScript +//| +//| open database and initialze it if needed +//| + +function openDatabase(pathname) +{ + //const DBNAME = "sciter-notes.db"; + //const pathname = dbPathFromArgs() || ...; + var ndb = Storage.open(pathname); + if(!ndb.root) { + // new db, initialize structure + ndb.root = + { + id2item :ndb.createIndex("string", true), // main index, item.id -> item, unique + date2item :ndb.createIndex("date", false), // item by date of creation index, item.cdate -> item, not unique + tags :{}, // map of tagid -> tag + books :{}, // map of bookid -> book; + version :1, + }; + } + ndb.path = pathname; + return ndb; +} +``` + diff --git a/storage/dybase/CHANGES b/storage/dybase/CHANGES new file mode 100644 index 000000000..e0af8df4f --- /dev/null +++ b/storage/dybase/CHANGES @@ -0,0 +1,77 @@ +\--- Release version 0.01 20.03.2003 ------------------------------------- +Initial release + +--- Release version 0.02 24.03.2003 ------------------------------------- +1. Add Index.set method which replace object in case of existed key +2. Fix memory leak in Ruby API +3. Add setup.py module to Python API +4. Fix bug in PHP API + +--- Release version 0.03 27.03.2003 ------------------------------------- +1. Clear OID attribute in Persistent.deallcoate method (to make it possible to call +deallocate method multiple times) +2. Fix bugs in PHP API +3. Correct declaration of storage_insertinindex function in Ruby API + +--- Release version 0.04 04.04.2003 ------------------------------------- +1. Add optional garbage collection +2. Fix bug in class descriptors caching which cause creation of class descriptor for each instance of the object. + +--- Release version 0.05 08.04.2003 ------------------------------------- +1. Add multithreaded support at language API level +2. Add methods for objects shared and exclusive locking + +--- Release version 0.06 18.04.2003 ------------------------------------- +1. Add Persistent.modify method +2. Add index iterator +3. Fix bug with recursive mutex locking in B-Tree + +--- Release version 0.07 22.04.2003 ------------------------------------- +1. Implement more sophisticated iterators for index search + +--- Release version 0.08 25.04.2003 ------------------------------------- +1. Add makefile for MinGW environment +2. Fix the problem with LONG_LONG in python API + +--- Release version 0.09 28.05.2003 ------------------------------------- +1. Use delegators in Ruby API + +--- Release version 0.10 29.05.2003 ------------------------------------- +1. Use delegators in Python API + +--- Release version 0.11 15.07.2003 ------------------------------------- +1. Fix bug with maintaining modifiedList in DyBASE and Ruby APIs. + +--- Release version 0.12 23.07.2003 ------------------------------------- +1. Fix bug in B-Tree index iterator (handling case of empty tree) + +--- Release version 0.13 19.11.2003 ------------------------------------- +1. Add support of map type. In PHP Api all arrays are now stored as maps, +so new version will be incompatible with databases created by previous versions. + +--- Release version 0.14 14.12.2003 ------------------------------------- +1. Fix critical bug in object index relocation algorithm +2. Fix bugs in index iterator +3. Beta version of Rebol API + +--- Release version 0.15 19.12.2003 ------------------------------------- +1. Optimized version of Rebol API + +--- Release version 0.16 21.12.2003 ------------------------------------- +1. New version of Rebol API +2. Fix bug in PHP API +3. Update comparison results + +--- Release version 0.17 21.12.2003 ------------------------------------- +1. New implementation of object cache in Rebol API +2. Fix bug in storage close method in Rebol API + +--- Release version 0.18 28.12.2003 ------------------------------------- +1. New implementation of fetching objects in Rebol API. Now it is not necessary to +specify prototype object. + +--- Release version 0.19 26.03.2004 ------------------------------------- +1. Fix bug in testlink.php +2. Change rule of creating object delegators in Python API to me able to automatically +handle object modification in all cases. +3. Fix bug in B-Tree search method with open boundaries and remove from empty tree. \ No newline at end of file diff --git a/storage/dybase/doc/dybase.html b/storage/dybase/doc/dybase.html new file mode 100644 index 000000000..6093fbcb1 --- /dev/null +++ b/storage/dybase/doc/dybase.html @@ -0,0 +1,1484 @@ + + +DyBASE - Object Oriented Database for languages with Dynamic Type Checking + + + + +
+

Introduction

+ +DyBASE is very simple object oriented embedded database for languages with dynamic type checking. In a dynamic type checking language the type of a class instance variable is not known at compile time. +Moreover the same instance variable can be used to store integers and string and later be assigned reference +to some other object. So it means that database could not keep information about object format in +class descriptor and should store type for each instance variable. DyBASE provides APIs to the most popular scripting languages +with OO extensions: PHP, Ruby, Python and Rebol.

+ +DyBASE is easy to use and provide high performance. It is intended to be used in applications which needs to deal with persistent +data in more sophisticated way than load/store object tree provided by standard serialization mechanism. +Although DyBASE is very simple, it provides fault tolerant support (ACID transactions) +and concurrent access to the database.

+ +The main advantage of DyBASE is tight integration with programming language. +There is no gap between database and application data models - DyBASE directly stores language objects. +So there is no need in packing/unpacking code, which has to be written for traditional relational databases. +Also DyBASE (unlike many other OODBMS) requires no special compiler or preprocessor. And still it is able to +provide a high level of transparency.

+ +

Features

+Lets now describe key features of DyBASE architecture. + +

Persistency by reachability

+ +DyBASE is implementing persistency by reachability approach. Object of any class derived from +Persistent base class is considered as persistent capable. It is automatically made +persistent and stored in the storage when it is referenced from some other persistent object and +store method of that object was invoked. So there is no need (but it is possible) to explicitly +assign object to the storage.

+ + + +The storage has one special root object. Root object is the only persistent object accessed in the special +way (using getRootObject method). All other persistent objects are accessed in normal way: +either by traversing by references from another persistent objects or using indices. +Unlike many other OODBMS, there can be only one root in the storage. If you need to have several named roots, +you should create Index object and use it as root object.

+ +Which classes are persistent capable depends on the particular language API. +In most of them they must be derived it from Persistent class. +This makes impossible to store "foreign" classes in the storage. This is the cost of easy use of DyBASE and lack of any specialized preprocessors or compilers. In Python it is possible to make persistent arbitrary class, +but it is still more convenient to derive it from Persistent.

+ +DyBASE supports the following basic types:

+ + + + + + + + + +
TypeDescriptionSizeRelated C++ type
Booleanboolean type1bool
Integer32-bit integer type4int
Long integer64-bit integer type8long long
Real64-bit floating point type8double
StringString with counterNchar*
ArrayOne dimensional array with components of any of the described type--

+ + +Unfortunately it is not possible to detect if object is changed or not without saving old state of the object and performing field-by-field comparison with new state of the object. But overhead of such solution (both space and CPU) is very high. In DyBASE it is responsibility of programmer to save object in the storage. It can be done by Persistent.store or Persistent.modify methods.

+ +Persistent.store method writes object in the storage as well +as all objects referenced from this object which are not yet persistent. So if you create a tree of objects and assign reference to the root of this tree to some persistent object X, it is only necessary to +invoke store() method in this object X. But then if you update one of the elements in this tree, +you should invoke store() individually for each such element (X.store() will +NOT now automatically save referenced objects).

+ +Persistent.modify method mark object is modified but doesn't immediately write it to the storage. +All objects marked as modified will be stored to the storage during transaction commit (store method +will be invoked for each modified object). So using modify method is preferable if object +is updated multiple times within transaction. In this case instead of storing it several times, it will +be stored only once at the end.

+ + +

Semitransparent object loading

+ +DyBASE is not using any special compiler or preprocessor. And only very few languages provide runtime behavior reflection (changing behavior of object at runtime), it is not possible to implement completely +transparent persistence (when there are no differences between access to transient and persistent objects). Instead DyBASE supports transparent behavior in most cases with some exceptions.

+ +When object is loaded from the storage, DyBASE will also try to recursively load all objects referenced +from this object. So as a result all cluster of referenced object will be loaded, references between then will +be correctly set and so programmer can access these object and traverse from one object to another +without explicit checks whether object is loaded or not.

+ +What is bad with this approach? If all objects in the storage are accessible from the rot by references (no indices are used), +then loading root object will cause loading of all objects from the database to the memory. +If the number of object is very large, it can take a significant amount of time and cause exhaustion of memory in application. +In DyBASE it is possible to stop recursive loading for particular objects. +This is done either by redefinition of recursiveLoading method and returning false, +either (in Python API) by setting __nonrecursive__ attribute). Objects referenced from the objects +with disables recursive loading should be explicitly loaded using Persistent.load method. +Before object is loaded, you should not access any of its components.

+ +Also it is important to notice that indices always load member objects on demand +(i.e. Dybase does not perform automatic loading of all objects in the containers). Since access to the container members is always +performed through methods of the container class, programmer will never notice it - container methods will always +return loaded object(s).

+ +Sometimes not all fields of persistent object need to be saved in the storage. Some of them are +transient. DyBASE use the following convention to distinguish persistent and transient fields: +all fields which name ends with "_" are considered to be transient and are not saved in the storage. +You can initialize such fields when object is loaded from the storage in onLoad() method +which is invoked for any persistent object after loading it from the storage (i.e. after restoring values of all persistent +fields).

+ +So summarizing all above, proposed mechanism is convenient and easy to use because it doesn't require programmer +to explicitly load any referenced object and from another point of view it is flexible above by providing programmer control +on object loading. Only those classes (usually containers) which explicitly control loading of their +members (by overloading recursiveLoading to return false value) should be aware +calling Persistent.load method.

+ + +

Delegators

+Some programming languages are providing delegation mechanism: possibility to redirect method +to other object. Such mechanism can be used to build convenient object database API. +Instead of recursive loading of all objects cluster we can create delegators which will +load objects on demand. No explicit invocations of load method and +overloading recursiveLoading to stop recursion are needed.

+ +Unfortunately it is still not possible to detect modification of the object. +Although some languages make it possible to redefine object attribute setter method, +it will not help to detect modification of self components inside instance method. +So explicit invocation of modify or store methods is needed.

+ +Although delegator mechanism provides more convenient and transparent API, it has its own drawbacks: +

    +
  1. It is not possible to check object class: it will return class of delegator and not +class of target object itself +
  2. As delegator and target objects are two different objects, comparison of objects +references should be done with special care. +
  3. Delegators adds extra space and processor overhead: instead of one object we have two and +each method invocation of field access requires extra delegator method call. +

+This is why by default delegators support is switch off in all APIs.

+ + +

Indices

+ +Usually objects are accessed by traversing from one object to another using references or links. +But it is frequently needed to locate object by key. Almost all languages provides classes like hashtable or associative array. +In databases usually more sophisticated search is required. +I do not want to implement in DyBASE complete SQL language, because it immediately makes DBMS huge and slow. +But, in most cases, an application is performing only very simple queries using exact match or key range. +This is done in DyBASE by Index class which make it possible to associate persistent object with +key of any supported scalar or string type.

+ +Indices are created in DyBASE using Storage.createXXXIndex method, +where XXX specifies type of the key. You can place in the index only keys with the same type as specified +at index creation time (so it is not possible to create index of strings and place integer key in it). +Index is implemented using B+Tree algorithm, because B+Tree is the most efficient structure +for disk based databases. Methods of Index class allows to add, remove and +locate objects by key. It is possible to perform search either specifying exact key value either specifying range of key values +(high or low boundary or both of them can be skipped or can be declared as been exclusive or inclusive). +So it is possible to perform the following types of search:

+ +

    +
  1. key is equals to VAL +
  2. key belongs to [MIN_VAL, MAX_VAL] +
  3. key belongs to [MIN_VAL, MAX_VAL) +
  4. key belongs to (MIN_VAL, MAX_VAL] +
  5. key belongs to (MIN_VAL, MAX_VAL) +
  6. key is greater than MIN_VAL +
  7. key is greater or equals to MIN_VAL +
  8. key is less than than MAX_VAL +
  9. key is less than or equals to MAX_VAL +

+ +

Transaction model

+ +DyBASE preserve consistency of the data in case of system or application failure. +Transaction mechanism is used to implement all-or-nothing database update. +Transaction in DyBASE are started implicitly when update operation is first time performed +and finished explicitly by commit, rollback or close methods.

+ +Commit of transaction cause synchronous write of changed pages to the disk. +Synchronous write (application is blocked until data is really flushed to the disk) is very expensive operation. +Average positioning time for modern disks is about 10ms, so them are usually not able to perform in one second +more than 100 writes in random places. As far as transaction usually consists of several updated pages, +it leads to average performance about 10 transaction commits per second.

+ +Performance can be greatly increased if you minimize number of commits (larger transactions). +DyBASE is using shadow mechanism for transaction implementation. When object is changed first time +during transaction, shadow of the object is created and original object is kept unchanged. If +object is updated multiple times during transaction, shadow is create only once. +Because of using shadows, DyBASE does not need a transaction log file. So in DyBASE +long transaction can not cause transaction log overflow as in most of other DBMSes. +Quite the contrary, if you do not call commit at all, DyBASE works as DBMS without transaction +support, adding almost no overhead of supporting transactions.

+ +The only drawback of long transactions is possibility to loose a lot of changes in case of fault. +DyBASE will preserve consistency of the database, but all changes made since list commit will be lost.

+ + + +

Application Program Interface

+ +DyBASE core is implemented in C++ (actually GigaBASE implementation is mostly reused). +Interaction with database core is performed using C functions defined in dybase.h file. +API of particular programming language consists of two parts: + +
    +
  1. C interface with database (language extension module) +
  2. Database wrapper classes implemented in language itself. +
+ +I try to made part 1 (extension module implemented in C) as small as possible and used mostly as +wrapper for functions defined in dybase.h. And most of the interface is implemented in language itself. +So all such things as object caching, recursive loading, investigating object fields are implemented in +target language and not in C. The main advantages of such decision is flexibility (it is easier to implement different +strategies at this level) and convenience (using language extension API is usually not convenient an error prone). +The only disadvantage is worse performance because interpreted languages are usually not as fast as C and certainly +implementation of the whole API in C will lead to better performance because no interpretation overhead is present here). +But I think that pro in this case is more significant than its contra.

+ +Below is the description of classes and method present in API of all languages. The next section describes +specific of implementation for particular language.

+ + +

Persistent class

+ +Persistent class is common root for all persistent capable objects. It provides method for loading and storing object. + +
+ +load() +
+Explicitly load object. This method will check if objects needs to be loaded, and, if so, load it from the storage. +
+ +
+ +isLoaded() +
+Check if object is already loaded or explicit invocation of load() method is required. +
+
Returns +
True if object is loaded, False otherwise +
+ +
+ +isPersistent() +
+Check if object is persistent (was assigned persistent OID). +
+
Returns +
True if object is persistent, False otherwise +
+ +
+ +isModified() +
+Check if object was modified during current transaction +
+
Returns +
True if modify method was invoked for the object within current transaction, False otherwise +
+ +
+ +store() +
+Store the object in the storage. If object is not yet persistent it is first made persistent by assigning persistent OID. If object references some other non-persistent object then they recursively made persistent and +also stored in the storage. But referenced persistent objects are not recursively stored. You should invoke store method explicitly for each changed persistent object. +
+ +
+ +modify() +
+Mark object as modified. This object will be automatically stored to the database during transaction commit. +
+ + +
+ +getStorage() +
+Get storage in which object is stored. +
+
Returns +
Storage in which object is stored or Null if object is not persistent. +
+ +
+ +deallocate() +
+Deallocate object in the storage. This method doesn't affect instance of the object in application memory - +it is deallocated in normal way by language runtime. If you are using garbage collector, there is no need to invoke this method. +
+
+ + +sharedLock(nowait=false) +
+Lock persistent object in shared mode. Other threads will be able to set their +shared locks on this objects, but no exclusive locks can be set on this object until this lock is released.
+Upgrading of the lock is not possible (thread holding a read lock can not upgrade it to exclusive lock). +This is done to prevent possible deadlocks caused by lock updates. +But locks are reentrant - so thread can request the same lock many times (and correspondent number of unlocks is needed to release the lock).
+Locking the object doesn't prevent other threads from accessing the object - +it only has influence on sharedLock and exclusiveLock methods. +So programmer should set proper lock before accessing the object in multi-threaded application.
+If object is concurrently accessed by several threads in read-only mode, then explicit locking of this object is not needed, because language API provides consistent retrieving of objects itself.
+Only persistent object (object which were assigned to the the storage either implicitly by saving some other persistent object referencing this object, either explicitly by Storage.makeObjectPersistent method. +
+
Parameters +
nowait - optional parameter specifying whether request should +wait until lock is available or fail if lock can not be granted immediately. +
Returns +
+
true if lock is successfully granted
+
false if lock can not be granted within specified time +
+ +
+ +exclusiveLock(nowait=false) +
+Lock persistent object in exclusive mode. Only one thread can lock object in exclusive mode at each moment of time. Shared or exclusive lock requests of other threads will be blocked until this lock is released. + +Shared locks, but not exclusive locks, can be set on this object until this lock is released.
+This lock is reentrant so thread owning the lock can successfully retrieve the lock many times (and correspondent number of unlocks is needed to release the lock).
+Locking the object doesn't prevent other threads from accessing the object - +it only has influence on sharedLock and exclusiveLock methods. +So programmer should set proper lock before accessing the object in multi-threaded application.
+Only persistent object (object which were assigned to the the storage either implicitly by saving some other persistent object referencing this object, either explicitly by +Storage.makeObjectPersistent method. +
+
Parameters +
nowait - optional parameter specifying whether request should +wait until lock is available or fail if lock can not be granted immediately. +
Returns +
+
true if lock is successfully granted
+
false if lock can not be granted within specified time +
+ +
+ +unlock() +
+Remove granted lock. If lock was requested several times by one thread, then correspondent number of unlocks is needed to release the lock. +
+ +
+ +

Index class

+ +The index class provides access to the objects by key. +Keys of any scalar or string type are supported. But in one index can contains keys only of one type. Index class extends Persistent class and so it is normal Persistent object. Index can be unique (duplicated keys are prohibited) or not unique.

+ +


+ +drop() +
+Delete index. This method removes all entries from index and deallocate index object. +
+ +
+ +clear() +
+Remove all entries from the index. This method doesn't deallocate indexed objects. +
+ +
+ +insert(key, value) +
+Insert object in index. +
+
Parameters +
key - key with type matching with type of the index +
value - persistent capable object to be associated with this key. This object is automatically made persistent +(if it isn't persistent yet). +
Returns +
True if object was successfully inserted in index, False if index is unique and such key already exists in index. +
+ +
+ +set(key, value) +
+Set object for the specified key. If such key already exists in the index, +previous association of this key will be replaced. +
+
Parameters +
key - key with type matching with type of the index +
value - persistent capable object to be associated with this key. This object is automatically made persistent (if it isn't persistent yet). +
+ +
+ +remove(key, value=Null) +
+Remove object from index +
+
Parameters +
key - key with type matching with type of the index +
value - optional reference to the persistent object removed from the index. If index is unique, this parameter can be skipped. +
Returns +
True if object was successfully removed from the index, False if there is no object with such key in index. +
+ +
+ +get(key) +
+Get object associated with specified key. +
+
Parameters +
key - key with type matching with type of the index +
Returns +
Null if there is no object with such key in the index,
+object itself if there is only one object with such key in the index,
+array of object if there are more than one object with such key in the index +
+ +
+ +find(low=null, lowInclusive=true, high=null, highInclusive=true) +
+Get objects which keys belongs to the specified range. +
+
Parameters +
low - low boundary for key value, if Null than there is no low boundary. +
lowInclusive - if low boundary is inclusive or not +
high - high boundary for key value, if Null than there is no high boundary. +
highInclusive - if high boundary is inclusive or not +
Returns +
Array of selected objects or Null if there are no object with key belonging to the specified range +
+ +
+ +iterator(low=null, lowInclusive=true, high=null, highInclusive=true, ascent=true) +
+Get iterator for objects in the index. +Objects will be traversed in key ascending order. +Details of iterator's implementation depends on particular language. +
+
Parameters +
low - low boundary for key value, if Null than there is no low boundary. +
lowInclusive - if low boundary is inclusive or not +
high - high boundary for key value, if Null than there is no high boundary. +
highInclusive - if high boundary is inclusive or not +
ascent - iteration order: if true, then objects will be traversed in key ascending order +
Returns +
Usually this method returns iterator object, but in some languages it is possible to pass block of code which +will be executed for each selected object. +
+ +
+ +

Storage class

+ +Storage is class is the main class of DyBASE API. It provides access to the database storage.

+ +


+ +Storage(pagePoolSize = 4*1024*1024, objectCacheSize = 1000) +
+Storage constructor +
+
Parameters +
pagePoolSize - database page pool in bytes (larger page pool usually leads to better performance) +
objectCacheSize - this parameter is used only by some of languages API and specify maximal number +of objects in application object cache. Not all languages APIs maintain such cache. +
Returns +
Storage object. It is not opened and you should invoke open method explicitly. +
+ +
+ +open(path) +
+Storage constructor +
+
Parameters +
path - path to the database file +
Returns +
True if storage is successfully opened, False otherwise. Some language APIs do not return False, but throw exception +in case of failure. +
+ +
+ +close() +
+Close the storage. If there is an open transaction, it will be first committed. +
+ +
+ +commit() +
+Commit current transaction. Transaction is automatically started once you update the database first time. +
+ +
+ +rollback() +
+Rollback current transaction. All changes done by current transaction are undone. +Attention!Rollback of transaction did not restore original values of application objects. +It just clears object cache. You should not use any variable referencing persistent object after rollback, +but instead of it use Storage.getRootObject method and traverse objects from the root. +
+ +
+ +getRootObject() +
+Get storage root object. +
+
Returns +
Loaded storage root object or Null if root was not yet specified. +
+ +
+ +setRootObject(root) +
+Specify new storage root object. Previous root object (if exists) is NOT deallocated. +
+
Parameters +
root - new storage root object which is automatically made persistent. +
+ +
+ +deallocateObject(obj) +
+Deallocate persistent object from the storage. If object is not persistent, this method has no effect. +
+
Parameters +
obj - persistent object +
+ + +
+ +makeObjectPeristent(obj) +
+Explicitly make object persistent. Object is automatically made persistent when persistent object containing reference +to this object is stored (persistency by reachability). But sometimes you may need to force assignment OID and +storage reference to the object. It can be done by makePerisistent method. This method doesn't actually store +object in the storage, just assign OID to it. +
+
Parameters +
obj - object to be made persistent, if it is already persistent = method as no effect. +
+ +
+
+This method is usually invoked by Persistent.store() method. +storeObject(obj) +
+Make object persistent if it is not yet persistent and store it in the storage. +
+
Parameters +
obj - stored object. +
+ +
+
+This method is usually invoked by Persistent.modify() method. +modifyObject(obj) +
+Mark object as modified. This object will be automatically stored to the database +during transaction commit. +
+
Parameters +
obj - modified object. +
+ +
+ +loadObject(obj) +
+Load object from the storage.
+This method is usually invoked by Persistent.load() method. +
+
Parameters +
obj - loaded object. +
+ +
+ +createStrIndex(unique = True) +
+Create index for keys of string type. +
+
Parameters +
unique - whether duplicated keys are allowed or not (by default not allowed) +
Returns +
Index object +
+ + +
+ +createIntIndex(unique = True) +
+Create index for keys of integer type. +
+
Parameters +
unique - whether duplicated keys are allowed or not (by default not allowed) +
Returns +
Index object +
+ +
+ +createLongIndex(unique = True) +
+Create index for keys of long integer type. Not all languages supports long (64-bit integer) type and so do not provide such method. +
+
Parameters +
unique - whether duplicated keys are allowed or not (by default not allowed) +
Returns +
Index object +
+ +
+ +createBoolIndex(unique = True) +
+Create index for keys of boolean type. Not all languages supports boolean type and so do not provide such method. +
+
Parameters +
unique - whether duplicated keys are allowed or not (by default not allowed) +
Returns +
Index object +
+ +
+ +createRealIndex(unique = True) +
+Create index for keys of floating point type. +
+
Parameters +
unique - whether duplicated keys are allowed or not (by default not allowed) +
Returns +
Index object +
+ + +
+ +resetHash() +
+Reset object hash. Each fetched object is stored in objByOidMap hash table. +It is needed to provide OID->instance mapping. Since placing object in hash increase its access counter, +such object can not be deallocated by garbage collector. So after some time all persistent objects from +the storage will be loaded to the memory. To solve the problem almost all languages with implicit +memory deallocation (garbage collection) provides weak references. But in some of them weak references are not supported +and sometime implementation of weak references is very inefficient. +So to prevent memory overflow you should use resetHash() method. +This method just clear hash table. After invocation of this method, you should not use any variable +referencing persistent objects. Instead you should invoke getRootObject method and access all other +persistent objects only through the root. +
+ + +
+ +gc() +
+Explicit start of garbage collector. Garbage collector will collect only committed object, so there is no need +to invoke garbage collector more than once within one transaction. Garbage collection can be used together with +explicit deallocator by Persistent.deallocate method. But when you are using garbage collector, +you should be careful with keeping references to the persistent objects in local variables. If there are no references +to such object from other persistent object (so it is not reachable from root object), then garbage collector +can deallocate such object. If you then try to access or update this object using reference stored +in local variable, you will get on error. +
+ +
+ +setGcThreashold(maxAllocatedDelta) +
+Set garbage collection threshold. +By default garbage collection is disable (threshold is set to 0). +If it is set to non zero value, GC will be started each time when +delta between total size of allocated and deallocated objects exceeds specified threshold OR +after reaching end of allocation bitmap in allocator. +
+
Parameters +
maxAllocatedDelta - delta between total size of allocated and deallocated object since last GC +or storage opening +
+ + +
+ +sharedLock(obj, nowait=false) +
+Lock object in shared mode. Other threads will be able to set their +shared locks on this objects, but not exclusive lock can be set until this lock is released. +Upgrading of the lock is not possible (thread having read lock can not upgrade it to exclusive lock). +It is done to prevent possible deadlocks caused by lock updates. +But locks are reentrant - so thread can request the same lock many times (and correspondent +number of unlocks is needed to release the lock). +Locking the object doesn't prevent other threads from accessing the object - +it only has influence on sharedLock and exclusiveLock methods. +So programmer should set proper lock before accessing the object in multithreaded application. +If object is concurrently accessed by several threads in read-only mode, then explicit locking +of this object is not needed, because language API provides consistent retrieving of objects itself. +
+
Parameters +
obj - locked object +
nowait - optional parameter specifying whether request should +wait until lock is available or fail if lock can not be granted immediately. +
Returns +
+
true if lock is successfully granted
+
false if lock can not be granted within specified time +
+ +
+ +exclusiveLock(obj, nowait=false) +
+Lock object in exclusive mode. Only one thread can lock object in exclusive mode at each +moment of time. Shared or exclusive lock requests of other threads will be blocked until +this lock is released. +shared locks on this objects, but not exclusive lock can be set until this lock is released. +This lock is reentrant, so thread owning the lock can successfully retrieve the lock many times +(and correspondent number of unlocks is needed to release the lock). +Locking the object doesn't prevent other threads from accessing the object - +it only has influence on sharedLock and exclusiveLock methods. +So programmer should set proper lock before accessing the object in multithreaded application. +
+
Parameters +
obj - locked object +
nowait - optional parameter specifying whether request should +wait until lock is available or fail if lock can not be granted immediately. +
Returns +
+
true if lock is successfully granted
+
false if lock can not be granted within specified time +
+ +
+ +unlock(obj) +
+Remove granted lock. If lock was requested several times by one thread, then correspondent number +of unlocks is needed to release the lock. +
+
Parameters +
obj - unlocked object +
+ +
+ + +

Language specific issues

+ +

Python

+ +Python seems to be the most serious language among those three languages. +It provides efficient weak reference dictionary which makes it possible to implement object cache and do not make programmer to explicitly call resetHash method.

+ +Python provides long integer type (64-bit integer) but it has not separate boolean type (boolean values are treated +as integers).

+ +In Python instance variables are not declared at all and are attached to to the object when first time assigned. +So objects of the same class can have different sets of instance variables. But this is not a problems for DyBASE. +But because of this feature of Python it is not required to derive persistent capable object from Persistent +(although it is still more convenient to do it, because in this case you can use methods derived fro Persistent class).

+ +Unlike other languages stop of recursive loading is done not by redefinition of recursiveLoading method +but by the assignment __nonrecursive__ attribute to the object.

+ +Python makes it possible to redefine getter/setter methods for attributes. +Using this facility delegators for persistent object can be implemented. +Instead of recursive loading of object cluster, it is possible to create delegators for the persistent +object and load objects on demand. Python API provides PersistentDelegator +class which catch method attribute access and load object from the database if needed. +This class also redefine comparison method to treat as equal two different delegators referencing +the same OID. The following things will not work with delegator: +

    +
  1. Check class of the objects with isinstance operator (it can return class of delegator instead of actual object class) +
  2. Comparison of persistent object not derived from Persistent class (Persistent class defines special redefine stand quality comparison operator to correctly handle delegators) +

+ +To enable usage of delagators you should path True to useDelegators +parameter of Storage constructor (default value is False).

+ + +Python API can be built either using standard makefiles in dybase/src +and dybase/python directories, either using setup.py +python script. If you will build python using setup.py at Windows with MinGW, +you may be faced with the following problem: + +

+     C:\devel\dybase\python>setup.py build -cmingw32
+     ...
+     error: command 'cc' failed: No such file or directory
+
+ +The problem is caused by using "cc" for linking while command with such name is not defined +in MinGW. To fix it, just copy g++.exe to cc.exe

+ + + +

Ruby

+ +Ruby is interesting language but with lack of some important features. +For example reflection support in Ruby is very restricted - it is not possible to access instance variables +outside the object. That is why I have to define C functions to access instance variables and +create instances of the class.

+ +Ruby provides weak references but its implementation is so inefficient, that by default it is switched off. +To enable weak references, set USE_WEAK_REFERENCES=true in dybase.rb. +Also Ruby support delegates: classes which redirect (delegate) methods to some other class. +With delegate classes there is no need in recursiveLoading method - objects +are loaded on demand. So it is much more convenient then common DyBase model of loading object. +But there are also some significant drawbacks of delegates: +

    +
  1. There are actually two object instances: delegator object and target object. +DyBASE always return reference to delegator object. But if you return self +from some method, if will not be equal to the object from which method was invoked: +
    +class MyRoot<Persistent 
    +    def me
    +        return self
    +    end
    +end
    +
    +root = db.getRootObject
    +itIsMe = (root == root.me) # !!! false
    +
    + +
  2. You can not inspect class of the object because it will return class of delegator (PersistentDelegator. + +
  3. Delegators adds extra space and CPU overhead (instead of one instance of the object we have two and +each method invocation requires extra redirection). +
+That is why delegators are also switched off by default. To enable them, set USE_DELEGATOR = false +in dybase.rb.

+ +Ruby has normal (mark-and-sweep) garbage collector so it is not suffer from cyclic references. +It support big numbers but not long (64 bit) integers.

+ + +

PHP

+ +May be this language is really very convenient for generation of Web pages, but as +it is almost impossible to use it (from my point of view) as normal object oriented language. +This is because of very strange copy by value model. You have to specify explicitly (in three different places!) +whether you want to copy object by value or by reference and certainly it is so easy to make a mistake with very +interesting effect.

+ +In PHP 4.3.x reference counter field has short type. It means that PHP is not able to correctly +handle objects which are referenced from more than 65535 places. As far as each persistent +object contains reference to the storage object, this limitation means that there can not be more +than 65535 persistent object loaded from the database to the memory at each moment of time. +You have to periodically invoke Storage.resetHash method to remove +persistent objects from the cache. Violation of this rule cause unpredictable behavior of the program +(corruption of memory and sometimes segmentation faults).

+ +PHP doesn't support weak references at all. Also it has no long (64-bit) integers.

+ +PHP 4.* doesn't provide any primitives for working in multithreaded environment. +So locking mechanisms are not supported by PHP API. + +

Rebol

+Requirements/restrictions of Rebol DyBASE API: +
    + +
  • You will have to use professional version of Rebol, because free Command and View version do not +support access to external functions (loading DLLs). + +
  • All persistent objects should be derived (prototyped) from "persistent" object +and specify word of prototype object in __class__ field: + +
    +my-persistent-object: make persistent [ __class__: 'my-persistent-object ... ]
    +
    + +
  • DyBASE Rebol API supports the following Rebol types: object! integer! decimal! string! block! hash!. Values of string, block and hash types are stored as part of referencing them object. +So if one block is referenced by two objects, then in database two copies of this block will be stored. +And after reloading of these objects, there will be two independent blocks in memory. +Also DyBASE doesn't store current position in the block. So the block next [1 2 3 4 5] +will be stored as [2 3 4 5]. + +
  • All other Rebol type (money, URL,...) will be converted and stored in database as strings. +And them will be also loaded as strings. + +
  • As far as Rebol doesn't provide weak reference, it is responsibility of programmer to periodically +clean object cache to avoid memory overflow. Without cleaning cache, all objects from the database will +sooner or later be loaded in memory. If database size is larger than size of available main memory, +it can cause application crash. But even if database fits in main memory, cleaning cache can significantly +increase performance, because adding object to hash table is very slow in Rebol and looks like it has +quadratic complexity (adding N objects requires O(N*N) time!!!). + +
  • If you want to mark some fields as transient (do not store them in the database), start their +names with "_" (underscore). +

+ + +

Comparison of performance of different languages

+ +I have three products GigaBASE, PERST and DyBASE build on the same core. +GigaBASE is implemented in C++ and provides C++ API, PERST is implemented in Java and C-Sharp and provides API +to the correspondent language, DyBASE mostly reuses GigaBASE implementation and provides API to the languages +with dynamic type checking: Python, Ruby, PHP and Rebol.

+ +I run the same simple test implemented in C++, Java, C-Sharp, PHP, Python, Ruby and Rebol. +This test contains three steps:

+ +

    +
  1. Create specified number of records with random long and string key and include it in long and +string indices. After inserting of all records, commit is performed. +
  2. Search for each record using long and string key. +
  3. Search and remove each record from the indices and deallocate it from the storage. +

+ +Time of execution of each step is measured. Number of records in each case is the same - 100000. +Page pool size in all cases is 32Mb, which is enough to hold all records in memory. +All test were executed at the same computer: AMD Athlon 1.3G, 512Mb RAM, WinXP. +I am using MS Visual.NET 2003 C++ compiler, Java JDK 1.4, Python 2.3.2, PHP 4.3., Ruby 1.8.0 and Rebol/View 1.2.10.3.1. +I divide time of each step by number of iteration and produce the following results:

+ + + + + + + + + +
ColorLanguageDatabase
1C++GigaBASE
2JavaPERST
3C-SharpPERST
4RubyDyBase
5PythonDyBase
6PHPDyBase
7RebolDyBase

+ +

Index searches per second

+
1238949
+
237821
+
326382
+
68000
+
57789
+
44348
+
73922
+

+ +

Stored objects per second

+
121612
+
314600
+
213986
+
55748
+
64347
+
43571
+
72941
+

+ +

Removed objects per second

+
119972
+
216589
+
39907
+
44761
+
54130
+
63704
+
72041
+

+ + + +

DyBASE implementation issues

+ +Below is more detailed description of DyBASE implementation. +This section can be skipped if you are not interested in the details of implementation:

+ + +

Memory allocation

+ +Memory allocation is performed in DyBASE by bitmap. Memory is allocated in +chunks called allocation quantum. In current version of DyBASE size of +allocation quantum is 64 byte. It means that size of all allocated objects is +aligned on 64 byte boundary. Each 64 byte of database memory is represented by +one bit in the bitmap. To locate hole of requested size in bitmap, DyBASE +sequentially searches bitmap pages for correspondent number of successive +cleared bits. DyBASE use three arrays indexed by bitmap byte, which +makes possible fast calculation of hole offset and size within the byte.

+ +DyBASE performs cyclic scanning of bitmap pages. It keeps identifier +of current bitmap page and current position within the page. Each time +when allocation request arrives, scanning of the bitmap starts from the +current position. +When last allocated bitmap page is scanned, scanning continues from the +beginning (from the first bitmap page) and until current position. +When no free space is found after full cycle through all bitmap pages, +new bulk of memory is allocated. Size of extension is maximum of +size of allocated object and extension quantum. Extension quantum is parameter +of database, specified in constructor. Bitmap is extended to be able to map +additional space. If virtual space is exhausted and no more +bitmap pages can be allocated, then OutOfMemory error +is reported.

+ +Allocation memory using bitmap provides high locality of references +(objects are mostly allocated sequentially) and also minimizes +number of modified pages. Minimization of number of modified pages is +significant when commit operation is performed and all dirty pages should +be flushed on the disk. When all cloned objects are placed sequentially, +number of modified pages is minimal and so transaction commit time is also +reduced. Using extension quantum also helps to +preserve sequential allocation. Once bitmap is extended, objects will +be allocated sequentially until extension quantum will be completely used. +Only after reaching the end of the bitmap, scanning restarts from the beginning +searching for holes in previously allocated memory.

+ + +To reduce number of bitmap pages scans, DyBASE associates descriptor with +each page, which is used to remember maximal size of the hole on the page. +Calculation of maximal hole size is performed in the following way: +if object of size M can not be allocated from this bitmap pages, +then maximal hole size is less than M, so M +is stored in the page descriptor if previous value of descriptor is large +than M. For next allocation of object of size greater or +equal than M, we will skip this bitmap page. Page descriptor +is reset when some object is deallocated within this bitmap page.

+ +Some database objects +(like hash table pages) should be aligned on page boundary +to provide more efficient access. DyBASE memory allocator checks requested +size and if it is aligned on page boundary, then address of +allocated memory segment is also aligned on page boundary. Search of free hole +will be done faster in this case, because DyBASE increases step of current +position increment according to the value of alignment.

+ +To be able to deallocate memory used by object, DyBASE needs to keep +somewhere +information about object size. DyBASE memory allocator deals with two types +of objects - normal table records and page objects. +All table records are prepended by record header, which contains +record size and pointer of L2-list linking all records in the table. +So size of the table record object can be extracted from record header. +Page objects always occupies the whole database page are are allocated at +the positions aligned on page boundary. Page objects has no headers. +DyBASE distinguish page objects +with normal object by using special marker in object index.

+ + +

Shadow transaction mechanism

+ +Each record (object) in DyBASE has unique identifier (OID). +Object identifiers +are used to implement references between objects. To locate object by +reference, its OID is used as index in array of object offsets within the file. +This array is called object index and element of this array - +object handle. These are two copies of object +indices in DyBASE, one of which is current and other - shadow. +Header of database contains pointers to both object indices and indicator +which index is current at this moment.

+ +When object is modified first time, it is cloned +(copy of the object is created) and object handle in current index is +changed to point to newly created object copy. And shadow index still +contains handle which points to the original version of the object. +All changes are done with the object copy, leaving original object unchanged. +DyBASE marks in special bitmap page of the object index, which contains +modified object handle.

+ +When transaction is committed, DyBASE first checks if size of object index +was increased during current transaction. If so, it also reallocates shadow +copy of object index. Then DyBASE frees memory for all "old objects", +i.e. objects which was cloned within transaction. Memory can not be +deallocated before commit, because we wants to preserve consistent +state of the database by keeping cloned object unchanged. +If we deallocate memory immediately after cloning, new object can be +allocated at the place of cloned object and we loose +consistency. As far as memory deallocation is done in DyBASE by bitmap +using the same transaction mechanism as for normal database objects, +deallocation of object space will require clearing some bits in bitmap page, +which also should be cloned before modification. Cloning bitmap page will +require new space for allocation the page copy, and we can reuse space of +deallocated objects. And it is not acceptable due to the reason explained +above - we will loose database consistency. That is why deallocation +of object is done in two steps. When object is cloned, all bitmap pages +used for marking objects space, are also cloned (if not +not cloned before). So when transaction is committed, we only clear bits in +bitmap pages and no more requests for allocation memory can be generated at +this moment.

+ +After deallocation of old copies, DyBASE flushes all modified pages on disk +to synchronize content of the memory and disk file. After that DyBASE +changes current object index indicator in database +header to switch roles of the object indices. Now object index, which was +current becomes shadow, and shadow index becomes current. Then DyBASE again +flushes modified page (i.e. page with database header) on disk, transferring +database to new consistent state. +After that DyBASE copies all modified handles from new object index +to object index which was previously shadow and now becomes current. +At this moment contents of both indices is synchronized and DyBASE is ready +to start new transaction.

+ +Bitmap of modified object index pages is used to minimize time of committing +transaction. Not the whole object index, but only its modified pages should be +copied. After committing of transaction bitmap is cleared.

+ +When transaction is explicitly aborted by Storage.rollback +method, shadow object index is copied back to the current index, eliminating +all changes done by aborted transaction. After the end of copying, +both indices are identical again and database state corresponds to the moment +before the start of current transaction.

+ +Allocation of object handles is done by free handles list. Header of the list +is also shadowed and two instances of list headers are stored in database +header. Switch between them is done in the same way as switch of +object indices. When there are no more free elements in the list, DyBASE +allocates handles from the unused part of new index. When there is no +more space in the index, it is reallocated. Object index is the only +entity in database whose is not cloned on modification. Instead of this +two copies of object index are always used.

+ +There are some predefined OID values in DyBASE. OID 0 is reserved +as invalid object identifier. OID starting from 1 are reserved for bitmap pages. +Number of bitmap pages depends on database maximum virtual space. +For one terabyte virtual space, 8 Kb page size and 64 byte allocation quantum, +32K bitmap pages are required. So 32K handles are reserved in object index for +bitmap. Bitmap pages are allocated on demand, when database size is extended. +So OID of first users object will be 0x8002.

+ +Recovery procedure is trivial in DyBASE. There are two instances of +object index, one of which is current and another corresponds to +consistent database state. When database is opened, DyBASE checks database +header to detect if database was normally closed. If not +(dirty flag is set in database header), then DyBASE performs +database recovery. Recovery is very similar to rollback of transaction. +Indicator of current index in database object header is used to +determine index corresponding to consistent database state and object handles +from this index are copied to another object index, eliminating +all changes done by uncommitted transaction. As far as the only action +performed by recovery procedure is copying of objects index (really only +handles having different values in current and shadow indices are copied to +reduce number of modified pages) and size of object index is small, +recovery can be done very fast. +Fast recovery procedure reduces "out-of-service" time of application.

+ + +

Where to use

+ +DyBASE is simple and fast embedded database engine. +If your applications need embedded database engine and do not need to execute complex SQL queries, +and the only thing you need is to be able to store/fetch/locate object in the database using navigation +through references or indexed search by key, then DyBASE is what you need. It will provide much better performance +than relational database and other (more sophisticated) object oriented database.

+ +The table below summarize pro features of DyBASE:

+ +

    +
  1. Tight and transparent integration with programming language +
  2. No gap in database and application data model +
  3. Easy to use +
  4. Minimal requirements (DyBASE package itself has size only 51Kb and it can be configured to use minimal memory and disk +space during its work) +
  5. High performance (no overheads of communication, locking and parsing and executing queries) +
  6. Fault tolerance (transaction support) +
  7. Fast recovery after fault +
  8. Zero administration efforts (database consists of the single file), there is no need +to define or tune any database parameters. Such situation like transaction log overflow can never happen +
+ +Certainly nothing in this world can have only positive features. +Now contra list which contains features lacking in DyBASE: + +
    +
  1. No procedural query language +
  2. Fine grain locking (DyBASE always access database in exclusive mode, making it possible for multiple threads +to access the database but provide completely no parallelism). +
  3. Remote access by multiple clients (unless you will implement you own server). +
  4. Data distribution +
  5. Database browsers and database administration tools and import/export utilities to other databases (may be +will be implemented later) +
  6. Lack of support of any standard (for example ODMG) +
+ +

Quick start

+ +DyBASE distribution includes binaries of libraries for MS-Windows and Visual C++ compiler. +The following modules are provides:

+ +

+
lib/dybase.lib +
static DyBASE library +
lib/dybasedll.dll +
DyBASE dynamically loaded library (used by all language APIs) +
python/pythonapi.dll +
Python extension library +
python/dybase.py +
Python module implementing DyBASE API (using pythonapi.dll) +
php/php_dybaseapi.dll +
PHP extension library +
php/dybase.php +
PHP DyBASE API (using php_dybaseapi.dll) +
ruby/rubyapi.dll +
Ruby extension library +
ruby/dybase.rb +
Ruby module implementing DyBASE API (using rubyapi.dll) +

+ + + +If you want to rebuild these libraries yourself, you should run make.bat (which invokes MS nmake +for makefile.mvc) in src directory and compile.bat in each language API +directory. +You make have to change first paths to language home directory in compile.bat scripts. +At Unix you should run make in each directory (GCC compiler and GNU make is expected). +Also paths to language installation directory may need to be adjusted in makefiles.

+ +The easiest way to learn DyBASE API is to look at the examples. +Directory of each language contains three examples:

+ +

+
Guess +
Game "Guess an Animal" - very simple game storing its binary tree in the database. +
TestIndex +
Example of using indices and also performance test. +
TestLink +
Classical Producer-Order-Detail example illustrating usage of one-to-many links. +

+ +To run these example and your own application do not forget to include dybase\lib +in PATH.

+ +

Tuning

+ +This sections contains several hints how to adjust DyBASE parameters and increase database performance.

+ +Speed of accessing data at the disk is several times slower than speed of access data in main memory. +That is why caching of data is the key to increase database performance. DyBASE is using +pool of pages to optimize access to the disk. Page pool size can be specified in Storage.open +method (by default it is 4Mb). Usually increasing page pool leads to better performance. But you should +notice the following things: + +

    +
  • Maximal size of memory used by application sometimes limited by interpreter (for example in PHP it is possible to specify limit +in php.ini file). + +
  • If you specify very large pool size, leaving no free memory for other applications and operating system, +then swapping will cause significant performance degradation. + +
  • Operating system itself maintains file buffers (it is not possible in Java to avoid it). +So data is cached twice. Certainly accessing data from page pool is much faster than from +operating system cache, because in this case no operating system calls and context switches are needed. + +
  • It is not possible to specify empty page pool (leaving all caching for operating system). +When data is access from the page, it is pinned in page pool. So page pool should contain enough entries +to keep all pinned pages. So do not make page pool size less then 64kb. +
+ + +There are some constants defined in database.h file which has influence on +initial and maximal database size. If you want to change them, you will have to rebuild DyBASE. +Below is detailed description of this parameters:

+ + + + + + + + + + + +
ParameterDefault valueDescription
dbDatabaseOffsetBits32Number of bits in offset within database file. This parameter limit the maximal database size. +Default value 32 restrict database to 1Gb. Increasing this parameter will also increase initial database +size. DyBASE is using bitmap to allocate space in the database. Each bitmap page has its own ID +which are reserved in objects index. When database is created, DyBASE reserve in object index space for +identifiers of ALL bitmap pages needed to map database virtual space (defined by dbDatabaseOffsetBits). +Number of bitmap pages needed to map the whole database can be calculated as 2 ** (dbDatabaseOffsetBits-32)). +Actually index will be two times larger, because it should contain some other elements and when index is reallocated its +size is always doubled. Each entry in object index is 8 byte long. There are two indices (active and shadow). +So to estimate initial size of the database, you should multiply value of the expression above by 32. +
dbDefaultInitIndexSize10*1024Initial object index size. Object index is increased on demand. Reallocation of index is +expensive operation and so to minimize number of such reallocations, object index size is always doubled. +Specifying larger initial index size allows to reduce number of future reallocations and so a little bit increase +performance (certainly if your application allocates such number of object). But it also leads to larger initial +size of database file. With default value of this parameter, initial database size is about 50Kb. +
dbDefaultExtensionQuantum512*1024Database extension quantum. +Memory is allocate by scanning bitmap. If there is no large enough hole, then database is extended by the value of +dbDefaultExtensionQuantum. Increasing the value of this parameters leads to less frequent +rescanning of allocation bitmap from the very beginning. It leads to faster allocation speed and better locality of +reference for created objects (because there is more chances that them will be allocated sequentially). +From the other side it leads to less efficient memory usage. Reducing the value of this parameter force reusing +of existed holes in memory allocation bitmap. +

+ +Now some hints how to increase DyBASE performance and reduce size of used main memory. +If you database performs a lot of updates of persistent data, then the main limiting factor is speed +of writing changes to the disk. Especially synchronous write to the disk performed by commit. +If you will do commit after each update, then average speed will be about 10 updates per second +(this estimation is based on the assumption than average disk access time is about 10msec and +each transaction commit usually requires writing about 10 pages in random places in the file). +But it is possible to dramatically increase update performance if you group several updates in +one transactions. DyBASE is creating shadow of the object when it is +first time updated inside transaction. If object will be updated once in N transactions, +then N shadows will be created. If object will be updated N times inside one transaction, then +shadow will be created only once. It explains advantage of having one large transaction.

+ +But if you will perform update of large number of objects in one transaction and for each updated +object shadow is created, then it leads to significant increase of database file size. +If you update each object in the database inside one transaction, database size will be +almost doubled! And if you perform each update in separate transaction, then size of database +will be almost unchanged (because space of allocated shadow objects will be reused in this case). +So the best approach is to perform commit after 100 or 1000 updates, it will +reduce overhead of each commit and save database size.

+ + +If your persistent object form tree or graph where all objects can be accessed by reference from the root object, +then once you will load root object in main memory and store reference to it in some variable, +GC will never be able to collect any instance of loaded persistent object (because it will be accessible from +the root object). So when you application access more and more objects from the storage, +at some moment of time all of them will have to be loaded in main memory. It can cause space exhaustion. +To prevent this situation you should avoid to store in variables references to container objects which +contain references to a large number of members. Especially it is true for storage root object. +In this case GC is able to do it work and throw out from the memory objects which are not used +at this moment (to which there are no references from local variable). +But it is important to say that objects accessible though the index by key can be normally deallocated by garbage +collector. So in this case special care is not needed.

+ + +

Distribution terms

+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 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 +AUTHOR OF THIS SOFTWARE 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. + +

+ +I will provide e-mail support and help you with development of +DyBASE applications.

+


+

+Look for new version at my homepage | + +E-Mail me about bugs and problems

+ + + + + + + +tor. So in this case special care is not needed.

+ + +

Distribution terms

+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 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 +AUTHOR OF THIS SOFTWARE 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. + +

+ +I will provide e-mail support and help you with development of +DyBASE applications.

+


+

+Look for new version at my homepage | + +E-Mail me about bugs and problems

+ + + + + + + diff --git a/storage/dybase/include/dybase.h b/storage/dybase/include/dybase.h new file mode 100644 index 000000000..1a5fc9339 --- /dev/null +++ b/storage/dybase/include/dybase.h @@ -0,0 +1,434 @@ +#ifndef __DYBASE_H__ +#define __DYBASE_H__ + +#ifndef DYBASE_DLL_ENTRY +#if defined(_WIN32) && defined(DYBASE_DLL) +#ifdef INSIDE_DYBASE +#define DYBASE_DLL_ENTRY __declspec(dllexport) +#else +#define DYBASE_DLL_ENTRY __declspec(dllimport) +#endif +#else +#define DYBASE_DLL_ENTRY +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _INC_CTYPE +#include +#endif //_INC_CTYPE + +/** + * Supported database field types + */ +enum dybase_type { + dybase_object_ref_type = 0, // object ref, oid + dybase_array_ref_type = 1, + dybase_index_ref_type = 2, + + dybase_bool_type = 3, + dybase_int_type = 4, + dybase_date_type = 5, + dybase_real_type = 6, + dybase_chars_type = 7, // literal string + dybase_array_type = 8, // literal array + dybase_map_type = 9, // literal key/value pairs map + + dybase_long_type = 10, + dybase_bytes_type = 11, // literal blob - byte vector, max length 2^32 +}; + +/** + * Error codes + */ +enum dybase_error_code { + dybase_no_error, + dybase_not_opened, + dybase_open_error, + dybase_file_error, + dybase_bad_key_type, + dybase_out_of_memory_error +}; + +typedef void * dybase_storage_t; +typedef void * dybase_handle_t; +typedef void * dybase_iterator_t; +typedef unsigned dybase_oid_t; + +typedef void * hashtable_t; + +typedef void (*dybase_error_handler_t)(int error_code, char const *msg); + +/** + * Open storage + * @param file_path path to the storage file + * @page_pool_size size of page pool in bytes, if 0, then default value will be + * used + * @param hnd error handler + * @return pointer to the opened storage or NULL if open failed + */ +dybase_storage_t DYBASE_DLL_ENTRY dybase_open(const char *file_path, + int page_pool_size, + dybase_error_handler_t hnd, + int read_write); + +/** + * Close storage + * @param storage pointer to the opened storage + */ +void DYBASE_DLL_ENTRY dybase_close(dybase_storage_t storage); + +/** + * Commit current transaction + * @param storage pointer to the opened storage + */ +void DYBASE_DLL_ENTRY dybase_commit(dybase_storage_t storage); + +/** + * Rollback current transaction + * @param storage pointer to the opened storage + */ +void DYBASE_DLL_ENTRY dybase_rollback(dybase_storage_t storage); + +/** + * Get identifier of the root object + * @param storage pointer to the opened storage + * @return root object OID or 0 if root was not yet specified + */ +dybase_oid_t DYBASE_DLL_ENTRY dybase_get_root_object(dybase_storage_t storage); + +/** + * Set storage root + * @param storage pointer to the opened storage + * @param oid object identifier of new storage root + */ +void DYBASE_DLL_ENTRY dybase_set_root_object(dybase_storage_t storage, + dybase_oid_t oid); + +/** + * Allocate object + * @param storage pointer to the opened storage + * @return new OID assigned to the object + */ +dybase_oid_t DYBASE_DLL_ENTRY dybase_allocate_object(dybase_storage_t storage); + +/** + * Deallocate object + * @param storage pointer to the opened storage + * @param oid object identifier of deallocated object + */ +void DYBASE_DLL_ENTRY dybase_deallocate_object(dybase_storage_t storage, + dybase_oid_t oid); + +/** + * Begin store of the object + * @param storage pointer to the opened storage + * @param oid object identifier of stored object + * @param class name name of the class of stored object + * @return handle of stored object which should be used in subsequent + * dybase_store_object_field and dybase_end_store_object methods + */ +dybase_handle_t DYBASE_DLL_ENTRY dybase_begin_store_object( + dybase_storage_t storage, dybase_oid_t oid, char const *class_name); + +/** + * Store object field + * @param handle object handle returned by dybase_begin_store_object + * @param field_name name of the field + * @param field_type type of the field (one of the constants from dybase_type + * enum) + * @param value_ptr pointer to the value + * @param value length (used for string, array and map types) + */ +void DYBASE_DLL_ENTRY dybase_store_object_field(dybase_handle_t handle, + char const * field_name, + int field_type, void *value_ptr, + int value_length); + +/** + * Store array element. This method can be also used to store map elements, in + * this case for each map entry the method should be invoked for entry key and + * entry value. + * @param handle object handle returned by dybase_begin_store_object + * @param elem_type type of the element (one of the constants from dybase_type + * enum) + * @param value_ptr pointer to the value + * @param value length (used for string, array and map types) + */ +void DYBASE_DLL_ENTRY dybase_store_array_element(dybase_handle_t handle, + int elem_type, void *value_ptr, + int value_length); + +/** + * Store map entry + * @param handle object handle returned by dybase_begin_store_object + * @param key_type type of the key (one of the constants from dybase_type enum) + * @param key_ptr pointer to the key + * @param key_length (used for string and array types) + * @param value_type type of the value (one of the constants from dybase_type + * enum) + * @param value_ptr pointer to the value + * @param value_length (used for string, array and map types) + */ +void DYBASE_DLL_ENTRY dybase_store_map_entry(dybase_handle_t handle, + int key_type, void *key_ptr, + int key_length, int value_type, + void *value_ptr, int value_length); + +/** + * End of object store + * @param handle object handle returned by dybase_begin_store_object + */ +void DYBASE_DLL_ENTRY dybase_end_store_object(dybase_handle_t handle); + +/** + * Begin loading of the object + * @param storage pointer to the opened storage + * @param oid object identifier of loaded object + * @return handle of stored object which should be used in subsequent + * dybase_load_object_field and dybase_get_class_name methods + */ +dybase_handle_t DYBASE_DLL_ENTRY + dybase_begin_load_object(dybase_storage_t storage, dybase_oid_t oid); + +/** + * End loading of the object + * @param handle of stored object + */ +void dybase_end_load_object(dybase_handle_t handle); + +/** + * Get loaded object class name + * @param handle object handle returned by dybase_begin_load_object + * @return class name of the loaded object + */ +DYBASE_DLL_ENTRY char *dybase_get_class_name(dybase_handle_t handle); + +/** + * Move to next field. This function should be called before dybase_get_value + * function. When this functions is called first time after + * dybase_begin_load_object, information about first field is returned. + * @param handle object handle returned by dybase_begin_load_object + * @return field name or NULL if there are no more fields (in this case this + * function also destruct the handle) + */ +DYBASE_DLL_ENTRY char *dybase_next_field(dybase_handle_t handle); + +/** + * Move to next array element. This function should be called before + * dybase_get_value function. When this functions is called first time after + * dybase_next_field, cursor is positioned at element of array with index 0 + * @param handle object handle returned by dybase_begin_load_object + */ +void DYBASE_DLL_ENTRY dybase_next_element(dybase_handle_t handle); + +/** + * Get value of the field, array element or map enrty. For map entry you should + * invoke this methogd twice - first for entry key, and second - for entry + * value. + * @param handle object handle returned by dybase_begin_load_object + * @param field_type pointer to the location to receive type of the field or + * array element + * @param value_ptr pointer to the location to receive pointer to the object + * value + * @param value_length pointer to the location to receive length of string, + * array or map field + */ +void DYBASE_DLL_ENTRY dybase_get_value(dybase_handle_t handle, int *type, + void **value_ptr, int *value_length); + +/** + * Create object index + * @param storage pointer to the opened storage + * @param key_type type of the index key + * @param unique whether index allows duplicates or not + * @return OID of created index + */ +dybase_oid_t DYBASE_DLL_ENTRY dybase_create_index(dybase_storage_t storage, + int key_type, int unique); + +/** + * Insert value in index + * @param storage pointer to the opened storage + * @param index OID of index created by dybase_create_index + * @param key pointer to the value of the key + * @param key_type type of the inserted key which should match type of the index + * @param key_size size of the string key + * @param obj OID of the object associated with this key + * @param replace object for existing key (if this parameter is 0, then + * inserting object with duplicated key will cause retruning error in case of + * unique index and presence of more than one record with the same value of the + * key in case of non unique index). + * @return 1 if object is successfully inserted, 0 if index is unique and eky is + * already presebnt in the index + */ +int DYBASE_DLL_ENTRY dybase_insert_in_index(dybase_storage_t storage, + dybase_oid_t index, void *key, + int key_type, int key_size, + dybase_oid_t obj, int replace); + +/** + * Remove key from the index + * @param storage pointer to the opened storage + * @param index OID of index created by dybase_create_index + * @param key pointer to the value of the key + * @param key_type type of the inserted key which should match type of the index + * @param key_size size of the string key + * @param obj OID of the object associated with this key (it can be 0 if index + * is unique) + * @return 1 if object is successfully removed from the index, 0 if key is not + * present in the index + */ +int DYBASE_DLL_ENTRY dybase_remove_from_index(dybase_storage_t storage, + dybase_oid_t index, void *key, + int key_type, int key_size, + dybase_oid_t obj); + +/** + * Returns uniqueness attribute of the index. + * @param storage pointer to the opened storage + * @param index OID of index created by dybase_create_index + * @return 1 if index is unique, 0 - otherwise. + */ + +int DYBASE_DLL_ENTRY dybase_is_index_unique(dybase_storage_t storage, + dybase_oid_t index); + +/** + * Returns type of the index. + * @param storage pointer to the opened storage + * @param index OID of index created by dybase_create_index + * @return type of the index. + */ + +int DYBASE_DLL_ENTRY dybase_get_index_type(dybase_storage_t storage, + dybase_oid_t index); + + + +/** + * Perform index search + * @param storage pointer to the opened storage + * @param index OID of index created by dybase_create_index + * @param key_type type of the inserted key which should match type of the index + * @param min_key pointer to the low boundary of key value (if NULL then there + * is no low boundary) + * @param min_key_size optional size of low boundary key value (for string type) + * @param min_key_inclusive is low boundary inclusive or not + * @param max_key pointer to the high boundary of key value (if NULL then there + * is no high boundary) + * @param min_key_size optional size of high boundary key value (for string + * type) + * @param max_key_inclusive is high boundary inclusive or not + * @param selected_objects pointer to the location to receive pointer to the + * array of selected objects, if number of selected objects is greater than 0, + * then the buffer should be deallocated by dybase_free_seletion + * @return number of the selected objects + */ +int DYBASE_DLL_ENTRY dybase_index_search( + dybase_storage_t storage, dybase_oid_t index, int key_type, void *min_key, + int min_key_size, int min_key_inclusive, void *max_key, int max_key_size, + int max_key_inclusive, dybase_oid_t **selected_objects); + +/** + * Deallocate selection + * @param storage pointer to the opened storage + * @param selected_objects array of selected objects returned by + * dybase_index_search + * @param n_selected number of selected objects + */ +void DYBASE_DLL_ENTRY dybase_free_selection(dybase_storage_t storage, + dybase_oid_t * selected_objects, + int n_selected); + +/** + * Drop index + * @param storage pointer to the opened storage + * @param index OID of index created by dybase_create_index + */ +void DYBASE_DLL_ENTRY dybase_drop_index(dybase_storage_t storage, + dybase_oid_t index); + +/** + * Remove all entries from the index + * @param storage pointer to the opened storage + * @param index OID of index created by dybase_create_index + */ +void DYBASE_DLL_ENTRY dybase_clear_index(dybase_storage_t storage, + dybase_oid_t index); + +/** + * Create index iterator. Iterator is used for traversing all index members in + * key ascending order + * @param storage pointer to the opened storage + * @param index OID of index created by dybase_create_index + * @param key_type type of the inserted key which should match type of the index + * @param min_key pointer to the low boundary of key value (if NULL then there + * is no low boundary) + * @param min_key_size optional size of low boundary key value (for string type) + * @param min_key_inclusive is low boundary inclusive or not + * @param max_key pointer to the high boundary of key value (if NULL then there + * is no high boundary) + * @param min_key_size optional size of high boundary key value (for string + * type) + * @param max_key_inclusive is high boundary inclusive or not + * @param ascent if true, then iterate in key ascending order + * @return new index iterator + */ +dybase_iterator_t DYBASE_DLL_ENTRY dybase_create_index_iterator( + dybase_storage_t storage, dybase_oid_t index, int key_type, void *min_key, + int min_key_size, int min_key_inclusive, void *max_key, int max_key_size, + int max_key_inclusive, int ascent); + +/** + * Get next element + * @param iterator index iterator + * @return oid of next object in the index or 0 if there are no more objects + */ +dybase_oid_t DYBASE_DLL_ENTRY + dybase_index_iterator_next(dybase_iterator_t iterator); + +/** + * Free index iterator + * @param iterator index iterator + */ +void DYBASE_DLL_ENTRY dybase_free_index_iterator(dybase_iterator_t iterator); + +/** + * Set garbage collection threshold. + * By default garbage collection is disable (threshold is set to 0). + * If it is set to non zero value, GC will be started each time when + * delta between total size of allocated and deallocated objects exceeds + * specified threshold OR after reaching end of allocation bitmap in allocator. + * @param allocated_delta delta between total size of allocated and deallocated + * object since last GC or storage opening + */ +void DYBASE_DLL_ENTRY dybase_set_gc_threshold(dybase_storage_t storage, + long allocated_delta); + +/** + * Explicit start of garbage collector + */ +void DYBASE_DLL_ENTRY dybase_gc(dybase_storage_t storage); + + +hashtable_t DYBASE_DLL_ENTRY hashtable_create(); +void DYBASE_DLL_ENTRY hashtable_put(hashtable_t ht, void *key, int keySize, void *value); +void* DYBASE_DLL_ENTRY hashtable_get(hashtable_t ht, void *key, int keySize); +void* DYBASE_DLL_ENTRY hashtable_remove(hashtable_t ht, void *key, int keySize); +void DYBASE_DLL_ENTRY hashtable_clear(hashtable_t ht); + +typedef int each_cb_t(void* key, unsigned int key_length, void* data, void* opaque); + +void DYBASE_DLL_ENTRY hashtable_each(hashtable_t ht, each_cb_t* pcb, void* opaque); +void DYBASE_DLL_ENTRY hashtable_free(hashtable_t ht); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/storage/dybase/src/btree.cpp b/storage/dybase/src/btree.cpp new file mode 100644 index 000000000..188a9b9b9 --- /dev/null +++ b/storage/dybase/src/btree.cpp @@ -0,0 +1,1725 @@ +//-< BTREE.CPP >-----------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 1-Jan-99 K.A. Knizhnik * / [] \ * +// Last update: 25-Oct-99 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// B-Tree implementation +//-------------------------------------------------------------------*--------* + +#include "stdtp.h" +#include "database.h" +#include "btree.h" + +#if defined(__sun) || defined(__SVR4) +#define NO_LARGE_LOCAL_ARRAYS +#endif + +void dbBtree::find(dbDatabase *db, oid_t treeId, dbSearchContext &sc) { + dbCriticalSection cs(db->mutex); + if (!db->opened) { + db->handleError(dybase_not_opened, "Database not opened"); + return; + } + dbGetTie tie; + dbBtree *tree = (dbBtree *)db->getObject(tie, treeId); + + if (sc.keyType != tree->type) { + if (sc.low != NULL || sc.high != NULL) { + db->handleError(dybase_bad_key_type, + "Type of the key doesn't match index type"); + return; + } + sc.keyType = tree->type; + } + + oid_t rootId = tree->root; + int height = tree->height; + if (rootId != 0) { + dbBtreePage *page = (dbBtreePage *)db->get(rootId); + (void)page->find(db, sc, height); + db->pool.unfix(page); + } +} + +oid_t dbBtree::allocate(dbDatabase *db, int type, bool unique) { + dbCriticalSection cs(db->mutex); + if (!db->opened) { + db->handleError(dybase_not_opened, "Database not opened"); + return 0; + } + /*dbBtree* tree = new dbBtree(); + tree->size = sizeof(dbBtree); + tree->root = 0; + tree->height = 0; + tree->type = type; + tree->unique = unique; + tree->cid = dbBtreeId; + return db->allocateObject(tree);*/ + + dbBtree tree; + tree.size = sizeof(dbBtree); + tree.root = 0; + tree.height = 0; + tree.type = type; + tree.unique = unique; + tree.cid = dbBtreeId; + return db->allocateObject(&tree); +} + +bool dbBtree::packItem(dbDatabase *db, dbBtree *tree, dbBtreePage::item &it, + void *key, int keyType, length_t keySize, oid_t oid) { + + if (keyType != tree->type) { + db->handleError(dybase_bad_key_type, + "Type of the key doesn't match index type"); + return false; + } + it.oid = oid; + switch (keyType) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: + it.keyLen = sizeof(oid_t); + it.refKey = *(oid_t *)key; + break; + case dybase_bool_type: + it.keyLen = sizeof(db_int1); + it.boolKey = *(db_int1 *)key; + break; + case dybase_int_type: + it.keyLen = sizeof(db_int4); + it.intKey = *(db_int4 *)key; + break; + case dybase_date_type: + case dybase_long_type: + it.keyLen = sizeof(db_int8); + it.longKey = *(db_int8 *)key; + break; + case dybase_real_type: + it.keyLen = sizeof(db_real8); + it.realKey = *(db_real8 *)key; + break; + case dybase_chars_type: + if (keySize > dbBtreePage::dbMaxKeyLen) { + db->handleError(dybase_bad_key_type, "Size of string key is too large"); + return false; + } + it.keyLen = int(keySize); + memcpy(it.charKey, key, keySize); + break; + case dybase_bytes_type: + if (keySize > dbBtreePage::dbMaxKeyLen) { + db->handleError(dybase_bad_key_type, "Size of string key is too large"); + return false; + } + it.keyLen = int(keySize); + memcpy(it.charKey, key, keySize); + break; + } + return true; +} + +bool dbBtree::insert(dbDatabase *db, oid_t treeId, void *key, int keyType, + length_t keySize, oid_t oid, bool replace) { + dbCriticalSection cs(db->mutex); + if (!db->opened) { + db->handleError(dybase_not_opened, "Database not opened"); + return false; + } + dbGetTie treeTie; + dbBtreePage::item ins; + dbBtree * tree = (dbBtree *)db->getObject(treeTie, treeId); + + if (!packItem(db, tree, ins, key, keyType, keySize, oid)) { return false; } + + oid_t rootId = tree->root; + int height = tree->height; + + if (rootId == 0) { + dbPutTie tie; + dbBtree *t = (dbBtree *)db->putObject(tie, treeId); + t->root = dbBtreePage::allocate(db, 0, tree->type, ins); + t->height = 1; + return true; + } else { + int result = dbBtreePage::insert(db, rootId, tree->type, ins, tree->unique, + replace, height); + assert(result != not_found); + if (result == overflow) { + dbPutTie tie; + dbBtree *t = (dbBtree *)db->putObject(tie, treeId); + t->root = dbBtreePage::allocate(db, rootId, tree->type, ins); + t->height += 1; + } + return result != duplicate; + } +} + +bool dbBtree::is_unique(dbDatabase *db, oid_t treeId) { + dbCriticalSection cs(db->mutex); + if (!db->opened) { + db->handleError(dybase_not_opened, "Database not opened"); + return false; + } + dbGetTie treeTie; + dbBtree *tree = (dbBtree *)db->getObject(treeTie, treeId); + return tree->unique; +} + +int dbBtree::get_type(dbDatabase *db, oid_t treeId) { + dbCriticalSection cs(db->mutex); + if (!db->opened) { + db->handleError(dybase_not_opened, "Database not opened"); + return 0; + } + dbGetTie treeTie; + dbBtree *tree = (dbBtree *)db->getObject(treeTie, treeId); + return tree->type; +} + + +bool dbBtree::remove(dbDatabase *db, oid_t treeId, void *key, int keyType, + length_t keySize, oid_t oid) { + dbCriticalSection cs(db->mutex); + if (!db->opened) { + db->handleError(dybase_not_opened, "Database not opened"); + return false; + } + dbGetTie treeTie; + dbBtreePage::item rem; + dbBtree * tree = (dbBtree *)db->getObject(treeTie, treeId); + + if (oid == 0 && !tree->unique) { + db->handleError(dybase_bad_key_type, "Associated object should be " + "specified to perform remove from " + "non-unique index"); + return false; + } + + if (!packItem(db, tree, rem, key, keyType, keySize, oid)) { return false; } + + oid_t rootId = tree->root; + int height = tree->height; + + if (rootId == 0) { return false; } + + int result = dbBtreePage::remove(db, rootId, tree->type, rem, height); + if (result == underflow) { + dbBtreePage *page = (dbBtreePage *)db->get(rootId); + if (page->nItems == 0) { + dbPutTie tie; + dbBtree *t = (dbBtree *)db->putObject(tie, treeId); + if (height == 1) { + t->height = 0; + t->root = 0; + } else { + if (tree->type == dybase_chars_type || tree->type == dybase_bytes_type) { + t->root = page->strKey[0].oid; + } else { + t->root = page->record[dbBtreePage::maxItems - 1]; + } + t->height -= 1; + } + db->freePage(rootId); + } + db->pool.unfix(page); + } else if (result == dbBtree::overflow) { + dbPutTie tie; + dbBtree *t = (dbBtree *)db->putObject(tie, treeId); + t->root = dbBtreePage::allocate(db, rootId, tree->type, rem); + t->height += 1; + } + return result != not_found; +} + +void dbBtree::clear(dbDatabase *db, oid_t treeId) { + dbCriticalSection cs(db->mutex); + if (!db->opened) { + db->handleError(dybase_not_opened, "Database not opened"); + return; + } + _clear(db, treeId); +} + +void dbBtree::_clear(dbDatabase *db, oid_t treeId) { + dbPutTie tie; + dbBtree *tree = (dbBtree *)db->putObject(tie, treeId); + if (tree->root != 0) { + dbBtreePage::purge(db, tree->root, tree->type, tree->height); + tree->root = 0; + tree->height = 0; + } +} + +void dbBtree::drop(dbDatabase *db, oid_t treeId) { + dbCriticalSection cs(db->mutex); + if (!db->opened) { + db->handleError(dybase_not_opened, "Database not opened"); + return; + } + _drop(db, treeId); +} + +void dbBtree::_drop(dbDatabase *db, oid_t treeId) { + _clear(db, treeId); + db->free(db->getPos(treeId) & ~dbFlagsMask, sizeof(dbBtree)); + db->freeId(treeId); +} + +#define CHECK(a, b, inclusion) (a > b || (a == b && !inclusion)) + +#define FIND(KEY, TYPE) \ + if (sc.low != NULL) { \ + TYPE key = *(TYPE *)sc.low; \ + while (l < r) { \ + int i = (l + r) >> 1; \ + if (CHECK(key, KEY[i], lowInclusion)) { \ + l = i + 1; \ + } else { \ + r = i; \ + } \ + } \ + assert(r == l); \ + } \ + if (sc.high != NULL) { \ + TYPE key = *(TYPE *)sc.high; \ + if (height == 0) { \ + while (l < n) { \ + if (CHECK(KEY[l], key, highInclusion)) { return false; } \ + sc.selection.add(record[maxItems - 1 - l]); \ + l += 1; \ + } \ + return true; \ + } else { \ + do { \ + dbBtreePage *pg = (dbBtreePage *)db->get(record[maxItems - 1 - l]); \ + if (!pg->find(db, sc, height)) { \ + db->pool.unfix(pg); \ + return false; \ + } \ + db->pool.unfix(pg); \ + if (l == n) { return true; } \ + } while (KEY[l++] <= key); \ + return false; \ + } \ + } \ + break + +inline int compareStrings(void *s1, length_t n1, void *s2, length_t n2) { + length_t len = n1 < n2 ? n1 : n2; + int diff = memcmp(s1, s2, len); + return diff != 0 ? diff : int(n1) - int(n2); +} + +bool dbBtreePage::find(dbDatabase *db, dbSearchContext &sc, int height) { + int l = 0, n = nItems, r = n; + height -= 1; + int lowInclusion = sc.lowInclusive; + int highInclusion = sc.highInclusive; + + switch (sc.keyType) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: FIND(refKey, oid_t); + case dybase_bool_type: FIND(boolKey, db_int1); + case dybase_int_type: FIND(intKey, db_int4); + case dybase_date_type: + case dybase_long_type: FIND(longKey, db_int8); + case dybase_real_type: FIND(realKey, db_real8); + case dybase_bytes_type: + case dybase_chars_type: + if (sc.low != NULL) { + while (l < r) { + int i = (l + r) >> 1; + if (compareStrings(sc.low, sc.lowSize, &charKey[strKey[i].offs], + strKey[i].size) >= lowInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + } + if (sc.high != NULL) { + if (height == 0) { + while (l < n) { + if (compareStrings(&charKey[strKey[l].offs], strKey[l].size, sc.high, + sc.highSize) >= highInclusion) { + return false; + } + sc.selection.add(strKey[l].oid); + l += 1; + } + } else { + do { + dbBtreePage *pg = (dbBtreePage *)db->get(strKey[l].oid); + if (!pg->find(db, sc, height)) { + db->pool.unfix(pg); + return false; + } + db->pool.unfix(pg); + if (l == n) { return true; } + l += 1; + } while (compareStrings(&charKey[strKey[l - 1].offs], + strKey[l - 1].size, sc.high, sc.highSize) <= 0); + return false; + } + } else { + if (height == 0) { + while (l < n) { + sc.selection.add(strKey[l].oid); + l += 1; + } + } else { + do { + dbBtreePage *pg = (dbBtreePage *)db->get(strKey[l].oid); + if (!pg->find(db, sc, height)) { + db->pool.unfix(pg); + return false; + } + db->pool.unfix(pg); + } while (++l <= n); + } + } + return true; + } + if (height == 0) { + while (l < n) { + sc.selection.add(record[maxItems - 1 - l]); + l += 1; + } + } else { + do { + dbBtreePage *pg = (dbBtreePage *)db->get(record[maxItems - 1 - l]); + if (!pg->find(db, sc, height)) { + db->pool.unfix(pg); + return false; + } + db->pool.unfix(pg); + } while (++l <= n); + } + return true; +} + +oid_t dbBtreePage::allocate(dbDatabase *db, oid_t root, int type, item &ins) { + oid_t pageId = db->allocatePage(); + dbBtreePage *page = (dbBtreePage *)db->put(pageId); + page->nItems = 1; + if (type == dybase_chars_type || type == dybase_bytes_type) { + page->size = ins.keyLen * sizeof(char); + page->strKey[0].offs = db_nat2(sizeof(page->charKey) - ins.keyLen * sizeof(char)); + page->strKey[0].size = db_nat2(ins.keyLen); + page->strKey[0].oid = ins.oid; + page->strKey[1].oid = root; + memcpy(&page->charKey[page->strKey[0].offs], ins.charKey, ins.keyLen); + } else { + memcpy(page->charKey, ins.charKey, dbSizeofType[type]); + page->record[maxItems - 1] = ins.oid; + page->record[maxItems - 2] = root; + } + db->pool.unfix(page); + return pageId; +} + +#define INSERT(KEY, TYPE) \ + { \ + TYPE key = ins.KEY; \ + while (l < r) { \ + int i = (l + r) >> 1; \ + if (key > pg->KEY[i]) \ + l = i + 1; \ + else \ + r = i; \ + } \ + assert(l == r); \ + /* insert before e[r] */ \ + if (--height != 0) { \ + result = insert(db, pg->record[maxItems - r - 1], type, ins, unique, \ + replace, height); \ + if (result != dbBtree::overflow) { \ + db->pool.unfix(pg); \ + return result; \ + } \ + n += 1; \ + } else if (r < n && key == pg->KEY[r]) { \ + if (replace) { \ + db->pool.unfix(pg); \ + pg = (dbBtreePage *)db->put(tie, pageId); \ + pg->record[maxItems - r - 1] = ins.oid; \ + return dbBtree::done; \ + } else if (unique) { \ + return dbBtree::duplicate; \ + } \ + } \ + db->pool.unfix(pg); \ + pg = (dbBtreePage *)db->put(tie, pageId); \ + const int max = sizeof(pg->KEY) / (sizeof(oid_t) + sizeof(TYPE)); \ + if (n < max) { \ + memmove(&pg->KEY[r + 1], &pg->KEY[r], (n - r) * sizeof(TYPE)); \ + memcpy(&pg->record[maxItems - n - 1], &pg->record[maxItems - n], \ + (n - r) * sizeof(oid_t)); \ + pg->KEY[r] = ins.KEY; \ + pg->record[maxItems - r - 1] = ins.oid; \ + pg->nItems += 1; \ + return dbBtree::done; \ + } else { /* page is full then divide page */ \ + oid_t pageId = db->allocatePage(); \ + dbBtreePage *b = (dbBtreePage *)db->put(pageId); \ + assert(n == max); \ + const int m = max / 2; \ + if (r < m) { \ + memcpy(b->KEY, pg->KEY, r * sizeof(TYPE)); \ + b->KEY[r] = ins.KEY; \ + memcpy(&b->KEY[r + 1], &pg->KEY[r], (m - r - 1) * sizeof(TYPE)); \ + memcpy(pg->KEY, &pg->KEY[m - 1], (max - m + 1) * sizeof(TYPE)); \ + memcpy(&b->record[maxItems - r], &pg->record[maxItems - r], \ + r * sizeof(oid_t)); \ + b->record[maxItems - r - 1] = ins.oid; \ + memcpy(&b->record[maxItems - m], &pg->record[maxItems - m + 1], \ + (m - r - 1) * sizeof(oid_t)); \ + memmove(&pg->record[maxItems - max + m - 1], \ + &pg->record[maxItems - max], (max - m + 1) * sizeof(oid_t)); \ + } else { \ + memcpy(b->KEY, pg->KEY, m * sizeof(TYPE)); \ + memcpy(pg->KEY, &pg->KEY[m], (r - m) * sizeof(TYPE)); \ + pg->KEY[r - m] = ins.KEY; \ + memcpy(&pg->KEY[r - m + 1], &pg->KEY[r], (max - r) * sizeof(TYPE)); \ + memcpy(&b->record[maxItems - m], &pg->record[maxItems - m], \ + m * sizeof(oid_t)); \ + memmove(&pg->record[maxItems - r + m], &pg->record[maxItems - r], \ + (r - m) * sizeof(oid_t)); \ + pg->record[maxItems - r + m - 1] = ins.oid; \ + memmove(&pg->record[maxItems - max + m - 1], \ + &pg->record[maxItems - max], (max - r) * sizeof(oid_t)); \ + } \ + ins.oid = pageId; \ + ins.KEY = b->KEY[m - 1]; \ + if (height == 0) { \ + pg->nItems = max - m + 1; \ + b->nItems = m; \ + } else { \ + pg->nItems = max - m; \ + b->nItems = m - 1; \ + } \ + db->pool.unfix(b); \ + return dbBtree::overflow; \ + } \ + \ +} + +int dbBtreePage::insert(dbDatabase *db, oid_t pageId, int type, item &ins, + bool unique, bool replace, int height) { + dbPutTie tie; + dbBtreePage *pg = (dbBtreePage *)db->get(pageId); + int result; + int l = 0, n = pg->nItems, r = n; + + switch (type) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: INSERT(refKey, oid_t); + case dybase_bool_type: INSERT(boolKey, db_int1); + case dybase_int_type: INSERT(intKey, db_int4); + case dybase_date_type: + case dybase_long_type: INSERT(longKey, db_int8); + case dybase_real_type: INSERT(realKey, db_real8); + case dybase_bytes_type: + case dybase_chars_type: { + while (l < r) { + int i = (l + r) >> 1; + if (compareStrings(ins.charKey, ins.keyLen, + &pg->charKey[pg->strKey[i].offs], + pg->strKey[i].size) > 0) { + l = i + 1; + } else { + r = i; + } + } + if (--height != 0) { + result = + insert(db, pg->strKey[r].oid, type, ins, unique, replace, height); + assert(result != dbBtree::not_found); + if (result != dbBtree::overflow) { + db->pool.unfix(pg); + return result; + } + } else if (r < n && compareStrings(ins.charKey, ins.keyLen, + &pg->charKey[pg->strKey[r].offs], + pg->strKey[r].size) == 0) { + if (replace) { + db->pool.unfix(pg); + pg = (dbBtreePage *)db->put(tie, pageId); + pg->strKey[r].oid = ins.oid; + return dbBtree::done; + } else if (unique) { + return dbBtree::duplicate; + } + } + db->pool.unfix(pg); + pg = (dbBtreePage *)db->put(tie, pageId); + return pg->insertStrKey(db, r, ins, height); + } + } + return dbBtree::done; +} + +int dbBtreePage::insertStrKey(dbDatabase *db, int r, item &ins, int height) { + int n = height != 0 ? nItems + 1 : nItems; + // insert before e[r] + int len = ins.keyLen; + if (size + len * sizeof(char) + (n + 1) * sizeof(str) <= sizeof(charKey)) { + memmove(&strKey[r + 1], &strKey[r], (n - r) * sizeof(str)); + size += len * sizeof(char); + strKey[r].offs = db_nat2(sizeof(charKey) - size); + strKey[r].size = db_nat2(len); + strKey[r].oid = ins.oid; + memcpy(&charKey[sizeof(charKey) - size], ins.charKey, len * sizeof(char)); + nItems += 1; + } else { // page is full then divide page + oid_t pageId = db->allocatePage(); + dbBtreePage *b = (dbBtreePage *)db->put(pageId); + length_t moved = 0; + length_t inserted = len * sizeof(char) + sizeof(str); + long prevDelta = (1L << (sizeof(long) * 8 - 1)) + 1; + for (int bn = 0, i = 0;; bn += 1) { + length_t addSize, subSize; + int j = nItems - i - 1; + length_t keyLen = strKey[i].size; + if (bn == r) { + keyLen = len; + inserted = 0; + addSize = len; + if (height == 0) { + subSize = 0; + j += 1; + } else { + subSize = strKey[i].size; + } + } else { + addSize = subSize = keyLen; + if (height != 0) { + if (i + 1 != r) { + subSize += strKey[i + 1].size; + j -= 1; + } else { + inserted = 0; + } + } + } + long delta = + long(moved + addSize * sizeof(char) + (bn + 1) * sizeof(str)) - + long(j * sizeof(str) + size - subSize * sizeof(char) + inserted); + if (delta >= -prevDelta) { + char insKey[dbBtreePage::dbMaxKeyLen]; + if (bn <= r) { memcpy(insKey, ins.charKey, len * sizeof(char)); } + if (height == 0) { + memcpy(ins.charKey, (char *)&b->charKey[b->strKey[bn - 1].offs], + b->strKey[bn - 1].size); + ins.keyLen = b->strKey[bn - 1].size; + } else { + assert(((void)"String fits in the B-Tree page", + moved + (bn + 1) * sizeof(str) <= sizeof(charKey))); + if (bn != r) { + ins.keyLen = int(keyLen); + memcpy(ins.charKey, &charKey[strKey[i].offs], + keyLen * sizeof(char)); + b->strKey[bn].oid = strKey[i].oid; + size -= db_nat4(keyLen * sizeof(char)); + i += 1; + } else { + b->strKey[bn].oid = ins.oid; + } + } + compactify(i); + if (bn < r || (bn == r && height == 0)) { + memmove(&strKey[r - i + 1], &strKey[r - i], (n - r) * sizeof(str)); + size += len * sizeof(char); + nItems += 1; + assert(((void)"String fits in the B-Tree page", + size + (n - i + 1) * sizeof(str) <= sizeof(charKey))); + strKey[r - i].offs = db_nat2(sizeof(charKey) - size); + strKey[r - i].size = db_nat2(len); + strKey[r - i].oid = ins.oid; + memcpy(&charKey[strKey[r - i].offs], insKey, len * sizeof(char)); + } + b->nItems = bn; + b->size = db_nat4(moved); + ins.oid = pageId; + db->pool.unfix(b); + assert(nItems > 0 && b->nItems > 0); + return dbBtree::overflow; + } + prevDelta = delta; + moved += keyLen * sizeof(char); + assert(((void)"String fits in the B-Tree page", + moved + (bn + 1) * sizeof(str) <= sizeof(charKey))); + b->strKey[bn].size = db_nat2(keyLen); + b->strKey[bn].offs = db_nat2(sizeof(charKey) - moved); + if (bn == r) { + b->strKey[bn].oid = ins.oid; + memcpy(&b->charKey[b->strKey[bn].offs], ins.charKey, + keyLen * sizeof(char)); + } else { + b->strKey[bn].oid = strKey[i].oid; + memcpy(&b->charKey[b->strKey[bn].offs], &charKey[strKey[i].offs], + keyLen * sizeof(char)); + size -= db_nat4(keyLen * sizeof(char)); + i += 1; + } + } + } + return size + sizeof(str) * (nItems + 1) < sizeof(charKey) / 2 + ? dbBtree::underflow + : dbBtree::done; +} + +void dbBtreePage::compactify(int m) { + int i, j, offs, len, n = nItems; +#ifdef NO_LARGE_LOCAL_ARRAYS + int *size = new int[dbPageSize]; + int *index = new int[dbPageSize]; +#else + int size[dbPageSize]; + int index[dbPageSize]; +#endif + if (m == 0) { return; } + if (m < 0) { + m = -m; + for (i = 0; i < n - m; i++) { + len = strKey[i].size; + size[strKey[i].offs + len * sizeof(char)] = len; + index[strKey[i].offs + len * sizeof(char)] = i; + } + for (; i < n; i++) { + len = strKey[i].size; + size[strKey[i].offs + len * sizeof(char)] = len; + index[strKey[i].offs + len * sizeof(char)] = -1; + } + } else { + for (i = 0; i < m; i++) { + len = strKey[i].size; + size[strKey[i].offs + len * sizeof(char)] = len; + index[strKey[i].offs + len * sizeof(char)] = -1; + } + for (; i < n; i++) { + len = strKey[i].size; + size[strKey[i].offs + len * sizeof(char)] = len; + index[strKey[i].offs + len * sizeof(char)] = i - m; + strKey[i - m].oid = strKey[i].oid; + strKey[i - m].size = db_nat2(len); + } + strKey[i - m].oid = strKey[i].oid; + } + nItems = n -= m; + for (offs = sizeof(charKey), i = offs; n != 0; i -= len) { + len = size[i] * sizeof(char); + j = index[i]; + if (j >= 0) { + offs -= len; + n -= 1; + strKey[j].offs = db_nat2(offs); + if (offs != i - len) { + memmove(&charKey[offs], &charKey[(i - len)], len); + } + } + } +#ifdef NO_LARGE_LOCAL_ARRAYS + delete[] size; + delete[] index; +#endif +} + +int dbBtreePage::removeStrKey(int r) { + int len = strKey[r].size; + int offs = strKey[r].offs; + memmove(charKey + sizeof(charKey) - size + len * sizeof(char), + charKey + sizeof(charKey) - size, size - sizeof(charKey) + offs); + memcpy(&strKey[r], &strKey[r + 1], (nItems - r) * sizeof(str)); + nItems -= 1; + size -= len * sizeof(char); + for (int i = nItems; --i >= 0;) { + if (strKey[i].offs < offs) { + strKey[i].offs += db_nat2(len * sizeof(char)); + } + } + return size + sizeof(str) * (nItems + 1) < sizeof(charKey) / 2 + ? dbBtree::underflow + : dbBtree::done; +} + +int dbBtreePage::replaceStrKey(dbDatabase *db, int r, item &ins, int height) { + ins.oid = strKey[r].oid; + removeStrKey(r); + return insertStrKey(db, r, ins, height); +} + +int dbBtreePage::handlePageUnderflow(dbDatabase *db, int r, int type, item &rem, + int height) { + dbPutTie tie; + if (type == dybase_chars_type || type == dybase_bytes_type) { + dbBtreePage *a = (dbBtreePage *)db->put(tie, strKey[r].oid); + int an = a->nItems; + if (r < (int)nItems) { // exists greater page + dbBtreePage *b = (dbBtreePage *)db->get(strKey[r + 1].oid); + int bn = b->nItems; + length_t merged_size = (an + bn) * sizeof(str) + a->size + b->size; + if (height != 1) { + merged_size += strKey[r].size * sizeof(char) + sizeof(str) * 2; + } + if (merged_size > sizeof(charKey)) { + // reallocation of nodes between pages a and b + int i, j, k; + dbPutTie tie; + db->pool.unfix(b); + b = (dbBtreePage *)db->put(tie, strKey[r + 1].oid); + length_t size_a = a->size; + length_t size_b = b->size; + length_t addSize, subSize; + if (height != 1) { + addSize = strKey[r].size; + subSize = b->strKey[0].size; + } else { + addSize = subSize = b->strKey[0].size; + } + i = 0; + long prevDelta = + long(an * sizeof(str) + size_a) - long(bn * sizeof(str) + size_b); + for (;;) { + i += 1; + long delta = + long((an + i) * sizeof(str) + size_a + addSize * sizeof(char)) - + long((bn - i) * sizeof(str) + size_b - subSize * sizeof(char)); + if (delta >= 0) { + if (delta >= -prevDelta) { i -= 1; } + break; + } + size_a += addSize * sizeof(char); + size_b -= subSize * sizeof(char); + prevDelta = delta; + if (height != 1) { + addSize = subSize; + subSize = b->strKey[i].size; + } else { + addSize = subSize = b->strKey[i].size; + } + } + int result = dbBtree::done; + if (i > 0) { + k = i; + if (height != 1) { + int len = strKey[r].size; + a->size += len * sizeof(char); + a->strKey[an].offs = db_nat2(sizeof(a->charKey) - a->size); + a->strKey[an].size = db_nat2(len); + memcpy(a->charKey + a->strKey[an].offs, charKey + strKey[r].offs, + len * sizeof(char)); + k -= 1; + an += 1; + a->strKey[an + k].oid = b->strKey[k].oid; + b->size -= b->strKey[k].size * sizeof(char); + } + for (j = 0; j < k; j++) { + int len = b->strKey[j].size; + a->size += len * sizeof(char); + b->size -= len * sizeof(char); + a->strKey[an].offs = db_nat2(sizeof(a->charKey) - a->size); + a->strKey[an].size = db_nat2(len); + a->strKey[an].oid = b->strKey[j].oid; + memcpy(a->charKey + a->strKey[an].offs, + b->charKey + b->strKey[j].offs, len * sizeof(char)); + an += 1; + } + memcpy(rem.charKey, b->charKey + b->strKey[i - 1].offs, + b->strKey[i - 1].size * sizeof(char)); + rem.keyLen = b->strKey[i - 1].size; + result = replaceStrKey(db, r, rem, height); + a->nItems = an; + b->compactify(i); + } + assert(a->nItems > 0 && b->nItems > 0); + return result; + } else { // merge page b to a + if (height != 1) { + a->size += (a->strKey[an].size = strKey[r].size) * sizeof(char); + a->strKey[an].offs = db_nat2(sizeof(charKey) - a->size); + memcpy(&a->charKey[a->strKey[an].offs], &charKey[strKey[r].offs], + strKey[r].size * sizeof(char)); + an += 1; + a->strKey[an + bn].oid = b->strKey[bn].oid; + } + for (int i = 0; i < bn; i++, an++) { + a->strKey[an] = b->strKey[i]; + a->strKey[an].offs -= db_nat2(a->size); + } + a->size += b->size; + a->nItems = an; + memcpy(a->charKey + sizeof(charKey) - a->size, + b->charKey + sizeof(charKey) - b->size, b->size); + db->pool.unfix(b); + db->freePage(strKey[r + 1].oid); + strKey[r + 1].oid = strKey[r].oid; + return removeStrKey(r); + } + } else { // page b is before a + dbBtreePage *b = (dbBtreePage *)db->get(strKey[r - 1].oid); + int bn = b->nItems; + length_t merged_size = (an + bn) * sizeof(str) + a->size + b->size; + if (height != 1) { + merged_size += strKey[r - 1].size * sizeof(char) + sizeof(str) * 2; + } + if (merged_size > sizeof(charKey)) { + // reallocation of nodes between pages a and b + dbPutTie tie; + int i, j, k; + db->pool.unfix(b); + b = (dbBtreePage *)db->put(tie, strKey[r - 1].oid); + length_t size_a = a->size; + length_t size_b = b->size; + length_t addSize, subSize; + if (height != 1) { + addSize = strKey[r - 1].size; + subSize = b->strKey[bn - 1].size; + } else { + addSize = subSize = b->strKey[bn - 1].size; + } + i = 0; + long prevDelta = + long(an * sizeof(str) + size_a) - long(bn * sizeof(str) + size_b); + for (;;) { + i += 1; + long delta = + long((an + i) * sizeof(str) + size_a + addSize * sizeof(char)) - + long((bn - i) * sizeof(str) + size_b - subSize * sizeof(char)); + if (delta >= 0) { + if (delta >= -prevDelta) { i -= 1; } + break; + } + prevDelta = delta; + size_a += addSize * sizeof(char); + size_b -= subSize * sizeof(char); + if (height != 1) { + addSize = subSize; + subSize = b->strKey[bn - i - 1].size; + } else { + addSize = subSize = b->strKey[bn - i - 1].size; + } + } + int result = dbBtree::done; + if (i > 0) { + k = i; + assert(i < bn); + if (height != 1) { + memmove(&a->strKey[i], a->strKey, (an + 1) * sizeof(str)); + b->size -= b->strKey[bn - k].size * sizeof(char); + k -= 1; + a->strKey[k].oid = b->strKey[bn].oid; + int len = strKey[r - 1].size; + a->strKey[k].size = db_nat2(len); + a->size += len * lengthof(char); + a->strKey[k].offs = db_nat2(sizeof(charKey) - a->size); + memcpy(&a->charKey[a->strKey[k].offs], &charKey[strKey[r - 1].offs], + len * sizeof(char)); + } else { + memmove(&a->strKey[i], a->strKey, an * sizeof(str)); + } + for (j = 0; j < k; j++) { + int len = b->strKey[bn - k + j].size; + a->size += len * sizeof(char); + b->size -= len * sizeof(char); + a->strKey[j].offs = db_nat2(sizeof(a->charKey) - a->size); + a->strKey[j].size = db_nat2(len); + a->strKey[j].oid = b->strKey[bn - k + j].oid; + memcpy(a->charKey + a->strKey[j].offs, + b->charKey + b->strKey[bn - k + j].offs, len * sizeof(char)); + } + an += i; + a->nItems = an; + memcpy(rem.charKey, b->charKey + b->strKey[bn - k - 1].offs, + b->strKey[bn - k - 1].size * sizeof(char)); + rem.keyLen = b->strKey[bn - k - 1].size; + result = replaceStrKey(db, r - 1, rem, height); + b->compactify(-i); + } + assert(a->nItems > 0 && b->nItems > 0); + return result; + } else { // merge page b to a + if (height != 1) { + memmove(a->strKey + bn + 1, a->strKey, (an + 1) * sizeof(str)); + a->size += (a->strKey[bn].size = strKey[r - 1].size) * sizeof(char); + a->strKey[bn].offs = db_nat2(sizeof(charKey) - a->size); + a->strKey[bn].oid = b->strKey[bn].oid; + memcpy(&a->charKey[a->strKey[bn].offs], &charKey[strKey[r - 1].offs], + strKey[r - 1].size * sizeof(char)); + an += 1; + } else { + memmove(a->strKey + bn, a->strKey, an * sizeof(str)); + } + for (int i = 0; i < bn; i++) { + a->strKey[i] = b->strKey[i]; + a->strKey[i].offs -= db_nat2(a->size); + } + an += bn; + a->nItems = an; + a->size += b->size; + memcpy(a->charKey + sizeof(charKey) - a->size, + b->charKey + sizeof(charKey) - b->size, b->size); + db->pool.unfix(b); + db->freePage(strKey[r - 1].oid); + return removeStrKey(r - 1); + } + } + } else { + dbBtreePage *a = (dbBtreePage *)db->put(tie, record[maxItems - r - 1]); + length_t sizeofType = dbSizeofType[type]; + int an = a->nItems; + if (r < int(nItems)) { // exists greater page + dbBtreePage *b = (dbBtreePage *)db->get(record[maxItems - r - 2]); + int bn = b->nItems; + assert(bn >= an); + if (height != 1) { + memcpy(a->charKey + an * sizeofType, charKey + r * sizeofType, + sizeofType); + an += 1; + bn += 1; + } + length_t merged_size = (an + bn) * (sizeof(oid_t) + sizeofType); + if (merged_size > sizeof(charKey)) { + // reallocation of nodes between pages a and b + int i = bn - ((an + bn) >> 1); + dbPutTie tie; + db->pool.unfix(b); + b = (dbBtreePage *)db->put(tie, record[maxItems - r - 2]); + memcpy(a->charKey + an * sizeofType, b->charKey, i * sizeofType); + memcpy(b->charKey, b->charKey + i * sizeofType, (bn - i) * sizeofType); + memcpy(&a->record[maxItems - an - i], &b->record[maxItems - i], + i * sizeof(oid_t)); + memmove(&b->record[maxItems - bn + i], &b->record[maxItems - bn], + (bn - i) * sizeof(oid_t)); + memcpy(charKey + r * sizeofType, a->charKey + (an + i - 1) * sizeofType, + sizeofType); + b->nItems -= i; + a->nItems += i; + return dbBtree::done; + } else { // merge page b to a + memcpy(a->charKey + an * sizeofType, b->charKey, bn * sizeofType); + memcpy(&a->record[maxItems - an - bn], &b->record[maxItems - bn], + bn * sizeof(oid_t)); + db->pool.unfix(b); + db->freePage(record[maxItems - r - 2]); + memmove(&record[maxItems - nItems], &record[maxItems - nItems - 1], + (nItems - r - 1) * sizeof(oid_t)); + memcpy(charKey + r * sizeofType, charKey + (r + 1) * sizeofType, + (nItems - r - 1) * sizeofType); + a->nItems += bn; + nItems -= 1; + return (nItems + 1) * (sizeofType + sizeof(oid_t)) < sizeof(charKey) / 2 + ? dbBtree::underflow + : dbBtree::done; + } + } else { // page b is before a + dbBtreePage *b = (dbBtreePage *)db->get(record[maxItems - r]); + int bn = b->nItems; + assert(bn >= an); + if (height != 1) { + an += 1; + bn += 1; + } + length_t merged_size = (an + bn) * (sizeof(oid_t) + sizeofType); + if (merged_size > sizeof(charKey)) { + // reallocation of nodes between pages a and b + int i = bn - ((an + bn) >> 1); + dbPutTie tie; + db->pool.unfix(b); + b = (dbBtreePage *)db->put(tie, record[maxItems - r]); + memmove(a->charKey + i * sizeofType, a->charKey, an * sizeofType); + memcpy(a->charKey, b->charKey + (bn - i) * sizeofType, i * sizeofType); + memcpy(&a->record[maxItems - an - i], &a->record[maxItems - an], + an * sizeof(oid_t)); + memcpy(&a->record[maxItems - i], &b->record[maxItems - bn], + i * sizeof(oid_t)); + if (height != 1) { + memcpy(a->charKey + (i - 1) * sizeofType, + charKey + (r - 1) * sizeofType, sizeofType); + } + memcpy(charKey + (r - 1) * sizeofType, + b->charKey + (bn - i - 1) * sizeofType, sizeofType); + b->nItems -= i; + a->nItems += i; + return dbBtree::done; + } else { // merge page b to a + memmove(a->charKey + bn * sizeofType, a->charKey, an * sizeofType); + memcpy(a->charKey, b->charKey, bn * sizeofType); + memcpy(&a->record[maxItems - an - bn], &a->record[maxItems - an], + an * sizeof(oid_t)); + memcpy(&a->record[maxItems - bn], &b->record[maxItems - bn], + bn * sizeof(oid_t)); + if (height != 1) { + memcpy(a->charKey + (bn - 1) * sizeofType, + charKey + (r - 1) * sizeofType, sizeofType); + } + db->pool.unfix(b); + db->freePage(record[maxItems - r]); + record[maxItems - r] = record[maxItems - r - 1]; + a->nItems += bn; + nItems -= 1; + return (nItems + 1) * (sizeofType + sizeof(oid_t)) < sizeof(charKey) / 2 + ? dbBtree::underflow + : dbBtree::done; + } + } + } +} + +#define REMOVE(KEY, TYPE) \ + { \ + TYPE key = rem.KEY; \ + while (l < r) { \ + i = (l + r) >> 1; \ + if (key > pg->KEY[i]) \ + l = i + 1; \ + else \ + r = i; \ + } \ + if (--height == 0) { \ + oid_t oid = rem.oid; \ + while (r < n) { \ + if (key == pg->KEY[r]) { \ + if (pg->record[maxItems - r - 1] == oid || oid == 0) { \ + db->pool.unfix(pg); \ + pg = (dbBtreePage *)db->put(tie, pageId); \ + memcpy(&pg->KEY[r], &pg->KEY[r + 1], (n - r - 1) * sizeof(TYPE)); \ + memmove(&pg->record[maxItems - n + 1], &pg->record[maxItems - n], \ + (n - r - 1) * sizeof(oid_t)); \ + pg->nItems = --n; \ + return n * (sizeof(TYPE) + sizeof(oid_t)) < \ + sizeof(pg->charKey) / 2 \ + ? dbBtree::underflow \ + : dbBtree::done; \ + } \ + } else { \ + break; \ + } \ + r += 1; \ + } \ + db->pool.unfix(pg); \ + return dbBtree::not_found; \ + } \ + break; \ + \ +} + +int dbBtreePage::remove(dbDatabase *db, oid_t pageId, int type, item &rem, + int height) { + dbBtreePage *pg = (dbBtreePage *)db->get(pageId); + dbPutTie tie; + int i, n = pg->nItems, l = 0, r = n; + + switch (type) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: REMOVE(refKey, oid_t); + case dybase_bool_type: REMOVE(boolKey, db_int1); + case dybase_int_type: REMOVE(intKey, db_int4); + case dybase_date_type: + case dybase_long_type: REMOVE(longKey, db_int8); + case dybase_real_type: REMOVE(realKey, db_real8); + case dybase_bytes_type: + case dybase_chars_type: { + while (l < r) { + i = (l + r) >> 1; + if (compareStrings(rem.charKey, rem.keyLen, + &pg->charKey[pg->strKey[i].offs], + pg->strKey[i].size) > 0) { + l = i + 1; + } else { + r = i; + } + } + if (--height != 0) { + do { + switch (remove(db, pg->strKey[r].oid, type, rem, height)) { + case dbBtree::underflow: + db->pool.unfix(pg); + pg = (dbBtreePage *)db->put(tie, pageId); + return pg->handlePageUnderflow(db, r, type, rem, height); + case dbBtree::done: db->pool.unfix(pg); return dbBtree::done; + case dbBtree::overflow: + db->pool.unfix(pg); + pg = (dbBtreePage *)db->put(tie, pageId); + return pg->insertStrKey(db, r, rem, height); + } + } while (++r <= n); + } else { + while (r < n) { + if (compareStrings(rem.charKey, rem.keyLen, + &pg->charKey[pg->strKey[r].offs], + pg->strKey[r].size) == 0) { + if (pg->strKey[r].oid == rem.oid || rem.oid == 0) { + db->pool.unfix(pg); + pg = (dbBtreePage *)db->put(tie, pageId); + return pg->removeStrKey(r); + } + } else { + break; + } + r += 1; + } + } + db->pool.unfix(pg); + return dbBtree::not_found; + } + default: assert(false); + } + do { + switch (remove(db, pg->record[maxItems - r - 1], type, rem, height)) { + case dbBtree::underflow: + db->pool.unfix(pg); + pg = (dbBtreePage *)db->put(tie, pageId); + return pg->handlePageUnderflow(db, r, type, rem, height); + case dbBtree::done: db->pool.unfix(pg); return dbBtree::done; + } + } while (++r <= n); + + db->pool.unfix(pg); + return dbBtree::not_found; +} + +void dbBtreePage::purge(dbDatabase *db, oid_t pageId, int type, int height) { + if (--height != 0) { + dbBtreePage *pg = (dbBtreePage *)db->get(pageId); + int n = pg->nItems + 1; + if (type == dybase_chars_type || type == dybase_bytes_type) { // page of strings + while (--n >= 0) { + purge(db, pg->strKey[n].oid, type, height); + } + } else { + while (--n >= 0) { + purge(db, pg->record[maxItems - n - 1], type, height); + } + } + db->pool.unfix(pg); + } + db->freePage(pageId); +} + +void dbBtreePage::markPage(dbDatabase *db, oid_t pageId, int type, int height) { + dbBtreePage *pg = + (dbBtreePage *)db->pool.get(db->getGCPos(pageId) & ~dbPageObjectFlag); + int i, n = pg->nItems; + if (--height != 0) { + if (type == dybase_chars_type || type == dybase_bytes_type) { // page of strings + for (i = 0; i <= n; i++) { + markPage(db, pg->strKey[i].oid, type, height); + } + } else { + for (i = 0; i <= n; i++) { + markPage(db, pg->record[maxItems - i - 1], type, height); + } + } + } else { + if (type != dybase_chars_type && type != dybase_bytes_type) { // page of scalars + for (i = 0; i < n; i++) { + db->markOid(pg->record[maxItems - i - 1]); + } + } else { // page of strings + for (i = 0; i < n; i++) { + db->markOid(pg->strKey[i].oid); + } + } + } + db->pool.unfix(pg); +} + +int dbBtreeIterator::compare(void *key, int keyType, dbBtreePage *pg, int pos) { + switch (keyType) { + case dybase_bool_type: return *(db_int1 *)key - pg->boolKey[pos]; + case dybase_int_type: return *(db_int4 *)key - pg->intKey[pos]; + case dybase_date_type: + case dybase_long_type: + return *(db_int8 *)key < pg->longKey[pos] + ? -1 + : *(db_int8 *)key == pg->longKey[pos] ? 0 : 1; + case dybase_real_type: + return *(db_real8 *)key < pg->realKey[pos] + ? -1 + : *(db_real8 *)key == pg->realKey[pos] ? 0 : 1; + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: return *(oid_t *)key - pg->refKey[pos]; + } + return 0; +} + +int dbBtreeIterator::compareStr(void *key, length_t keyLength, dbBtreePage *pg, + int pos) { + return compareStrings(key, keyLength, &pg->charKey[pg->strKey[pos].offs], + pg->strKey[pos].size); +} + +dbBtreeIterator::dbBtreeIterator(dbDatabase *db, oid_t treeId, int type, + void *from, length_t fromLength, + int fromInclusion, void *till, + length_t tillLength, int tillInclusion, + bool ascent) { + int l, r, i; + dbGetTie tie; + dbBtree *tree = (dbBtree *)db->getObject(tie, treeId); + sp = 0; + + if (tree->height == 0) { return; } + + if (type != tree->type) { + if (from != NULL || till != NULL) { + db->throwException(dybase_bad_key_type, + "Type of the key doesn't match index type"); + } else { + type = tree->type; + } + } + dbBtreePage *pg; + this->db = db; + this->from = from; + this->till = till; + this->fromLength = fromLength; + this->tillLength = tillLength; + this->fromInclusion = fromInclusion; + this->tillInclusion = tillInclusion; + this->type = type; + this->ascent = ascent; + this->height = tree->height; + int height = tree->height; + + if (from != NULL) { + switch (type) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: + from_val.refKey = *(oid_t *)from; + this->from = &from_val.refKey; + break; + case dybase_bool_type: + from_val.boolKey = *(db_int1 *)from; + this->from = &from_val.boolKey; + break; + case dybase_int_type: + from_val.intKey = *(db_int4 *)from; + this->from = &from_val.intKey; + break; + case dybase_date_type: + case dybase_long_type: + from_val.longKey = *(db_int8 *)from; + this->from = &from_val.longKey; + break; + case dybase_real_type: + from_val.realKey = *(db_real8 *)from; + this->from = &from_val.realKey; + break; + } + } + if (till != NULL) { + switch (type) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: + till_val.refKey = *(oid_t *)till; + this->till = &till_val.refKey; + break; + case dybase_bool_type: + till_val.boolKey = *(db_int1 *)till; + this->till = &till_val.boolKey; + break; + case dybase_int_type: + till_val.intKey = *(db_int4 *)till; + this->till = &till_val.intKey; + break; + case dybase_date_type: + case dybase_long_type: + till_val.longKey = *(db_int8 *)till; + this->till = &till_val.longKey; + break; + case dybase_real_type: + till_val.realKey = *(db_real8 *)till; + this->till = &till_val.realKey; + break; + } + } + + int pageId = tree->root; + + if (type == dybase_chars_type || type == dybase_bytes_type) { + if (ascent) { + if (from == NULL) { + while (--height >= 0) { + posStack[sp] = 0; + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + pageId = pg->strKey[0].oid; + end = pg->nItems; + db->pool.unfix(pg); + sp += 1; + } + } else { + while (--height > 0) { + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + l = 0; + r = pg->nItems; + while (l < r) { + i = (l + r) >> 1; + if (compareStr(from, fromLength, pg, i) >= fromInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + posStack[sp] = r; + pageId = pg->strKey[r].oid; + db->pool.unfix(pg); + sp += 1; + } + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + l = 0; + end = r = pg->nItems; + while (l < r) { + i = (l + r) >> 1; + if (compareStr(from, fromLength, pg, i) >= fromInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + if (r == end) { + sp += 1; + gotoNextItem(pg, r - 1); + } else { + posStack[sp++] = r; + db->pool.unfix(pg); + } + } + if (sp != 0 && till != NULL) { + pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + if (-compareStr(till, tillLength, pg, posStack[sp - 1]) >= + tillInclusion) { + sp = 0; + } + db->pool.unfix(pg); + } + } else { // descent order + if (till == NULL) { + while (--height > 0) { + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + posStack[sp] = pg->nItems; + pageId = pg->strKey[posStack[sp]].oid; + db->pool.unfix(pg); + sp += 1; + } + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + posStack[sp++] = pg->nItems - 1; + db->pool.unfix(pg); + } else { + while (--height > 0) { + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + l = 0; + r = pg->nItems; + while (l < r) { + i = (l + r) >> 1; + if (compareStr(till, tillLength, pg, i) >= 1 - tillInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + posStack[sp] = r; + pageId = pg->strKey[r].oid; + db->pool.unfix(pg); + sp += 1; + } + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + l = 0; + r = pg->nItems; + while (l < r) { + i = (l + r) >> 1; + if (compareStr(till, tillLength, pg, i) >= 1 - tillInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + if (r == 0) { + sp += 1; + gotoNextItem(pg, r); + } else { + posStack[sp++] = r - 1; + db->pool.unfix(pg); + } + } + if (sp != 0 && from != NULL) { + pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + if (compareStr(from, fromLength, pg, posStack[sp - 1]) >= + fromInclusion) { + sp = 0; + } + db->pool.unfix(pg); + } + } + } else { // scalar type + if (ascent) { + if (from == NULL) { + while (--height >= 0) { + posStack[sp] = 0; + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + pageId = pg->record[dbBtreePage::maxItems - 1]; + end = pg->nItems; + db->pool.unfix(pg); + sp += 1; + } + } else { + while (--height > 0) { + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + l = 0; + r = pg->nItems; + while (l < r) { + i = (l + r) >> 1; + if (compare(from, type, pg, i) >= fromInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + posStack[sp] = r; + pageId = pg->record[dbBtreePage::maxItems - 1 - r]; + db->pool.unfix(pg); + sp += 1; + } + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + l = 0; + r = end = pg->nItems; + while (l < r) { + i = (l + r) >> 1; + if (compare(from, type, pg, i) >= fromInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + if (r == end) { + sp += 1; + gotoNextItem(pg, r - 1); + } else { + posStack[sp++] = r; + db->pool.unfix(pg); + } + } + if (sp != 0 && till != NULL) { + pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + if (-compare(till, type, pg, posStack[sp - 1]) >= tillInclusion) { + sp = 0; + } + db->pool.unfix(pg); + } + } else { // descent order + if (till == NULL) { + while (--height > 0) { + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + posStack[sp] = pg->nItems; + pageId = pg->record[dbBtreePage::maxItems - 1 - posStack[sp]]; + db->pool.unfix(pg); + sp += 1; + } + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + posStack[sp++] = pg->nItems - 1; + db->pool.unfix(pg); + } else { + while (--height > 0) { + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + l = 0; + r = pg->nItems; + while (l < r) { + i = (l + r) >> 1; + if (compare(till, type, pg, i) >= 1 - tillInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + posStack[sp] = r; + pageId = pg->record[dbBtreePage::maxItems - 1 - r]; + db->pool.unfix(pg); + sp += 1; + } + pageStack[sp] = pageId; + pg = (dbBtreePage *)db->get(pageId); + l = 0; + r = pg->nItems; + while (l < r) { + i = (l + r) >> 1; + if (compare(till, type, pg, i) >= 1 - tillInclusion) { + l = i + 1; + } else { + r = i; + } + } + assert(r == l); + if (r == 0) { + sp += 1; + gotoNextItem(pg, r); + } else { + posStack[sp++] = r - 1; + db->pool.unfix(pg); + } + } + if (sp != 0 && from != NULL) { + pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + if (compare(from, type, pg, posStack[sp - 1]) >= fromInclusion) { + sp = 0; + } + db->pool.unfix(pg); + } + } + } +} + +oid_t dbBtreeIterator::next() { + if (sp == 0) { return 0; } + int pos = posStack[sp - 1]; + dbBtreePage *pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + oid_t oid = (type == dybase_chars_type || type == dybase_bytes_type) + ? pg->strKey[pos].oid + : pg->record[dbBtreePage::maxItems - 1 - pos]; + gotoNextItem(pg, pos); + return oid; +} + +void dbBtreeIterator::gotoNextItem(dbBtreePage *pg, int pos) { + oid_t pageId; + if (type == dybase_chars_type || type == dybase_bytes_type) { + if (ascent) { + if (++pos == end) { + while (--sp != 0) { + db->pool.unfix(pg); + pos = posStack[sp - 1]; + pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + if (++pos <= (int)pg->nItems) { + posStack[sp - 1] = pos; + do { + pageId = pg->strKey[pos].oid; + db->pool.unfix(pg); + pg = (dbBtreePage *)db->get(pageId); + end = pg->nItems; + pageStack[sp] = pageId; + posStack[sp] = pos = 0; + } while (++sp < height); + break; + } + } + } else { + posStack[sp - 1] = pos; + } + if (sp != 0 && till != NULL && + -compareStr(till, tillLength, pg, pos) >= tillInclusion) { + sp = 0; + } + } else { // descent order + if (--pos < 0) { + while (--sp != 0) { + db->pool.unfix(pg); + pos = posStack[sp - 1]; + pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + if (--pos >= 0) { + posStack[sp - 1] = pos; + do { + pageId = pg->strKey[pos].oid; + db->pool.unfix(pg); + pg = (dbBtreePage *)db->get(pageId); + pageStack[sp] = pageId; + posStack[sp] = pos = pg->nItems; + } while (++sp < height); + posStack[sp - 1] = --pos; + break; + } + } + } else { + posStack[sp - 1] = pos; + } + if (sp != 0 && from != NULL && + compareStr(from, fromLength, pg, pos) >= fromInclusion) { + sp = 0; + } + } + } else { // scalar type + if (ascent) { + if (++pos == end) { + while (--sp != 0) { + db->pool.unfix(pg); + pos = posStack[sp - 1]; + pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + if (++pos <= (int)pg->nItems) { + posStack[sp - 1] = pos; + do { + pageId = pg->record[dbBtreePage::maxItems - 1 - pos]; + db->pool.unfix(pg); + pg = (dbBtreePage *)db->get(pageId); + end = pg->nItems; + pageStack[sp] = pageId; + posStack[sp] = pos = 0; + } while (++sp < height); + break; + } + } + } else { + posStack[sp - 1] = pos; + } + if (sp != 0 && till != NULL && + -compare(till, type, pg, pos) >= tillInclusion) { + sp = 0; + } + } else { // descent order + if (--pos < 0) { + while (--sp != 0) { + db->pool.unfix(pg); + pos = posStack[sp - 1]; + pg = (dbBtreePage *)db->get(pageStack[sp - 1]); + if (--pos >= 0) { + posStack[sp - 1] = pos; + do { + pageId = pg->record[dbBtreePage::maxItems - 1 - pos]; + db->pool.unfix(pg); + pg = (dbBtreePage *)db->get(pageId); + pageStack[sp] = pageId; + posStack[sp] = pos = pg->nItems; + } while (++sp < height); + posStack[sp - 1] = --pos; + break; + } + } + } else { + posStack[sp - 1] = pos; + } + if (sp != 0 && from != NULL && + compare(from, type, pg, pos) >= fromInclusion) { + sp = 0; + } + } + } + db->pool.unfix(pg); +} diff --git a/storage/dybase/src/btree.h b/storage/dybase/src/btree.h new file mode 100644 index 000000000..808d28659 --- /dev/null +++ b/storage/dybase/src/btree.h @@ -0,0 +1,162 @@ +//-< BTREE.CPP >-----------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 1-Jan-99 K.A. Knizhnik * / [] \ * +// Last update: 25-Oct-99 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// B-Tree interface +//-------------------------------------------------------------------*--------* + +#ifndef __BTREE_H__ +#define __BTREE_H__ + +#include "buffer.h" + +class dbSearchContext { +public: + void * low; + length_t lowSize; + int lowInclusive; + void * high; + length_t highSize; + int highInclusive; + int keyType; + dbBuffer selection; +}; + +class dbBtreePage { +public: + db_nat4 nItems; + db_nat4 size; + + struct str { + oid_t oid; + db_nat2 size; + db_nat2 offs; + }; + + enum { dbMaxKeyLen = (dbPageSize - sizeof(str) * 2) / sizeof(char) / 2 }; + + struct item { + oid_t oid; + int keyLen; + union { + db_int1 boolKey; + db_int4 intKey; + db_int8 longKey; + oid_t refKey; + db_real8 realKey; + char charKey[dbMaxKeyLen]; + }; + }; + enum { maxItems = (dbPageSize - 8) / sizeof(oid_t) }; + + union { + oid_t record[maxItems]; + oid_t refKey[(dbPageSize - 8) / sizeof(oid_t)]; + db_int4 intKey[(dbPageSize - 8) / sizeof(db_int4)]; + db_int8 longKey[(dbPageSize - 8) / sizeof(db_int8)]; + db_real8 realKey[(dbPageSize - 8) / sizeof(db_real8)]; + db_int1 boolKey[dbPageSize - 8]; + char charKey[dbPageSize - 8]; + str strKey[1]; + }; + + static oid_t allocate(dbDatabase *db, oid_t root, int type, item &ins); + + static int insert(dbDatabase *db, oid_t pageId, int type, item &ins, + bool unique, bool replace, int height); + static int remove(dbDatabase *db, oid_t pageId, int type, item &rem, + int height); + + static void markPage(dbDatabase *db, oid_t pageId, int type, int height); + + static void purge(dbDatabase *db, oid_t pageId, int type, int height); + + int insertStrKey(dbDatabase *db, int r, item &ins, int height); + int replaceStrKey(dbDatabase *db, int r, item &ins, int height); + int removeStrKey(int r); + void compactify(int m); + + int handlePageUnderflow(dbDatabase *db, int r, int type, item &rem, + int height); + + bool find(dbDatabase *db, dbSearchContext &sc, int height); +}; + +class dbBtree : public dbObject { + friend class dbDatabase; + friend class dbBtreeIterator; + +protected: + oid_t root; + db_int4 height; + db_int4 type; + db_int4 flags; + db_int4 unique; + + static bool packItem(dbDatabase *db, dbBtree *tree, dbBtreePage::item &it, + void *key, int keyType, length_t keySize, oid_t oid); + + static void _drop(dbDatabase *db, oid_t treeId); + static void _clear(dbDatabase *db, oid_t treeId); + +public: + enum OperationEffect { done, overflow, underflow, duplicate, not_found }; + + static oid_t allocate(dbDatabase *db, int type, bool unique); + static void find(dbDatabase *db, oid_t treeId, dbSearchContext &sc); + static bool insert(dbDatabase *db, oid_t treeId, void *key, int keyType, + length_t keySize, oid_t oid, bool replace); + static bool remove(dbDatabase *db, oid_t treeId, void *key, int keyType, + length_t keySize, oid_t oid); + static void drop(dbDatabase *db, oid_t treeId); + static void clear(dbDatabase *db, oid_t treeId); + static bool is_unique(dbDatabase *db, oid_t treeId); + static int get_type(dbDatabase *db, oid_t treeId); + + void markTree(dbDatabase *db) { + if (root != 0) { dbBtreePage::markPage(db, root, type, height); } + } +}; + +class dbBtreeIterator { +public: + dbBtreeIterator(dbDatabase *db, oid_t treeId, int keyType, void *from, + length_t fromLength, int fromInclusion, void *till, + length_t tillLength, int tillInclusion, bool ascent); + oid_t next(); + +private: + void gotoNextItem(dbBtreePage *pg, int pos); + static int compare(void *key, int keyType, dbBtreePage *pg, int pos); + static int compareStr(void *key, length_t keyLength, dbBtreePage *pg, + int pos); + + enum { MaxTreeHeight = 8 }; + + dbDatabase *db; + int height; + int type; + int sp; + int end; + union { + db_int1 boolKey; + db_int4 intKey; + db_int8 longKey; + oid_t refKey; + db_real8 realKey; + } from_val, till_val; + void * from; + void * till; + length_t fromLength; + length_t tillLength; + int fromInclusion; + int tillInclusion; + bool ascent; + oid_t pageStack[MaxTreeHeight]; + int posStack[MaxTreeHeight]; +}; + +#endif diff --git a/storage/dybase/src/buffer.h b/storage/dybase/src/buffer.h new file mode 100644 index 000000000..bb5eabd6c --- /dev/null +++ b/storage/dybase/src/buffer.h @@ -0,0 +1,88 @@ + +#ifndef __BUFFER_H__ +#define __BUFFER_H__ + +template class dbSmallBuffer { +private: + T buf[initSize]; + length_t used; + T * ptr; + length_t allocated; + +public: + dbSmallBuffer() { + ptr = buf; + used = 0; + allocated = initSize; + } + + ~dbSmallBuffer() { + if (ptr != buf) { delete[] ptr; } + } + + T *base() { return ptr; } + + length_t size() { return used; } + + T *append(int n) { + if (n + used > allocated) { + length_t newSize = n + used > allocated * 2 ? n + used : allocated * 2; + T * newBuf = new T[newSize]; + for (int i = int(used); --i >= 0;) { + newBuf[i] = ptr[i]; + } + if (ptr != buf) { delete[] ptr; } + ptr = newBuf; + allocated = newSize; + } + T *p = ptr + used; + used += n; + return p; + } +}; + +template class dbBuffer { +private: + length_t used; + T * ptr; + length_t allocated; + +public: + dbBuffer() { + ptr = NULL; + used = 0; + allocated = 0; + } + + ~dbBuffer() { delete[] ptr; } + + T *base() { return ptr; } + + T *grab() { + T *p = ptr; + ptr = NULL; + return p; + } + + length_t size() { return used; } + + void add(T val) { *append(1) = val; } + + T *append(int n) { + if (n + used > allocated) { + length_t newSize = n + used > allocated * 2 ? n + used : allocated * 2; + T * newBuf = new T[newSize]; + for (int i = int(used); --i >= 0;) { + newBuf[i] = ptr[i]; + } + delete[] ptr; + ptr = newBuf; + allocated = newSize; + } + T *p = ptr + used; + used += n; + return p; + } +}; + +#endif diff --git a/storage/dybase/src/database.cpp b/storage/dybase/src/database.cpp new file mode 100644 index 000000000..2bf0ebdf4 --- /dev/null +++ b/storage/dybase/src/database.cpp @@ -0,0 +1,1444 @@ +//-< DATABASE.CPP >--------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 20-Nov-1998 K.A. Knizhnik * / [] \ * +// Last update: 23-Nov-2001 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// Database memory management, query execution, scheme evaluation +//-------------------------------------------------------------------*--------* + +#include "stdtp.h" +#include "database.h" +#include "btree.h" + +void dbDatabase::handleError(int error, char const *msg) { + if (errorHandler != NULL) { + (*errorHandler)(error, msg); + } else { + fprintf(stderr, "Error %d: %s\n", error, msg); + } +} + +void dbDatabase::throwException(int error, char const *msg) { + handleError(error, msg); + throw dbException(error, msg); +} + +//bool dbDatabase::open(const wchar_t *name, int openAttr) { + //return open(cvt::w2a(name), openAttr); +//} + +bool dbDatabase::open(const char *name, int openAttr) { + dbCriticalSection cs(mutex); + int rc; + opened = false; + + length_t indexSize = + initIndexSize < dbFirstUserId ? length_t(dbFirstUserId) : initIndexSize; + indexSize = DOALIGN(indexSize, dbHandlesPerPage); + + memset(dirtyPagesMap, 0, dbDirtyPageBitmapSize + 4); + + for (int i = dbBitmapId + dbBitmapPages; --i >= 0;) { + bitmapPageAvailableSpace[i] = INT_MAX; + } + currRBitmapPage = currPBitmapPage = dbBitmapId; + currRBitmapOffs = currPBitmapOffs = 0; + reservedChain = NULL; + classDescList = NULL; + gcThreshold = 0; + allocatedDelta = 0; + gcDone = false; + modified = false; + + if (accessType == dbReadOnly) { openAttr |= dbFile::read_only; } + if (*name == L'@') { + // char fn[1024]; + // wcstombs ( fn, name+1, 1024 ); + FILE *f = fopen(name, "r"); + if (f == NULL) { + handleError(dybase_open_error, + "Failed to open database configuration file"); + return false; + } + dbMultiFile::dbSegment segment[dbMaxFileSegments]; + const int maxFileNameLen = 1024; + char fileName[maxFileNameLen]; + int i, n; + db_int8 size; + bool raid = false; + length_t raidBlockSize = dbDefaultRaidBlockSize; + for (i = 0; (n = fscanf(f, "%s" INT8_FORMAT, fileName, &size)) >= 1; i++) { + if (i == dbMaxFileSegments) { + while (--i >= 0) + delete[] segment[i].name; + fclose(f); + handleError(dybase_open_error, "Too much segments"); + return false; + } + + if (n == 1) { + if (i == 0) { + raid = true; + } else if (!raid && segment[i - 1].size == 0) { + while (--i >= 0) + delete[] segment[i].name; + fclose(f); + handleError(dybase_open_error, "Segment size was not specified"); + return false; + } + size = 0; + } else if (size == 0 || raid) { + while (--i >= 0) + delete[] segment[i].name; + fclose(f); + handleError(dybase_open_error, + size == 0 + ? "Invalid segment size" + : "segment size should not be specified for raid"); + return false; + } + + if (strcmp(fileName, ".RaidBlockSize") == 0) { + raidBlockSize = (length_t)size; + raid = true; + i -= 1; + continue; + } + segment[i].size = offs_t(size); + char * suffix = strchr(fileName, '['); + db_int8 offs = 0; + if (suffix != NULL) { + *suffix = '\0'; + sscanf(suffix + 1, INT8_FORMAT, &offs); + } + segment[i].name = new char[strlen(fileName) + 1]; + strcpy(segment[i].name, fileName); + segment[i].offs = offs_t(offs); + } + fclose(f); + if (i == 0) { + // fclose(f); + handleError(dybase_open_error, "File should have at least one segment"); + return false; + } + if (i == 1 && raid) { raid = false; } + dbMultiFile *mfile; + if (raid) { + mfile = new dbRaidFile(raidBlockSize); + } else { + mfile = new dbMultiFile; + } + rc = mfile->open(i, segment, openAttr); + while (--i >= 0) + delete[] segment[i].name; + if (rc != dbFile::ok) { + delete mfile; + handleError(dybase_open_error, "Failed to create database file"); + return false; + } + file = mfile; + } else { + file = new dbFile; + if (file->open(name, openAttr) != dbFile::ok) { + delete file; + handleError(dybase_open_error, "Failed to create database file"); + return false; + } + } + memset(header, 0, sizeof(dbHeader)); + rc = file->read(0, header, dbPageSize); + if (rc != dbFile::ok && rc != dbFile::eof) { + delete file; + handleError(dybase_open_error, "Failed to read file header"); + return false; + } + + if ((unsigned)header->curr > 1) { + delete file; + handleError(dybase_open_error, + "Database file was corrupted: invalid root index"); + return false; + } + if (!header->isInitialized()) { + if (accessType == dbReadOnly) { + delete file; + handleError(dybase_open_error, + "Can not open uninitialized file in read only mode"); + return false; + } + curr = header->curr = 0; + length_t used = dbPageSize; + header->root[0].index = used; + header->root[0].indexSize = indexSize; + header->root[0].indexUsed = dbFirstUserId; + header->root[0].freeList = 0; + header->root[0].classDescList = 0; + header->root[0].rootObject = 0; + used += indexSize * sizeof(offs_t); + header->root[1].index = used; + header->root[1].indexSize = indexSize; + header->root[1].indexUsed = dbFirstUserId; + header->root[1].freeList = 0; + header->root[1].classDescList = 0; + header->root[1].rootObject = 0; + used += indexSize * sizeof(offs_t); + + header->root[0].shadowIndex = header->root[1].index; + header->root[1].shadowIndex = header->root[0].index; + header->root[0].shadowIndexSize = indexSize; + header->root[1].shadowIndexSize = indexSize; + + length_t bitmapPages = + (used + dbPageSize * (dbAllocationQuantum * 8 - 1) - 1) / + (dbPageSize * (dbAllocationQuantum * 8 - 1)); + length_t bitmapSize = bitmapPages * dbPageSize; + length_t usedBitmapSize = (used + bitmapSize) / (dbAllocationQuantum * 8); + byte * bitmap = (byte *)dbFile::allocateBuffer(bitmapSize); + memset(bitmap, 0xFF, usedBitmapSize); + memset(bitmap + usedBitmapSize, 0, bitmapSize - usedBitmapSize); + rc = file->write(used, bitmap, bitmapSize); + dbFile::deallocateBuffer(bitmap); + if (rc != dbFile::ok) { + delete file; + handleError(dybase_open_error, "Failed to write to the file"); + return false; + } + length_t bitmapIndexSize = + DOALIGN((dbBitmapId + dbBitmapPages) * sizeof(offs_t), dbPageSize); + offs_t *index = (offs_t *)dbFile::allocateBuffer(bitmapIndexSize); + index[dbInvalidId] = dbFreeHandleFlag; + length_t i; + for (i = 0; i < bitmapPages; i++) { + index[dbBitmapId + i] = used | dbPageObjectFlag | dbModifiedFlag; + used += dbPageSize; + } + header->root[0].bitmapEnd = dbBitmapId + i; + header->root[1].bitmapEnd = dbBitmapId + i; + while (i < dbBitmapPages) { + index[dbBitmapId + i] = dbFreeHandleFlag; + i += 1; + } + rc = file->write(header->root[1].index, index, bitmapIndexSize); + dbFile::deallocateBuffer(index); + if (rc != dbFile::ok) { + delete file; + handleError(dybase_open_error, "Failed to write index to the file"); + return false; + } + header->root[0].size = used; + header->root[1].size = used; + currIndexSize = dbFirstUserId; + if (!pool.open(file, used)) { + delete file; + handleError(dybase_open_error, "Failed to allocate page pool"); + return false; + } + if (dbFileExtensionQuantum != 0) { + file->setSize(DOALIGN(used, dbFileExtensionQuantum)); + } + offs_t indexPage = header->root[1].index; + offs_t lastIndexPage = + indexPage + header->root[1].bitmapEnd * sizeof(offs_t); + while (indexPage < lastIndexPage) { + offs_t *p = (offs_t *)pool.put(indexPage); + for (i = 0; i < dbHandlesPerPage; i++) { + p[i] &= ~dbModifiedFlag; + } + pool.unfix(p); + indexPage += dbPageSize; + } + pool.copy(header->root[0].index, header->root[1].index, + currIndexSize * sizeof(offs_t)); + header->dirty = true; + header->root[0].size = header->root[1].size; + if (file->write(0, header, dbPageSize) != dbFile::ok) { + pool.close(); + delete file; + handleError(dybase_open_error, "Failed to write to the file"); + return false; + } + pool.flush(); + header->initialized = true; + if (file->write(0, header, dbPageSize) != dbFile::ok || + file->flush() != dbFile::ok) { + pool.close(); + delete file; + handleError(dybase_open_error, "Failed to complete file initialization"); + return false; + } + } else { + int curr = header->curr; + this->curr = curr; + if (header->root[curr].indexSize != header->root[curr].shadowIndexSize) { + delete file; + handleError(dybase_open_error, "Header of database file is corrupted"); + return false; + } + + if (rc != dbFile::ok) { + delete file; + handleError(dybase_open_error, "Failed to read object index"); + return false; + } + pool.open(file, header->root[curr].size); + if (header->dirty) { + TRACE_MSG(("Database was not normally closed: start recovery\n")); + if (accessType == dbReadOnly) { + pool.close(); + delete file; + handleError(dybase_open_error, + "Can not open dirty file in read only mode"); + return false; + } + header->root[1 - curr].size = header->root[curr].size; + header->root[1 - curr].indexUsed = header->root[curr].indexUsed; + header->root[1 - curr].freeList = header->root[curr].freeList; + header->root[1 - curr].index = header->root[curr].shadowIndex; + header->root[1 - curr].indexSize = header->root[curr].shadowIndexSize; + header->root[1 - curr].shadowIndex = header->root[curr].index; + header->root[1 - curr].shadowIndexSize = header->root[curr].indexSize; + header->root[1 - curr].bitmapEnd = header->root[curr].bitmapEnd; + header->root[1 - curr].rootObject = header->root[curr].rootObject; + header->root[1 - curr].classDescList = header->root[curr].classDescList; + + pool.copy( + header->root[1 - curr].index, header->root[curr].index, + DOALIGN(header->root[curr].indexUsed * sizeof(offs_t), dbPageSize)); + TRACE_MSG(("Recovery completed\n")); + } + currIndexSize = header->root[1 - curr].indexUsed; + } + committedIndexSize = currIndexSize; + + loadScheme(); + opened = true; + return true; +} + +void dbDatabase::loadScheme() { + dbGetTie tie; + dbClassDescriptor **cpp = &classDescList; + int cid = header->root[1 - curr].classDescList; + while (cid != 0) { + dbClass * cls = ((dbClass *)getObject(tie, cid))->clone(); + dbClassDescriptor *desc = new dbClassDescriptor(cls, cid); + classOidHash.put(&desc->oid, sizeof(desc->oid), desc); + classSignatureHash.put(cls->signature, desc->signatureSize, desc); + *cpp = desc; + cpp = &desc->next; + cid = cls->next; + } + *cpp = NULL; +} + +void dbDatabase::close() { + dbCriticalSection cs(mutex); + if (!opened) { + handleError(dybase_not_opened, "Database not opened"); + return; + } + if (modified) { commitTransaction(); } + dbClassDescriptor *desc, *next; + for (desc = classDescList; desc != NULL; desc = next) { + next = desc->next; + delete desc; + } + classDescList = NULL; + classOidHash.clear(); + classSignatureHash.clear(); + + opened = false; + if (header->dirty) { + int rc = file->write(0, header, dbPageSize); + if (rc != dbFile::ok) { + throwException(dybase_file_error, "Failed to write header to the disk"); + } + pool.flush(); + header->dirty = false; + rc = file->write(0, header, dbPageSize); + if (rc != dbFile::ok) { + throwException(dybase_file_error, "Failed to write header to the disk"); + } + } + pool.close(); + file->close(); + delete file; +} + +dbObject *dbDatabase::putObject(dbPutTie &tie, oid_t oid) { + offs_t pos = getPos(oid); + int offs = (int)pos & (dbPageSize - 1); + byte * p = pool.get(pos - offs); + dbObject *obj = (dbObject *)(p + (offs & ~dbFlagsMask)); + if (!(offs & dbModifiedFlag)) { + dirtyPagesMap[length_t(oid / dbHandlesPerPage / 32)] |= + 1 << int(oid / dbHandlesPerPage & 31); + cloneBitmap(pos & ~dbFlagsMask, obj->size); + allocate(obj->size, oid); + pos = getPos(oid); + } + tie.set(pool, oid, pos & ~dbFlagsMask, obj->size); + pool.unfix(p); + return (dbObject *)tie.get(); +} + +byte *dbDatabase::put(dbPutTie &tie, oid_t oid) { + offs_t pos = getPos(oid); + if (!(pos & dbModifiedFlag)) { + dirtyPagesMap[length_t(oid / dbHandlesPerPage / 32)] |= + 1 << int(oid / dbHandlesPerPage & 31); + allocate(dbPageSize, oid); + cloneBitmap(pos & ~dbFlagsMask, dbPageSize); + pos = getPos(oid); + } + tie.set(pool, oid, pos & ~dbFlagsMask, dbPageSize); + return tie.get(); +} + +oid_t dbDatabase::getRoot() { return header->root[1 - curr].rootObject; } + +void dbDatabase::setRoot(oid_t oid) { + header->root[1 - curr].rootObject = oid; + modified = true; +} + +dbLoadHandle *dbDatabase::getLoadHandle(oid_t oid) { + dbCriticalSection cs(mutex); + if (!opened) { + handleError(dybase_not_opened, "Database not opened"); + return NULL; + } + dbLoadHandle *hnd = new dbLoadHandle(); + dbObject * obj = getObject(hnd->tie, oid); + hnd->curr = (byte *)(obj + 1); + hnd->end = (byte *)obj + obj->size; + hnd->desc = + (dbClassDescriptor *)classOidHash.get(&obj->cid, sizeof(obj->cid)); + // assert(hnd->desc != NULL); + if (hnd->desc == NULL) + handleError(dybase_bad_key_type, "Bad object descriptor"); + return hnd; +} + +void dbDatabase::storeObject(dbStoreHandle *handle) { + dbCriticalSection cs(mutex); + if (!opened) { + handleError(dybase_not_opened, "Database not opened"); + return; + } + dbObject * obj = (dbObject *)handle->body.base(); + dbClassDescriptor *desc = (dbClassDescriptor *)classSignatureHash.get( + handle->signature.base(), handle->signature.size()); + if (desc == NULL) { + dbClass *cls = + dbClass::create(handle->signature.base(), handle->signature.size()); + cls->next = header->root[1 - curr].classDescList; + desc = new dbClassDescriptor(cls, allocateObject(cls)); + header->root[1 - curr].classDescList = desc->oid; + classOidHash.put(&desc->oid, sizeof(desc->oid), desc); + classSignatureHash.put(cls->signature, desc->signatureSize, desc); + desc->next = classDescList; + classDescList = desc; + } + obj->size = handle->body.size(); + obj->cid = desc->oid; + oid_t oid = handle->oid; + offs_t pos = getPos(oid); + if (pos == 0) { + pos = allocate(obj->size); + setPos(oid, pos | dbModifiedFlag); + } else { + int offs = (int)pos & (dbPageSize - 1); + byte * p = pool.get(pos - offs); + length_t oldSize = ((dbObject *)(p + (offs & ~dbFlagsMask)))->size; + pool.unfix(p); + if (!(offs & dbModifiedFlag)) { + dirtyPagesMap[length_t(oid / dbHandlesPerPage / 32)] |= + 1 << int(oid / dbHandlesPerPage & 31); + cloneBitmap(pos, oldSize); + pos = allocate(obj->size); + setPos(oid, pos | dbModifiedFlag); + } else { + if (DOALIGN(oldSize, dbAllocationQuantum) != + DOALIGN(obj->size, dbAllocationQuantum)) { + offs_t newPos = allocate(obj->size); + cloneBitmap(pos & ~dbFlagsMask, oldSize); + free(pos & ~dbFlagsMask, oldSize); + pos = newPos; + setPos(oid, pos | dbModifiedFlag); + } + } + } + pool.put(pos & ~dbFlagsMask, (byte *)obj, obj->size); +} + +oid_t dbDatabase::allocateObject(dbObject *obj) { + if (!opened) { + handleError(dybase_not_opened, "Database not opened"); + return 0; + } + oid_t oid = allocateId(); + offs_t pos = allocate(obj->size); + setPos(oid, pos | dbModifiedFlag); + pool.put(pos, (byte *)obj, obj->size); + return oid; +} + +void dbDatabase::freeObject(oid_t oid) { + dbCriticalSection cs(mutex); + if (!opened) { + handleError(dybase_not_opened, "Database not opened"); + return; + } + dbObject hdr; + getHeader(hdr, oid); + offs_t pos = getPos(oid); + if (pos & dbModifiedFlag) { + free(pos & ~dbFlagsMask, hdr.size); + } else { + cloneBitmap(pos, hdr.size); + } + freeId(oid); +} + +void dbDatabase::freePage(oid_t oid) { + offs_t pos = getPos(oid); + if (pos & dbModifiedFlag) { + free(pos & ~dbFlagsMask, dbPageSize); + } else { + cloneBitmap(pos & ~dbFlagsMask, dbPageSize); + } + freeId(oid); +} + +inline void dbDatabase::extend(offs_t size) { + if (size > header->root[1 - curr].size) { + if (dbFileExtensionQuantum != 0 && + DOALIGN(size, dbFileExtensionQuantum) != + DOALIGN(header->root[1 - curr].size, dbFileExtensionQuantum)) { + file->setSize(DOALIGN(size, dbFileExtensionQuantum)); + } + header->root[1 - curr].size = size; + } +} + +inline bool dbDatabase::wasReserved(offs_t pos, length_t size) { + for (dbLocation *location = reservedChain; location != NULL; + location = location->next) { + if (pos - location->pos < location->size || location->pos - pos < size) { + return true; + } + } + return false; +} + +inline void dbDatabase::reserveLocation(dbLocation &location, offs_t pos, + length_t size) { + location.pos = pos; + location.size = size; + location.next = reservedChain; + reservedChain = &location; +} + +inline void dbDatabase::commitLocation() { + reservedChain = reservedChain->next; +} + +void dbDatabase::setDirty() { + modified = true; + if (!header->dirty) { + header->dirty = true; + if (file->write(0, header, dbPageSize) != dbFile::ok) { + throwException(dybase_file_error, "Failed to write header to the file"); + } + pool.flush(); + } +} + +offs_t dbDatabase::allocate(length_t size, oid_t oid) { + static byte const firstHoleSize[] = { + 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, + 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, + 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, + 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, + 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, + 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; + static byte const lastHoleSize[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + static byte const maxHoleSize[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, + 4, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 6, 5, 4, 4, 3, 3, 3, 3, + 3, 2, 2, 2, 2, 2, 2, 2, 4, 3, 2, 2, 2, 1, 1, 1, 3, 2, 1, 1, 2, 1, 1, 1, + 5, 4, 3, 3, 2, 2, 2, 2, 3, 2, 1, 1, 2, 1, 1, 1, 4, 3, 2, 2, 2, 1, 1, 1, + 3, 2, 1, 1, 2, 1, 1, 1, 7, 6, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 5, 4, 3, 3, 2, 2, 2, 2, + 3, 2, 1, 1, 2, 1, 1, 1, 4, 3, 2, 2, 2, 1, 1, 1, 3, 2, 1, 1, 2, 1, 1, 1, + 6, 5, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 4, 3, 2, 2, 2, 1, 1, 1, + 3, 2, 1, 1, 2, 1, 1, 1, 5, 4, 3, 3, 2, 2, 2, 2, 3, 2, 1, 1, 2, 1, 1, 1, + 4, 3, 2, 2, 2, 1, 1, 1, 3, 2, 1, 1, 2, 1, 1, 0}; + static byte const maxHoleOffset[] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 0, 1, 5, 5, 5, 5, 5, 5, + 0, 5, 5, 5, 5, 5, 5, 5, 0, 1, 2, 2, 0, 3, 3, 3, 0, 1, 6, 6, 0, 6, 6, 6, + 0, 1, 2, 2, 0, 6, 6, 6, 0, 1, 6, 6, 0, 6, 6, 6, 0, 1, 2, 2, 3, 3, 3, 3, + 0, 1, 4, 4, 0, 4, 4, 4, 0, 1, 2, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, + 0, 1, 2, 2, 0, 3, 3, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 2, 2, 0, 1, 0, 3, + 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 2, 2, 3, 3, 3, 3, 0, 4, 4, 4, 4, 4, 4, 4, + 0, 1, 2, 2, 0, 5, 5, 5, 0, 1, 5, 5, 0, 5, 5, 5, 0, 1, 2, 2, 0, 3, 3, 3, + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 2, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, + 0, 1, 2, 2, 3, 3, 3, 3, 0, 1, 4, 4, 0, 4, 4, 4, 0, 1, 2, 2, 0, 1, 0, 3, + 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 2, 2, 0, 3, 3, 3, 0, 1, 0, 2, 0, 1, 0, 4, + 0, 1, 2, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0}; + + setDirty(); + size = DOALIGN(size, dbAllocationQuantum); + allocatedDelta += size; + if (gcThreshold != 0 && allocatedDelta > gcThreshold && !gcDone) { + startGC(); + } + + int objBitSize = size >> dbAllocationQuantumBits; + offs_t pos; + int holeBitSize = 0; + int alignment = size & (dbPageSize - 1); + length_t offs; + const int pageBits = dbPageSize * 8; + oid_t firstPage, lastPage; + int holeBeforeFreePage = 0; + oid_t freeBitmapPage = 0; + dbLocation location; + dbPutTie tie; + oid_t i; + const length_t inc = dbPageSize / dbAllocationQuantum / 8; + + lastPage = header->root[1 - curr].bitmapEnd; + if (alignment == 0) { + firstPage = currPBitmapPage; + offs = DOALIGN(currPBitmapOffs, inc); + } else { + firstPage = currRBitmapPage; + offs = currRBitmapOffs; + } + + for (;;) { + if (alignment == 0) { + // allocate page object + for (i = firstPage; i < lastPage; i++) { + int spaceNeeded = objBitSize - holeBitSize < pageBits + ? objBitSize - holeBitSize + : pageBits; + if (bitmapPageAvailableSpace[i] <= spaceNeeded) { + holeBitSize = 0; + offs = 0; + continue; + } + byte * begin = get(i); + length_t startOffs = offs; + while (offs < dbPageSize) { + if (begin[offs++] != 0) { + offs = DOALIGN(offs, inc); + holeBitSize = 0; + } else if ((holeBitSize += 8) == objBitSize) { + pos = + ((offs_t(i - dbBitmapId) * dbPageSize + offs) * 8 - holeBitSize) + << dbAllocationQuantumBits; + if (wasReserved(pos, size)) { + offs += objBitSize >> 3; + startOffs = offs = DOALIGN(offs, inc); + holeBitSize = 0; + continue; + } + reserveLocation(location, pos, size); + currPBitmapPage = i; + currPBitmapOffs = offs; + extend(pos + size); + if (oid != 0) { + offs_t prev = getPos(oid); + int marker = (int)prev & dbFlagsMask; + pool.copy(pos, prev - marker, size); + setPos(oid, pos | marker | dbModifiedFlag); + } + pool.unfix(begin); + begin = put(tie, i); + length_t holeBytes = holeBitSize >> 3; + if (holeBytes > offs) { + memset(begin, 0xFF, offs); + holeBytes -= offs; + begin = put(tie, --i); + offs = dbPageSize; + } + while (holeBytes > dbPageSize) { + memset(begin, 0xFF, dbPageSize); + holeBytes -= dbPageSize; + bitmapPageAvailableSpace[i] = 0; + begin = put(tie, --i); + } + memset(&begin[offs - holeBytes], 0xFF, holeBytes); + commitLocation(); + return pos; + } + } + if (startOffs == 0 && holeBitSize == 0 && + spaceNeeded < bitmapPageAvailableSpace[i]) { + bitmapPageAvailableSpace[i] = spaceNeeded; + } + offs = 0; + pool.unfix(begin); + } + } else { + for (i = firstPage; i < lastPage; i++) { + int spaceNeeded = objBitSize - holeBitSize < pageBits + ? objBitSize - holeBitSize + : pageBits; + if (bitmapPageAvailableSpace[i] <= spaceNeeded) { + holeBitSize = 0; + offs = 0; + continue; + } + byte * begin = get(i); + length_t startOffs = offs; + + while (offs < dbPageSize) { + int mask = begin[offs]; + if (holeBitSize + firstHoleSize[mask] >= objBitSize) { + pos = + ((offs_t(i - dbBitmapId) * dbPageSize + offs) * 8 - holeBitSize) + << dbAllocationQuantumBits; + if (wasReserved(pos, size)) { + startOffs = offs += (objBitSize + 7) >> 3; + holeBitSize = 0; + continue; + } + reserveLocation(location, pos, size); + currRBitmapPage = i; + currRBitmapOffs = offs; + extend(pos + size); + if (oid != 0) { + offs_t prev = getPos(oid); + int marker = (int)prev & dbFlagsMask; + pool.copy(pos, prev - marker, size); + setPos(oid, pos | marker | dbModifiedFlag); + } + pool.unfix(begin); + begin = put(tie, i); + begin[offs] |= (1 << (objBitSize - holeBitSize)) - 1; + if (holeBitSize != 0) { + if (length_t(holeBitSize) > offs * 8) { + memset(begin, 0xFF, offs); + holeBitSize -= offs * 8; + begin = put(tie, --i); + offs = dbPageSize; + } + while (holeBitSize > pageBits) { + memset(begin, 0xFF, dbPageSize); + holeBitSize -= pageBits; + bitmapPageAvailableSpace[i] = 0; + begin = put(tie, --i); + } + while ((holeBitSize -= 8) > 0) { + begin[--offs] = 0xFF; + } + begin[offs - 1] |= ~((1 << -holeBitSize) - 1); + } + commitLocation(); + return pos; + } else if (maxHoleSize[mask] >= objBitSize) { + int holeBitOffset = maxHoleOffset[mask]; + pos = ((offs_t(i - dbBitmapId) * dbPageSize + offs) * 8 + + holeBitOffset) + << dbAllocationQuantumBits; + if (wasReserved(pos, size)) { + startOffs = offs += (objBitSize + 7) >> 3; + holeBitSize = 0; + continue; + } + reserveLocation(location, pos, size); + currRBitmapPage = i; + currRBitmapOffs = offs; + extend(pos + size); + if (oid != 0) { + offs_t prev = getPos(oid); + int marker = (int)prev & dbFlagsMask; + pool.copy(pos, prev - marker, size); + setPos(oid, pos | marker | dbModifiedFlag); + } + pool.unfix(begin); + begin = put(tie, i); + begin[offs] |= ((1 << objBitSize) - 1) << holeBitOffset; + commitLocation(); + return pos; + } + offs += 1; + if (lastHoleSize[mask] == 8) { + holeBitSize += 8; + } else { + holeBitSize = lastHoleSize[mask]; + } + } + if (startOffs == 0 && holeBitSize == 0 && + spaceNeeded < bitmapPageAvailableSpace[i]) { + bitmapPageAvailableSpace[i] = spaceNeeded; + } + offs = 0; + pool.unfix(begin); + } + } + if (firstPage == dbBitmapId) { + if (freeBitmapPage > i) { + i = freeBitmapPage; + holeBitSize = holeBeforeFreePage; + } + if (i == dbBitmapId + dbBitmapPages) { + throwException(dybase_out_of_memory_error, "Out of memory"); + } + length_t extension = (size > extensionQuantum) ? size : extensionQuantum; + int morePages = + (extension + dbPageSize * (dbAllocationQuantum * 8 - 1) - 1) / + (dbPageSize * (dbAllocationQuantum * 8 - 1)); + + if (length_t(i + morePages) > dbBitmapId + dbBitmapPages) { + morePages = (size + dbPageSize * (dbAllocationQuantum * 8 - 1) - 1) / + (dbPageSize * (dbAllocationQuantum * 8 - 1)); + if (length_t(i + morePages) > dbBitmapId + dbBitmapPages) { + throwException(dybase_out_of_memory_error, "Out of memory"); + } + } + objBitSize -= holeBitSize; + int skip = DOALIGN(objBitSize, dbPageSize / dbAllocationQuantum); + pos = (offs_t(i - dbBitmapId) + << (dbPageBits + dbAllocationQuantumBits + 3)) + + (skip << dbAllocationQuantumBits); + extend(pos + morePages * dbPageSize); + length_t len = objBitSize >> 3; + offs_t adr = pos; + byte * p; + while (len >= dbPageSize) { + p = pool.put(adr); + memset(p, 0xFF, dbPageSize); + pool.unfix(p); + adr += dbPageSize; + len -= dbPageSize; + } + p = pool.put(adr); + memset(p, 0xFF, len); + p[len] = (1 << (objBitSize & 7)) - 1; + pool.unfix(p); + adr = pos + (skip >> 3); + len = morePages * (dbPageSize / dbAllocationQuantum / 8); + for (;;) { + int off = (int)adr & (dbPageSize - 1); + p = pool.put(adr - off); + if (dbPageSize - off >= len) { + memset(p + off, 0xFF, len); + pool.unfix(p); + break; + } else { + memset(p + off, 0xFF, dbPageSize - off); + pool.unfix(p); + adr += dbPageSize - off; + len -= dbPageSize - off; + } + } + oid_t j = i; + while (--morePages >= 0) { + dirtyPagesMap[length_t(j / dbHandlesPerPage / 32)] |= + 1 << int(j / dbHandlesPerPage & 31); + setPos(j++, pos | dbPageObjectFlag | dbModifiedFlag); + pos += dbPageSize; + } + freeBitmapPage = header->root[1 - curr].bitmapEnd = j; + j = i + objBitSize / pageBits; + if (alignment != 0) { + currRBitmapPage = j; + currRBitmapOffs = 0; + } else { + currPBitmapPage = j; + currPBitmapOffs = 0; + } + while (j > i) { + bitmapPageAvailableSpace[length_t(--j)] = 0; + } + + pos = (offs_t(i - dbBitmapId) * dbPageSize * 8 - holeBitSize) + << dbAllocationQuantumBits; + if (oid != 0) { + offs_t prev = getPos(oid); + int marker = (int)prev & dbFlagsMask; + pool.copy(pos, prev - marker, size); + setPos(oid, pos | marker | dbModifiedFlag); + } + if (holeBitSize != 0) { + reserveLocation(location, pos, size); + while (holeBitSize > pageBits) { + holeBitSize -= pageBits; + byte *p = put(tie, --i); + memset(p, 0xFF, dbPageSize); + bitmapPageAvailableSpace[i] = 0; + } + byte *cur = (byte *)put(tie, --i) + dbPageSize; + while ((holeBitSize -= 8) > 0) { + *--cur = 0xFF; + } + *(cur - 1) |= ~((1 << -holeBitSize) - 1); + commitLocation(); + } + return pos; + } + if (gcThreshold != 0 && !gcDone) { + allocatedDelta -= size; + startGC(); + currRBitmapPage = currPBitmapPage = dbBitmapId; + currRBitmapOffs = currPBitmapOffs = 0; + return allocate(size, oid); + } + freeBitmapPage = i; + holeBeforeFreePage = holeBitSize; + holeBitSize = 0; + lastPage = firstPage + 1; + firstPage = dbBitmapId; + offs = 0; + } +} + +void dbDatabase::free(offs_t pos, length_t size) { + assert(pos != 0 && (pos & (dbAllocationQuantum - 1)) == 0); + dbPutTie tie; + offs_t quantNo = pos / dbAllocationQuantum; + int objBitSize = (size + dbAllocationQuantum - 1) / dbAllocationQuantum; + oid_t pageId = dbBitmapId + oid_t(quantNo / (dbPageSize * 8)); + length_t offs = (length_t(quantNo) & (dbPageSize * 8 - 1)) >> 3; + byte * p = put(tie, pageId) + offs; + int bitOffs = int(quantNo) & 7; + + allocatedDelta -= objBitSize * dbAllocationQuantum; + + if ((length_t(pos) & (dbPageSize - 1)) == 0 && size >= dbPageSize) { + if (pageId == currPBitmapPage && offs < currPBitmapOffs) { + currPBitmapOffs = offs; + } + } else { + if (pageId == currRBitmapPage && offs < currRBitmapOffs) { + currRBitmapOffs = offs; + } + } + + bitmapPageAvailableSpace[pageId] = INT_MAX; + + if (objBitSize > 8 - bitOffs) { + objBitSize -= 8 - bitOffs; + *p++ &= (1 << bitOffs) - 1; + offs += 1; + while (objBitSize + offs * 8 > dbPageSize * 8) { + memset(p, 0, dbPageSize - offs); + p = put(tie, ++pageId); + bitmapPageAvailableSpace[pageId] = INT_MAX; + objBitSize -= (dbPageSize - offs) * 8; + offs = 0; + } + while ((objBitSize -= 8) > 0) { + *p++ = 0; + } + *p &= ~((1 << (objBitSize + 8)) - 1); + } else { + *p &= ~(((1 << objBitSize) - 1) << bitOffs); + } +} + +void dbDatabase::gc() { + dbCriticalSection cs(mutex); + if (gcDone) { return; } + startGC(); +} + +void dbDatabase::startGC() { + int bitmapSize = + (int)(header->root[curr].size >> (dbAllocationQuantumBits + 5)) + 1; + bool existsNotMarkedObjects; + offs_t pos; + int i, j; + + // mark + greyBitmap = new db_int4[bitmapSize]; + blackBitmap = new db_int4[bitmapSize]; + memset(greyBitmap, 0, bitmapSize * sizeof(db_int4)); + memset(blackBitmap, 0, bitmapSize * sizeof(db_int4)); + int rootOid = header->root[curr].rootObject; + if (rootOid != 0) { + dbGetTie tie; + markOid(rootOid); + do { + existsNotMarkedObjects = false; + for (i = 0; i < bitmapSize; i++) { + if (greyBitmap[i] != 0) { + existsNotMarkedObjects = true; + for (j = 0; j < 32; j++) { + if ((greyBitmap[i] & (1 << j)) != 0) { + pos = (((offs_t)i << 5) + j) << dbAllocationQuantumBits; + greyBitmap[i] &= ~(1 << j); + blackBitmap[i] |= 1 << j; + int offs = (int)pos & (dbPageSize - 1); + byte * pg = pool.get(pos - offs); + dbObject *obj = (dbObject *)(pg + offs); + if (obj->cid == dbBtreeId) { + ((dbBtree *)obj)->markTree(this); + } else if (obj->cid >= dbFirstUserId) { + markOid(obj->cid); + tie.set(pool, pos); + markObject((dbObject *)tie.get()); + } + pool.unfix(pg); + } + } + } + } + } while (existsNotMarkedObjects); + } + + // sweep + gcDone = true; + for (i = dbFirstUserId, j = committedIndexSize; i < j; i++) { + pos = getGCPos(i); + if (((int)pos & (dbPageObjectFlag | dbFreeHandleFlag)) == 0) { + unsigned bit = (unsigned)(pos >> dbAllocationQuantumBits); + if ((blackBitmap[bit >> 5] & (1 << (bit & 31))) == 0) { + // object is not accessible + assert(getPos(i) == pos); + int offs = (int)pos & (dbPageSize - 1); + byte * pg = pool.get(pos - offs); + dbObject *obj = (dbObject *)(pg + offs); + if (obj->cid == dbBtreeId) { + dbBtree::_drop(this, i); + } else if (obj->cid >= dbFirstUserId) { + freeId(i); + cloneBitmap(pos, obj->size); + } + pool.unfix(pg); + } + } + } + + delete[] greyBitmap; + delete[] blackBitmap; + allocatedDelta = 0; +} + +void dbDatabase::markObject(dbObject *obj) { + byte *p = (byte *)(obj + 1); + byte *end = (byte *)obj + obj->size; + while (p < end) { + p = markField(p); + } +} + +byte *dbDatabase::markField(byte *p) { + int type = *p++; + db_int4 len; + oid_t oid; + int i; + + switch (type & 0xF) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: + memcpy(&oid, p, sizeof(oid_t)); + markOid(oid); + p += sizeof(oid_t); + break; + case dybase_bool_type: p += 1; break; + case dybase_int_type: p += sizeof(db_int4); break; + case dybase_date_type: + case dybase_long_type: + case dybase_real_type: p += sizeof(db_int8); break; + case dybase_chars_type: + if (type != dybase_chars_type) { + // small string + p += type >> 4; + } else { + memcpy(&len, p, sizeof(db_int4)); + p += sizeof(db_int4) + len; + } + break; + case dybase_bytes_type: + if (type != dybase_bytes_type) { + // small blob + p += type >> 4; + } + else { + memcpy(&len, p, sizeof(db_int4)); + p += sizeof(db_int4) + len; + } + break; + case dybase_array_type: + if (type != dybase_array_type) { + // small array + for (i = type >> 4; --i >= 0;) { + p = markField(p); + } + } else { + memcpy(&len, p, sizeof(db_int4)); + p += sizeof(db_int4); + for (i = len; --i >= 0;) { + p = markField(p); + } + } + break; + case dybase_map_type: + if (type != dybase_map_type) { + // small map + for (i = (type >> 4) << 1; --i >= 0;) { + p = markField(p); + } + } else { + memcpy(&len, p, sizeof(db_int4)); + p += sizeof(db_int4); + for (i = len << 1; --i >= 0;) { + p = markField(p); + } + } + } + return p; +} + +void dbDatabase::cloneBitmap(offs_t pos, length_t size) { + offs_t quantNo = pos / dbAllocationQuantum; + int objBitSize = (size + dbAllocationQuantum - 1) / dbAllocationQuantum; + oid_t pageId = dbBitmapId + oid_t(quantNo / (dbPageSize * 8)); + length_t offs = (length_t(quantNo) & (dbPageSize * 8 - 1)) >> 3; + int bitOffs = int(quantNo) & 7; + oid_t oid = pageId; + pos = getPos(oid); + if (!(pos & dbModifiedFlag)) { + dirtyPagesMap[length_t(oid / dbHandlesPerPage / 32)] |= + 1 << (int(oid / dbHandlesPerPage) & 31); + allocate(dbPageSize, oid); + cloneBitmap(pos & ~dbFlagsMask, dbPageSize); + } + + if (objBitSize > 8 - bitOffs) { + objBitSize -= 8 - bitOffs; + offs += 1; + while (objBitSize + offs * 8 > dbPageSize * 8) { + oid = ++pageId; + pos = getPos(oid); + if (!(pos & dbModifiedFlag)) { + dirtyPagesMap[length_t(oid / dbHandlesPerPage / 32)] |= + 1 << (int(oid / dbHandlesPerPage) & 31); + allocate(dbPageSize, oid); + cloneBitmap(pos & ~dbFlagsMask, dbPageSize); + } + objBitSize -= (dbPageSize - offs) * 8; + offs = 0; + } + } +} + +oid_t dbDatabase::allocate() { + dbCriticalSection cs(mutex); + return allocateId(); +} + +oid_t dbDatabase::allocateId() { + oid_t oid; + int curr = 1 - this->curr; + setDirty(); + if ((oid = header->root[curr].freeList) != 0) { + header->root[curr].freeList = oid_t(getPos(oid) >> dbFlagsBits); + dirtyPagesMap[length_t(oid / dbHandlesPerPage / 32)] |= + 1 << (int(oid / dbHandlesPerPage) & 31); + } else { + if (currIndexSize + 1 > header->root[curr].indexSize) { + length_t oldIndexSize = header->root[curr].indexSize; + length_t newIndexSize = oldIndexSize * 2; + while (newIndexSize < oldIndexSize + 1) { + newIndexSize = newIndexSize * 2; + } + TRACE_MSG( + ("Extend index size from %ld to %ld\n", oldIndexSize, newIndexSize)); + offs_t newIndex = allocate(newIndexSize * sizeof(offs_t)); + offs_t oldIndex = header->root[curr].index; + pool.copy(newIndex, oldIndex, currIndexSize * sizeof(offs_t)); + header->root[curr].index = newIndex; + header->root[curr].indexSize = newIndexSize; + free(oldIndex, oldIndexSize * sizeof(offs_t)); + } + oid = currIndexSize; + header->root[curr].indexUsed = ++currIndexSize; + } + setPos(oid, 0); + return oid; +} + +void dbDatabase::freeId(oid_t oid) { + dirtyPagesMap[length_t(oid / dbHandlesPerPage / 32)] |= + 1 << (int(oid / dbHandlesPerPage) & 31); + setPos(oid, (offs_t(header->root[1 - curr].freeList) << dbFlagsBits) | + dbFreeHandleFlag); + header->root[1 - curr].freeList = oid; +} + +void dbDatabase::commit() { + dbCriticalSection cs(mutex); + commitTransaction(); +} + +void dbDatabase::commitTransaction() { + if (!opened) { + handleError(dybase_not_opened, "Database not opened"); + return; + } + if (!modified) { return; } + // + // Commit transaction + // + int rc; + int n, curr = header->curr; + oid_t i; + db_int4 *map = dirtyPagesMap; + length_t currIndexSize = this->currIndexSize; + length_t committedIndexSize = this->committedIndexSize; + length_t oldIndexSize = header->root[curr].indexSize; + length_t newIndexSize = header->root[1 - curr].indexSize; + length_t nPages = committedIndexSize / dbHandlesPerPage; + if (newIndexSize > oldIndexSize) { + offs_t newIndex = allocate(newIndexSize * sizeof(offs_t)); + header->root[1 - curr].shadowIndex = newIndex; + header->root[1 - curr].shadowIndexSize = newIndexSize; + cloneBitmap(header->root[curr].index, oldIndexSize * sizeof(offs_t)); + free(header->root[curr].index, oldIndexSize * sizeof(offs_t)); + } + + for (i = 0; i < nPages; i++) { + if (map[length_t(i >> 5)] & (1 << int(i & 31))) { + offs_t *srcIndex = + (offs_t *)pool.get(header->root[1 - curr].index + i * dbPageSize); + offs_t *dstIndex = + (offs_t *)pool.get(header->root[curr].index + i * dbPageSize); + for (length_t j = 0; j < dbHandlesPerPage; j++) { + offs_t pos = dstIndex[j]; + if (srcIndex[j] != pos) { + if (!(pos & dbFreeHandleFlag)) { + if (pos & dbPageObjectFlag) { + free(pos & ~dbFlagsMask, dbPageSize); + } else { + int offs = (int)pos & (dbPageSize - 1); + dbObject *rec = + (dbObject *)(pool.get(pos - offs) + (offs & ~dbFlagsMask)); + free(pos, rec->size); + pool.unfix(rec); + } + } + } + } + pool.unfix(srcIndex); + pool.unfix(dstIndex); + } + } + if ((committedIndexSize % dbHandlesPerPage) != 0 && + (map[length_t(i >> 5)] & (1 << int(i & 31)))) { + offs_t *srcIndex = + (offs_t *)pool.get(header->root[1 - curr].index + i * dbPageSize); + offs_t *dstIndex = + (offs_t *)pool.get(header->root[curr].index + i * dbPageSize); + n = committedIndexSize % dbHandlesPerPage; + do { + offs_t pos = *dstIndex; + if (*srcIndex != pos) { + if (!(pos & dbFreeHandleFlag)) { + if (pos & dbPageObjectFlag) { + free(pos & ~dbFlagsMask, dbPageSize); + } else { + int offs = (int)pos & (dbPageSize - 1); + dbObject *rec = + (dbObject *)(pool.get(pos - offs) + (offs & ~dbFlagsMask)); + free(pos, rec->size); + pool.unfix(rec); + } + } + } + dstIndex += 1; + srcIndex += 1; + } while (--n != 0); + + pool.unfix(srcIndex); + pool.unfix(dstIndex); + } + + for (i = 0; i <= nPages; i++) { + if (map[length_t(i >> 5)] & (1 << int(i & 31))) { + offs_t *p = + (offs_t *)pool.put(header->root[1 - curr].index + i * dbPageSize); + for (length_t j = 0; j < dbHandlesPerPage; j++) { + p[j] &= ~dbModifiedFlag; + } + pool.unfix(p); + } + } + if (currIndexSize > committedIndexSize) { + offs_t page = + (header->root[1 - curr].index + committedIndexSize * sizeof(offs_t)) & + ~((offs_t)dbPageSize - 1); + offs_t end = (header->root[1 - curr].index + dbPageSize - 1 + + currIndexSize * sizeof(offs_t)) & + ~((offs_t)dbPageSize - 1); + while (page < end) { + offs_t *p = (offs_t *)pool.put(page); + for (length_t h = 0; h < dbHandlesPerPage; h++) { + p[h] &= ~dbModifiedFlag; + } + pool.unfix(p); + page += dbPageSize; + } + } + + if ((rc = file->write(0, header, dbPageSize)) != dbFile::ok) { + throwException(dybase_file_error, "Failed to write header"); + } + + pool.flush(); + + header->curr = curr ^= 1; + + if ((rc = file->write(0, header, dbPageSize)) != dbFile::ok || + (rc = file->flush()) != dbFile::ok) { + throwException(dybase_file_error, "Failed to flush changes to the disk"); + } + + header->root[1 - curr].size = header->root[curr].size; + header->root[1 - curr].indexUsed = currIndexSize; + header->root[1 - curr].freeList = header->root[curr].freeList; + header->root[1 - curr].bitmapEnd = header->root[curr].bitmapEnd; + header->root[1 - curr].rootObject = header->root[curr].rootObject; + header->root[1 - curr].classDescList = header->root[curr].classDescList; + + if (newIndexSize != oldIndexSize) { + header->root[1 - curr].index = header->root[curr].shadowIndex; + header->root[1 - curr].indexSize = header->root[curr].shadowIndexSize; + header->root[1 - curr].shadowIndex = header->root[curr].index; + header->root[1 - curr].shadowIndexSize = header->root[curr].indexSize; + pool.copy(header->root[1 - curr].index, header->root[curr].index, + currIndexSize * sizeof(offs_t)); + memset(map, 0, + 4 * ((currIndexSize + dbHandlesPerPage * 32 - 1) / + (dbHandlesPerPage * 32))); + } else { + for (i = 0; i < nPages; i++) { + if (map[length_t(i >> 5)] & (1 << int(i & 31))) { + map[length_t(i >> 5)] -= (1 << int(i & 31)); + pool.copy(header->root[1 - curr].index + i * dbPageSize, + header->root[curr].index + i * dbPageSize, dbPageSize); + } + } + if (currIndexSize > i * dbHandlesPerPage && + ((map[length_t(i >> 5)] & (1 << int(i & 31))) != 0 || + currIndexSize != committedIndexSize)) { + pool.copy(header->root[1 - curr].index + i * dbPageSize, + header->root[curr].index + i * dbPageSize, + length_t(sizeof(offs_t) * currIndexSize - i * dbPageSize)); + memset(map + length_t(i >> 5), 0, + length_t(((currIndexSize + dbHandlesPerPage * 32 - 1) / + (dbHandlesPerPage * 32) - + (i >> 5)) * + 4)); + } + } + this->curr = curr; + this->committedIndexSize = currIndexSize; + modified = false; + gcDone = false; +} + +void dbDatabase::rollback() { + dbCriticalSection cs(mutex); + if (!opened) { + handleError(dybase_not_opened, "Database not opened"); + return; + } + if (!modified) { return; } + int curr = header->curr; + length_t nPages = + (committedIndexSize + dbHandlesPerPage - 1) / dbHandlesPerPage; + db_int4 *map = dirtyPagesMap; + if (header->root[1 - curr].index != header->root[curr].shadowIndex) { + pool.copy(header->root[curr].shadowIndex, header->root[curr].index, + dbPageSize * nPages); + } else { + for (oid_t i = 0; i < nPages; i++) { + if (map[length_t(i >> 5)] & (1 << int(i & 31))) { + pool.copy(header->root[curr].shadowIndex + i * dbPageSize, + header->root[curr].index + i * dbPageSize, dbPageSize); + } + } + } + memset(map, 0, + length_t((currIndexSize + dbHandlesPerPage * 32 - 1) / + (dbHandlesPerPage * 32)) * + 4); + header->root[1 - curr].indexSize = header->root[curr].shadowIndexSize; + header->root[1 - curr].indexUsed = header->root[curr].indexUsed; + header->root[1 - curr].freeList = header->root[curr].freeList; + header->root[1 - curr].index = header->root[curr].shadowIndex; + header->root[1 - curr].bitmapEnd = header->root[curr].bitmapEnd; + header->root[1 - curr].size = header->root[curr].size; + header->root[1 - curr].rootObject = header->root[curr].rootObject; + header->root[1 - curr].classDescList = header->root[curr].classDescList; + + currRBitmapPage = currPBitmapPage = dbBitmapId; + currRBitmapOffs = currPBitmapOffs = 0; + currIndexSize = committedIndexSize; + + modified = false; + + oid_t cid = header->root[curr].classDescList; + dbClassDescriptor *desc = classDescList; + while (desc->oid != cid) { + classOidHash.remove(&desc->oid, sizeof(desc->oid)); + classSignatureHash.remove(desc->cls->signature, desc->signatureSize); + dbClassDescriptor *next = desc->next; + delete desc; + desc = next; + } + classDescList = desc; +} + +dbDatabase::dbDatabase(dbAccessType type, dbErrorHandler hnd, length_t poolSize, + length_t dbExtensionQuantum, length_t dbInitIndexSize) + : accessType(type), extensionQuantum(dbExtensionQuantum), + initIndexSize(dbInitIndexSize), pool(this, poolSize), errorHandler(hnd) { + dirtyPagesMap = new db_int4[dbDirtyPageBitmapSize / 4 + 1]; + bitmapPageAvailableSpace = new int[dbBitmapId + dbBitmapPages]; + classDescList = NULL; + opened = false; + header = (dbHeader *)dbFile::allocateBuffer(dbPageSize); + dbFileExtensionQuantum = 0; + dbFileSizeLimit = 0; +} + +dbDatabase::~dbDatabase() { + delete[] dirtyPagesMap; + delete[] bitmapPageAvailableSpace; + dbFile::deallocateBuffer(header); +} + +void dbTrace(char *message, ...) { + va_list args; + va_start(args, message); + vfprintf(stderr, message, args); + va_end(args); +} diff --git a/storage/dybase/src/database.h b/storage/dybase/src/database.h new file mode 100644 index 000000000..acee76acc --- /dev/null +++ b/storage/dybase/src/database.h @@ -0,0 +1,795 @@ +//-< DATABASE.H >----------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 20-Nov-98 K.A. Knizhnik * / [] \ * +// Last update: 14-Feb-99 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// Database management +//-------------------------------------------------------------------*--------* + +#ifndef __DATABASE_H__ +#define __DATABASE_H__ + +#include "dybase.h" +#include "stdtp.h" + +#define _LARGEFILE64_SOURCE 1 // access to files greater than 2Gb in Solaris +#define _LARGE_FILE_API 1 // access to files greater than 2Gb in AIX + +#ifndef dbDatabaseOffsetBits +#define dbDatabaseOffsetBits 32 // 37 - up to 1 terabyte +#endif + +typedef dybase_oid_t oid_t; +#define dbDatabaseOidBits \ + sizeof(oid_t) * 8 // can be greater than 32 only at 64-bit platforms + +/** + * Object offset in the file type + */ +#if dbDatabaseOffsetBits > 32 +typedef db_nat8 offs_t; // It will work only for 64-bit OS +typedef db_nat8 length_t; // It will work only for 64-bit OS +#define lengthof(T) sizeof(T) +#else +typedef db_nat4 offs_t; +typedef db_nat4 length_t; +#define lengthof(T) (length_t(sizeof(T))) +#endif + +#include "buffer.h" +#include "pagepool.h" +#include "hashtab.h" +#include "sync.h" + +/** + * Default size of memory mapping object for the database (bytes) + */ +const length_t dbDefaultInitIndexSize = + 10 * 1024; // typical nr. of objects in db + +/** + * Default initial index size (number of objects) + */ +const length_t dbDefaultExtensionQuantum = 512 * 1024; // alloc per half meg. + +/** + * Default initial index size (in bytes) + */ +const length_t dbDefaultPagePoolSize = 8 * 1024 * 1024; + +/** + * Object handler falgs + */ +enum dbHandleFlags { + dbPageObjectFlag = 0x1, + dbModifiedFlag = 0x2, + dbFreeHandleFlag = 0x4, + dbFlagsMask = 0x7, + dbFlagsBits = 3 +}; + +const length_t dbAllocationQuantumBits = 5; +const length_t dbAllocationQuantum = 1 << dbAllocationQuantumBits; +const length_t dbPageBits = 12; +const length_t dbPageSize = 1 << dbPageBits; +const length_t dbIdsPerPage = dbPageSize / sizeof(oid_t); +const length_t dbHandlesPerPage = dbPageSize / sizeof(offs_t); +const length_t dbBitmapSegmentBits = dbPageBits + 3 + dbAllocationQuantumBits; +const length_t dbBitmapSegmentSize = 1 << dbBitmapSegmentBits; +const length_t dbBitmapPages = 1 + << (dbDatabaseOffsetBits - dbBitmapSegmentBits); +const length_t dbDirtyPageBitmapSize = + 1 << (dbDatabaseOidBits - dbPageBits + (1 + sizeof(offs_t) / 4) - 3); + +const int dbMaxFileSegments = 64; + +/** + * Predefined object identifiers + */ +enum dbPredefinedIds { + dbInvalidId, + dbClassDescId, + dbBtreeId, + dbBitmapId, + dbFirstUserId = dbBitmapId + dbBitmapPages +}; + +/* + dybase_object_ref_type = 0, // object ref, oid + dybase_array_ref_type = 1, + dybase_index_ref_type = 2, + + dybase_bool_type = 3, + dybase_int_type = 4, + dybase_date_type = 5, + dybase_real_type = 6, + dybase_chars_type = 7, // literal string + dybase_array_type = 8, // literal array + dybase_map_type = 9, // literal key/value pairs map + + dybase_long_type = 10, + dybase_bytes_type = 11, // literal blob, max length 2^32 +*/ + +static const int dbSizeofType[] = { + sizeof(oid_t), // dybase_object_type + sizeof(oid_t), // dybase_object_type + sizeof(oid_t), // dybase_object_type + sizeof(db_int1), // dybase_bool_type + sizeof(db_int4), // dybase_int_type + sizeof(db_int8), // dybase_date_type + sizeof(db_real8), // dybase_real_type + 0, // dybase_chars_type + 0, // dybase_array_type + 0, // dybase_map_type + sizeof(db_int8), // dybase_long_type + 0, // dybase_bytes_type +}; + +//static const int dbFieldTypeBits = 3; + +class dbException { + char const *msg; + int error; + +public: + /** + * Get error code + * @return error code as defined in dbErrorClass enum in + * database.h + */ + int getErrCode() const { return error; } + + /** + * Get message text + */ + char *getMsg() const { return (char *)msg; } + + dbException(int error, char const *msg) { + this->error = error; + this->msg = msg; + } +}; + +/** + * Database header + */ +class dbHeader { +public: + db_int4 curr; // current root + db_int4 dirty; // database was not closed normally + db_int4 initialized; // database is initilaized + struct { + offs_t size; // database file size + offs_t index; // offset to object index + offs_t shadowIndex; // offset to shadow index + oid_t indexSize; // size of object index + oid_t shadowIndexSize; // size of object index + oid_t indexUsed; // used part of the index + oid_t freeList; // L1 list of free descriptors + oid_t bitmapEnd; // index of last allocated bitmap page + oid_t rootObject; // storage root + oid_t classDescList; // list of class descriptors + } root[2]; + + bool isInitialized() { + return initialized == 1 && (dirty == 1 || dirty == 0) && + (curr == 1 || curr == 0) && root[curr].size > root[curr].index && + root[curr].size > root[curr].shadowIndex && + root[curr].size > root[curr].indexSize * sizeof(offs_t) + + root[curr].shadowIndexSize * sizeof(offs_t) && + root[curr].indexSize >= root[curr].indexUsed && + root[curr].indexUsed >= dbFirstUserId && + root[curr].bitmapEnd > dbBitmapId; + } +}; + +class dbObject { +public: + oid_t cid; + db_nat4 size; +}; + +class dbClass : public dbObject { +public: + oid_t next; + char signature[1]; + + static dbClass *create(char *signature, length_t signatureSize) { + length_t size = sizeof(dbObject) + sizeof(oid_t) + signatureSize; + dbClass *cls = (dbClass *)new char[size]; + cls->size = (db_nat4)size; + cls->cid = dbClassDescId; + memcpy(cls->signature, signature, signatureSize); + return cls; + } + + dbClass *clone() { + dbClass *cls = create(signature, getSignatureSize()); + cls->size = size; + cls->next = next; + cls->cid = cid; + return cls; + } + + void remove() { delete[](char *) this; } + + length_t getSignatureSize() { + return size - sizeof(dbObject) - sizeof(oid_t); + } +}; + +class dbClassDescriptor { + + dbClassDescriptor(const dbClassDescriptor &); + dbClassDescriptor &operator=(const dbClassDescriptor &); + +public: + oid_t oid; + dbClass * cls; + char * name; + char ** field; + length_t signatureSize; + dbClassDescriptor *next; + + dbClassDescriptor(dbClass *cls, oid_t oid) { + char *p; + this->oid = oid; + this->cls = cls; + name = cls->signature; + signatureSize = cls->getSignatureSize(); + char *start = name + strlen(name) + 1; + char *end = name + signatureSize; + int n = 0; + for (p = start; p < end; p += strlen(p) + 1) { + n += 1; + } + field = new char *[n]; + for (p = start, n = 0; p < end; p += strlen(p) + 1) { + field[n++] = p; + } + } + + ~dbClassDescriptor() { + cls->remove(); + delete[] field; + } +}; + +class dbLoadHandle { + friend class dbDatabase; + +private: + dbGetTie tie; + byte * curr; + byte * end; + union { + byte bval; + oid_t oval; + db_int8 lval; + db_int4 ival; + db_real8 dval; + } u; + unsigned type; + int fieldNo; + void * ptr; + dbClassDescriptor *desc; + +public: + dbLoadHandle() { fieldNo = -1; } + + char *getClassName() { return desc->name; } + + char *getFieldName() { return desc->field[fieldNo]; } + + bool hasNextField() { + bool success = hasNext(); + if (success) { fieldNo += 1; } + return success; + } + + bool hasNext() { + if (curr == end) { return false; } + ptr = (byte *)&u; + type = *curr++; + switch (type & 0xF) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: + memcpy(&u, curr, sizeof(oid_t)); + curr += sizeof(oid_t); + break; + case dybase_bool_type: u.bval = *curr++; break; + case dybase_int_type: + memcpy(&u, curr, sizeof(db_int4)); + curr += sizeof(db_int4); + break; + case dybase_date_type: + case dybase_long_type: + case dybase_real_type: + memcpy(&u, curr, sizeof(db_int8)); + curr += sizeof(db_int8); + break; + case dybase_chars_type: + if (type != dybase_chars_type) { + // small string + u.ival = type >> 4; + type = dybase_chars_type; + ptr = curr; + curr += u.ival; + } else { + memcpy(&u.ival, curr, sizeof(db_int4)); + curr += sizeof(db_int4); + ptr = curr; + curr += u.ival; + } + break; + case dybase_bytes_type: + if (type != dybase_bytes_type) { + // small string + u.ival = type >> 4; + type = dybase_bytes_type; + ptr = curr; + curr += u.ival; + } + else { + memcpy(&u.ival, curr, sizeof(db_int4)); + curr += sizeof(db_int4); + ptr = curr; + curr += u.ival; + } + break; + case dybase_array_type: + if (type != dybase_array_type) { + // small array + u.ival = type >> 4; + type = dybase_array_type; + } else { + memcpy(&u.ival, curr, sizeof(db_int4)); + curr += sizeof(db_int4); + } + break; + case dybase_map_type: + if (type != dybase_map_type) { + // small array + u.ival = type >> 4; + type = dybase_map_type; + } else { + memcpy(&u.ival, curr, sizeof(db_int4)); + curr += sizeof(db_int4); + } + break; + } + return true; + } + + int getType() { return type; } + + void *getValue() { return ptr; } + + int getLength() { return u.ival; } +}; + +class dbStoreHandle { +private: + friend class dbDatabase; + dbSmallBuffer signature; + dbSmallBuffer body; + oid_t oid; + +public: + dbDatabase *db; + + dbStoreHandle(dbDatabase *db, oid_t oid, char const *className) { + this->db = db; + this->oid = oid; + body.append(sizeof(dbObject)); + strcpy(signature.append((int)strlen(className) + 1), className); + } + + void setFieldValue(char const *fieldName, int type, void *value, int length) { + strcpy(signature.append((int)strlen(fieldName) + 1), fieldName); + setElement(type, value, length); + } + + void setElement(int type, void *value, int length) { + switch (type) { + case dybase_object_ref_type: + case dybase_array_ref_type: + case dybase_index_ref_type: + *body.append(1) = char(type); + memcpy(body.append(sizeof(oid_t)), value, sizeof(oid_t)); + break; + case dybase_bool_type: + *body.append(1) = char(type); + *body.append(1) = *(byte *)value; + break; + case dybase_int_type: + *body.append(1) = char(type); + memcpy(body.append(sizeof(db_int4)), value, sizeof(db_int4)); + break; + case dybase_date_type: + case dybase_long_type: + case dybase_real_type: + *body.append(1) = char(type); + memcpy(body.append(sizeof(db_int8)), value, sizeof(db_int8)); + break; + case dybase_chars_type: + if ((unsigned)(length - 1) < 15) { + *body.append(1) = (byte)(dybase_chars_type | (length << 4)); + } else { + *body.append(1) = char(type); + memcpy(body.append(sizeof(db_int4)), &length, sizeof(db_int4)); + } + memcpy(body.append(length), value, length); + break; + case dybase_bytes_type: + if ((unsigned)(length - 1) < 15) { + *body.append(1) = (byte)(dybase_bytes_type | (length << 4)); + } + else { + *body.append(1) = char(type); + memcpy(body.append(sizeof(db_int4)), &length, sizeof(db_int4)); + } + memcpy(body.append(length), value, length); + break; + case dybase_array_type: + if ((unsigned)(length - 1) < 15) { + *body.append(1) = (byte)(dybase_array_type | (length << 4)); + } else { + *body.append(1) = char(type); + memcpy(body.append(sizeof(db_int4)), &length, sizeof(db_int4)); + } + break; + case dybase_map_type: + if ((unsigned)(length - 1) < 15) { + *body.append(1) = (byte)(dybase_map_type | (length << 4)); + } else { + *body.append(1) = char(type); + memcpy(body.append(sizeof(db_int4)), &length, sizeof(db_int4)); + } + break; + default: assert(false); + } + } +}; + +/** + * Database class + */ +class dbDatabase { + friend class dbBtree; + friend class dbBtreePage; + friend class dbBtreeIterator; + friend class dbBtreeLeafPage; + friend class dbPagePool; + + friend class dbGetTie; + friend class dbPutTie; + + dbDatabase(const dbDatabase &); + dbDatabase &operator=(const dbDatabase &); + +public: + typedef void (*dbErrorHandler)(int error, char const *msg); + + bool open(char const *databaseName, int openAttr = dbFile::no_buffering); + //bool open(wchar_t const *databaseName, int openAttr = dbFile::no_buffering); + + /** + * Close database + */ + void close(); + + /** + * Commit transaction + */ + void commit(); + + /** + * Rollback transaction + */ + void rollback(); + + /** + * Allocate object identifier + * @return allocated object identifier + */ + oid_t allocate(); + + /** + * Free object + * @param oif object identifier of deallocated object + */ + void freeObject(oid_t oid); + + dbStoreHandle *getStoreHandle(oid_t oid, char const *className) { + return new dbStoreHandle(this, oid, className); + } + + dbLoadHandle *getLoadHandle(oid_t oid); + + void storeObject(dbStoreHandle *handle); + + oid_t getRoot(); + + void setRoot(oid_t oid); + + void setGcThreshold(long maxAllocatedDelta) { + gcThreshold = maxAllocatedDelta; + } + + void gc(); + + void handleError(int error, char const *msg = NULL); + void throwException(int error, char const *msg = NULL); + + enum dbAccessType { dbReadOnly = 0, dbAllAccess = 1 }; + const dbAccessType accessType; + const length_t extensionQuantum; + const length_t initIndexSize; + + dbDatabase(dbAccessType type = dbAllAccess, dbErrorHandler hnd = NULL, + length_t poolSize = dbDefaultPagePoolSize, + length_t dbExtensionQuantum = dbDefaultExtensionQuantum, + length_t dbInitIndexSize = dbDefaultInitIndexSize); + + /** + * Database detructor + */ + ~dbDatabase(); + +protected: + dbHeader *header; // base address of database file mapping + db_int4 * dirtyPagesMap; // bitmap of changed pages in current index + bool modified; + + int curr; // copy of header->root, used to allow read access to the database + // during transaction commit + + offs_t dbFileExtensionQuantum; + offs_t dbFileSizeLimit; + + length_t currRBitmapPage; // current bitmap page for allocating records + length_t currRBitmapOffs; // offset in current bitmap page for allocating + // unaligned records + length_t currPBitmapPage; // current bitmap page for allocating page objects + length_t currPBitmapOffs; // offset in current bitmap page for allocating + // page objects + + struct dbLocation { + offs_t pos; + length_t size; + dbLocation *next; + }; + dbLocation *reservedChain; + + length_t committedIndexSize; + length_t currIndexSize; + + dbClassDescriptor *classDescList; + + dbFile * file; + dbMutex mutex; + dbPagePool pool; + + int *bitmapPageAvailableSpace; + bool opened; + + dbHashtable classOidHash; + dbHashtable classSignatureHash; + + db_int4 *greyBitmap; // bitmap of visited during GC but not yet marked object + db_int4 *blackBitmap; // bitmap of objects marked during GC + long gcThreshold; + long allocatedDelta; + bool gcDone; + + dbErrorHandler errorHandler; + + /** + * Get position of the object in the database file + * @param oid object identifier + * @param offset of the object in database file + */ + offs_t getPos(oid_t oid) { + byte * p = pool.get(header->root[1 - curr].index + + oid / dbHandlesPerPage * dbPageSize); + offs_t pos = *((offs_t *)p + oid % dbHandlesPerPage); + pool.unfix(p); + return pos; + } + + offs_t getGCPos(oid_t oid) { + byte * p = pool.get(header->root[curr].index + + oid / dbHandlesPerPage * dbPageSize); + offs_t pos = *((offs_t *)p + oid % dbHandlesPerPage); + pool.unfix(p); + return pos; + } + + void markOid(oid_t oid) { + if (oid != 0) { + offs_t pos = getGCPos(oid); + unsigned bit = (unsigned)(pos >> dbAllocationQuantumBits); + if ((blackBitmap[bit >> 5] & (1 << (bit & 31))) == 0) { + greyBitmap[bit >> 5] |= 1 << (bit & 31); + } + } + } + + void markObject(dbObject *obj); + byte *markField(byte *p); + void startGC(); + + /** + * Set position of the object + * @param oid object identifier + * @param pos offset of the object in database file + */ + void setPos(oid_t oid, offs_t pos) { + byte *p = pool.put(header->root[1 - curr].index + + oid / dbHandlesPerPage * dbPageSize); + *((offs_t *)p + oid % dbHandlesPerPage) = pos; + pool.unfix(p); + } + + /** + * Get object + * @param tie get tie used to pin accessed object + * @param oid object indentifier + * @return object with this oid + */ + dbObject *getObject(dbGetTie &tie, oid_t oid) { + offs_t pos = getPos(oid); + assert(!(pos & (dbFreeHandleFlag | dbPageObjectFlag))); + tie.set(pool, pos & ~dbFlagsMask); + return (dbObject *)tie.get(); + } + + /** + * Get object header + * @param rec variable to receive object header + * @param oid object identifier + */ + void getHeader(dbObject &rec, oid_t oid) { + offs_t pos = getPos(oid); + int offs = (int)pos & (dbPageSize - 1); + byte * p = pool.get(pos - offs); + rec = *(dbObject *)(p + (offs & ~dbFlagsMask)); + pool.unfix(p); + } + + /** + * Get pointer to the body of page object which can be used to update this + * object + * @param oid page object identifier + * @return pointer to the pinned object + */ + byte *put(oid_t oid) { + offs_t pos = getPos(oid); + int offs = (int)pos & (dbPageSize - 1); + return pool.put(pos - offs) + (offs & ~dbFlagsMask); + } + + /** + * Get readonly pointer to the body of page object + * @param oid page object identifier + * @return pointer to the pinned object + */ + byte *get(oid_t oid) { + offs_t pos = getPos(oid); + int offs = (int)pos & (dbPageSize - 1); + return pool.get(pos - offs) + (offs & ~dbFlagsMask); + } + + /** + * Get pointer to the record which can be used to uodate this record. Record + * length is not changed. + * @param tie put tie used to pin updated object + * @param oid page object identifier + * @return pointer to the pinned object + */ + dbObject *putObject(dbPutTie &tie, oid_t oid); + + /** + * Get pointer to the page object which can be used to uodate this object + * @param oid page object identifier + * @return pointer to the page object + */ + byte *put(dbPutTie &tie, oid_t oid); + + oid_t allocateId(); + + offs_t allocate(length_t size, oid_t oid = 0); + + /** + * Free object + * @param pos position of the object in database file + * @param size size of the object + */ + void free(offs_t pos, length_t size); + + /** + * Check that allocated object fits in the database file and extend database + * file if it is not true + * @param size position of the allocated object + size of the object + */ + void extend(offs_t size); + + /** + * Clone bitmap page(s). Thisd method is used to clonepages of the bitmap (if + * them were not already cloned within this transaction) which will ber + * affected by free method at the end of transaction. + * @param pos position of the object whcih will be deallocated + * @param size size of the object whcih will be deallocated + */ + void cloneBitmap(offs_t pos, length_t size); + + /** + * Release obejct identifier + * @param oid deallocated object identifier + */ + void freeId(oid_t oid); + + /** + * Allocate and write object + * @return object identifer of new object + */ + oid_t allocateObject(dbObject *obj); + + /** + * Allocate page object + * @return object identifer of page object + */ + oid_t allocatePage() { + oid_t oid = allocateId(); + setPos(oid, allocate(dbPageSize) | dbPageObjectFlag | dbModifiedFlag); + return oid; + } + + /** + * Deallocate page object + * @param oid object identifer of page object + */ + void freePage(oid_t oid); + + /** + * Load database schema. This method loads table decriptors from database, + * compare them with application classes, do necessary reformatting and save + * update andnew table decriptor in database + * @return true if schema was successfully loaded + */ + void loadScheme(); + + /** + * Check if location is reserved + * @param pos start position of the location + * @param size location size + * @return true id location was reserved + */ + bool wasReserved(offs_t pos, length_t size); + + /** + * Mark location as reserved. This method is used by allocator to protect hole + * located in memory allocation bitmap, from been used by recursuve call of + * allocator (needed to clone bitmap pages). + * @param location [out] local structure describing location. + * @param pos start position of the location + * @param size location size + */ + void reserveLocation(dbLocation &location, offs_t pos, length_t size); + + /** + * Remove location from list of reserved locations. It is done after location + * is marked as occupied in bitmap. + */ + void commitLocation(); + + void commitTransaction(); + void setDirty(); +}; + +#endif diff --git a/storage/dybase/src/dybase.cpp b/storage/dybase/src/dybase.cpp new file mode 100644 index 000000000..4ebe6f2fa --- /dev/null +++ b/storage/dybase/src/dybase.cpp @@ -0,0 +1,304 @@ + +#include "stdtp.h" +#include "database.h" + +#define INSIDE_DYBASE + +#include "btree.h" +#include "dybase.h" + +dybase_storage_t dybase_open(const char *file_path, int page_pool_size, + dybase_error_handler_t hnd, int read_write) { + try { + if (page_pool_size == 0) { page_pool_size = dbDefaultPagePoolSize; } + + dbDatabase::dbAccessType at = + read_write ? dbDatabase::dbAllAccess : dbDatabase::dbReadOnly; + + dbDatabase *db = new dbDatabase(at, (dbDatabase::dbErrorHandler)hnd, + page_pool_size / dbPageSize); + if (db->open(file_path)) { + return db; + } else { + delete db; + return NULL; + } + } catch (dbException &) { + return NULL; + } +} + +void dybase_close(dybase_storage_t storage) { + dbDatabase *db = (dbDatabase *)storage; + try { + db->close(); + delete db; + } catch (dbException &) { delete db; } +} + +void dybase_commit(dybase_storage_t storage) { + try { + ((dbDatabase *)storage)->commit(); + } catch (dbException &) {} +} + +void dybase_rollback(dybase_storage_t storage) { + try { + ((dbDatabase *)storage)->rollback(); + } catch (dbException &) {} +} + +dybase_oid_t dybase_get_root_object(dybase_storage_t storage) { + // try { + return ((dbDatabase *)storage)->getRoot(); + //} catch (dbException&) { + // return 0; + //} +} + +void dybase_set_root_object(dybase_storage_t storage, dybase_oid_t oid) { + try { + ((dbDatabase *)storage)->setRoot(oid); + } catch (dbException &) {} +} + +dybase_oid_t dybase_allocate_object(dybase_storage_t storage) { + try { + return ((dbDatabase *)storage)->allocate(); + } catch (dbException &) { return 0; } +} + +void dybase_deallocate_object(dybase_storage_t storage, dybase_oid_t oid) { + try { + ((dbDatabase *)storage)->freeObject(oid); + } catch (dbException &) {} +} + +dybase_handle_t dybase_begin_store_object(dybase_storage_t storage, + dybase_oid_t oid, + char const * class_name) { + try { + return ((dbDatabase *)storage)->getStoreHandle(oid, class_name); + } catch (dbException &) { return NULL; } +} + +void dybase_store_object_field(dybase_handle_t handle, char const *field_name, + int field_type, void *value_ptr, + int value_length) { + try { + ((dbStoreHandle *)handle) + ->setFieldValue(field_name, field_type, value_ptr, value_length); + } catch (dbException &) {} +} + +void dybase_store_array_element(dybase_handle_t handle, int elem_type, + void *value_ptr, int value_length) { + try { + ((dbStoreHandle *)handle)->setElement(elem_type, value_ptr, value_length); + } catch (dbException &) {} +} + +void dybase_store_map_entry(dybase_handle_t handle, int key_type, void *key_ptr, + int key_length, int value_type, void *value_ptr, + int value_length) { + try { + ((dbStoreHandle *)handle)->setElement(key_type, key_ptr, key_length); + ((dbStoreHandle *)handle)->setElement(value_type, value_ptr, value_length); + } catch (dbException &) {} +} + +void dybase_end_store_object(dybase_handle_t handle) { + dbStoreHandle *hnd = (dbStoreHandle *)handle; + try { + hnd->db->storeObject(hnd); + delete hnd; + } catch (dbException &) { delete hnd; } +} + +dybase_handle_t dybase_begin_load_object(dybase_storage_t storage, + dybase_oid_t oid) { + try { + return ((dbDatabase *)storage)->getLoadHandle(oid); + } catch (dbException &) { return NULL; } +} + +void dybase_end_load_object(dybase_handle_t handle) { + if (handle) { + dbLoadHandle *hnd = (dbLoadHandle *)handle; + assert(hnd); + delete hnd; + } +} + +char *dybase_get_class_name(dybase_handle_t handle) { + return ((dbLoadHandle *)handle)->getClassName(); +} + +char *dybase_next_field(dybase_handle_t handle) { + dbLoadHandle *hnd = (dbLoadHandle *)handle; + if (!hnd->hasNextField()) { + delete hnd; + return NULL; + } else { + return hnd->getFieldName(); + } +} + +void dybase_next_element(dybase_handle_t handle) { + bool hasNext = ((dbLoadHandle *)handle)->hasNext(); + assert(hasNext); + hasNext = hasNext; +} + +void dybase_get_value(dybase_handle_t handle, int *type, void **value_ptr, + int *value_length) { + dbLoadHandle *hnd = (dbLoadHandle *)handle; + *type = hnd->getType(); + *value_ptr = hnd->getValue(); + *value_length = hnd->getLength(); +} + +dybase_oid_t dybase_create_index(dybase_storage_t storage, int key_type, + int unique) { + try { + return dbBtree::allocate((dbDatabase *)storage, key_type, (bool)unique); + } catch (dbException &) { return 0; } +} + +int dybase_insert_in_index(dybase_storage_t storage, dybase_oid_t index, + void *key, int key_type, int key_size, + dybase_oid_t obj, int replace) { + try { + return dbBtree::insert((dbDatabase *)storage, (oid_t)index, key, key_type, + key_size, (oid_t)obj, (bool)replace); + } catch (dbException &) { return 0; } +} + +int dybase_remove_from_index(dybase_storage_t storage, dybase_oid_t index, + void *key, int key_type, int key_size, + dybase_oid_t obj) { + try { + return dbBtree::remove((dbDatabase *)storage, (oid_t)index, key, key_type, + key_size, (oid_t)obj); + } catch (dbException &) { return 0; } +} + +int dybase_is_index_unique(dybase_storage_t storage, dybase_oid_t index) { + try { + return dbBtree::is_unique((dbDatabase *)storage, (oid_t)index); + } catch (dbException &) { return 0; } +} + +int dybase_get_index_type(dybase_storage_t storage, dybase_oid_t index) { + try { + return dbBtree::get_type((dbDatabase *)storage, (oid_t)index); + } + catch (dbException &) { return 0; } +} + +int dybase_index_search(dybase_storage_t storage, dybase_oid_t index, + int key_type, void *min_key, int min_key_size, + int min_key_inclusive, void *max_key, int max_key_size, + int max_key_inclusive, + dybase_oid_t **selected_objects) { + try { + dbSearchContext ctx; + ctx.low = min_key; + ctx.lowSize = min_key_size; + ctx.lowInclusive = min_key_inclusive; + ctx.high = max_key; + ctx.highSize = max_key_size; + ctx.highInclusive = max_key_inclusive; + ctx.keyType = key_type; + dbBtree::find((dbDatabase *)storage, (oid_t)index, ctx); + *selected_objects = ctx.selection.grab(); + return ctx.selection.size(); + } catch (dbException &) { return 0; } +} + +void dybase_free_selection(dybase_storage_t /*storage*/, + dybase_oid_t *selected_objects, int /*n_selected*/) { + try { + delete[] selected_objects; + } catch (dbException &) {} +} + +void dybase_drop_index(dybase_storage_t storage, dybase_oid_t index) { + try { + dbBtree::drop((dbDatabase *)storage, (oid_t)index); + } catch (dbException &) {} +} + +void dybase_clear_index(dybase_storage_t storage, dybase_oid_t index) { + try { + dbBtree::clear((dbDatabase *)storage, (oid_t)index); + } catch (dbException &) {} +} + +dybase_iterator_t dybase_create_index_iterator( + dybase_storage_t storage, dybase_oid_t index, int key_type, void *min_key, + int min_key_size, int min_key_inclusive, void *max_key, int max_key_size, + int max_key_inclusive, int ascent) { + try { + return (dybase_iterator_t) new dbBtreeIterator( + (dbDatabase *)storage, (oid_t)index, key_type, min_key, min_key_size, + min_key_inclusive, max_key, max_key_size, max_key_inclusive, + (bool)ascent); + } catch (dbException &) { return NULL; } +} + +dybase_oid_t dybase_index_iterator_next(dybase_iterator_t iterator) { + try { + return ((dbBtreeIterator *)iterator)->next(); + } catch (dbException &) { return 0; } +} + +void dybase_free_index_iterator(dybase_iterator_t iterator) { + delete (dbBtreeIterator *)iterator; +} + +void dybase_set_gc_threshold(dybase_storage_t storage, long allocated_delta) { + ((dbDatabase *)storage)->setGcThreshold(allocated_delta); +} + +void dybase_gc(dybase_storage_t storage) { ((dbDatabase *)storage)->gc(); } + + +hashtable_t hashtable_create() { + return new dbHashtable(); +} +void hashtable_put(hashtable_t ht, void *key, int keySize, void *value) +{ + dbHashtable* pht = (dbHashtable*)ht; + pht->put(key, keySize, value); +} +void* hashtable_get(hashtable_t ht, void *key, int keySize) +{ + dbHashtable* pht = (dbHashtable*)ht; + return pht->get(key, keySize); +} +void hashtable_free(hashtable_t ht) +{ + dbHashtable* pht = (dbHashtable*)ht; + delete pht; +} + +void* hashtable_remove(hashtable_t ht, void *key, int keySize) +{ + dbHashtable* pht = (dbHashtable*)ht; + return pht->remove(key, keySize); +} +void hashtable_clear(hashtable_t ht) { + dbHashtable* pht = (dbHashtable*)ht; + pht->clear(); +} + +typedef int each_cb_t(void* key, unsigned int key_length, void* data, void* opaque); + +void hashtable_each(hashtable_t ht, each_cb_t* pcb, void* opaque) +{ + dbHashtable* pht = (dbHashtable*)ht; + pht->each(pcb, opaque); +} + + diff --git a/storage/dybase/src/file.cpp b/storage/dybase/src/file.cpp new file mode 100644 index 000000000..e33a62819 --- /dev/null +++ b/storage/dybase/src/file.cpp @@ -0,0 +1,492 @@ +//-< FILE.CPP >------------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 20-Nov-98 K.A. Knizhnik * / [] \ * +// Last update: 10-Dec-98 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// System dependent implementation of mapped on memory file +//-------------------------------------------------------------------*--------* + +#include "stdtp.h" +#include "database.h" + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + +dbFile::~dbFile() { close(); } + +#if defined(_WIN32) + + // class OS_info : public OSVERSIONINFO { + // public: + // OS_info() { + // dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + // GetVersionEx(this); + // } + //}; + // + // static OS_info osinfo; + +#define BAD_POS 0xFFFFFFFF // returned by SetFilePointer and GetFileSize + +dbFile::dbFile() { fh = INVALID_HANDLE_VALUE; } + +int dbFile::open(char const *fileName, int attr) { +#ifdef UNICODE + WCHAR buffer[MAX_PATH] = {0}; + //utf8_to_wstr(fileName, strlen(fileName), buffer, MAX_PATH); + MultiByteToWideChar(CP_UTF8, 0, fileName,-1, buffer, MAX_PATH); + fh = CreateFile(buffer, + (attr & read_only) +#else + fh = CreateFile(fileName, + (attr & read_only) +#endif + ? GENERIC_READ + : GENERIC_READ | GENERIC_WRITE, + (attr & read_only) ? FILE_SHARE_READ : 0, NULL, + (attr & read_only) + ? OPEN_EXISTING + : (attr & truncate) ? CREATE_ALWAYS : OPEN_ALWAYS, +#ifdef _WINCE + FILE_ATTRIBUTE_NORMAL, +#else + ((attr & no_buffering) ? FILE_FLAG_NO_BUFFERING : 0) | + ((attr & sequential) ? FILE_FLAG_SEQUENTIAL_SCAN + : FILE_FLAG_RANDOM_ACCESS), +#endif + NULL); + if (fh == INVALID_HANDLE_VALUE) { return GetLastError(); } + return ok; +} + +int dbFile::open(wchar_t const *fileName, int attr) { + fh = CreateFileW( + fileName, + (attr & read_only) ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + (attr & read_only) ? FILE_SHARE_READ : 0, NULL, + (attr & read_only) ? OPEN_EXISTING + : (attr & truncate) ? CREATE_ALWAYS : OPEN_ALWAYS, +#ifdef _WINCE + FILE_ATTRIBUTE_NORMAL, +#else + ((attr & no_buffering) ? FILE_FLAG_NO_BUFFERING : 0) | + ((attr & sequential) ? FILE_FLAG_SEQUENTIAL_SCAN + : FILE_FLAG_RANDOM_ACCESS), +#endif + NULL); + if (fh == INVALID_HANDLE_VALUE) { return GetLastError(); } + return ok; +} + +int dbFile::read(offs_t pos, void *buf, length_t size) { + DWORD readBytes; + // if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { + OVERLAPPED Overlapped; + Overlapped.Offset = nat8_low_part(pos); + Overlapped.OffsetHigh = nat8_high_part(pos); + Overlapped.hEvent = NULL; + if (ReadFile(fh, buf, size, &readBytes, &Overlapped)) { + return readBytes == size ? ok : eof; + } else { + int rc = GetLastError(); + return (rc == ERROR_HANDLE_EOF) ? eof : rc; + } + //} else { + // LONG high_pos = nat8_high_part(pos); + // LONG low_pos = nat8_low_part(pos); + // dbCriticalSection cs(mutex); + // if (SetFilePointer(fh, low_pos, + // &high_pos, FILE_BEGIN) != BAD_POS + // && ReadFile(fh, buf, size, &readBytes, NULL)) + // { + // return (readBytes == size) ? ok : eof; + // } else { + // int rc = GetLastError(); + // return rc == ERROR_HANDLE_EOF ? eof : rc; + // } + //} +} + +int dbFile::read(void *buf, length_t size) { + DWORD readBytes; + if (ReadFile(fh, buf, size, &readBytes, NULL)) { + return (readBytes == size) ? ok : eof; + } else { + int rc = GetLastError(); + return rc == ERROR_HANDLE_EOF ? eof : rc; + } +} + +int dbFile::setSize(offs_t size) { + LONG low_pos = nat8_low_part(size); + LONG high_pos = nat8_high_part(size); + if (SetFilePointer(fh, low_pos, &high_pos, FILE_BEGIN) == BAD_POS || + !SetEndOfFile(fh)) { + return GetLastError(); + } + return ok; +} + +int dbFile::write(void const *buf, length_t size) { + DWORD writtenBytes; + return !WriteFile(fh, buf, size, &writtenBytes, NULL) + ? GetLastError() + : (writtenBytes == size) ? int(ok) : int(eof); +} + +int dbFile::write(offs_t pos, void const *buf, length_t size) { + DWORD writtenBytes; + // if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { + OVERLAPPED Overlapped; + Overlapped.Offset = nat8_low_part(pos); + Overlapped.OffsetHigh = nat8_high_part(pos); + Overlapped.hEvent = NULL; + return WriteFile(fh, buf, size, &writtenBytes, &Overlapped) + ? writtenBytes == size ? int(ok) : int(eof) + : GetLastError(); + //} else { + // LONG high_pos = nat8_high_part(pos); + // LONG low_pos = nat8_low_part(pos); + // dbCriticalSection cs(mutex); + // return SetFilePointer(fh, low_pos, &high_pos, FILE_BEGIN) + // == BAD_POS || + // !WriteFile(fh, buf, size, &writtenBytes, NULL) + // ? GetLastError() + // : (writtenBytes == size) ? int(ok) : int(eof); + //} +} + +int dbFile::flush() { return FlushFileBuffers(fh) ? int(ok) : GetLastError(); } + +int dbFile::close() { + if (fh != INVALID_HANDLE_VALUE) { + if (CloseHandle(fh)) { + fh = INVALID_HANDLE_VALUE; + return ok; + } else { + return GetLastError(); + } + } else { + return ok; + } +} + +void *dbFile::allocateBuffer(length_t size) { + return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +} + +void dbFile::protectBuffer(void *buf, length_t size, bool readonly) { + DWORD oldProt; + VirtualProtect(buf, size, readonly ? PAGE_READONLY : PAGE_READWRITE, + &oldProt); +} + +void dbFile::deallocateBuffer(void *buffer, length_t /*size*/) { + VirtualFree(buffer, 0, MEM_RELEASE); +} + +char *dbFile::errorText(int code, char *buf, length_t bufSize) { + int len = 0; + + switch (code) { + case ok: strncpy(buf, "No error", bufSize); break; + case eof: strncpy(buf, "Transfer less bytes than specified", bufSize); break; + default: +#ifndef UNDER_CE + len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, code, 0, buf, + bufSize, NULL); +#endif + if (len == 0) { + char errcode[64]; + sprintf(errcode, "unknown error %u", code); + strncpy(buf, errcode, bufSize); + } + } + return buf; +} + +#else // Unix + +#include +#include +#include + +#ifdef __linux__ +#define lseek(fd, offs, whence) lseek64(fd, offs, whence) +#endif + +dbFile::dbFile() { fd = -1; } + +int dbFile::open(char const *fileName, int attr) { + char *name = (char *)fileName; +#if defined(__sun) + fd = ::open64(name, + ((attr & read_only) ? O_RDONLY : O_CREAT | O_RDWR) | + ((attr & truncate) ? O_TRUNC : 0), + 0666); + if (fd >= 0) { directio(fd, DIRECTIO_ON); } +#elif defined(_AIX) +#if defined(_AIX43) + fd = + ::open64(name, + ((attr & read_only) ? O_RDONLY + : O_CREAT | O_RDWR | O_LARGEFILE | O_DSYNC | + ((attr & no_buffering) ? O_DIRECT : 0)) +#else + fd = ::open64(name, ((attr & read_only) ? O_RDONLY : O_CREAT|O_RDWR|O_LARGEFILE +#endif /* _AIX43 */ + | ((attr & truncate) ? O_TRUNC : 0), + 0666); +#else + fd = ::open(name, + O_LARGEFILE | ((attr & read_only) ? O_RDONLY : O_CREAT | O_RDWR) | + ((attr & truncate) ? O_TRUNC : 0), + 0666); +#endif + if (fd < 0) { return errno; } + return ok; +} + +//int dbFile::open(wchar_t const *fileName, int attr) { +// return open(cvt::w2a(fileName), attr); +//} + +int dbFile::setSize(offs_t size) { return ftruncate(fd, size); } + +int dbFile::read(offs_t pos, void *buf, length_t size) { + ssize_t rc; +#if defined(__sun) || defined(_AIX43) + rc = pread64(fd, buf, size, pos); +#else + { + dbCriticalSection cs(mutex); + if (offs_t(lseek(fd, pos, SEEK_SET)) != pos) { return errno; } + rc = ::read(fd, buf, size); + } +#endif + if (rc == -1) { + return errno; + } else if (length_t(rc) != size) { + return eof; + } else { + return ok; + } +} + +int dbFile::read(void *buf, length_t size) { + ssize_t rc = ::read(fd, buf, size); + if (rc == -1) { + return errno; + } else if (length_t(rc) != size) { + return eof; + } else { + return ok; + } +} + +int dbFile::write(void const *buf, length_t size) { + ssize_t rc = ::write(fd, buf, size); + if (rc == -1) { + return errno; + } else if (length_t(rc) != size) { + return eof; + } else { + return ok; + } +} + +int dbFile::write(offs_t pos, void const *buf, length_t size) { + ssize_t rc; +#if defined(__sun) || defined(_AIX43) + rc = pwrite64(fd, buf, size, pos); +#else + { + dbCriticalSection cs(mutex); + if (offs_t(lseek(fd, pos, SEEK_SET)) != pos) { return errno; } + rc = ::write(fd, buf, size); + } +#endif + if (rc == -1) { + return errno; + } else if (length_t(rc) != size) { + return eof; + } else { + return ok; + } +} + +int dbFile::flush() { +#if defined(_AIX43) + return ok; // direct IO is used: no need in flush +#else + return fsync(fd) != ok ? errno : ok; +#endif +} + +int dbFile::close() { + if (fd != -1) { + if (::close(fd) == ok) { + fd = -1; + return ok; + } else { + return errno; + } + } else { + return ok; + } +} + +void *dbFile::allocateBuffer(length_t size) { +//#if defined(__MINGW__) || defined(__CYGWIN__) + return malloc(size); +//#else +// return memalign(sizeof(void *),size); +//#endif +} + +void dbFile::deallocateBuffer(void *buffer, length_t) { free(buffer); } + +char *dbFile::errorText(int code, char *buf, length_t bufSize) { + switch (code) { + case ok: strncpy(buf, "No error", bufSize); break; + case eof: strncpy(buf, "Transfer less bytes than specified", bufSize); break; + default: strncpy(buf, strerror(code), bufSize); + } + return buf; +} + +#endif + +int dbMultiFile::open(int n, dbSegment *seg, int attr) { + segment = new dbFileSegment[n]; + nSegments = n; + while (--n >= 0) { + segment[n].size = seg[n].size * dbPageSize; + segment[n].offs = seg[n].offs; + int rc = segment[n].open(seg[n].name, attr); + if (rc != ok) { + while (++n < nSegments) { + segment[n].close(); + } + return rc; + } + } + return ok; +} + +int dbMultiFile::close() { + if (segment != NULL) { + for (int i = nSegments; --i >= 0;) { + int rc = segment[i].close(); + if (rc != ok) { return rc; } + } + delete[] segment; + segment = NULL; + } + return ok; +} + +int dbMultiFile::setSize(offs_t) { return ok; } + +int dbMultiFile::flush() { + for (int i = nSegments; --i >= 0;) { + int rc = segment[i].flush(); + if (rc != ok) { return rc; } + } + return ok; +} + +int dbMultiFile::write(offs_t pos, void const *ptr, length_t size) { + int n = nSegments - 1; + char const *src = (char const *)ptr; + for (int i = 0; i < n; i++) { + if (pos < segment[i].size) { + if (pos + size > segment[i].size) { + int rc = segment[i].write(segment[i].offs + pos, src, + length_t(segment[i].size - pos)); + if (rc != ok) { return rc; } + size -= length_t(segment[i].size - pos); + src += length_t(segment[i].size - pos); + pos = 0; + } else { + return segment[i].write(segment[i].offs + pos, src, size); + } + } else { + pos -= segment[i].size; + } + } + return segment[n].write(segment[n].offs + pos, src, size); +} + +int dbMultiFile::read(offs_t pos, void *ptr, length_t size) { + int n = nSegments - 1; + char *dst = (char *)ptr; + for (int i = 0; i < n; i++) { + if (pos < segment[i].size) { + if (pos + size > segment[i].size) { + int rc = segment[i].read(segment[i].offs + pos, dst, + length_t(segment[i].size - pos)); + if (rc != ok) { return rc; } + size -= length_t(segment[i].size - pos); + dst += length_t(segment[i].size - pos); + pos = 0; + } else { + return segment[i].read(segment[i].offs + pos, dst, size); + } + } else { + pos -= segment[i].size; + } + } + return segment[n].read(segment[n].offs + pos, dst, size); +} + +int dbRaidFile::setSize(offs_t) { return ok; } + +int dbRaidFile::write(offs_t pos, void const *ptr, length_t size) { + char const *src = (char const *)ptr; + for (;;) { + int i = (int)(pos / raidBlockSize % nSegments); + int offs = (unsigned)pos % raidBlockSize; + length_t available = raidBlockSize - offs; + if (available >= size) { + return segment[i].write( + segment[i].offs + pos / (raidBlockSize * nSegments) * raidBlockSize + + offs, + src, size); + } + int rc = segment[i].write( + segment[i].offs + pos / (raidBlockSize * nSegments) * raidBlockSize + + offs, + src, available); + if (rc != ok) { return rc; } + src += available; + pos += available; + size -= available; + } +} + +int dbRaidFile::read(offs_t pos, void *ptr, length_t size) { + char *dst = (char *)ptr; + for (;;) { + int i = (int)(pos / raidBlockSize % nSegments); + int offs = (unsigned)pos % raidBlockSize; + length_t available = raidBlockSize - offs; + if (available >= size) { + return segment[i].read( + segment[i].offs + pos / (raidBlockSize * nSegments) * raidBlockSize + + offs, + dst, size); + } + int rc = segment[i].read( + segment[i].offs + pos / (raidBlockSize * nSegments) * raidBlockSize + + offs, + dst, available); + if (rc != ok) { return rc; } + dst += available; + pos += available; + size -= available; + } +} diff --git a/storage/dybase/src/file.h b/storage/dybase/src/file.h new file mode 100644 index 000000000..247d08516 --- /dev/null +++ b/storage/dybase/src/file.h @@ -0,0 +1,115 @@ +//-< FILE.CPP >------------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 20-Nov-98 K.A. Knizhnik * / [] \ * +// Last update: 30-Jan-99 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// System independent intrface to operating system file +//-------------------------------------------------------------------*--------* + +#ifndef __FILE_H__ +#define __FILE_H__ + +#include "sync.h" + +const length_t dbDefaultRaidBlockSize = 1024 * 1024; + +/** + * Internal implementation of file + */ +class dbFile { +protected: +#if defined(_WIN32) + HANDLE fh; +#else + int fd; +#endif + dbMutex mutex; + +public: + enum ReturnStatus { + ok = 0, + eof = -1 // number of read/written bytes is smaller than requested + }; + enum OpenAttributes { + read_only = 0x01, + truncate = 0x02, + sequential = 0x04, + no_buffering = 0x08 + }; + int open(char const *fileName, int attr); + int open(wchar_t const *fileName, int attr); + int write(void const *ptr, length_t size); + int read(void *ptr, length_t size); + + dbFile(); + virtual ~dbFile(); + + virtual int flush(); + virtual int close(); + + virtual int setSize(offs_t offs); + + virtual int write(offs_t pos, void const *ptr, length_t size); + virtual int read(offs_t pos, void *ptr, length_t size); + + static void *allocateBuffer(length_t bufferSize); + static void deallocateBuffer(void *buffer, length_t size = 0); + static void protectBuffer(void *buf, length_t bufSize, bool readonly); + + static length_t ramSize(); + + static char *errorText(int code, char *buf, length_t bufSize); +}; + +/** + * File consisting of multiple segments + */ +class dbMultiFile : public dbFile { +public: + struct dbSegment { + char * name; + offs_t size; + offs_t offs; + }; + + int open(int nSegments, dbSegment *segments, int attr); + + virtual int setSize(offs_t offs); + + virtual int flush(); + virtual int close(); + + virtual int write(offs_t pos, void const *ptr, length_t size); + virtual int read(offs_t pos, void *ptr, length_t size); + + dbMultiFile() { segment = NULL; } + ~dbMultiFile() {} + +protected: + class dbFileSegment : public dbFile { + public: + offs_t size; + offs_t offs; + }; + int nSegments; + dbFileSegment *segment; +}; + +/* + * RAID-1 file. Scattern file blocks between several physical segments + */ +class dbRaidFile : public dbMultiFile { + length_t raidBlockSize; + +public: + dbRaidFile(length_t blockSize) { raidBlockSize = blockSize; } + + virtual int setSize(offs_t offs); + + virtual int write(offs_t pos, void const *ptr, length_t size); + virtual int read(offs_t pos, void *ptr, length_t size); +}; + +#endif diff --git a/storage/dybase/src/hashtab.h b/storage/dybase/src/hashtab.h new file mode 100644 index 000000000..3cb7bc9e4 --- /dev/null +++ b/storage/dybase/src/hashtab.h @@ -0,0 +1,106 @@ +#ifndef __HASHTAB_H__ +#define __HASHTAB_H__ + +static const length_t dbHashtableSize = 1013; + +// if it returns non-zero - stops enumeration +typedef int each_cb(void* key, unsigned int key_length, void* data, void* opaque); + +class dbHashtable { +private: + struct Entry { + Entry * next; + void * value; + void * key; + length_t keySize; + unsigned hashCode; + }; + + Entry **table; + + static unsigned calculateHashCode(void *key, length_t keySize) { + unsigned char *p = (unsigned char *)key; + int n = int(keySize); + unsigned h = 0; + while (--n >= 0) { + h = (h << 2) ^ *p++; + } + return h; + } + + dbHashtable(const dbHashtable &); + dbHashtable &operator=(const dbHashtable &); + +public: + dbHashtable() { + table = new Entry *[dbHashtableSize]; + memset(table, 0, sizeof(Entry *) * dbHashtableSize); + } + + void put(void *key, length_t keySize, void *value) { + unsigned hashCode = calculateHashCode(key, keySize); + Entry * e = new Entry(); + e->hashCode = hashCode; + e->key = key; + e->keySize = keySize; + e->value = value; + unsigned h = hashCode % dbHashtableSize; + e->next = table[h]; + table[h] = e; + } + + void *get(void *key, length_t keySize) { + unsigned hashCode = calculateHashCode(key, keySize); + unsigned h = hashCode % dbHashtableSize; + for (Entry *e = table[h]; e != NULL; e = e->next) { + if (e->hashCode == hashCode && e->keySize == keySize && + memcmp(e->key, key, keySize) == 0) { + return e->value; + } + } + return NULL; + } + + void *remove(void *key, length_t keySize) { + Entry ** epp, *ep; + unsigned hashCode = calculateHashCode(key, keySize); + unsigned h = hashCode % dbHashtableSize; + for (epp = &table[h]; (ep = *epp) != NULL; epp = &ep->next) { + if (ep->hashCode == hashCode && memcmp(ep->key, key, keySize) == 0) { + *epp = ep->next; + return ep->value; + } + } + return NULL; + } + + void clear() { + for (int i = dbHashtableSize; --i >= 0;) { + Entry *e, *next; + for (e = table[i]; e != NULL; e = next) { + next = e->next; + delete e; + } + table[i] = NULL; + } + } + + void each(each_cb* pcb, void* opaque) { + for (int i = dbHashtableSize; --i >= 0;) { + Entry *e, *next; + for (e = table[i]; e != NULL; e = next) { + next = e->next; + if (pcb(e->key, e->keySize, e->value, opaque)) + break; + } + } + } + + + ~dbHashtable() { + clear(); + delete[] table; + } +}; + +#endif diff --git a/storage/dybase/src/pagepool.cpp b/storage/dybase/src/pagepool.cpp new file mode 100644 index 000000000..70852dc71 --- /dev/null +++ b/storage/dybase/src/pagepool.cpp @@ -0,0 +1,407 @@ +//-< PAGEPOOL.CPP >--------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 6-Feb-98 K.A. Knizhnik * / [] \ * +// Last update: 8-Feb-99 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// Page pool implementation +//-------------------------------------------------------------------*--------* + +#include "stdtp.h" +#include "dybase.h" +#include "database.h" + +byte *dbPagePool::find(offs_t addr, int state) { + dbPageHeader *ph; + assert(((int)addr & (dbPageSize - 1)) == 0); + + int hashCode = (unsigned(addr) >> dbPageBits) & hashBits; + int i, rc; + for (i = hashTable[hashCode]; i != 0; i = ph->collisionChain) { + ph = &pages[i]; + if (ph->offs == addr) { + if (ph->accessCount++ == 0) { + pages[ph->next].prev = ph->prev; + pages[ph->prev].next = ph->next; + } else { + assert((ph->state & dbPageHeader::psRaw) == 0); + } + if (!(ph->state & dbPageHeader::psDirty) && + (state & dbPageHeader::psDirty)) { + dirtyPages[nDirtyPages] = ph; + ph->writeQueueIndex = nDirtyPages++; + } +#ifdef PROTECT_PAGE_POOL + if ((state & dbPageHeader::psDirty)) { + dbFile::protectBuffer(buffer + (i - 1) * dbPageSize, dbPageSize, false); + } +#endif + ph->state |= state; + // printf("Find page %x, offs=%x\n", ph, addr); + return buffer + (i - 1) * dbPageSize; + } + } + i = freePages; + if (i == 0) { + i = pages->prev; + assert(((void)"unfixed page availabe", i != 0)); + ph = &pages[i]; + // printf("Throw page %p offs=%x\n", ph, ph->offs); + if (ph->state & dbPageHeader::psDirty) { + // printf("Write page " INT8_FORMAT "\n", ph->offs); + rc = file->write(ph->offs, buffer + (i - 1) * dbPageSize, dbPageSize); + if (rc != dbFile::ok) { + db->throwException(dybase_file_error, "Failed to write page"); + } + if (!flushing) { + dirtyPages[ph->writeQueueIndex] = dirtyPages[--nDirtyPages]; + dirtyPages[ph->writeQueueIndex]->writeQueueIndex = ph->writeQueueIndex; + } + if (ph->offs >= fileSize) { fileSize = ph->offs + dbPageSize; } + } + unsigned h = (unsigned(ph->offs) >> dbPageBits) & hashBits; + int * np; + for (np = &hashTable[h]; *np != i; np = &pages[*np].collisionChain) + ; + *np = ph->collisionChain; + pages[ph->next].prev = ph->prev; + pages[ph->prev].next = ph->next; + } else { + ph = &pages[i]; + freePages = ph->next; + if (i >= nPages) { nPages = i + 1; } + } + // printf("Use page %p offs=%x\n", ph, addr); + ph->accessCount = 1; + ph->state = 0; + ph->offs = addr; + ph->collisionChain = hashTable[hashCode]; + hashTable[hashCode] = i; + + if (state & dbPageHeader::psDirty) { + dirtyPages[nDirtyPages] = ph; + ph->writeQueueIndex = nDirtyPages++; + ph->state |= dbPageHeader::psDirty; + } + + byte *p = buffer + (i - 1) * dbPageSize; +#ifdef PROTECT_PAGE_POOL + dbFile::protectBuffer(p, dbPageSize, false); +#endif + + if (addr < fileSize) { + ph->state |= dbPageHeader::psRaw; + // printf("read addr=%x\n", addr); + rc = file->read(addr, p, dbPageSize); + if (rc == dbFile::eof) { + memset(p, 0, dbPageSize); + } else if (rc != dbFile::ok) { + db->throwException(dybase_file_error, "Failed to read page"); + } + ph->state &= ~(dbPageHeader::psWait | dbPageHeader::psRaw); + } else { + memset(p, 0, dbPageSize); + } +#ifdef PROTECT_PAGE_POOL + if (!(state & dbPageHeader::psDirty)) { + dbFile::protectBuffer(p, dbPageSize, true); + } +#endif + return p; +} + +void dbPagePool::copy(offs_t dst, offs_t src, length_t size) { + length_t dstOffs = (length_t)dst & (dbPageSize - 1); + length_t srcOffs = (length_t)src & (dbPageSize - 1); + dst -= dstOffs; + src -= srcOffs; + byte *dstPage = find(dst, dbPageHeader::psDirty); + byte *srcPage = find(src, 0); + size = (size + 3) >> 2; + do { + if (dstOffs == dbPageSize) { + unfix(dstPage); + dst += dbPageSize; + dstPage = find(dst, dbPageHeader::psDirty); + dstOffs = 0; + } + if (srcOffs == dbPageSize) { + unfix(srcPage); + src += dbPageSize; + srcPage = find(src, 0); + srcOffs = 0; + } + *(db_int4 *)(dstPage + dstOffs) = *(db_int4 *)(srcPage + srcOffs); + dstOffs += 4; + srcOffs += 4; + } while (--size != 0); + + unfix(dstPage); + unfix(srcPage); +} + +bool dbPagePool::open(dbFile *file, offs_t fileSize) { + int i; + + this->file = file; + this->fileSize = fileSize; + + length_t hashSize; + for (hashSize = minHashSize; hashSize < poolSize; hashSize *= 2) + ; + hashTable = new int[hashSize]; + memset(hashTable, 0, sizeof(int) * hashSize); + hashBits = hashSize - 1; + + pages = new dbPageHeader[poolSize + 1]; + pages->next = pages->prev = 0; + for (i = poolSize + 1; --i != 0;) { + pages[i].state = 0; + pages[i].next = i + 1; + } + pages[poolSize].next = 0; + freePages = 1; + + flushing = false; + nPages = 0; + nDirtyPages = 0; + dirtyPages = new dbPageHeader *[poolSize]; + +#if defined(__WATCOMC__) + // reserve one more pages to allow access after end of page + bufferSize = (poolSize + 1) * dbPageSize; +#else + bufferSize = poolSize * dbPageSize; +#endif + buffer = (byte *)dbFile::allocateBuffer(bufferSize); + return buffer != NULL; +} + +void dbPagePool::close() { + delete[] hashTable; + delete[] pages; + delete[] dirtyPages; + dbFile::deallocateBuffer(buffer, bufferSize); + pages = NULL; +} + +void dbPagePool::unfix(void *ptr) { + int i = (length_t((byte *)ptr - buffer) >> dbPageBits) + 1; + dbPageHeader *ph = &pages[i]; + assert(ph->accessCount > 0); + if (--ph->accessCount == 0) { + ph->next = pages->next; + ph->prev = 0; + pages->next = pages[ph->next].prev = i; +#ifdef PROTECT_PAGE_POOL + if (ph->state & dbPageHeader::psDirty) { + dbFile::protectBuffer(buffer + (i - 1) * dbPageSize, dbPageSize, true); + } +#endif + } +} + +void dbPagePool::unfixLIFO(void *ptr) { + int i = (length_t((byte *)ptr - buffer) >> dbPageBits) + 1; + dbPageHeader *ph = &pages[i]; + assert(ph->accessCount > 0); + if (--ph->accessCount == 0) { + ph->next = 0; + ph->prev = pages->prev; + pages->prev = pages[ph->prev].next = i; + } +} + +void dbPagePool::fix(void *ptr) { + int i = (length_t((byte *)ptr - buffer) >> dbPageBits) + 1; + dbPageHeader *ph = &pages[i]; + assert(ph->accessCount != 0); + ph->accessCount += 1; +} + +void dbPagePool::modify(void *ptr) { + int i = (length_t((byte *)ptr - buffer) >> dbPageBits) + 1; + dbPageHeader *ph = &pages[i]; + assert(ph->accessCount != 0); + if (!(ph->state & dbPageHeader::psDirty)) { + ph->state |= dbPageHeader::psDirty; + dirtyPages[nDirtyPages] = ph; + ph->writeQueueIndex = nDirtyPages++; + } +} + +void dbPagePool::put(offs_t pos, byte *obj, length_t size) { + int offs = (int)pos & (dbPageSize - 1); + byte *pg = find(pos - offs, dbPageHeader::psDirty); + while (size > dbPageSize - offs) { + memcpy(pg + offs, obj, dbPageSize - offs); + unfix(pg); + size -= dbPageSize - offs; + pos += dbPageSize - offs; + obj += dbPageSize - offs; + pg = find(pos, dbPageHeader::psDirty); + offs = 0; + } + memcpy(pg + offs, obj, size); + unfix(pg); +} + +static int __cdecl compareOffs(void const *a, void const *b) { + dbPageHeader *pa = *(dbPageHeader **)a; + dbPageHeader *pb = *(dbPageHeader **)b; + return pa->offs < pb->offs ? -1 : pa->offs == pb->offs ? 0 : 1; +} + +void dbPagePool::flush() { + int rc; + if (nDirtyPages != 0) { + flushing = true; + qsort(dirtyPages, nDirtyPages, sizeof(dbPageHeader *), compareOffs); + for (int i = 0, n = nDirtyPages; i < n; i++) { + dbPageHeader *ph = dirtyPages[i]; + if (ph->accessCount++ == 0) { + pages[ph->next].prev = ph->prev; + pages[ph->prev].next = ph->next; + } + if (ph->state & dbPageHeader::psDirty) { + // printf("Flush page " INT8_FORMAT "\n", ph->offs); + rc = file->write(ph->offs, buffer + (ph - pages - 1) * dbPageSize, + dbPageSize); + if (rc != dbFile::ok) { + db->throwException(dybase_file_error, "Failed to write page"); + } + ph->state &= ~dbPageHeader::psDirty; + if (ph->offs >= fileSize) { fileSize = ph->offs + dbPageSize; } + } + if (--ph->accessCount == 0) { + ph->next = pages->next; + ph->prev = 0; + pages->next = pages[ph->next].prev = int(ph - pages); + } + } + flushing = false; + nDirtyPages = 0; + } + rc = file->flush(); + if (rc != dbFile::ok) { + db->throwException(dybase_file_error, "Failed to flush pages pool"); + } +} + +void dbGetTie::set(dbPagePool &pool, offs_t pos) { + reset(); + int offs = (int)pos & (dbPageSize - 1); + byte * p = pool.get(pos - offs); + length_t size = ((dbObject *)(p + offs))->size; + if (offs + size > dbPageSize) { + byte *dst = new byte[size]; + obj = dst; + memcpy(dst, p + offs, dbPageSize - offs); + pool.unfix(p); + size -= dbPageSize - offs; + pos += dbPageSize - offs; + dst += dbPageSize - offs; + while (size > dbPageSize) { + p = pool.get(pos); + memcpy(dst, p, dbPageSize); + dst += dbPageSize; + size -= dbPageSize; + pos += dbPageSize; + pool.unfix(p); + } + p = pool.get(pos); + memcpy(dst, p, size); + pool.unfix(p); + page = NULL; + } else { + this->pool = &pool; + page = p; + obj = p + offs; + } +} + +void dbGetTie::reset() { + if (obj != NULL) { + if (page != NULL) { + assert(!pool->destructed()); // hack: page pool should not be + // destructed before any reference to the storage + // (cursors, references),... + pool->unfix(page); + page = NULL; + } else { + delete[] obj; + } + obj = NULL; + } +} + +void dbPutTie::set(dbPagePool &pool, oid_t oid, offs_t pos, length_t size) { + reset(); + + this->oid = oid; + this->pool = &pool; + + int offs = (int)pos & (dbPageSize - 1); + byte *p = pool.put(pos - offs); + if (offs + size > dbPageSize) { + this->size = size; + this->pos = pos; + byte *dst = new byte[size]; + obj = dst; + memcpy(dst, p + offs, dbPageSize - offs); + pool.unfix(p); + size -= dbPageSize - offs; + pos += dbPageSize - offs; + dst += dbPageSize - offs; + while (size > dbPageSize) { + p = pool.get(pos); + memcpy(dst, p, dbPageSize); + dst += dbPageSize; + size -= dbPageSize; + pos += dbPageSize; + pool.unfix(p); + } + p = pool.get(pos); + memcpy(dst, p, size); + pool.unfix(p); + page = NULL; + } else { + page = p; + obj = page + offs; + } +} + +void dbPutTie::reset() { + if (obj == NULL) { return; } + if (page == NULL) { + offs_t pos = this->pos; + int offs = (int)pos & (dbPageSize - 1); + length_t size = this->size; + assert(offs + size > dbPageSize); + byte *p = pool->put(pos - offs); + byte *src = obj; + memcpy(p + offs, src, dbPageSize - offs); + pool->unfix(p); + src += dbPageSize - offs; + size -= dbPageSize - offs; + pos += dbPageSize - offs; + while (size > dbPageSize) { + p = pool->put(pos); + memcpy(p, src, dbPageSize); + pool->unfix(p); + src += dbPageSize; + pos += dbPageSize; + size -= dbPageSize; + } + p = pool->put(pos); + memcpy(p, src, size); + pool->unfix(p); + delete[] obj; + } else { + pool->unfix(page); + page = NULL; + } + obj = NULL; + oid = 0; +} diff --git a/storage/dybase/src/pagepool.h b/storage/dybase/src/pagepool.h new file mode 100644 index 000000000..d063d14fd --- /dev/null +++ b/storage/dybase/src/pagepool.h @@ -0,0 +1,133 @@ +//-< PAGEPOOL.H >----------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 6-Feb-99 K.A. Knizhnik * / [] \ * +// Last update: 6-Feb-99 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// Page pool interface +//-------------------------------------------------------------------*--------* + +#include "file.h" + +class dbPageLruList { +public: + int next; + int prev; +}; + +class dbPageHeader : public dbPageLruList { +public: + int collisionChain; + int accessCount; + offs_t offs; + int writeQueueIndex; + int state; + enum PageState { // flag in accessCount field + psDirty = 0x01, // page has been modified + psRaw = 0x02, // page is loaded from the disk + psWait = 0x04 // other thread(s) wait load operation completion + }; +}; + +class dbGetTie; +class dbPutTie; +class dbDatabase; + +class dbPagePool { + friend class dbGetTie; + friend class dbPutTie; + friend class dbDatabase; + +protected: + dbPageHeader *pages; + int * hashTable; + int freePages; + int nPages; + + dbFile * file; + dbDatabase *db; + length_t hashBits; + length_t poolSize; + byte * buffer; + length_t bufferSize; + offs_t fileSize; + + int flushing; + + enum { + initialWobArraySize = 8, + minPoolSize = 256, + minHashSize = 16 * 1024, + maxUnusedMemory = 64 * 1024 * 1024 + }; + + length_t nDirtyPages; + dbPageHeader **dirtyPages; + + byte *find(offs_t addr, int state); + +public: + byte *get(offs_t addr) { return find(addr, 0); } + byte *put(offs_t addr) { return find(addr, dbPageHeader::psDirty); } + void put(offs_t addr, byte *obj, length_t size); + void copy(offs_t dst, offs_t src, length_t size); + void unfix(void *ptr); + void unfixLIFO(void *ptr); + void fix(void *ptr); + void modify(void *ptr); + bool open(dbFile *file, offs_t fileSize); + void close(); + void flush(); + + bool destructed() { return pages == NULL; } + + dbPagePool(dbDatabase *dbs, length_t size) : db(dbs), poolSize(size) {} +}; + +class dbGetTie { + friend class dbDatabase; + friend class dbAnyCursor; + dbPagePool *pool; + byte * obj; + byte * page; + + void set(dbPagePool &pool, offs_t pos); + void reset(); + +public: + byte *get() { return obj; } + + dbGetTie() { obj = NULL; } + ~dbGetTie() { reset(); } +}; + +class dbPutTie { + friend class dbDatabase; + friend class dbBtree; + + dbPagePool *pool; + byte * obj; + byte * page; + length_t size; + offs_t pos; + oid_t oid; + + void set(dbPagePool &pool, oid_t oid, offs_t pos, length_t size); + void reset(); + void unset() { + if (obj != NULL) { + if (page == NULL) { delete[] obj; } + obj = NULL; + } + } + +public: + byte *get() { return obj; } + + dbPutTie() { + obj = NULL; + oid = 0; + } + ~dbPutTie() { reset(); } +}; diff --git a/storage/dybase/src/stdtp.h b/storage/dybase/src/stdtp.h new file mode 100644 index 000000000..e1fea7135 --- /dev/null +++ b/storage/dybase/src/stdtp.h @@ -0,0 +1,142 @@ +//-< STDTP.H >-------------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 20-Nov-98 K.A. Knizhnik * / [] \ * +// Last update: 10-Dec-98 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// Standart type and macro definitions +//-------------------------------------------------------------------*--------* + +#ifndef __STDTP_H__ +#define __STDTP_H__ + +#if defined(_WIN32) +#include +#ifdef _MSC_VER +#pragma warning(disable : 4800 4355 4146 4251) +#pragma warning(disable : 4458 4456 4457 4459) // warning C4458 : declaration of + // 'name' hides class member +#endif +#else +#ifdef _AIX +#define INT8_IS_DEFINED +#endif +#ifndef NO_PTHREADS +#ifndef _REENTRANT +#define _REENTRANT +#endif +#endif +#endif + +#if defined(__VACPP_MULTI__) // IBM compiler produce a lot of stupid warnings +#pragma report(disable, "CPPC1608") +#pragma report(disable, "CPPC1281") +#endif /* __VACPP_MULTI__ */ + +#ifdef _WINCE +#include +#include +#include +#include +#include +#include +#include "wince.h" + +#else + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +#if !defined(_WIN32) +#define __cdecl +#endif + +#define DEBUG_NONE 0 +#define DEBUG_CHECK 1 +#define DEBUG_TRACE 2 + +#if GIGABASE_DEBUG == DEBUG_TRACE +#define TRACE_MSG(x) dbTrace x +#else +#define TRACE_MSG(x) +#endif + +extern void dbTrace(char *message, ...); + +// Align value 'x' to boundary 'b' which should be power of 2 +#define DOALIGN(x, b) (((x) + (b)-1) & ~((b)-1)) + +typedef signed char db_int1; +typedef unsigned char db_nat1; + +typedef signed short db_int2; +typedef unsigned short db_nat2; + +typedef signed int db_int4; +typedef unsigned int db_nat4; + +typedef float db_real4; +typedef double db_real8; + +typedef unsigned char byte; + +#if defined(_WIN32) && !defined(__MINGW32__) +typedef unsigned __int64 db_nat8; +typedef __int64 db_int8; +#if defined(__IBMCPP__) +#define INT8_FORMAT "%lld" +#define T_INT8_FORMAT _T("%lld") +#else +#define INT8_FORMAT "%I64d" +#define T_INT8_FORMAT _T("%I64d") +#endif +#define CONST64(c) c +#else +#if SIZEOF_LONG == 8 +typedef unsigned long db_nat8; +typedef signed long db_int8; +#define INT8_FORMAT "%ld" +#define T_INT8_FORMAT _T("%ld") +#define CONST64(c) c##L +#else +typedef unsigned long long db_nat8; +typedef signed long long db_int8; +#define INT8_FORMAT "%lld" +#define T_INT8_FORMAT _T("%lld") +#define CONST64(c) c##LL +#endif +#endif + +#if !defined(bool) && (defined(__SUNPRO_CC) || defined(__IBMCPP__)) +#define bool char +#define true(1) +#define false(0) +#endif + +#define nat8_low_part(x) ((db_nat4)(x)) +#define int8_low_part(x) ((db_int4)(x)) +#if defined(_MSC_VER) // bug in MVC 6.0 +#define nat8_high_part(x) (sizeof(x) < 8 ? 0 : ((db_nat4)((db_nat8)(x) >> 32))) +#define int8_high_part(x) (sizeof(x) < 8 ? 0 : ((db_int4)((db_int8)(x) >> 32))) +#else +#define nat8_high_part(x) ((db_nat4)((db_nat8)(x) >> 32)) +#define int8_high_part(x) ((db_int4)((db_int8)(x) >> 32)) +#endif + +#define cons_nat8(hi, lo) ((((db_nat8)(hi)) << 32) | (db_nat4)(lo)) +#define cons_int8(hi, lo) ((((db_int8)(hi)) << 32) | (db_nat4)(lo)) + +#define MAX_NAT8 db_nat8(-1) + +#define itemsof(array) (sizeof(array) / sizeof *(array)) + +#endif diff --git a/storage/dybase/src/sync.h b/storage/dybase/src/sync.h new file mode 100644 index 000000000..fafb265d3 --- /dev/null +++ b/storage/dybase/src/sync.h @@ -0,0 +1,68 @@ +//-< SYNC.H >--------------------------------------------------------*--------* +// GigaBASE Version 1.0 (c) 1999 GARRET * ? * +// (Post Relational Database Management System) * /\| * +// * / \ * +// Created: 20-Nov-98 K.A. Knizhnik * / [] \ * +// Last update: 8-Feb-99 K.A. Knizhnik * GARRET * +//-------------------------------------------------------------------*--------* +// Intertask synchonization primitives +//-------------------------------------------------------------------*--------* + +#ifndef __SYNC_H__ +#define __SYNC_H__ + +#if defined(_WIN32) +class dbMutex { + CRITICAL_SECTION cs; + +public: + dbMutex() { InitializeCriticalSection(&cs); } + ~dbMutex() { DeleteCriticalSection(&cs); } + void lock() { EnterCriticalSection(&cs); } + void unlock() { LeaveCriticalSection(&cs); } +}; + +#else // Unix + +#ifndef NO_PTHREADS + +#include +#include +#include + +class dbMutex { + friend class dbEvent; + friend class dbSemaphore; + pthread_mutex_t cs; + +public: + dbMutex() { pthread_mutex_init(&cs, NULL); } + ~dbMutex() { pthread_mutex_destroy(&cs); } + void lock() { pthread_mutex_lock(&cs); } + void unlock() { pthread_mutex_unlock(&cs); } +}; + +#else + +class dbMutex { +public: + void lock() {} + void unlock() {} +}; + +#endif + +#endif + +class dbCriticalSection { +private: + dbMutex &mutex; + dbCriticalSection(const dbCriticalSection &); + dbCriticalSection &operator=(const dbCriticalSection &); + +public: + dbCriticalSection(dbMutex &guard) : mutex(guard) { mutex.lock(); } + ~dbCriticalSection() { mutex.unlock(); } +}; + +#endif diff --git a/storage/quickjs-storage.c b/storage/quickjs-storage.c new file mode 100644 index 000000000..4d25b6fbb --- /dev/null +++ b/storage/quickjs-storage.c @@ -0,0 +1,1187 @@ + + +/* + * QuickJS C library + * + * Copyright (c) 2017-2020 Fabrice Bellard + * Copyright (c) 2017-2020 Charlie Gordon + * + * 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 "../cutils.h" +#include "dybase/include/dybase.h" +#include "quickjs-storage.h" + +enum { + __JS_ATOM_NULL = JS_ATOM_NULL, +#define DEF(name, str) JS_ATOM_ ## name, +#include "../quickjs-atom.h" +#undef DEF + JS_ATOM_END, +}; + +JSValue JS_GetObjectClassName(JSContext *ctx, JSValueConst obj); +JSValue JS_GetLocalValue(JSContext *ctx, JSAtom name); + +typedef struct JSStorage { + dybase_storage_t hs; + JSContext* ctx; + hashtable_t oid2obj; + JSValue classname2proto; + JSValue root; +} JSStorage; + +static JSClassID js_storage_class_id = 0; +static JSClassID js_index_class_id = 0; +static JSClassID js_index_iterator_class_id = 0; + +void errHandler(int error_code, char const *msg) { + fprintf(stderr, "Storage error: %d - '%s'\n", error_code, msg ); + //CsThrowKnownError(VM::get_current(), CsErrPersistError, msg); +} + + +#define JS_CLASS_OBJECT 1 +#define JS_CLASS_ARRAY 2 + +JS_BOOL js_is_persitable(JSValue val) { + JSClassID cid = JS_GetClassID(val, NULL); + return cid == JS_CLASS_OBJECT || cid == JS_CLASS_ARRAY || cid == js_index_class_id; +} + +JS_BOOL js_set_persistent_rt(JSRuntime* rt, JSValue val, struct JSStorage* pst, uint32_t oid, JS_PERSISTENT_STATUS status); +JS_BOOL js_set_persistent(JSContext* ctx, JSValue val, struct JSStorage* pst, uint32_t oid, JS_PERSISTENT_STATUS status); +void js_set_persistent_status(JSValue val, JS_PERSISTENT_STATUS status); +JS_PERSISTENT_STATUS js_is_persistent(JSValue val, JSStorage** pstor, uint32_t* poid); +uint32_t* js_get_persistent_oid_ref(JSValue val); + +static JSStorage* storage_of(JSValue obj) { return JS_GetOpaque(obj, js_storage_class_id); } + +static dybase_oid_t db_persist_entity(JSContext *ctx, JSStorage* pst, JSValue obj); + +JS_BOOL db_is_index(JSValue val); + +typedef unsigned char byte; + +typedef union db_data { + int32_t i; + double d; + byte * s; // string + int64_t i64; + dybase_oid_t oid; +} db_data; + +typedef struct db_triplet { + db_data data; + int32_t type; + int32_t len; +} db_triplet; + +static void *keyptr(db_triplet *tri) { + if (tri->type == dybase_chars_type || tri->type == dybase_bytes_type) + return (void *)tri->data.s; + return (void *)&tri->data; +} + +void db_transform(JSContext *ctx, JSStorage* pst, JSValueConst val, db_triplet *pt) { + + pt->len = 0; + pt->data.i64 = 0; + + size_t size; + double ms1970; + + switch (JS_VALUE_GET_NORM_TAG(val)) + { + case JS_TAG_INT: + pt->data.i = JS_VALUE_GET_INT(val); + pt->type = dybase_int_type; + break; + case JS_TAG_BIG_INT: + JS_ToBigInt64(ctx, &pt->data.i64, val); + pt->type = dybase_long_type; + break; + case JS_TAG_BOOL: + pt->data.i = val == JS_TRUE; + pt->type = dybase_bool_type; + break; + case JS_TAG_NULL: + case JS_TAG_UNDEFINED: + pt->type = dybase_chars_type; // null is null string + pt->len = 0; + pt->data.i64 = 0; + break; + case JS_TAG_FLOAT64: + JS_ToFloat64(ctx,&pt->data.d,val); + pt->type = dybase_real_type; + break; + case JS_TAG_STRING: + { + size_t len; + const char *str = JS_ToCStringLen(ctx, &len, val); + pt->len = len; + pt->data.s = (byte*)str; + pt->type = dybase_chars_type; + break; + } + case JS_TAG_OBJECT: + if (JS_IsArray(ctx, val)) { + pt->type = dybase_array_ref_type; + pt->data.oid = db_persist_entity(ctx, pst, val); + } + else if (db_is_index(val)) { + pt->type = dybase_index_ref_type; + JSStorage* ipst; + if (!js_is_persistent(val, &ipst, &pt->data.oid) || (ipst != pst)) + assert(0); + } + else if (JS_GetArrayBuffer(ctx, &size, val)) { + uint8_t * ptr = JS_GetArrayBuffer(ctx, &size, val); + pt->len = size; // length in bytes + 1 byte for the type + pt->data.s = ptr; + pt->type = dybase_bytes_type; + } + else if(JS_IsObjectPlain(ctx,val)) + { + pt->type = dybase_object_ref_type; + pt->data.oid = db_persist_entity(ctx, pst, val); + } + else if (JS_IsDate(ctx, val, &ms1970)) { + int64_t ft = (int64_t)(ms1970 * 10000) + 116444736000000LL /*SEC_TO_UNIX_EPOCH*/; + pt->type = dybase_date_type; + pt->data.i64 = ft; + } + break; + } + return; +} + +void db_free_transform(JSContext *ctx, db_triplet *pt) { + if(pt->type == dybase_chars_type) + JS_FreeCString(ctx, pt->data.s); + return; +} + +void db_store_field(JSContext *ctx, JSStorage* pst, dybase_handle_t h, JSValueConst val) +{ + db_triplet db_val; + db_transform(ctx, pst, val, &db_val); + dybase_store_array_element(h, + db_val.type, + keyptr(&db_val), + db_val.len); + db_free_transform(ctx, &db_val); +} + +void db_store_atom(JSContext *ctx, JSStorage* pst, dybase_handle_t h, JSAtom atom) +{ + db_triplet db_val; + + char buf[1024]; + const char *str = JS_AtomGetStr(ctx, &buf[1], 1024 - 2, atom); + db_val.len = strlen(str); // length in bytes + 1 byte for the type + db_val.data.s = (byte*)str; + db_val.type = dybase_chars_type; + + dybase_store_array_element(h, db_val.type, (void *)db_val.data.s, db_val.len); +} + +void db_store_object_data(JSContext *ctx, JSStorage* pst, dybase_oid_t oid, JSValue obj) { + + JSPropertyEnum* tab = NULL; + uint32_t len = 0; + + JSValue cname = JS_GetObjectClassName(ctx, obj); + + const char *class_name = ""; + + // trying to get name of custom class (if any) + + if (JS_IsString(cname)) + class_name = JS_ToCString(ctx, cname); + + dybase_handle_t h = dybase_begin_store_object(pst->hs, oid, class_name); + assert(h); + + if(class_name[0]) + JS_FreeCString(ctx, class_name); + + JS_FreeValue(ctx, cname); + + JS_GetOwnPropertyNames(ctx, &tab, &len, obj, JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY); + + dybase_store_object_field(h, ".", dybase_map_type, 0, len); + + for (uint32_t n = 0; n < len; ++n) { + db_store_atom(ctx, pst, h, tab[n].atom); + JSValue val = JS_GetProperty(ctx, obj, tab[n].atom); + db_store_field(ctx, pst, h, val); + JS_FreeValue(ctx, val); + JS_SetProperty(ctx, obj, tab[n].atom, JS_UNDEFINED); // to free sub-items to make obj dormant + } + + dybase_end_store_object(h); + + js_free_prop_enum(ctx, tab, len); + + js_set_persistent_status(obj, JS_PERSISTENT_DORMANT); +} + +void db_store_array_data(JSContext *ctx, JSStorage* pst, dybase_oid_t oid, JSValue obj) { + + uint32_t len = 0; + + dybase_handle_t h = dybase_begin_store_object(pst->hs, oid, ""); + assert(h); + + uint64_t length = 0; + + JS_GetPropertyLength(ctx, (int64_t*)&length, obj); + + if (length > UINT32_MAX) + length = UINT32_MAX; + + dybase_store_object_field(h, ".", dybase_array_type, 0, (int)length); + + for (uint32_t n = 0; n < length; ++n) { + JSValue val = JS_GetPropertyUint32(ctx,obj,n); + db_store_field(ctx, pst, h, val); + JS_FreeValue(ctx, val); + JS_SetPropertyUint32(ctx, obj, n, JS_UNDEFINED); // to free references + } + + dybase_end_store_object(h); + + js_set_persistent_status(obj, JS_PERSISTENT_DORMANT); +} + +void db_store_entity(JSContext *ctx, JSStorage* pst, dybase_oid_t oid, JSValue obj) { + + JS_PERSISTENT_STATUS status = js_is_persistent(obj, NULL, NULL); + if (status != JS_PERSISTENT_MODIFIED) + return; + if (JS_IsArray(ctx, obj)) + db_store_array_data(ctx, pst, oid, obj); + else if (JS_IsObjectPlain(ctx, obj)) // pure Object + db_store_object_data(ctx, pst, oid, obj); + else if (db_is_index(obj)) + ; + else + assert(0); +} + +JSValue db_fetch_value(JSContext *ctx, JSStorage* pst, dybase_handle_t h); +JSAtom db_fetch_atom(JSContext *ctx, JSStorage* pst, dybase_handle_t h); + + +int db_fetch_object_data(JSContext *ctx, JSValue obj, JSStorage* pst, dybase_oid_t oid) { + + int pf = js_is_persistent(obj, NULL, NULL); + + if (pf >= JS_PERSISTENT_LOADED) + return 0; // already loaded, nothing to do. + + dybase_handle_t h = dybase_begin_load_object(pst->hs, oid); + + char *class_name = dybase_get_class_name(h); + if (!class_name) { + assert(0); + return -1; + } + if (class_name[0]) { /* custom */ + JSValue proto = JS_UNDEFINED; + JSAtom cname = JS_NewAtom(ctx, class_name); + if (pst->classname2proto == JS_UNINITIALIZED) + pst->classname2proto = JS_NewObject(ctx); + else + proto = JS_GetProperty(ctx, pst->classname2proto, cname); + if (proto == JS_UNDEFINED) { + JSValue cls = JS_GetLocalValue(ctx, cname); + if (JS_IsConstructor(ctx,cls)) + proto = JS_GetProperty(ctx, cls, JS_ATOM_prototype); + JS_FreeValue(ctx, cls); + } + if (proto != JS_UNDEFINED) { + JS_SetPrototype(ctx, obj, proto); + JS_SetProperty(ctx, pst->classname2proto, cname,proto); + } + JS_FreeAtom(ctx, cname); + } + + char *field_name = dybase_next_field(h); + if (!field_name) { + assert(0); + return -1; + } + + int type; + void *value_ptr = NULL; + int value_length = 0; + dybase_get_value(h, &type, &value_ptr, &value_length); + + assert(type == dybase_map_type); + + for (int i = 0; i < value_length; i++) { + dybase_next_element(h); + JSAtom key_atom = db_fetch_atom(ctx,pst,h); + assert(key_atom != JS_ATOM_NULL); + dybase_next_element(h); + JSValue val = db_fetch_value(ctx, pst, h); + JS_SetProperty(ctx, obj, key_atom, val); + JS_FreeAtom(ctx, key_atom); + //??? JS_FreeValue(ctx, val); + } + + dybase_end_load_object(h); + + js_set_persistent_status(obj, JS_PERSISTENT_LOADED); // drop DORMANT flag + + return 1; + +} + +int db_fetch_array_data(JSContext *ctx, JSValue obj, JSStorage* pst, dybase_oid_t oid) { + + int pf = js_is_persistent(obj, NULL, NULL); + + if (pf >= JS_PERSISTENT_LOADED) + return 0; // already loaded, nothing to do. + + dybase_handle_t h = dybase_begin_load_object(pst->hs, oid); + assert(h); + + char *className = dybase_get_class_name(h); + if (!className) { + assert(0); + dybase_end_load_object(h); + return -1; + } + + char *fieldName = dybase_next_field(h); + if (!fieldName) { + assert(0); + dybase_end_load_object(h); + return -1; + } + + int type; + void *value_ptr = NULL; + int value_length = 0; + dybase_get_value(h, &type, &value_ptr, &value_length); + + assert(type == dybase_array_type); + + for (int i = 0; i < value_length; i++) { + dybase_next_element(h); + JSValue el = db_fetch_value(ctx,pst,h); + JS_SetPropertyInt64(ctx, obj, i, el); + } + + dybase_end_load_object(h); + + js_set_persistent_status(obj, JS_PERSISTENT_LOADED); // drop DORMANT flag + + return 1; +} + +JSValue db_fetch_object(JSContext *ctx, JSStorage* pst, dybase_oid_t oid) +{ + JSValue rv = JS_NewObject(ctx); + if(js_set_persistent(ctx, rv, pst, oid, JS_PERSISTENT_DORMANT)) + hashtable_put(pst->oid2obj, &oid, sizeof(oid), JS_VALUE_GET_PTR(rv)); + return rv; +} + +JSValue db_fetch_array(JSContext *ctx, JSStorage* pst, dybase_oid_t oid) +{ + JSValue rv = JS_NewArray(ctx); + if(js_set_persistent(ctx, rv, pst, oid, JS_PERSISTENT_DORMANT)) + hashtable_put(pst->oid2obj, &oid, sizeof(oid), JS_VALUE_GET_PTR(rv)); + return rv; +} + +JSAtom db_fetch_atom(JSContext *ctx, JSStorage* pst, dybase_handle_t h) { + int type; + void *value_ptr = NULL; + int value_length = 0; + dybase_get_value(h, &type, &value_ptr, &value_length); + if (type != dybase_chars_type) + return JS_ATOM_NULL; + if (!value_length) + return JS_ATOM_NULL; + return JS_NewAtomLen(ctx, (const char *)value_ptr, value_length); +} + +JS_BOOL db_check_cache(JSContext *ctx, JSStorage* pst, dybase_oid_t oid, JSValue* pval) +{ + struct JSObject* pobj = hashtable_get(pst->oid2obj, &oid, sizeof(oid)); + if (!pobj) + return 0; + *pval = JS_MKPTR(JS_TAG_OBJECT, pobj); + return 1; +} + +// loads object (plain JS object) from storage by its oid +JSValue db_load_object(JSContext *ctx, JSStorage* pst, dybase_oid_t oid) +{ + JSValue obj; + if (db_check_cache(ctx, pst, oid, &obj)) + return JS_DupValue(ctx,obj); + obj = db_fetch_object(ctx, pst, oid); + hashtable_put(pst->oid2obj, js_get_persistent_oid_ref(obj), sizeof(oid), JS_VALUE_GET_PTR(obj)); + return obj; +} + +static JSValue db_load_index(JSContext *ctx, JSStorage* pst, dybase_oid_t index_oid, int force_new); + +JSValue db_fetch_value(JSContext *ctx, JSStorage* pst, dybase_handle_t h) { + + int type; + void *value_ptr = NULL; + int value_length = 0; + dybase_get_value(h, &type, &value_ptr, &value_length); + + dybase_oid_t oid = 0; + JSValue obj = JS_UNDEFINED; + + switch (type) { + case dybase_object_ref_type: { + oid = *((dybase_oid_t *)value_ptr); + if (db_check_cache(ctx, pst, oid, &obj)) + return JS_DupValue(ctx,obj); + obj = db_fetch_object(ctx, pst, oid); + break; + } + case dybase_array_ref_type: { + oid = *((dybase_oid_t *)value_ptr); + if (db_check_cache(ctx, pst, oid, &obj)) + return JS_DupValue(ctx, obj); + obj = db_fetch_array(ctx, pst, oid); + break; + } + case dybase_index_ref_type: { + oid = *((dybase_oid_t *)value_ptr); + return db_load_index(ctx, pst, oid, FALSE); + } + case dybase_bool_type: + return JS_NewBool(ctx,*((char *)value_ptr)); + + case dybase_int_type: + return JS_NewInt32(ctx,*((int *)value_ptr)); + + case dybase_date_type: { + int64_t wtime = *((int64_t *)value_ptr); + double date_ms1970 = wtime / 10000.0 - 11644473600LL /*SEC_TO_UNIX_EPOCH*/; + return JS_NewDate(ctx, date_ms1970); + } + case dybase_long_type: + return JS_NewBigInt64(ctx,*((int64_t *)value_ptr)); + + case dybase_real_type: + return JS_NewFloat64(ctx, *(double *)value_ptr); + + case dybase_chars_type: + if (!value_length) + return JS_NULL; + else + return JS_NewStringLen(ctx, (const char *)value_ptr, value_length); + break; + + case dybase_bytes_type: + if (!value_length) + return JS_NULL; + else + return JS_NewArrayBufferCopy(ctx, (const byte *)value_ptr, value_length); + break; + + // + case dybase_map_type: + // element couldn't be a map + // map =(by default) to object + return JS_EXCEPTION; + + default: + return JS_EXCEPTION; + } + + hashtable_put(pst->oid2obj, js_get_persistent_oid_ref(obj), sizeof(oid), JS_VALUE_GET_PTR(obj)); + + return obj; +} + +int db_fetch_entity(JSContext *ctx, JSValue obj) +{ + dybase_oid_t oid; + JSStorage* pst; + + if (!js_is_persistent(obj, &pst, &oid)) + return -1; + + assert(js_is_persitable(obj)); + + int r = 0; + + if (JS_IsArray(ctx, obj)) + r = db_fetch_array_data(ctx, obj, pst, oid); + else if (db_is_index(obj)) + r = 1; + else if (JS_IsObjectPlain(ctx, obj)) // pure Object + r = db_fetch_object_data(ctx, obj, pst, oid); + else { + assert(0); + r = -1; + } + + return r; +} + +dybase_oid_t db_persist_entity(JSContext *ctx, JSStorage* pst, JSValue obj) { + + assert(js_is_persitable(obj)); + + dybase_oid_t oid; + JSStorage* vps; + + if (js_is_persistent(obj, &vps, &oid)) { + if (vps == pst) { // already here + //js_set_persistent_status(obj, status); + return oid; + } + // it is attached to another storage + if (vps) { + db_store_entity(ctx, vps, oid, obj); + hashtable_remove(vps->oid2obj, &oid, sizeof(oid)); + js_set_persistent(ctx, obj, NULL, 0, JS_NOT_PERSISTENT); + } + } + + oid = dybase_allocate_object(pst->hs); + if(!oid) + return 0; + + assert(oid); + + if (js_set_persistent(ctx, obj, pst, oid, JS_PERSISTENT_MODIFIED /*to force its saving*/)) + { + hashtable_put(pst->oid2obj, js_get_persistent_oid_ref(obj), sizeof(oid), JS_VALUE_GET_PTR(obj)); + return oid; + } else + return 0; +} + +static JSValue db_storage_open(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + const char *filename = NULL; + int mode; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + goto fail; + + mode = argv[1] == JS_UNDEFINED ? 1 : JS_ToBool(ctx, argv[1]); + if (!mode < 0) + goto fail; + + dybase_storage_t hs = dybase_open(filename, 4 * 1024 * 1024, errHandler, mode != 0); + + if(!hs) + goto fail; + + if (mode) dybase_gc(hs); + + JSStorage* pst = js_mallocz(ctx, sizeof(JSStorage)); + + pst->hs = hs; + pst->oid2obj = hashtable_create(); + pst->root = JS_NULL; + pst->classname2proto = JS_UNINITIALIZED; + pst->ctx = JS_DupContext(ctx); + + JSValue obj = JS_NewObjectClass(ctx, js_storage_class_id); + + JS_SetOpaque(obj, pst); + + JS_FreeCString(ctx, filename); + + dybase_oid_t root_oid = dybase_get_root_object(hs); + if (root_oid) { + JSValue root = JS_NewObject(ctx); + if (js_set_persistent(ctx, root, pst, root_oid, JS_PERSISTENT_DORMANT)) + { + hashtable_put(pst->oid2obj, js_get_persistent_oid_ref(root), sizeof(dybase_oid_t), JS_VALUE_GET_PTR(root)); + pst->root = root; + } else + JS_FreeValue(ctx, root); + } + return obj; + +fail: + JS_FreeCString(ctx, filename); + return JS_EXCEPTION; +} + + +JSStorage* get_storage(JSValueConst obj) { + return (JSStorage*) JS_GetOpaque(obj, js_storage_class_id); +} + +typedef struct commit_ctx { + JSContext *ctx; + JSStorage *pst; + int forget; + int count; +} commit_ctx; + +static int commit_value(void* key, unsigned int key_length, void* data, void* opaque) { + JSValue obj = JS_MKPTR(JS_TAG_OBJECT, data); + commit_ctx *cc = (commit_ctx *)opaque; + dybase_oid_t *poid = (dybase_oid_t *)key; + db_store_entity(cc->ctx, cc->pst, *poid, obj); + return 0; +} + +static int final_commit_value(void* key, unsigned int key_length, void* data, void* opaque) { + JSValue obj = JS_MKPTR(JS_TAG_OBJECT, data); + commit_ctx *cc = (commit_ctx *)opaque; + dybase_oid_t *poid = (dybase_oid_t *)key; + db_store_entity(cc->ctx, cc->pst, *poid, obj); + js_set_persistent(cc->ctx, obj, NULL, 0, JS_NOT_PERSISTENT); + ++cc->count; + return 0; +} + +static void commit_storage(JSContext *ctx, JSStorage* pst) { + commit_ctx cc = { ctx,pst,1}; + hashtable_each(pst->oid2obj, &commit_value, &cc); +} + +static void final_commit_storage(JSContext *ctx, JSStorage* pst) { + commit_ctx cc = { ctx,pst,1, 0 }; + do { + cc.count = 0; + hashtable_t ht = pst->oid2obj; + pst->oid2obj = hashtable_create(); + hashtable_each(ht, &final_commit_value, &cc); + hashtable_free(ht); + } while (cc.count); +} + +void free_storage(JSValue st) +{ + JSStorage* ps = storage_of(st); + if (!ps) return; + JSContext *ctx = ps->ctx; + js_set_persistent(ctx, ps->root, NULL, 0, JS_NOT_PERSISTENT); + JS_FreeValue(ctx, ps->root); + JS_FreeValue(ctx, ps->classname2proto); + final_commit_storage(ctx, ps); + dybase_commit(ps->hs); + dybase_close(ps->hs); + ps->hs = 0; + hashtable_free(ps->oid2obj); + JS_FreeContext(ctx); + js_free(ctx, ps); + JS_SetOpaque(st, NULL); +} + +static JSValue db_storage_commit(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + JSStorage* ps = storage_of(this_val); + if (!ps) return JS_EXCEPTION; + commit_storage(ctx, ps); + dybase_commit(ps->hs); + return JS_UNDEFINED; +} + +static JSValue db_storage_create_index(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + +static JSValue db_storage_close(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + JSStorage* ps = get_storage(this_val); + if (!ps) return JS_UNDEFINED; + free_storage(this_val); + return JS_TRUE; +} + +static JSValue db_storage_get_root(JSContext *ctx, JSValueConst this_val) +{ + JSStorage* ps = get_storage(this_val); + if (!ps) + return JS_NULL; + return JS_DupValue(ctx, ps->root); +} + +static JSValue db_storage_set_root(JSContext *ctx, JSValueConst this_val, JSValueConst val) +{ + JSStorage* pst = get_storage(this_val); + if (!pst) + return JS_EXCEPTION; + JS_FreeValue(ctx, pst->root); + pst->root = JS_DupValue(ctx, val); + dybase_oid_t oid = db_persist_entity(ctx, pst, val); + dybase_set_root_object(pst->hs, oid); + db_store_entity(ctx, pst, oid, val); // need this immediately ? + return JS_UNDEFINED; +} + +int js_load_persistent_object(JSContext *ctx, JSValueConst obj) { + return db_fetch_entity(ctx, obj); +} + +int js_free_persistent_object(JSRuntime *rt, JSValueConst obj) { + JSStorage* pst; + dybase_oid_t oid; + JS_PERSISTENT_STATUS status = js_is_persistent(obj, &pst, &oid); + if (pst) { + if(status == JS_PERSISTENT_MODIFIED) + db_store_entity(pst->ctx, pst, oid, obj); + hashtable_remove(pst->oid2obj, &oid, sizeof(oid)); + js_set_persistent_rt(rt, obj, pst, 0, JS_NOT_PERSISTENT); + } + return 0; +} + +static void js_storage_finalizer(JSRuntime *rt, JSValue val) +{ + free_storage(val); +} + +static void js_storage_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) +{ + JSStorage *pst = get_storage(val); + if (pst) { + JS_MarkValue(rt, pst->root, mark_func); + //JS_MarkValue(rt, pst->oid2obj, mark_func); + JS_MarkValue(rt, pst->classname2proto, mark_func); + } +} + + +static const JSCFunctionListEntry js_storage_funcs[] = { + JS_CFUNC_DEF("open", 2, db_storage_open), + //JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE), + //JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE), + //JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE), + //JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE), +}; + +static const JSCFunctionListEntry js_storage_proto_funcs[] = { + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Storage", JS_PROP_CONFIGURABLE), + JS_CFUNC_DEF("close", 0, db_storage_close), + JS_CFUNC_DEF("commit", 0, db_storage_commit), + JS_CFUNC_DEF("createIndex", 0, db_storage_create_index), + JS_CGETSET_DEF("root", db_storage_get_root, db_storage_set_root), +}; + +static JSClassDef js_storage_class = { + "Storage", + .finalizer = js_storage_finalizer, + .gc_mark = js_storage_mark +}; + +//| +//| class Storage.Index +//| + +JS_BOOL db_is_index(JSValue val) { + return JS_GetClassID(val,NULL) == js_index_class_id; +} + +static JSValue db_load_index(JSContext *ctx, JSStorage* pst, dybase_oid_t index_oid, int force_new) +{ + JSValue obj; + if (!force_new) { + if (db_check_cache(ctx, pst, index_oid, &obj)) + return JS_DupValue(ctx, obj); + } + + obj = JS_NewObjectClass(ctx, js_index_class_id); + + js_set_persistent(ctx, obj, pst, index_oid, JS_PERSISTENT_LOADED); + + hashtable_put(pst->oid2obj, js_get_persistent_oid_ref(obj), sizeof(index_oid), JS_VALUE_GET_PTR(obj)); + + return obj; +} + +static JSValue db_storage_create_index(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + JSStorage* pst = get_storage(this_val); + if (!pst) + return JS_EXCEPTION; + + dybase_oid_t oid_idx = 0; + + const char* type = JS_ToCString(ctx, argv[0]); + + int key_type = 0; + + if (strcmp(type, "string") == 0) key_type = dybase_chars_type; + else if (strcmp(type, "integer") == 0) key_type = dybase_int_type; + else if (strcmp(type, "long") == 0) key_type = dybase_long_type; + else if (strcmp(type, "float") == 0) key_type = dybase_real_type; + else if (strcmp(type, "date") == 0) key_type = dybase_date_type; + else { + JS_FreeCString(ctx, type); + return JS_ThrowTypeError(ctx, "invalid Index type"); + } + JS_FreeCString(ctx, type); + + int unique = 1; + + if (argc > 1) + unique = JS_ToBool(ctx, argv[1]); + + dybase_oid_t oid = dybase_create_index(pst->hs, key_type, unique); + + return db_load_index(ctx, pst, oid, TRUE); +} + +// for unique indexes: either object or undefined +// for non-unique indexes: [object1,... objectN] or [] + +static JSValue db_index_get(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + + JSStorage* pst; + dybase_oid_t index_oid; + + if (!js_is_persistent(this_val, &pst, &index_oid)) + return JS_EXCEPTION; + + db_triplet db_key; + db_transform(ctx,pst,argv[0],&db_key); + + dybase_oid_t *selected_objects = NULL; + + int num_selected = dybase_index_search( pst->hs, index_oid, db_key.type, + keyptr(&db_key), + db_key.len, 1 /*min_key_inclusive*/, + keyptr(&db_key), + db_key.len, 1 /*min_key_inclusive*/, &selected_objects); + + JSValue val; + if (dybase_is_index_unique(pst->hs, index_oid)) + // return the 1st element + val = num_selected ? db_load_object(ctx, pst, selected_objects[0]) : JS_UNDEFINED; + else { + val = JS_NewArray(ctx); + for (int n = 0; n < num_selected; ++n) { + JSValue el = db_load_object(ctx, pst, selected_objects[n]); + JS_SetPropertyInt64(ctx, val, n, el); + } + } + // free selected array + dybase_free_selection(pst->hs, selected_objects, num_selected); + return val; +} + +static JSValue db_index_set(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + JSStorage* pst; + dybase_oid_t index_oid; + + if (!js_is_persistent(this_val, &pst, &index_oid)) + return JS_EXCEPTION; + + if (!JS_IsObjectPlain(ctx,argv[1])) + return JS_ThrowTypeError(ctx,"index can contain only plain objects"); + + dybase_oid_t oid = db_persist_entity(ctx, pst, argv[1]); + db_store_entity(ctx, pst, oid, argv[1]); + + int replace = JS_ToBool(ctx, argv[2]) > 0; + + // transform 'key' into triplet + db_triplet db_key; + db_transform(ctx,pst, argv[0], &db_key); + + int ret = dybase_insert_in_index(pst->hs, index_oid, keyptr(&db_key), db_key.type, db_key.len, oid, replace); + + db_free_transform(ctx, &db_key); + + return JS_NewBool(ctx, ret); +} + +static JSValue db_index_delete(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + return JS_UNDEFINED; +} + +static JSValue db_create_index_iterator(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); +static JSValue db_index_select(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); + +static JSValue db_index_clear(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { + JSStorage* pst; + dybase_oid_t index_oid; + + if (!js_is_persistent(this_val, &pst, &index_oid)) + return JS_EXCEPTION; + + dybase_clear_index(pst->hs, index_oid); + + return JS_UNDEFINED; +} + +static JSValue db_index_get_length(JSContext *ctx, JSValueConst this_val) { + JSStorage* pst; + dybase_oid_t index_oid; + + if (!js_is_persistent(this_val, &pst, &index_oid)) + return JS_EXCEPTION; + + dybase_oid_t *selected_objects = NULL; + + int key_type = dybase_get_index_type(pst->hs, index_oid); + + int num_selected = dybase_index_search(pst->hs, index_oid, key_type, + NULL, 0, 1, + NULL, 0, 1, &selected_objects); + + dybase_free_selection(pst->hs, selected_objects, num_selected); + + return JS_NewInt32(ctx, num_selected); +} + +static JSValue db_index_get_type(JSContext *ctx, JSValueConst this_val) { + JSStorage* pst; + dybase_oid_t index_oid; + + if (!js_is_persistent(this_val, &pst, &index_oid)) + return JS_EXCEPTION; + + int key_type = dybase_get_index_type(pst->hs, index_oid); + switch (key_type) { + case dybase_chars_type: return JS_NewString(ctx, "string"); + case dybase_int_type: return JS_NewString(ctx, "integer"); + case dybase_long_type: return JS_NewString(ctx, "long"); + case dybase_real_type: return JS_NewString(ctx, "float"); + case dybase_date_type: return JS_NewString(ctx, "date"); + default: break; + } + return JS_NULL; +} + +static JSValue db_index_get_unique(JSContext *ctx, JSValueConst this_val) { + JSStorage* pst; + dybase_oid_t index_oid; + + if (!js_is_persistent(this_val, &pst, &index_oid)) + return JS_EXCEPTION; + + int u = dybase_is_index_unique(pst->hs, index_oid); + + return JS_NewBool(ctx,u); +} + + +static void js_index_finalizer(JSRuntime *rt, JSValue val) +{ + // we are not allocating anything for the index +} + +static const JSCFunctionListEntry js_index_proto_funcs[] = { + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Storage.Index", JS_PROP_CONFIGURABLE), + JS_CFUNC_DEF("delete", 1, db_index_delete), + JS_CFUNC_DEF("clear", 0, db_index_clear), + JS_CFUNC_DEF("get", 1, db_index_get), + JS_CFUNC_DEF("set", 2, db_index_set), + JS_CFUNC_DEF("select", 5, db_index_select), + JS_CGETSET_DEF("length", db_index_get_length, NULL), + JS_CGETSET_DEF("unique", db_index_get_unique, NULL), + JS_CGETSET_DEF("type", db_index_get_type, NULL), + JS_CFUNC_DEF("[Symbol.iterator]", 0, db_create_index_iterator), +}; + +static JSClassDef js_index_class = { + "Index", + //.finalizer = js_index_finalizer +}; + +typedef struct IndexIterator { + JSStorage* pst; + dybase_iterator_t iterator; +} IndexIterator; + +static JSValue js_index_iterator_next(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, + BOOL *pdone, int magic) +{ + IndexIterator *it = JS_GetOpaque2(ctx, this_val, js_index_iterator_class_id); + if (!it) + return JS_EXCEPTION; + + dybase_oid_t oid = dybase_index_iterator_next( it->iterator ); + + if (!oid) { + *pdone = TRUE; + return JS_UNDEFINED; + } + + *pdone = FALSE; + JSValue item = db_load_object(ctx, it->pst, oid); + return item; +} + +static JSValue db_index_select(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + JSValue enum_obj; + IndexIterator *it; + + JSStorage *pst; + dybase_oid_t index_oid; + + if (!js_is_persistent(this_val, &pst, &index_oid)) + return JS_EXCEPTION; + + enum_obj = JS_NewObjectClass(ctx, js_index_iterator_class_id); + if (JS_IsException(enum_obj)) + goto fail; + it = js_malloc(ctx, sizeof(*it)); + if (!it) + goto fail1; + JS_SetOpaque(enum_obj, it); + + it->pst = pst; + + db_triplet start; + db_triplet end; + + db_transform(ctx, pst, argv[0], &start); + db_transform(ctx, pst, argv[1], &end); + + int ascending = 1; if (argc >= 3) ascending = JS_ToBool(ctx, argv[2]) > 0; + int start_inclusive = 1; if (argc >= 4) start_inclusive = JS_ToBool(ctx, argv[3]) > 0; + int end_inclusive = 1; if (argc >= 5) end_inclusive = JS_ToBool(ctx, argv[4]) > 0; + + it->iterator = dybase_create_index_iterator( + pst->hs, index_oid, start.type, + keyptr(&start), start.len, start_inclusive, + keyptr(&end), end.len, end_inclusive, + ascending); + + db_free_transform(ctx, &start); + db_free_transform(ctx, &end); + + if(it->iterator) + return enum_obj; +fail1: + JS_FreeValue(ctx, enum_obj); +fail: + return JS_EXCEPTION; +} + +static JSValue db_create_index_iterator(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + JSValue enum_obj; + IndexIterator *it; + + JSStorage *pst; + dybase_oid_t index_oid; + + if (!js_is_persistent(this_val, &pst, &index_oid)) + return JS_EXCEPTION; + + enum_obj = JS_NewObjectClass(ctx, js_index_iterator_class_id); + if (JS_IsException(enum_obj)) + goto fail; + it = js_malloc(ctx, sizeof(*it)); + if (!it) + goto fail1; + JS_SetOpaque(enum_obj, it); + + it->pst = pst; + + int index_type = dybase_get_index_type(pst->hs, index_oid); + + it->iterator = dybase_create_index_iterator( + pst->hs, index_oid, index_type, + NULL, 0, 0, + NULL, 0, 0, + 1); + + if (it->iterator) + return enum_obj; +fail1: + JS_FreeValue(ctx, enum_obj); +fail: + return JS_EXCEPTION; +} + +static JSValue js_index_iterator(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) +{ + return JS_DupValue(ctx,this_val); +} + +static const JSCFunctionListEntry js_index_iterator_proto_funcs[] = { + JS_ITERATOR_NEXT_DEF("next", 0, js_index_iterator_next, 0), + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Storage.IndexIterator", JS_PROP_CONFIGURABLE), + JS_CFUNC_DEF("[Symbol.iterator]", 0, js_index_iterator), +}; + +static void js_index_iterator_finalizer(JSRuntime *rt, JSValue val) { + IndexIterator *it = JS_GetOpaque(val, js_index_iterator_class_id); + if (it) { + dybase_free_index_iterator(it->iterator); + js_free_rt(rt, it); + } +} + +static JSClassDef js_index_iterator_class = { + "Storage.IndexIterator", + .finalizer = js_index_iterator_finalizer +}; + +static int js_storage_init(JSContext *ctx, JSModuleDef *m) +{ + JSValue proto; + + /* Storage class */ + /* the class ID is created once */ + JS_NewClassID(&js_storage_class_id); + /* the class is created once per runtime */ + JS_NewClass(JS_GetRuntime(ctx), js_storage_class_id, &js_storage_class); + proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, proto, js_storage_proto_funcs, countof(js_storage_proto_funcs)); + JS_SetClassProto(ctx, js_storage_class_id, proto); + JS_SetModuleExportList(ctx, m, js_storage_funcs, countof(js_storage_funcs)); + + JS_NewClassID(&js_index_class_id); + JS_NewClass(JS_GetRuntime(ctx), js_index_class_id, &js_index_class); + JSValue index_proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, index_proto, js_index_proto_funcs, countof(js_index_proto_funcs)); + JS_SetClassProto(ctx, js_index_class_id, index_proto); + + JS_NewClassID(&js_index_iterator_class_id); + JS_NewClass(JS_GetRuntime(ctx), js_index_iterator_class_id, &js_index_iterator_class); + JSValue index_iterator_proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, index_iterator_proto, js_index_iterator_proto_funcs, countof(js_index_iterator_proto_funcs)); + JS_SetClassProto(ctx, js_index_iterator_class_id, index_iterator_proto); + + return 0; +} + +JSModuleDef *js_init_module_storage(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_storage_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_storage_funcs, countof(js_storage_funcs)); + return m; +} diff --git a/storage/quickjs-storage.h b/storage/quickjs-storage.h new file mode 100644 index 000000000..0c343fab0 --- /dev/null +++ b/storage/quickjs-storage.h @@ -0,0 +1,40 @@ +/* + * QuickJS C library + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QUICKJS_STORAGE_H +#define QUICKJS_STORAGE_H + +#include "../quickjs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +JSModuleDef *js_init_module_storage(JSContext *ctx, const char *module_name); + + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + +#endif /* QUICKJS_LIBC_H */ diff --git a/test262.conf b/test262.conf index e1eeb0386..6fbb5793a 100644 --- a/test262.conf +++ b/test262.conf @@ -49,6 +49,9 @@ testdir=test262/test # skipped features are tagged as such to avoid warnings AggregateError +align-detached-buffer-semantics-with-web-reality +arbitrary-module-namespace-names=skip +Array.prototype.at=skip Array.prototype.flat Array.prototype.flatMap Array.prototype.flatten @@ -82,7 +85,6 @@ DataView.prototype.getInt8 DataView.prototype.getUint16 DataView.prototype.getUint32 DataView.prototype.setUint8 -default-arg default-parameters destructuring-assignment destructuring-binding @@ -90,6 +92,7 @@ dynamic-import export-star-as-namespace-from-module FinalizationGroup=skip FinalizationRegistry=skip +FinalizationRegistry.prototype.cleanupSome=skip Float32Array Float64Array for-in-order @@ -99,10 +102,12 @@ globalThis hashbang host-gc-required=skip import.meta +Int16Array Int32Array Int8Array IsHTMLDDA json-superset +legacy-regexp=skip let logical-assignment-operators Map @@ -114,6 +119,7 @@ Object.fromEntries Object.is optional-catch-binding optional-chaining +Promise Promise.allSettled Promise.any Promise.prototype.finally @@ -135,6 +141,7 @@ string-trimming String.fromCodePoint String.prototype.endsWith String.prototype.includes +String.prototype.at=skip String.prototype.matchAll String.prototype.replaceAll String.prototype.trimEnd @@ -159,14 +166,19 @@ tail-call-optimization=skip template top-level-await=skip TypedArray +TypedArray.prototype.at=skip u180e Uint16Array +Uint32Array Uint8Array Uint8ClampedArray WeakMap WeakRef=skip WeakSet well-formed-json-stringify +__getter__ +__proto__ +__setter__ [exclude] # list excluded tests and directories here @@ -183,8 +195,5 @@ test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js #test262/test/built-ins/RegExp/CharacterClassEscapes/ #test262/test/built-ins/RegExp/property-escapes/ -# invalid tests -test262/test/language/module-code/verify-dfs.js - [tests] # list test files or use config.testdir diff --git a/test262_errors.txt b/test262_errors.txt index d00d4f19b..b7f6aef38 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -1,30 +1,35 @@ test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: Test262Error: Expected a ReferenceError but got a ReferenceError test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError -test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents. -test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: strict mode: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents. test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name -test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/expressions/async-arrow-function/eval-var-scope-syntax-err.js:49: TypeError: $DONE() not called -test262/test/language/expressions/async-function/named-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called -test262/test/language/expressions/async-function/nameless-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called -test262/test/language/expressions/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/expressions/async-generator/named-eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/expressions/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name -test262/test/language/expressions/class/elements/grammar-private-field-optional-chaining.js:26: strict mode: SyntaxError: expecting field name +test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: Test262Error: (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: strict mode: Test262Error: (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: Test262Error: (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: strict mode: Test262Error: (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: strict mode: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: strict mode: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: strict mode: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: strict mode: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: strict mode: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: strict mode: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.) +test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.) test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called -test262/test/language/expressions/function/eval-var-scope-syntax-err.js:48: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/expressions/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/expressions/object/method-definition/async-gen-meth-eval-var-scope-syntax-err.js:32: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/expressions/object/method-definition/async-meth-eval-var-scope-syntax-err.js:36: TypeError: $DONE() not called -test262/test/language/expressions/object/method-definition/gen-meth-eval-var-scope-syntax-err.js:54: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/expressions/object/method-definition/meth-eval-var-scope-syntax-err.js:50: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined -test262/test/language/statements/async-function/eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called -test262/test/language/statements/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name -test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: strict mode: SyntaxError: expecting field name -test262/test/language/statements/function/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all -test262/test/language/statements/generators/eval-var-scope-syntax-err.js:49: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all +test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: unexpected error type: Test262: This statement should not be evaluated. +test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: strict mode: unexpected error type: Test262: This statement should not be evaluated. diff --git a/tests/JSX/test-jsx.js b/tests/JSX/test-jsx.js new file mode 100644 index 000000000..957b2f1ae --- /dev/null +++ b/tests/JSX/test-jsx.js @@ -0,0 +1,63 @@ + + +// "driver" of JSX expressions +JSX = function(tag,atts,kids) { + return [tag,atts,kids]; // just produce "vnode" tuple +} + +function isObject(object) { + return object != null && typeof object === 'object'; +} + +function deepEqual(object1, object2) { + const keys1 = Object.keys(object1); + const keys2 = Object.keys(object2); + + if (keys1.length !== keys2.length) { + return false; + } + + for (const key of keys1) { + const val1 = object1[key]; + const val2 = object2[key]; + const areObjects = isObject(val1) && isObject(val2); + if ( + areObjects && !deepEqual(val1, val2) || + !areObjects && val1 !== val2 + ) { + return false; + } + } + + return true; +} + +function assert(v1,v2) { + if(!deepEqual(v1,v2)) { + //console.log(JSON.stringify(v1,v2)); + throw "problem in JSX construct" + } +} + + +var t1 =
test
; +var t1a = ["div",{},["test"]]; +assert(t1,t1a); + +var t2 =

test

; +var t2a = ["h1",{id:"foo"},["test"]]; + +assert(t2,t2a); + +var t3 =

; +var t3a = ["div",{},[["h1",{},[]]]]; + +assert(t3,t3a); + + +var t4 =

header

; +var t4a = ["div",{id:"foo",class:"bar"},[["h1",{},["header"]],["button",{},["clicks"]]]]; + +assert(t4,t4a); + +console.log("JSX test passed!"); diff --git a/tests/storage/test-all.js b/tests/storage/test-all.js new file mode 100644 index 000000000..59ffe14dd --- /dev/null +++ b/tests/storage/test-all.js @@ -0,0 +1,147 @@ + + +import * as Storage from "storage"; +import * as std from "std"; +import * as os from "os"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +function isObject(object) { + return object != null && typeof object === 'object'; +} + +function deepEqual(object1, object2) { + const keys1 = Object.keys(object1); + const keys2 = Object.keys(object2); + + if (keys1.length !== keys2.length) + return false; + + for (const key of keys1) { + const val1 = object1[key]; + const val2 = object2[key]; + const areObjects = isObject(val1) && isObject(val2); + if (areObjects && !deepEqual(val1, val2) + || !areObjects && val1 !== val2) + return false; + } + + return true; +} + +const path = __DIR__ + "test.db"; +os.remove(path); + +function init() +{ + let storage = Storage.open(path); + + assert(storage.root, null, "fresh storage has null root"); + + let index_int = storage.createIndex("integer"); index_int.set(1,{a:1}); index_int.set(2,{b:2}); index_int.set(3,{c:3}); + let index_date = storage.createIndex("date"); + let index_long = storage.createIndex("long"); + let index_float = storage.createIndex("float"); + let index_string = storage.createIndex("string"); index_string.set("a",{a:1}); index_string.set("b",{b:2}); index_string.set("c",{c:3}); + + storage.root = { + //basic types + types: + { + tbool: true, + tinteger: 42, + tlong: 420n, + tfloat: 3.1415926, + tstring: "forty two", + tarray: [1,2,3], + tobject: { a:1, b:2, c:3}, + tdate: new Date(2021, 2, 28) + }, + //indexes + indexes: { + iint: index_int, + idate: index_date, + ilong : index_long, + ifloat: index_float, + istring : index_string + } + }; + storage.close(); +} + +function test() +{ + let storage = Storage.open(path); + + assert(!!storage); + + let dbTypes = storage.root.types; + + const types = { + tbool: true, + tinteger: 42, + tlong: 420n, + tfloat: 3.1415926, + tstring: "forty two", + tarray: [1,2,3], + tobject: { a:1, b:2, c:3}, + tdate: new Date(2021, 2, 28) + }; + + assert(deepEqual(dbTypes,types)); + + let indexes = storage.root.indexes; + + assert(indexes.iint.length,3); + + assert(deepEqual(indexes.iint.get(1),{a:1})); + assert(deepEqual(indexes.iint.get(2),{b:2})); + assert(deepEqual(indexes.iint.get(3),{c:3})); + + assert(indexes.istring.length,3); + + assert(deepEqual(indexes.istring.get("a"),{a:1})); + assert(deepEqual(indexes.istring.get("b"),{b:2})); + assert(deepEqual(indexes.istring.get("c"),{c:3})); + + var r = []; + for(let obj of indexes.istring) + r.push(obj); + + assert(deepEqual(r,[{a:1},{b:2},{c:3}])); + + r = []; + for(let obj of indexes.istring.select("b","c")) // range inclusive + r.push(obj); + assert(deepEqual(r,[{b:2},{c:3}])); + + r = []; + for(let obj of indexes.istring.select("b",null)) // range, open end + r.push(obj); + assert(deepEqual(r,[{b:2},{c:3}])); + + r = []; + for(let obj of indexes.istring.select(null,"b")) // range, open start + r.push(obj); + assert(deepEqual(r,[{a:1},{b:2}])); + + storage.close(); + + print("PASSED"); +} + +init(); +test(); \ No newline at end of file diff --git a/tests/storage/test-basic.js b/tests/storage/test-basic.js new file mode 100644 index 000000000..577aac789 --- /dev/null +++ b/tests/storage/test-basic.js @@ -0,0 +1,45 @@ +import * as storage from "storage"; +import * as std from "std"; +import * as os from "os"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +const path = __DIR__ + "test.db"; +os.remove(path); + +function init() { + let db = storage.open(path); + db.root = { foo:"foofoo", bar:42, arr: [1,2,3] }; + db.close(); +} + +function test() { + let db = storage.open(path); + let r = db.root; + let arr = db.root.arr; + print(JSON.stringify(r)); + print(JSON.stringify(arr)); + assert(r.foo, "foofoo"); + db.close(); +} + +init(); +test(); + + + diff --git a/tests/storage/test-classes.js b/tests/storage/test-classes.js new file mode 100644 index 000000000..1bf8d45ea --- /dev/null +++ b/tests/storage/test-classes.js @@ -0,0 +1,61 @@ +import * as storage from "storage"; +import * as std from "std"; +import * as os from "os"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +export class Account +{ + constructor() { + this.balance = 0n; + this.name = "Foo"; + } + show() { + print("account:", this.name); + print("balance:", this.balance); + } +} + +const path = __DIR__ + "test.db"; +os.remove(path); + +function init() { + + var inst = new Account(); + inst.show(); + + let db = storage.open(path); + db.root = { + inst: inst + }; + db.close(); +} + +function test() { + let db = storage.open(path); + let r = db.root; + r.inst.show(); + db.close(); + print("PASSED"); +} + +init(); +test(); + + + diff --git a/tests/storage/test-index.js b/tests/storage/test-index.js new file mode 100644 index 000000000..5477a05a6 --- /dev/null +++ b/tests/storage/test-index.js @@ -0,0 +1,58 @@ +import * as storage from "storage"; +import * as std from "std"; +import * as os from "os"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +const path = __DIR__ + "test.db"; +os.remove(path); + +function init() { + let db = storage.open(path); + + let index = db.createIndex("string"); + db.root = { + index: index + }; + index.set("a", { key: "a" }); + index.set("b", { key: "b" }); + index.set("c", { key: "c" }); + + assert(index.length, 3); + db.close(); +} + +function test() { + let db = storage.open(path); + + let index = db.root.index; + assert(index.length, 3); + for( let item of index ) + print(JSON.stringify(item)); + print("---- select() ----"); + for( let item of index.select("b","c") ) + print(JSON.stringify(item)); + + db.close(); +} + +init(); +test(); + + + diff --git a/tests/test-obj-call.js b/tests/test-obj-call.js new file mode 100644 index 000000000..439fb8ee4 --- /dev/null +++ b/tests/test-obj-call.js @@ -0,0 +1,5 @@ +function foo(obj) { + console.log(obj); +} + +foo {bar:"bar"}; diff --git a/tests/test_builtin.js b/tests/test_builtin.js index 5650c528a..8134fe1e7 100644 --- a/tests/test_builtin.js +++ b/tests/test_builtin.js @@ -17,6 +17,22 @@ function assert(actual, expected, message) { (message ? " (" + message + ")" : "")); } +function assert_throws(expected_error, func) +{ + var err = false; + try { + func(); + } catch(e) { + err = true; + if (!(e instanceof expected_error)) { + throw Error("unexpected exception type"); + } + } + if (!err) { + throw Error("expected exception"); + } +} + // load more elaborate version of assert if available try { __loadScript("test_assert.js"); } catch(e) {} @@ -48,6 +64,13 @@ function test_function() r = my_func.apply(null, [1, 2]); assert(r, 3, "apply"); + r = (function () { return 1; }).apply(null, undefined); + assert(r, 1); + + assert_throws(TypeError, (function() { + Reflect.apply((function () { return 1; }), null, undefined); + })); + r = new Function("a", "b", "return a + b;"); assert(r(2,3), 5, "function"); @@ -376,7 +399,7 @@ function test_eval() function test_typed_array() { - var buffer, a, i; + var buffer, a, i, str; a = new Uint8Array(4); assert(a.length, 4); @@ -416,7 +439,12 @@ function test_typed_array() a = new Uint8Array(buffer); - assert(a.toString(), "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255"); + str = a.toString(); + /* test little and big endian cases */ + if (str !== "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255" && + str !== "0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255") { + assert(false); + } assert(a.buffer, buffer); diff --git a/tests/test_language.js b/tests/test_language.js index 6b0846789..8d13deb94 100644 --- a/tests/test_language.js +++ b/tests/test_language.js @@ -15,6 +15,22 @@ function assert(actual, expected, message) { (message ? " (" + message + ")" : "")); } +function assert_throws(expected_error, func) +{ + var err = false; + try { + func(); + } catch(e) { + err = true; + if (!(e instanceof expected_error)) { + throw Error("unexpected exception type"); + } + } + if (!err) { + throw Error("expected exception"); + } +} + // load more elaborate version of assert if available try { __loadScript("test_assert.js"); } catch(e) {} @@ -233,8 +249,13 @@ function test_delete() function test_prototype() { - function f() { } + var f = function f() { }; assert(f.prototype.constructor, f, "prototype"); + + var g = function g() { }; + /* QuickJS bug */ + Object.defineProperty(g, "prototype", { writable: false }); + assert(g.prototype.constructor, g, "prototype"); } function test_arguments() @@ -376,6 +397,135 @@ function test_spread() assert(Object.getOwnPropertyNames(x).toString(), "0,length"); } +function test_function_length() +{ + assert( ((a, b = 1, c) => {}).length, 1); + assert( (([a,b]) => {}).length, 1); + assert( (({a,b}) => {}).length, 1); + assert( ((c, [a,b] = 1, d) => {}).length, 1); +} + +function test_argument_scope() +{ + var f; + var c = "global"; + + f = function(a = eval("var arguments")) {}; + assert_throws(SyntaxError, f); + + f = function(a = eval("1"), b = arguments[0]) { return b; }; + assert(f(12), 12); + + f = function(a, b = arguments[0]) { return b; }; + assert(f(12), 12); + + f = function(a, b = () => arguments) { return b; }; + assert(f(12)()[0], 12); + + f = function(a = eval("1"), b = () => arguments) { return b; }; + assert(f(12)()[0], 12); + + (function() { + "use strict"; + f = function(a = this) { return a; }; + assert(f.call(123), 123); + + f = function f(a = f) { return a; }; + assert(f(), f); + + f = function f(a = eval("f")) { return a; }; + assert(f(), f); + })(); + + f = (a = eval("var c = 1"), probe = () => c) => { + var c = 2; + assert(c, 2); + assert(probe(), 1); + } + f(); + + f = (a = eval("var arguments = 1"), probe = () => arguments) => { + var arguments = 2; + assert(arguments, 2); + assert(probe(), 1); + } + f(); + + f = function f(a = eval("var c = 1"), b = c, probe = () => c) { + assert(b, 1); + assert(c, 1); + assert(probe(), 1) + } + f(); + + assert(c, "global"); + f = function f(a, b = c, probe = () => c) { + eval("var c = 1"); + assert(c, 1); + assert(b, "global"); + assert(probe(), "global") + } + f(); + assert(c, "global"); + + f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) { + assert(probe(), 1) + } + f(); +} + +function test_function_expr_name() +{ + var f; + + /* non strict mode test : assignment to the function name silently + fails */ + + f = function myfunc() { + myfunc = 1; + return myfunc; + }; + assert(f(), f); + + f = function myfunc() { + myfunc = 1; + (() => { + myfunc = 1; + })(); + return myfunc; + }; + assert(f(), f); + + f = function myfunc() { + eval("myfunc = 1"); + return myfunc; + }; + assert(f(), f); + + /* strict mode test : assignment to the function name raises a + TypeError exception */ + + f = function myfunc() { + "use strict"; + myfunc = 1; + }; + assert_throws(TypeError, f); + + f = function myfunc() { + "use strict"; + (() => { + myfunc = 1; + })(); + }; + assert_throws(TypeError, f); + + f = function myfunc() { + "use strict"; + eval("myfunc = 1"); + }; + assert_throws(TypeError, f); +} + test_op1(); test_cvt(); test_eq(); @@ -392,3 +542,6 @@ test_regexp_skip(); test_labels(); test_destructuring(); test_spread(); +test_function_length(); +test_argument_scope(); +test_function_expr_name(); diff --git a/win/dirent.h b/win/dirent.h new file mode 100644 index 000000000..077674e45 --- /dev/null +++ b/win/dirent.h @@ -0,0 +1,1166 @@ +/* + * Dirent interface for Microsoft Visual Studio + * + * Copyright (C) 1998-2019 Toni Ronkko + * This file is part of dirent. Dirent may be freely distributed + * under the MIT license. For all details and documentation, see + * https://github.com/tronkko/dirent + */ +#ifndef DIRENT_H +#define DIRENT_H + +/* Hide warnings about unreferenced local functions */ +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunused-function" +#elif defined(_MSC_VER) +# pragma warning(disable:4505) +#elif defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +/* + * Include windows.h without Windows Sockets 1.1 to prevent conflicts with + * Windows Sockets 2.0. + */ +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Indicates that d_type field is available in dirent structure */ +#define _DIRENT_HAVE_D_TYPE + +/* Indicates that d_namlen field is available in dirent structure */ +#define _DIRENT_HAVE_D_NAMLEN + +/* Entries missing from MSVC 6.0 */ +#if !defined(FILE_ATTRIBUTE_DEVICE) +# define FILE_ATTRIBUTE_DEVICE 0x40 +#endif + +/* File type and permission flags for stat(), general mask */ +#if !defined(S_IFMT) +# define S_IFMT _S_IFMT +#endif + +/* Directory bit */ +#if !defined(S_IFDIR) +# define S_IFDIR _S_IFDIR +#endif + +/* Character device bit */ +#if !defined(S_IFCHR) +# define S_IFCHR _S_IFCHR +#endif + +/* Pipe bit */ +#if !defined(S_IFFIFO) +# define S_IFFIFO _S_IFFIFO +#endif + +/* Regular file bit */ +#if !defined(S_IFREG) +# define S_IFREG _S_IFREG +#endif + +/* Read permission */ +#if !defined(S_IREAD) +# define S_IREAD _S_IREAD +#endif + +/* Write permission */ +#if !defined(S_IWRITE) +# define S_IWRITE _S_IWRITE +#endif + +/* Execute permission */ +#if !defined(S_IEXEC) +# define S_IEXEC _S_IEXEC +#endif + +/* Pipe */ +#if !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO +#endif + +/* Block device */ +#if !defined(S_IFBLK) +# define S_IFBLK 0 +#endif + +/* Link */ +#if !defined(S_IFLNK) +# define S_IFLNK 0 +#endif + +/* Socket */ +#if !defined(S_IFSOCK) +# define S_IFSOCK 0 +#endif + +/* Read user permission */ +#if !defined(S_IRUSR) +# define S_IRUSR S_IREAD +#endif + +/* Write user permission */ +#if !defined(S_IWUSR) +# define S_IWUSR S_IWRITE +#endif + +/* Execute user permission */ +#if !defined(S_IXUSR) +# define S_IXUSR 0 +#endif + +/* Read group permission */ +#if !defined(S_IRGRP) +# define S_IRGRP 0 +#endif + +/* Write group permission */ +#if !defined(S_IWGRP) +# define S_IWGRP 0 +#endif + +/* Execute group permission */ +#if !defined(S_IXGRP) +# define S_IXGRP 0 +#endif + +/* Read others permission */ +#if !defined(S_IROTH) +# define S_IROTH 0 +#endif + +/* Write others permission */ +#if !defined(S_IWOTH) +# define S_IWOTH 0 +#endif + +/* Execute others permission */ +#if !defined(S_IXOTH) +# define S_IXOTH 0 +#endif + +/* Maximum length of file name */ +#if !defined(PATH_MAX) +# define PATH_MAX MAX_PATH +#endif +#if !defined(FILENAME_MAX) +# define FILENAME_MAX MAX_PATH +#endif +#if !defined(NAME_MAX) +# define NAME_MAX FILENAME_MAX +#endif + +/* File type flags for d_type */ +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK + +/* Macros for converting between st_mode and d_type */ +#define IFTODT(mode) ((mode) & S_IFMT) +#define DTTOIF(type) (type) + +/* + * File type macros. Note that block devices, sockets and links cannot be + * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are + * only defined for compatibility. These macros should always return false + * on Windows. + */ +#if !defined(S_ISFIFO) +# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISDIR) +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISLNK) +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) +# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISCHR) +# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISBLK) +# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#endif + +/* Return the exact length of the file name without zero terminator */ +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) + +/* Return the maximum size of a file name */ +#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Wide-character version */ +struct _wdirent { + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + wchar_t d_name[PATH_MAX+1]; +}; +typedef struct _wdirent _wdirent; + +struct _WDIR { + /* Current directory entry */ + struct _wdirent ent; + + /* Private file data */ + WIN32_FIND_DATAW data; + + /* True if data is valid */ + int cached; + + /* Win32 search handle */ + HANDLE handle; + + /* Initial directory name */ + wchar_t *patt; +}; +typedef struct _WDIR _WDIR; + +/* Multi-byte character version */ +struct dirent { + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + char d_name[PATH_MAX+1]; +}; +typedef struct dirent dirent; + +struct DIR { + struct dirent ent; + struct _WDIR *wdirp; +}; +typedef struct DIR DIR; + + +/* Dirent functions */ +static DIR *opendir (const char *dirname); +static _WDIR *_wopendir (const wchar_t *dirname); + +static struct dirent *readdir (DIR *dirp); +static struct _wdirent *_wreaddir (_WDIR *dirp); + +static int readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result); +static int _wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); + +static int closedir (DIR *dirp); +static int _wclosedir (_WDIR *dirp); + +static void rewinddir (DIR* dirp); +static void _wrewinddir (_WDIR* dirp); + +static int scandir (const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)); + +static int alphasort (const struct dirent **a, const struct dirent **b); + +static int versionsort (const struct dirent **a, const struct dirent **b); + + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir + + +/* Internal utility functions */ +static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); +static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); + +static int dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count); + +static int dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, + const wchar_t *wcstr, + size_t count); + +static void dirent_set_errno (int error); + + +/* + * Open directory stream DIRNAME for read and return a pointer to the + * internal working area that is used to retrieve individual directory + * entries. + */ +static _WDIR* +_wopendir( + const wchar_t *dirname) +{ + _WDIR *dirp; +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + DWORD n; +#else + /* WinRT */ + size_t n; +#endif + wchar_t *p; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate new _WDIR structure */ + dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); + if (!dirp) { + return NULL; + } + + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + + /* + * Compute the length of full path plus zero terminator + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + n = GetFullPathNameW (dirname, 0, NULL, NULL); +#else + /* WinRT */ + n = wcslen (dirname); +#endif + + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); + if (dirp->patt == NULL) { + goto exit_closedir; + } + + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + n = GetFullPathNameW (dirname, n, dirp->patt, NULL); + if (n <= 0) { + goto exit_closedir; + } +#else + /* WinRT */ + wcsncpy_s (dirp->patt, n+1, dirname, n); +#endif + + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } + *p++ = '*'; + *p = '\0'; + + /* Open directory stream and retrieve the first entry */ + if (!dirent_first (dirp)) { + goto exit_closedir; + } + + /* Success */ + return dirp; + + /* Failure */ +exit_closedir: + _wclosedir (dirp); + return NULL; +} + +/* + * Read next directory entry. + * + * Returns pointer to static directory entry which may be overwritten by + * subsequent calls to _wreaddir(). + */ +static struct _wdirent* +_wreaddir( + _WDIR *dirp) +{ + struct _wdirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) _wreaddir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry. + * + * Returns zero on success. If end of directory stream is reached, then sets + * result to NULL and returns zero. + */ +static int +_wreaddir_r( + _WDIR *dirp, + struct _wdirent *entry, + struct _wdirent **result) +{ + WIN32_FIND_DATAW *datap; + + /* Read next directory entry */ + datap = dirent_next (dirp); + if (datap) { + size_t n; + DWORD attr; + + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + n = 0; + while (n < PATH_MAX && datap->cFileName[n] != 0) { + entry->d_name[n] = datap->cFileName[n]; + n++; + } + entry->d_name[n] = 0; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = n; + + /* File type */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entry->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entry->d_type = DT_DIR; + } else { + entry->d_type = DT_REG; + } + + /* Reset dummy fields */ + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct _wdirent); + + /* Set result address */ + *result = entry; + + } else { + + /* Return NULL to indicate end of directory */ + *result = NULL; + + } + + return /*OK*/0; +} + +/* + * Close directory stream opened by opendir() function. This invalidates the + * DIR structure as well as any directory entry read previously by + * _wreaddir(). + */ +static int +_wclosedir( + _WDIR *dirp) +{ + int ok; + if (dirp) { + + /* Release search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + } + + /* Release search pattern */ + free (dirp->patt); + + /* Release directory structure */ + free (dirp); + ok = /*success*/0; + + } else { + + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + + } + return ok; +} + +/* + * Rewind directory stream such that _wreaddir() returns the very first + * file name again. + */ +static void +_wrewinddir( + _WDIR* dirp) +{ + if (dirp) { + /* Release existing search handle */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose (dirp->handle); + } + + /* Open new search handle */ + dirent_first (dirp); + } +} + +/* Get first directory entry (internal) */ +static WIN32_FIND_DATAW* +dirent_first( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *datap; + DWORD error; + + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileExW( + dirp->patt, FindExInfoStandard, &dirp->data, + FindExSearchNameMatch, NULL, 0); + if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* a directory entry is now waiting in memory */ + datap = &dirp->data; + dirp->cached = 1; + + } else { + + /* Failed to open directory: no directory entry in memory */ + dirp->cached = 0; + datap = NULL; + + /* Set error code */ + error = GetLastError (); + switch (error) { + case ERROR_ACCESS_DENIED: + /* No read access to directory */ + dirent_set_errno (EACCES); + break; + + case ERROR_DIRECTORY: + /* Directory name is invalid */ + dirent_set_errno (ENOTDIR); + break; + + case ERROR_PATH_NOT_FOUND: + default: + /* Cannot find the file */ + dirent_set_errno (ENOENT); + } + + } + return datap; +} + +/* + * Get next directory entry (internal). + * + * Returns + */ +static WIN32_FIND_DATAW* +dirent_next( + _WDIR *dirp) +{ + WIN32_FIND_DATAW *p; + + /* Get next directory entry */ + if (dirp->cached != 0) { + + /* A valid directory entry already in memory */ + p = &dirp->data; + dirp->cached = 0; + + } else if (dirp->handle != INVALID_HANDLE_VALUE) { + + /* Get the next directory entry from stream */ + if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { + /* Got a file */ + p = &dirp->data; + } else { + /* The very last entry has been processed or an error occurred */ + FindClose (dirp->handle); + dirp->handle = INVALID_HANDLE_VALUE; + p = NULL; + } + + } else { + + /* End of directory stream reached */ + p = NULL; + + } + + return p; +} + +/* + * Open directory stream using plain old C-string. + */ +static DIR* +opendir( + const char *dirname) +{ + struct DIR *dirp; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno (ENOENT); + return NULL; + } + + /* Allocate memory for DIR structure */ + dirp = (DIR*) malloc (sizeof (struct DIR)); + if (!dirp) { + return NULL; + } + { + int error; + wchar_t wname[PATH_MAX + 1]; + size_t n; + + /* Convert directory name to wide-character string */ + error = dirent_mbstowcs_s( + &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); + if (error) { + /* + * Cannot convert file name to wide-character string. This + * occurs if the string contains invalid multi-byte sequences or + * the output buffer is too small to contain the resulting + * string. + */ + goto exit_free; + } + + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir (wname); + if (!dirp->wdirp) { + goto exit_free; + } + + } + + /* Success */ + return dirp; + + /* Failure */ +exit_free: + free (dirp); + return NULL; +} + +/* + * Read next directory entry. + */ +static struct dirent* +readdir( + DIR *dirp) +{ + struct dirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) readdir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry into called-allocated buffer. + * + * Returns zero on success. If the end of directory stream is reached, then + * sets result to NULL and returns zero. + */ +static int +readdir_r( + DIR *dirp, + struct dirent *entry, + struct dirent **result) +{ + WIN32_FIND_DATAW *datap; + + /* Read next directory entry */ + datap = dirent_next (dirp->wdirp); + if (datap) { + size_t n; + int error; + + /* Attempt to convert file name to multi-byte string */ + error = dirent_wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); + + /* + * If the file name cannot be represented by a multi-byte string, + * then attempt to use old 8+3 file name. This allows traditional + * Unix-code to access some file names despite of unicode + * characters, although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file + * name unless the file system provides one. At least + * VirtualBox shared folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') { + error = dirent_wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, + datap->cAlternateFileName, PATH_MAX + 1); + } + + if (!error) { + DWORD attr; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = n - 1; + + /* File attributes */ + attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { + entry->d_type = DT_CHR; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + entry->d_type = DT_DIR; + } else { + entry->d_type = DT_REG; + } + + /* Reset dummy fields */ + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct dirent); + + } else { + + /* + * Cannot convert file name to multi-byte string so construct + * an erroneous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entry->d_name[0] = '?'; + entry->d_name[1] = '\0'; + entry->d_namlen = 1; + entry->d_type = DT_UNKNOWN; + entry->d_ino = 0; + entry->d_off = -1; + entry->d_reclen = 0; + + } + + /* Return pointer to directory entry */ + *result = entry; + + } else { + + /* No more directory entries */ + *result = NULL; + + } + + return /*OK*/0; +} + +/* + * Close directory stream. + */ +static int +closedir( + DIR *dirp) +{ + int ok; + if (dirp) { + + /* Close wide-character directory stream */ + ok = _wclosedir (dirp->wdirp); + dirp->wdirp = NULL; + + /* Release multi-byte character version */ + free (dirp); + + } else { + + /* Invalid directory stream */ + dirent_set_errno (EBADF); + ok = /*failure*/-1; + + } + return ok; +} + +/* + * Rewind directory stream to beginning. + */ +static void +rewinddir( + DIR* dirp) +{ + /* Rewind wide-character string directory stream */ + _wrewinddir (dirp->wdirp); +} + +/* + * Scan directory for entries. + */ +static int +scandir( + const char *dirname, + struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)) +{ + struct dirent **files = NULL; + size_t size = 0; + size_t allocated = 0; + const size_t init_size = 1; + DIR *dir = NULL; + struct dirent *entry; + struct dirent *tmp = NULL; + size_t i; + int result = 0; + + /* Open directory stream */ + dir = opendir (dirname); + if (dir) { + + /* Read directory entries to memory */ + while (1) { + + /* Enlarge pointer table to make room for another pointer */ + if (size >= allocated) { + void *p; + size_t num_entries; + + /* Compute number of entries in the enlarged pointer table */ + if (size < init_size) { + /* Allocate initial pointer table */ + num_entries = init_size; + } else { + /* Double the size */ + num_entries = size * 2; + } + + /* Allocate first pointer table or enlarge existing table */ + p = realloc (files, sizeof (void*) * num_entries); + if (p != NULL) { + /* Got the memory */ + files = (dirent**) p; + allocated = num_entries; + } else { + /* Out of memory */ + result = -1; + break; + } + + } + + /* Allocate room for temporary directory entry */ + if (tmp == NULL) { + tmp = (struct dirent*) malloc (sizeof (struct dirent)); + if (tmp == NULL) { + /* Cannot allocate temporary directory entry */ + result = -1; + break; + } + } + + /* Read directory entry to temporary area */ + if (readdir_r (dir, tmp, &entry) == /*OK*/0) { + + /* Did we get an entry? */ + if (entry != NULL) { + int pass; + + /* Determine whether to include the entry in result */ + if (filter) { + /* Let the filter function decide */ + pass = filter (tmp); + } else { + /* No filter function, include everything */ + pass = 1; + } + + if (pass) { + /* Store the temporary entry to pointer table */ + files[size++] = tmp; + tmp = NULL; + + /* Keep up with the number of files */ + result++; + } + + } else { + + /* + * End of directory stream reached => sort entries and + * exit. + */ + qsort (files, size, sizeof (void*), + (int (*) (const void*, const void*)) compare); + break; + + } + + } else { + /* Error reading directory entry */ + result = /*Error*/ -1; + break; + } + + } + + } else { + /* Cannot open directory */ + result = /*Error*/ -1; + } + + /* Release temporary directory entry */ + free (tmp); + + /* Release allocated memory on error */ + if (result < 0) { + for (i = 0; i < size; i++) { + free (files[i]); + } + free (files); + files = NULL; + } + + /* Close directory stream */ + if (dir) { + closedir (dir); + } + + /* Pass pointer table to caller */ + if (namelist) { + *namelist = files; + } + return result; +} + +/* Alphabetical sorting */ +static int +alphasort( + const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} + +/* Sort versions */ +static int +versionsort( + const struct dirent **a, const struct dirent **b) +{ + /* FIXME: implement strverscmp and use that */ + return alphasort (a, b); +} + +/* Convert multi-byte string to wide character string */ +static int +dirent_mbstowcs_s( + size_t *pReturnValue, + wchar_t *wcstr, + size_t sizeInWords, + const char *mbstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to wide-character string (or count characters) */ + n = mbstowcs (wcstr, mbstr, sizeInWords); + if (!wcstr || n < count) { + + /* Zero-terminate output buffer */ + if (wcstr && sizeInWords) { + if (n >= sizeInWords) { + n = sizeInWords - 1; + } + wcstr[n] = 0; + } + + /* Length of resulting multi-byte string WITH zero terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + + } else { + + /* Could not convert string */ + error = 1; + + } + +#endif + return error; +} + +/* Convert wide-character string to multi-byte string */ +static int +dirent_wcstombs_s( + size_t *pReturnValue, + char *mbstr, + size_t sizeInBytes, /* max size of mbstr */ + const wchar_t *wcstr, + size_t count) +{ + int error; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 or later */ + error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); + +#else + + /* Older Visual Studio or non-Microsoft compiler */ + size_t n; + + /* Convert to multi-byte string (or count the number of bytes needed) */ + n = wcstombs (mbstr, wcstr, sizeInBytes); + if (!mbstr || n < count) { + + /* Zero-terminate output buffer */ + if (mbstr && sizeInBytes) { + if (n >= sizeInBytes) { + n = sizeInBytes - 1; + } + mbstr[n] = '\0'; + } + + /* Length of resulting multi-bytes string WITH zero-terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + error = 0; + + } else { + + /* Cannot convert string */ + error = 1; + + } + +#endif + return error; +} + +/* Set errno variable */ +static void +dirent_set_errno( + int error) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + + /* Microsoft Visual Studio 2005 and later */ + _set_errno (error); + +#else + + /* Non-Microsoft compiler or older Microsoft compiler */ + errno = error; + +#endif +} + + +#ifdef __cplusplus +} +#endif +#endif /*DIRENT_H*/ \ No newline at end of file diff --git a/win/getopt.h b/win/getopt.h new file mode 100644 index 000000000..d78b753b2 --- /dev/null +++ b/win/getopt.h @@ -0,0 +1,653 @@ +#ifndef __GETOPT_H__ +/** + * DISCLAIMER + * This file is part of the mingw-w64 runtime package. + * + * The mingw-w64 runtime package and its code is distributed in the hope that it + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + /* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#pragma warning(disable:4996) + +#define __GETOPT_H__ + +/* All the headers include this file. */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +#undef optreset /* see getopt.h */ +#define optreset __mingw_optreset +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +//extern int optind; /* index of first non-option in argv */ +//extern int optopt; /* single option character, as parsed */ +//extern int opterr; /* flag to enable built-in diagnostics... */ +// /* (user may set to zero, to suppress) */ +// +//extern char *optarg; /* pointer to argument of current option */ + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#ifndef __CYGWIN__ +#define __progname __argv[0] +#else +extern char __declspec(dllimport) *__progname; +#endif + +#ifdef __CYGWIN__ +static char EMSG[] = ""; +#else +#define EMSG "" +#endif + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +static void +_vwarnx(const char *fmt,va_list ap) +{ + (void)fprintf(stderr,"%s: ",__progname); + if (fmt != NULL) + (void)vfprintf(stderr,fmt,ap); + (void)fprintf(stderr,"\n"); +} + +static void +warnx(const char *fmt,...) +{ + va_list ap; + va_start(ap,fmt); + _vwarnx(fmt,ap); + va_end(ap); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +//extern int getopt(int nargc, char * const *nargv, const char *options); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ + +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + current_argv = place; + match = -1; + ambiguous = 0; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +#undef IDENTICAL_INTERPRETATION +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + * + * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or + * optreset != 0 for GNU compatibility. + */ + if (posixly_correct == -1 || optreset != 0) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = (char*)strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} + +//extern int getopt_long(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +//extern int getopt_long_only(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ \ No newline at end of file diff --git a/win/premake-vs2017.bat b/win/premake-vs2017.bat new file mode 100644 index 000000000..87ce8de30 --- /dev/null +++ b/win/premake-vs2017.bat @@ -0,0 +1,4 @@ +cd .. +premake5 vs2017 --jsx --storage +cd .build +start vs2017\quickjs.sln diff --git a/win/premake-vs2019.bat b/win/premake-vs2019.bat new file mode 100644 index 000000000..3bceb0dfe --- /dev/null +++ b/win/premake-vs2019.bat @@ -0,0 +1,4 @@ +cd .. +premake5 vs2019 --jsx --storage +cd .build +start vs2019\quickjs.sln \ No newline at end of file