From: stephan Date: Thu, 25 Sep 2025 00:53:30 +0000 (+0000) Subject: Wasm build deps fixes. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ef565295f56e125894d36a26437500c122bd94bd;p=thirdparty%2Fsqlite.git Wasm build deps fixes. FossilOrigin-Name: fd0c649047f4e444ea682138a3555a973839627150e1124bb9d9ced17880a9e5 --- diff --git a/ext/wasm/GNUmakefile b/ext/wasm/GNUmakefile index b88a675f0c..e536ebeba8 100644 --- a/ext/wasm/GNUmakefile +++ b/ext/wasm/GNUmakefile @@ -38,15 +38,6 @@ MAKEFILE.fiddle = fiddle.make CLEAN_FILES = DISTCLEAN_FILES = config.make MAKING_CLEAN = $(if $(filter %clean,$(MAKECMDGOALS)),1,0) -.PHONY: clean distclean -clean: - -rm -f $(CLEAN_FILES) - -rm -fr $(dir.fiddle-debug) $(dir.dout) $(dir.tmp) - -distclean: clean - -rm -f $(DISTCLEAN_FILES) - -more: all # dir.top = the top dir of the canonical build tree, where # sqlite3.[ch] live. @@ -60,7 +51,7 @@ dir.api = api dir.jacc = jaccwabyt dir.common = common dir.fiddle = fiddle -dir.fiddle-debug = fiddle-debug +dir.fiddle.debug = fiddle-debug dir.tool = $(dir.top)/tool # dir.dout = output dir for deliverables dir.dout = $(dir.wasm)/jswasm @@ -69,8 +60,6 @@ dir.dout = $(dir.wasm)/jswasm dir.tmp = $(dir.wasm)/bld dir.wasmfs = $(dir.dout) -CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~ $(dir.fiddle)/*~ \ - # # Emoji for log messages. # @@ -223,6 +212,8 @@ $(3): $$(MAKEFILE_LIST) $$(bin.c-pp) $(2) CLEAN_FILES += $(3) endef +c-pp.D.64bit = -D64bit + # # $(call b.call.strip-emcc-js-cruft) # @@ -591,12 +582,6 @@ $(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE) @$(call b.call.mkdir@) cat $(EXPORTED_FUNCTIONS.api.in) > $@ -# -# $(sqlite3-api.ext.jses) = API-related files which are standalone -# files, not part of the amalgamation. -# -sqlite3-api.ext.jses = $(dir.api)/sqlite3-opfs-async-proxy.js - ######################################################################## # emcc flags for .c/.o/.wasm/.js. emcc.flags = @@ -785,6 +770,7 @@ sqlite3-wasmfs.cfiles = $(sqlite3-wasm.cfiles) # # Maintenance reminder: Mac sed works differently than GNU sed, so we # use awk instead of sed for this. +# define b.call.patch-export-default if [ x1 = x$(1) ]; then \ echo "$(if $(3),$(3),$(logtag.@)) $(emo.bug) Fragile workaround for emscripten/issues/18237." \ @@ -1013,7 +999,7 @@ define gen-worker1 # $2 = $(c-pp.D.NAME) $(call b.eval.c-pp,filter,$(dir.api)/sqlite3-worker1.c-pp.js,\ $(dir.dout)/sqlite3-worker1$(1),$(2)) -sqlite3-api.ext.jses += $(dir.dout)/sqlite3-worker1$(1) +sqlite3.ext.js += $(dir.dout)/sqlite3-worker1$(1) all: $(dir.dout)/sqlite3-worker1$(1) endef @@ -1030,7 +1016,7 @@ define gen-promiser # $2 = $(c-pp.D.NAME) $(call b.eval.c-pp,filter,$(dir.api)/sqlite3-worker1-promiser.c-pp.js,\ $(dir.dout)/sqlite3-worker1-promiser$(1),$(2)) -sqlite3-api.ext.jses += $(dir.dout)/sqlite3-worker1-promiser$(1) +sqlite3.ext.js += $(dir.dout)/sqlite3-worker1-promiser$(1) all: $(dir.dout)/sqlite3-worker1-promiser$(1) endef @@ -1047,20 +1033,43 @@ $(eval $(call gen-promiser,-bundler-friendly.mjs,$(c-pp.D.bundler))) define gen-dwp $(call b.eval.c-pp,test,demo-worker1-promiser.c-pp.js,demo-worker1-promiser$(1),$(3)) $(call b.eval.c-pp,test,demo-worker1-promiser.c-pp.html,demo-worker1-promiser$(2),$(3)) -all: demo-worker1-promiser$(1) demo-worker1-promiser$(2) +demos: demo-worker1-promiser$(1) demo-worker1-promiser$(2) endef $(eval $(call gen-dwp,.js,.html,$(c-pp.D.vanilla))) $(eval $(call gen-dwp,.mjs,-esm.html,$(c-pp.D.esm))) +all: demos + + +# +# $(sqlite3.ext.in) = API-related files which are standalone +# files, not part of the amalgamation. This list holds +# the name of each such _output_ file. +# +sqlite3.ext.js += $(dir.dout)/sqlite3-opfs-async-proxy.js +$(dir.dout)/sqlite3-opfs-async-proxy.js: $(dir.api)/sqlite3-opfs-async-proxy.js + @$(call b.call.cp,@,$<,$@) + # -# Add a dep of $(sqlite3-api.ext.jses) on every build's JS file. +# Copy "external" files - those which are not part of the amalgamation +# - to $(dir.dout). +# +#define gen-extjs +#sqlite3.ext.js += $(dir.dout)/$(notdir $(1)) +#$(dir.dout)/$(notdir $(1)): $(1) +# @$(call b.cp,@,$(1),$@) +#endef +#sqlite3.ext.js = +#$(foreach X,$(sqlite3.ext.js.in),$(eval $(call gen-extjs,$(X)))) + +# +# Add a dep of $(sqlite3.ext.js) on every build's JS file. # The primary purpose of this is to force them to be copied early # in the build process, which is sometimes a time-saver during # development, allowing the developer to reload a test page while # other parts of the build are still running. # -$(foreach B,$(b.names),$(eval $(out.$(B).js): $(sqlite3-api.ext.jses))) - +$(foreach B,$(b.names),$(eval $(out.$(B).js): $(sqlite3.ext.js))) ######################################################################## # batch-runner.js is part of one of the test apps which reads in SQL @@ -1138,29 +1147,29 @@ $(EXPORTED_FUNCTIONS.speedtest1): $(EXPORTED_FUNCTIONS.api.core) @echo "Making $@ ..." @$(call b.call.mkdir@) @{ echo _wasm_main; cat $(EXPORTED_FUNCTIONS.api.core); } > $@ -emcc.flags.speedtest1-vanilla = $(cflags.common) -DSQLITE_SPEEDTEST1_WASM +emcc.flags.speedtest1 = $(cflags.common) -DSQLITE_SPEEDTEST1_WASM speedtest1.cfiles = $(speedtest1.c) $(sqlite3-wasm.c) -$(out.speedtest1-vanilla.js): $(MAKEFILE) $(speedtest1.cfiles) \ - $(pre-post.speedtest1-vanilla.deps) \ +$(out.speedtest1.js): $(MAKEFILE) $(speedtest1.cfiles) \ + $(pre-post.speedtest1.deps) \ $(EXPORTED_FUNCTIONS.speedtest1) - @$(call b.echo,speedtest1-vanilla,$(emo.compile) building ...) + @$(call b.echo,speedtest1,$(emo.compile) building ...) @$(call b.call.mkdir@) $(b.cmd@)$(bin.emcc) \ $(emcc.speedtest1) \ $(emcc.speedtest1.common) \ - $(emcc.flags.speedtest1-vanilla) $(pre-post.speedtest1-vanilla.flags) \ + $(emcc.flags.speedtest1) $(pre-post.speedtest1.flags) \ $(SQLITE_OPT) \ -USQLITE_WASM_BARE_BONES \ -USQLITE_C -DSQLITE_C=$(sqlite3.canonical.c) \ $(speedtest1.exit-runtime0) \ -o $@ $(speedtest1.cfiles) -lm @chmod -x $(basename $@).wasm - @$(call b.call.wasm-strip,speedtest1-vanilla) - @$(call b.do.wasm-opt,speedtest1-vanilla) - @$(call b.call.strip-emcc-js-cruft,$(logtag.speedtest1-vanilla)) + @$(call b.call.wasm-strip,speedtest1) + @$(call b.do.wasm-opt,speedtest1) + @$(call b.call.strip-emcc-js-cruft,$(logtag.speedtest1)) @ls -la $@ $(speedtest1.wasm) -speedtest1: $(out.speedtest1-vanilla.js) +speedtest1: $(out.speedtest1.js) # end speedtest1.js ######################################################################## @@ -1183,36 +1192,42 @@ speedtest1: $(out.speedtest1-vanilla.js) # pair of js/wasm files. # # To create those, we filter tester1.c-pp.js with $(bin.c-pp)... -c-pp.D.64bit = -D64bit # tester1.js variants: -$(eval $(call b.eval.c-pp,test,tester1.c-pp.js,tester1.js,$(c-pp.D.vanilla))) -$(eval $(call b.eval.c-pp,test,tester1.c-pp.js,tester1-64bit.js,$(c-pp.D.vanilla64) $(c-pp.D.64bit))) -$(eval $(call b.eval.c-pp,test,tester1.c-pp.js,tester1.mjs,$(c-pp.D.esm))) -$(eval $(call b.eval.c-pp,test,tester1.c-pp.js,tester1-64bit.mjs,$(c-pp.D.esm64) $(c-pp.D.64bit))) +define gen-tester1.js +# $1=build name to have dep on +# $2=suffix for tester1SUFFIX JS +# $3=c-pp flags +$(call b.eval.c-pp,test,tester1.c-pp.js,tester1$(2),$(3)) +tester1$(2): $(sqlite3.ext.js) $(out.$(1).wasm) +tester1: tester1$(2) +tester1-$(1): tester1$(2) +endef +$(eval $(call gen-tester1.js,vanilla,.js,$(c-pp.D.vanilla))) +$(eval $(call gen-tester1.js,vanilla64,-64bit.js,$(c-pp.D.vanilla64))) +$(eval $(call gen-tester1.js,esm,.mjs,$(c-pp.D.esm))) +$(eval $(call gen-tester1.js,esm64,-64bit.mjs,$(c-pp.D.esm64))) # tester1.html variants: -$(eval $(call b.eval.c-pp,test,tester1.c-pp.html,tester1.html,$(c-pp.D.vanilla))) -$(eval $(call b.eval.c-pp,test,tester1.c-pp.html,tester1-64bit.html,$(c-pp.D.vanilla64) $(c-pp.D.64bit))) -$(eval $(call b.eval.c-pp,test,tester1.c-pp.html,tester1-esm.html,$(c-pp.D.esm))) -$(eval $(call b.eval.c-pp,test,tester1.c-pp.html,tester1-esm-64bit.html,$(c-pp.D.esm64) $(c-pp.D.64bit))) +define gen-tester1.html +$(call b.eval.c-pp,test,tester1.c-pp.html,tester1$(2).html,$(3)) +tester1$(2).html: tester1-$(1) +tester1: tester1$(2).html +endef +$(eval $(call gen-tester1.html,vanilla,,$(c-pp.D.vanilla))) +$(eval $(call gen-tester1.html,vanilla64,-64bit,$(c-pp.D.vanilla64))) +$(eval $(call gen-tester1.html,esm,-esm,$(c-pp.D.esm64))) +$(eval $(call gen-tester1.html,esm64,-esm-64bit,$(c-pp.D.esm64))) + # tester1-worker.html variants: # There is no ESM variant. Instead, that page accepts a ?esm URL flag to switch # to ESM mode. $(eval $(call b.eval.c-pp,test,tester1-worker.c-pp.html,tester1-worker.html)) $(eval $(call b.eval.c-pp,test,tester1-worker.c-pp.html,tester1-worker-64bit.html,$(c-pp.D.64bit))) +tester: tester1-worker.html tester1-worker-64bit.html -tester1.js: $(out.vanilla.wasm) -tester1.mjs: $(out.esm.wasm) -tester1-64bit.js: $(out.vanilla64.wasm) -tester1-64bit.mjs: $(out.esm64.wasm) -tester1: tester1.js tester1.mjs tester1.html tester1-esm.html -tester1: tester1-64bit.js tester1-64bit.mjs tester1-64bit.html tester1-esm-64bit.html -tester1: tester1-worker.html tester1-worker-64bit.html -# We do not include $(dir.dout)/sqlite3-bundler-friendly.mjs in this -# because bundlers are client-specific. We don't use any of them. -all: tester1 +all: tester ######################################################################## # Convenience rules to rebuild with various -Ox levels. Much @@ -1236,14 +1251,14 @@ o0: clean o1: clean $(MAKE) -e "emcc_opt=-O1 $(emcc-opt-extra)" o2: clean - $(MAKE) -j2 -e "emcc_opt=-O2 $(emcc-opt-extra)" + $(MAKE) -e "emcc_opt=-O2 $(emcc-opt-extra)" o3: clean $(MAKE) -e "emcc_opt=-O3 $(emcc-opt-extra)" os: clean @echo "$(emo.fire)WARNING$(emo.fire): -Os can result in a build with mysteriously missing pieces!" $(MAKE) -e "emcc_opt=-Os $(emcc-opt-extra)" oz: clean - $(MAKE) -j2 -e "emcc_opt=-Oz $(emcc-opt-extra)" + $(MAKE) -e "emcc_opt=-Oz $(emcc-opt-extra)" ######################################################################## # Sub-makes... @@ -1255,8 +1270,8 @@ include $(MAKEFILE.fiddle) # Push files to public wasm-testing.sqlite.org server wasm-testing.include = *.js *.mjs *.html \ ./tests \ - $(dir.dout) $(dir.common) $(dir.fiddle) $(dir.fiddle-debug) $(dir.jacc) -wasm-testing.exclude = sql/speedtest1.sql + $(dir.dout) $(dir.common) $(dir.fiddle) $(dir.fiddle.debug) $(dir.jacc) +wasm-testing.exclude = sql/speedtest1.sql jswasm/*/* wasm-testing.dir = /jail/sites/wasm-testing wasm-testing.dest ?= wasm-testing:$(wasm-testing.dir) # ---------------------^^^^^^^^^^^^ ssh alias @@ -1269,6 +1284,18 @@ push-testing: ssh wasm-testing 'cd $(wasm-testing.dir) && bash .gzip' || \ echo "SSH failed: it's likely that stale content will be served via old gzip files." +.PHONY: for-testing +for-testing: emcc_opt=-Oz +for-testing: loud=1 +#$(foreach B,$(b.names),$(eval for-testing: $(out.$(B).js))) +for-testing.deps = \ + tester1 demos \ + b-vanilla b-vanilla64 \ + b-esm b-esm64 \ + b-fiddle b-fiddle.debug \ + speedtest1 +for-testing: $(for-testing.deps) + ######################################################################## # If we find a copy of https://sqlite.org/wasm checked out, copy # certain files over to it, applying some automated edits... @@ -1304,3 +1331,14 @@ endif # Run local web server for the test/demo pages. httpd: althttpd -max-age 1 -enable-sab 1 -page index.html + + +.PHONY: clean distclean +clean: + -rm -f $(CLEAN_FILES) + -rm -fr $(dir.fiddle.debug) $(dir.dout) $(dir.tmp) + +distclean: clean + -rm -f $(DISTCLEAN_FILES) + +CLEAN_FILES += *~ $(dir.jacc)/*~ $(dir.api)/*~ $(dir.common)/*~ $(dir.fiddle)/*~ \ diff --git a/ext/wasm/mkwasmbuilds.c b/ext/wasm/mkwasmbuilds.c index 051dbd691f..bdf59e35d5 100644 --- a/ext/wasm/mkwasmbuilds.c +++ b/ext/wasm/mkwasmbuilds.c @@ -314,8 +314,7 @@ static void mk_prologue(void){ "dir.api", "dir.dout", "dir.tmp", "MAKEFILE", "MAKEFILE_LIST", /* Fiddle... */ - "dir.fiddle", "dir.fiddle-debug", - "MAKEFILE.fiddle", + "dir.fiddle", "dir.fiddle.debug", "EXPORTED_FUNCTIONS.fiddle", /* Some core JS files... */ // todo: we don't need these anymore @@ -407,8 +406,7 @@ static void mk_prologue(void){ ps("b.do.wasm-opt = echo '$(logtag.$(1)) wasm-opt not available'"); } ps("else"); { - ps("define b.do.wasm-opt" - ); + ps("define b.do.wasm-opt"); pf( "echo '[$(emo.b.$(1)) $(out.$(1).wasm)] $(emo.wasm-opt) $(bin.wasm-opt)';\\\n" "\ttmpfile=$(dir.dout.$(1))/wasm-opt-tmp.$(1).wasm; \\\n" @@ -433,6 +431,8 @@ static void mk_prologue(void){ } ps("endif"); } + + ps("more: all"); } /* @@ -583,7 +583,6 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){ "b.names += %s\n" "emo.b.%s = %s\n", zBuildName, zBuildName, pB->zEmo); - pf("b.names += %s\n", zBuildName); pf("logtag.%s ?= [%s [%s] $@]:\n", zBuildName, pB->zEmo, zBuildName); if( pB->zIfCond ){ @@ -616,6 +615,9 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){ pf("emcc.flags.%s ?= %s\n", zBuildName, pB->zEmcc ? pB->zEmcc : ""); emit_api_js(zBuildName, pB->zCmppD); + if( pB->flags & F_64BIT ){ + pf("c-pp.D.%s += $(c-pp.D.64bit)\n", zBuildName); + } mk_pre_post(zBuildName); { /* build it... */ @@ -637,10 +639,6 @@ static void mk_lib_mode(const char *zBuildName, const BuildDef * pB){ { /* Post-compilation transformations and copying to $(dir.dout)... */ if( (F_ESM & pB->flags) || (F_NODEJS & pB->flags) ){ - /* TODO? Replace this $(call) with the corresponding makefile - ** code. OTOH, we also use this $(call) in the speedtest1-wasmfs - ** build, which is not part of the rules emitted by this - ** program. */ pf("\t@$(call b.call.patch-export-default,1,%d,$(logtag.%s))\n", (F_WASMFS & pB->flags) ? 1 : 0, zBuildName @@ -834,7 +832,7 @@ static void mk_fiddle(void){ } static void mk_speedtest1(void){ - char const *zBuildName = "speedtest1-vanilla"; + char const *zBuildName = "speedtest1"; pf(zBanner "# Begin build %s\n", zBuildName); pf("emo.%s =" "🛼" // roller skates @@ -843,10 +841,11 @@ static void mk_speedtest1(void){ zBuildName); pf("logtag.%s = [$(emo.%s) [%s] $@]:\n" "$(info $(logtag.%s) Setting up target speedtest1)\n" - "all: speedtest1\n", + "all: %s\n", zBuildName, zBuildName, zBuildName, - zBuildName ); + zBuildName, zBuildName ); + pf("dir.dout.%s ?= $(dir.dout)\n", zBuildName); pf("out.%s.js = $(dir.dout)/speedtest1.js\n" "out.%s.wasm = $(dir.dout)/speedtest1.wasm\n", zBuildName, zBuildName); @@ -854,6 +853,8 @@ static void mk_speedtest1(void){ emit_api_js(zBuildName, 0); mk_pre_post(zBuildName); + /* Main rules are in the makefile */ + #if 0 mk_pre_post("speedtest1-vanilla"); ps(zBanner "ifeq (1,$(HAVE_WASMFS))"); diff --git a/manifest b/manifest index 9c253be183..a568a30b1e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Move\sthe\sstatic\smakefile\scode\sfrom\smkwamsbuilds.c\sinto\sthe\smakefile.\sMove\sutil.make\sback\sinto\sthe\smain\smakefile.\sRemove\sa\sbunch\sof\sdead\smakefile\scode\sand\sdocs. -D 2025-09-24T23:07:45.647 +C Wasm\sbuild\sdeps\sfixes. +D 2025-09-25T00:53:30.968 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -578,7 +578,7 @@ F ext/session/sqlite3session.c 9cd47bfefb23c114b7a5d9ee5822d941398902f30516bf0dd F ext/session/sqlite3session.h 7404723606074fcb2afdc6b72c206072cdb2b7d8ba097ca1559174a80bc26f7a F ext/session/test_session.c 8766b5973a6323934cb51248f621c3dc87ad2a98f023c3cc280d79e7d78d36fb F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c -F ext/wasm/GNUmakefile 2ccc1a25b21dcbe2e758bf16228ecd4223196a4249249f38aa4e2aed15b4e5c9 +F ext/wasm/GNUmakefile 3e4798dd38252e361b4baab2cba60ef329621a3d1955db0c53b004f3a37e8630 F ext/wasm/README-dist.txt f01081a850ce38a56706af6b481e3a7878e24e42b314cfcd4b129f0f8427066a F ext/wasm/README.md 66ace67ae98a45e4116f2ca5425b716887bcee4d64febee804ff6398e1ae9ec7 F ext/wasm/SQLTester/GNUmakefile e0794f676d55819951bbfae45cc5e8d7818dc460492dc317ce7f0d2eca15caff @@ -639,7 +639,7 @@ F ext/wasm/index-dist.html 56132399702b15d70c474c3f1952541e25cb0922942868f70daf1 F ext/wasm/index.html 1b329fb63e057c02a17ce178308d6b06aac62d92af7dd6d821fb0e183e0f1557 F ext/wasm/jaccwabyt/jaccwabyt.js bbac67bc7a79dca34afe6215fd16b27768d84e22273507206f888c117e2ede7d F ext/wasm/jaccwabyt/jaccwabyt.md 167fc0b624c9bc2c477846e336de9403842d81b1a24fc4d3b24317cb9eba734f -F ext/wasm/mkwasmbuilds.c 1c52e949c1301f3bc8c66a7b9bd5f565d6c66ca6127267dbed6f666535e42985 +F ext/wasm/mkwasmbuilds.c 238cc9a9888dec4a9b48e9b608982cc5b7f4b307438d9266e0d4fcca939d697d F ext/wasm/module-symbols.html dc476b403369b26a1a23773e13b80f41b9a49f0825e81435fe3600a7cfbbe337 F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96 F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63 @@ -2175,8 +2175,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 4ec7e6800e090f7e17469a77bc37b57d3e1777171a5b354dfc68345416de504f -R 342a67038077e1175d39de0f455be049 +P 18beeb26bfa48f806866e0e330024535adabcf668071abc4b6251eb39de2701d +R b0e1a74c5137f4633645ae07790f221a U stephan -Z 2c80b2640c338bdfc3dd972e978d7a39 +Z 436e3963d5b7b3aa761dea055937d61e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d3d58b5dd9..51e6980ca1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -18beeb26bfa48f806866e0e330024535adabcf668071abc4b6251eb39de2701d +fd0c649047f4e444ea682138a3555a973839627150e1124bb9d9ced17880a9e5