Fix xterm.js terminal issues: xterm256 support, data display, polling, debug logging, and crash fix

parent 9c8b37b9
# Makefile for wssshd2 - Generated by configure.sh
# Do not edit manually, run ./configure.sh instead
CC = gcc
CFLAGS = -Wall -Wextra -O2 -I. -pthread
LDFLAGS = -lssl -lcrypto -lm -luuid -lsqlite3
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/share/man
CONFIGDIR = /etc
# Source files
SRCS = main.c config.c tunnel.c terminal.c websocket.c websocket_protocol.c web.c assets.c ssl.c
OBJS = $(SRCS:.c=.o)
# Target
TARGET = wssshd
.PHONY: all clean install uninstall
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# Dependencies
main.o: main.c config.h websocket.h web.h
config.o: config.c config.h
tunnel.o: tunnel.c tunnel.h websocket.h
terminal.o: terminal.c terminal.h config.h
websocket.o: websocket.c websocket.h websocket_protocol.h config.h
websocket_protocol.o: websocket_protocol.c websocket_protocol.h
web.o: web.c web.h terminal.h assets.h websocket.h html_pages/index_page.h html_pages/login_page.h html_pages/terminal_page.h html_pages/users_page.h
assets.o: assets.c assets.h
ssl.o: ssl.c ssl.h
# Asset embedding (run before compilation)
assets.o: image_data.h
image_data.h: embed_assets.sh
./embed_assets.sh
# HTML page generation
html_pages/index_page.h html_pages/login_page.h html_pages/terminal_page.h: embed_assets.sh
./embed_assets.sh
clean:
rm -f $(OBJS) $(TARGET) image_data.h favicon_data.h
install: $(TARGET)
install -d $(DESTDIR)$(BINDIR)
install -m 755 $(TARGET) $(DESTDIR)$(BINDIR)/
install -d $(DESTDIR)$(CONFIGDIR)
[ -f $(DESTDIR)$(CONFIGDIR)/wssshd.conf ] || install -m 644 wssshd.conf.example $(DESTDIR)$(CONFIGDIR)/wssshd.conf
install -d $(DESTDIR)$(MANDIR)/man8
install -m 644 wssshd.8 $(DESTDIR)$(MANDIR)/man8/
uninstall:
rm -f $(DESTDIR)$(BINDIR)/$(TARGET)
rm -f $(DESTDIR)$(MANDIR)/man8/wssshd.8
# Development targets
debug: CFLAGS += -g -DDEBUG
debug: clean all
test: $(TARGET)
@echo "Running basic functionality test..."
./$(TARGET) --help || true
distclean: clean
rm -f Makefile
# Help target
help:
@echo "Available targets:"
@echo " all - Build wssshd2 (default)"
@echo " clean - Remove build artifacts"
@echo " install - Install wssshd2 to system"
@echo " uninstall - Remove wssshd2 from system"
@echo " debug - Build with debug symbols"
@echo " test - Run basic tests"
@echo " distclean - Remove all generated files"
@echo " help - Show this help"
unsigned char favicon_ico[] = {
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00,
0x08, 0x00, 0x68, 0x05, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x20, 0x20,
0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0xa8, 0x10, 0x00, 0x00, 0x8e, 0x05,
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe9, 0xdc, 0xd4, 0x00, 0xe9, 0xdd,
0xd5, 0x00, 0xea, 0xdd, 0xd5, 0x00, 0xe8, 0xdc, 0xd4, 0x00, 0xea, 0xde,
0xd6, 0x00, 0xeb, 0xde, 0xd6, 0x00, 0xe9, 0xde, 0xd5, 0x00, 0xe8, 0xda,
0xd1, 0x00, 0xea, 0xdd, 0xd6, 0x00, 0xeb, 0xde, 0xd7, 0x00, 0xeb, 0xdd,
0xd5, 0x00, 0xe9, 0xdc, 0xd5, 0x00, 0xf3, 0xe9, 0xe7, 0x00, 0xf1, 0xe5,
0xe2, 0x00, 0xef, 0xe3, 0xde, 0x00, 0xf5, 0xed, 0xed, 0x00, 0xed, 0xdf,
0xd9, 0x00, 0xe8, 0xda, 0xd2, 0x00, 0xf3, 0xea, 0xe9, 0x00, 0xde, 0xcc,
0xbc, 0x00, 0xc8, 0xad, 0x94, 0x00, 0xc8, 0xae, 0x96, 0x00, 0xd4, 0xb9,
0xa3, 0x00, 0xf5, 0xec, 0xeb, 0x00, 0xe8, 0xdb, 0xd2, 0x00, 0xea, 0xdc,
0xd4, 0x00, 0xe9, 0xdd, 0xd4, 0x00, 0xe9, 0xdc, 0xd3, 0x00, 0xf1, 0xe6,
0xe4, 0x00, 0xe7, 0xd6, 0xc9, 0x00, 0xc3, 0xa8, 0x8d, 0x00, 0xd3, 0xce,
0xcb, 0x00, 0xd5, 0xd1, 0xcf, 0x00, 0xc8, 0xb2, 0xa2, 0x00, 0xd7, 0xbe,
0xac, 0x00, 0xfb, 0xf7, 0xfa, 0x00, 0xee, 0xe2, 0xdc, 0x00, 0xec, 0xe2,
0xdb, 0x00, 0xeb, 0xe0, 0xd8, 0x00, 0xeb, 0xe0, 0xd9, 0x00, 0xea, 0xdf,
0xd8, 0x00, 0xec, 0xe2, 0xdc, 0x00, 0xf8, 0xf0, 0xf0, 0x00, 0xd5, 0xba,
0xa4, 0x00, 0xd7, 0xcd, 0xc6, 0x00, 0xc1, 0xb5, 0xae, 0x00, 0xb6, 0xa4,
0x98, 0x00, 0xdc, 0xd9, 0xd8, 0x00, 0xc3, 0xa2, 0x8a, 0x00, 0xd5, 0xbc,
0xac, 0x00, 0xd1, 0xb2, 0x9d, 0x00, 0xc5, 0xa3, 0x8b, 0x00, 0xcd, 0xb1,
0x9e, 0x00, 0xc9, 0xac, 0x97, 0x00, 0xc9, 0xaa, 0x94, 0x00, 0xcd, 0xaf,
0x9a, 0x00, 0xd1, 0xb3, 0x9f, 0x00, 0xe6, 0xd9, 0xd1, 0x00, 0xf8, 0xef,
0xf0, 0x00, 0xdc, 0xc6, 0xb5, 0x00, 0xd0, 0xbf, 0xb1, 0x00, 0xd5, 0xd4,
0xd4, 0x00, 0xcf, 0xc9, 0xc6, 0x00, 0xd7, 0xce, 0xc8, 0x00, 0xd3, 0xb7,
0xa3, 0x00, 0xbe, 0x94, 0x75, 0x00, 0xb3, 0x82, 0x5e, 0x00, 0xc1, 0xa0,
0x88, 0x00, 0xba, 0x94, 0x79, 0x00, 0xb9, 0x94, 0x79, 0x00, 0xb9, 0x92,
0x77, 0x00, 0xae, 0x7d, 0x5a, 0x00, 0xbf, 0x95, 0x78, 0x00, 0xea, 0xdc,
0xd5, 0x00, 0xf2, 0xe4, 0xe1, 0x00, 0xf4, 0xee, 0xed, 0x00, 0xc5, 0xa6,
0x8f, 0x00, 0xcc, 0xb9, 0xaa, 0x00, 0xd3, 0xc4, 0xb8, 0x00, 0xc3, 0xa6,
0x90, 0x00, 0xde, 0xd2, 0xc9, 0x00, 0xdb, 0xce, 0xc6, 0x00, 0xd4, 0xc2,
0xb6, 0x00, 0xcf, 0xb8, 0xaa, 0x00, 0xcb, 0xb0, 0x9e, 0x00, 0xcb, 0xb1,
0xa0, 0x00, 0xcb, 0xb1, 0x9f, 0x00, 0xca, 0xb0, 0x9f, 0x00, 0xe2, 0xd2,
0xca, 0x00, 0xf0, 0xe0, 0xdc, 0x00, 0xf0, 0xdf, 0xdb, 0x00, 0xf5, 0xf2,
0xf1, 0x00, 0xe2, 0xd3, 0xca, 0x00, 0xbf, 0x9b, 0x81, 0x00, 0xcc, 0xba,
0xac, 0x00, 0xee, 0xec, 0xec, 0x00, 0xed, 0xe3, 0xe0, 0x00, 0xf4, 0xea,
0xe9, 0x00, 0xf7, 0xee, 0xef, 0x00, 0xf7, 0xf0, 0xf1, 0x00, 0xf7, 0xed,
0xed, 0x00, 0xf4, 0xe6, 0xe3, 0x00, 0xee, 0xde, 0xd9, 0x00, 0xf0, 0xdf,
0xda, 0x00, 0xf2, 0xe4, 0xe2, 0x00, 0xf4, 0xec, 0xec, 0x00, 0xfe, 0xfe,
0xff, 0x00, 0xe6, 0xe0, 0xdb, 0x00, 0xe2, 0xd7, 0xd1, 0x00, 0xf7, 0xf4,
0xf4, 0x00, 0xf6, 0xed, 0xed, 0x00, 0xf3, 0xe3, 0xe0, 0x00, 0xf2, 0xe2,
0xde, 0x00, 0xf2, 0xe1, 0xde, 0x00, 0xf2, 0xe3, 0xdf, 0x00, 0xf1, 0xe1,
0xde, 0x00, 0xf1, 0xe0, 0xdd, 0x00, 0xee, 0xde, 0xd8, 0x00, 0xef, 0xdf,
0xd9, 0x00, 0xf3, 0xe6, 0xe4, 0x00, 0xf4, 0xeb, 0xeb, 0x00, 0xee, 0xe8,
0xe7, 0x00, 0xf8, 0xf4, 0xf5, 0x00, 0xf5, 0xee, 0xee, 0x00, 0xf4, 0xe8,
0xe7, 0x00, 0xf3, 0xe2, 0xde, 0x00, 0xf2, 0xe1, 0xdd, 0x00, 0xf2, 0xe2,
0xdf, 0x00, 0xf1, 0xe0, 0xdc, 0x00, 0xef, 0xdf, 0xda, 0x00, 0xf3, 0xe4,
0xe2, 0x00, 0xf4, 0xe8, 0xe6, 0x00, 0xf6, 0xed, 0xec, 0x00, 0xf5, 0xeb,
0xea, 0x00, 0xf4, 0xe6, 0xe4, 0x00, 0xf3, 0xe2, 0xdf, 0x00, 0xf1, 0xe0,
0xdb, 0x00, 0xf0, 0xe0, 0xda, 0x00, 0xf1, 0xe1, 0xdd, 0x00, 0xf5, 0xe9,
0xe7, 0x00, 0xf5, 0xea, 0xe8, 0x00, 0xf3, 0xe3, 0xdf, 0x00, 0xf2, 0xe2,
0xdd, 0x00, 0xf3, 0xe4, 0xe0, 0x00, 0xf5, 0xe8, 0xe6, 0x00, 0xf4, 0xe7,
0xe4, 0x00, 0xf4, 0xe4, 0xe0, 0x00, 0xf1, 0xe1, 0xdc, 0x00, 0xf3, 0xe3,
0xdd, 0x00, 0xf4, 0xe4, 0xe1, 0x00, 0xf5, 0xe7, 0xe4, 0x00, 0xf6, 0xea,
0xe8, 0x00, 0xf6, 0xeb, 0xe9, 0x00, 0xf7, 0xec, 0xea, 0x00, 0xf7, 0xea,
0xe8, 0x00, 0xf5, 0xe6, 0xe3, 0x00, 0xf4, 0xe5, 0xe1, 0x00, 0xf5, 0xe4,
0xe1, 0x00, 0xf5, 0xe4, 0xe0, 0x00, 0xf3, 0xe3, 0xde, 0x00, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x94,
0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x92, 0x9f,
0x93, 0x81, 0x89, 0x8e, 0x8f, 0x65, 0x90, 0x8c, 0x8b, 0x91, 0x92, 0x8d,
0x8d, 0x8d, 0x8d, 0x7d, 0x93, 0x75, 0x89, 0x8a, 0x6f, 0x86, 0x8b, 0x85,
0x8c, 0x65, 0x8d, 0x7d, 0x70, 0x87, 0x87, 0x70, 0x80, 0x75, 0x81, 0x7e,
0x82, 0x83, 0x84, 0x0f, 0x85, 0x86, 0x87, 0x7d, 0x70, 0x70, 0x7f, 0x70,
0x88, 0x75, 0x76, 0x70, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x6f, 0x7d,
0x7e, 0x70, 0x7f, 0x7f, 0x80, 0x75, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x72, 0x73, 0x74, 0x75, 0x5a, 0x0f,
0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x0d, 0x61, 0x62, 0x63, 0x63, 0x64,
0x65, 0x66, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x2a, 0x2b,
0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x27, 0x29, 0x03, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x10, 0x18, 0x19, 0x1a, 0x00, 0x19, 0x00, 0x1b, 0x0b, 0x00, 0x00,
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x00, 0x04, 0x05, 0x02, 0x02, 0x05, 0x02,
0x01, 0x0b, 0x02, 0x01, 0x07, 0x08, 0x09, 0x07, 0x00, 0x02, 0x0a, 0x02,
0x05, 0x0a, 0x02, 0x05, 0x02, 0x0b, 0x01, 0x04, 0x04, 0x02, 0x02, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x01, 0x00, 0x01,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xe0,
0xda, 0xff, 0xf1, 0xe1, 0xdb, 0xff, 0xf3, 0xe2, 0xdd, 0xff, 0xf4, 0xe3,
0xdf, 0xff, 0xf4, 0xe4, 0xe0, 0xff, 0xf5, 0xe5, 0xe1, 0xff, 0xf6, 0xe7,
0xe3, 0xff, 0xf6, 0xe8, 0xe5, 0xff, 0xf6, 0xea, 0xe8, 0xff, 0xf7, 0xeb,
0xe9, 0xff, 0xf7, 0xeb, 0xe9, 0xff, 0xf7, 0xeb, 0xea, 0xff, 0xf8, 0xed,
0xec, 0xff, 0xf7, 0xed, 0xec, 0xff, 0xf7, 0xec, 0xeb, 0xff, 0xf7, 0xea,
0xe8, 0xff, 0xf6, 0xe8, 0xe5, 0xff, 0xf5, 0xe6, 0xe2, 0xff, 0xf5, 0xe5,
0xe1, 0xff, 0xf5, 0xe5, 0xe1, 0xff, 0xf5, 0xe5, 0xe0, 0xff, 0xf5, 0xe5,
0xe1, 0xff, 0xf5, 0xe5, 0xe1, 0xff, 0xf5, 0xe4, 0xe0, 0xff, 0xf5, 0xe4,
0xe1, 0xff, 0xf5, 0xe4, 0xe0, 0xff, 0xf4, 0xe3, 0xde, 0xff, 0xf3, 0xe3,
0xde, 0xff, 0xf2, 0xe2, 0xdc, 0xff, 0xf1, 0xe1, 0xdc, 0xff, 0xf0, 0xe1,
0xdc, 0xff, 0xee, 0xe0, 0xda, 0xff, 0xef, 0xe0, 0xda, 0xff, 0xf1, 0xe1,
0xdb, 0xff, 0xf2, 0xe2, 0xdc, 0xff, 0xf3, 0xe3, 0xde, 0xff, 0xf4, 0xe4,
0xe0, 0xff, 0xf4, 0xe5, 0xe1, 0xff, 0xf4, 0xe6, 0xe3, 0xff, 0xf5, 0xe7,
0xe4, 0xff, 0xf5, 0xe9, 0xe6, 0xff, 0xf6, 0xea, 0xe8, 0xff, 0xf6, 0xea,
0xe8, 0xff, 0xf6, 0xeb, 0xe9, 0xff, 0xf6, 0xeb, 0xe9, 0xff, 0xf6, 0xeb,
0xe9, 0xff, 0xf6, 0xea, 0xe8, 0xff, 0xf6, 0xe8, 0xe6, 0xff, 0xf5, 0xe6,
0xe3, 0xff, 0xf5, 0xe5, 0xe1, 0xff, 0xf4, 0xe4, 0xe1, 0xff, 0xf4, 0xe4,
0xe0, 0xff, 0xf4, 0xe4, 0xe0, 0xff, 0xf4, 0xe4, 0xe1, 0xff, 0xf4, 0xe4,
0xe0, 0xff, 0xf5, 0xe4, 0xe0, 0xff, 0xf4, 0xe3, 0xe0, 0xff, 0xf4, 0xe3,
0xe0, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf3, 0xe3, 0xde, 0xff, 0xf2, 0xe2,
0xdc, 0xff, 0xf1, 0xe1, 0xdb, 0xff, 0xef, 0xe0, 0xda, 0xff, 0xed, 0xde,
0xd8, 0xff, 0xf0, 0xe0, 0xd9, 0xff, 0xf1, 0xe1, 0xdb, 0xff, 0xf1, 0xe2,
0xdc, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf3, 0xe3, 0xe0, 0xff, 0xf4, 0xe4,
0xe0, 0xff, 0xf4, 0xe5, 0xe2, 0xff, 0xf5, 0xe7, 0xe4, 0xff, 0xf5, 0xe7,
0xe4, 0xff, 0xf5, 0xe9, 0xe7, 0xff, 0xf5, 0xe9, 0xe7, 0xff, 0xf5, 0xe9,
0xe7, 0xff, 0xf5, 0xe9, 0xe7, 0xff, 0xf6, 0xe9, 0xe7, 0xff, 0xf5, 0xe9,
0xe7, 0xff, 0xf4, 0xe7, 0xe4, 0xff, 0xf4, 0xe5, 0xe1, 0xff, 0xf4, 0xe4,
0xe0, 0xff, 0xf3, 0xe4, 0xe0, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf3, 0xe3,
0xdf, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf4, 0xe4, 0xe0, 0xff, 0xf3, 0xe3,
0xdf, 0xff, 0xf3, 0xe3, 0xe0, 0xff, 0xf4, 0xe3, 0xdf, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf3, 0xe2, 0xdf, 0xff, 0xf2, 0xe1, 0xdd, 0xff, 0xf0, 0xe0,
0xda, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xed, 0xde, 0xd8, 0xff, 0xef, 0xdf,
0xd9, 0xff, 0xf0, 0xe1, 0xdb, 0xff, 0xf1, 0xe1, 0xdc, 0xff, 0xf2, 0xe2,
0xde, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf4, 0xe4, 0xe1, 0xff, 0xf4, 0xe5,
0xe2, 0xff, 0xf4, 0xe6, 0xe3, 0xff, 0xf5, 0xe8, 0xe5, 0xff, 0xf5, 0xe8,
0xe6, 0xff, 0xf5, 0xea, 0xe9, 0xff, 0xf5, 0xeb, 0xea, 0xff, 0xf5, 0xe9,
0xe7, 0xff, 0xf4, 0xe8, 0xe6, 0xff, 0xf4, 0xe7, 0xe5, 0xff, 0xf4, 0xe5,
0xe2, 0xff, 0xf3, 0xe4, 0xe0, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf3, 0xe3,
0xde, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf3, 0xe3, 0xde, 0xff, 0xf2, 0xe2,
0xde, 0xff, 0xf3, 0xe3, 0xde, 0xff, 0xf3, 0xe3, 0xde, 0xff, 0xf3, 0xe3,
0xdf, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf2, 0xe2,
0xdd, 0xff, 0xf2, 0xe1, 0xdd, 0xff, 0xf1, 0xe1, 0xdb, 0xff, 0xef, 0xdf,
0xd9, 0xff, 0xed, 0xde, 0xd7, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xf0, 0xe0,
0xdb, 0xff, 0xf1, 0xe1, 0xdc, 0xff, 0xf2, 0xe2, 0xdd, 0xff, 0xf3, 0xe3,
0xdf, 0xff, 0xf4, 0xe4, 0xe1, 0xff, 0xf4, 0xe5, 0xe2, 0xff, 0xf4, 0xe7,
0xe4, 0xff, 0xf5, 0xe8, 0xe6, 0xff, 0xf5, 0xe9, 0xe8, 0xff, 0xf5, 0xeb,
0xea, 0xff, 0xf6, 0xeb, 0xea, 0xff, 0xf5, 0xea, 0xe8, 0xff, 0xf5, 0xe9,
0xe7, 0xff, 0xf4, 0xe7, 0xe4, 0xff, 0xf4, 0xe5, 0xe2, 0xff, 0xf4, 0xe3,
0xe0, 0xff, 0xf3, 0xe2, 0xdf, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf3, 0xe2,
0xde, 0xff, 0xf2, 0xe2, 0xdd, 0xff, 0xf3, 0xe3, 0xde, 0xff, 0xf3, 0xe3,
0xdf, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf3, 0xe2, 0xdf, 0xff, 0xf3, 0xe2,
0xde, 0xff, 0xf3, 0xe2, 0xdf, 0xff, 0xf2, 0xe1, 0xdd, 0xff, 0xf2, 0xe1,
0xdc, 0xff, 0xf1, 0xe0, 0xdc, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xed, 0xdd,
0xd7, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xf1, 0xe0, 0xdb, 0xff, 0xf1, 0xe1,
0xdc, 0xff, 0xf1, 0xe1, 0xdd, 0xff, 0xf3, 0xe3, 0xe0, 0xff, 0xf3, 0xe4,
0xe1, 0xff, 0xf4, 0xe6, 0xe3, 0xff, 0xf4, 0xe8, 0xe6, 0xff, 0xf5, 0xe9,
0xe8, 0xff, 0xf5, 0xea, 0xe8, 0xff, 0xf5, 0xeb, 0xea, 0xff, 0xf6, 0xeb,
0xea, 0xff, 0xf5, 0xeb, 0xea, 0xff, 0xf5, 0xe9, 0xe8, 0xff, 0xf4, 0xe7,
0xe4, 0xff, 0xf4, 0xe5, 0xe2, 0xff, 0xf3, 0xe3, 0xe0, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf2, 0xe2,
0xde, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf2, 0xe1, 0xdd, 0xff, 0xf1, 0xe0, 0xdc, 0xff, 0xf1, 0xe0,
0xdc, 0xff, 0xf0, 0xdf, 0xd9, 0xff, 0xed, 0xdd, 0xd7, 0xff, 0xef, 0xdf,
0xd9, 0xff, 0xf0, 0xe0, 0xdb, 0xff, 0xf1, 0xe1, 0xdc, 0xff, 0xf2, 0xe1,
0xde, 0xff, 0xf3, 0xe3, 0xe0, 0xff, 0xf3, 0xe5, 0xe2, 0xff, 0xf3, 0xe6,
0xe4, 0xff, 0xf4, 0xe8, 0xe7, 0xff, 0xf5, 0xe9, 0xe9, 0xff, 0xf5, 0xeb,
0xeb, 0xff, 0xf5, 0xed, 0xed, 0xff, 0xf5, 0xed, 0xed, 0xff, 0xf5, 0xec,
0xeb, 0xff, 0xf5, 0xe9, 0xe8, 0xff, 0xf4, 0xe7, 0xe5, 0xff, 0xf4, 0xe5,
0xe2, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf3, 0xe2,
0xde, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf2, 0xe1,
0xdd, 0xff, 0xf2, 0xe1, 0xde, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf2, 0xe2,
0xde, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf2, 0xe2,
0xde, 0xff, 0xf1, 0xe0, 0xdc, 0xff, 0xf1, 0xdf, 0xdb, 0xff, 0xf0, 0xde,
0xd8, 0xff, 0xee, 0xdd, 0xd7, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xf0, 0xe0,
0xdb, 0xff, 0xf1, 0xe1, 0xdd, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf3, 0xe4,
0xe1, 0xff, 0xf4, 0xe6, 0xe3, 0xff, 0xf4, 0xe8, 0xe6, 0xff, 0xf5, 0xeb,
0xea, 0xff, 0xf4, 0xeb, 0xeb, 0xff, 0xf6, 0xef, 0xef, 0xff, 0xf6, 0xef,
0xee, 0xff, 0xf6, 0xef, 0xee, 0xff, 0xf5, 0xed, 0xec, 0xff, 0xf5, 0xe9,
0xe8, 0xff, 0xf4, 0xe7, 0xe5, 0xff, 0xf4, 0xe6, 0xe3, 0xff, 0xf3, 0xe3,
0xe0, 0xff, 0xf3, 0xe2, 0xdf, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf3, 0xe2,
0xde, 0xff, 0xf2, 0xe2, 0xdd, 0xff, 0xf2, 0xe2, 0xdd, 0xff, 0xf2, 0xe1,
0xde, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf2, 0xe1, 0xde, 0xff, 0xf2, 0xe1,
0xdd, 0xff, 0xf1, 0xdf, 0xda, 0xff, 0xef, 0xde, 0xd8, 0xff, 0xed, 0xdd,
0xd7, 0xff, 0xee, 0xde, 0xd8, 0xff, 0xf0, 0xdf, 0xdb, 0xff, 0xf1, 0xe0,
0xdd, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf3, 0xe4, 0xe2, 0xff, 0xf4, 0xe7,
0xe4, 0xff, 0xf5, 0xea, 0xe8, 0xff, 0xf5, 0xec, 0xec, 0xff, 0xf5, 0xee,
0xee, 0xff, 0xf2, 0xed, 0xec, 0xff, 0xf6, 0xf0, 0xf0, 0xff, 0xf5, 0xee,
0xee, 0xff, 0xf5, 0xee, 0xee, 0xff, 0xf5, 0xed, 0xed, 0xff, 0xf5, 0xea,
0xe8, 0xff, 0xf4, 0xe7, 0xe5, 0xff, 0xf3, 0xe4, 0xe1, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf2, 0xe2,
0xdd, 0xff, 0xf2, 0xe1, 0xdd, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf2, 0xe2,
0xdf, 0xff, 0xf3, 0xe2, 0xdf, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf2, 0xe2,
0xdf, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf1, 0xe1, 0xdc, 0xff, 0xf0, 0xdf,
0xda, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xed, 0xde, 0xd8, 0xff, 0xee, 0xde,
0xd8, 0xff, 0xf0, 0xdf, 0xdb, 0xff, 0xf1, 0xe1, 0xde, 0xff, 0xf2, 0xe4,
0xe0, 0xff, 0xf3, 0xe6, 0xe3, 0xff, 0xf4, 0xe9, 0xe8, 0xff, 0xf4, 0xec,
0xec, 0xff, 0xf6, 0xf1, 0xf1, 0xff, 0xf1, 0xec, 0xec, 0xff, 0xdd, 0xd6,
0xd2, 0xff, 0xf7, 0xf3, 0xf3, 0xff, 0xf6, 0xf1, 0xf1, 0xff, 0xf6, 0xf1,
0xf1, 0xff, 0xf5, 0xee, 0xee, 0xff, 0xf5, 0xeb, 0xea, 0xff, 0xf4, 0xe7,
0xe5, 0xff, 0xf3, 0xe4, 0xe1, 0xff, 0xf2, 0xe3, 0xdf, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf2, 0xe1, 0xdd, 0xff, 0xf2, 0xe1,
0xdd, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf2, 0xe2,
0xdf, 0xff, 0xf2, 0xe1, 0xde, 0xff, 0xf0, 0xe0, 0xdb, 0xff, 0xef, 0xdf,
0xd9, 0xff, 0xed, 0xdd, 0xd7, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xf0, 0xe0,
0xdb, 0xff, 0xf1, 0xe2, 0xde, 0xff, 0xf3, 0xe6, 0xe3, 0xff, 0xf4, 0xea,
0xe9, 0xff, 0xf4, 0xed, 0xec, 0xff, 0xf5, 0xef, 0xef, 0xff, 0xf9, 0xf6,
0xf8, 0xff, 0xec, 0xe5, 0xe3, 0xff, 0xd9, 0xce, 0xc6, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf3, 0xef, 0xef, 0xff, 0xf4, 0xef, 0xef, 0xff, 0xf6, 0xf0,
0xf0, 0xff, 0xf5, 0xec, 0xec, 0xff, 0xf4, 0xe7, 0xe6, 0xff, 0xf3, 0xe4,
0xe1, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf3, 0xe2,
0xde, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf3, 0xe2, 0xde, 0xff, 0xf3, 0xe2,
0xdf, 0xff, 0xf3, 0xe3, 0xe0, 0xff, 0xf3, 0xe3, 0xe0, 0xff, 0xf2, 0xe3,
0xe0, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf2, 0xe2, 0xdf, 0xff, 0xf1, 0xe2,
0xdf, 0xff, 0xf1, 0xe0, 0xdc, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xed, 0xdd,
0xd7, 0xff, 0xee, 0xde, 0xd8, 0xff, 0xf1, 0xe1, 0xdd, 0xff, 0xf2, 0xe4,
0xe1, 0xff, 0xf3, 0xe8, 0xe7, 0xff, 0xf4, 0xed, 0xed, 0xff, 0xf5, 0xef,
0xef, 0xff, 0xf5, 0xf0, 0xf0, 0xff, 0xf7, 0xf3, 0xf3, 0xff, 0xf0, 0xeb,
0xe9, 0xff, 0xd1, 0xc4, 0xb9, 0xff, 0xd0, 0xba, 0xab, 0xff, 0xcc, 0xbd,
0xb1, 0xff, 0xf3, 0xf1, 0xf2, 0xff, 0xf5, 0xef, 0xef, 0xff, 0xf4, 0xed,
0xec, 0xff, 0xf4, 0xe9, 0xe8, 0xff, 0xf3, 0xe5, 0xe2, 0xff, 0xf2, 0xe2,
0xdf, 0xff, 0xf3, 0xe3, 0xdf, 0xff, 0xf3, 0xe3, 0xe0, 0xff, 0xf3, 0xe2,
0xe0, 0xff, 0xf2, 0xe3, 0xe0, 0xff, 0xf3, 0xe4, 0xe2, 0xff, 0xf3, 0xe4,
0xe2, 0xff, 0xf3, 0xe5, 0xe2, 0xff, 0xf2, 0xe5, 0xe2, 0xff, 0xf2, 0xe4,
0xe1, 0xff, 0xf2, 0xe3, 0xe0, 0xff, 0xf1, 0xe2, 0xdf, 0xff, 0xf1, 0xe1,
0xdd, 0xff, 0xf0, 0xdf, 0xda, 0xff, 0xed, 0xdd, 0xd7, 0xff, 0xef, 0xde,
0xd9, 0xff, 0xf1, 0xe1, 0xde, 0xff, 0xf3, 0xe7, 0xe5, 0xff, 0xf5, 0xed,
0xed, 0xff, 0xf4, 0xef, 0xef, 0xff, 0xf7, 0xf2, 0xf3, 0xff, 0xfd, 0xfd,
0xfe, 0xff, 0xfd, 0xfd, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb6, 0x92,
0x78, 0xff, 0xb4, 0x92, 0x7a, 0xff, 0xf7, 0xf7, 0xf8, 0xff, 0xfc, 0xfa,
0xfb, 0xff, 0xfa, 0xf7, 0xf9, 0xff, 0xf8, 0xf2, 0xf3, 0xff, 0xf5, 0xeb,
0xea, 0xff, 0xf3, 0xe5, 0xe3, 0xff, 0xf1, 0xe2, 0xdf, 0xff, 0xf1, 0xe3,
0xe0, 0xff, 0xf1, 0xe4, 0xe1, 0xff, 0xf2, 0xe4, 0xe2, 0xff, 0xf3, 0xe6,
0xe5, 0xff, 0xf2, 0xe7, 0xe6, 0xff, 0xf2, 0xe7, 0xe6, 0xff, 0xf3, 0xe8,
0xe6, 0xff, 0xf2, 0xe6, 0xe4, 0xff, 0xf2, 0xe4, 0xe2, 0xff, 0xf2, 0xe4,
0xe1, 0xff, 0xf1, 0xe2, 0xdf, 0xff, 0xf1, 0xe1, 0xde, 0xff, 0xf0, 0xdf,
0xdb, 0xff, 0xec, 0xdd, 0xd7, 0xff, 0xef, 0xdf, 0xd9, 0xff, 0xf2, 0xe3,
0xe0, 0xff, 0xf3, 0xea, 0xe9, 0xff, 0xf4, 0xee, 0xee, 0xff, 0xf9, 0xf7,
0xf7, 0xff, 0xf6, 0xf7, 0xf7, 0xff, 0xd3, 0xbe, 0xb0, 0xff, 0xbc, 0x97,
0x7e, 0xff, 0xb7, 0x8b, 0x6b, 0xff, 0xa0, 0x60, 0x33, 0xff, 0xd3, 0xca,
0xc4, 0xff, 0xdb, 0xda, 0xda, 0xff, 0xd5, 0xca, 0xc3, 0xff, 0xde, 0xd4,
0xce, 0xff, 0xe9, 0xe0, 0xdc, 0xff, 0xf1, 0xe9, 0xe7, 0xff, 0xf6, 0xed,
0xec, 0xff, 0xf8, 0xef, 0xf0, 0xff, 0xfa, 0xf4, 0xf6, 0xff, 0xfa, 0xf5,
0xf8, 0xff, 0xfb, 0xf7, 0xf9, 0xff, 0xfc, 0xf8, 0xfb, 0xff, 0xfb, 0xf6,
0xf9, 0xff, 0xfb, 0xf7, 0xfa, 0xff, 0xfb, 0xf8, 0xfb, 0xff, 0xfa, 0xf5,
0xf8, 0xff, 0xfa, 0xf4, 0xf6, 0xff, 0xfa, 0xf3, 0xf4, 0xff, 0xf7, 0xed,
0xed, 0xff, 0xf1, 0xe2, 0xdf, 0xff, 0xf0, 0xdf, 0xda, 0xff, 0xec, 0xdd,
0xd7, 0xff, 0xf0, 0xe0, 0xda, 0xff, 0xf3, 0xe5, 0xe2, 0xff, 0xf4, 0xec,
0xeb, 0xff, 0xf9, 0xf8, 0xf9, 0xff, 0xeb, 0xe5, 0xe1, 0xff, 0xb2, 0x7f,
0x5a, 0xff, 0xb2, 0x83, 0x60, 0xff, 0xc8, 0xad, 0x99, 0xff, 0xc0, 0xa9,
0x96, 0xff, 0xc7, 0xa9, 0x92, 0xff, 0xaa, 0x76, 0x50, 0xff, 0xcb, 0xae,
0x9a, 0xff, 0xef, 0xef, 0xf1, 0xff, 0xd8, 0xcc, 0xc3, 0xff, 0xcc, 0xb9,
0xac, 0xff, 0xca, 0xb6, 0xaa, 0xff, 0xc9, 0xb2, 0xa3, 0xff, 0xce, 0xb5,
0xa6, 0xff, 0xcc, 0xb4, 0xa4, 0xff, 0xd5, 0xc2, 0xb6, 0xff, 0xd5, 0xbf,
0xb1, 0xff, 0xd1, 0xb9, 0xaa, 0xff, 0xd7, 0xc6, 0xbc, 0xff, 0xd6, 0xc3,
0xb8, 0xff, 0xd6, 0xc2, 0xb6, 0xff, 0xdc, 0xcc, 0xc2, 0xff, 0xd7, 0xc3,
0xb8, 0xff, 0xd9, 0xc3, 0xb7, 0xff, 0xe1, 0xcf, 0xc5, 0xff, 0xf4, 0xe9,
0xe8, 0xff, 0xf0, 0xe0, 0xdb, 0xff, 0xec, 0xdc, 0xd6, 0xff, 0xf1, 0xe0,
0xdc, 0xff, 0xf3, 0xe6, 0xe5, 0xff, 0xf6, 0xf1, 0xf1, 0xff, 0xf3, 0xf1,
0xf0, 0xff, 0xac, 0x74, 0x49, 0xff, 0xb3, 0x95, 0x80, 0xff, 0xf5, 0xfc,
0xff, 0xff, 0xee, 0xf2, 0xf4, 0xff, 0xd5, 0xd4, 0xd4, 0xff, 0xf6, 0xfa,
0xfe, 0xff, 0xea, 0xea, 0xe9, 0xff, 0xa0, 0x6d, 0x47, 0xff, 0xcd, 0xb0,
0x9b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xe9, 0xe5, 0xff, 0xdb, 0xcc,
0xc2, 0xff, 0xe2, 0xd9, 0xd4, 0xff, 0xd1, 0xbd, 0xb0, 0xff, 0xda, 0xca,
0xc1, 0xff, 0xb0, 0x87, 0x69, 0xff, 0xb9, 0x96, 0x7c, 0xff, 0xcc, 0xb4,
0xa3, 0xff, 0xa8, 0x7a, 0x59, 0xff, 0xbb, 0x9a, 0x82, 0xff, 0xc4, 0xa7,
0x92, 0xff, 0xa6, 0x76, 0x54, 0xff, 0xc0, 0xa1, 0x8c, 0xff, 0xba, 0x97,
0x7f, 0xff, 0xc5, 0xab, 0x98, 0xff, 0xdf, 0xd0, 0xc8, 0xff, 0xf3, 0xe3,
0xe0, 0xff, 0xea, 0xdb, 0xd4, 0xff, 0xf2, 0xe1, 0xdd, 0xff, 0xf3, 0xe7,
0xe5, 0xff, 0xfd, 0xfe, 0xff, 0xff, 0xca, 0xa7, 0x8a, 0xff, 0xbd, 0x94,
0x77, 0xff, 0xe3, 0xea, 0xf0, 0xff, 0xc8, 0xbf, 0xba, 0xff, 0xd9, 0xd5,
0xd1, 0xff, 0xc9, 0xc2, 0xbd, 0xff, 0xd7, 0xd2, 0xce, 0xff, 0xce, 0xc9,
0xc7, 0xff, 0xd5, 0xd1, 0xcd, 0xff, 0xab, 0x73, 0x48, 0xff, 0xf2, 0xf1,
0xf1, 0xff, 0xcd, 0xae, 0x98, 0xff, 0xa0, 0x5e, 0x2f, 0xff, 0xbf, 0x9a,
0x7f, 0xff, 0xb0, 0x78, 0x51, 0xff, 0xe2, 0xdb, 0xd7, 0xff, 0xbf, 0x9f,
0x88, 0xff, 0xab, 0x75, 0x4f, 0xff, 0xcb, 0xb4, 0xa4, 0xff, 0xc7, 0xad,
0x99, 0xff, 0xac, 0x78, 0x54, 0xff, 0xc4, 0xa9, 0x96, 0xff, 0xc1, 0x9d,
0x84, 0xff, 0xa9, 0x74, 0x50, 0xff, 0xba, 0x92, 0x78, 0xff, 0xda, 0xc6,
0xb9, 0xff, 0xbd, 0x90, 0x71, 0xff, 0xf5, 0xea, 0xe9, 0xff, 0xe8, 0xd9,
0xd1, 0xff, 0xf2, 0xe2, 0xde, 0xff, 0xf3, 0xe9, 0xe8, 0xff, 0xf8, 0xf9,
0xfa, 0xff, 0xb9, 0x84, 0x5a, 0xff, 0xe0, 0xd4, 0xcc, 0xff, 0xf4, 0xf7,
0xf9, 0xff, 0xce, 0xca, 0xc6, 0xff, 0xbe, 0xae, 0xa4, 0xff, 0xc2, 0xb2,
0xa8, 0xff, 0xc2, 0xb4, 0xab, 0xff, 0xd8, 0xd3, 0xd0, 0xff, 0xfd, 0xff,
0xff, 0xff, 0xbd, 0x91, 0x72, 0xff, 0xd6, 0xbe, 0xac, 0xff, 0xc7, 0xa4,
0x89, 0xff, 0xac, 0x77, 0x51, 0xff, 0xa8, 0x6e, 0x43, 0xff, 0xaf, 0x7c,
0x56, 0xff, 0xda, 0xc9, 0xbe, 0xff, 0xbe, 0x99, 0x7e, 0xff, 0xb7, 0x8a,
0x68, 0xff, 0xd7, 0xc6, 0xba, 0xff, 0xbe, 0x9a, 0x81, 0xff, 0xb8, 0x8d,
0x6d, 0xff, 0xd5, 0xc2, 0xb5, 0xff, 0xba, 0x90, 0x73, 0xff, 0xb9, 0x91,
0x73, 0xff, 0xad, 0x74, 0x4e, 0xff, 0xa6, 0x68, 0x3c, 0xff, 0xbe, 0x8d,
0x6c, 0xff, 0xf0, 0xe7, 0xe4, 0xff, 0xe6, 0xd8, 0xd1, 0xff, 0xf1, 0xe1,
0xdd, 0xff, 0xf4, 0xeb, 0xea, 0xff, 0xf3, 0xee, 0xec, 0xff, 0xb3, 0x7e,
0x53, 0xff, 0xd0, 0xc8, 0xc3, 0xff, 0xd1, 0xcd, 0xcb, 0xff, 0xc8, 0xbc,
0xb3, 0xff, 0xb8, 0xa7, 0x9d, 0xff, 0xb6, 0xb2, 0xaf, 0xff, 0xc1, 0xae,
0xa0, 0xff, 0xd4, 0xcd, 0xc8, 0xff, 0xe1, 0xe2, 0xe4, 0xff, 0xc1, 0x9e,
0x85, 0xff, 0xbf, 0x98, 0x7a, 0xff, 0xbc, 0x96, 0x7a, 0xff, 0xce, 0xb0,
0x9c, 0xff, 0xb2, 0x7a, 0x50, 0xff, 0xca, 0xaa, 0x93, 0xff, 0xa8, 0x73,
0x4d, 0xff, 0xa5, 0x6c, 0x43, 0xff, 0xcb, 0xb4, 0xa2, 0xff, 0xc1, 0xa1,
0x8a, 0xff, 0x9e, 0x63, 0x39, 0xff, 0xce, 0xba, 0xaa, 0xff, 0xb2, 0x84,
0x64, 0xff, 0xa7, 0x72, 0x4b, 0xff, 0xd1, 0xbc, 0xae, 0xff, 0xb7, 0x87,
0x68, 0xff, 0xd0, 0xb4, 0xa1, 0xff, 0xb3, 0x83, 0x5f, 0xff, 0xee, 0xe6,
0xe1, 0xff, 0xe6, 0xd9, 0xd1, 0xff, 0xef, 0xe0, 0xdc, 0xff, 0xf4, 0xe9,
0xe7, 0xff, 0xf5, 0xf3, 0xf4, 0xff, 0xb6, 0x81, 0x55, 0xff, 0xd7, 0xcc,
0xc5, 0xff, 0xe5, 0xe6, 0xe5, 0xff, 0xce, 0xc7, 0xc2, 0xff, 0xb5, 0xa1,
0x93, 0xff, 0xb1, 0x9f, 0x92, 0xff, 0xc3, 0xb3, 0xa9, 0xff, 0xcf, 0xc8,
0xc3, 0xff, 0xde, 0xdf, 0xe1, 0xff, 0xb2, 0x89, 0x6b, 0xff, 0xc9, 0xa8,
0x8f, 0xff, 0xee, 0xea, 0xea, 0xff, 0xed, 0xe3, 0xe0, 0xff, 0xe3, 0xd0,
0xc7, 0xff, 0xe6, 0xd6, 0xcd, 0xff, 0xde, 0xcd, 0xc1, 0xff, 0xd2, 0xb7,
0xa4, 0xff, 0xcc, 0xae, 0x98, 0xff, 0xe6, 0xda, 0xd2, 0xff, 0xcd, 0xb2,
0x9e, 0xff, 0xd2, 0xb8, 0xa5, 0xff, 0xe3, 0xd5, 0xcc, 0xff, 0xc7, 0xa7,
0x8f, 0xff, 0xd3, 0xbb, 0xa9, 0xff, 0xdc, 0xca, 0xbe, 0xff, 0xe3, 0xd4,
0xca, 0xff, 0xda, 0xc6, 0xb8, 0xff, 0xe9, 0xde, 0xd7, 0xff, 0xe6, 0xda,
0xd4, 0xff, 0xed, 0xde, 0xd7, 0xff, 0xf1, 0xe4, 0xe0, 0xff, 0xfb, 0xfb,
0xff, 0xff, 0xc8, 0xa1, 0x7b, 0xff, 0xc6, 0xa2, 0x84, 0xff, 0xe9, 0xee,
0xf4, 0xff, 0xba, 0xad, 0xa4, 0xff, 0xd2, 0xca, 0xc5, 0xff, 0xcd, 0xc1,
0xb9, 0xff, 0xc2, 0xb8, 0xb2, 0xff, 0xd9, 0xd5, 0xd2, 0xff, 0xf3, 0xf7,
0xf9, 0xff, 0xac, 0x72, 0x47, 0xff, 0xe8, 0xdc, 0xd4, 0xff, 0xfb, 0xf9,
0xfc, 0xff, 0xf3, 0xe7, 0xe6, 0xff, 0xf0, 0xe3, 0xdf, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xe0, 0xd9, 0xff, 0xed, 0xe4, 0xdf, 0xff, 0xee, 0xe5,
0xe0, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xee, 0xe5, 0xdf, 0xff, 0xed, 0xe3,
0xdd, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xef, 0xe6, 0xe2, 0xff, 0xed, 0xe2,
0xdc, 0xff, 0xec, 0xe0, 0xd9, 0xff, 0xea, 0xde, 0xd7, 0xff, 0xeb, 0xe1,
0xda, 0xff, 0xe7, 0xdb, 0xd3, 0xff, 0xe7, 0xdb, 0xd4, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xee, 0xe0, 0xda, 0xff, 0xf6, 0xed, 0xee, 0xff, 0xec, 0xe6,
0xe0, 0xff, 0xb3, 0x82, 0x4c, 0xff, 0xb5, 0x9b, 0x87, 0xff, 0xec, 0xf1,
0xf6, 0xff, 0xe0, 0xe0, 0xe1, 0xff, 0xd1, 0xcd, 0xcb, 0xff, 0xf2, 0xf5,
0xf8, 0xff, 0xcd, 0xcf, 0xd1, 0xff, 0xaf, 0x7e, 0x5a, 0xff, 0xc6, 0x9f,
0x80, 0xff, 0xfb, 0xfd, 0xff, 0xff, 0xf2, 0xe7, 0xe4, 0xff, 0xf0, 0xe2,
0xde, 0xff, 0xeb, 0xdc, 0xd5, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xe9, 0xdb, 0xd2, 0xff, 0xe8, 0xdb, 0xd3, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xe8, 0xdb, 0xd2, 0xff, 0xe8, 0xdb, 0xd3, 0xff, 0xe8, 0xdc,
0xd4, 0xff, 0xe6, 0xda, 0xd1, 0xff, 0xe8, 0xdb, 0xd3, 0xff, 0xe9, 0xdc,
0xd3, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe9, 0xdb, 0xd3, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe8, 0xdc, 0xd5, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xf0, 0xe2, 0xde, 0xff, 0xf8, 0xf2, 0xf4, 0xff, 0xe4, 0xdb,
0xd0, 0xff, 0xb4, 0x87, 0x53, 0xff, 0xbf, 0x9b, 0x7b, 0xff, 0xc9, 0xb6,
0xa6, 0xff, 0xc5, 0xb5, 0xa8, 0xff, 0xcf, 0xba, 0xa7, 0xff, 0xae, 0x78,
0x4b, 0xff, 0xc2, 0x95, 0x70, 0xff, 0xf7, 0xf7, 0xf9, 0xff, 0xf4, 0xec,
0xec, 0xff, 0xf2, 0xe6, 0xe3, 0xff, 0xee, 0xdf, 0xd9, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xea, 0xdd, 0xd4, 0xff, 0xe9, 0xdc,
0xd5, 0xff, 0xe8, 0xdc, 0xd4, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xed, 0xde,
0xd8, 0xff, 0xf2, 0xe4, 0xe1, 0xff, 0xf8, 0xf2, 0xf5, 0xff, 0xee, 0xea,
0xe8, 0xff, 0xcc, 0xb2, 0x98, 0xff, 0xb8, 0x8f, 0x67, 0xff, 0xb5, 0x89,
0x60, 0xff, 0xbe, 0x96, 0x71, 0xff, 0xdf, 0xcc, 0xba, 0xff, 0xfa, 0xf9,
0xfc, 0xff, 0xf4, 0xeb, 0xea, 0xff, 0xf2, 0xe5, 0xe3, 0xff, 0xee, 0xe0,
0xda, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xe9, 0xde, 0xd6, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xdc,
0xd4, 0xff, 0xea, 0xdd, 0xd4, 0xff, 0xe9, 0xdc, 0xd5, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xe8, 0xdd, 0xd5, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xed, 0xdf,
0xd9, 0xff, 0xf1, 0xe3, 0xe0, 0xff, 0xf5, 0xea, 0xe9, 0xff, 0xfa, 0xf6,
0xf9, 0xff, 0xf8, 0xf5, 0xf8, 0xff, 0xf7, 0xf4, 0xf6, 0xff, 0xfb, 0xfa,
0xfe, 0xff, 0xf9, 0xf5, 0xf8, 0xff, 0xf3, 0xe8, 0xe6, 0xff, 0xf1, 0xe3,
0xdf, 0xff, 0xed, 0xde, 0xd8, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd4, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xea, 0xdc, 0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd4, 0xff, 0xe9, 0xdc, 0xd5, 0xff, 0xea, 0xdd, 0xd4, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xeb, 0xdd,
0xd5, 0xff, 0xed, 0xde, 0xd8, 0xff, 0xef, 0xe0, 0xdc, 0xff, 0xf2, 0xe4,
0xe1, 0xff, 0xf2, 0xe5, 0xe2, 0xff, 0xf0, 0xe3, 0xde, 0xff, 0xee, 0xe1,
0xdc, 0xff, 0xed, 0xdf, 0xd9, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xe9, 0xdc,
0xd5, 0xff, 0xe8, 0xdc, 0xd5, 0xff, 0xea, 0xdd, 0xd4, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xdd, 0xd4, 0xff, 0xe9, 0xdc,
0xd5, 0xff, 0xea, 0xdc, 0xd4, 0xff, 0xea, 0xdc, 0xd4, 0xff, 0xea, 0xdc,
0xd4, 0xff, 0xea, 0xdc, 0xd4, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xea, 0xdc, 0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xec, 0xde,
0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe9, 0xdc, 0xd5, 0xff, 0xe8, 0xdc,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xeb, 0xdd,
0xd5, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xea, 0xdd, 0xd4, 0xff, 0xe9, 0xdc, 0xd5, 0xff, 0xea, 0xdd,
0xd4, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdc, 0xd5, 0xff, 0xe9, 0xdd, 0xd4, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xe8, 0xdd, 0xd6, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdc,
0xd5, 0xff, 0xea, 0xdd, 0xd4, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xeb, 0xdd,
0xd5, 0xff, 0xeb, 0xdd, 0xd5, 0xff, 0xeb, 0xde, 0xd5, 0xff, 0xeb, 0xde,
0xd5, 0xff, 0xeb, 0xde, 0xd5, 0xff, 0xeb, 0xde, 0xd5, 0xff, 0xeb, 0xde,
0xd5, 0xff, 0xeb, 0xde, 0xd5, 0xff, 0xeb, 0xde, 0xd5, 0xff, 0xeb, 0xde,
0xd5, 0xff, 0xeb, 0xde, 0xd5, 0xff, 0xeb, 0xde, 0xd5, 0xff, 0xeb, 0xde,
0xd6, 0xff, 0xeb, 0xde, 0xd6, 0xff, 0xe9, 0xde, 0xd6, 0xff, 0xe8, 0xdd,
0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xe9, 0xdc, 0xd5, 0xff, 0xea, 0xdc,
0xd4, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xde,
0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xdd,
0xd6, 0xff, 0xea, 0xde, 0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xdd,
0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xdd,
0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xdd,
0xd6, 0xff, 0xea, 0xdd, 0xd6, 0xff, 0xea, 0xdd, 0xd5, 0xff, 0xea, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xe8, 0xdc, 0xd5, 0xff, 0xe8, 0xdc, 0xd4, 0xff, 0xe8, 0xdc,
0xd4, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd,
0xd5, 0xff, 0xe9, 0xdd, 0xd5, 0xff, 0xe9, 0xdd, 0xd4, 0xff, 0xe9, 0xdc,
0xd4, 0xff, 0xe9, 0xdc, 0xd4, 0xff, 0xe8, 0xdc, 0xd4, 0xff, 0xe8, 0xdb,
0xd4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int favicon_ico_len = 5686;
/**
* base page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BASE_PAGE_H
#define BASE_PAGE_H
// base page HTML template
static const char *base_page_html =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
" <title>{% block title %}WebSocket SSH Daemon{% endblock %}</title>\n"
" <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n"
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n"
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\">\n"
" <link rel=\"stylesheet\" href=\"https://unpkg.com/xterm@5.3.0/css/xterm.css\">\n"
" <script src=\"https://unpkg.com/xterm@5.3.0/lib/xterm.js\"></script>\n"
" <script src=\"https://unpkg.com/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js\"></script>\n"
" <script>\n"
" // Ensure libraries are loaded\n"
" function checkLibraries() {\n"
" if (typeof Terminal === 'undefined') {\n"
" console.error('Terminal not loaded from CDN');\n"
" return false;\n"
" }\n"
" if (typeof FitAddon === 'undefined') {\n"
" console.error('FitAddon not loaded from CDN');\n"
" return false;\n"
" }\n"
" console.log('All xterm libraries loaded successfully');\n"
" return true;\n"
" }\n"
"\n"
" // Check immediately and after a delay\n"
" if (!checkLibraries()) {\n"
" setTimeout(checkLibraries, 1000);\n"
" }\n"
" </script>\n"
" <style>\n"
" .navbar-brand {\n"
" font-weight: bold;\n"
" }\n"
" .client-card {\n"
" transition: transform 0.2s;\n"
" }\n"
" .client-card:hover {\n"
" transform: translateY(-2px);\n"
" box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n"
" }\n"
" .terminal-container {\n"
" background-color: #1e1e1e;\n"
" color: #f8f8f2;\n"
" font-family: 'Courier New', monospace;\n"
" border-radius: 8px;\n"
" height: calc(100vh - 200px);\n"
" min-height: 400px;\n"
" overflow: hidden;\n"
" position: relative;\n"
" }\n"
" .terminal-input {\n"
" background: transparent;\n"
" border: none;\n"
" color: #f8f8f2;\n"
" font-family: 'Courier New', monospace;\n"
" width: 100%;\n"
" outline: none;\n"
" }\n"
" .terminal-input:focus {\n"
" box-shadow: none;\n"
" }\n"
" </style>\n"
"</head>\n"
"<body>\n"
" <nav class=\"navbar navbar-expand-lg navbar-dark bg-primary\">\n"
" <div class=\"container\">\n"
" <a class=\"navbar-brand\" href=\"{{ url_for('index') }}\">\n"
" <i class=\"fas fa-terminal\"></i> WebSocket SSH Daemon\n"
" </a>\n"
" <div class=\"navbar-nav ms-auto\">\n"
" {% if current_user.is_authenticated %}\n"
" <span class=\"navbar-text me-3\">\n"
" Welcome, {{ current_user.username }}!\n"
" </span>\n"
" <button class=\"btn btn-outline-warning btn-sm me-2\" data-bs-toggle=\"modal\" data-bs-target=\"#donationModal\">\n"
" <i class=\"fas fa-heart\"></i> Donate\n"
" </button>\n"
" <a class=\"nav-link\" href=\"{{ url_for('logout') }}\">\n"
" <i class=\"fas fa-sign-out-alt\"></i> Logout\n"
" </a>\n"
" {% endif %}\n"
" </div>\n"
" </div>\n"
" </nav>\n"
"\n"
" <div class=\"container mt-4\">\n"
" {% with messages = get_flashed_messages(with_categories=true) %}\n"
" {% if messages %}\n"
" {% for category, message in messages %}\n"
" <div class=\"alert alert-{{ 'danger' if category == 'error' else 'info' }} alert-dismissible fade show\" role=\"alert\">\n"
" {{ message }}\n"
" <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\"></button>\n"
" </div>\n"
" {% endfor %}\n"
" {% endif %}\n"
" {% endwith %}\n"
"\n"
" {% block content %}{% endblock %}\n"
" </div>\n"
"\n"
" <!-- Donation Modal -->\n"
" <div class=\"modal fade\" id=\"donationModal\" tabindex=\"-1\">\n"
" <div class=\"modal-dialog\">\n"
" <div class=\"modal-content\">\n"
" <div class=\"modal-header\">\n"
" <h5 class=\"modal-title\">\n"
" <i class=\"fas fa-heart text-danger\"></i> Support WebSocket SSH Development\n"
" </h5>\n"
" <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button>\n"
" </div>\n"
" <div class=\"modal-body\">\n"
" <p class=\"text-muted\">Your support helps us continue developing and maintaining this open-source project!</p>\n"
"\n"
" <div class=\"row\">\n"
" <div class=\"col-md-4 text-center mb-3\">\n"
" <h6><i class=\"fab fa-paypal text-primary\"></i> PayPal</h6>\n"
" <a href=\"https://www.paypal.com/paypalme/nexlab\" target=\"_blank\" class=\"btn btn-primary btn-sm\">\n"
" <i class=\"fab fa-paypal\"></i> Donate via PayPal\n"
" </a>\n"
" <small class=\"d-block text-muted mt-1\">info@nexlab.net</small>\n"
" </div>\n"
"\n"
" <div class=\"col-md-4 text-center mb-3\">\n"
" <h6><i class=\"fab fa-bitcoin text-warning\"></i> Bitcoin</h6>\n"
" <div class=\"mb-2\">\n"
" <img src=\"https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=bitcoin:bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx\" alt=\"BTC QR Code\" class=\"img-fluid rounded\">\n"
" </div>\n"
" <div class=\"input-group input-group-sm\">\n"
" <input type=\"text\" class=\"form-control form-control-sm font-monospace\" value=\"bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx\" readonly style=\"font-size: 0.75rem;\">\n"
" <button class=\"btn btn-outline-secondary btn-sm\" type=\"button\" onclick=\"copyToClipboard('bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx')\">\n"
" <i class=\"fas fa-copy\"></i>\n"
" </button>\n"
" </div>\n"
" </div>\n"
"\n"
" <div class=\"col-md-4 text-center mb-3\">\n"
" <h6><i class=\"fab fa-ethereum text-secondary\"></i> Ethereum</h6>\n"
" <div class=\"mb-2\">\n"
" <img src=\"https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=ethereum:0xdA6dAb526515b5cb556d20269207D43fcc760E51\" alt=\"ETH QR Code\" class=\"img-fluid rounded\">\n"
" </div>\n"
" <div class=\"input-group input-group-sm\">\n"
" <input type=\"text\" class=\"form-control form-control-sm font-monospace\" value=\"0xdA6dAb526515b5cb556d20269207D43fcc760E51\" readonly style=\"font-size: 0.75rem;\">\n"
" <button class=\"btn btn-outline-secondary btn-sm\" type=\"button\" onclick=\"copyToClipboard('0xdA6dAb526515b5cb556d20269207D43fcc760E51')\">\n"
" <i class=\"fas fa-copy\"></i>\n"
" </button>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"\n"
" <hr>\n"
" <p class=\"text-center mb-0\">\n"
" <small class=\"text-muted\">\n"
" Thank you for your support! ❤️\n"
" </small>\n"
" </p>\n"
" </div>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"\n"
" <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n"
" <script src=\"https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js\"></script>\n"
" <script>\n"
" function copyToClipboard(text) {\n"
" navigator.clipboard.writeText(text).then(function() {\n"
" // Show a temporary success message\n"
" const btn = event.target.closest('button');\n"
" const originalHtml = btn.innerHTML;\n"
" btn.innerHTML = '<i class=\"fas fa-check\"></i>';\n"
" btn.classList.remove('btn-outline-secondary');\n"
" btn.classList.add('btn-success');\n"
" setTimeout(() => {\n"
" btn.innerHTML = originalHtml;\n"
" btn.classList.remove('btn-success');\n"
" btn.classList.add('btn-outline-secondary');\n"
" }, 1000);\n"
" });\n"
" }\n"
" </script>\n"
" {% block scripts %}{% endblock %}\n"
"</body>\n"
"</html>\n";
#endif /* BASE_PAGE_H */
/**
* index page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef INDEX_PAGE_H
#define INDEX_PAGE_H
// index page HTML template
static const char *index_page_html =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
" <title>Dashboard - WebSocket SSH Daemon</title>\n"
" <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n"
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n"
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\">\n"
"</head>\n"
"<body>\n"
"<nav class=\"navbar navbar-expand-lg navbar-dark bg-primary\">\n"
"<div class=\"container\">\n"
"<a class=\"navbar-brand\" href=\"/\">\n"
"<i class=\"fas fa-terminal\"></i> WebSocket SSH Daemon</a>\n"
"<div class=\"navbar-nav ms-auto\">\n"
"<span class=\"navbar-text me-3\">%s</span>\n"
"<a class=\"nav-link\" href=\"/logout\">Logout</a>\n"
"</div></div></nav>\n"
"%s\n"
"<div class=\"container mt-4\">\n"
"<div class=\"row\">\n"
" <div class=\"col-md-8\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header\">\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-server\"></i> Registered Clients\n"
" </h3>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" <div id=\"client-list\">%s</div>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"\n"
" <div class=\"col-md-4\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header\">\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-cogs\"></i> Quick Actions\n"
" </h3>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" %s\n"
" <button class=\"btn btn-outline-secondary btn-sm w-100\" onclick=\"location.reload()\">\n"
" <i class=\"fas fa-sync\"></i> Refresh Status\n"
" </button>\n"
" </div>\n"
" </div>\n"
"\n"
" <div class=\"card mt-3\">\n"
" <div class=\"card-header\">\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-info-circle\"></i> System Info\n"
" </h3>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" <p class=\"mb-1\"><strong>WebSocket Port:</strong> <span id=\"websocket-port\">%d</span></p>\n"
" <p class=\"mb-1\"><strong>Domain:</strong> <span id=\"domain\">%s</span></p>\n"
" <p class=\"mb-0\"><strong>Connected Clients:</strong> <span id=\"client-count\">%d</span></p>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"</div>\n"
"<script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n"
"<script>\n"
"function showNotification(message, type = 'info') {\n"
" const notificationArea = document.getElementById('notification-area');\n"
" const notification = document.createElement('div');\n"
" notification.className = `alert alert-${type} alert-dismissible fade show`;\n"
" notification.innerHTML = `${message}<button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\"></button>`;\n"
" notificationArea.appendChild(notification);\n"
" setTimeout(() => {\n"
" if (notification.parentNode) {\n"
" notification.remove();\n"
" }\n"
" }, 5000);\n"
"}\n"
"\n"
"function updateClients() {\n"
" fetch('/api/clients')\n"
" .then(response => response.json())\n"
" .then(data => {\n"
" // Update client count\n"
" document.getElementById('client-count').textContent = data.count;\n"
"\n"
" // Generate HTML for client list\n"
" let clientListHtml = '';\n"
" if (data.count === 0) {\n"
" clientListHtml = '<div class=\"text-center py-5\"><i class=\"fas fa-server fa-4x text-muted mb-3\"></i><h4 class=\"text-muted\">No clients registered</h4><p class=\"text-muted\">Clients will appear here when they register.</p></div>';\n"
" } else {\n"
" for (const [clientId, clientData] of Object.entries(data.clients)) {\n"
" const statusIcon = clientData.status === 'connected' ? 'fa-desktop text-success' : 'fa-server text-warning';\n"
" const statusText = clientData.status === 'connected' ? 'Connected' : 'Registered';\n"
" const services = clientData.services;\n"
" let actionsHtml = '';\n"
" if (services.includes('ssh')) {\n"
" actionsHtml += `<a href=\"/terminal/${clientId}\" class=\"btn btn-primary btn-sm me-1\"><i class=\"fas fa-terminal\"></i> SSH</a>`;\n"
" }\n"
" // Add other services if needed\n"
" clientListHtml += `\n"
" <div class=\"col-md-4 mb-3\">\n"
" <div class=\"card client-card h-100\">\n"
" <div class=\"card-body text-center\">\n"
" <i class=\"fas ${statusIcon} fa-3x mb-3\"></i>\n"
" <h5 class=\"card-title\">${clientId}</h5>\n"
" <p class=\"card-text text-muted\">${statusText}</p>\n"
" <p class=\"card-text small\">Services: ${services}</p>\n"
" <div class=\"d-flex justify-content-center\">${actionsHtml}</div>\n"
" </div>\n"
" </div>\n"
" </div>`;\n"
" }\n"
" }\n"
"\n"
" // Update client list only if changed\n"
" const clientListDiv = document.getElementById('client-list');\n"
" if (clientListDiv.innerHTML !== clientListHtml) {\n"
" clientListDiv.innerHTML = clientListHtml;\n"
" }\n"
" })\n"
" .catch(error => {\n"
" console.log('Error fetching client data:', error);\n"
" });\n"
"}\n"
"\n"
"// Update every 5 seconds\n"
"setInterval(updateClients, 5000);\n"
"\n"
"// Initial update after 1 second\n"
"setTimeout(updateClients, 1000);\n"
"</script>\n"
"</body>\n"
"</html>\n";
#endif /* INDEX_PAGE_H */
/**
* login page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef LOGIN_PAGE_H
#define LOGIN_PAGE_H
// login page HTML template
static const char *login_page_html =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
" <title>Login - WebSocket SSH Daemon</title>\n"
" <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n"
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n"
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\">\n"
"</head>\n"
"<body>\n"
"<nav class=\"navbar navbar-expand-lg navbar-dark bg-primary\">\n"
"<div class=\"container\">\n"
"<a class=\"navbar-brand\" href=\"/\">\n"
"<i class=\"fas fa-terminal\"></i> WebSocket SSH Daemon</a>\n"
"</div></nav>\n"
"<div class=\"container mt-4\">\n"
"<div class=\"row justify-content-center\">\n"
" <div class=\"col-md-6\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header\">\n"
" <h3 class=\"card-title mb-0\"><i class=\"fas fa-sign-in-alt\"></i> Login</h3>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" <form method=\"post\">\n"
" <div class=\"mb-3\">\n"
" <label for=\"username\" class=\"form-label\">Username</label>\n"
" <input type=\"text\" class=\"form-control\" id=\"username\" name=\"username\" required>\n"
" </div>\n"
" <div class=\"mb-3\">\n"
" <label for=\"password\" class=\"form-label\">Password</label>\n"
" <input type=\"password\" class=\"form-control\" id=\"password\" name=\"password\" required>\n"
" </div>\n"
" <button type=\"submit\" class=\"btn btn-primary\">\n"
" <i class=\"fas fa-sign-in-alt\"></i> Login\n"
" </button>\n"
" </form>\n"
" <div class=\"mt-3\">\n"
" <small class=\"text-muted\">\n"
" Default credentials: admin / admin123\n"
" </small>\n"
" </div>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"</div>\n"
"<script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n"
"</body>\n"
"</html>\n";
#endif /* LOGIN_PAGE_H */
/**
* terminal page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef TERMINAL_PAGE_H
#define TERMINAL_PAGE_H
// terminal page HTML template
static const char *terminal_page_html =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
" <title>Terminal - %s</title>\n"
" <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n"
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n"
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\">\n"
" <link rel=\"stylesheet\" href=\"https://unpkg.com/xterm@5.3.0/css/xterm.css\">\n"
" <script src=\"/xterm.js\"></script>\n"
" <script src=\"/xterm-addon-fit.js\"></script>\n"
" <script>\n"
" // Ensure libraries are loaded\n"
" function checkLibraries() {\n"
" if (typeof Terminal === 'undefined') {\n"
" console.error('Terminal not loaded from CDN');\n"
" return false;\n"
" }\n"
" if (typeof FitAddon === 'undefined') {\n"
" console.error('FitAddon not loaded from CDN');\n"
" return false;\n"
" }\n"
" console.log('All xterm libraries loaded successfully');\n"
" return true;\n"
" }\n"
"\n"
" // Check immediately and after a delay\n"
" if (!checkLibraries()) {\n"
" setTimeout(checkLibraries, 1000);\n"
" }\n"
" </script>\n"
" <style>\n"
" .navbar-brand {\n"
" font-weight: bold;\n"
" }\n"
" .client-card {\n"
" transition: transform 0.2s;\n"
" }\n"
" .client-card:hover {\n"
" transform: translateY(-2px);\n"
" box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n"
" }\n"
" .terminal-container {\n"
" background-color: #1e1e1e;\n"
" color: #f8f8f2;\n"
" font-family: 'Courier New', monospace;\n"
" border-radius: 8px;\n"
" height: calc(100vh - 200px);\n"
" min-height: 400px;\n"
" overflow: hidden;\n"
" position: relative;\n"
" }\n"
" .terminal-input {\n"
" background: transparent;\n"
" border: none;\n"
" color: #f8f8f2;\n"
" font-family: 'Courier New', monospace;\n"
" width: 100%;\n"
" outline: none;\n"
" }\n"
" .terminal-input:focus {\n"
" box-shadow: none;\n"
" }\n"
" </style>\n"
"</head>\n"
"<body>\n"
"<nav class=\"navbar navbar-expand-lg navbar-dark bg-primary\">\n"
"<div class=\"container\">\n"
"<a class=\"navbar-brand\" href=\"/\">\n"
"<i class=\"fas fa-terminal\"></i> WebSocket SSH Daemon</a>\n"
"<div class=\"navbar-nav ms-auto\">\n"
"<span class=\"navbar-text me-3\">SSH Terminal - %s</span>\n"
"<a class=\"nav-link\" href=\"/logout\">Logout</a>\n"
"</div></div></nav>\n"
"<div id=\"notification-area\" class=\"position-fixed top-0 end-0 p-3\" style=\"z-index: 1050;\"></div>\n"
"<div class=\"container mt-4\">\n"
"<div class=\"row\">\n"
" <div class=\"col-12\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header d-flex justify-content-between align-items-center\">\n"
" <div class=\"d-flex align-items-center\">\n"
" <a href=\"/\" class=\"btn btn-outline-secondary btn-sm me-3\">\n"
" <i class=\"fas fa-arrow-left\"></i> Back to Dashboard\n"
" </a>\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-terminal\"></i> SSH Terminal - %s\n"
" </h3>\n"
" </div>\n"
" <div>\n"
" <input type=\"text\" id=\"sshUsername\" class=\"form-control form-control-sm d-inline-block w-auto me-2\" placeholder=\"Username\" value=\"root\">\n"
" <button id=\"connectBtn\" class=\"btn btn-success btn-sm\">\n"
" <i class=\"fas fa-play\"></i> Connect\n"
" </button>\n"
" <button id=\"disconnectBtn\" class=\"btn btn-danger btn-sm\" disabled>\n"
" <i class=\"fas fa-stop\"></i> Disconnect\n"
" </button>\n"
" <button id=\"fullscreenBtn\" class=\"btn btn-secondary btn-sm\" title=\"Toggle Fullscreen\">\n"
" <i class=\"fas fa-expand\"></i>\n"
" </button>\n"
" </div>\n"
" </div>\n"
" <div class=\"card-body p-2\">\n"
" <div id=\"terminal\" class=\"terminal-container w-100\"></div>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"</div>\n"
"\n"
"<script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n"
"<script>\n"
"console.log('Terminal script starting...');\n"
"console.log('xterm available:', typeof Terminal);\n"
"console.log('xterm-fit available:', typeof FitAddon);\n"
"\n"
"let term = null;\n"
"let fitAddon = null;\n"
"let connected = false;\n"
"let requestId = null;\n"
"let pollInterval = null;\n"
"\n"
"console.log('Terminal page loaded, adding event listeners');\n"
"document.getElementById('connectBtn').addEventListener('click', connect);\n"
"document.getElementById('disconnectBtn').addEventListener('click', disconnect);\n"
"document.getElementById('fullscreenBtn').addEventListener('click', toggleFullscreen);\n"
"console.log('Event listeners added');\n"
"\n"
"// Fullscreen functionality\n"
"function toggleFullscreen() {\n"
" const terminalContainer = document.getElementById('terminal');\n"
" const fullscreenBtn = document.getElementById('fullscreenBtn');\n"
" const icon = fullscreenBtn.querySelector('i');\n"
"\n"
" if (!document.fullscreenElement) {\n"
" // Enter fullscreen\n"
" if (terminalContainer.requestFullscreen) {\n"
" terminalContainer.requestFullscreen();\n"
" } else if (terminalContainer.webkitRequestFullscreen) { // Safari\n"
" terminalContainer.webkitRequestFullscreen();\n"
" } else if (terminalContainer.msRequestFullscreen) { // IE11\n"
" terminalContainer.msRequestFullscreen();\n"
" }\n"
" } else {\n"
" // Exit fullscreen\n"
" if (document.exitFullscreen) {\n"
" document.exitFullscreen();\n"
" } else if (document.webkitExitFullscreen) { // Safari\n"
" document.webkitExitFullscreen();\n"
" } else if (document.msExitFullscreen) { // IE11\n"
" document.msExitFullscreen();\n"
" }\n"
" }\n"
"}\n"
"\n"
"// Update fullscreen button icon based on state\n"
"function updateFullscreenButton() {\n"
" const fullscreenBtn = document.getElementById('fullscreenBtn');\n"
" const icon = fullscreenBtn.querySelector('i');\n"
"\n"
" if (document.fullscreenElement) {\n"
" icon.className = 'fas fa-compress';\n"
" fullscreenBtn.title = 'Exit Fullscreen';\n"
" } else {\n"
" icon.className = 'fas fa-expand';\n"
" fullscreenBtn.title = 'Enter Fullscreen';\n"
" }\n"
"}\n"
"\n"
"// Listen for fullscreen changes\n"
"function handleFullscreenChange() {\n"
" updateFullscreenButton();\n"
" // Resize terminal after fullscreen change\n"
" setTimeout(() => {\n"
" if (window.fitTerminal) {\n"
" window.fitTerminal();\n"
" }\n"
" // Update backend terminal size if connected\n"
" if (connected && requestId && fitAddon) {\n"
" const newDimensions = fitAddon.proposeDimensions();\n"
" const newCols = newDimensions.cols || 80;\n"
" const newRows = newDimensions.rows || 24;\n"
"\n"
" fetch('/terminal/%s/xterm/resize', {\n"
" method: 'POST',\n"
" headers: {\n"
" 'Content-Type': 'application/x-www-form-urlencoded',\n"
" },\n"
" body: 'request_id=' + encodeURIComponent(requestId) +\n"
" '&cols=' + encodeURIComponent(newCols) +\n"
" '&rows=' + encodeURIComponent(newRows)\n"
" }).catch(error => {\n"
" console.error('Resize error during fullscreen change:', error);\n"
" });\n"
" }\n"
" }, 100); // Small delay to ensure DOM is updated\n"
"}\n"
"\n"
"document.addEventListener('fullscreenchange', handleFullscreenChange);\n"
"document.addEventListener('webkitfullscreenchange', handleFullscreenChange); // Safari\n"
"document.addEventListener('msfullscreenchange', handleFullscreenChange); // IE11\n"
"\n"
"function connect() {\n"
" console.log('Connect button clicked');\n"
" console.log('Connect function called');\n"
" if (typeof Terminal === 'undefined') {\n"
" alert('xterm.js library failed to load. Please check your internet connection or refresh the page.');\n"
" return;\n"
" }\n"
" const username = document.getElementById('sshUsername').value;\n"
" console.log('Username value:', username);\n"
" if (!username) {\n"
" alert('Please enter a username');\n"
" return;\n"
" }\n"
" console.log('Username validation passed');\n"
"\n"
" // Initialize xterm with proper configuration\n"
" if (!term) {\n"
" term = new Terminal({\n"
" cursorBlink: true,\n"
" cursorStyle: 'block',\n"
" fontSize: 14,\n"
" fontFamily: 'Monaco, Menlo, \"Ubuntu Mono\", monospace',\n"
" theme: {\n"
" background: '#1e1e1e',\n"
" foreground: '#f8f8f2',\n"
" cursor: '#f8f8f2',\n"
" cursorAccent: '#1e1e1e',\n"
" selection: 'rgba(248, 248, 242, 0.3)'\n"
" },\n"
" allowTransparency: true,\n"
" scrollback: 1000,\n"
" tabStopWidth: 4,\n"
" convertEol: true,\n"
" disableStdin: false,\n"
" cursorWidth: 2,\n"
" bellStyle: 'none',\n"
" rightClickSelectsWord: true,\n"
" fastScrollModifier: 'alt',\n"
" fastScrollSensitivity: 5,\n"
" screenReaderMode: false,\n"
" macOptionIsMeta: false,\n"
" macOptionClickForcesSelection: false,\n"
" minimumContrastRatio: 1\n"
" });\n"
" term.open(document.getElementById('terminal'));\n"
"\n"
" // Load fit addon\n"
" try {\n"
" if (typeof FitAddon !== 'undefined') {\n"
" fitAddon = new FitAddon.FitAddon();\n"
" term.loadAddon(fitAddon);\n"
" console.log('FitAddon loaded successfully');\n"
" } else {\n"
" console.error('FitAddon is not available');\n"
" throw new Error('FitAddon not loaded');\n"
" }\n"
" } catch (e) {\n"
" console.error('Failed to load FitAddon:', e);\n"
" term.write('Warning: Terminal auto-resizing not available\\r\\n');\n"
" // Continue without fit addon - terminal will still work\n"
" }\n"
"\n"
" // Initial fit after a short delay to ensure DOM is ready\n"
" setTimeout(() => {\n"
" window.fitTerminal();\n"
" // Calculate dimensions after initial fit\n"
" let initialDimensions = { cols: 80, rows: 24 };\n"
" if (fitAddon) {\n"
" initialDimensions = fitAddon.proposeDimensions();\n"
" }\n"
" term._initialCols = initialDimensions.cols || 80;\n"
" term._initialRows = initialDimensions.rows || 24;\n"
" }, 100);\n"
"\n"
" // Fit on window resize and update backend terminal size\n"
" window.addEventListener('resize', () => {\n"
" window.fitTerminal();\n"
" // Update terminal size on backend if connected\n"
" if (connected && requestId && fitAddon) {\n"
" const newDimensions = fitAddon.proposeDimensions();\n"
" const newCols = newDimensions.cols || 80;\n"
" const newRows = newDimensions.rows || 24;\n"
"\n"
" fetch('/terminal/%s/xterm/resize', {\n"
" method: 'POST',\n"
" headers: {\n"
" 'Content-Type': 'application/x-www-form-urlencoded',\n"
" },\n"
" body: 'request_id=' + encodeURIComponent(requestId) +\n"
" '&cols=' + encodeURIComponent(newCols) +\n"
" '&rows=' + encodeURIComponent(newRows)\n"
" }).catch(error => {\n"
" console.error('Resize error:', error);\n"
" });\n"
" }\n"
" });\n"
"\n"
" term.focus();\n"
" }\n"
"\n"
" // Define fitTerminal function globally for fullscreen handling\n"
" window.fitTerminal = function() {\n"
" if (fitAddon) {\n"
" fitAddon.fit();\n"
" }\n"
" };\n"
"\n"
" term.write('Connecting to ' + username + '@%s...\\r\\n');\n"
"\n"
" connected = true;\n"
" document.getElementById('connectBtn').disabled = true;\n"
" document.getElementById('disconnectBtn').disabled = false;\n"
" document.getElementById('sshUsername').disabled = true;\n"
"\n"
" // Use calculated dimensions (either from initial fit or current)\n"
" let cols = term._initialCols || 80;\n"
" let rows = term._initialRows || 24;\n"
" if (fitAddon) {\n"
" const dimensions = fitAddon.proposeDimensions();\n"
" cols = dimensions.cols || cols;\n"
" rows = dimensions.rows || rows;\n"
" }\n"
"\n"
" // Send connect request with terminal dimensions\n"
" const connectUrl = '/terminal/%s/xterm/connect';\n"
" console.log('Sending connect request to:', connectUrl);\n"
" console.log('Username:', username, 'Cols:', cols, 'Rows:', rows);\n"
"\n"
" fetch(connectUrl, {\n"
" method: 'POST',\n"
" headers: {\n"
" 'Content-Type': 'application/x-www-form-urlencoded',\n"
" },\n"
" body: 'username=' + encodeURIComponent(username) +\n"
" '&cols=' + encodeURIComponent(cols) +\n"
" '&rows=' + encodeURIComponent(rows),\n"
" // Add timeout and credentials\n"
" credentials: 'same-origin'\n"
" })\n"
" .then(response => {\n"
" console.log('Connect response status:', response.status, 'OK:', response.ok);\n"
" if (!response.ok) {\n"
" throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n"
" }\n"
" return response.json();\n"
" })\n"
" .then(data => {\n"
" console.log('Connect response data:', data);\n"
" if (data.request_id) {\n"
" requestId = data.request_id;\n"
" if (data.command) {\n"
" console.log('Launching command:', data.command);\n"
" }\n"
" term.write('Connected successfully!\\r\\n');\n"
" pollInterval = setInterval(pollData, 500);\n"
" // Poll immediately to get any buffered output\n"
" pollData();\n"
" } else {\n"
" term.write('Error: ' + (data.error || 'Unknown error') + '\\r\\n');\n"
" disconnect();\n"
" }\n"
" })\n"
" .catch(error => {\n"
" console.error('Connection failed:', error);\n"
" term.write('Connection failed: ' + error.message + '\\r\\n');\n"
" disconnect();\n"
" });\n"
"\n"
" // Handle input - send all keystrokes to server, let SSH handle echo\n"
" term.onKey(e => {\n"
" if (!connected || !requestId) return;\n"
"\n"
" let data = e.key;\n"
" console.log('Sending input data:', data);\n"
"\n"
" // Send to server\n"
" fetch('/terminal/%s/xterm/data', {\n"
" method: 'POST',\n"
" headers: {\n"
" 'Content-Type': 'application/x-www-form-urlencoded',\n"
" },\n"
" body: 'request_id=' + encodeURIComponent(requestId) + '&data=' + encodeURIComponent(data)\n"
" }).then(response => {\n"
" if (response.status !== 200) {\n"
" console.log('Input send response status:', response.status);\n"
" }\n"
" }).catch(error => {\n"
" console.error('Input send error:', error);\n"
" });\n"
"\n"
" // Prevent local display of input\n"
" e.domEvent.preventDefault();\n"
" });\n"
"}\n"
"\n"
"function disconnect() {\n"
" connected = false;\n"
" document.getElementById('connectBtn').disabled = false;\n"
" document.getElementById('disconnectBtn').disabled = true;\n"
" document.getElementById('sshUsername').disabled = false;\n"
"\n"
" if (pollInterval) {\n"
" clearInterval(pollInterval);\n"
" pollInterval = null;\n"
" }\n"
"\n"
" if (requestId) {\n"
" fetch('/terminal/%s/xterm/disconnect', {\n"
" method: 'POST',\n"
" headers: {\n"
" 'Content-Type': 'application/x-www-form-urlencoded',\n"
" },\n"
" body: 'request_id=' + encodeURIComponent(requestId)\n"
" });\n"
" requestId = null;\n"
" }\n"
"\n"
" if (term) {\n"
" term.write('\\r\\nDisconnect\\r\\n');\n"
" setTimeout(() => {\n"
" location.reload();\n"
" }, 3000);\n"
" }\n"
"}\n"
"\n"
"function pollData() {\n"
" if (!requestId) return;\n"
" fetch('/terminal/%s/xterm/data?request_id=' + encodeURIComponent(requestId))\n"
" .then(response => {\n"
" if (response.status !== 200) {\n"
" console.log('Poll response status:', response.status);\n"
" }\n"
" const contentType = response.headers.get('content-type');\n"
" if (contentType && contentType.includes('json')) {\n"
" return response.json();\n"
" } else {\n"
" return response.arrayBuffer();\n"
" }\n"
" })\n"
" .then(data => {\n"
" console.log('Poll data received:', data);\n"
" if (data.ended !== undefined) {\n"
" console.log('Session ended, reloading page');\n"
" if (pollInterval) {\n"
" clearInterval(pollInterval);\n"
" pollInterval = null;\n"
" }\n"
" location.reload();\n"
" } else if (data) {\n"
" console.log('Received data:', data.byteLength || data.length, 'bytes/characters');\n"
" // Write data to terminal\n"
" if (data.byteLength !== undefined) {\n"
" // Binary data\n"
" term.write(new Uint8Array(data));\n"
" } else {\n"
" // Text data\n"
" term.write(data);\n"
" }\n"
" }\n"
" })\n"
" .catch(error => {\n"
" console.error('Polling error:', error);\n"
" // Stop polling on error\n"
" if (pollInterval) {\n"
" clearInterval(pollInterval);\n"
" pollInterval = null;\n"
" }\n"
" });\n"
"}\n"
"\n"
"// Focus on terminal when connected\n"
"document.addEventListener('keydown', function(e) {\n"
" if (connected && term) {\n"
" term.focus();\n"
" }\n"
"});\n"
"</script>\n"
"</body>\n"
"</html>\n"
;
#endif /* TERMINAL_PAGE_H */
/**
* users page HTML template for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef USERS_PAGE_H
#define USERS_PAGE_H
// users page HTML template
static const char *users_page_html =
"<!DOCTYPE html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"UTF-8\">\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
" <title>Users - WebSocket SSH Daemon</title>\n"
" <link rel=\"icon\" href=\"/favicon.ico\" type=\"image/x-icon\">\n"
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n"
" <link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\">\n"
"</head>\n"
"<body>\n"
"<nav class=\"navbar navbar-expand-lg navbar-dark bg-primary\">\n"
"<div class=\"container\">\n"
"<a class=\"navbar-brand\" href=\"/\">\n"
"<i class=\"fas fa-terminal\"></i> WebSocket SSH Daemon</a>\n"
"<div class=\"navbar-nav ms-auto\">\n"
"<span class=\"navbar-text me-3\">%s</span>\n"
"<a class=\"nav-link\" href=\"/logout\">Logout</a>\n"
"</div></div></nav>\n"
"<div class=\"container mt-4\">\n"
" <div class=\"card\">\n"
" <div class=\"card-header d-flex justify-content-between align-items-center\">\n"
" <h3 class=\"card-title mb-0\">\n"
" <i class=\"fas fa-users\"></i> User Management\n"
" </h3>\n"
" <div>\n"
" <a href=\"/\" class=\"btn btn-outline-secondary btn-sm me-2\">\n"
" <i class=\"fas fa-home\"></i> Back to Home\n"
" </a>\n"
" <button class=\"btn btn-primary btn-sm\" data-bs-toggle=\"modal\" data-bs-target=\"#addUserModal\">\n"
" <i class=\"fas fa-plus\"></i> Add User\n"
" </button>\n"
" </div>\n"
" </div>\n"
" <div class=\"card-body\">\n"
" <div class=\"table-responsive\">\n"
" <table class=\"table table-striped\">\n"
" <thead>\n"
" <tr>\n"
" <th>Username</th>\n"
" <th>Role</th>\n"
" <th>Actions</th>\n"
" </tr>\n"
" </thead>\n"
" <tbody>\n"
" %s\n"
" </tbody>\n"
" </table>\n"
" </div>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"\n"
"<!-- Add User Modal -->\n"
"<div class=\"modal fade\" id=\"addUserModal\" tabindex=\"-1\">\n"
" <div class=\"modal-dialog\">\n"
" <div class=\"modal-content\">\n"
" <div class=\"modal-header\">\n"
" <h5 class=\"modal-title\">Add New User</h5>\n"
" <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button>\n"
" </div>\n"
" <form id=\"addUserForm\">\n"
" <div class=\"modal-body\">\n"
" <div class=\"mb-3\">\n"
" <label for=\"addUsername\" class=\"form-label\">Username</label>\n"
" <input type=\"text\" class=\"form-control\" id=\"addUsername\" name=\"username\" required>\n"
" </div>\n"
" <div class=\"mb-3\">\n"
" <label for=\"addPassword\" class=\"form-label\">Password</label>\n"
" <input type=\"password\" class=\"form-control\" id=\"addPassword\" name=\"password\" required>\n"
" </div>\n"
" <div class=\"mb-3 form-check\">\n"
" <input type=\"checkbox\" class=\"form-check-input\" id=\"addIsAdmin\" name=\"is_admin\">\n"
" <label class=\"form-check-label\" for=\"addIsAdmin\">Administrator</label>\n"
" </div>\n"
" </div>\n"
" <div class=\"modal-footer\">\n"
" <button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button>\n"
" <button type=\"submit\" class=\"btn btn-primary\">Add User</button>\n"
" </div>\n"
" </form>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"\n"
"<!-- Edit User Modal -->\n"
"<div class=\"modal fade\" id=\"editUserModal\" tabindex=\"-1\">\n"
" <div class=\"modal-dialog\">\n"
" <div class=\"modal-content\">\n"
" <div class=\"modal-header\">\n"
" <h5 class=\"modal-title\">Edit User</h5>\n"
" <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button>\n"
" </div>\n"
" <form id=\"editUserForm\">\n"
" <input type=\"hidden\" id=\"editUserId\" name=\"user_id\">\n"
" <div class=\"modal-body\">\n"
" <div class=\"mb-3\">\n"
" <label for=\"editUsername\" class=\"form-label\">Username</label>\n"
" <input type=\"text\" class=\"form-control\" id=\"editUsername\" name=\"username\" required>\n"
" </div>\n"
" <div class=\"mb-3\">\n"
" <label for=\"editPassword\" class=\"form-label\">New Password (leave empty to keep current)</label>\n"
" <input type=\"password\" class=\"form-control\" id=\"editPassword\" name=\"password\">\n"
" </div>\n"
" <div class=\"mb-3 form-check\">\n"
" <input type=\"checkbox\" class=\"form-check-input\" id=\"editIsAdmin\" name=\"is_admin\">\n"
" <label class=\"form-check-label\" for=\"editIsAdmin\">Administrator</label>\n"
" </div>\n"
" </div>\n"
" <div class=\"modal-footer\">\n"
" <button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button>\n"
" <button type=\"submit\" class=\"btn btn-primary\">Update User</button>\n"
" </div>\n"
" </form>\n"
" </div>\n"
" </div>\n"
"</div>\n"
"\n"
"<script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script>\n"
"<script>\n"
"function editUser(userId, username, isAdmin) {\n"
" document.getElementById('editUserId').value = userId;\n"
" document.getElementById('editUsername').value = username;\n"
" document.getElementById('editPassword').value = '';\n"
" document.getElementById('editIsAdmin').checked = isAdmin;\n"
" new bootstrap.Modal(document.getElementById('editUserModal')).show();\n"
"}\n"
"\n"
"function deleteUser(userId, username) {\n"
" if (confirm(`Are you sure you want to delete user \"${username}\"?`)) {\n"
" fetch(`/delete_user/${userId}`, {\n"
" method: 'POST',\n"
" headers: {'Content-Type': 'application/x-www-form-urlencoded'}\n"
" })\n"
" .then(response => response.json())\n"
" .then(data => {\n"
" if (data.success) location.reload();\n"
" else alert('Error: ' + data.error);\n"
" });\n"
" }\n"
"}\n"
"\n"
"document.getElementById('addUserForm').addEventListener('submit', function(e) {\n"
" e.preventDefault();\n"
" const formData = new FormData(this);\n"
" fetch('/add_user', {method: 'POST', body: formData})\n"
" .then(response => response.json())\n"
" .then(data => {\n"
" if (data.success) {\n"
" bootstrap.Modal.getInstance(document.getElementById('addUserModal')).hide();\n"
" location.reload();\n"
" } else alert('Error: ' + data.error);\n"
" });\n"
"});\n"
"\n"
"document.getElementById('editUserForm').addEventListener('submit', function(e) {\n"
" e.preventDefault();\n"
" const formData = new FormData(this);\n"
" const userId = document.getElementById('editUserId').value;\n"
" fetch(`/edit_user/${userId}`, {method: 'POST', body: formData})\n"
" .then(response => response.json())\n"
" .then(data => {\n"
" if (data.success) {\n"
" bootstrap.Modal.getInstance(document.getElementById('editUserModal')).hide();\n"
" location.reload();\n"
" } else alert('Error: ' + data.error);\n"
" });\n"
"});\n"
"</script>\n"
"</body>\n"
"</html>\n";
#endif /* USERS_PAGE_H */
/**
* xterm-addon-fit.js library for wssshd
*
* Copyright (C) 2024 Stefy Lanza <stefy@nexlab.net> and SexHack.me
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef XTERM_ADDON_PAGE_H
#define XTERM_ADDON_PAGE_H
// xterm-addon-fit.js library
const char *xterm_addon_fit_js =
"!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define([],t):\"object\"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(()=>(()=>{\"use strict\";var e={};return(()=>{var t=e;Object.defineProperty(t,\"__esModule\",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue(\"height\")),s=Math.max(0,parseInt(i.getPropertyValue(\"width\"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue(\"padding-top\"))+parseInt(n.getPropertyValue(\"padding-bottom\"))),a=s-(parseInt(n.getPropertyValue(\"padding-right\"))+parseInt(n.getPropertyValue(\"padding-left\")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})()));\n"
"//# sourceMappingURL=xterm-addon-fit.js.map\n";
#endif /* XTERM_ADDON_PAGE_H */
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
File added
File added
...@@ -354,10 +354,9 @@ function connect() { ...@@ -354,10 +354,9 @@ function connect() {
console.log('Launching command:', data.command); console.log('Launching command:', data.command);
} }
term.write('Connected successfully!\r\n'); term.write('Connected successfully!\r\n');
pollInterval = setInterval(pollData, 500);
setTimeout(() => { // Poll immediately to get any buffered output
pollInterval = setInterval(pollData, 100); pollData();
}, 100);
} else { } else {
term.write('Error: ' + (data.error || 'Unknown error') + '\r\n'); term.write('Error: ' + (data.error || 'Unknown error') + '\r\n');
disconnect(); disconnect();
...@@ -419,7 +418,10 @@ function disconnect() { ...@@ -419,7 +418,10 @@ function disconnect() {
} }
if (term) { if (term) {
term.write('\r\nDisconnected.\r\n'); term.write('\r\nDisconnect\r\n');
setTimeout(() => {
location.reload();
}, 3000);
} }
} }
...@@ -441,8 +443,10 @@ function pollData() { ...@@ -441,8 +443,10 @@ function pollData() {
console.log('Poll data received:', data); console.log('Poll data received:', data);
if (data.ended !== undefined) { if (data.ended !== undefined) {
console.log('Session ended, reloading page'); console.log('Session ended, reloading page');
clearInterval(pollInterval); if (pollInterval) {
pollInterval = null; clearInterval(pollInterval);
pollInterval = null;
}
location.reload(); location.reload();
} else if (data) { } else if (data) {
console.log('Received data:', data.byteLength || data.length, 'bytes/characters'); console.log('Received data:', data.byteLength || data.length, 'bytes/characters');
......
...@@ -354,10 +354,9 @@ function connect() { ...@@ -354,10 +354,9 @@ function connect() {
console.log('Launching command:', data.command); console.log('Launching command:', data.command);
} }
term.write('Connected successfully!\r\n'); term.write('Connected successfully!\r\n');
setTimeout(() => { setTimeout(() => {
pollInterval = setInterval(pollData, 100); pollInterval = setInterval(pollData, 200);
}, 100); }, 200);
} else { } else {
term.write('Error: ' + (data.error || 'Unknown error') + '\r\n'); term.write('Error: ' + (data.error || 'Unknown error') + '\r\n');
disconnect(); disconnect();
...@@ -374,13 +373,6 @@ function connect() { ...@@ -374,13 +373,6 @@ function connect() {
if (!connected || !requestId) return; if (!connected || !requestId) return;
let data = e.key; let data = e.key;
if (data === 'Enter') {
data = '\r';
} else if (data === 'Backspace') {
data = '\b';
} else if (data === 'Tab') {
data = '\t';
}
console.log('Sending input data:', data); console.log('Sending input data:', data);
// Send to server // Send to server
...@@ -426,7 +418,10 @@ function disconnect() { ...@@ -426,7 +418,10 @@ function disconnect() {
} }
if (term) { if (term) {
term.write('\r\nDisconnected.\r\n'); term.write('\r\nDisconnect\r\n');
setTimeout(() => {
location.reload();
}, 3000);
} }
} }
......
...@@ -175,7 +175,7 @@ terminal_session_t *terminal_create_session(const wssshd_config_t *config, const ...@@ -175,7 +175,7 @@ terminal_session_t *terminal_create_session(const wssshd_config_t *config, const
close(slave_fd); close(slave_fd);
// Set environment // Set environment
setenv("TERM", "xterm", 1); setenv("TERM", "xterm-256color", 1);
setenv("COLUMNS", "80", 1); setenv("COLUMNS", "80", 1);
setenv("LINES", "24", 1); setenv("LINES", "24", 1);
......
...@@ -586,7 +586,7 @@ static int parse_http_request(int client_fd, http_request_t *req) { ...@@ -586,7 +586,7 @@ static int parse_http_request(int client_fd, http_request_t *req) {
buffer[bytes_read] = '\0'; buffer[bytes_read] = '\0';
if (global_config && global_config->debug_web) { if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Raw buffer (%zd bytes): '", bytes_read); printf("[WEB-DEBUG] Raw buffer (%zd bytes): '", bytes_read);
for (ssize_t i = 0; i < bytes_read; i++) { for (ssize_t i = 0; i < bytes_read; i++) {
if (buffer[i] == '\r') printf("\\r"); if (buffer[i] == '\r') printf("\\r");
...@@ -626,7 +626,7 @@ static int parse_http_request(int client_fd, http_request_t *req) { ...@@ -626,7 +626,7 @@ static int parse_http_request(int client_fd, http_request_t *req) {
content_length = atoi(cl_header); content_length = atoi(cl_header);
} }
if (global_config && global_config->debug_web) { if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Content-Length from header: %d\n", content_length); printf("[WEB-DEBUG] Content-Length from header: %d\n", content_length);
} }
...@@ -635,7 +635,7 @@ static int parse_http_request(int client_fd, http_request_t *req) { ...@@ -635,7 +635,7 @@ static int parse_http_request(int client_fd, http_request_t *req) {
char *body_start = NULL; char *body_start = NULL;
size_t body_length = 0; size_t body_length = 0;
if (global_config && global_config->debug_web) { if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Looking for body separator...\n"); printf("[WEB-DEBUG] Looking for body separator...\n");
} }
...@@ -830,7 +830,7 @@ static const char *get_cookie(const char *headers, const char *name) { ...@@ -830,7 +830,7 @@ static const char *get_cookie(const char *headers, const char *name) {
static void send_response(int client_fd, int status_code, const char *status_text, static void send_response(int client_fd, int status_code, const char *status_text,
const char *content_type, const char *body, size_t body_len, const char *content_type, const char *body, size_t body_len,
const char *set_cookie, const char *extra_header) { const char *set_cookie, const char *extra_header) {
if (global_config && global_config->debug_web) { if (global_config && global_config->debug_web && strcmp(content_type, "application/octet-stream") != 0) {
printf("[WEB-DEBUG] Sending response: %d %s, Content-Type: %s, Length: %zu\n", printf("[WEB-DEBUG] Sending response: %d %s, Content-Type: %s, Length: %zu\n",
status_code, status_text, content_type, body_len); status_code, status_text, content_type, body_len);
if (set_cookie) { if (set_cookie) {
...@@ -1019,7 +1019,7 @@ static void handle_request(int client_fd, const http_request_t *req) { ...@@ -1019,7 +1019,7 @@ static void handle_request(int client_fd, const http_request_t *req) {
const char *username = NULL; const char *username = NULL;
int is_admin = 0; int is_admin = 0;
if (global_config && global_config->debug_web) { if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Session ID: %s\n", session_id ? session_id : "none"); printf("[WEB-DEBUG] Session ID: %s\n", session_id ? session_id : "none");
} }
...@@ -1031,7 +1031,7 @@ static void handle_request(int client_fd, const http_request_t *req) { ...@@ -1031,7 +1031,7 @@ static void handle_request(int client_fd, const http_request_t *req) {
} }
} }
if (global_config && global_config->debug_web) { if (global_config && global_config->debug_web && !strstr(req->path, "/xterm/data")) {
printf("[WEB-DEBUG] Authenticated user: %s (admin: %s)\n", printf("[WEB-DEBUG] Authenticated user: %s (admin: %s)\n",
username ? username : "none", is_admin ? "yes" : "no"); username ? username : "none", is_admin ? "yes" : "no");
} }
...@@ -1055,7 +1055,7 @@ static void handle_request(int client_fd, const http_request_t *req) { ...@@ -1055,7 +1055,7 @@ static void handle_request(int client_fd, const http_request_t *req) {
} }
} }
if (global_config && global_config->debug_web) { if (global_config && global_config->debug_web && (!action || strcmp(action, "data") != 0)) {
printf("[WEB-DEBUG] Terminal request: path=%s, client_id=%s, action=%s\n", req->path, client_id, action ? action : "(null)"); printf("[WEB-DEBUG] Terminal request: path=%s, client_id=%s, action=%s\n", req->path, client_id, action ? action : "(null)");
} }
...@@ -1119,7 +1119,7 @@ static void handle_request(int client_fd, const http_request_t *req) { ...@@ -1119,7 +1119,7 @@ static void handle_request(int client_fd, const http_request_t *req) {
break; break;
} }
} }
if (global_config && global_config->debug_web) { if (global_config && global_config->debug_web && strcmp(action, "data") != 0) {
printf("[WEB-DEBUG] Terminal action '%s' for client %s, client_exists=%d\n", action, client_id, client_exists); printf("[WEB-DEBUG] Terminal action '%s' for client %s, client_exists=%d\n", action, client_id, client_exists);
} }
if (!client_exists) { if (!client_exists) {
...@@ -1341,11 +1341,12 @@ static void handle_request(int client_fd, const http_request_t *req) { ...@@ -1341,11 +1341,12 @@ static void handle_request(int client_fd, const http_request_t *req) {
if (session_ended) { if (session_ended) {
send_response(client_fd, 200, "OK", "application/json; charset=utf-8", ended_json, sizeof(ended_json) - 1, NULL, NULL); send_response(client_fd, 200, "OK", "application/json; charset=utf-8", ended_json, sizeof(ended_json) - 1, NULL, NULL);
} else if (output) { } else if (output) {
send_response(client_fd, 200, "OK", "text/plain; charset=utf-8", output, output_len, NULL, NULL); send_response(client_fd, 200, "OK", "application/octet-stream", output, output_len, NULL, NULL);
free(output); free(output);
} else { } else {
send_response(client_fd, 200, "OK", "text/plain; charset=utf-8", "", 0, NULL, NULL); send_response(client_fd, 200, "OK", "application/octet-stream", "", 0, NULL, NULL);
} }
// Skip debug for data responses to avoid spam
} else { } else {
send_response(client_fd, 404, "Not Found", "text/plain", "Not found", 9, NULL, NULL); send_response(client_fd, 404, "Not Found", "text/plain", "Not found", 9, NULL, NULL);
} }
......
File added
File added
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment