Compare commits

..

5 Commits

Author SHA1 Message Date
ee0aac8877 Add some images for F-Droid.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 6m14s
2024-08-02 20:31:22 -04:00
641c699720 Put android:versionCode and such back in the static AndroidManifest.xml. I forgot that F-Droid needs to see it. 2024-08-02 20:07:21 -04:00
aa1ad0a080 The beginnings of "What would it look like if I used a DHT for peer discovery?"
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 4m7s
2024-07-31 20:50:41 -04:00
1bc492aef1 Update libbacktrace to latest. 2024-07-31 20:21:50 -04:00
928ff690d2 Start work on v0.0.22. 2024-07-31 20:21:38 -04:00
157 changed files with 7652 additions and 17131 deletions

View File

@ -14,7 +14,7 @@ IndentWidth: 4
MaxEmptyLinesToKeep: 1
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: false
SortIncludes: true
SortIncludes: false
TabWidth: 4
UseTab: Always
...

40
.fdroid.yml Normal file
View File

@ -0,0 +1,40 @@
Categories:
- Internet
License: MIT
AutoName: tildefriends
AuthorName: Cory McWilliams
AuthorEmail: cory@tildefriends.net
RepoType: git
Repo: https://dev.tildefriends.net/cory/tildefriends.git
Builds:
- versionName: 0.0.21-wip
versionCode: 22
commit: 09b6a00731d45fa160b23a2c44be6def98d92d6a
subdir: src/android
submodules: true
sudo:
- apt-get update
- apt-get install -y ant make zip
androidupdate:
- no
scandelete:
- deps/libuv/docs/src/static/diagrams.key/Index.zip
- deps/openssl_src/cloudflare-quiche/*
- deps/openssl_src/fuzz/*
- deps/openssl_src/gost-engine/*
- deps/openssl_src/test/*
- deps/openssl_src/tlslite-ng/*
prebuild:
- sdkmanager "platforms;android-34" "build-tools;34.0.0"
build:
- mkdir bin/
- ANDROID_SDK=$$SDK$$ ANDROID_NDK=$$NDK$$ ANDROID_NDK_ROOT=$$NDK$$ make -C ../../ -j`nproc` fdroid
ndk: r26d
AutoUpdateMode: Version ^v[0-9\.]+$
UpdateCheckMode: Tags
CurrentVersion: 0.0.21-wip
CurrentVersionCode: 22

View File

@ -5,34 +5,11 @@ on: [push]
jobs:
Build-All:
runs-on: ubuntu-latest
container:
valid_volumes: ['/opt/keys']
volumes:
- /opt/keys:/opt/keys
steps:
- name: check out code
uses: actions/checkout@v4
with:
submodules: true
- run: ln -s /opt/keys .keys
- name: Setup JDK
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
packages: 'tools platform-tools build-tools;34.0.0 platforms;android-34 ndk;26.3.11579264'
- run: sudo apt update && sudo apt install -y doxygen graphviz mingw-w64 libgpgme11
- run: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all docs
- run: sudo apt update && sudo apt install -y doxygen mingw-w64
- run: make all -j`nproc` docs
- run: docker build .
- uses: actions/upload-artifact@v3
with:
path: out/TildeFriends-release.fdroid.apk
- uses: actions/upload-artifact@v3
with:
path: out/winrelease/tildefriends.exe
- uses: actions/upload-artifact@v3
with:
path: out/tildefriends-x86_64.AppImage

1
.gitignore vendored
View File

@ -4,7 +4,6 @@ db.*
deps/ios_toolchain/
deps/openssl/
dist/
.flatpak-builder
.keys
logs/
**/node_modules

10
.gitmodules vendored
View File

@ -22,10 +22,6 @@
[submodule "deps/openssl_src"]
path = deps/openssl_src
url = https://github.com/openssl/openssl.git
shallow = true
[submodule "deps/c-ares"]
path = deps/c-ares
url = https://github.com/c-ares/c-ares.git
[submodule "docs"]
path = docs
url = https://dev.tildefriends.net/cory/tildefriends.wiki.git
[submodule "deps/dht"]
path = deps/dht
url = https://github.com/jech/dht.git

659
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@ -3,27 +3,13 @@
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
## == Tilde Friends build. ==
##
## This is a list of all supported build targets.
##
## Consider passing -j$(nproc) or adding it to your $MAKEFLAGS to build in
## parallel (faster).
##
## Useful variables to override:
## CC := Compiler.
## AS := Assembler.
## LD := Linker.
## ANDROID_SDK := Path to the Android SDK.
VERSION_CODE := 25
VERSION_NUMBER := 0.0.22-wip
VERSION_NAME := This looks like a good place.
VERSION_CODE := 31
VERSION_NUMBER := 0.0.26-wip
VERSION_NAME := This program kills fascists.
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3470200.zip
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460000.zip
LIBUV_URL := https://dist.libuv.org/dist/v1.48.0/libuv-v1.48.0.tar.gz
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
APPIMAGETOOL_URL := https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool
PROJECT = tildefriends
BUILD_DIR ?= out
@ -35,9 +21,6 @@ BUNDLETOOL = out/bundletool.jar
HAVE_WIN := 0
export SOURCE_DATE_EPOCH=1
export TZ=UTC
ifeq ($(UNAME_S),Darwin)
BUILD_TYPES := macosdebug macosrelease iosdebug iosrelease iossimdebug iossimrelease
else ifeq ($(UNAME_S),Linux)
@ -50,8 +33,7 @@ BUILD_TYPES := debug release
CFLAGS += -Dstatic_assert=_Static_assert
LDFLAGS += \
-lbsd \
-lnetwork \
-Wno-stringop-overflow
-lnetwork
else ifeq ($(UNAME_S),OpenBSD)
BUILD_TYPES := debug release
CFLAGS += \
@ -70,23 +52,26 @@ CFLAGS += \
-Wall \
-Wextra \
-Wno-unused-parameter \
-Wno-unknown-warning-option \
-MMD \
-MP \
-ffunction-sections \
-fdata-sections \
-fno-exceptions \
-g
-g \
-flto
LDFLAGS += \
-Wno-attributes \
-Wno-aggressive-loop-optimizations \
-flto=auto
-flto=auto \
-Wno-attributes
ANDROID_MIN_SDK_VERSION := 24
ANDROID_TARGET_SDK_VERSION := 34
ANDROID_BUILD_TOOLS := $(ANDROID_SDK)/build-tools/34.0.0
ANDROID_PLATFORM := $(ANDROID_SDK)/platforms/android-$(ANDROID_TARGET_SDK_VERSION)
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/26.3.11579264
ifneq "$(wildcard $(ANDROID_SDK)/ndk/27.0.12077973/.)" ""
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/27.0.12077973
else
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/26.2.11394342
endif
ANDROID_ARMV7A_TARGETS := \
out/androiddebug-armv7a/tildefriends \
@ -176,9 +161,6 @@ NONANDROID_RELEASE_TARGETS := $(filter-out $(ANDROID_ARM64_TARGETS),$(RELEASE_TA
NONANDROID_TARGETS := $(filter-out $(ANDROID_TARGETS),$(ALL_TARGETS))
NONMACOS_TARGETS := $(filter-out $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS),$(ALL_TARGETS))
DEADSTRIP_TARGETS := $(filter-out $(ANDROID_TARGETS),$(NONMACOS_TARGETS))
ifneq ($(UNAME_S),OpenBSD)
$(NONMACOS_TARGETS): LDFLAGS += -static-libgcc
endif
$(NONANDROID_TARGETS): CFLAGS += -fno-omit-frame-pointer
$(filter-out $(WINDOWS_TARGETS),$(ALL_TARGETS)): LDFLAGS += -rdynamic
@ -188,13 +170,10 @@ $(ANDROID_TARGETS): CFLAGS += \
-fdebug-compilation-dir . \
-fomit-frame-pointer \
-fno-asynchronous-unwind-tables \
-funwind-tables \
-Wno-unknown-warning-option
-funwind-tables
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
$(RELEASE_TARGETS): CFLAGS += \
-DNDEBUG \
-flto
$(RELEASE_TARGETS): CFLAGS += -DNDEBUG
$(NONANDROID_RELEASE_TARGETS): CFLAGS += -O3
$(ANDROID_RELEASE_TARGETS): CFLAGS += -Oz
$(WINDOWS_TARGETS): CC = x86_64-w64-mingw32-gcc-win32
@ -238,15 +217,12 @@ $(ANDROID_X86_64_TARGETS): CFLAGS += -Ideps/openssl/android/x86_64/usr/local/inc
$(ANDROID_X86_64_TARGETS): LDFLAGS += -Ldeps/openssl/android/x86_64/usr/local/lib
$(NONMACOS_TARGETS): CFLAGS += -Wno-cast-function-type
$(DEADSTRIP_TARGETS): LDFLAGS += -Wl,--gc-sections
$(IOS_TARGETS): CFLAGS += -miphoneos-version-min=9.0 -Ideps/openssl/ios/ios64-xcrun/usr/local/include
$(IOS_TARGETS): LDFLAGS += -miphoneos-version-min=9.0 -Ldeps/openssl/ios/ios64-xcrun/usr/local/lib
$(IOS_TARGETS): CFLAGS += -mios-version-min=9.0 -Ideps/openssl/ios/ios64-xcrun/usr/local/include
$(IOS_TARGETS): LDFLAGS += -Ldeps/openssl/ios/ios64-xcrun/usr/local/lib
$(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include
$(IOSSIM_TARGETS): LDFLAGS += -Ldeps/openssl/ios/iossimulator-xcrun/usr/local/lib
ifeq ($(UNAME_M),x86_64)
ifeq ($(UNAME_S),Linux)
all: appimage
endif
ifneq ($(UNAME_S),Haiku)
out/debug/tildefriends: CFLAGS += -fsanitize=address -fsanitize=undefined -fno-common
out/debug/tildefriends: LDFLAGS += -fsanitize=address -fsanitize=undefined
@ -273,9 +249,8 @@ APP_SOURCES_ios := $(wildcard src/*.m)
APP_OBJS := $(call get_objs,APP_SOURCES)
$(APP_OBJS): CFLAGS += \
-Ideps/base64c/include \
-Ideps/c-ares/include \
-Ideps/c-ares_config \
-Ideps/crypt_blowfish \
-Ideps/dht \
-Ideps/libbacktrace \
-Ideps/libsodium \
-Ideps/libsodium/src/libsodium/include \
@ -293,108 +268,6 @@ $(filter-out $(BUILD_DIR)/android% $(BUILD_DIR)/macos% $(BUILD_DIR)/ios%,$(APP_O
-fanalyzer
endif
ARES_SOURCES := \
deps/c-ares/src/lib/ares_addrinfo2hostent.c \
deps/c-ares/src/lib/ares_addrinfo_localhost.c \
deps/c-ares/src/lib/ares_android.c \
deps/c-ares/src/lib/ares_cancel.c \
deps/c-ares/src/lib/ares_close_sockets.c \
deps/c-ares/src/lib/ares_conn.c \
deps/c-ares/src/lib/ares_cookie.c \
deps/c-ares/src/lib/ares_data.c \
deps/c-ares/src/lib/ares_destroy.c \
deps/c-ares/src/lib/ares_free_hostent.c \
deps/c-ares/src/lib/ares_free_string.c \
deps/c-ares/src/lib/ares_freeaddrinfo.c \
deps/c-ares/src/lib/ares_getaddrinfo.c \
deps/c-ares/src/lib/ares_getenv.c \
deps/c-ares/src/lib/ares_gethostbyaddr.c \
deps/c-ares/src/lib/ares_gethostbyname.c \
deps/c-ares/src/lib/ares_getnameinfo.c \
deps/c-ares/src/lib/ares_hosts_file.c \
deps/c-ares/src/lib/ares_init.c \
deps/c-ares/src/lib/ares_library_init.c \
deps/c-ares/src/lib/ares_metrics.c \
deps/c-ares/src/lib/ares_options.c \
deps/c-ares/src/lib/ares_parse_into_addrinfo.c \
deps/c-ares/src/lib/ares_process.c \
deps/c-ares/src/lib/ares_qcache.c \
deps/c-ares/src/lib/ares_query.c \
deps/c-ares/src/lib/ares_search.c \
deps/c-ares/src/lib/ares_send.c \
deps/c-ares/src/lib/ares_set_socket_functions.c \
deps/c-ares/src/lib/ares_socket.c \
deps/c-ares/src/lib/ares_sortaddrinfo.c \
deps/c-ares/src/lib/ares_strerror.c \
deps/c-ares/src/lib/ares_sysconfig.c \
deps/c-ares/src/lib/ares_sysconfig_files.c \
deps/c-ares/src/lib/ares_sysconfig_mac.c \
deps/c-ares/src/lib/ares_sysconfig_win.c \
deps/c-ares/src/lib/ares_update_servers.c \
deps/c-ares/src/lib/ares_version.c \
deps/c-ares/src/lib/dsa/ares_array.c \
deps/c-ares/src/lib/dsa/ares_htable.c \
deps/c-ares/src/lib/dsa/ares_htable_asvp.c \
deps/c-ares/src/lib/dsa/ares_htable_dict.c \
deps/c-ares/src/lib/dsa/ares_htable_strvp.c \
deps/c-ares/src/lib/dsa/ares_htable_szvp.c \
deps/c-ares/src/lib/dsa/ares_htable_vpvp.c \
deps/c-ares/src/lib/dsa/ares_llist.c \
deps/c-ares/src/lib/dsa/ares_slist.c \
deps/c-ares/src/lib/event/ares_event_configchg.c \
deps/c-ares/src/lib/event/ares_event_epoll.c \
deps/c-ares/src/lib/event/ares_event_kqueue.c \
deps/c-ares/src/lib/event/ares_event_poll.c \
deps/c-ares/src/lib/event/ares_event_select.c \
deps/c-ares/src/lib/event/ares_event_thread.c \
deps/c-ares/src/lib/event/ares_event_wake_pipe.c \
deps/c-ares/src/lib/event/ares_event_win32.c \
deps/c-ares/src/lib/inet_net_pton.c \
deps/c-ares/src/lib/inet_ntop.c \
deps/c-ares/src/lib/legacy/ares_create_query.c \
deps/c-ares/src/lib/legacy/ares_expand_name.c \
deps/c-ares/src/lib/legacy/ares_expand_string.c \
deps/c-ares/src/lib/legacy/ares_fds.c \
deps/c-ares/src/lib/legacy/ares_getsock.c \
deps/c-ares/src/lib/legacy/ares_parse_a_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_caa_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_mx_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_naptr_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_ns_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_ptr_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_soa_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_srv_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_txt_reply.c \
deps/c-ares/src/lib/legacy/ares_parse_uri_reply.c \
deps/c-ares/src/lib/record/ares_dns_mapping.c \
deps/c-ares/src/lib/record/ares_dns_multistring.c \
deps/c-ares/src/lib/record/ares_dns_name.c \
deps/c-ares/src/lib/record/ares_dns_parse.c \
deps/c-ares/src/lib/record/ares_dns_record.c \
deps/c-ares/src/lib/record/ares_dns_write.c \
deps/c-ares/src/lib/str/ares_buf.c \
deps/c-ares/src/lib/str/ares_str.c \
deps/c-ares/src/lib/str/ares_strsplit.c \
deps/c-ares/src/lib/util/ares_iface_ips.c \
deps/c-ares/src/lib/util/ares_math.c \
deps/c-ares/src/lib/util/ares_rand.c \
deps/c-ares/src/lib/util/ares_threads.c \
deps/c-ares/src/lib/util/ares_timeval.c \
deps/c-ares/src/lib/util/ares_uri.c \
deps/c-ares/src/lib/windows_port.c \
deps/c-ares/src/lib/ares_timeout.c
ARES_OBJS := $(call get_objs,ARES_SOURCES)
$(ARES_OBJS): CFLAGS += \
-Ideps/c-ares/include \
-Ideps/c-ares/src/lib \
-Ideps/c-ares/src/lib/include \
-Ideps/c-ares_config/ \
-D_GNU_SOURCE \
-Wno-unused-function \
-Wno-deprecated-declarations \
-Wno-unused-result
BLOWFISH_SOURCES := \
deps/crypt_blowfish/crypt_blowfish.c \
deps/crypt_blowfish/crypt_gensalt.c \
@ -522,17 +395,10 @@ $(UV_OBJS): CFLAGS += \
-Wno-incompatible-pointer-types \
-Wno-maybe-uninitialized \
-Wno-sign-compare \
-Wno-unknown-attributes \
-Wno-unused-but-set-parameter \
-Wno-unused-but-set-variable \
-Wno-unused-result \
-Wno-unused-variable \
-Wno-nonnull
$(UV_OBJS): CFLAGS += -fno-lto
$(filter out/win%,$(UV_OBJS)): \
CFLAGS += \
-Wno-cast-function-type \
-Wno-missing-braces
-Wno-unused-variable
ifeq ($(UNAME_S),Linux)
$(UV_OBJS): CFLAGS += \
-D_GNU_SOURCE
@ -722,6 +588,9 @@ $(MINIUNZIP_OBJS): CFLAGS += \
-Ideps/zlib \
-Wno-maybe-uninitialized
DHT_SOURCES := deps/dht/dht.c
DHT_OBJS := $(call get_objs,DHT_SOURCES)
LDFLAGS += \
-pthread \
-lm
@ -760,32 +629,15 @@ $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
-framework UIKit \
-framework WebKit
##
## Common targets:
##
debug: ## Build a debug executable for the current platform.
release: ## Build a release executable for the current platform.
all: $(BUILD_TYPES) ## Build all targets that appear possible to build on this machine.
unix: debug release ## Build all UNIX targets.
win: windebug winrelease ## Build all Windows targets.
unix: debug release
win: windebug winrelease
all: $(BUILD_TYPES)
.PHONY: all win unix
##
## Windows targets:
##
windebug: ## Build a debug win32 executable.
winrelease: ## Build a release win32 executable.
##
## MacOS targets:
##
macosdebug: ## Build a MacOS debug executable.
macosrelease: ## Build a MacOS release executable.
ALL_APP_OBJS := \
$(APP_OBJS) \
$(ARES_OBJS) \
$(BLOWFISH_OBJS) \
$(DHT_OBJS) \
$(LIBBACKTRACE_OBJS) \
$(MINIUNZIP_OBJS) \
$(PICOHTTPPARSER_OBJS) \
@ -837,18 +689,7 @@ src/android/AndroidManifest.xml : $(firstword $(MAKEFILE_LIST))
-e 's/android:targetSdkVersion="[[:digit:]]*"/android:targetSdkVersion="$(ANDROID_TARGET_SDK_VERSION)"/' \
$@
##
## Android targets:
##
androiddebug: ## Build a debug 64-bit ARM Android APK.
androidrelease: ## Build a release 64-bit ARM Android APK.
androiddebug-armv7a: ## Build a debug 32-bit ARM Android APK.
androidrelease-armv7a: ## Build a release 32-bit ARM Android APK.
androiddebug-x86: ## Build a debug x86 Android APK.
androidrelease-x86: ## Build a release x86 Android APK.
androiddebug-x86_64: ## Build a debug x86_64 Android APK.
androidrelease-x86_64: ## Build a release x86_64 Android APK.
# Android support.
out/res/layout_activity_main.xml.flat: src/android/res/layout/activity_main.xml
@mkdir -p $(dir $@)
@echo "[aapt2] $@"
@ -899,7 +740,7 @@ PACKAGE_DIRS := \
deps/prettier/ \
deps/lit/
RAW_FILES := $(sort $(filter-out apps/blog% apps/issues% apps/welcome% apps/journal% %.map, $(shell find $(PACKAGE_DIRS) -type f -not -name '.*')))
RAW_FILES := $(filter-out apps/blog% apps/issues% apps/welcome% apps/journal% %.map, $(shell find $(PACKAGE_DIRS) -type f))
out/apk/TildeFriends-arm-debug.unsigned.apk: BUILD_TYPE := debug
out/apk/TildeFriends-arm-release.unsigned.apk: BUILD_TYPE := release
@ -955,7 +796,7 @@ out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGET
@java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@
@jarsigner -keystore .keys/android.jks $@ androidKey -storepass android
aab: out/TildeFriends.aab ## Build an Android App Bundle.
aab: out/TildeFriends.aab
.PHONY: aab
out/TildeFriends.apks: out/TildeFriends.aab $(BUNDLETOOL)
@ -992,7 +833,6 @@ out/apk/TildeFriends-x86-%.unsigned.apk:
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
out/apk/TildeFriends-%.fdroid.unsigned.apk:
@rm -rf out/apk-fdroid-$(BUILD_TYPE) out/apk-fdroid-$(BUILD_TYPE)-raw
@mkdir -p $(dir $@) out/apk-fdroid-$(BUILD_TYPE)/lib/x86_64/ out/apk-fdroid-$(BUILD_TYPE)/lib/x86/ out/apk-fdroid-$(BUILD_TYPE)/lib/arm64-v8a/ out/apk-fdroid-$(BUILD_TYPE)/lib/armeabi-v7a/
@echo "[aapt] $@"
@cp out/android$(BUILD_TYPE)-x86_64/tildefriends out/apk-fdroid-$(BUILD_TYPE)/lib/x86_64/libtildefriends.so
@ -1005,12 +845,8 @@ out/apk/TildeFriends-%.fdroid.unsigned.apk:
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-fdroid-$(BUILD_TYPE)/lib/armeabi-v7a/libtildefriends.so
@cp out/apk/res.fdroid.apk $@.zip
@cp out/apk/classes.dex out/apk-fdroid-$(BUILD_TYPE)/classes.dex
@touch -d @0 out/apk-fdroid-$(BUILD_TYPE)/classes.dex out/apk-fdroid-$(BUILD_TYPE)/lib/*/libtildefriends.so
@chmod 755 out/apk-fdroid-$(BUILD_TYPE)/classes.dex out/apk-fdroid-$(BUILD_TYPE)/lib/*/libtildefriends.so
@cd out/apk-fdroid-$(BUILD_TYPE) && zip -X -u ../../$@.zip -q classes.dex lib/*/libtildefriends.so && cd ../../
@mkdir out/apk-fdroid-$(BUILD_TYPE)-raw
@for i in $(RAW_FILES); do mkdir -p $$(dirname out/apk-fdroid-$(BUILD_TYPE)-raw/$$i) && cp $$i out/apk-fdroid-$(BUILD_TYPE)-raw/$$i && touch -d @0 out/apk-fdroid-$(BUILD_TYPE)-raw/$$i && chmod 644 out/apk-fdroid-$(BUILD_TYPE)-raw/$$i; done
@cd out/apk-fdroid-$(BUILD_TYPE)-raw && zip -X -u ../../$@.zip -q $(RAW_FILES) && cd ../../
@cd out/apk-fdroid-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../
@zip -u $@.zip -q -9 $(RAW_FILES)
@$(ANDROID_BUILD_TOOLS)/zipalign -f 4 $@.zip $@
out/%.apk: out/apk/%.unsigned.apk
@ -1022,32 +858,20 @@ out/%.zopfli.apk: out/%.apk
$(ANDROID_BUILD_TOOLS)/zipalign -f -z 4 $< $@.zopfli
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ $@.zopfli
release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk ## Build an Android release APK.
release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk
.PHONY: release-apk
fdroid: out/apk/TildeFriends-release.fdroid.unsigned.apk ## Build Android APK for distribution on F-Droid.
.PHONY: fdroid
apkgo: out/TildeFriends-arm-debug.apk ## Build, install, and run a debug Android APK.
apkgo: out/TildeFriends-arm-debug.apk
@adb install -r $<
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
.PHONY: apkgo
releaseapkgo: out/TildeFriends-arm-release.apk ## Build, install, and run a release Android APK.
releaseapkgo: out/TildeFriends-arm-release.apk
@adb install -r $<
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
.PHONY: releaseapkgo
apklog: ## Display Android log output.
@adb logcat *:S tildefriends
.PHONY: apklog
##
## iPhoneOS targets:
##
iosdebug: ## Build a debug iPhoneOS executable.
iosrelease: ## Build a release iPhoneOS executable.
# iOS Support
out/%.app/Info.plist: src/ios/Info.plist
@mkdir -p $(dir $@)
@cp -v $< $@
@ -1061,7 +885,6 @@ out/data.zip: $(RAW_FILES)
out/tildefriends-%.app/tildefriends: out/%/tildefriends out/tildefriends-%.app/Info.plist out/tildefriends-%.app/tildefriends.png out/data.zip
@mkdir -p $(dir $@)
@cp -v $< $@
@cp -v out/data.zip $(@D)/
ifeq ($(HAVE_LINUX_IOS),1)
@zsign -q -k .keys/apple.p12 -f -m src/ios/embedded.mobileprovision $(realpath $(dir $@))
endif
@ -1084,23 +907,43 @@ out/%/tildefriends.standalone.exe: out/%/tildefriends.exe out/data.zip
@cat $< out/data.zip > $@
@chmod +x $@
iossimdebug-app: out/tildefriends-iossimdebug.app/tildefriends ## Build a debug iOS Simulator .app directory.
iossimrelease-app: out/tildefriends-iossimrelease.app/tildefriends ## Build a release iOS Simulator .app directory.
iosdebug-app: out/tildefriends-iosdebug.app/tildefriends ## Build a debug iOS .app directory.
iosrelease-app: out/tildefriends-iosrelease.app/tildefriends ## Build a release iOS .app directory.
iossimdebug-app: out/tildefriends-iossimdebug.app/tildefriends
iossimrelease-app: out/tildefriends-iossimrelease.app/tildefriends
iosdebug-app: out/tildefriends-iosdebug.app/tildefriends
iosrelease-app: out/tildefriends-iosrelease.app/tildefriends
iosdebug-ipa: out/tildefriends-debug.ipa ## Build a debug iOS .ipa.
iosrelease-ipa: out/tildefriends-release.ipa ## Build a release iOS .ipa.
iosdebug-ipa: out/tildefriends-debug.ipa
iosrelease-ipa: out/tildefriends-release.ipa
.PHONY: iossimdebug-app iossimrelease-app iosdebug-app iosrelease-app
ios%go: out/tildefriends-ios%.app/tildefriends
ideviceinstaller -i $(realpath $(dir $<))
iossimdebuggo: out/tildefriends-iossimdebug.app/tildefriends ## Build, install, and run an iOS debug build.
iossimdebuggo: out/tildefriends-iossimdebug.app/tildefriends
xcrun simctl install booted out/tildefriends-iossimdebug.app/
xcrun simctl launch booted com.unprompted.tildefriends
.PHONY: iossimdebuggo
apklog:
@adb logcat *:S tildefriends
.PHONY: apklog
fetchdeps:
@echo "[fetch] libuv"
@test -f out/deps/libuv.tar.gz && test "$$(cat out/deps/libuv.txt 2>/dev/null)" = $(LIBUV_URL) || (mkdir -p out/deps/ && curl -q $(LIBUV_URL) -o out/deps/libuv.tar.gz)
@test -d deps/libuv/ && test "$$(cat out/deps/libuv.txt 2>/dev/null)" = $(LIBUV_URL) || (rm -rf deps/libuv/ && mkdir -p deps/libuv/ && tar -C deps/libuv/ -m --strip=1 -xf out/deps/libuv.tar.gz)
@echo -n $(LIBUV_URL) > out/deps/libuv.txt
@echo "[fetch] sqlite"
@test -f out/deps/sqlite.zip && test "$$(cat out/deps/sqlite.txt 2>/dev/null)" = $(SQLITE_URL) || (mkdir -p out/deps/ && curl -q $(SQLITE_URL) -o out/deps/sqlite.zip)
@test -d deps/sqlite/ && test "$$(cat out/deps/sqlite.txt 2>/dev/null)" = $(SQLITE_URL) || (mkdir -p deps/sqlite/ && unzip -qDjo -d deps/sqlite/ out/deps/sqlite.zip)
@echo -n $(SQLITE_URL) > out/deps/sqlite.txt
@echo "[fetch] prettier"
@test -f deps/prettier/standalone.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/standalone.mjs
@test -f deps/prettier/html.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/plugins/html.mjs
@test -f deps/prettier/babel.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/plugins/babel.mjs
@test -f deps/prettier/estree.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/plugins/estree.mjs
.PHONY: fetchdeps
ANDROID_DEPS := deps/openssl/android/arm64-v8a/usr/local/lib/libssl.a
$(ANDROID_DEPS):
+@ANDROID_NDK_ROOT=$(ANDROID_NDK) tools/ssl-android
@ -1120,62 +963,14 @@ $(IOS_DEPS):
$(filter $(BUILD_DIR)/ios%,$(APP_OBJS)): | $(IOS_DEPS)
endif
##
## Linux package targets:
##
clean:
rm -rf $(BUILD_DIR)
.PHONY: clean
out/tildefriends-x86_64.AppImage: out/release/tildefriends out/data.zip
@echo "[appimage] $$@"
@rm -rf out/tildefriends.AppDir
@mkdir -p out/tildefriends.AppDir/usr/bin
@mkdir -p out/tildefriends.AppDir/usr/share/applications
@mkdir -p out/tildefriends.AppDir/usr/share/icons/hicolor/scalable/apps
@mkdir -p out/tildefriends.AppDir/usr/share/tildefriends
@echo $(APPIMAGETOOL_MD5) > out/appimagetool.md5
@test -x out/appimagetool || curl -q -L -o out/appimagetool $(APPIMAGETOOL_URL) && md5sum -c out/appimagetool.md5 && chmod +x out/appimagetool
@echo "[Desktop Entry]\nName=tildefriends\nExec=/usr/bin/tildefriends\nIcon=/usr/share/icons/hicolor/scalable/apps/tildefriends\nType=Application\nCategories=Network" > out/tildefriends.AppDir/tildefriends.desktop
@cp src/ios/tildefriends.svg out/tildefriends.AppDir/usr/share/icons/hicolor/scalable/apps/
@cp src/ios/tildefriends.svg out/tildefriends.AppDir/
@cp out/release/tildefriends out/tildefriends.AppDir/usr/bin/
@cp out/data.zip out/tildefriends.AppDir/usr/share/tildefriends/data.zip
@echo "#!/bin/sh\n\$${APPDIR}/usr/bin/tildefriends run -z \$$APPDIR/usr/share/tildefriends/data.zip" > out/tildefriends.AppDir/AppRun
@chmod +x out/tildefriends.AppDir/AppRun
@cd out; ./appimagetool --appimage-extract; cd ..
@cd out; unset SOURCE_DATE_EPOCH; PATH=$$PATH:squashfs-root/usr/bin ARCH=x86_64 squashfs-root/usr/bin/appimagetool -u 'zsync|https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage.zsync' tildefriends.AppDir tildefriends-x86_64.AppImage; cd ..
appimage: out/tildefriends-x86_64.AppImage ## Build an AppImage.
.PHONY: appimage
flatpak: out/ ## Build a flatpak.
flatpak-builder --force-clean --user --install-deps-from=flathub --install --repo=out/flatpak-repo out/flatpak src/com.unprompted.tildefriends.yml
flatpak build-bundle out/flatpak-repo out/tildefriends.flatpak com.unprompted.tildefriends
.PHONY: flatpak
##
## Targets for release management:
##
fetchdeps: ## Update various external sources that live in the tree that can't be pulled in as git submodules.
@echo "[fetch] sqlite"
@test -f out/deps/sqlite.zip && test "$$(cat out/deps/sqlite.txt 2>/dev/null)" = $(SQLITE_URL) || (mkdir -p out/deps/ && curl -q $(SQLITE_URL) -o out/deps/sqlite.zip)
@test -d deps/sqlite/ && test "$$(cat out/deps/sqlite.txt 2>/dev/null)" = $(SQLITE_URL) || (mkdir -p deps/sqlite/ && unzip -qDjo -d deps/sqlite/ out/deps/sqlite.zip)
@echo -n $(SQLITE_URL) > out/deps/sqlite.txt
@echo "[fetch] prettier"
@test -f deps/prettier/standalone.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/standalone.mjs
@test -f deps/prettier/html.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/plugins/html.mjs
@test -f deps/prettier/babel.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/plugins/babel.mjs
@test -f deps/prettier/estree.mjs || curl -q --create-dirs -O --output-dir deps/prettier/ https://cdn.jsdelivr.net/npm/prettier@3.2.5/plugins/estree.mjs
.PHONY: fetchdeps
shots: ## Copy generated screenshots from `tildefriends test -t=auto` into place in the metadata/ directory.
@echo [shots] $(wildcard out/screenshot*.png)
@cp -f out/screenshot*.png metadata/en-US/images/phoneScreenshots/
.PHONY: shots
tarball: ## Build an all-inclusive source tarball (.tar.xz).
@echo [archive] out/tildefriends-$(VERSION_NUMBER).tar.xz
dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefriends.standalone.exe)
@echo [archive] dist/tildefriends-$(VERSION_NUMBER).tar.xz
@rm -rf out/tildefriends-$(VERSION_NUMBER)
@mkdir -p out/tildefriends-$(VERSION_NUMBER)
@mkdir -p dist/ out/tildefriends-$(VERSION_NUMBER)
@git ls-files --recurse-submodules | tar -c -T- | tar -x -C out/tildefriends-$(VERSION_NUMBER)
@tar \
--exclude=apps/welcome* \
@ -1192,16 +987,9 @@ tarball: ## Build an all-inclusive source tarball (.tar.xz).
--exclude=deps/sqlite/shell.c \
--exclude=deps/zlib/contrib/vstudio \
--exclude=deps/zlib/doc \
-caf out/tildefriends-$(VERSION_NUMBER).tar.xz \
-caf dist/tildefriends-$(VERSION_NUMBER).tar.xz \
-C out/ \
tildefriends-$(VERSION_NUMBER)
.PHONY: tarball
dist: ## Build versions of all distributables for release.
dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefriends.standalone.exe) out/TildeFriends-release.fdroid.apk appimage tarball
@mkdir -p dist/
@echo "[cp] tildefriends-$(VERSION_NUMBER).tar.xz"
@cp out/tildefriends-$(VERSION_NUMBER).tar.xz dist/tildefriends-$(VERSION_NUMBER).tar.xz
@echo "[cp] TildeFriends-x86-$(VERSION_NUMBER).apk"
@cp out/TildeFriends-x86-release.zopfli.apk dist/TildeFriends-x86-$(VERSION_NUMBER).apk
@echo "[cp] TildeFriends-arm-$(VERSION_NUMBER).apk"
@ -1210,61 +998,27 @@ dist: release-apk iosrelease-ipa aab $(if $(HAVE_WIN), out/winrelease/tildefrien
@cp out/tildefriends-release.ipa dist/TildeFriends-$(VERSION_NUMBER).ipa
@test $(HAVE_WIN) && echo "[cp] tildefriends-$(VERSION_NUMBER).exe"
@test $(HAVE_WIN) && cp out/winrelease/tildefriends.standalone.exe dist/tildefriends-$(VERSION_NUMBER).exe
@echo "[cp] TildeFriends-$(VERSION_NUMBER).aab"
@cp out/TildeFriends.aab dist/TildeFriends-$(VERSION_NUMBER).aab
@echo "[cp] TildeFriends-$(VERSION_NUMBER).fdroid.apk"
@cp out/TildeFriends-release.fdroid.apk dist/TildeFriends-$(VERSION_NUMBER).fdroid.apk
@echo "[cp] TildeFriends-x86_64-$(VERSION_NUMBER).AppImage"
@cp out/tildefriends-x86_64.AppImage dist/TildeFriends-x86_64-$(VERSION_NUMBER).AppImage
.PHONY: dist
dist-test: dist ## Exercise some built distributable files, making sure they work as intended.
dist-test: dist
@tar -xf tildefriends-$(VERSION_NUMBER).tar.xz
@$(MAKE) -C tildefriends-$(VERSION_NUMBER)/ debug release
@docker build tildefriends-$(VERSION_NUMBER)/
@rm -rf tildefriends-$(VERSION_NUMBER)
.PHONY: dist-test
##
## Targets for tidying up:
##
format: ## Standardize formatting of C source.
format:
@clang-format -i $(wildcard src/*.c src/*.h src/*.m)
.PHONY: format
prettier: ## Standardize formatting of JavaScript and Markdown source.
prettier:
@npm run prettier
.PHONY: prettier
clean: ## Clean all generated files from the out/ directory.
rm -rf $(BUILD_DIR)
.PHONY: clean
##
## Documentation:
##
help: ## Display this help message.
@awk \
-F: \
-vG=$$(tput setaf 2) \
-vO=$$(tput setaf 3) \
-vB=$$(tput setaf 4) \
-vM=$$(tput setaf 5) \
-vC=$$(tput setaf 6) \
-vR=$$(tput sgr0) ' \
/^## ==.*==$$/ { sub(/^## ?/, ""); printf "%s%s%s\n", C, $$0, R } \
/^##.*:=.*/ { sub(/^## ?/, ""); sub(/:=/, ":"); printf " %s%-20s%s %s%s%s\n", M, $$1, R, O, $$2, R } \
/^##/ { sub(/^## ?/, ""); print $$0 } \
/^[[:alnum:]-]+:.*##/ { \
sub(/:.*##\s?/, ":"); \
printf " %s%-20s%s %s%s%s\n", G, $$1, R, O, $$2, R \
} \
' < $(filter-out %.d,$(MAKEFILE_LIST))
@echo "" # Blank line.
.PHONY: help
.DEFAULT_GOAL := help
docs: ## Build HTML docs.
docs:
@doxygen
.PHONY: docs
fdroid: out/apk/TildeFriends-release.fdroid.unsigned.apk
.PHONE: fdroid

View File

@ -14,53 +14,25 @@ Scuttlebutt, as well as a platform for writing and running web applications.
3. Make creating and sharing web applications accessible to anyone with a
browser.
## Getting the Source
Tilde Friends uses git submodules, so either:
```
git clone --recurse-submodules https://dev.tildefriends.net/cory/tildefriends.git
```
or:
```
git clone https://dev.tildefriends.net/cory/tildefriends.git
cd tildefriends
git submodule update --init --recursive
```
The `.tar.xz` source releases are all-inclusive.
## Building
Builds on Linux (x86_64 and aarch64), MacOS, OpenBSD, and Haiku. It's possible
to build for Android, iOS, and Windows on Linux, if you have the right
dependencies in the right places.
Builds on Linux (x86_64 and aarch64), MacOS, OpenBSD, and Haiku. Builds for
all of those host platforms plus mingw64, iOS, and android.
### Requirements
On Linux only, system OpenSSL libraries (`libssl-dev`, in debian-speak) are
assumed to be available.
On MacOS, Xcode's command-line tools are expected to be available.
### Build Commands
Run `make` with no arguments to see available build targets and options. `make
debug` is a good place to start.
To build in docker, `docker build .`.
`make format` and `make prettier` will normalize formatting to the coding
standard.
1. Requires openssl (`libssl-dev`, in debian-speak). All other dependencies
are kept up to date in the tree.
2. To build, run `make debug` or `make release`. An executable will be
generated in a subdirectory of `out/`.
3. It's possible to build for Android, iOS, and Windows on Linux, if you have
the right dependencies in the right places. `make windebug winrelease
iosdebug-ipa iosrelease-ipa release-apk`.
4. To build in docker, `docker build .`.
5. `make format` will normalize formatting to the coding standard.
## Running
By default, running the built `out/debug/tildefriends` executable will start a
web server at <http://localhost:12345/>. It expects to be run with the
repository root as the current working directory. `tildefriends -h` lists
further options.
By default, running the built `tildefriends` executable will start a web server
at <http://localhost:12345/>. `tildefriends -h` lists further options.
The first user to create an account and log in will be granted administrative
privileges. Further administration can be done at
@ -69,7 +41,7 @@ privileges. Further administration can be done at
## Documentation
Docs are a work in progress:
<https://dev.tildefriends.net/cory/tildefriends/wiki>.
<https://www.tildefriends.net/~cory/wiki/#test-wiki/tf-app-quick-reference>.
## License

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🎛",
"previous": "&R49FywYF8CXPhoSEydLbSCgvCddeyTiBwGuDU/gqY+M=.sha256"
"previous": "&vrpS/vE7n588iYv1p8HafDxHB+YDHTrtUbJiu9nGA9I=.sha256"
}

View File

@ -27,30 +27,23 @@ function global_settings_set(key, value) {
});
}
function title_case(name) {
return name
.split('_')
.map((x) => x.charAt(0).toUpperCase() + x.substring(1))
.join(' ');
}
window.addEventListener('load', function () {
const permission_template = (permission) => html` <code>${permission}</code>`;
function input_template(key, description) {
if (description.type === 'boolean') {
return html`
<li class="w3-row">
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold">${title_case(key)}</label>
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold">${key}</label>
<div class="w3-quarter w3-padding">${description.description}</div>
<div class="w3-quarter w3-padding w3-center"><input class="w3-check" type="checkbox" ?checked=${description.value} id=${'gs_' + key}></input></div>
<button class="w3-quarter w3-button w3-theme-action" @click=${(e) => global_settings_set(key, e.srcElement.previousElementSibling.firstChild.checked)}>Set</button>
<input class="w3-quarter w3-check" type="checkbox" ?checked=${description.value} id=${'gs_' + key}></input>
<button class="w3-quarter w3-button w3-theme-action" @click=${(e) => global_settings_set(key, e.srcElement.previousElementSibling.checked)}>Set</button>
</li>
`;
} else if (description.type === 'textarea') {
return html`
<li class="w3-row">
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold"
>${title_case(key)}</label
>${key}</label
>
<div class="w3-rest w3-padding">${description.description}</div>
<textarea
@ -75,7 +68,7 @@ ${description.value}</textarea
} else {
return html`
<li class="w3-row">
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold">${title_case(key)}</label>
<label class="w3-quarter" for=${'gs_' + key} style="font-weight: bold">${key}</label>
<div class="w3-quarter w3-padding">${description.description}</div>
<input class="w3-input w3-quarter" type="text" value="${description.value}" id=${'gs_' + key}></input>
<button class="w3-button w3-quarter w3-theme-action" @click=${(e) => global_settings_set(key, e.srcElement.previousElementSibling.value)}>Set</button>

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "📜",
"previous": "&BEf0nraBdHk/+PWqx6tOSu5rheWVaxaL7orAOz3285M=.sha256"
"previous": "&miGORZ8BwjHg2YO0t4bms6SI28XWPYqnqOZ8u9zsbZc=.sha256"
}

View File

@ -21,7 +21,7 @@ function* treeify(prefix, o) {
function markdown(md) {
let parsed = new commonmark.Parser().parse(md ?? '*undocumented*');
return new commonmark.HtmlRenderer({safe: true}).render(parsed);
return new commonmark.HtmlRenderer().render(parsed);
}
function document(api) {

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🪵",
"previous": "&3jabNEk6W2uolzTvfXX6fcWF50N3501vtgZ6ZxFVJ1s=.sha256"
"previous": "&TIrBnpN3iz3O9L9MCCteAcVJZjA83EKdcfu4SCM76VE=.sha256"
}

View File

@ -52,8 +52,8 @@ export async function get_blog_message(id) {
}
export function markdown(md) {
let reader = new commonmark.Parser();
let writer = new commonmark.HtmlRenderer({safe: true});
let reader = new commonmark.Parser({safe: true});
let writer = new commonmark.HtmlRenderer();
let parsed = reader.parse(md || '');
let walker = parsed.walker();
let event, node;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,4 @@
{
"type": "tildefriends-app",
"emoji": "💽",
"previous": "&uQzkIe/Aj8yNhLKe3hEq+5fEJsGwIUx8NVBjJKwoV2U=.sha256"
"emoji": "💽"
}

View File

@ -51,19 +51,6 @@ async function key_list(db) {
app.setDocument(doc);
}
function load() {
if (core.user?.credentials?.session) {
database_list();
} else {
app.setDocument(`<!DOCTYPE html>
<html>
<body style="background: #888">
<h1>Must be signed in to examine databases.</h1>
</body>
</html>`);
}
}
core.register('message', async function (message) {
if (message.event == 'hashChange') {
let hash = message.hash.substring(1);
@ -75,9 +62,9 @@ core.register('message', async function (message) {
} else if (hash.length) {
key_list(await database(hash.split(':').slice(1).join(':')));
} else {
load();
database_list();
}
}
});
load();
database_list();

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🪪",
"previous": "&5kw/2PgcySwOYCmAkjHTR2xTkIx3i7UjQmtQ8MfgWw8=.sha256"
"previous": "&de7q4A59auHP/34bXgeNH05JZoxsGr5TjwXPvehWH30=.sha256"
}

View File

@ -1,7 +1,5 @@
import * as tfrpc from '/tfrpc.js';
const is_admin = core.user?.credentials?.permissions?.administration;
tfrpc.register(async function get_private_key(id) {
return bip39Words(await ssb.getPrivateKey(id));
});
@ -17,13 +15,9 @@ tfrpc.register(async function delete_id(id) {
tfrpc.register(async function reload() {
await main();
});
tfrpc.register(async function make_server(id) {
return await ssb.swapWithServerIdentity(id);
});
async function main() {
let ids = await ssb.getIdentities();
let server_id = await ssb.getServerIdentity();
await app.setDocument(
`
<head>
@ -104,16 +98,6 @@ async function main() {
alert('Error deleting ID: ' + e);
}
}
handler.make_server = async function make_server(event) {
let id = event.srcElement.dataset.id;
try {
if (confirm('Are you sure you want to make "' + id + '" the server identity?\\n\\nFor it to take effect, you will need to both sign in again and restart Tilde Friends.')) {
await tfrpc.rpc.make_server(id);
}
} catch (e) {
alert('Error making server ID: ' + e);
}
}
</script>
<header class="w3-theme w3-padding"><h1>SSB Identity Management</h1></header>
<div class="w3-card-4 w3-margin">
@ -132,15 +116,14 @@ async function main() {
<div class="w3-card-4 w3-margin">
<header class="w3-container w3-theme-l2"><h2>Identities</h2></header>
<ul class="w3-ul">` +
(ids ?? [])
ids
.map(
(
id
) => `<li style="overflow: hidden; text-wrap: nowrap; text-overflow: ellipsis">
<button onclick="handler.export_id(event)" data-id="${id}" class="w3-button w3-theme">Export Identity</button>
<button onclick="handler.delete_id(event)" data-id="${id}" class="w3-button w3-theme">Delete Identity</button>
${is_admin && id != server_id ? `<button onclick="handler.make_server(event)" data-id="${id}" class="w3-button w3-theme">Make Server Identity</button>` : ''}
${id}${id == server_id ? ' <div class="w3-tag w3-theme-l4 w3-round">🖥 local server</div>' : ''}
${id}
</li>`
)
.join('\n') +

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🦟",
"previous": "&O0huuEgL/UQC9bkUfhPOyZFo9eRiz+koOkba6QwCGNA=.sha256"
"previous": "&cUqvSDUls3jn0haD85LPFAGdkc8wFuy347TtATNcJgg=.sha256"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,5 @@
import * as linkify from './commonmark-linkify.js';
var reUnsafeProtocol = /^javascript:|vbscript:|file:|data:/i;
var reSafeDataProtocol = /^data:image\/(?:png|gif|jpeg|webp)/i;
var potentiallyUnsafe = function (url) {
return reUnsafeProtocol.test(url) && !reSafeDataProtocol.test(url);
};
function image(node, entering) {
if (
node.firstChild?.type === 'text' &&
@ -67,8 +61,8 @@ function image(node, entering) {
}
export function markdown(md) {
var reader = new commonmark.Parser();
var writer = new commonmark.HtmlRenderer({safe: true});
var reader = new commonmark.Parser({safe: true});
var writer = new commonmark.HtmlRenderer();
writer.image = image;
var parsed = reader.parse(md || '');
parsed = linkify.transform(parsed);

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "📝",
"previous": "&5LpOTEnor/rYFk3axyfmmehAoq9aEwNQRH4jwNhRQ7o=.sha256"
"previous": "&b//KqE4Vx6kOSBRODK1p/8wjOLKZJ+CBB5IkaBt5YsM=.sha256"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -18,8 +18,8 @@ class TfJournalEntryElement extends LitElement {
}
markdown(md) {
var reader = new commonmark.Parser();
var writer = new commonmark.HtmlRenderer({safe: true});
var reader = new commonmark.Parser({safe: true});
var writer = new commonmark.HtmlRenderer();
var parsed = reader.parse(md || '');
return writer.render(parsed);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🐌",
"previous": "&0gBRfD+3EaZD2S82zAnXT3hgGuNTnUncOh5vGwZwbSw=.sha256"
"previous": "&2xK//SIpjFb0+uT5I7MSAGJ3d1FKuI/rlzhcCQd3NME=.sha256"
}

View File

@ -103,9 +103,6 @@ tfrpc.register(async function encrypt(id, recipients, content) {
tfrpc.register(async function getActiveIdentity() {
return await ssb.getActiveIdentity();
});
tfrpc.register(async function sync() {
return await ssb.sync();
});
core.register('onBroadcastsChanged', async function () {
await tfrpc.rpc.set('broadcasts', await ssb.getBroadcasts());
});

View File

@ -7,7 +7,7 @@ function textNode(text) {
function linkNode(text, link) {
const linkNode = new commonmark.Node('link', undefined);
if (link.startsWith('#')) {
linkNode.destination = `#${encodeURIComponent('#' + link)}`;
linkNode.destination = `#q=${encodeURIComponent(link)}`;
} else {
linkNode.destination = link;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8,16 +8,10 @@ import * as tf_compose from './tf-compose.js';
import * as tf_news from './tf-news.js';
import * as tf_profile from './tf-profile.js';
import * as tf_reactions_modal from './tf-reactions-modal.js';
import * as tf_tab_mentions from './tf-tab-mentions.js';
import * as tf_tab_news from './tf-tab-news.js';
import * as tf_tab_news_feed from './tf-tab-news-feed.js';
import * as tf_tab_search from './tf-tab-search.js';
import * as tf_tab_connections from './tf-tab-connections.js';
import * as tf_tab_query from './tf-tab-query.js';
import * as tf_tag from './tf-tag.js';
import * as tf_styles from './tf-styles.js';
window.addEventListener('load', function () {
let style = document.createElement('style');
style.innerText = tf_styles.styles;
document.body.appendChild(style);
});

View File

@ -16,9 +16,7 @@ class TfElement extends LitElement {
following: {type: Array},
users: {type: Object},
ids: {type: Array},
channels: {type: Array},
channels_unread: {type: Object},
channels_latest: {type: Object},
tags: {type: Array},
};
}
@ -35,9 +33,7 @@ class TfElement extends LitElement {
this.following = [];
this.users = {};
this.loaded = false;
this.channels = [];
this.channels_unread = {};
this.channels_latest = {};
this.tags = [];
tfrpc.rpc.getBroadcasts().then((b) => {
self.broadcasts = b || [];
});
@ -68,76 +64,16 @@ class TfElement extends LitElement {
let ids = (await tfrpc.rpc.getIdentities()) || [];
this.whoami = whoami ?? (ids.length ? ids[0] : undefined);
this.ids = ids;
await this.load_channels();
}
async load_channels() {
let channels = await tfrpc.rpc.query(
`
SELECT
content ->> 'channel' AS channel,
content ->> 'subscribed' AS subscribed
FROM
messages
WHERE
author = ? AND
content ->> 'type' = 'channel'
ORDER BY sequence
`,
[this.whoami]
);
let channel_map = {};
for (let row of channels) {
if (row.subscribed) {
channel_map[row.channel] = true;
} else {
delete channel_map[row.channel];
}
}
this.channels = Object.keys(channel_map).sort();
}
connectedCallback() {
super.connectedCallback();
this._keydown = this.keydown.bind(this);
window.addEventListener('keydown', this._keydown);
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener('keydown', this._keydown);
}
keydown(event) {
if (event.altKey && event.key == 'ArrowUp') {
this.next_channel(1);
event.preventDefault();
} else if (event.altKey && event.key == 'ArrowDown') {
this.next_channel(-1);
event.preventDefault();
}
}
next_channel(delta) {
let channel_names = ['', '@'].concat(this.channels);
let index = channel_names.indexOf(this.hash.substring(1));
if (index != -1) {
index += delta;
this.set_hash(
'#' +
encodeURIComponent(
channel_names[(index + channel_names.length) % channel_names.length]
)
);
}
}
set_hash(hash) {
this.hash = decodeURIComponent(hash || '#');
this.hash = hash || '#';
if (this.hash.startsWith('#q=')) {
this.tab = 'search';
} else if (this.hash === '#connections') {
this.tab = 'connections';
} else if (this.hash === '#mentions') {
this.tab = 'mentions';
} else if (this.hash.startsWith('#sql=')) {
this.tab = 'query';
} else {
@ -231,14 +167,6 @@ class TfElement extends LitElement {
`,
[JSON.stringify(this.following), id]
);
for (let message of messages) {
if (message.author == this.whoami) {
let content = JSON.parse(message.content);
if (content?.type == 'channel') {
this.load_channels();
}
}
}
if (messages && messages.length) {
this.unread = [...this.unread, ...messages];
this.unread = this.unread.slice(this.unread.length - 1024);
@ -267,36 +195,32 @@ class TfElement extends LitElement {
}
}
async get_latest_private(following) {
let latest = (await tfrpc.rpc.query('SELECT MAX(rowid) AS latest FROM messages'))[0].latest;
const k_chunk_count = 256;
while (latest - k_chunk_count >= 0) {
let messages = await tfrpc.rpc.query(`
SELECT messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
FROM messages
JOIN json_each(?1) AS following ON messages.author = following.value
WHERE
messages.rowid > ?2 AND
messages.rowid <= ?3 AND
json(messages.content) LIKE '"%'
ORDER BY sequence DESC
async load_recent_tags() {
let start = new Date();
this.tags = await tfrpc.rpc.query(
`
WITH
recent AS (SELECT id, json(content) AS content FROM messages
WHERE messages.timestamp > ? AND json_extract(content, '$.type') = 'post'
ORDER BY timestamp DESC LIMIT 1024),
recent_channels AS (SELECT recent.id, '#' || json_extract(content, '$.channel') AS tag
FROM recent
WHERE json_extract(content, '$.channel') IS NOT NULL),
recent_mentions AS (SELECT recent.id, json_extract(mention.value, '$.link') AS tag
FROM recent, json_each(recent.content, '$.mentions') AS mention
WHERE json_valid(mention.value) AND tag LIKE '#%'),
combined AS (SELECT id, tag FROM recent_channels UNION ALL SELECT id, tag FROM recent_mentions),
by_message AS (SELECT DISTINCT id, tag FROM combined)
SELECT tag, COUNT(*) AS count FROM by_message GROUP BY tag ORDER BY count DESC LIMIT 10
`,
[
JSON.stringify(following),
latest - k_chunk_count,
latest,
]);
messages = (await this.decrypt(messages)).filter(x => x.decrypted);
if (messages.length) {
return Math.max(...messages.map(x => x.rowid));
}
latest -= k_chunk_count;
};
return -1;
[new Date() - 7 * 24 * 60 * 60 * 1000]
);
console.log('tags took', (new Date() - start) / 1000.0, 'seconds');
}
async load() {
let whoami = this.whoami;
let tags = this.load_recent_tags();
let following = await tfrpc.rpc.following([whoami], 2);
let users = {};
let by_count = [];
@ -309,31 +233,7 @@ class TfElement extends LitElement {
};
by_count.push({count: v.of, id: id});
}
let channels = tfrpc.rpc.query(
`
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
JOIN json_each(?1) AS channels ON messages.content ->> 'channel' = channels.value
JOIN json_each(?2) AS following ON messages.author = following.value
WHERE messages.content ->> 'type' = 'post' AND messages.content ->> 'root' IS NULL
GROUP by channel
UNION
SELECT '' AS channel, MAX(messages.rowid) AS rowid FROM messages
JOIN json_each(?2) AS following ON messages.author = following.value
UNION
SELECT '@' AS channel, MAX(messages.rowid) AS rowid FROM messages_fts(?3)
JOIN messages ON messages.rowid = messages_fts.rowid
JOIN json_each(?2) AS following ON messages.author = following.value
`,
[
JSON.stringify(this.channels),
JSON.stringify(Object.keys(following)),
'"' + this.whoami.replace('"', '""') + '"',
]
);
let latest_private = this.get_latest_private(Object.keys(following));
this.channels_unread = JSON.parse(
(await tfrpc.rpc.databaseGet('unread')) ?? '{}'
);
console.log(by_count.sort((x, y) => y.count - x.count).slice(0, 20));
let start_time = new Date();
users = await this.fetch_about(Object.keys(following).sort(), users);
console.log(
@ -343,54 +243,14 @@ class TfElement extends LitElement {
Object.keys(users).length,
'users'
);
start_time = new Date();
channels = await channels;
console.log('channels took', (new Date() - start_time) / 1000.0);
this.channels_latest = Object.fromEntries(
channels.map((x) => [x.channel, x.rowid])
);
let self = this;
latest_private.then(function(latest) {
self.channels_latest = Object.assign({}, self.channels_latest, {'🔐': latest});
console.log('private took', (new Date() - start_time) / 1000.0);
});
this.following = Object.keys(following);
this.users = users;
await tags;
console.log(`load finished ${whoami} => ${this.whoami}`);
this.whoami = whoami;
this.loaded = whoami;
}
channel_set_unread(event) {
this.channels_unread[event.detail.channel ?? ''] = event.detail.unread;
this.channels_unread = Object.assign({}, this.channels_unread);
tfrpc.rpc.databaseSet('unread', JSON.stringify(this.channels_unread));
}
async decrypt(messages) {
let whoami = this.whoami;
return Promise.all(messages.map(async function (message) {
let content;
try {
content = JSON.parse(message?.content);
} catch {}
if (typeof content === 'string') {
let decrypted;
try {
decrypted = await tfrpc.rpc.try_decrypt(whoami, content);
} catch {}
if (decrypted) {
try {
message.decrypted = JSON.parse(decrypted);
} catch {
message.decrypted = decrypted;
}
}
}
return message;
}));
}
render_tab() {
let following = this.following;
let users = this.users;
@ -405,10 +265,6 @@ class TfElement extends LitElement {
.unread=${this.unread}
@refresh=${() => (this.unread = [])}
?loading=${this.loading}
.channels=${this.channels}
.channels_latest=${this.channels_latest}
.channels_unread=${this.channels_unread}
@channelsetunread=${this.channel_set_unread}
></tf-tab-news>
`;
} else if (this.tab === 'connections') {
@ -419,6 +275,14 @@ class TfElement extends LitElement {
.broadcasts=${this.broadcasts}
></tf-tab-connections>
`;
} else if (this.tab === 'mentions') {
return html`
<tf-tab-mentions
.following=${this.following}
whoami=${this.whoami}
.users="${this.users}}"
></tf-tab-mentions>
`;
} else if (this.tab === 'search') {
return html`
<tf-tab-search
@ -450,15 +314,13 @@ class TfElement extends LitElement {
await tfrpc.rpc.setHash('#');
} else if (tab === 'connections') {
await tfrpc.rpc.setHash('#connections');
} else if (tab === 'mentions') {
await tfrpc.rpc.setHash('#mentions');
} else if (tab === 'query') {
await tfrpc.rpc.setHash('#sql=');
}
}
refresh() {
tfrpc.rpc.sync();
}
render() {
let self = this;
@ -472,21 +334,13 @@ class TfElement extends LitElement {
const k_tabs = {
'📰': 'news',
'📡': 'connections',
'@': 'mentions',
'🔍': 'search',
'👩‍💻': 'query',
};
let tabs = html`
<div
class="w3-bar w3-theme-l1"
style="position: sticky; top: 0; z-index: 10"
>
<button
class="w3-bar-item w3-button w3-circle w3-ripple"
@click=${this.refresh}
>
</button>
<div class="w3-bar w3-theme-l1">
${Object.entries(k_tabs).map(
([k, v]) => html`
<button
@ -520,7 +374,13 @@ class TfElement extends LitElement {
style="width: 100vw; min-height: 100vh; height: 100%"
class="w3-theme-dark"
>
${tabs} ${contents}
${tabs}
<div style="padding: 8px">
${this.tags.map(
(x) => html`<tf-tag tag=${x.tag} count=${x.count}></tf-tag>`
)}
${contents}
</div>
</div>
`;
}

View File

@ -14,7 +14,6 @@ class TfComposeElement extends LitElement {
apps: {type: Object},
drafts: {type: Object},
author: {type: String},
channel: {type: String},
};
}
@ -181,13 +180,6 @@ class TfComposeElement extends LitElement {
break;
}
}
event.preventDefault();
document.execCommand(
'insertText',
false,
event.clipboardData.getData('text/plain')
);
}
async submit() {
@ -197,7 +189,6 @@ class TfComposeElement extends LitElement {
let message = {
type: 'post',
text: edit.innerText,
channel: this.channel,
};
if (this.root || this.branch) {
message.root = this.root;
@ -537,9 +528,6 @@ class TfComposeElement extends LitElement {
class="w3-card-4 w3-theme-d4 w3-padding-small"
style="box-sizing: border-box"
>
${this.channel !== undefined
? html`<p>To #${this.channel}:</p>`
: undefined}
${this.render_encrypt()}
<div class="w3-container w3-padding-small">
<div class="w3-half">

View File

@ -14,8 +14,6 @@ class TfMessageElement extends LitElement {
format: {type: String},
blog_data: {type: String},
expanded: {type: Object},
channel: {type: String},
channel_unread: {type: Number},
};
}
@ -30,7 +28,6 @@ class TfMessageElement extends LitElement {
this.drafts = {};
this.format = 'message';
this.expanded = {};
this.channel_unread = -1;
}
show_reply() {
@ -76,23 +73,18 @@ class TfMessageElement extends LitElement {
}
}
if (this.message?.votes?.length) {
return html` <div class="w3-container">
<div
class="w3-button w3-bar w3-padding-small"
@click=${this.show_reactions}
>
return html`<div class="w3-button" @click=${this.show_reactions}>
${(this.message.votes || []).map(
(vote) => html`
<span
class="w3-bar-item w3-padding-small"
title="${this.users[vote.author]?.name ??
vote.author} ${new Date(vote.timestamp)}"
title="${this.users[vote.author]?.name ?? vote.author} ${new Date(
vote.timestamp
)}"
>
${normalize_expression(vote.content.vote.expression)}
</span>
`
)}
</div>
</div>`;
}
}
@ -231,7 +223,7 @@ class TfMessageElement extends LitElement {
>${mention.name}</a
>`;
} else if (mention.link?.startsWith('#')) {
return html` <a href=${'#' + encodeURIComponent('#' + mention.link)}
return html` <a href=${'#q=' + encodeURIComponent(mention.link)}
>${mention.link}</a
>`;
} else if (
@ -315,27 +307,12 @@ ${JSON.stringify(mention, null, 2)}</pre
.users=${this.users}
.drafts=${this.drafts}
.expanded=${this.expanded}
channel=${this.channel}
channel_unread=${this.channel_unread}
></tf-message>`
)}`;
}
}
}
mark_unread() {
this.dispatchEvent(
new CustomEvent('channelsetunread', {
bubbles: true,
composed: true,
detail: {
channel: this.channel,
unread: this.message.rowid,
},
})
);
}
render_channels() {
let content = this.message?.content;
if (this?.messsage?.decrypted?.type == 'post') {
@ -362,8 +339,6 @@ ${JSON.stringify(mention, null, 2)}</pre
}
let class_background = this.message?.decrypted
? 'w3-pale-red'
: this.message?.rowid >= this.channel_unread
? 'w3-theme-d2'
: 'w3-theme-d4';
let self = this;
let raw_button;
@ -428,10 +403,9 @@ ${JSON.stringify(mention, null, 2)}</pre
>
<tf-user id=${self.message.author} .users=${self.users}></tf-user>
<span style="padding-right: 8px"
><a tfarget="_top" href=${'#' + encodeURIComponent(self.message.id)}
>%</a
>
${new Date(self.message.timestamp).toLocaleString()}</span
><a tfarget="_top" href=${'#' + self.message.id}>%</a> ${new Date(
self.message.timestamp
).toLocaleString()}</span
>
${raw_button} ${self.format == 'raw' ? self.render_raw() : inner}
${self.render_votes()}
@ -443,8 +417,6 @@ ${JSON.stringify(mention, null, 2)}</pre
.users=${self.users}
.drafts=${self.drafts}
.expanded=${self.expanded}
channel=${self.channel}
channel_unread=${self.channel_unread}
></tf-message>
`
)}
@ -464,8 +436,6 @@ ${JSON.stringify(mention, null, 2)}</pre
.users=${this.users}
.drafts=${this.drafts}
.expanded=${this.expanded}
channel=${this.channel}
channel_unread=${this.channel_unread}
></tf-message>`
)}
</div>`;
@ -474,9 +444,7 @@ ${JSON.stringify(mention, null, 2)}</pre
class="w3-card-4 w3-theme-d4 w3-border-theme"
style="margin-top: 8px; padding: 16px; overflow-wrap: anywhere"
>
<a target="_top" href=${'#' + encodeURIComponent(this.message.id)}
>${this.message.id}</a
>
<a target="_top" href=${'#' + this.message.id}>${this.message.id}</a>
(placeholder)
<div>${this.render_votes()}</div>
${(this.message.child_messages || []).map(
@ -487,8 +455,6 @@ ${JSON.stringify(mention, null, 2)}</pre
.users=${this.users}
.drafts=${this.drafts}
.expanded=${this.expanded}
channel=${this.channel}
channel_unread=${this.channel_unread}
></tf-message>
`
)}
@ -629,11 +595,7 @@ ${JSON.stringify(content, null, 2)}</pre
${is_encrypted}
<span style="flex: 1"></span>
<span style="padding-right: 8px"
><a
target="_top"
href=${'#' + encodeURIComponent(self.message.id)}
>%</a
>
><a target="_top" href=${'#' + self.message.id}>%</a>
${new Date(this.message.timestamp).toLocaleString()}</span
>
<span>${raw_button}</span>
@ -644,16 +606,6 @@ ${JSON.stringify(content, null, 2)}</pre
<button class="w3-button w3-theme-d1" @click=${this.react}>
React
</button>
${!content.root && this.message.rowid < this.channel_unread
? html`
<button
class="w3-button w3-theme-d1"
@click=${this.mark_unread}
>
Mark Unread
</button>
`
: undefined}
</p>
${this.render_children()}
</div>
@ -686,11 +638,7 @@ ${JSON.stringify(content, null, 2)}</pre
${is_encrypted}
<span style="flex: 1"></span>
<span style="padding-right: 8px"
><a
target="_top"
href=${'#' + encodeURIComponent(self.message.id)}
>%</a
>
><a target="_top" href=${'#' + self.message.id}>%</a>
${new Date(this.message.timestamp).toLocaleString()}</span
>
<span>${raw_button}</span>
@ -780,11 +728,7 @@ ${JSON.stringify(content, null, 2)}</pre
<tf-user id=${this.message.author} .users=${this.users}></tf-user>
<span style="flex: 1"></span>
<span style="padding-right: 8px"
><a
target="_top"
href=${'#' + encodeURIComponent(self.message.id)}
>%</a
>
><a target="_top" href=${'#' + self.message.id}>%</a>
${new Date(this.message.timestamp).toLocaleString()}</span
>
<span>${raw_button}</span>
@ -823,7 +767,7 @@ ${JSON.stringify(content, null, 2)}</pre
return small_frame(html`
<div>
${content.subscribed ? 'subscribed to' : 'unsubscribed from'}
<a href=${'#' + encodeURIComponent('#' + content.channel)}
<a href=${'#q=' + encodeURIComponent('#' + content.channel)}
>#${content.channel}</a
>
</div>

View File

@ -11,8 +11,6 @@ class TfNewsElement extends LitElement {
following: {type: Array},
drafts: {type: Object},
expanded: {type: Object},
channel: {type: String},
channel_unread: {type: Number},
};
}
@ -27,7 +25,6 @@ class TfNewsElement extends LitElement {
this.following = [];
this.drafts = {};
this.expanded = {};
this.channel_unread = -1;
}
process_messages(messages) {
@ -36,13 +33,12 @@ class TfNewsElement extends LitElement {
console.log('processing', messages.length, 'messages');
function ensure_message(id, rowid) {
function ensure_message(id) {
let found = messages_by_id[id];
if (found) {
return found;
} else {
let added = {
rowid: rowid,
id: id,
placeholder: true,
content: '"placeholder"',
@ -57,7 +53,7 @@ class TfNewsElement extends LitElement {
function link_message(message) {
if (message.content.type === 'vote') {
let parent = ensure_message(message.content.vote.link, message.rowid);
let parent = ensure_message(message.content.vote.link);
if (!parent.votes) {
parent.votes = [];
}
@ -66,14 +62,14 @@ class TfNewsElement extends LitElement {
} else if (message.content.type == 'post') {
if (message.content.root) {
if (typeof message.content.root === 'string') {
let m = ensure_message(message.content.root, message.rowid);
let m = ensure_message(message.content.root);
if (!m.child_messages) {
m.child_messages = [];
}
m.child_messages.push(message);
message.parent_message = message.content.root;
} else {
let m = ensure_message(message.content.root[0], message.rowid);
let m = ensure_message(message.content.root[0]);
if (!m.child_messages) {
m.child_messages = [];
}
@ -166,7 +162,6 @@ class TfNewsElement extends LitElement {
} else {
if (group.length > 0) {
result.push({
rowid: Math.max(...group.map((x) => x.rowid)),
type: 'contact_group',
messages: group,
});
@ -175,13 +170,6 @@ class TfNewsElement extends LitElement {
result.push(message);
}
}
if (group.length > 0) {
result.push({
rowid: Math.max(...group.map((x) => x.rowid)),
type: 'contact_group',
messages: group,
});
}
return result;
}
@ -190,39 +178,18 @@ class TfNewsElement extends LitElement {
let final_messages = this.group_following(
this.finalize_messages(messages_by_id)
);
let unread_rowid = -1;
for (let message of final_messages) {
if (message.rowid >= this.channel_unread) {
unread_rowid = message.rowid;
}
}
return html`
<div>
<div style="display: flex; flex-direction: column">
${final_messages.map(
(x) =>
html`
<tf-message
html`<tf-message
.message=${x}
whoami=${this.whoami}
.users=${this.users}
.drafts=${this.drafts}
.expanded=${this.expanded}
collapsed="true"
channel=${this.channel}
channel_unread=${this.channel_unread}
></tf-message>
${x.rowid == unread_rowid && x != final_messages[0]
? html`<div style="display: flex; flex-direction: row">
<div
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
></div>
<div style="color: #f00; padding: 8px">unread</div>
<div
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
></div>
</div>`
: undefined}
`
></tf-message>`
)}
</div>
`;

View File

@ -188,10 +188,6 @@ class TfProfileElement extends LitElement {
}
}
copy_id() {
navigator.clipboard.writeText(this.id);
}
render() {
if (
this.id == this.whoami &&
@ -233,11 +229,7 @@ class TfProfileElement extends LitElement {
</button>`;
}
edit = html`
<button
id="save_profile"
class="w3-button w3-theme-d1"
@click=${this.save_edits}
>
<button class="w3-button w3-theme-d1" @click=${this.save_edits}>
Save Profile
</button>
<button class="w3-button w3-theme-d1" @click=${this.discard_edits}>
@ -246,11 +238,7 @@ class TfProfileElement extends LitElement {
${server_follow}
`;
} else {
edit = html`<button
id="edit_profile"
class="w3-button w3-theme-d1"
@click=${this.edit}
>
edit = html`<button class="w3-button w3-theme-d1" @click=${this.edit}>
Edit Profile
</button>`;
}
@ -297,10 +285,8 @@ class TfProfileElement extends LitElement {
typeof profile.image == 'string' ? profile.image : profile.image?.link;
image = this.editing?.image ?? image;
let description = this.editing?.description ?? profile.description;
return html`<div class="w3-container" style="box-sizing: border-box; border: 2px solid black; background-color: rgba(255, 255, 255, 0.2)">
<p><tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)})
<input type="text" class="w3-input w3-border w3-theme-d1" readonly value=${this.id}></input>
<button class="w3-button w3-theme-d1 w3-ripple" @click=${this.copy_id}>Copy</button>
return html`<div style="border: 2px solid black; background-color: rgba(255, 255, 255, 0.2); padding: 16px">
<tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)})
<div style="display: flex; flex-direction: row; gap: 1em">
${edit_profile}
<div style="flex: 1 0 50%">
@ -314,11 +300,11 @@ class TfProfileElement extends LitElement {
Blocking ${profile.blocking} identities.
Blocked by ${profile.blocked} identities.
</div>
<p>
<div>
${edit}
${follow}
${block}
</p>
</div>
</div>`;
}
}

View File

@ -27,12 +27,8 @@ class TfReactionsModalElement extends LitElement {
? html` <div
class="w3-modal w3-animate-opacity"
style="display: block; box-sizing: border-box"
@click=${this.clear}
>
<div
class="w3-modal-content w3-card-4 w3-theme-d1"
onclick="event.stopPropagation()"
>
<div class="w3-modal-content w3-card-4 w3-theme-d1">
<div class="w3-container w3-padding">
<header class="w3-container">
<h2>Reactions</h2>

View File

@ -286,29 +286,29 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
`;
// prettier-ignore
const w3_2016_snorkel_blue = css`
.w3-theme-l5 {color:#000 !important; background-color:#e9f5ff !important}
.w3-theme-l4 {color:#000 !important; background-color:#b5dffd !important}
.w3-theme-l3 {color:#000 !important; background-color:#6bc0fc !important}
.w3-theme-l2 {color:#fff !important; background-color:#21a0fa !important}
.w3-theme-l1 {color:#fff !important; background-color:#0479cc !important}
.w3-theme-d1 {color:#fff !important; background-color:#024575 !important}
.w3-theme-d2 {color:#fff !important; background-color:#023e68 !important}
.w3-theme-d3 {color:#fff !important; background-color:#02365b !important}
.w3-theme-d4 {color:#fff !important; background-color:#022e4e !important}
.w3-theme-d5 {color:#fff !important; background-color:#012641 !important}
const w3_2016_riverside = css`
.w3-theme-l5 {color:#000 !important; background-color:#f4f6f9 !important}
.w3-theme-l4 {color:#000 !important; background-color:#d9e1ec !important}
.w3-theme-l3 {color:#000 !important; background-color:#b4c3d8 !important}
.w3-theme-l2 {color:#fff !important; background-color:#8ea6c5 !important}
.w3-theme-l1 {color:#fff !important; background-color:#6888b1 !important}
.w3-theme-d1 {color:#fff !important; background-color:#456185 !important}
.w3-theme-d2 {color:#fff !important; background-color:#3d5676 !important}
.w3-theme-d3 {color:#fff !important; background-color:#354b68 !important}
.w3-theme-d4 {color:#fff !important; background-color:#2e4059 !important}
.w3-theme-d5 {color:#fff !important; background-color:#26364a !important}
.w3-theme-light {color:#000 !important; background-color:#e9f5ff !important}
.w3-theme-dark {color:#fff !important; background-color:#012641 !important}
.w3-theme-action {color:#fff !important; background-color:#012641 !important}
.w3-theme-light {color:#000 !important; background-color:#f4f6f9 !important}
.w3-theme-dark {color:#fff !important; background-color:#26364a !important}
.w3-theme-action {color:#fff !important; background-color:#26364a !important}
.w3-theme {color:#fff !important; background-color:#034f84 !important}
.w3-text-theme {color:#034f84 !important}
.w3-border-theme {border-color:#034f84 !important}
.w3-theme {color:#fff !important; background-color:#4c6a92 !important}
.w3-text-theme {color:#4c6a92 !important}
.w3-border-theme {border-color:#4c6a92 !important}
.w3-hover-theme:hover {color:#fff !important; background-color:#034f84 !important}
.w3-hover-text-theme:hover {color:#034f84 !important}
.w3-hover-border-theme:hover {border-color:#034f84 !important}
.w3-hover-theme:hover {color:#fff !important; background-color:#4c6a92 !important}
.w3-hover-text-theme:hover {color:#4c6a92 !important}
.w3-hover-border-theme:hover {border-color:#4c6a92 !important}
`;
export let styles = [tf, w3, w3_2016_snorkel_blue];
export let styles = [tf, w3, w3_2016_riverside];

View File

@ -12,20 +12,11 @@ class TfTabConnectionsElement extends LitElement {
stored_connections: {type: Array},
users: {type: Object},
server_identity: {type: String},
connect_attempt: {type: Object},
connect_message: {type: String},
connect_success: {type: Boolean},
};
}
static styles = styles;
static k_broadcast_emojis = {
discovery: '🏓',
room: '🚪',
peer_exchange: '🕸',
};
constructor() {
super();
let self = this;
@ -91,36 +82,19 @@ class TfTabConnectionsElement extends LitElement {
`;
}
render_message(connection) {
return html`<div
?hidden=${this.connect_message === undefined ||
this.connect_attempt != connection}
style="cursor: pointer"
class=${'w3-panel ' + (this.connect_success ? 'w3-green' : 'w3-red')}
@click=${() => (this.connect_attempt = undefined)}
>
<p>${this.connect_message}</p>
</div>`;
}
render_broadcast(connection) {
let self = this;
return html`
<li>
<div class="w3-bar" style="overflow: hidden; overflow-wrap: nowrap">
<li class="w3-bar" style="overflow: hidden; overflow-wrap: nowrap">
<button
class="w3-bar-item w3-button w3-theme-d1"
@click=${() => self.connect(connection)}
@click=${() => tfrpc.rpc.connect(connection)}
>
Connect
</button>
<div class="w3-bar-item">
${TfTabConnectionsElement.k_broadcast_emojis[connection.origin]}
<tf-user id=${connection.pubkey} .users=${this.users}></tf-user>
${this.render_connection_summary(connection)}
</div>
</div>
${this.render_message(connection)}
</li>
`;
}
@ -148,7 +122,6 @@ class TfTabConnectionsElement extends LitElement {
>
Close
</button>
${connection.flags.one_shot ? '🔃' : undefined}
<tf-user id=${connection.id} .users=${this.users}></tf-user>
${connection.tunnel !== undefined
? '🚇'
@ -156,9 +129,7 @@ class TfTabConnectionsElement extends LitElement {
<div>
${requests.map(
(x) => html`
<span
class=${'w3-tag w3-small ' +
(x.active ? 'w3-theme-l3' : 'w3-theme-d3')}
<span class="w3-tag w3-small"
>${x.request_number > 0 ? '🟩' : '🟥'} ${x.name}
<span
class="w3-badge w3-white"
@ -178,38 +149,16 @@ class TfTabConnectionsElement extends LitElement {
`;
}
connect(address) {
let self = this;
self.connect_attempt = address;
self.connect_message = undefined;
self.connect_success = false;
tfrpc.rpc
.connect(address)
.then(function () {
if (self.connect_attempt == address) {
self.connect_message = 'Connected.';
self.connect_success = true;
}
})
.catch(function (error) {
if (self.connect_attempt == address) {
self.connect_message = 'Error: ' + error;
self.connect_success = false;
}
});
}
render() {
let self = this;
return html`
<div class="w3-container" style="box-sizing: border-box">
<h2>New Connection</h2>
<textarea class="w3-input w3-theme-d1" id="code"></textarea>
${this.render_message(this.renderRoot.getElementById('code')?.value)}
<button
class="w3-button w3-theme-d1"
@click=${() =>
self.connect(self.renderRoot.getElementById('code')?.value)}
tfrpc.rpc.connect(self.renderRoot.getElementById('code').value)}
>
Connect
</button>
@ -217,9 +166,6 @@ class TfTabConnectionsElement extends LitElement {
<ul class="w3-ul w3-border">
${this.broadcasts
.filter((x) => x.address)
.filter(
(x) => self.connections.map((c) => c.id).indexOf(x.pubkey) == -1
)
.map((x) => self.render_broadcast(x))}
</ul>
<h2>Connections</h2>
@ -236,8 +182,7 @@ class TfTabConnectionsElement extends LitElement {
<ul class="w3-ul w3-border">
${this.stored_connections.map(
(x) => html`
<li>
<div class="w3-bar">
<li class="w3-bar">
<button
class="w3-bar-item w3-button w3-theme-d1"
@click=${() => self.forget_stored_connection(x)}
@ -246,7 +191,7 @@ class TfTabConnectionsElement extends LitElement {
</button>
<button
class="w3-bar-item w3-button w3-theme-d1"
@click=${() => this.connect(x)}
@click=${() => tfrpc.rpc.connect(x)}
>
Connect
</button>
@ -254,8 +199,6 @@ class TfTabConnectionsElement extends LitElement {
<tf-user id=${x.pubkey} .users=${self.users}></tf-user>
<div><small>${x.address}:${x.port}</small></div>
</div>
</div>
${this.render_message(x)}
</li>
`
)}

View File

@ -0,0 +1,78 @@
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js';
class TfTabMentionsElement extends LitElement {
static get properties() {
return {
whoami: {type: String},
users: {type: Object},
following: {type: Array},
expanded: {type: Object},
messages: {type: Array},
};
}
static styles = styles;
constructor() {
super();
let self = this;
this.whoami = null;
this.users = {};
this.following = [];
this.expanded = {};
this.messages = [];
}
async load() {
console.log('Loading...', this.whoami);
let results = await tfrpc.rpc.query(
`
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM messages_fts(?)
JOIN messages ON messages.rowid = messages_fts.rowid
JOIN json_each(?) AS following ON messages.author = following.value
WHERE messages.author != ?
ORDER BY timestamp DESC limit 20
`,
[
'"' + this.whoami.replace('"', '""') + '"',
JSON.stringify(this.following),
this.whoami,
]
);
console.log('Done.');
this.messages = results;
}
on_expand(event) {
if (event.detail.expanded) {
let expand = {};
expand[event.detail.id] = true;
this.expanded = Object.assign({}, this.expanded, expand);
} else {
delete this.expanded[event.detail.id];
this.expanded = Object.assign({}, this.expanded);
}
}
render() {
let self = this;
if (!this.loading) {
this.loading = true;
this.load();
}
return html`
<tf-news
id="news"
whoami=${this.whoami}
.messages=${this.messages}
.users=${this.users}
.expanded=${this.expanded}
@tf-expand=${this.on_expand}
></tf-news>
`;
}
}
customElements.define('tf-tab-mentions', TfTabMentionsElement);

View File

@ -12,11 +12,6 @@ class TfTabNewsFeedElement extends LitElement {
messages: {type: Array},
drafts: {type: Object},
expanded: {type: Object},
channels_unread: {type: Object},
channels_latest: {type: Object},
loading: {type: Number},
time_range: {type: Array},
time_loading: {type: Array},
};
}
@ -31,67 +26,30 @@ class TfTabNewsFeedElement extends LitElement {
this.following = [];
this.drafts = {};
this.expanded = {};
this.channels_unread = {};
this.channels_latest = {};
this.start_time = new Date().valueOf();
this.time_range = [0, 0];
this.time_loading = undefined;
this.loading = 0;
this.start_time = new Date().valueOf() - 24 * 60 * 60 * 1000;
}
channel() {
return this.hash.startsWith('##')
? this.hash.substring(2)
: this.hash.substring(1);
}
async fetch_messages(start_time, end_time) {
this.time_loading = [start_time, end_time];
let result;
if (this.hash == '#@') {
result = await tfrpc.rpc.query(
async fetch_messages() {
if (this.hash.startsWith('#@')) {
let r = await tfrpc.rpc.query(
`
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM messages_fts(?1)
JOIN messages ON messages.rowid = messages_fts.rowid
JOIN json_each(?2) AS following ON messages.author = following.value
WHERE
messages.author != ?1 AND
messages.timestamp >= ?3 AND
messages.timestamp < ?4
ORDER BY timestamp DESC limit 20
`,
[
'"' + this.whoami.replace('"', '""') + '"',
JSON.stringify(this.following),
start_time,
end_time,
]
);
} else if (this.hash.startsWith('#@')) {
result = await tfrpc.rpc.query(
`
WITH mine AS (SELECT rowid, id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
WITH mine AS (SELECT id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
FROM messages
WHERE messages.author = ?
ORDER BY sequence DESC)
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
ORDER BY sequence DESC
LIMIT 20)
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM mine
JOIN messages_refs ON mine.id = messages_refs.ref
JOIN messages ON messages_refs.message = messages.id
WHERE
mine.timestamp >= ?2 AND
mine.timestamp < ?3
UNION
SELECT * FROM mine
WHERE
mine.timestamp >= ?2 AND
mine.timestamp < ?3
`,
[this.hash.substring(1), start_time, end_time]
[this.hash.substring(1)]
);
return r;
} else if (this.hash.startsWith('#%')) {
result = await tfrpc.rpc.query(
return await tfrpc.rpc.query(
`
SELECT id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
FROM messages
@ -104,68 +62,6 @@ class TfTabNewsFeedElement extends LitElement {
`,
[this.hash.substring(1)]
);
} else if (this.hash.startsWith('##')) {
let promises = [];
const k_following_limit = 256;
for (let i = 0; i < this.following.length; i += k_following_limit) {
promises.push(
tfrpc.rpc.query(
`
WITH news AS (SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM messages
JOIN json_each(?) AS following ON messages.author = following.value
WHERE
messages.timestamp >= ? AND
messages.timestamp < ? AND
messages.content ->> 'channel' = ?
ORDER BY messages.timestamp DESC)
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM news
JOIN messages_refs ON news.id = messages_refs.ref
JOIN messages ON messages_refs.message = messages.id
UNION
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM news
JOIN messages_refs ON news.id = messages_refs.message
JOIN messages ON messages_refs.ref = messages.id
UNION
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM messages_fts(?5)
JOIN messages ON messages.rowid = messages_fts.rowid
JOIN json_each(?1) AS following ON messages.author = following.value
JOIN json_tree(messages.content, '$.mentions') AS mention ON mention.value = '#' || ?4
WHERE
messages.timestamp >= ?2 AND
messages.timestamp < ?3
UNION
SELECT news.* FROM news
`,
[
JSON.stringify(this.following.slice(i, i + k_following_limit)),
start_time,
end_time,
this.hash.substring(2),
'"#' + this.hash.substring(2).replace('"', '""') + '"',
]
)
);
}
result = [].concat(...(await Promise.all(promises)));
} else if (this.hash == '#🔐') {
result = await tfrpc.rpc.query(
`
SELECT messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
FROM messages
JOIN json_each(?1) AS following ON messages.author = following.value
WHERE
messages.timestamp >= ?2 AND
messages.timestamp < ?3 AND
json(messages.content) LIKE '"%'
ORDER BY sequence DESC
`,
[JSON.stringify(this.following), start_time, end_time]
);
result = (await this.decrypt(result)).filter(x => x.decrypted);
} else {
let promises = [];
const k_following_limit = 256;
@ -173,17 +69,17 @@ class TfTabNewsFeedElement extends LitElement {
promises.push(
tfrpc.rpc.query(
`
WITH news AS (SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
WITH news AS (SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM messages
JOIN json_each(?) AS following ON messages.author = following.value
WHERE messages.timestamp >= ? AND messages.timestamp < ?
WHERE messages.timestamp > ? AND messages.timestamp < ?
ORDER BY messages.timestamp DESC)
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM news
JOIN messages_refs ON news.id = messages_refs.ref
JOIN messages ON messages_refs.message = messages.id
UNION
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM news
JOIN messages_refs ON news.id = messages_refs.message
JOIN messages ON messages_refs.ref = messages.id
@ -192,58 +88,50 @@ class TfTabNewsFeedElement extends LitElement {
`,
[
JSON.stringify(this.following.slice(i, i + k_following_limit)),
start_time,
end_time,
this.start_time,
/*
** Don't show messages more than a day into the future to prevent
** messages with far-future timestamps from staying at the top forever.
*/
new Date().valueOf() + 24 * 60 * 60 * 1000,
]
)
);
}
result = [].concat(...(await Promise.all(promises)));
return [].concat(...(await Promise.all(promises)));
}
this.time_loading = undefined;
return result;
}
update_time_range_from_messages(messages) {
this.time_range = [
messages.reduce(
(accumulator, current) => Math.min(accumulator, current.timestamp),
this.time_range[0]
),
messages.reduce(
(accumulator, current) => Math.max(accumulator, current.timestamp),
this.time_range[1]
),
];
}
async load_more() {
this.loading++;
this.loading_canceled = false;
try {
let more = [];
while (!more.length && !this.loading_canceled) {
let last_start_time = this.start_time;
this.start_time = last_start_time - 7 * 24 * 60 * 60 * 1000;
more = await this.fetch_messages(this.start_time, last_start_time);
this.update_time_range_from_messages(
more.filter(
(x) =>
x.timestamp >= this.start_time && x.timestamp < last_start_time
)
this.start_time = last_start_time - 24 * 60 * 60 * 1000;
let more = await tfrpc.rpc.query(
`
WITH news AS (SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM messages
JOIN json_each(?) AS following ON messages.author = following.value
WHERE messages.timestamp > ?
AND messages.timestamp <= ?
ORDER BY messages.timestamp DESC)
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM news
JOIN messages_refs ON news.id = messages_refs.ref
JOIN messages ON messages_refs.message = messages.id
UNION
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
FROM news
JOIN messages_refs ON news.id = messages_refs.message
JOIN messages ON messages_refs.ref = messages.id
UNION
SELECT news.* FROM news
`,
[JSON.stringify(this.following), this.start_time, last_start_time]
);
}
this.messages = await this.decrypt([...more, ...this.messages]);
} finally {
this.loading--;
}
}
cancel_load() {
this.loading_canceled = true;
}
async decrypt(messages) {
console.log('decrypt');
let result = [];
for (let message of messages) {
let content;
@ -268,89 +156,8 @@ class TfTabNewsFeedElement extends LitElement {
return result;
}
async load_latest() {
this.loading++;
let now = new Date().valueOf();
let end_time = now + 24 * 60 * 60 * 1000;
let messages = [];
try {
messages = await this.fetch_messages(this.time_range[1], end_time);
messages = await this.decrypt(messages);
this.update_time_range_from_messages(
messages.filter(
(x) => x.timestamp >= this.time_range[1] && x.timestamp < end_time
)
);
} finally {
this.loading--;
}
this.messages = [...this.messages, ...messages];
console.log('done loading latest messages.');
}
async load_messages() {
let self = this;
this.loading++;
let messages = [];
try {
this.messages = [];
this._messages_hash = this.hash;
this._messages_following = this.following;
let now = new Date().valueOf();
let start_time = now - 24 * 60 * 60 * 1000;
this.start_time = start_time;
this.time_range = [this.start_time, now + 24 * 60 * 60 * 1000];
messages = await this.fetch_messages(
this.time_range[0],
this.time_range[1]
);
this.update_time_range_from_messages(
messages.filter(
(x) =>
x.timestamp >= this.time_range[0] &&
x.timestamp < this.time_range[1]
)
);
messages = await this.decrypt(messages);
if (!messages.length) {
let more = [];
while (!more.length && start_time >= 0) {
let last_start_time = start_time;
start_time = last_start_time - 7 * 24 * 60 * 60 * 1000;
more = await this.fetch_messages(start_time, last_start_time);
this.update_time_range_from_messages(
more.filter(
(x) => x.timestamp >= start_time && x.timestamp < last_start_time
)
);
}
messages = await this.decrypt([...more, ...this.messages]);
}
} finally {
this.loading--;
}
this.messages = messages;
this.time_loading = undefined;
console.log(`loading messages done for ${self.whoami}`);
}
mark_all_read() {
let newest = this.messages.reduce(
(accumulator, current) => Math.max(accumulator, current.rowid),
this.channels_latest[this.channel()] ?? -1
);
if (newest >= 0) {
this.dispatchEvent(
new CustomEvent('channelsetunread', {
bubbles: true,
composed: true,
detail: {
channel: this.channel(),
unread: newest + 1,
},
})
);
}
async add_messages(messages) {
this.messages = await this.decrypt([...messages, ...this.messages]);
}
render() {
@ -362,49 +169,31 @@ class TfTabNewsFeedElement extends LitElement {
console.log(
`loading messages for ${this.whoami} (following ${this.following.length})`
);
this.load_messages();
let self = this;
this.messages = [];
this._messages_hash = this.hash;
this._messages_following = this.following;
this.fetch_messages()
.then(this.decrypt.bind(this))
.then(function (messages) {
self.messages = messages;
console.log(`loading mesages done for ${self.whoami}`);
})
.catch(function (error) {
alert(JSON.stringify(error, null, 2));
});
}
let more;
if (!this.hash.startsWith('#%')) {
if (!this.hash.startsWith('#@') && !this.hash.startsWith('#%')) {
more = html`
<p>
<button class="w3-button w3-theme-d1" @click=${this.mark_all_read}>
Mark All Read
</button>
<button
?disabled=${this.loading}
class="w3-button w3-theme-d1"
@click=${this.load_more}
>
<button class="w3-button w3-theme-d1" @click=${this.load_more}>
Load More
</button>
<button
class=${'w3-button w3-theme-d1' + (this.loading ? '' : ' w3-hide')}
@click=${this.cancel_load}
>
Cancel
</button>
<span
>Showing
${new Date(
this.time_loading
? Math.min(this.time_loading[0], this.time_range[0])
: this.time_range[0]
).toLocaleDateString()}
-
${new Date(
this.time_loading
? Math.max(this.time_loading[1], this.time_range[1])
: this.time_range[1]
).toLocaleDateString()}.</span
>
</p>
`;
}
return html`
<button class="w3-button w3-theme-d1" @click=${this.mark_all_read}>
Mark All Read
</button>
<tf-news
id="news"
whoami=${this.whoami}
@ -413,8 +202,6 @@ class TfTabNewsFeedElement extends LitElement {
.following=${this.following}
.drafts=${this.drafts}
.expanded=${this.expanded}
channel=${this.channel()}
channel_unread=${this.channels_unread?.[this.channel()]}
></tf-news>
${more}
`;

View File

@ -13,9 +13,6 @@ class TfTabNewsElement extends LitElement {
drafts: {type: Object},
expanded: {type: Object},
loading: {type: Boolean},
channels: {type: Array},
channels_unread: {type: Object},
channels_latest: {type: Object},
};
}
@ -32,9 +29,6 @@ class TfTabNewsElement extends LitElement {
this.cache = {};
this.drafts = {};
this.expanded = {};
this.channels_unread = {};
this.channels_latest = {};
this.channels = [];
tfrpc.rpc.localStorageGet('drafts').then(function (d) {
self.drafts = JSON.parse(d || '{}');
});
@ -54,7 +48,10 @@ class TfTabNewsElement extends LitElement {
let unread = this.unread;
let news = this.shadowRoot?.getElementById('news');
if (news) {
news.load_latest();
console.log('injecting messages', news.messages);
news.add_messages(
Object.values(Object.fromEntries(this.unread.map((x) => [x.id, x])))
);
this.dispatchEvent(new CustomEvent('refresh'));
}
}
@ -109,52 +106,9 @@ class TfTabNewsElement extends LitElement {
}
}
unread_status(channel) {
if (
this.channels_latest[channel] &&
(this.channels_unread[channel] === undefined ||
this.channels_unread[channel] < this.channels_latest[channel])
) {
return '🔵';
}
}
show_sidebar() {
this.renderRoot.getElementById('sidebar').style.display = 'block';
this.renderRoot.getElementById('sidebar_overlay').style.display = 'block';
}
hide_sidebar() {
this.renderRoot.getElementById('sidebar').style.display = 'none';
this.renderRoot.getElementById('sidebar_overlay').style.display = 'none';
}
async channel_toggle_subscribed() {
let channel = this.hash.substring(2);
let subscribed = this.channels.indexOf(channel) != -1;
subscribed = !subscribed;
await tfrpc.rpc.appendMessage(this.whoami, {
type: 'channel',
channel: channel,
subscribed: subscribed,
});
if (subscribed) {
this.channels = [].concat([channel], this.channels).sort();
} else {
this.channels = this.channels.filter((x) => x != channel);
}
}
channel() {
return this.hash.startsWith('##') ? this.hash.substring(2) : undefined;
}
render() {
let profile =
this.hash.startsWith('#@') && this.hash != '#@'
let profile = this.hash.startsWith('#@')
? html`<tf-profile
class="tf-profile"
id=${this.hash.substring(1)}
whoami=${this.whoami}
.users=${this.users}
@ -174,88 +128,13 @@ class TfTabNewsElement extends LitElement {
</div>`;
}
return html`
<div
class="w3-sidebar w3-bar-block w3-theme-d1 w3-collapse w3-animate-left"
style="width: 2in; left: 0; z-index: 5"
id="sidebar"
<p class="w3-bar">
<button
class="w3-bar-item w3-button w3-theme-d1"
@click=${this.show_more}
>
<div
class="w3-right w3-button w3-hide-large"
@click=${this.hide_sidebar}
>
&times;
</div>
${this.hash.startsWith('##') &&
this.channels.indexOf(this.hash.substring(2)) == -1
? html`
<div class="w3-bar-item w3-theme-d2">Viewing</div>
<a
href="#"
class="w3-bar-item w3-button"
style="font-weight: bold"
>${this.hash.substring(2)}</a
>
`
: undefined}
<div class="w3-bar-item w3-theme-d2">Channels</div>
<a
href="#"
class="w3-bar-item w3-button"
style=${this.hash == '#' ? 'font-weight: bold' : undefined}
>general ${this.unread_status('')}</a
>
<a
href="#@"
class="w3-bar-item w3-button"
style=${this.hash == '#@' ? 'font-weight: bold' : undefined}
>@mentions ${this.unread_status('@')}</a
>
<a
href="#🔐"
class="w3-bar-item w3-button"
style=${this.hash == '#🔐' ? 'font-weight: bold' : undefined}
>🔐private ${this.unread_status('🔐')}</a
>
${this.channels.map(
(x) => html`
<a
href=${'#' + encodeURIComponent('#' + x)}
class="w3-bar-item w3-button"
style=${this.hash == '##' + x ? 'font-weight: bold' : undefined}
>#${x} ${this.unread_status(x)}</a
>
`
)}
</div>
<div
class="w3-overlay"
id="sidebar_overlay"
@click=${this.hide_sidebar}
></div>
<div style="margin-left: 2in; padding: 8px" id="main" class="w3-main">
<div
id="show_sidebar"
class="w3-left w3-button w3-hide-large"
@click=${this.show_sidebar}
>
&#9776;
</div>
<p>
<button class="w3-button w3-theme-d1" @click=${this.show_more}>
${this.new_messages_text()}
</button>
${this.hash.startsWith('##')
? html`
<button
class="w3-button w3-theme-d1"
@click=${this.channel_toggle_subscribed}
>
${this.channels.indexOf(this.hash.substring(2)) != -1
? 'Unsubscribe from #'
: 'Subscribe to #'}${this.hash.substring(2)}
</button>
`
: undefined}
</p>
<div class="w3-bar">
Welcome, <tf-user id=${this.whoami} .users=${this.users}></tf-user>!
@ -268,7 +147,6 @@ class TfTabNewsElement extends LitElement {
.users=${this.users}
.drafts=${this.drafts}
@tf-draft=${this.draft}
.channel=${this.channel()}
></tf-compose>
</div>
${profile}
@ -282,10 +160,7 @@ class TfTabNewsElement extends LitElement {
.expanded=${this.expanded}
@tf-draft=${this.draft}
@tf-expand=${this.on_expand}
.channels_unread=${this.channels_unread}
.channels_latest=${this.channels_latest}
></tf-tab-news-feed>
</div>
`;
}
}

View File

@ -5,7 +5,6 @@ import {styles} from './tf-styles.js';
class TfTabSearchElement extends LitElement {
static get properties() {
return {
drafts: {type: Object},
whoami: {type: String},
users: {type: Object},
following: {type: Array},
@ -23,10 +22,6 @@ class TfTabSearchElement extends LitElement {
this.users = {};
this.following = [];
this.expanded = {};
this.drafts = {};
tfrpc.rpc.localStorageGet('drafts').then(function (d) {
self.drafts = JSON.parse(d || '{}');
});
}
async search(query) {
@ -75,18 +70,6 @@ class TfTabSearchElement extends LitElement {
}
}
draft(event) {
let id = event.detail.id || '';
let previous = this.drafts[id];
if (event.detail.draft !== undefined) {
this.drafts[id] = event.detail.draft;
} else {
delete this.drafts[id];
}
this.drafts = Object.assign({}, this.drafts);
tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts));
}
render() {
if (this.query !== this.last_query) {
this.last_query = this.query;
@ -98,7 +81,7 @@ class TfTabSearchElement extends LitElement {
<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input>
<button class="w3-button w3-theme-d1" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}>Search</button>
</div>
<tf-news id="news" whoami=${this.whoami} .messages=${this.messages} .users=${this.users} .expanded=${this.expanded} .drafts=${this.drafts} @tf-expand=${this.on_expand} @tf-draft=${this.draft}></tf-news>
<tf-news id="news" whoami=${this.whoami} .messages=${this.messages} .users=${this.users} .expanded=${this.expanded} @tf-expand=${this.on_expand}></tf-news>
`;
}
}

View File

@ -18,7 +18,7 @@ class TfTagElement extends LitElement {
render() {
let number = this.count ? html` (${this.count})` : undefined;
return html`<a
href=${'#' + encodeURIComponent(this.tag)}
href="#q=${this.tag}"
style="display: inline-block; margin: 3px; border: 1px solid black; background-color: #444; padding: 4px; border-radius: 3px"
>${this.tag}${number}</a
>`;

View File

@ -37,7 +37,7 @@ class TfUserElement extends LitElement {
if (image_link !== undefined) {
image = html`<img
class="w3-circle"
style="width: 2em; height: 2em; vertical-align: middle; object-fit: cover"
style="width: 2em; height: 2em; vertical-align: middle"
src="/${image_link}/view"
/>`;
}

View File

@ -2,12 +2,6 @@ import * as hashtagify from './commonmark-hashtag.js';
const k_code_classes = 'w3-theme-l4 w3-theme-border w3-round';
var reUnsafeProtocol = /^javascript:|vbscript:|file:|data:/i;
var reSafeDataProtocol = /^data:image\/(?:png|gif|jpeg|webp)/i;
var potentiallyUnsafe = function (url) {
return reUnsafeProtocol.test(url) && !reSafeDataProtocol.test(url);
};
function image(node, entering) {
if (
node.firstChild?.type === 'text' &&
@ -87,8 +81,8 @@ function attrs(node) {
}
export function markdown(md) {
let reader = new commonmark.Parser();
let writer = new commonmark.HtmlRenderer({safe: true});
let reader = new commonmark.Parser({safe: true});
let writer = new commonmark.HtmlRenderer();
writer.image = image;
writer.code = code;
writer.attrs = attrs;

View File

@ -1,5 +0,0 @@
{
"type": "tildefriends-app",
"emoji": "💾",
"previous": "&mvGTlWKFR5QM/3nb4fJ2WQq0n/gNKvBmhGDkAvb8ki8=.sha256"
}

View File

@ -1,127 +0,0 @@
async function query(sql, args) {
let rows = [];
await ssb.sqlAsync(sql, args ?? [], function (row) {
rows.push(row);
});
return rows;
}
async function get_biggest() {
return query(`
select author, sum(length(content)) as size from messages group by author order by size desc limit 10;
`);
}
async function get_total() {
return (
await query(`
select sum(length(content)) as size, count(distinct author) as count from messages;
`)
)[0];
}
async function get_names(identities) {
return query(
`
SELECT author, name FROM (
SELECT
messages.author,
RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank,
messages.content ->> 'name' AS name
FROM messages
JOIN json_each(?) AS identities ON identities.value = messages.author
WHERE
json_extract(messages.content, '$.type') = 'about' AND
content ->> 'about' = messages.author AND name IS NOT NULL)
WHERE author_rank = 1
`,
[JSON.stringify(identities)]
);
}
async function get_most_follows() {
return query(`
select author, count(*) as count
from messages
where content ->> 'type' = 'contact' and content ->> 'following' = true
group by author
order by count desc
limit 10;
`);
}
function nice_size(bytes) {
let value = bytes;
let index = 0;
let units = ['B', 'kB', 'MB', 'GB'];
while (value > 1024 && index < units.length - 1) {
value /= 1024;
index++;
}
return `${Math.round(value * 10) / 10} ${units[index]}`;
}
async function main() {
await app.setDocument(
'<p style="color: #fff">Finding the top 10 largest feeds...</p>'
);
let most_follows = await get_most_follows();
let total = await get_total();
let identities = await ssb.getAllIdentities();
let following1 = await ssb.following(identities, 1);
let following2 = await ssb.following(identities, 2);
let biggest = await get_biggest();
let names = await get_names(
[].concat(
biggest.map((x) => x.author),
most_follows.map((x) => x.author)
)
);
names = Object.fromEntries(names.map((x) => [x.author, x.name]));
for (let item of biggest) {
item.name = names[item.author];
item.following =
identities.indexOf(item.author) != -1
? 0
: following1[item.author] !== undefined
? 1
: following2[item.author] !== undefined
? 2
: undefined;
}
for (let item of most_follows) {
item.name = names[item.author];
}
let html = `<body style="color: #000; background-color: #ddd">\n
<h1>Storage Summary</h1>
<h2>Top 10 Accounts by Size</h2>
<ol>`;
for (let item of biggest) {
html += `<li>
<span style="color: #888">${nice_size(item.size)}</span>
<a target="_top" href="/~core/ssb/#${encodeURI(item.author)}">${item.name ?? item.author}</a>
</li>
\n`;
}
html += `
</ol>
<h2>Top 10 Accounts by Follows</h2>
<ol>`;
for (let item of most_follows) {
html += `<li>
<span style="color: #888">${item.count}</span>
${following2[item.author] ? '✅' : '🚫'}
<a target="_top" href="/~core/ssb/#${encodeURI(item.author)}">${item.name ?? item.author}</a>
</li>
\n`;
}
html += `
</ol>
<p>Total <span style="color: #888">${nice_size(total.size)}</span> in ${total.count} accounts.</p>
`;
await app.setDocument(html);
}
main().catch(function (e) {
print(e);
});

View File

@ -1,4 +0,0 @@
{
"type": "tildefriends-app",
"emoji": "📦"
}

View File

@ -1,3 +0,0 @@
app.setDocument(
'<p style="color: #fff">Maybe one day this app will run tests, but for now there is nothing to see here.</p>'
);

View File

@ -1 +0,0 @@
Hello, world!

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "👋",
"previous": "&7gFmLW5zSMhmxWWY1+jeRcHdullgujSqGJg94lVgr1k=.sha256"
"previous": "&W5aJp2DgOW5rQ0AOIC9Ut3DpsahPrO6PjkJ1PQbNRdM=.sha256"
}

View File

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="48px" height="48px" id="svg3832" version="1.1" inkscape:version="0.47 r22583" sodipodi:docname="appimage-assistant_alt3.svg">
<defs id="defs3834">
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3308-4-6-931-761-0" id="linearGradient2975" gradientUnits="userSpaceOnUse" x1="24.3125" y1="22.96875" x2="24.3125" y2="41.03125"/>
<linearGradient id="linearGradient3308-4-6-931-761-0">
<stop id="stop2919-2" style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
<stop id="stop2921-76" style="stop-color:#ffffff;stop-opacity:0" offset="1"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4222" id="linearGradient2979" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,0.3704967,-0.3617496,0,33.508315,6.1670925)" x1="7.6485429" y1="26.437023" x2="41.861729" y2="26.437023"/>
<linearGradient id="linearGradient4222">
<stop id="stop4224" style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
<stop id="stop4226" style="stop-color:#ffffff;stop-opacity:0" offset="1"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3308-4-6-931-761" id="linearGradient2982" gradientUnits="userSpaceOnUse" gradientTransform="translate(0,0.9999987)" x1="23.99999" y1="4.999989" x2="23.99999" y2="43"/>
<linearGradient id="linearGradient3308-4-6-931-761">
<stop id="stop2919" style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
<stop id="stop2921" style="stop-color:#ffffff;stop-opacity:0" offset="1"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient3575" id="radialGradient2985" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,1.0262008,-1.6561124,9.4072203e-4,-56.097482,-45.332325)" cx="48.42384" cy="-48.027504" fx="48.42384" fy="-48.027504" r="38.212933"/>
<linearGradient id="linearGradient3575">
<stop id="stop3577" style="stop-color:#fafafa;stop-opacity:1" offset="0"/>
<stop id="stop3579" style="stop-color:#e6e6e6;stop-opacity:1" offset="1"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient3993" id="radialGradient2990" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0,2.0478765,-2.7410544,-8.6412258e-8,47.161382,-8.837436)" cx="9.3330879" cy="8.4497671" fx="9.3330879" fy="8.4497671" r="19.99999"/>
<linearGradient id="linearGradient3993">
<stop offset="0" style="stop-color:#a3c0d0;stop-opacity:1" id="stop3995"/>
<stop offset="1" style="stop-color:#427da1;stop-opacity:1" id="stop4001"/>
</linearGradient>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient2508" id="linearGradient2992" gradientUnits="userSpaceOnUse" gradientTransform="translate(0,0.9674382)" x1="14.048676" y1="44.137306" x2="14.048676" y2="4.0000005"/>
<linearGradient id="linearGradient2508">
<stop offset="0" style="stop-color:#2e4a5a;stop-opacity:1" id="stop2510"/>
<stop offset="1" style="stop-color:#6e8796;stop-opacity:1" id="stop2512"/>
</linearGradient>
<radialGradient cx="4.9929786" cy="43.5" r="2.5" fx="4.9929786" fy="43.5" id="radialGradient2873-966-168" xlink:href="#linearGradient3688-166-749" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.003784,0,0,1.4,27.98813,-17.4)"/>
<linearGradient id="linearGradient3688-166-749">
<stop id="stop2883" style="stop-color:#181818;stop-opacity:1" offset="0"/>
<stop id="stop2885" style="stop-color:#181818;stop-opacity:0" offset="1"/>
</linearGradient>
<radialGradient cx="4.9929786" cy="43.5" r="2.5" fx="4.9929786" fy="43.5" id="radialGradient2875-742-326" xlink:href="#linearGradient3688-464-309" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.003784,0,0,1.4,-20.01187,-104.4)"/>
<linearGradient id="linearGradient3688-464-309">
<stop id="stop2889" style="stop-color:#181818;stop-opacity:1" offset="0"/>
<stop id="stop2891" style="stop-color:#181818;stop-opacity:0" offset="1"/>
</linearGradient>
<linearGradient x1="25.058096" y1="47.027729" x2="25.058096" y2="39.999443" id="linearGradient2877-634-617" xlink:href="#linearGradient3702-501-757" gradientUnits="userSpaceOnUse"/>
<linearGradient id="linearGradient3702-501-757">
<stop id="stop2895" style="stop-color:#181818;stop-opacity:0" offset="0"/>
<stop id="stop2897" style="stop-color:#181818;stop-opacity:1" offset="0.5"/>
<stop id="stop2899" style="stop-color:#181818;stop-opacity:0" offset="1"/>
</linearGradient>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7" inkscape:cx="24" inkscape:cy="24" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" inkscape:window-width="603" inkscape:window-height="484" inkscape:window-x="417" inkscape:window-y="162" inkscape:window-maximized="0"/>
<metadata id="metadata3837">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
<g style="display:inline" id="g2036" transform="matrix(1.1,0,0,0.4444449,-2.4000022,25.11107)">
<g style="opacity:0.4" id="g3712" transform="matrix(1.052632,0,0,1.285713,-1.263158,-13.42854)">
<rect style="fill:url(#radialGradient2873-966-168);fill-opacity:1;stroke:none" id="rect2801" y="40" x="38" height="7" width="5"/>
<rect style="fill:url(#radialGradient2875-742-326);fill-opacity:1;stroke:none" id="rect3696" transform="scale(-1,-1)" y="-47" x="-10" height="7" width="5"/>
<rect style="fill:url(#linearGradient2877-634-617);fill-opacity:1;stroke:none" id="rect3700" y="40" x="10" height="7.0000005" width="28"/>
</g>
</g>
<rect style="fill:url(#radialGradient2990);fill-opacity:1;stroke:url(#linearGradient2992);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" id="rect5505" y="5.4674392" x="4.5" ry="2.2322156" rx="2.2322156" height="39" width="39"/>
<path style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path4294-1" d="m 21,6.9687498 a 2.0165107,2.0165107 0 0 0 -2.03125,2.03125 l 0,3.9687502 -1.15625,0 a 2.0165107,2.0165107 0 0 0 -1.5,3.375 l 5.0625,5.75 c -0.06312,0.110777 -0.178724,0.246032 -0.21875,0.34375 -0.195898,0.478256 -0.25,0.83653 -0.25,1.21875 l 0,0.125 L 20.8125,23.6875 C 20.534322,23.409323 20.213169,23.162739 19.71875,22.96875 19.47154,22.87176 19.185456,22.791748 18.75,22.8125 c -0.435456,0.02075 -1.054055,0.210302 -1.46875,0.625 L 15.75,24.96875 c -0.414689,0.414689 -0.604245,1.033294 -0.625,1.46875 -0.02075,0.435456 0.05925,0.721537 0.15625,0.96875 C 15.475241,27.900677 15.721817,28.221821 16,28.5 l 0.09375,0.09375 -0.125,0 c -0.382218,0 -0.740493,0.0541 -1.21875,0.25 -0.239128,0.09795 -0.538285,0.214988 -0.84375,0.53125 -0.305465,0.316262 -0.625,0.914788 -0.625,1.53125 l 0,2.1875 c 0,0.616465 0.319536,1.214989 0.625,1.53125 0.305464,0.316261 0.604622,0.433301 0.84375,0.53125 0.478256,0.195898 0.83653,0.25 1.21875,0.25 l 0.125,0 L 16,35.5 c -0.278175,0.278176 -0.52476,0.599329 -0.71875,1.09375 -0.09699,0.24721 -0.177003,0.533292 -0.15625,0.96875 0.02075,0.435458 0.210304,1.054058 0.625,1.46875 l 1.53125,1.53125 c 0.414691,0.414697 1.033292,0.604245 1.46875,0.625 0.435458,0.02076 0.721537,-0.05926 0.96875,-0.15625 0.494425,-0.19399 0.81557,-0.440568 1.09375,-0.71875 l 0.09375,-0.09375 0,0.125 c 0,0.38222 0.0541,0.740495 0.25,1.21875 0.09795,0.239127 0.214989,0.538285 0.53125,0.84375 0.316261,0.305465 0.914783,0.625 1.53125,0.625 l 2.1875,0 c 0.616466,0 1.214989,-0.319534 1.53125,-0.625 0.316261,-0.305466 0.433302,-0.604622 0.53125,-0.84375 0.195896,-0.478255 0.25,-0.836532 0.25,-1.21875 l 0,-0.125 0.09375,0.09375 c 0.278176,0.278175 0.599329,0.52476 1.09375,0.71875 0.24721,0.09699 0.533292,0.177003 0.96875,0.15625 0.435458,-0.02075 1.054058,-0.210304 1.46875,-0.625 L 32.875,39.03125 C 33.289697,38.616559 33.479245,37.997958 33.5,37.5625 33.52076,37.127042 33.44074,36.840963 33.34375,36.59375 33.14976,36.099325 32.903182,35.77818 32.625,35.5 l -0.09375,-0.09375 0.125,0 c 0.38222,0 0.740494,-0.0541 1.21875,-0.25 0.239128,-0.09795 0.538286,-0.214988 0.84375,-0.53125 0.305464,-0.316262 0.625,-0.914787 0.625,-1.53125 l 0,-2.1875 c 0,-0.61646 -0.319535,-1.214987 -0.625,-1.53125 -0.305465,-0.316263 -0.604621,-0.433301 -0.84375,-0.53125 -0.478257,-0.195898 -0.836532,-0.25 -1.21875,-0.25 l -0.125,0 L 32.625,28.5 c 0.278177,-0.278177 0.52476,-0.599329 0.71875,-1.09375 C 33.44074,27.15904 33.520753,26.872957 33.5,26.4375 33.47925,26.002043 33.289697,25.383443 32.875,24.96875 L 31.34375,23.4375 c -0.414688,-0.414694 -1.03329,-0.604245 -1.46875,-0.625 -0.43546,-0.02076 -0.721537,0.05925 -0.96875,0.15625 -0.494426,0.193991 -0.815572,0.44057 -1.09375,0.71875 l -0.09375,0.09375 0,-0.125 c 0,-0.382218 -0.0541,-0.740493 -0.25,-1.21875 -0.09112,-0.22245 -0.228127,-0.500183 -0.5,-0.78125 l 4.71875,-5.3125 a 2.0165107,2.0165107 0 0 0 -1.5,-3.375 l -1.15625,0 0,-3.9687502 A 2.0165107,2.0165107 0 0 0 27,6.9687498 l -6,0 z M 24.3125,31.25 c 0.427097,0 0.75,0.322904 0.75,0.75 0,0.427096 -0.322903,0.75 -0.75,0.75 -0.427094,0 -0.75,-0.322906 -0.75,-0.75 0,-0.427094 0.322906,-0.75 0.75,-0.75 z"/>
<path style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path4294" d="m 20.90625,8.0312498 a 0.96385067,0.96385067 0 0 0 -0.875,0.96875 l 0,5.0312502 -2.21875,0 A 0.96385067,0.96385067 0 0 0 17.09375,15.625 l 5.78125,6.53125 c -0.158814,0.0616 -0.341836,0.0951 -0.4375,0.1875 -0.169161,0.163386 -0.252971,0.323419 -0.3125,0.46875 -0.119058,0.290663 -0.15625,0.566746 -0.15625,0.84375 l 0,1.65625 C 21.718163,25.40233 21.485871,25.509772 21.25,25.625 l -1.1875,-1.1875 c -0.199651,-0.19965 -0.421433,-0.352095 -0.71875,-0.46875 -0.148659,-0.05833 -0.329673,-0.104846 -0.5625,-0.09375 -0.232827,0.0111 -0.53583,0.09833 -0.75,0.3125 L 16.5,25.71875 c -0.214168,0.214168 -0.301403,0.517173 -0.3125,0.75 -0.0111,0.232827 0.03542,0.41384 0.09375,0.5625 0.116655,0.297321 0.269096,0.519099 0.46875,0.71875 l 1.1875,1.1875 c -0.115228,0.235871 -0.222668,0.468163 -0.3125,0.71875 l -1.65625,0 c -0.277003,0 -0.553087,0.03719 -0.84375,0.15625 -0.145332,0.05953 -0.305363,0.143338 -0.46875,0.3125 -0.163387,0.169162 -0.3125,0.46403 -0.3125,0.78125 l 0,2.1875 c 0,0.317221 0.149114,0.612089 0.3125,0.78125 0.163386,0.169161 0.323419,0.252971 0.46875,0.3125 0.290663,0.119058 0.566746,0.15625 0.84375,0.15625 l 1.65625,0 c 0.08983,0.250587 0.197272,0.482879 0.3125,0.71875 L 16.75,36.25 c -0.199649,0.19965 -0.352095,0.421432 -0.46875,0.71875 -0.05833,0.148659 -0.104846,0.329672 -0.09375,0.5625 0.0111,0.232828 0.09833,0.535831 0.3125,0.75 l 1.53125,1.53125 c 0.214168,0.214172 0.517172,0.301403 0.75,0.3125 0.232828,0.0111 0.41384,-0.03542 0.5625,-0.09375 0.29732,-0.116655 0.519098,-0.269096 0.71875,-0.46875 L 21.25,38.375 c 0.235871,0.115228 0.468164,0.222668 0.71875,0.3125 l 0,1.65625 c 0,0.277003 0.03719,0.553087 0.15625,0.84375 0.05953,0.145331 0.143339,0.305364 0.3125,0.46875 0.169161,0.163386 0.464028,0.3125 0.78125,0.3125 l 2.1875,0 c 0.317221,0 0.612089,-0.149113 0.78125,-0.3125 0.169161,-0.163387 0.252971,-0.323419 0.3125,-0.46875 0.119057,-0.290663 0.15625,-0.566748 0.15625,-0.84375 l 0,-1.65625 c 0.250586,-0.08983 0.482879,-0.197272 0.71875,-0.3125 l 1.1875,1.1875 c 0.19965,0.199649 0.421432,0.352095 0.71875,0.46875 0.148659,0.05833 0.329672,0.104846 0.5625,0.09375 0.232828,-0.0111 0.535831,-0.09833 0.75,-0.3125 L 32.125,38.28125 c 0.214172,-0.214168 0.301403,-0.517172 0.3125,-0.75 0.0111,-0.232828 -0.03542,-0.41384 -0.09375,-0.5625 C 32.227095,36.67143 32.074654,36.449652 31.875,36.25 L 30.6875,35.0625 C 30.802728,34.82663 30.910168,34.594337 31,34.34375 l 1.65625,0 c 0.277004,0 0.553087,-0.03719 0.84375,-0.15625 0.145332,-0.05953 0.305364,-0.143339 0.46875,-0.3125 0.163386,-0.169161 0.3125,-0.46403 0.3125,-0.78125 l 0,-2.1875 c 0,-0.317219 -0.149114,-0.612088 -0.3125,-0.78125 C 33.805364,29.955838 33.645332,29.872029 33.5,29.8125 33.209336,29.693442 32.933253,29.65625 32.65625,29.65625 l -1.65625,0 C 30.91017,29.405663 30.802728,29.17337 30.6875,28.9375 L 31.875,27.75 c 0.19965,-0.19965 0.352095,-0.421432 0.46875,-0.71875 0.05833,-0.148659 0.104846,-0.329672 0.09375,-0.5625 -0.0111,-0.232828 -0.09833,-0.535831 -0.3125,-0.75 L 30.59375,24.1875 c -0.214167,-0.21417 -0.517171,-0.301403 -0.75,-0.3125 -0.232829,-0.0111 -0.41384,0.03542 -0.5625,0.09375 -0.29732,0.116656 -0.519099,0.269097 -0.71875,0.46875 L 27.375,25.625 c -0.235871,-0.115228 -0.468163,-0.222668 -0.71875,-0.3125 l 0,-1.65625 c 0,-0.277003 -0.03719,-0.553087 -0.15625,-0.84375 -0.05953,-0.145332 -0.143338,-0.305363 -0.3125,-0.46875 -0.169162,-0.163387 -0.46403,-0.3125 -0.78125,-0.3125 l -0.15625,0 5.65625,-6.40625 A 0.96385067,0.96385067 0 0 0 30.1875,14.03125 l -2.21875,0 0,-5.0312502 A 0.96385067,0.96385067 0 0 0 27,8.0312498 l -6,0 a 0.96385067,0.96385067 0 0 0 -0.09375,0 z M 24.3125,30.1875 c 1.002113,0 1.8125,0.810388 1.8125,1.8125 0,1.002112 -0.810387,1.8125 -1.8125,1.8125 C 23.31039,33.8125 22.5,33.002111 22.5,32 c 0,-1.002111 0.81039,-1.8125 1.8125,-1.8125 z"/>
<path style="fill:url(#radialGradient2985);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path2317" d="M 21,8.9999996 21,15 17.8125,15 24,22 30.1875,15 27,15 l 0,-6.0000004 -6,0 z M 23.21875,23 c -0.172892,0 -0.28125,0.294922 -0.28125,0.65625 l 0,2.28125 C 22.24145,26.095996 21.585954,26.379869 21,26.75 l -1.625,-1.625 c -0.255498,-0.255497 -0.533998,-0.372253 -0.65625,-0.25 l -1.53125,1.53125 c -0.122254,0.122254 -0.0055,0.400753 0.25,0.65625 l 1.625,1.625 c -0.37013,0.585953 -0.654003,1.24145 -0.8125,1.9375 l -2.28125,0 c -0.361328,0 -0.65625,0.108357 -0.65625,0.28125 l 0,2.1875 c 0,0.172892 0.294922,0.28125 0.65625,0.28125 l 2.28125,0 c 0.158497,0.69605 0.44237,1.351546 0.8125,1.9375 l -1.625,1.625 c -0.255497,0.255498 -0.372254,0.533997 -0.25,0.65625 l 1.53125,1.53125 c 0.122252,0.122254 0.400752,0.0055 0.65625,-0.25 L 21,37.25 c 0.585954,0.37013 1.24145,0.654002 1.9375,0.8125 l 0,2.28125 C 22.9375,40.705077 23.045858,41 23.21875,41 l 2.1875,0 c 0.172893,0 0.28125,-0.294924 0.28125,-0.65625 l 0,-2.28125 c 0.69605,-0.158498 1.351546,-0.44237 1.9375,-0.8125 l 1.625,1.625 c 0.255498,0.255497 0.533997,0.372254 0.65625,0.25 l 1.53125,-1.53125 c 0.122254,-0.122252 0.0055,-0.400752 -0.25,-0.65625 l -1.625,-1.625 c 0.370129,-0.585954 0.654003,-1.24145 0.8125,-1.9375 l 2.28125,0 c 0.361329,0 0.65625,-0.108358 0.65625,-0.28125 l 0,-2.1875 c 0,-0.172893 -0.294921,-0.28125 -0.65625,-0.28125 l -2.28125,0 c -0.158497,-0.69605 -0.442371,-1.351547 -0.8125,-1.9375 l 1.625,-1.625 c 0.255497,-0.255497 0.372254,-0.533997 0.25,-0.65625 L 29.90625,24.875 C 29.783997,24.752745 29.505498,24.8695 29.25,25.125 l -1.625,1.625 c -0.585954,-0.370131 -1.24145,-0.654004 -1.9375,-0.8125 l 0,-2.28125 C 25.6875,23.294922 25.579143,23 25.40625,23 l -2.1875,0 z m 1.09375,6.21875 c 1.528616,0 2.78125,1.252635 2.78125,2.78125 0,1.528615 -1.252634,2.78125 -2.78125,2.78125 -1.528614,0 -2.78125,-1.252635 -2.78125,-2.78125 0,-1.528615 1.252636,-2.78125 2.78125,-2.78125 z"/>
<rect style="opacity:0.4;fill:none;stroke:url(#linearGradient2982);stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" id="rect6741" y="6.4999886" x="5.4999981" ry="1.365193" rx="1.365193" height="37.000011" width="36.999985"/>
<path style="fill:none;stroke:url(#linearGradient2979);stroke-width:0.99829447;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" id="path2777" d="M 28.926376,15.466668 24,21.177578 18.963089,15.5 21.5,15.5 l 0,-6.0000004 5,0 0,6.0000004 2.426376,-0.03333 z"/>
<path style="fill:none;stroke:url(#linearGradient2975);stroke-width:1;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path4243" d="m 23.4375,23.46875 c -0.01166,0.05381 -0.03125,0.100205 -0.03125,0.1875 l 0,2.28125 a 0.48185467,0.48185467 0 0 1 -0.375,0.46875 c -0.638467,0.145384 -1.238423,0.407111 -1.78125,0.75 a 0.48185467,0.48185467 0 0 1 -0.59375,-0.0625 l -1.625,-1.625 C 18.9779,25.4154 18.9477,25.40242 18.90625,25.375 l -1.21875,1.21875 c 0.02742,0.04145 0.0404,0.07165 0.09375,0.125 l 1.625,1.625 a 0.48185467,0.48185467 0 0 1 0.0625,0.59375 c -0.342888,0.542826 -0.604615,1.142782 -0.75,1.78125 a 0.48185467,0.48185467 0 0 1 -0.46875,0.375 l -2.28125,0 c -0.08729,0 -0.133695,0.01959 -0.1875,0.03125 l 0,1.75 c 0.05381,0.01166 0.100205,0.03125 0.1875,0.03125 l 2.28125,0 a 0.48185467,0.48185467 0 0 1 0.46875,0.375 c 0.145385,0.638468 0.407112,1.238423 0.75,1.78125 a 0.48185467,0.48185467 0 0 1 -0.0625,0.59375 l -1.625,1.625 c -0.05335,0.05335 -0.06633,0.08355 -0.09375,0.125 l 1.21875,1.21875 c 0.04145,-0.02742 0.07165,-0.0404 0.125,-0.09375 l 1.625,-1.625 A 0.48185467,0.48185467 0 0 1 21.25,36.84375 c 0.542827,0.342888 1.142781,0.604614 1.78125,0.75 a 0.48185467,0.48185467 0 0 1 0.375,0.46875 l 0,2.28125 c 0,0.08729 0.01959,0.133695 0.03125,0.1875 l 1.75,0 c 0.01166,-0.0538 0.03125,-0.100206 0.03125,-0.1875 l 0,-2.28125 a 0.48185467,0.48185467 0 0 1 0.375,-0.46875 c 0.638469,-0.145386 1.238423,-0.407112 1.78125,-0.75 a 0.48185467,0.48185467 0 0 1 0.59375,0.0625 l 1.625,1.625 c 0.05335,0.05335 0.08355,0.06633 0.125,0.09375 l 1.21875,-1.21875 c -0.02742,-0.04145 -0.0404,-0.07165 -0.09375,-0.125 l -1.625,-1.625 a 0.48185467,0.48185467 0 0 1 -0.0625,-0.59375 c 0.342888,-0.542828 0.604615,-1.142783 0.75,-1.78125 a 0.48185467,0.48185467 0 0 1 0.46875,-0.375 l 2.28125,0 c 0.08729,0 0.133695,-0.01959 0.1875,-0.03125 l 0,-1.75 c -0.0538,-0.01166 -0.100204,-0.03125 -0.1875,-0.03125 l -2.28125,0 a 0.48185467,0.48185467 0 0 1 -0.46875,-0.375 c -0.145385,-0.638467 -0.407113,-1.238424 -0.75,-1.78125 a 0.48185467,0.48185467 0 0 1 0.0625,-0.59375 l 1.625,-1.625 c 0.05335,-0.05335 0.06633,-0.08355 0.09375,-0.125 L 29.71875,25.375 c -0.04145,0.02742 -0.07165,0.0404 -0.125,0.09375 l -1.625,1.625 a 0.48185467,0.48185467 0 0 1 -0.59375,0.0625 c -0.542827,-0.342889 -1.142783,-0.604616 -1.78125,-0.75 a 0.48185467,0.48185467 0 0 1 -0.375,-0.46875 l 0,-2.28125 c 0,-0.0873 -0.01959,-0.133695 -0.03125,-0.1875 l -1.75,0 z m 0.875,5.28125 c 1.791829,0 3.25,1.458172 3.25,3.25 0,1.791828 -1.458171,3.25 -3.25,3.25 -1.791827,0 -3.25,-1.458172 -3.25,-3.25 0,-1.791828 1.458173,-3.25 3.25,-3.25 z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,75 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="48" height="48" viewBox="0 0 48.000001 48.000001" id="svg4230" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="fdroid-logo.svg">
<defs id="defs4232">
<linearGradient inkscape:collect="always" id="linearGradient5212">
<stop style="stop-color:#ffffff;stop-opacity:0.09803922" offset="0" id="stop5214"/>
<stop style="stop-color:#ffffff;stop-opacity:0" offset="1" id="stop5216"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient5212" id="radialGradient5220" cx="-98.23381" cy="3.4695871" fx="-98.23381" fy="3.4695871" r="22.671185" gradientTransform="matrix(0,1.9747624,-2.117225,3.9784049e-8,8.677247,1199.588)" gradientUnits="userSpaceOnUse"/>
<filter inkscape:collect="always" style="color-interpolation-filters:sRGB" id="filter4175" x="-0.023846937" width="1.0476939" y="-0.02415504" height="1.0483101">
<feGaussianBlur inkscape:collect="always" stdDeviation="0.45053152" id="feGaussianBlur4177"/>
</filter>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="11.313708" inkscape:cx="6.4184057" inkscape:cy="25.737489" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" units="px" inkscape:window-width="1920" inkscape:window-height="1009" inkscape:window-x="0" inkscape:window-y="34" inkscape:window-maximized="1" gridtolerance="10000"/>
<metadata id="metadata4235">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(0,-1004.3622)">
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#263238;fill-opacity:0.4;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4175);color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 2.613462,1006.3488 a 1.250125,1.250125 0 0 0 -1.01172,2.0293 l 3.60351,4.6641 c -0.12699,0.3331 -0.20312,0.6915 -0.20312,1.0703 l 0,4 0,2.8652 0,0.1348 c 0,1.662 1.338,3 3,3 l 32,0 c 1.662,0 3,-1.338 3,-3 l 0,-4 0,-2.8652 0,-0.1348 c 0,-0.3803 -0.0771,-0.74 -0.20508,-1.0742 l 3.60156,-4.6602 a 1.250125,1.250125 0 0 0 -1.04882,-2.0273 1.250125,1.250125 0 0 0 -0.92969,0.498 l -3.43164,4.4414 c -0.31022,-0.1079 -0.63841,-0.1777 -0.98633,-0.1777 l -32,0 c -0.34857,0 -0.67757,0.069 -0.98828,0.1777 l -3.4336,-4.4414 a 1.250125,1.250125 0 0 0 -0.96679,-0.5 z m 5.38867,18.7637 c -0.20775,0 -0.40983,0.021 -0.60547,0.061 -1.36951,0.2761 -2.39453,1.4698 -2.39453,2.9101 l 0,0.029 0,19.7793 0,0.029 0,0.1914 c 0,1.662 1.338,3 3,3 l 32,0 c 1.662,0 3,-1.338 3,-3 l 0,-20 0,-0.029 c 0,-1.4403 -1.02502,-2.634 -2.39453,-2.9101 -0.19565,-0.039 -0.39772,-0.061 -0.60547,-0.061 l -32,0 z" id="path4192" inkscape:connector-curvature="0"/>
<g id="g5012">
<g id="g4179" transform="matrix(-1,0,0,1,47.999779,0)">
<path style="fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:#769616;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m 2.5889342,1006.8622 4.25,5.5" id="path4181" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
<path sodipodi:nodetypes="cccccc" inkscape:connector-curvature="0" id="path4183" d="m 2.6113281,1005.6094 c -0.4534623,0.012 -0.7616975,0.189 -0.9807462,0.4486 2.0269314,2.4089 2.368401,2.7916 5.1354735,6.2214 1.0195329,1.319 2.0816026,0.6373 1.0620696,-0.6817 l -4.25,-5.5 c -0.2289894,-0.3056 -0.5850813,-0.478 -0.9667969,-0.4883 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:0.29803923;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
<path sodipodi:nodetypes="ccccc" inkscape:connector-curvature="0" id="path4185" d="m 1.6220992,1006.0705 c -0.1238933,0.1479 -0.561176,0.8046 -0.02249,1.5562 l 4.25,5.5 c 1.0195329,1.319 1.1498748,-0.6123 1.1498748,-0.6123 0,0 -3.7344514,-4.51 -5.3773848,-6.4439 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#263238;fill-opacity:0.2;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
<path sodipodi:nodetypes="cscccc" inkscape:connector-curvature="0" id="path4187" d="m 2.3378905,1005.8443 c -0.438175,0 -0.959862,0.1416 -0.8242183,0.7986 0.103561,0.5016 4.6608262,6.0744 4.6608262,6.0744 1.0195329,1.319 2.4934721,0.6763 1.4739391,-0.6425 l -4.234375,-5.4727 c -0.2602394,-0.29 -0.6085188,-0.7436 -1.076172,-0.7578 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
</g>
<g id="g4955">
<path sodipodi:nodetypes="cc" inkscape:connector-curvature="0" id="path4945" d="m 2.5889342,1006.8622 4.25,5.5" style="fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:#769616;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:0.29803923;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 2.6113281,1005.6094 c -0.4534623,0.012 -0.7616975,0.189 -0.9807462,0.4486 2.0269314,2.4089 2.368401,2.7916 5.1354735,6.2214 1.0195329,1.319 2.0816026,0.6373 1.0620696,-0.6817 l -4.25,-5.5 c -0.2289894,-0.3056 -0.5850813,-0.478 -0.9667969,-0.4883 z" id="path4947" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#263238;fill-opacity:0.2;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 1.6220992,1006.0705 c -0.1238933,0.1479 -0.561176,0.8046 -0.02249,1.5562 l 4.25,5.5 c 1.0195329,1.319 1.1498748,-0.6123 1.1498748,-0.6123 0,0 -3.7344514,-4.51 -5.3773848,-6.4439 z" id="path4951" inkscape:connector-curvature="0" sodipodi:nodetypes="ccccc"/>
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#8ab000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 2.3378905,1005.8443 c -0.438175,0 -0.959862,0.1416 -0.8242183,0.7986 0.103561,0.5016 4.6608262,6.0744 4.6608262,6.0744 1.0195329,1.319 2.4934721,0.6763 1.4739391,-0.6425 l -4.234375,-5.4727 c -0.2602394,-0.29 -0.6085188,-0.7436 -1.076172,-0.7578 z" id="path4925" inkscape:connector-curvature="0" sodipodi:nodetypes="cscccc"/>
</g>
<g transform="translate(42,0)" id="g4967">
<rect style="opacity:1;fill:#aeea00;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="rect4144" width="38" height="13" x="-37" y="1010.3622" rx="3" ry="3"/>
<rect ry="3" rx="3" y="1013.3622" x="-37" height="10" width="38" id="rect4961" style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/>
<rect ry="3" rx="3" y="1010.3622" x="-37" height="10" width="38" id="rect4963" style="opacity:1;fill:#ffffff;fill-opacity:0.29803923;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/>
<rect ry="2.5384617" rx="3" y="1011.3622" x="-37" height="11" width="38" id="rect4965" style="opacity:1;fill:#aeea00;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/>
</g>
<g id="g4979">
<rect style="opacity:1;fill:#1976d2;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="rect4146" width="38" height="26" x="5" y="1024.3622" rx="3" ry="3"/>
<rect ry="3" rx="3" y="1037.3622" x="5" height="13" width="38" id="rect4973" style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/>
<rect ry="3" rx="3" y="1024.3622" x="5" height="13" width="38" id="rect4975" style="opacity:1;fill:#ffffff;fill-opacity:0.2;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/>
<rect ry="2.7692308" rx="3" y="1025.3622" x="5" height="24" width="38" id="rect4977" style="opacity:1;fill:#1976d2;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"/>
</g>
<g transform="translate(0,1013.3622)" id="g4211">
<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0d47a1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 24,17.75 c -2.880662,0 -5.319789,1.984685 -6.033203,4.650391 l 3.212891,0 C 21.734004,21.415044 22.774798,20.75 24,20.75 c 1.812692,0 3.25,1.437308 3.25,3.25 0,1.812693 -1.437308,3.25 -3.25,3.25 -1.307381,0 -2.411251,-0.75269 -2.929688,-1.849609 l -3.154296,0 C 18.558263,28.166146 21.04791,30.25 24,30.25 c 3.434013,0 6.25,-2.815987 6.25,-6.25 0,-3.434012 -2.815987,-6.25 -6.25,-6.25 z" id="path4161" inkscape:connector-curvature="0"/>
<circle style="opacity:1;fill:none;fill-opacity:0.40392157;stroke:#0d47a1;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" id="path4209" cx="24" cy="24" r="9.5500002"/>
</g>
<g id="g4989" transform="translate(0,0.50001738)">
<ellipse cy="1016.4872" cx="14.375" id="circle4985" style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117" rx="3.375" ry="3.875"/>
<circle style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117" id="path4859" cx="14.375" cy="1016.9872" r="3.375"/>
</g>
<g transform="translate(19.5,0.50001738)" id="g4171">
<ellipse ry="3.875" rx="3.375" style="opacity:1;fill:#263238;fill-opacity:0.2;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117" id="ellipse4175" cx="14.375" cy="1016.4872"/>
<circle r="3.375" cy="1016.9872" cx="14.375" id="circle4177" style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.69721117"/>
</g>
</g>
<path inkscape:connector-curvature="0" id="path5128" d="m 2.613462,1005.5987 a 1.250125,1.250125 0 0 0 -1.01172,2.0293 l 3.60351,4.6641 c -0.12699,0.3331 -0.20312,0.6915 -0.20312,1.0703 l 0,4 0,2.8652 0,0.1348 c 0,1.662 1.338,3 3,3 l 32,0 c 1.662,0 3,-1.338 3,-3 l 0,-4 0,-2.8652 0,-0.1348 c 0,-0.3803 -0.0771,-0.74 -0.20508,-1.0742 l 3.60156,-4.6602 a 1.250125,1.250125 0 0 0 -1.04882,-2.0273 1.250125,1.250125 0 0 0 -0.92969,0.498 l -3.43164,4.4414 c -0.31022,-0.1079 -0.63841,-0.1777 -0.98633,-0.1777 l -32,0 c -0.34857,0 -0.67757,0.069 -0.98828,0.1777 l -3.4336,-4.4414 a 1.250125,1.250125 0 0 0 -0.96679,-0.5 z m 5.38867,18.7637 c -0.20775,0 -0.40983,0.021 -0.60547,0.061 -1.36951,0.2761 -2.39453,1.4698 -2.39453,2.9101 l 0,0.029 0,19.7793 0,0.029 0,0.1914 c 0,1.662 1.338,3 3,3 l 32,0 c 1.662,0 3,-1.338 3,-3 l 0,-20 0,-0.029 c 0,-1.4403 -1.02502,-2.634 -2.39453,-2.9101 -0.19565,-0.039 -0.39772,-0.061 -0.60547,-0.061 l -32,0 z" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#radialGradient5220);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 511.999 511.999" xml:space="preserve">
<g>
<path style="fill:#32BBFF;" d="M382.369,175.623C322.891,142.356,227.427,88.937,79.355,6.028
C69.372-0.565,57.886-1.429,47.962,1.93l254.05,254.05L382.369,175.623z"/>
<path style="fill:#32BBFF;" d="M47.962,1.93c-1.86,0.63-3.67,1.39-5.401,2.308C31.602,10.166,23.549,21.573,23.549,36v439.96
c0,14.427,8.052,25.834,19.012,31.761c1.728,0.917,3.537,1.68,5.395,2.314L302.012,255.98L47.962,1.93z"/>
<path style="fill:#32BBFF;" d="M302.012,255.98L47.956,510.035c9.927,3.384,21.413,2.586,31.399-4.103
c143.598-80.41,237.986-133.196,298.152-166.746c1.675-0.941,3.316-1.861,4.938-2.772L302.012,255.98z"/>
</g>
<path style="fill:#2C9FD9;" d="M23.549,255.98v219.98c0,14.427,8.052,25.834,19.012,31.761c1.728,0.917,3.537,1.68,5.395,2.314
L302.012,255.98H23.549z"/>
<path style="fill:#29CC5E;" d="M79.355,6.028C67.5-1.8,53.52-1.577,42.561,4.239l255.595,255.596l84.212-84.212
C322.891,142.356,227.427,88.937,79.355,6.028z"/>
<path style="fill:#D93F21;" d="M298.158,252.126L42.561,507.721c10.96,5.815,24.939,6.151,36.794-1.789
c143.598-80.41,237.986-133.196,298.152-166.746c1.675-0.941,3.316-1.861,4.938-2.772L298.158,252.126z"/>
<path style="fill:#FFD500;" d="M488.45,255.98c0-12.19-6.151-24.492-18.342-31.314c0,0-22.799-12.721-92.682-51.809l-83.123,83.123
l83.204,83.205c69.116-38.807,92.6-51.892,92.6-51.892C482.299,280.472,488.45,268.17,488.45,255.98z"/>
<path style="fill:#FFAA00;" d="M470.108,287.294c12.191-6.822,18.342-19.124,18.342-31.314H294.303l83.204,83.205
C446.624,300.379,470.108,287.294,470.108,287.294z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -66,30 +66,8 @@
<a
class="w3-button w3-black w3-padding-large"
href="https://dev.tildefriends.net/"
><i class="fa fa-mug-hot"></i> Development</a
><i class="fa fa-mug-hot"></i> Code</a
>
<p>
<a
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://f-droid.org/en/packages/com.unprompted.tildefriends.fdroid/"
><img src="f-droid.svg" style="height: 2em; margin: 0" /> Get it
on F-Droid</a
>
<a
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://dev.tildefriends.net/releases/tildefriends-x86_64.AppImage"
>
<img src="appimage.svg" style="height: 2em; margin: 0" />
Get Linux 64-bit AppImage
</a>
<a
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://play.google.com/store/apps/details?id=com.unprompted.tildefriends"
>
<img src="googleplay.svg" style="height: 2em; margin: 0" />
Get it on Google Play (Open Testing)
</a>
</p>
</div>
<div class="w3-col l4 m6">
<img src="tildefriends.png" class="w3-image w3-right w3-hide-small" />
@ -110,31 +88,36 @@
<a href="https://dev.tildefriends.net/cory/tildefriends/releases"
>Download</a
>
Tilde Friends or use
Tilde Friends and run your own instance, or use
<a href="https://www.tildefriends.net/"
>https://www.tildefriends.net/</a
>.
</li>
<li>Create an account to identify yourself with that instance.</li>
<li>
Create an account to identify yourself with that instance by
username and password.
</li>
<li>
Create an SSB identity in the <b>ssb</b> app. This will generate a
keypair used to identify yourself to other users and sign your
messages so that they can be verified as from you.
</li>
<li>
Describe yourself in your profile in the <b>ssb</b> app. Give
yourself a name and an avatar if you like.
</li>
<li>
Connect to others.
<ul>
<li>Automatically discover peers on the same network.</li>
<li>
Manually connect to rooms and pubs, including
Connect to others. You will automatically discover peers on the
same instance and same network if there are any. Or use
<a href="https://github.com/staltz/ssb-room/blob/master/FAQ.md"
>rooms</a
>
and pubs to reach more distant users.
<a href="https://www.tildefriends.net/~cory/room/"
>tildefriends.net itself</a
>.
</li>
<li>
Enable <b>Peer Exchange</b> in the <b>admin</b> to discover
internet peers.
</li>
</ul>
>
operates as a room, so you can connect and see who else is online
and establish a connection.
</li>
<li>Follow people to grow your network.</li>
<li>
@ -223,13 +206,8 @@
<!-- Technlology Section -->
<div class="w3-container w3-padding-64 w3-light-grey w3-center">
<h1 class="w3-jumbo"><b>Boring Technology</b></h1>
<p>
Tilde Friends is built using boring, trusted tech. Unless a better
reason presents itself, it strives to use only simple and widely adopted
dependencies in order to keep it easy to build for all sorts of
platforms and maintainable for a very long time.
</p>
<h1 class="w3-jumbo"><b>Trusted Technology</b></h1>
<p>Tilde Friends is built using boring, trusted tech.</p>
<p>
Though of course for building Tilde Friends apps, you are free to use
whatever fits.
@ -266,7 +244,7 @@
<i class="fa fa-lock w3-text-purple w3-jumbo"></i>
<p>libsodium</p>
</a>
<a href="https://github.com/openssl/openssl/releases" class="w3-col s3">
<a href="https://www.openssl.org/" class="w3-col s3">
<i class="fa fa-shield-halved w3-text-green w3-jumbo"></i>
<p>OpenSSL</p>
</a>
@ -292,13 +270,6 @@
<i class="fa fa-fire w3-text-cyan w3-jumbo"></i>
<p>Lit</p>
</a>
<a href="https://github.com/c-ares/c-ares" class="w3-col s3">
<i class="fa fa-book-atlas w3-text-purple w3-jumbo"></i>
<p>c-ares</p>
</a>
</div>
<div class="w3-row" style="margin-top: 64px">
<a href="https://www.gnu.org/software/make/" class="w3-col s3">
<i class="fa fa-hammer w3-text-teal w3-jumbo"></i>
<p>GNU Make</p>

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "📝",
"previous": "&4UHlsfQJvSh7L3D86uFtr7KUKCMRVBBTFxRIMqIc5as=.sha256"
"previous": "&DaYqKHRBKhjFGaOzbKZ1+/pLspJeEkDJYTF2B50tH6k=.sha256"
}

File diff suppressed because one or more lines are too long

View File

@ -2,8 +2,8 @@ import * as utils from './utils.js';
import * as commonmark from './commonmark.min.js';
function markdown(md) {
let reader = new commonmark.Parser();
let writer = new commonmark.HtmlRenderer({safe: true});
let reader = new commonmark.Parser({safe: true});
let writer = new commonmark.HtmlRenderer();
let parsed = reader.parse(md || '');
let walker = parsed.walker();
let event;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -20,8 +20,8 @@ class TfWikiDocElement extends LitElement {
}
markdown(md) {
let reader = new commonmark.Parser();
let writer = new commonmark.HtmlRenderer({safe: true});
let reader = new commonmark.Parser({safe: true});
let writer = new commonmark.HtmlRenderer();
let parsed = reader.parse(md || '');
let walker = parsed.walker();
let event;

View File

@ -10,7 +10,7 @@ let gSessionIndex = 0;
* @returns
*/
function makeSessionId() {
return 'session_' + (gSessionIndex++).toString();
return (gSessionIndex++).toString();
}
/**
@ -172,7 +172,11 @@ async function socket(request, response, client) {
0x1
);
} else {
process = await core.getProcessBlob(blobId, sessionId, options);
process = await core.getSessionProcessBlob(
blobId,
sessionId,
options
);
}
}
if (process) {

View File

@ -56,7 +56,7 @@ class TfNavigationElement extends LitElement {
status: {type: Object},
spark_lines: {type: Object},
version: {type: Object},
show_expanded: {type: Boolean},
show_version: {type: Boolean},
identity: {type: String},
identities: {type: Array},
names: {type: Object},
@ -105,6 +105,7 @@ class TfNavigationElement extends LitElement {
let spark_line = document.createElement('tf-sparkline');
spark_line.title = key;
spark_line.classList.add('w3-bar-item');
spark_line.classList.add('w3-hide-small');
spark_line.style.paddingRight = '0';
if (options) {
if (options.max) {
@ -161,10 +162,6 @@ class TfNavigationElement extends LitElement {
class="w3-dropdown-content w3-bar-block w3-card-4"
style="max-width: 100%; right: 0"
>
<div
style="position: fixed; left: 0; right: 0; top: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.25); z-index: -100"
@click=${self.toggle_id_dropdown}
></div>
<button
class="w3-bar-item w3-button w3-border"
@click=${() => (window.location.href = '/~core/identity')}
@ -172,7 +169,6 @@ class TfNavigationElement extends LitElement {
Manage Identities...
</button>
<button
id="edit_profile"
class="w3-bar-item w3-button w3-border"
@click=${self.edit_profile}
>
@ -315,13 +311,13 @@ class TfNavigationElement extends LitElement {
<span
class="w3-bar-item"
style="cursor: pointer"
@click=${() => (this.show_expanded = !this.show_expanded)}
@click=${() => (this.show_version = !this.show_version)}
>😎</span
>
<span
class="w3-bar-item"
style=${'white-space: nowrap' +
(this.show_expanded ? '' : '; display: none')}
(this.show_version ? '' : '; display: none')}
title=${this.version?.name +
' ' +
Object.entries(this.version || {})
@ -376,11 +372,9 @@ class TfNavigationElement extends LitElement {
</div>
`
: undefined}
<span class=${this.show_expanded ? '' : 'w3-hide-small'}>
${Object.keys(this.spark_lines)
.sort()
.map((x) => this.spark_lines[x])}
</span>
${this.render_identity()}
</div>
${this.status?.is_error
@ -388,8 +382,8 @@ class TfNavigationElement extends LitElement {
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
<div class="w3-model w3-animate-top" style="position: absolute; left: 50%; transform: translate(-50%); z-index: 1">
<dijv class="w3-modal-content w3-card-4" style="display: block; padding: 1em">
<span id="close_error" @click=${self.clear_error} class="w3-button w3-display-topright">&times;</span>
<div style="color: ${this.status.color ?? kErrorColor}"><b>ERROR:</b><p id="error" style="white-space: pre">${this.status.message}</p></div>
<span @click=${self.clear_error} class="w3-button w3-display-topright">&times;</span>
<div style="color: ${this.status.color ?? kErrorColor}"><b>ERROR:</b><p style="white-space: pre">${this.status.message}</p></div>
</div>
</div>
`
@ -1196,7 +1190,6 @@ function api_requestPermission(permission, id) {
check.classList.add('w3-check');
check.classList.add('w3-blue');
div.appendChild(check);
div.appendChild(document.createTextNode(' '));
let label = document.createElement('label');
label.htmlFor = check.id;
label.appendChild(document.createTextNode('Remember this decision.'));
@ -1789,11 +1782,10 @@ async function sourcePretty() {
let prettier = (await import('/prettier/standalone.mjs')).default;
let babel = (await import('/prettier/babel.mjs')).default;
let estree = (await import('/prettier/estree.mjs')).default;
let prettier_html = (await import('/prettier/html.mjs')).default;
let source = gEditor.state.doc.toString();
let formatted = await prettier.format(source, {
parser: gCurrentFile?.toLowerCase()?.endsWith('.html') ? 'html' : 'babel',
plugins: [babel, estree, prettier_html],
parser: 'babel',
plugins: [babel, estree],
trailingComma: 'es5',
useTabs: true,
semi: true,
@ -1828,8 +1820,8 @@ function toggleVisibleWhitespace() {
.cm-highlightTab {
background-image: unset !important;
}
.cm-highlightSpace {
background-image: unset !important;
.cm-highlightSpace:before {
content: unset !important;
}
`;
window.localStorage.setItem('visible_whitespace', '1');

View File

@ -4,6 +4,72 @@ import * as http from './http.js';
let gProcesses = {};
let gStatsTimer = false;
const k_content_security_policy =
'sandbox allow-downloads allow-top-navigation-by-user-activation';
const k_global_settings = {
index: {
type: 'string',
default_value: '/~core/apps/',
description: 'Default path.',
},
index_map: {
type: 'textarea',
default_value: undefined,
description:
'Mappings from hostname to redirect path, one per line, as in: "www.tildefriends.net=/~core/index/"',
},
room: {
type: 'boolean',
default_value: true,
description: 'Whether this instance should behave as a room.',
},
room_name: {
type: 'string',
default_value: 'tilde friends tunnel',
description: 'Name of the room.',
},
code_of_conduct: {
type: 'textarea',
default_value: undefined,
description: 'Code of conduct presented at sign-in.',
},
http_redirect: {
type: 'string',
default_value: undefined,
description:
'If connecting by HTTP and HTTPS is configured, Location header prefix (ie, "https://example.com")',
},
fetch_hosts: {
type: 'string',
default_value: undefined,
description:
'Comma-separated list of host names to which HTTP fetch requests are allowed. None if empty.',
},
blob_fetch_age_seconds: {
type: 'integer',
default_value:
platform() == 'android' || platform() == 'iphone'
? 0.5 * 365 * 24 * 60 * 60
: undefined,
description:
'Only blobs mentioned more recently than this age will be automatically fetched.',
},
blob_expire_age_seconds: {
type: 'integer',
default_value:
platform() == 'android' || platform() == 'iphone'
? 1.0 * 365 * 24 * 60 * 60
: undefined,
description: 'Blobs older than this will be automatically deleted.',
},
};
let gGlobalSettings = {
index: '/~core/apps/',
};
let kPingInterval = 60 * 1000;
/**
@ -175,6 +241,23 @@ function postMessageInternal(from, to, message) {
}
}
/**
* TODOC
* @param {*} blobId
* @param {*} session
* @param {*} options
* @returns
*/
async function getSessionProcessBlob(blobId, session, options) {
let actualOptions = {timeout: kPingInterval};
if (options) {
for (let i in options) {
actualOptions[i] = options[i];
}
}
return getProcessBlob(blobId, 'session_' + session, actualOptions);
}
/**
* TODOC
* @param {*} blobId
@ -202,7 +285,7 @@ async function getProcessBlob(blobId, key, options) {
}
process.lastActive = Date.now();
process.lastPing = null;
process.timeout = kPingInterval;
process.timeout = options.timeout;
process.ready = new Promise(function (resolve, reject) {
resolveReady = resolve;
rejectReady = reject;
@ -241,59 +324,59 @@ async function getProcessBlob(blobId, key, options) {
return [];
}
},
permissionsGranted: async function () {
permissionsGranted: function () {
let user = process?.credentials?.session?.name;
let settings = await loadSettings();
if (
user &&
options?.packageOwner &&
options?.packageName &&
settings.userPermissions &&
settings.userPermissions[user] &&
settings.userPermissions[user][options.packageOwner]
gGlobalSettings.userPermissions &&
gGlobalSettings.userPermissions[user] &&
gGlobalSettings.userPermissions[user][options.packageOwner]
) {
return settings.userPermissions[user][options.packageOwner][
options.packageName
];
return gGlobalSettings.userPermissions[user][
options.packageOwner
][options.packageName];
}
},
allPermissionsGranted: async function () {
allPermissionsGranted: function () {
let user = process?.credentials?.session?.name;
let settings = await loadSettings();
if (
user &&
options?.packageOwner &&
options?.packageName &&
settings.userPermissions &&
settings.userPermissions[user]
gGlobalSettings.userPermissions &&
gGlobalSettings.userPermissions[user]
) {
return settings.userPermissions[user];
return gGlobalSettings.userPermissions[user];
}
},
permissionsForUser: async function (user) {
let settings = await loadSettings();
return settings?.permissions?.[user] ?? [];
permissionsForUser: function (user) {
return (
(gGlobalSettings?.permissions
? gGlobalSettings.permissions[user]
: []) ?? []
);
},
apps: (user) => getApps(user, process),
getSockets: getSockets,
permissionTest: async function (permission) {
permissionTest: function (permission) {
let user = process?.credentials?.session?.name;
let settings = await loadSettings();
if (!user || !options?.packageOwner || !options?.packageName) {
return;
} else if (
settings.userPermissions &&
settings.userPermissions[user] &&
settings.userPermissions[user][options.packageOwner] &&
settings.userPermissions[user][options.packageOwner][
gGlobalSettings.userPermissions &&
gGlobalSettings.userPermissions[user] &&
gGlobalSettings.userPermissions[user][options.packageOwner] &&
gGlobalSettings.userPermissions[user][options.packageOwner][
options.packageName
] &&
settings.userPermissions[user][options.packageOwner][
gGlobalSettings.userPermissions[user][options.packageOwner][
options.packageName
][permission] !== undefined
) {
if (
settings.userPermissions[user][options.packageOwner][
gGlobalSettings.userPermissions[user][options.packageOwner][
options.packageName
][permission]
) {
@ -304,9 +387,9 @@ async function getProcessBlob(blobId, key, options) {
} else if (process.app) {
return process.app
.makeFunction(['requestPermission'])(permission)
.then(async function (value) {
.then(function (value) {
if (value == 'allow') {
await ssb.setUserPermission(
storePermission(
user,
options.packageOwner,
options.packageName,
@ -318,7 +401,7 @@ async function getProcessBlob(blobId, key, options) {
} else if (value == 'allow once') {
return true;
} else if (value == 'deny') {
await ssb.setUserPermission(
storePermission(
user,
options.packageOwner,
options.packageName,
@ -405,25 +488,22 @@ async function getProcessBlob(blobId, key, options) {
}
};
if (process.credentials?.permissions?.administration) {
imports.core.globalSettingsDescriptions = async function () {
let settings = Object.assign({}, defaultGlobalSettings());
for (let [key, value] of Object.entries(await loadSettings())) {
imports.core.globalSettingsDescriptions = function () {
let settings = Object.assign({}, k_global_settings);
for (let [key, value] of Object.entries(gGlobalSettings)) {
if (settings[key]) {
settings[key].value = value;
}
}
return settings;
};
imports.core.globalSettingsGet = async function (key) {
let settings = await loadSettings();
return settings?.[key];
imports.core.globalSettingsGet = function (key) {
return gGlobalSettings[key];
};
imports.core.globalSettingsSet = async function (key, value) {
await imports.core.permissionTest('set_global_setting');
imports.core.globalSettingsSet = function (key, value) {
print('Setting', key, value);
let settings = await loadSettings();
settings[key] = value;
await new Database('core').set('settings', JSON.stringify(settings));
gGlobalSettings[key] = value;
setGlobalSettings(gGlobalSettings);
print('Done.');
};
imports.core.deleteUser = async function (user) {
@ -590,24 +670,11 @@ async function getProcessBlob(blobId, key, options) {
);
}
};
imports.ssb.swapWithServerIdentity = function (id) {
if (
process.credentials &&
process.credentials.session &&
process.credentials.session.name
) {
return ssb.swapWithServerIdentity(
process.credentials.session.name,
id
);
}
};
imports.ssb.addEventListener = undefined;
imports.ssb.removeEventListener = undefined;
imports.ssb.getIdentityInfo = undefined;
imports.fetch = async function (url, options) {
let settings = await loadSettings();
return http.fetch(url, options, settings?.fetch_hosts);
imports.fetch = function (url, options) {
return http.fetch(url, options, gGlobalSettings.fetch_hosts);
};
if (
@ -634,12 +701,12 @@ async function getProcessBlob(blobId, key, options) {
Object.keys(db).map((x) => [x, db[x].bind(db)])
);
};
imports.databases = async function () {
imports.databases = function () {
return [].concat(
await databases.list(
databases.list(
':shared:' + process.credentials.session.name + ':%'
),
await databases.list(process.credentials.session.name + ':%')
databases.list(process.credentials.session.name + ':%')
);
};
}
@ -658,22 +725,22 @@ async function getProcessBlob(blobId, key, options) {
);
};
}
process.sendPermissions = async function sendPermissions() {
process.sendPermissions = function sendPermissions() {
process.app.send({
action: 'permissions',
permissions: await imports.core.permissionsGranted(),
permissions: imports.core.permissionsGranted(),
});
};
process.resetPermission = async function resetPermission(permission) {
process.resetPermission = function resetPermission(permission) {
let user = process?.credentials?.session?.name;
await ssb.setUserPermission(
storePermission(
user,
options?.packageOwner,
options?.packageName,
permission,
undefined
);
return process.sendPermissions();
process.sendPermissions();
};
process.task.setImports(imports);
process.task.activate();
@ -706,7 +773,7 @@ async function getProcessBlob(blobId, key, options) {
broadcastEvent('onSessionBegin', [getUser(process, process)]);
if (process.app) {
process.app.send({action: 'ready', version: version()});
await process.sendPermissions();
process.sendPermissions();
}
await process.task.execute({name: appSourceName, source: appSource});
resolveReady(process);
@ -730,6 +797,374 @@ async function getProcessBlob(blobId, key, options) {
return process;
}
/**
* TODOC
* @param {*} settings
* @returns
*/
async function setGlobalSettings(settings) {
gGlobalSettings = settings;
try {
return await new Database('core').set('settings', JSON.stringify(settings));
} catch (error) {
print('Error storing settings:', error);
}
}
/**
* TODOC
* @param {*} response
* @param {*} data
* @param {*} type
* @param {*} headers
* @param {*} status_code
*/
function sendData(response, data, type, headers, status_code) {
if (data) {
response.writeHead(
status_code ?? 200,
Object.assign(
{
'Content-Type':
type ||
httpd.mime_type_from_magic_bytes(data) ||
'application/binary',
'Content-Length': data.byteLength,
},
headers || {}
)
);
response.end(data);
} else {
response.writeHead(
status_code ?? 404,
Object.assign(
{
'Content-Type': 'text/plain; charset=utf-8',
'Content-Length': 'File not found'.length,
},
headers || {}
)
);
response.end('File not found');
}
}
let g_handler_index = 0;
/**
* TODOC
* @param {*} response
* @param {*} handler_blob_id
* @param {*} path
* @param {*} query
* @param {*} headers
* @param {*} packageOwner
* @param {*} packageName
* @returns
*/
async function useAppHandler(
response,
handler_blob_id,
path,
query,
headers,
packageOwner,
packageName
) {
print('useAppHandler', packageOwner, packageName);
let do_resolve;
let promise = new Promise(async function (resolve, reject) {
do_resolve = resolve;
});
let process;
let result;
try {
process = await getProcessBlob(
handler_blob_id,
'handler_' + g_handler_index++,
{
script: 'handler.js',
imports: {
request: {
path: path,
query: query,
},
respond: do_resolve,
},
credentials: await httpd.auth_query(headers),
packageOwner: packageOwner,
packageName: packageName,
}
);
await process.ready;
result = await promise;
} finally {
if (process?.task) {
await process.task.kill();
}
}
return result;
}
/**
* TODOC
* @param {*} request
* @param {*} response
* @param {*} blobId
* @param {*} uri
* @returns
*/
async function blobHandler(request, response, blobId, uri) {
if (!uri) {
response.writeHead(303, {
Location:
(request.client.tls ? 'https://' : 'http://') +
(request.headers['x-forwarded-host'] ?? request.headers.host) +
blobId +
'/',
'Content-Length': '0',
});
response.end();
return;
}
let process;
if (uri == '/view') {
let data;
let match;
let query = form.decodeForm(request.query);
let headers = {
'Content-Security-Policy': k_content_security_policy,
};
if (query.filename && query.filename.match(/^[A-Za-z0-9\.-]*$/)) {
headers['Content-Disposition'] = `attachment; filename=${query.filename}`;
}
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
let id = await new Database(match[1]).get('path:' + match[2]);
if (id) {
if (request.headers['if-none-match'] === '"' + id + '"') {
headers['Content-Length'] = '0';
response.writeHead(304, headers);
response.end();
} else {
data = await ssb.blobGet(id);
if (match[3]) {
let appObject = JSON.parse(data);
data = appObject.files[match[3]];
}
sendData(
response,
data,
undefined,
Object.assign({etag: '"' + id + '"'}, headers)
);
}
} else {
if (request.headers['if-none-match'] === '"' + blobId + '"') {
headers['Content-Length'] = '0';
response.writeHead(304, headers);
response.end();
} else {
sendData(
response,
data,
undefined,
Object.assign({etag: '"' + blobId + '"'}, headers)
);
}
}
} else {
if (request.headers['if-none-match'] === '"' + blobId + '"') {
headers['Content-Length'] = '0';
response.writeHead(304, headers);
response.end();
} else {
data = await ssb.blobGet(blobId);
sendData(
response,
data,
undefined,
Object.assign({etag: '"' + blobId + '"'}, headers)
);
}
}
} else if (uri == '/save') {
let match;
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
let user = match[1];
let appName = match[2];
let credentials = await httpd.auth_query(request.headers);
if (
credentials &&
credentials.session &&
(credentials.session.name == user ||
(credentials.permissions.administration && user == 'core'))
) {
let database = new Database(user);
let app_object = JSON.parse(utf8Decode(request.body));
let previous_id = await database.get('path:' + appName);
if (previous_id) {
try {
let previous_object = JSON.parse(
utf8Decode(await ssb.blobGet(previous_id))
);
delete previous_object.previous;
delete app_object.previous;
if (JSON.stringify(previous_object) == JSON.stringify(app_object)) {
response.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8',
});
response.end('/' + previous_id);
return;
}
} catch {}
}
app_object.previous = previous_id;
let newBlobId = await ssb.blobStore(JSON.stringify(app_object));
let apps = new Set();
let apps_original = await database.get('apps');
try {
apps = new Set(JSON.parse(apps_original));
} catch {}
if (!apps.has(appName)) {
apps.add(appName);
}
apps = JSON.stringify([...apps].sort());
if (apps != apps_original) {
await database.set('apps', apps);
}
await database.set('path:' + appName, newBlobId);
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
response.end('/' + newBlobId);
} else {
response.writeHead(401, {'Content-Type': 'text/plain; charset=utf-8'});
response.end('401 Unauthorized');
return;
}
} else if (blobId === '') {
let newBlobId = await ssb.blobStore(request.body);
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
response.end('/' + newBlobId);
} else {
response.writeHead(400, {'Content-Type': 'text/plain; charset=utf-8'});
response.end('Invalid name.');
}
} else if (uri == '/delete') {
let match;
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
let user = match[1];
let appName = match[2];
let credentials = await httpd.auth_query(request.headers);
if (
credentials &&
credentials.session &&
(credentials.session.name == user ||
(credentials.permissions.administration && user == 'core'))
) {
let database = new Database(user);
let apps = new Set();
try {
apps = new Set(JSON.parse(await database.get('apps')));
} catch {}
if (apps.delete(appName)) {
await database.set('apps', JSON.stringify([...apps].sort()));
}
database.remove('path:' + appName);
} else {
response.writeHead(401, {'Content-Type': 'text/plain; charset=utf-8'});
response.end('401 Unauthorized');
return;
}
}
response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
response.end('OK');
} else {
let data;
let match;
let id;
let app_id = blobId;
let packageOwner;
let packageName;
if ((match = /^\/\~(\w+)\/(\w+)$/.exec(blobId))) {
packageOwner = match[1];
packageName = match[2];
let db = new Database(match[1]);
app_id = await db.get('path:' + match[2]);
}
let app_object = JSON.parse(utf8Decode(await ssb.blobGet(app_id)));
id = app_object?.files[uri.substring(1)];
if (!id && app_object?.files['handler.js']) {
let answer;
try {
answer = await useAppHandler(
response,
app_id,
uri.substring(1),
request.query ? form.decodeForm(request.query) : undefined,
request.headers,
packageOwner,
packageName
);
} catch (error) {
data = utf8Encode(
`Internal Server Error\n\n${error?.message}\n${error?.stack}`
);
response.writeHead(500, {
'Content-Type': 'text/plain; charset=utf-8',
'Content-Length': data.length,
});
response.end(data);
return;
}
if (answer && typeof answer.data == 'string') {
answer.data = utf8Encode(answer.data);
}
sendData(
response,
answer?.data,
answer?.content_type,
Object.assign(answer?.headers ?? {}, {
'Access-Control-Allow-Origin': '*',
'Content-Security-Policy': k_content_security_policy,
}),
answer.status_code
);
} else if (id) {
if (
request.headers['if-none-match'] &&
request.headers['if-none-match'] == '"' + id + '"'
) {
let headers = {
'Access-Control-Allow-Origin': '*',
'Content-Security-Policy': k_content_security_policy,
'Content-Length': '0',
};
response.writeHead(304, headers);
response.end();
} else {
let headers = {
ETag: '"' + id + '"',
'Access-Control-Allow-Origin': '*',
'Content-Security-Policy': k_content_security_policy,
};
data = await ssb.blobGet(id);
let type =
httpd.mime_type_from_extension(uri) ||
httpd.mime_type_from_magic_bytes(data);
sendData(response, data, type, headers);
}
} else {
sendData(response, data, undefined, {});
}
}
}
ssb.addEventListener('message', function () {
broadcastEvent('onMessage', [...arguments]);
});
@ -755,12 +1190,12 @@ async function loadSettings() {
} catch (error) {
print('Settings not found in database:', error);
}
for (let [key, value] of Object.entries(defaultGlobalSettings())) {
for (let [key, value] of Object.entries(k_global_settings)) {
if (data[key] === undefined) {
data[key] = value.default_value;
}
}
return data;
gGlobalSettings = data;
}
/**
@ -781,82 +1216,34 @@ function sendStats() {
}
}
let g_handler_index = 0;
exports.callAppHandler = async function callAppHandler(
response,
app_blob_id,
path,
query,
headers,
package_owner,
package_name
) {
let answer;
try {
let do_resolve;
let promise = new Promise(async function (resolve, reject) {
do_resolve = resolve;
});
let process;
try {
process = await getProcessBlob(
app_blob_id,
'handler_' + g_handler_index++,
{
script: 'handler.js',
imports: {
request: {
path: path,
query: query,
},
respond: do_resolve,
},
credentials: await httpd.auth_query(headers),
packageOwner: package_owner,
packageName: package_name,
}
);
await process.ready;
answer = await promise;
} finally {
if (process?.task) {
await process.task.kill();
}
}
} catch (error) {
let data = utf8Encode(
`Internal Server Error\n\n${error?.message}\n${error?.stack}`
);
response.writeHead(500, {
'Content-Type': 'text/plain; charset=utf-8',
'Content-Length': data.length,
});
response.end(data);
return;
}
if (typeof answer?.data == 'string') {
answer.data = utf8Encode(answer.data);
}
response.writeHead(answer?.status_code, {
'Content-Type': answer?.content_type,
'Content-Length': answer?.data?.length,
'Access-Control-Allow-Origin': '*',
'Content-Security-Policy':
'sandbox allow-downloads allow-top-navigation-by-user-activation',
});
response.end(answer?.data);
};
/**
* TODOC
*/
loadSettings()
.then(function (settings) {
if (tildefriends.https_port && settings.http_redirect) {
httpd.set_http_redirect(settings.http_redirect);
.then(function () {
if (tildefriends.https_port && gGlobalSettings.http_redirect) {
httpd.set_http_redirect(gGlobalSettings.http_redirect);
}
httpd.all('/app/socket', app.socket);
httpd.all('', function default_http_handler(request, response) {
let match;
if ((match = /^(\/~[^\/]+\/[^\/]+)(\/?.*)$/.exec(request.uri))) {
return blobHandler(request, response, match[1], match[2]);
} else if (
(match = /^\/([&\%][^\.]{44}(?:\.\w+)?)(\/?.*)/.exec(request.uri))
) {
return blobHandler(request, response, match[1], match[2]);
} else if ((match = /^(.*)(\/(?:save|delete)?)$/.exec(request.uri))) {
return blobHandler(request, response, match[1], match[2]);
} else {
let data = 'File not found.';
response.writeHead(404, {
'Content-Type': 'text/plain; charset=utf-8',
'Content-Length': data.length.toString(),
});
return response.end(data);
}
});
let port = httpd.start(tildefriends.http_port);
if (tildefriends.args.out_http_port_file) {
print('Writing the port file.');
@ -903,4 +1290,48 @@ loadSettings()
exit(1);
});
export {invoke, getProcessBlob};
/**
* TODOC
* @param {*} user
* @param {*} packageOwner
* @param {*} packageName
* @param {*} permission
* @param {*} allow
*/
function storePermission(user, packageOwner, packageName, permission, allow) {
if (!gGlobalSettings.userPermissions) {
gGlobalSettings.userPermissions = {};
}
if (!gGlobalSettings.userPermissions[user]) {
gGlobalSettings.userPermissions[user] = {};
}
if (!gGlobalSettings.userPermissions[user][packageOwner]) {
gGlobalSettings.userPermissions[user][packageOwner] = {};
}
if (!gGlobalSettings.userPermissions[user][packageOwner][packageName]) {
gGlobalSettings.userPermissions[user][packageOwner][packageName] = {};
}
if (
gGlobalSettings.userPermissions[user][packageOwner][packageName][
permission
] !== allow
) {
if (allow === undefined) {
delete gGlobalSettings.userPermissions[user][packageOwner][packageName][
permission
];
} else {
gGlobalSettings.userPermissions[user][packageOwner][packageName][
permission
] = allow;
}
setGlobalSettings(gGlobalSettings);
}
}
export {
gGlobalSettings as globalSettings,
setGlobalSettings,
invoke,
getSessionProcessBlob,
};

View File

@ -6,26 +6,6 @@
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
<link type="image/svg+xml" rel="icon" href="/static/tildefriends.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="title"
content="Tilde Friends - Make friends and apps from your web browser."
/>
<meta
name="description"
content="Tilde Friends is a Secure Scuttlebutt client and a platform for building, running, and sharing web applications. "
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="https://metatags.io/" />
<meta
property="og:title"
content="Tilde Friends - Make friends and apps from your web browser."
/>
<meta
property="og:description"
content="Tilde Friends is a Secure Scuttlebutt client and a platform for building, running, and sharing web applications. "
/>
<meta property="og:image" content="/static/tildefriends.svg" />
<script>
function set_access_key_title(event) {
if (!event.srcElement.title) {

View File

@ -21,14 +21,14 @@
}:
pkgs.stdenv.mkDerivation rec {
pname = "tildefriends";
version = "0.0.25";
version = "0.0.21";
src = pkgs.fetchFromGitea {
domain = "dev.tildefriends.net";
owner = "cory";
repo = "tildefriends";
rev = "v${version}";
hash = "sha256-Rfk+CUhi+Ss0z70CCgmtVM/w4nCL1GX/MsD4sPYIa5s=";
hash = "sha256-cBj9Hz0qT0Tqm7ivM8HPG9TNwC9iv0lTcE8XCNba8F4=";
fetchSubmodules = true;
};

1
deps/c-ares vendored

@ -1 +0,0 @@
Subproject commit b82840329a4081a1f1b125e6e6b760d4e1237b52

View File

@ -1,177 +0,0 @@
#ifndef __CARES_BUILD_H
#define __CARES_BUILD_H
/*
* Copyright (C) The c-ares project and its contributors
* SPDX-License-Identifier: MIT
*/
#define CARES_STATICLIB
#ifdef CARES_HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef CARES_HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef CARES_HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#if defined(_WIN32)
#undef HAVE_REGISTERWAITFORSINGLEOBJECT
#define CARES_HAVE_WINSOCK2_H
#define CARES_HAVE_WINDOWS_H
#define CARES_HAVE_WS2TCPIP_H
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define CARES_TYPEOF_ARES_SOCKLEN_T int
#define CARES_TYPEOF_ARES_SSIZE_T ssize_t
#else
#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
#define CARES_TYPEOF_ARES_SSIZE_T ssize_t
#endif
#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__HAIKU__)
#define GETSERVBYNAME_R_ARGS 6
#define GETSERVBYPORT_R_ARGS 6
#define HAVE_GETSERVBYNAME_R 1
#define HAVE_GETSERVBYPORT_R 1
#endif
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__HAIKU__)
#define HAVE_PIPE2 1
#endif
#if defined(__OpenBSD__) || defined(__HAIKU__)
#define GETSERVBYNAME_R_ARGS 4
#define GETSERVBYPORT_R_ARGS 4
#endif
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__HAIKU__)
#define HAVE_MALLOC_H 1
#define HAVE_EPOLL 1
#define HAVE_SYS_EPOLL_H 1
#define HAVE_SYS_RANDOM_H 1
#endif
#if !defined(__WIN32)
#undef AC_APPLE_UNIVERSAL_BUILD
#undef ETC_INET
#define GETHOSTNAME_TYPE_ARG2 size_t
#define GETNAMEINFO_QUAL_ARG1
#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
#define GETNAMEINFO_TYPE_ARG2 socklen_t
#define GETNAMEINFO_TYPE_ARG46 socklen_t
#define GETNAMEINFO_TYPE_ARG7 int
#define HAVE_AF_INET6 1
#define HAVE_ARPA_INET_H 1
#define HAVE_ARPA_NAMESER_COMPAT_H 1
#define HAVE_ARPA_NAMESER_H 1
#define HAVE_ASSERT_H 1
#define HAVE_CLOCK_GETTIME_MONOTONIC 1
#define HAVE_CONNECT 1
#define HAVE_DLFCN_H 1
#define HAVE_ERRNO_H 1
#define HAVE_POLL_H 1
#define HAVE_POLL 1
#define HAVE_PIPE 1
#define HAVE_FCNTL 1
#define HAVE_FCNTL_H 1
#define HAVE_FCNTL_O_NONBLOCK 1
#define HAVE_FREEADDRINFO 1
#define HAVE_GETADDRINFO 1
#define HAVE_GETENV 1
#define HAVE_GETHOSTNAME 1
#define HAVE_GETNAMEINFO 1
#if !defined(__HAIKU__)
#define HAVE_GETRANDOM 1
#endif
#define HAVE_GETTIMEOFDAY 1
#define HAVE_IF_INDEXTONAME 1
#define HAVE_IF_NAMETOINDEX 1
#define HAVE_INET_NTOP 1
#define HAVE_INET_PTON 1
#define HAVE_INTTYPES_H 1
#define HAVE_IOCTL 1
#define HAVE_IOCTL_FIONBIO 1
#define HAVE_IOCTL_SIOCGIFADDR 1
#define HAVE_LIMITS_H 1
#define HAVE_LONGLONG 1
#define HAVE_MEMORY_H 1
#define HAVE_MSG_NOSIGNAL 1
#define HAVE_NETDB_H 1
#define HAVE_NETINET_IN_H 1
#define HAVE_NETINET_TCP_H 1
#define HAVE_NET_IF_H 1
#define HAVE_PF_INET6 1
#define HAVE_RECV 1
#define HAVE_RECVFROM 1
#define HAVE_SEND 1
#define HAVE_SETSOCKOPT 1
#define HAVE_SIGNAL_H 1
#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1
#define HAVE_SOCKET 1
#define HAVE_STDBOOL_H 1
#define HAVE_STDINT_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRCASECMP 1
#define HAVE_STRDUP 1
#define HAVE_STRINGS_H 1
#define HAVE_STRING_H 1
#define HAVE_STRNCASECMP 1
#define HAVE_STRUCT_ADDRINFO 1
#define HAVE_STRUCT_IN6_ADDR 1
#define HAVE_STRUCT_SOCKADDR_IN6 1
#define HAVE_STRUCT_SOCKADDR_STORAGE 1
#define HAVE_STRUCT_TIMEVAL 1
#define HAVE_SYS_IOCTL_H 1
#define HAVE_SYS_PARAM_H 1
#define HAVE_SYS_SELECT_H 1
#define HAVE_SYS_SOCKET_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TIME_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_SYS_UIO_H 1
#define HAVE_TIME_H 1
#define HAVE_IFADDRS_H 1
#define HAVE_UNISTD_H 1
#define HAVE_WRITEV 1
#if defined(__ANDROID__) || defined(__APPLE__) || defined(__OpenBSD__)
#define HAVE_ARC4RANDOM_BUF 1
#else
#undef HAVE_ARC4RANDOM_BUF
#endif
#define HAVE_GETIFADDRS 1
#define HAVE_STAT 1
#define CARES_RANDOM_FILE "/dev/urandom"
#define RECVFROM_QUAL_ARG5
#define RECVFROM_TYPE_ARG1 int
#define RECVFROM_TYPE_ARG2 void *
#define RECVFROM_TYPE_ARG2_IS_VOID 0
#define RECVFROM_TYPE_ARG3 size_t
#define RECVFROM_TYPE_ARG4 int
#define RECVFROM_TYPE_ARG5 struct sockaddr *
#define RECVFROM_TYPE_ARG5_IS_VOID 0
#define RECVFROM_TYPE_ARG6 socklen_t *
#define RECVFROM_TYPE_ARG6_IS_VOID 0
#define RECVFROM_TYPE_RETV ssize_t
#define RECV_TYPE_ARG1 int
#define RECV_TYPE_ARG2 void *
#define RECV_TYPE_ARG3 size_t
#define RECV_TYPE_ARG4 int
#define RECV_TYPE_RETV ssize_t
#define SEND_TYPE_ARG1 int
#define SEND_TYPE_ARG2 const void *
#define SEND_TYPE_ARG3 size_t
#define SEND_TYPE_ARG4 int
#define SEND_TYPE_RETV ssize_t
#undef USE_BLOCKING_SOCKETS
#undef WIN32_LEAN_AND_MEAN
#define HAVE_PTHREAD_H 1
#define CARES_THREADS 1
#endif
#endif /* __CARES_BUILD_H */

File diff suppressed because one or more lines are too long

433
deps/codemirror_src/package-lock.json generated vendored
View File

@ -19,10 +19,9 @@
}
},
"node_modules/@codemirror/autocomplete": {
"version": "6.18.3",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.3.tgz",
"integrity": "sha512-1dNIOmiM0z4BIBwxmxEfA1yoxh1MF/6KPBbh20a5vphGV0ictKlgQsbJs6D6SkR6iJpGbpwRsa6PFMNlg9T9pQ==",
"license": "MIT",
"version": "6.17.0",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.17.0.tgz",
"integrity": "sha512-fdfj6e6ZxZf8yrkMHUSJJir7OJkHkZKaOZGzLWIYp2PZ3jd+d+UjG8zVPqJF6d3bKxkhvXTPan/UZ1t7Bqm0gA==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
@ -37,10 +36,9 @@
}
},
"node_modules/@codemirror/commands": {
"version": "6.7.1",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.7.1.tgz",
"integrity": "sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==",
"license": "MIT",
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.0.tgz",
"integrity": "sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.4.0",
@ -49,23 +47,21 @@
}
},
"node_modules/@codemirror/lang-css": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
"license": "MIT",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.2.1.tgz",
"integrity": "sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.0.2",
"@lezer/css": "^1.1.7"
"@lezer/css": "^1.0.0"
}
},
"node_modules/@codemirror/lang-html": {
"version": "6.4.9",
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/lang-css": "^6.0.0",
@ -82,7 +78,6 @@
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz",
"integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
@ -97,17 +92,15 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/json": "^1.0.0"
}
},
"node_modules/@codemirror/language": {
"version": "6.10.6",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.6.tgz",
"integrity": "sha512-KrsbdCnxEztLVbB5PycWXFxas4EOyk/fPAfruSOnDDppevQgid2XZ+KbJ9u+fDikP/e7MW7HPBTvTb8JlZK9vA==",
"license": "MIT",
"version": "6.10.2",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.2.tgz",
"integrity": "sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.23.0",
@ -118,21 +111,19 @@
}
},
"node_modules/@codemirror/lint": {
"version": "6.8.4",
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.4.tgz",
"integrity": "sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A==",
"license": "MIT",
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.1.tgz",
"integrity": "sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.35.0",
"@codemirror/view": "^6.0.0",
"crelt": "^1.0.5"
}
},
"node_modules/@codemirror/search": {
"version": "6.5.8",
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.8.tgz",
"integrity": "sha512-PoWtZvo7c1XFeZWmmyaOp2G0XVbOnm+fJzvghqGAktBW3cufwJUWvSCcNG0ppXiBEM05mZu6RhMtXPv2hpllig==",
"license": "MIT",
"version": "6.5.6",
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.6.tgz",
"integrity": "sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
@ -140,19 +131,14 @@
}
},
"node_modules/@codemirror/state": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.0.tgz",
"integrity": "sha512-MwBHVK60IiIHDcoMet78lxt6iw5gJOGSbNbOIVBHWVXIH4/Nq1+GQgLLGgI1KlnN86WDXsPudVaqYHKBIx7Eyw==",
"license": "MIT",
"dependencies": {
"@marijn/find-cluster-break": "^1.0.0"
}
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz",
"integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A=="
},
"node_modules/@codemirror/theme-one-dark": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
"integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
@ -161,12 +147,11 @@
}
},
"node_modules/@codemirror/view": {
"version": "6.35.3",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.35.3.tgz",
"integrity": "sha512-ScY7L8+EGdPl4QtoBiOzE4FELp7JmNUsBvgBcCakXWM2uiv/K89VAzU3BMDscf0DsACLvTKePbd5+cFDTcei6g==",
"license": "MIT",
"version": "6.29.1",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.29.1.tgz",
"integrity": "sha512-7r+DlO/QFwPqKp73uq5mmrS4TuLPUVotbNOKYzN3OLP5ScrOVXcm4g13/48b6ZXGhdmzMinzFYqH0vo+qihIkQ==",
"dependencies": {
"@codemirror/state": "^6.5.0",
"@codemirror/state": "^6.4.0",
"style-mod": "^4.1.0",
"w3c-keyname": "^2.2.4"
}
@ -176,7 +161,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
@ -191,7 +175,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
@ -201,7 +184,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
@ -211,7 +193,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
@ -221,31 +202,27 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
"license": "MIT"
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
"integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ=="
},
"node_modules/@lezer/css": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.9.tgz",
"integrity": "sha512-TYwgljcDv+YrV0MZFFvYFQHCfGgbPMR6nuqLabBdmZoFH3EP1gvw8t0vae326Ne3PszQkbXfVBjCnf3ZVCr0bA==",
"license": "MIT",
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.8.tgz",
"integrity": "sha512-7JhxupKuMBaWQKjQoLtzhGj83DdnZY9MckEOG5+/iLKNK2ZJqKc6hf6uc0HjwCX7Qlok44jBNqZhHKDhEhZYLA==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
@ -253,10 +230,9 @@
}
},
"node_modules/@lezer/highlight": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
"license": "MIT",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz",
"integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==",
"dependencies": {
"@lezer/common": "^1.0.0"
}
@ -265,7 +241,6 @@
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
@ -273,10 +248,9 @@
}
},
"node_modules/@lezer/javascript": {
"version": "1.4.21",
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.21.tgz",
"integrity": "sha512-lL+1fcuxWYPURMM/oFZLEDm0XuLN128QPV+VuGtKpeaOGdcl9F2LYC3nh1S9LkPqx9M0mndZFdXCipNAZpzIkQ==",
"license": "MIT",
"version": "1.4.17",
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.17.tgz",
"integrity": "sha512-bYW4ctpyGK+JMumDApeUzuIezX01H76R1foD6LcRX224FWfyYit/HYxiPGDjXXe/wQWASjCvVGoukTH68+0HIA==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.1.3",
@ -287,7 +261,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz",
"integrity": "sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
@ -298,26 +271,19 @@
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.0.0"
}
},
"node_modules/@marijn/find-cluster-break": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
"license": "MIT"
},
"node_modules/@rollup/plugin-node-resolve": {
"version": "15.3.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz",
"integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==",
"license": "MIT",
"version": "15.2.3",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
"integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"@types/resolve": "1.20.2",
"deepmerge": "^4.2.2",
"is-builtin-module": "^3.2.1",
"is-module": "^1.0.0",
"resolve": "^1.22.1"
},
@ -338,7 +304,6 @@
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
"dev": true,
"license": "MIT",
"dependencies": {
"serialize-javascript": "^6.0.1",
"smob": "^1.0.0",
@ -357,14 +322,13 @@
}
},
"node_modules/@rollup/pluginutils": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz",
"integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==",
"license": "MIT",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
"integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
"picomatch": "^4.0.2"
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=14.0.0"
@ -379,270 +343,212 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz",
"integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.1.tgz",
"integrity": "sha512-XzqSg714++M+FXhHfXpS1tDnNZNpgxxuGZWlRG/jSj+VEPmZ0yg6jV4E0AL3uyBKxO8mO3xtOsP5mQ+XLfrlww==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz",
"integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.19.1.tgz",
"integrity": "sha512-thFUbkHteM20BGShD6P08aungq4irbIZKUNbG70LN8RkO7YztcGPiKTTGZS7Kw+x5h8hOXs0i4OaHwFxlpQN6A==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz",
"integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.19.1.tgz",
"integrity": "sha512-8o6eqeFZzVLia2hKPUZk4jdE3zW7LCcZr+MD18tXkgBBid3lssGVAYuox8x6YHoEPDdDa9ixTaStcmx88lio5Q==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz",
"integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.19.1.tgz",
"integrity": "sha512-4T42heKsnbjkn7ovYiAdDVRRWZLU9Kmhdt6HafZxFcUdpjlBlxj4wDrt1yFWLk7G4+E+8p2C9tcmSu0KA6auGA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz",
"integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz",
"integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz",
"integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.19.1.tgz",
"integrity": "sha512-MXg1xp+e5GhZ3Vit1gGEyoC+dyQUBy2JgVQ+3hUrD9wZMkUw/ywgkpK7oZgnB6kPpGrxJ41clkPPnsknuD6M2Q==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz",
"integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.19.1.tgz",
"integrity": "sha512-DZNLwIY4ftPSRVkJEaxYkq7u2zel7aah57HESuNkUnz+3bZHxwkCUkrfS2IWC1sxK6F2QNIR0Qr/YXw7nkF3Pw==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz",
"integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.19.1.tgz",
"integrity": "sha512-C7evongnjyxdngSDRRSQv5GvyfISizgtk9RM+z2biV5kY6S/NF/wta7K+DanmktC5DkuaJQgoKGf7KUDmA7RUw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz",
"integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.19.1.tgz",
"integrity": "sha512-89tFWqxfxLLHkAthAcrTs9etAoBFRduNfWdl2xUs/yLV+7XDrJ5yuXMHptNqf1Zw0UCA3cAutkAiAokYCkaPtw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz",
"integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==",
"cpu": [
"loong64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz",
"integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.19.1.tgz",
"integrity": "sha512-PromGeV50sq+YfaisG8W3fd+Cl6mnOOiNv2qKKqKCpiiEke2KiKVyDqG/Mb9GWKbYMHj5a01fq/qlUR28PFhCQ==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz",
"integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.19.1.tgz",
"integrity": "sha512-/1BmHYh+iz0cNCP0oHCuF8CSiNj0JOGf0jRlSo3L/FAyZyG2rGBuKpkZVH9YF+x58r1jgWxvm1aRg3DHrLDt6A==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz",
"integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.19.1.tgz",
"integrity": "sha512-0cYP5rGkQWRZKy9/HtsWVStLXzCF3cCBTRI+qRL8Z+wkYlqN7zrSYm6FuY5Kd5ysS5aH0q5lVgb/WbG4jqXN1Q==",
"cpu": [
"s390x"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz",
"integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.19.1.tgz",
"integrity": "sha512-XUXeI9eM8rMP8aGvii/aOOiMvTs7xlCosq9xCjcqI9+5hBxtjDpD+7Abm1ZhVIFE1J2h2VIg0t2DX/gjespC2Q==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz",
"integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.19.1.tgz",
"integrity": "sha512-V7cBw/cKXMfEVhpSvVZhC+iGifD6U1zJ4tbibjjN+Xi3blSXaj/rJynAkCFFQfoG6VZrAiP7uGVzL440Q6Me2Q==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz",
"integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.19.1.tgz",
"integrity": "sha512-88brja2vldW/76jWATlBqHEoGjJLRnP0WOEKAUbMcXaAZnemNhlAHSyj4jIwMoP2T750LE9lblvD4e2jXleZsA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz",
"integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.19.1.tgz",
"integrity": "sha512-LdxxcqRVSXi6k6JUrTah1rHuaupoeuiv38du8Mt4r4IPer3kwlTo+RuvfE8KzZ/tL6BhaPlzJ3835i6CxrFIRQ==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz",
"integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.19.1.tgz",
"integrity": "sha512-2bIrL28PcK3YCqD9anGxDxamxdiJAxA+l7fWIwM5o8UqNy1t3d1NdAweO2XhA0KTDJ5aH1FsuiT5+7VhtHliXg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@types/estree": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"license": "MIT"
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
},
"node_modules/@types/resolve": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
"license": "MIT"
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
},
"node_modules/acorn": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@ -654,14 +560,23 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
"dev": true
},
"node_modules/builtin-modules": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/codemirror": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/commands": "^6.0.0",
@ -676,20 +591,17 @@
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
"dev": true
},
"node_modules/crelt": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
"license": "MIT"
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
},
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@ -697,15 +609,13 @@
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"license": "MIT"
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
@ -718,7 +628,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -727,7 +636,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
@ -735,11 +643,24 @@
"node": ">= 0.4"
}
},
"node_modules/is-builtin-module": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
"integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
"dependencies": {
"builtin-modules": "^3.3.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-core-module": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
"license": "MIT",
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz",
"integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==",
"dependencies": {
"hasown": "^2.0.2"
},
@ -753,22 +674,19 @@
"node_modules/is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
"license": "MIT"
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"license": "MIT"
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"license": "MIT",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"engines": {
"node": ">=12"
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
@ -779,7 +697,6 @@
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"safe-buffer": "^5.1.0"
}
@ -788,7 +705,6 @@
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"license": "MIT",
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
@ -802,12 +718,11 @@
}
},
"node_modules/rollup": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz",
"integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==",
"license": "MIT",
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.19.1.tgz",
"integrity": "sha512-K5vziVlg7hTpYfFBI+91zHBEMo6jafYXpkMlqZjg7/zhIG9iHqazBf4xz9AVdjS9BruRn280ROqLI7G3OFRIlw==",
"dependencies": {
"@types/estree": "1.0.6"
"@types/estree": "1.0.5"
},
"bin": {
"rollup": "dist/bin/rollup"
@ -817,25 +732,22 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.28.1",
"@rollup/rollup-android-arm64": "4.28.1",
"@rollup/rollup-darwin-arm64": "4.28.1",
"@rollup/rollup-darwin-x64": "4.28.1",
"@rollup/rollup-freebsd-arm64": "4.28.1",
"@rollup/rollup-freebsd-x64": "4.28.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.28.1",
"@rollup/rollup-linux-arm-musleabihf": "4.28.1",
"@rollup/rollup-linux-arm64-gnu": "4.28.1",
"@rollup/rollup-linux-arm64-musl": "4.28.1",
"@rollup/rollup-linux-loongarch64-gnu": "4.28.1",
"@rollup/rollup-linux-powerpc64le-gnu": "4.28.1",
"@rollup/rollup-linux-riscv64-gnu": "4.28.1",
"@rollup/rollup-linux-s390x-gnu": "4.28.1",
"@rollup/rollup-linux-x64-gnu": "4.28.1",
"@rollup/rollup-linux-x64-musl": "4.28.1",
"@rollup/rollup-win32-arm64-msvc": "4.28.1",
"@rollup/rollup-win32-ia32-msvc": "4.28.1",
"@rollup/rollup-win32-x64-msvc": "4.28.1",
"@rollup/rollup-android-arm-eabi": "4.19.1",
"@rollup/rollup-android-arm64": "4.19.1",
"@rollup/rollup-darwin-arm64": "4.19.1",
"@rollup/rollup-darwin-x64": "4.19.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.19.1",
"@rollup/rollup-linux-arm-musleabihf": "4.19.1",
"@rollup/rollup-linux-arm64-gnu": "4.19.1",
"@rollup/rollup-linux-arm64-musl": "4.19.1",
"@rollup/rollup-linux-powerpc64le-gnu": "4.19.1",
"@rollup/rollup-linux-riscv64-gnu": "4.19.1",
"@rollup/rollup-linux-s390x-gnu": "4.19.1",
"@rollup/rollup-linux-x64-gnu": "4.19.1",
"@rollup/rollup-linux-x64-musl": "4.19.1",
"@rollup/rollup-win32-arm64-msvc": "4.19.1",
"@rollup/rollup-win32-ia32-msvc": "4.19.1",
"@rollup/rollup-win32-x64-msvc": "4.19.1",
"fsevents": "~2.3.2"
}
},
@ -857,15 +769,13 @@
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
]
},
"node_modules/serialize-javascript": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"randombytes": "^2.1.0"
}
@ -874,15 +784,13 @@
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
"dev": true,
"license": "MIT"
"dev": true
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
@ -892,7 +800,6 @@
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
@ -901,14 +808,12 @@
"node_modules/style-mod": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
"license": "MIT"
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
@ -917,11 +822,10 @@
}
},
"node_modules/terser": {
"version": "5.37.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz",
"integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==",
"version": "5.31.3",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz",
"integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@ -938,8 +842,7 @@
"node_modules/w3c-keyname": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
"license": "MIT"
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
}
}
}

1
deps/dht vendored Submodule

@ -0,0 +1 @@
Subproject commit 111230894416d400c9a1e038a033586bfeaafc93

2
deps/libbacktrace vendored

@ -1 +1 @@
Subproject commit d48f84034ce3e53e501d10593710d025cb1121db
Subproject commit 0dd27b95f9f2c11b4a89db5f185a888af912838e

2
deps/libsodium vendored

@ -1 +1 @@
Subproject commit 0217d07326f0ffbe79d6ce09793843e135a67487
Subproject commit 9511c982fb1d046470a8b42aa36556cdb7da15de

2
deps/libuv vendored

@ -1 +1 @@
Subproject commit e1095c7a4373ce00cd8874d8e820de5afb25776e
Subproject commit e9f29cb984231524e3931aa0ae2c5dae1a32884e

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
deps/openssl_src vendored

@ -1 +1 @@
Subproject commit 98acb6b02839c609ef5b837794e08d906d965335
Subproject commit db2ac4f6ebd8f3d7b2a60882992fbea1269114e2

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>speedscope</title><link href="source-code-pro.52b1676f.css" rel="stylesheet"><script></script><link rel="stylesheet" href="reset.8c46b7a1.css"><link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.bc503437.png"><link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.f74b3187.png"></head><body> <script src="speedscope.6f107512.js"></script>
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>speedscope</title><link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet"><script></script><link rel="stylesheet" href="reset.8c46b7a1.css"><link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.bc503437.png"><link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.f74b3187.png"></head><body> <script src="speedscope.80eb88d2.js"></script>
</body></html>

View File

@ -1,3 +1,3 @@
speedscope@1.21.0
Sat Nov 16 22:13:27 PST 2024
d36c3a54424063a8df7bc67a7b824a223d73861b
speedscope@1.20.0
Fri Jan 12 09:57:49 PST 2024
68fd88ceaf93d89aa27f3f0a20a27c9cfdc015c5

View File

@ -1,2 +0,0 @@
@font-face{font-family:Source Code Pro;font-weight:400;font-style:normal;font-stretch:normal;src:url(SourceCodePro-Regular.ttf.f546cbe0.woff2) format("woff2")}
/*# sourceMappingURL=source-code-pro.52b1676f.css.map */

View File

@ -1,93 +0,0 @@
Copyright 2010-2019 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

File diff suppressed because one or more lines are too long

6035
deps/sqlite/shell.c vendored

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More