feat: Phase 1 网络端到端打通 + FirstInit/Login/DevMode 完善
- 用户态共享网络协议栈 CODE/tools/net_stack.h(eth/ARP/IPv4/ICMP/UDP-DNS/TCP static inline,轮询模型) - shell 内建 ping/curl/run 命令;ping.elf/curl.elf 对齐 net_stack.h 真实协议栈 - shell dev_mode 串口镜像(g_serial_mirror)便于自动化验证 - DSK 启动流程:firstInit.txt 双行格式(firstInit + dev_mode),dev_mode=1 触发 shell 自动回归测试 - FirstInit 完成→持久化 USER.CONF + 翻转 firstInit 0->1(保留 dev_mode) - firstInit=1 时 DSK 加载 login.elf 进行用户选择 + 密码校验后再进 desktop - 新增 CODE/login/ 登录应用、CODE/DKM/dkm_shared.h、Logo.png - ahci/e1000/virtio_net/fat32/console_fb 驱动更新;utsm serial/block/dsk_loader 调整 - build.ps1 打包 ping.elf/curl.elf 进 SATA FAT32 根目录 - 移除 CODE/tools/bash(与 shell.elf 重复)
This commit is contained in:
+110
-138
@@ -4,100 +4,7 @@
|
||||
* and ports so later block I/O can be added safely.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DKM_DRIVER_MAGIC 0x444B4D31u
|
||||
#define DKM_ABI_VERSION 1u
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
struct dkm_log_api {
|
||||
void (*info)(const char *msg);
|
||||
void (*warn)(const char *msg);
|
||||
void (*error)(const char *msg);
|
||||
void (*panic)(const char *msg);
|
||||
};
|
||||
|
||||
struct dkm_dma_buffer {
|
||||
void *virt;
|
||||
u64 phys;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
struct dkm_dma_api {
|
||||
int (*alloc_pages)(u64 page_count, u64 alignment, u64 max_phys, struct dkm_dma_buffer *out);
|
||||
};
|
||||
|
||||
struct dkm_block_device_desc {
|
||||
const char *name;
|
||||
u64 sector_size;
|
||||
u64 sector_count;
|
||||
void *ctx;
|
||||
int (*read)(void *ctx, u64 lba, u32 count, void *buffer);
|
||||
};
|
||||
|
||||
struct dkm_block_api {
|
||||
int (*register_device)(const struct dkm_block_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*read)(u32 index, u64 lba, u32 count, void *buffer);
|
||||
u64 (*sector_size)(u32 index);
|
||||
const char *(*device_name)(u32 index);
|
||||
};
|
||||
|
||||
struct dkm_kernel_api {
|
||||
u32 version;
|
||||
u32 size;
|
||||
u64 feature_bits;
|
||||
const struct dkm_log_api *log;
|
||||
const void *mem;
|
||||
const void *utsm;
|
||||
const void *irq;
|
||||
const void *pci;
|
||||
const struct dkm_dma_api *dma;
|
||||
const void *vfs;
|
||||
const void *net;
|
||||
const void *timer;
|
||||
const void *drr;
|
||||
const void *rsdp_address;
|
||||
const void *fb_address;
|
||||
u64 fb_width;
|
||||
u64 fb_height;
|
||||
u64 fb_pitch;
|
||||
u16 fb_bpp;
|
||||
const void *boot_modules_response;
|
||||
int (*irq_register)(u8 irq, void *handler);
|
||||
u64 hhdm_offset;
|
||||
const struct dkm_block_api *block;
|
||||
};
|
||||
|
||||
struct dkm_driver_handle;
|
||||
|
||||
struct dkm_driver_desc {
|
||||
u32 magic;
|
||||
u16 abi_version;
|
||||
u16 desc_size;
|
||||
const char *name;
|
||||
const char *version;
|
||||
const char *vendor;
|
||||
u32 driver_class;
|
||||
u32 stage;
|
||||
u32 flags;
|
||||
u32 priority;
|
||||
const char *const *depends;
|
||||
u32 depends_count;
|
||||
const char *const *provides;
|
||||
u32 provides_count;
|
||||
u64 min_kernel_abi;
|
||||
u64 feature_bits;
|
||||
u64 reserved0;
|
||||
u64 reserved1;
|
||||
};
|
||||
#include "../dkm_shared.h"
|
||||
|
||||
static const char *const g_depends[] = { "pci", "irq" };
|
||||
static const char *const g_provides[] = { "block" };
|
||||
@@ -124,21 +31,6 @@ const struct dkm_driver_desc driver_desc = {
|
||||
.reserved1 = 0
|
||||
};
|
||||
|
||||
#define PCI_ADDR 0xCF8
|
||||
#define PCI_DATA 0xCFC
|
||||
#define PCI_VENDOR_ID 0x00
|
||||
#define PCI_COMMAND 0x04
|
||||
#define PCI_PROG_IF 0x09
|
||||
#define PCI_SUBCLASS 0x0A
|
||||
#define PCI_CLASS 0x0B
|
||||
#define PCI_HEADER 0x0E
|
||||
#define PCI_BAR5 0x24
|
||||
#define PCI_IRQ_LINE 0x3C
|
||||
|
||||
#define PCI_CMD_IO (1u << 0)
|
||||
#define PCI_CMD_MEM (1u << 1)
|
||||
#define PCI_CMD_BUSM (1u << 2)
|
||||
|
||||
#define AHCI_CLASS_STORAGE 0x01
|
||||
#define AHCI_SUBCLASS_SATA 0x06
|
||||
#define AHCI_PROGIF_AHCI 0x01
|
||||
@@ -170,12 +62,15 @@ const struct dkm_driver_desc driver_desc = {
|
||||
|
||||
#define AHCI_CMD_ST (1u << 0)
|
||||
#define AHCI_CMD_FRE (1u << 4)
|
||||
#define AHCI_CMD_W (1u << 6)
|
||||
#define AHCI_CMD_FR (1u << 14)
|
||||
#define AHCI_CMD_CR (1u << 15)
|
||||
#define AHCI_CMD_ICC_ACTIVE (1u << 28)
|
||||
|
||||
#define ATA_CMD_IDENTIFY 0xEC
|
||||
#define ATA_CMD_IDENTIFY_PACKET 0xA1
|
||||
#define ATA_CMD_READ_DMA_EXT 0x25
|
||||
#define ATA_CMD_WRITE_DMA_EXT 0x35
|
||||
|
||||
typedef struct __attribute__((packed)) ahci_cmd_header {
|
||||
u16 flags;
|
||||
@@ -207,34 +102,12 @@ static ahci_cmd_header *g_cmd_header;
|
||||
static struct dkm_dma_buffer g_cmd_table;
|
||||
static struct dkm_dma_buffer g_data;
|
||||
|
||||
static __inline__ void outl(u16 port, u32 value) {
|
||||
__asm__ volatile ("outl %0, %1" :: "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static __inline__ u32 inl(u16 port) {
|
||||
u32 value;
|
||||
__asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static u32 pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
|
||||
u32 addr = (1u << 31)
|
||||
| ((u32)bus << 16)
|
||||
| ((u32)dev << 11)
|
||||
| ((u32)func << 8)
|
||||
| ((u32)reg & 0xFC);
|
||||
outl(PCI_ADDR, addr);
|
||||
return inl(PCI_DATA);
|
||||
return dkm_pci_read(bus, dev, func, reg);
|
||||
}
|
||||
|
||||
static void pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 value) {
|
||||
u32 addr = (1u << 31)
|
||||
| ((u32)bus << 16)
|
||||
| ((u32)dev << 11)
|
||||
| ((u32)func << 8)
|
||||
| ((u32)reg & 0xFC);
|
||||
outl(PCI_ADDR, addr);
|
||||
outl(PCI_DATA, value);
|
||||
dkm_pci_write(bus, dev, func, reg, value);
|
||||
}
|
||||
|
||||
static void log_hex(const char *prefix, u64 value) {
|
||||
@@ -333,15 +206,21 @@ static int ahci_stop_port(u32 port) {
|
||||
u32 cmd = g_abar[(base + PxCMD) / 4];
|
||||
cmd &= ~AHCI_CMD_ST;
|
||||
g_abar[(base + PxCMD) / 4] = cmd;
|
||||
for (u32 i = 0; i < 100000; i++) {
|
||||
/* 实机: 500ms TSC 超时等待 CR 清除 */
|
||||
u64 deadline = dkm_rdtsc() + dkm_tsc_per_ms * 500;
|
||||
while (dkm_rdtsc() < deadline) {
|
||||
cmd = g_abar[(base + PxCMD) / 4];
|
||||
if (!(cmd & AHCI_CMD_CR)) break;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
cmd &= ~AHCI_CMD_FRE;
|
||||
g_abar[(base + PxCMD) / 4] = cmd;
|
||||
for (u32 i = 0; i < 100000; i++) {
|
||||
/* 实机: 500ms TSC 超时等待 FR 清除 */
|
||||
deadline = dkm_rdtsc() + dkm_tsc_per_ms * 500;
|
||||
while (dkm_rdtsc() < deadline) {
|
||||
cmd = g_abar[(base + PxCMD) / 4];
|
||||
if (!(cmd & AHCI_CMD_FR)) return 0;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -368,7 +247,23 @@ static void ahci_fill_read_fis(u8 *fis, u64 lba, u32 count) {
|
||||
ahci_zero(fis, 64);
|
||||
fis[0] = 0x27;
|
||||
fis[1] = 1u << 7;
|
||||
fis[2] = 0x25; /* READ DMA EXT */
|
||||
fis[2] = ATA_CMD_READ_DMA_EXT;
|
||||
fis[4] = (u8)(lba & 0xff);
|
||||
fis[5] = (u8)((lba >> 8) & 0xff);
|
||||
fis[6] = (u8)((lba >> 16) & 0xff);
|
||||
fis[7] = (1u << 6) | (u8)((lba >> 24) & 0x0f);
|
||||
fis[8] = (u8)((lba >> 24) & 0xff);
|
||||
fis[9] = (u8)((lba >> 32) & 0xff);
|
||||
fis[10] = (u8)((lba >> 40) & 0xff);
|
||||
fis[12] = (u8)(count & 0xff);
|
||||
fis[13] = (u8)((count >> 8) & 0xff);
|
||||
}
|
||||
|
||||
static void ahci_fill_write_fis(u8 *fis, u64 lba, u32 count) {
|
||||
ahci_zero(fis, 64);
|
||||
fis[0] = 0x27;
|
||||
fis[1] = 1u << 7;
|
||||
fis[2] = ATA_CMD_WRITE_DMA_EXT;
|
||||
fis[4] = (u8)(lba & 0xff);
|
||||
fis[5] = (u8)((lba >> 8) & 0xff);
|
||||
fis[6] = (u8)((lba >> 16) & 0xff);
|
||||
@@ -420,7 +315,81 @@ static int ahci_read_blocks_internal(u32 port, ahci_cmd_header *hdr, struct dkm_
|
||||
return -3;
|
||||
}
|
||||
|
||||
static int ahci_write_blocks_internal(u32 port, ahci_cmd_header *hdr, struct dkm_dma_buffer *table, struct dkm_dma_buffer *data, u64 lba, u32 count, const void *buffer) {
|
||||
if (!buffer || count == 0) return -1;
|
||||
if (count > 8) return -2;
|
||||
u32 base = HBA_PORT_BASE + port * HBA_PORT_SIZE;
|
||||
ahci_cmd_table *tbl = (ahci_cmd_table *)table->virt;
|
||||
u32 bytes = count * 512;
|
||||
ahci_zero(tbl, sizeof(ahci_cmd_table));
|
||||
|
||||
/* copy data from user buffer into DMA buffer */
|
||||
{
|
||||
u8 *dst = (u8 *)data->virt;
|
||||
const u8 *src = (const u8 *)buffer;
|
||||
for (u32 j = 0; j < bytes; j++) dst[j] = src[j];
|
||||
}
|
||||
|
||||
hdr[0].flags = 5 | (1u << 6); /* CFL=5, W=1 (write) */
|
||||
hdr[0].prdtl = 1;
|
||||
hdr[0].prdbc = 0;
|
||||
hdr[0].ctba = (u32)(table->phys & 0xffffffffu);
|
||||
hdr[0].ctbau = (u32)(table->phys >> 32);
|
||||
|
||||
tbl->prdt[0].dba = (u32)(data->phys & 0xffffffffu);
|
||||
tbl->prdt[0].dbau = (u32)(data->phys >> 32);
|
||||
tbl->prdt[0].dbc_i = (bytes - 1) | (1u << 31);
|
||||
ahci_fill_write_fis(tbl->cfis, lba, count);
|
||||
|
||||
/* set PxCMD.W to indicate write direction */
|
||||
u32 cmd = g_abar[(base + PxCMD) / 4];
|
||||
cmd |= AHCI_CMD_W;
|
||||
g_abar[(base + PxCMD) / 4] = cmd;
|
||||
|
||||
g_abar[(base + PxIS) / 4] = 0xffffffffu;
|
||||
g_abar[HBA_IS / 4] = (1u << port);
|
||||
g_abar[(base + PxCI) / 4] = 1;
|
||||
for (u32 i = 0; i < 5000000; i++) {
|
||||
if ((g_abar[(base + PxCI) / 4] & 1u) == 0) {
|
||||
/* clear PxCMD.W after write completes */
|
||||
cmd = g_abar[(base + PxCMD) / 4];
|
||||
cmd &= ~AHCI_CMD_W;
|
||||
g_abar[(base + PxCMD) / 4] = cmd;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* timeout: clear PxCMD.W */
|
||||
cmd = g_abar[(base + PxCMD) / 4];
|
||||
cmd &= ~AHCI_CMD_W;
|
||||
g_abar[(base + PxCMD) / 4] = cmd;
|
||||
|
||||
g_log->warn("[ahci] WRITE timeout");
|
||||
log_hex("[ahci] WRITE lba=", lba);
|
||||
log_hex("[ahci] WRITE count=", count);
|
||||
log_hex("[ahci] WRITE CI=", g_abar[(base + PxCI) / 4]);
|
||||
log_hex("[ahci] WRITE IS=", g_abar[(base + PxIS) / 4]);
|
||||
log_hex("[ahci] WRITE TFD=", g_abar[(base + PxTFD) / 4]);
|
||||
return -3;
|
||||
}
|
||||
|
||||
static int ahci_block_read(void *ctx, u64 lba, u32 count, void *buffer) {
|
||||
(void)ctx;
|
||||
if (g_ready_port == 0xffffffffu || !g_cmd_header) return -1;
|
||||
log_hex("[ahci] block_read lba=", lba);
|
||||
log_hex("[ahci] block_read count=", count);
|
||||
while (count > 0) {
|
||||
u32 chunk = count > 8 ? 8 : count;
|
||||
int status = ahci_read_blocks_internal(g_ready_port, g_cmd_header, &g_cmd_table, &g_data, lba, chunk, buffer);
|
||||
if (status != 0) return status;
|
||||
lba += chunk;
|
||||
count -= chunk;
|
||||
buffer = (void *)((u8 *)buffer + (chunk * 512));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ahci_block_write(void *ctx, u64 lba, u32 count, const void *buffer) {
|
||||
(void)ctx;
|
||||
if (g_ready_port == 0xffffffffu || !g_cmd_header) return -1;
|
||||
/* ensure port is in ST+FRE state */
|
||||
@@ -433,11 +402,11 @@ static int ahci_block_read(void *ctx, u64 lba, u32 count, void *buffer) {
|
||||
}
|
||||
while (count > 0) {
|
||||
u32 chunk = count > 8 ? 8 : count;
|
||||
int status = ahci_read_blocks_internal(g_ready_port, g_cmd_header, &g_cmd_table, &g_data, lba, chunk, buffer);
|
||||
int status = ahci_write_blocks_internal(g_ready_port, g_cmd_header, &g_cmd_table, &g_data, lba, chunk, buffer);
|
||||
if (status != 0) return status;
|
||||
lba += chunk;
|
||||
count -= chunk;
|
||||
buffer = (void *)((u8 *)buffer + (chunk * 512));
|
||||
buffer = (const void *)((const u8 *)buffer + (chunk * 512));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -536,6 +505,8 @@ __attribute__((visibility("default")))
|
||||
int driver_init(const struct dkm_kernel_api *api,
|
||||
struct dkm_driver_handle *handle) {
|
||||
(void)handle;
|
||||
/* 实机要求: 先校准 TSC, 再使用基于 CPU 频率的延迟 */
|
||||
dkm_tsc_calibrate();
|
||||
|
||||
if (!api || !api->log) return -1;
|
||||
g_log = api->log;
|
||||
@@ -628,6 +599,7 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
desc.sector_count = 0;
|
||||
desc.ctx = 0;
|
||||
desc.read = ahci_block_read;
|
||||
desc.write = ahci_block_write;
|
||||
int index = api->block->register_device(&desc);
|
||||
log_hex("[ahci] block provider index=", (u64)(i64)index);
|
||||
} else if (identified) {
|
||||
|
||||
+38
-151
@@ -17,105 +17,7 @@
|
||||
* 部分高级特性(ANI/MRR/AGC 调优)留待硬件验证后增量完善。
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DKM_DRIVER_MAGIC 0x444B4D31u
|
||||
#define DKM_ABI_VERSION 1u
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
typedef signed char i8;
|
||||
#define NULL ((void *)0)
|
||||
|
||||
/* ---- DKM ABI ---- */
|
||||
struct dkm_log_api {
|
||||
void (*info)(const char *msg);
|
||||
void (*warn)(const char *msg);
|
||||
void (*error)(const char *msg);
|
||||
void (*panic)(const char *msg);
|
||||
};
|
||||
|
||||
struct dkm_net_scan_result {
|
||||
char ssid[33];
|
||||
u8 bssid[6];
|
||||
u8 channel;
|
||||
i8 rssi;
|
||||
u8 security;
|
||||
};
|
||||
|
||||
struct dkm_net_device_desc {
|
||||
const char *name;
|
||||
u8 mac[6];
|
||||
u32 flags;
|
||||
void *ctx;
|
||||
int (*tx)(void *ctx, const void *packet, u32 length);
|
||||
int (*rx_poll)(void *ctx, void *buffer, u32 capacity, u32 *out_length);
|
||||
int (*scan_start)(void *ctx);
|
||||
int (*scan_count)(void *ctx);
|
||||
int (*scan_result)(void *ctx, u32 n, struct dkm_net_scan_result *out);
|
||||
int (*is_wireless)(void *ctx);
|
||||
};
|
||||
|
||||
struct dkm_net_api {
|
||||
int (*register_device)(const struct dkm_net_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*device_info)(u32 index, void *out);
|
||||
int (*tx)(u32 index, const void *packet, u32 length);
|
||||
int (*rx_poll)(u32 index, void *buffer, u32 capacity, u32 *out_length);
|
||||
int (*scan_start)(u32 index);
|
||||
int (*scan_count)(u32 index);
|
||||
int (*scan_result)(u32 index, u32 n, struct dkm_net_scan_result *out);
|
||||
int (*is_wireless)(u32 index);
|
||||
};
|
||||
|
||||
struct dkm_dma_buffer {
|
||||
void *virt;
|
||||
u64 phys;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
struct dkm_dma_api {
|
||||
int (*alloc_pages)(u64 page_count, u64 alignment, u64 max_phys, struct dkm_dma_buffer *out);
|
||||
};
|
||||
|
||||
#define DKM_NET_F_LINK_UP (1u << 0)
|
||||
#define DKM_NET_F_TX_READY (1u << 1)
|
||||
#define DKM_NET_F_RX_READY (1u << 2)
|
||||
#define DKM_NET_F_WIRELESS (1u << 3)
|
||||
|
||||
#define DKM_NET_SEC_OPEN 0u
|
||||
#define DKM_NET_SEC_WEP 1u
|
||||
#define DKM_NET_SEC_WPA 2u
|
||||
#define DKM_NET_SEC_WPA2 3u
|
||||
#define DKM_NET_SEC_WPA3 4u
|
||||
|
||||
struct dkm_kernel_api {
|
||||
u32 version; u32 size; u64 feature_bits;
|
||||
const struct dkm_log_api *log;
|
||||
const void *mem,*utsm,*irq_api,*pci_api;
|
||||
const struct dkm_dma_api *dma;
|
||||
const void *vfs_api;
|
||||
const struct dkm_net_api *net;
|
||||
const void *timer,*drr;
|
||||
const void *rsdp_address,*fb_address;
|
||||
u64 fb_width,fb_height,fb_pitch; u16 fb_bpp;
|
||||
const void *boot_modules_response;
|
||||
int (*irq_register)(u8 irq, void *handler);
|
||||
u64 hhdm_offset;
|
||||
};
|
||||
|
||||
struct dkm_driver_handle;
|
||||
struct dkm_driver_desc {
|
||||
u32 magic; u16 abi_version; u16 desc_size;
|
||||
const char *name,*version,*vendor;
|
||||
u32 driver_class,stage,flags,priority;
|
||||
const char *const *depends; u32 depends_count;
|
||||
const char *const *provides; u32 provides_count;
|
||||
u64 min_kernel_abi,feature_bits,reserved0,reserved1;
|
||||
};
|
||||
#include "../dkm_shared.h"
|
||||
|
||||
static const char *const g_depends[] = {"pci","irq"};
|
||||
static const char *const g_provides[] = {"netdev"};
|
||||
@@ -129,19 +31,6 @@ const struct dkm_driver_desc driver_desc = {
|
||||
.provides=g_provides,.provides_count=1,.min_kernel_abi=1,
|
||||
};
|
||||
|
||||
/* ---- PCI config ---- */
|
||||
#define PCI_ADDR 0xCF8
|
||||
#define PCI_DATA 0xCFC
|
||||
#define PCI_VENDOR_ID 0x00
|
||||
#define PCI_COMMAND 0x04
|
||||
#define PCI_BAR0 0x10
|
||||
#define PCI_BAR1 0x14
|
||||
#define PCI_IRQ_LINE 0x3C
|
||||
|
||||
#define PCI_CMD_IO (1u << 0)
|
||||
#define PCI_CMD_MEM (1u << 1)
|
||||
#define PCI_CMD_BUSMST (1u << 2)
|
||||
|
||||
/* ---- ath9k 寄存器(AR9280/9285/9287 PCIe MAC,Linux ath9k reg.h 关键子集) ---- */
|
||||
#define AR_RC 0x4000u
|
||||
#define AR_RC_MAC 0x00000001u
|
||||
@@ -285,20 +174,20 @@ static u32 g_scan_count;
|
||||
static int g_scanning;
|
||||
|
||||
/* ---- 串口日志(参考 e1000 raw_log) ---- */
|
||||
static __inline__ void outb(u16 p, u8 v) { __asm__ volatile("outb %0,%1"::"a"(v),"Nd"(p):"memory"); }
|
||||
static __inline__ u8 inb(u16 p) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(p):"memory"); return v; }
|
||||
static __inline__ void outl(u16 p, u32 v) { __asm__ volatile("outl %0,%1"::"a"(v),"Nd"(p):"memory"); }
|
||||
static __inline__ u32 inl(u16 p) { u32 v; __asm__ volatile("inl %1,%0":"=a"(v):"Nd"(p):"memory"); return v; }
|
||||
#define COM1 0x3F8
|
||||
|
||||
/* 串口发送等待 thin wrapper — 调用 dkm 共享实现 */
|
||||
static void serial_wait_tx(void) { dkm_serial_wait_tx(COM1); }
|
||||
|
||||
static void raw_log(const char *s) {
|
||||
while (*s) {
|
||||
char c = *s++;
|
||||
if (c == '\n') {
|
||||
for (u32 i=0;i<100000;i++) if (inb(0x3F8+5)&0x20) break;
|
||||
outb(0x3F8, '\r');
|
||||
serial_wait_tx();
|
||||
dkm_outb(COM1, '\r');
|
||||
}
|
||||
for (u32 i=0;i<100000;i++) if (inb(0x3F8+5)&0x20) break;
|
||||
outb(0x3F8, (u8)c);
|
||||
serial_wait_tx();
|
||||
dkm_outb(COM1, (u8)c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,26 +196,19 @@ static void raw_hex(const char *prefix, u64 v) {
|
||||
raw_log(prefix);
|
||||
raw_log("0x");
|
||||
for (int i=15; i>=0; i--) {
|
||||
for (u32 wait=0; wait<100000; wait++) if (inb(0x3F8+5)&0x20) break;
|
||||
outb(0x3F8, (u8)h[(v >> (i * 4)) & 0xf]);
|
||||
serial_wait_tx();
|
||||
dkm_outb(COM1, (u8)h[(v >> (i * 4)) & 0xf]);
|
||||
}
|
||||
raw_log("\n");
|
||||
}
|
||||
|
||||
static void delay_us(u32 us) {
|
||||
/* 粗略延时:每个 iteration ~1us on QEMU x86 */
|
||||
for (u32 i = 0; i < us * 10; i++) __asm__ volatile("pause");
|
||||
}
|
||||
|
||||
/* ---- PCI 配置空间 ---- */
|
||||
static u32 pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
|
||||
u32 a = (1u<<31)|((u32)bus<<16)|((u32)dev<<11)|((u32)func<<8)|((u32)reg&0xFC);
|
||||
outl(PCI_ADDR,a); return inl(PCI_DATA);
|
||||
return dkm_pci_read(bus, dev, func, reg);
|
||||
}
|
||||
|
||||
static void pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 v) {
|
||||
u32 a = (1u<<31)|((u32)bus<<16)|((u32)dev<<11)|((u32)func<<8)|((u32)reg&0xFC);
|
||||
outl(PCI_ADDR,a); outl(PCI_DATA,v);
|
||||
dkm_pci_write(bus, dev, func, reg, v);
|
||||
}
|
||||
|
||||
/* ath9k PCI 设备 ID 表(vendor 0x168c Atheros) */
|
||||
@@ -403,11 +285,12 @@ static u16 ath9k_eeprom_read(u16 addr) {
|
||||
/* AR5416_EEPROM_CMD: bit0=READ, bit1=BUSY, bit2=RESET */
|
||||
/* 启动 read:写 cmd=READ | addr<<3 */
|
||||
ath9k_reg_write(AR_EEPROM_CMD, AR_EEPROM_CMD_RESET);
|
||||
delay_us(5);
|
||||
dkm_delay_us(5);
|
||||
u32 cmd = AR_EEPROM_CMD_READ | ((u32)(addr & 0x3FF) << 3);
|
||||
ath9k_reg_write(AR_EEPROM_CMD, cmd);
|
||||
/* 等待 RDBUSY 清除 */
|
||||
for (u32 i = 0; i < 100000; i++) {
|
||||
/* 等待 RDBUSY 清除 (实机: 100ms TSC 超时) */
|
||||
u64 deadline = dkm_rdtsc() + dkm_tsc_per_ms * 100;
|
||||
while (dkm_rdtsc() < deadline) {
|
||||
u32 sts = ath9k_reg_read(AR_EEPROM_STS);
|
||||
if (!(sts & AR_EEPROM_STS_RDBUSY)) {
|
||||
if (sts & AR_EEPROM_STS_VALID) {
|
||||
@@ -415,7 +298,7 @@ static u16 ath9k_eeprom_read(u16 addr) {
|
||||
}
|
||||
return 0xffff;
|
||||
}
|
||||
delay_us(1);
|
||||
dkm_delay_us(1);
|
||||
}
|
||||
return 0xffff;
|
||||
}
|
||||
@@ -425,27 +308,29 @@ static int ath9k_reset(void) {
|
||||
raw_log("[ath9k.raw] reset sequence\n");
|
||||
/* 1. 强制唤醒(Power-On) */
|
||||
ath9k_reg_write(AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON | AR_RTC_FORCE_WAKE_INT);
|
||||
delay_us(50);
|
||||
/* 2. 等待 RTC 进入 ON 状态 */
|
||||
for (u32 i = 0; i < 100000; i++) {
|
||||
dkm_delay_us(50);
|
||||
/* 2. 等待 RTC 进入 ON 状态 (实机: 100ms TSC 超时) */
|
||||
u64 deadline = dkm_rdtsc() + dkm_tsc_per_ms * 100;
|
||||
while (dkm_rdtsc() < deadline) {
|
||||
u32 s = ath9k_reg_read(AR_RTC_STATUS);
|
||||
if ((s & 0x3) == AR_RTC_STATUS_ON) break;
|
||||
delay_us(1);
|
||||
dkm_delay_us(1);
|
||||
}
|
||||
/* 3. 全 chip 复位 */
|
||||
ath9k_reg_write(AR_RC, AR_RC_MAC | AR_RC_BB | AR_RC_RPCU);
|
||||
delay_us(100);
|
||||
dkm_delay_us(100);
|
||||
ath9k_reg_write(AR_RC, 0);
|
||||
delay_us(100);
|
||||
dkm_delay_us(100);
|
||||
/* 4. 重新唤醒 */
|
||||
ath9k_reg_write(AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON | AR_RTC_FORCE_WAKE_INT);
|
||||
delay_us(50);
|
||||
/* 5. 等待 RTC ON */
|
||||
dkm_delay_us(50);
|
||||
/* 5. 等待 RTC ON (实机: 100ms TSC 超时) */
|
||||
u32 ok = 0;
|
||||
for (u32 i = 0; i < 100000; i++) {
|
||||
u64 deadline2 = dkm_rdtsc() + dkm_tsc_per_ms * 100;
|
||||
while (dkm_rdtsc() < deadline2) {
|
||||
u32 s = ath9k_reg_read(AR_RTC_STATUS);
|
||||
if ((s & 0x3) == AR_RTC_STATUS_ON) { ok = 1; break; }
|
||||
delay_us(1);
|
||||
dkm_delay_us(1);
|
||||
}
|
||||
if (!ok) { raw_log("[ath9k.raw] reset: RTC not ON\n"); return -1; }
|
||||
raw_log("[ath9k.raw] reset: RTC ON\n");
|
||||
@@ -461,7 +346,7 @@ static int ath9k_hw_init(void) {
|
||||
raw_log("[ath9k.raw] hw_init minimal\n");
|
||||
/* 关闭 RX/DMA,清 STA_ID1 */
|
||||
ath9k_reg_write(AR_CR, AR_CR_RXD);
|
||||
delay_us(10);
|
||||
dkm_delay_us(10);
|
||||
ath9k_reg_write(AR_STA_ID1, 0);
|
||||
/* 清中断 */
|
||||
ath9k_reg_write(AR_ISR, 0xFFFFFFFFu);
|
||||
@@ -650,13 +535,13 @@ static void ath9k_set_channel(u8 channel) {
|
||||
/* TODO: 完整 ath9k 信道切换序列(参考 ar9002_hw_set_channel) */
|
||||
/* 触发 RFBUS 请求,等待 grant */
|
||||
ath9k_reg_write(AR_PHY_RFBUS_REQ, 0x1);
|
||||
delay_us(5);
|
||||
dkm_delay_us(5);
|
||||
for (u32 i = 0; i < 1000; i++) {
|
||||
if (ath9k_reg_read(AR_PHY_RFBUS_REQ) & 0x2) break;
|
||||
delay_us(1);
|
||||
dkm_delay_us(1);
|
||||
}
|
||||
ath9k_reg_write(AR_PHY_RFBUS_REQ, 0);
|
||||
delay_us(50);
|
||||
dkm_delay_us(50);
|
||||
}
|
||||
|
||||
/* ---- 被动扫描状态机 ----
|
||||
@@ -684,7 +569,7 @@ static int ath9k_scan_start_impl(void *ctx) {
|
||||
/* 在该信道停留 ~400ms,期间轮询 RX 环 */
|
||||
for (u32 tick = 0; tick < 400; tick++) {
|
||||
ath9k_rx_drain();
|
||||
delay_us(1000);
|
||||
dkm_delay_us(1000);
|
||||
}
|
||||
}
|
||||
g_scanning = 0;
|
||||
@@ -752,6 +637,8 @@ __attribute__((visibility("default")))
|
||||
int driver_init(const struct dkm_kernel_api *api,
|
||||
struct dkm_driver_handle *handle) {
|
||||
(void)handle;
|
||||
/* 实机要求: 先校准 TSC, 再使用基于 CPU 频率的延迟 */
|
||||
dkm_tsc_calibrate();
|
||||
raw_log("[ath9k.raw] driver_init entered\n");
|
||||
if (!api || !api->log) return -1;
|
||||
g_log = api->log;
|
||||
@@ -766,7 +653,7 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
|
||||
/* 2. 启用 PCI 命令(MEM + Bus Master) */
|
||||
u32 cmd = pci_read(bus, dev, 0, PCI_COMMAND);
|
||||
pci_write(bus, dev, 0, PCI_COMMAND, cmd | PCI_CMD_MEM | PCI_CMD_BUSMST);
|
||||
pci_write(bus, dev, 0, PCI_COMMAND, cmd | PCI_CMD_MEM | PCI_CMD_BUSM);
|
||||
|
||||
/* 3. 读取 BAR0 */
|
||||
u32 bar0 = pci_read(bus, dev, 0, PCI_BAR0);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* DKM Console Framebuffer Driver
|
||||
* Stage 1, optional, provides "console".
|
||||
* Light-blue background + centered circular loading animation (4-color arc ring).
|
||||
* Clears the framebuffer to a solid light-blue background so the screen is
|
||||
* clean before DSK takes over and draws the Logo. The former 4-color arc
|
||||
* loading ring has been removed — DSK now shows a static Logo instead.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -51,7 +53,7 @@ __attribute__((visibility("default"), used))
|
||||
const struct dkm_driver_desc driver_desc = {
|
||||
.magic=DKM_DRIVER_MAGIC, .abi_version=DKM_ABI_VERSION,
|
||||
.desc_size=sizeof(struct dkm_driver_desc),
|
||||
.name="console_fb", .version="0.2.0", .vendor="Deshab",
|
||||
.name="console_fb", .version="0.3.0", .vendor="Deshab",
|
||||
.driver_class=5, .stage=1, .flags=0, .priority=0,
|
||||
.depends=NULL, .depends_count=0,
|
||||
.provides=g_provides, .provides_count=1,
|
||||
@@ -61,18 +63,11 @@ const struct dkm_driver_desc driver_desc = {
|
||||
/* ---------------------------------------------------------------
|
||||
* Colors
|
||||
* --------------------------------------------------------------- */
|
||||
static const u32 BG = 0xFFC8E0F0; /* light blue background */
|
||||
static const u32 ARC[4] = { 0xFF4488CC, 0xFF2266AA, 0xFF66AAEE, 0xFF88CCFF };
|
||||
static const u32 BG = 0xFFC8E0F0; /* light blue background — cleared before DSK Logo */
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* Drawing helpers – all integer arithmetic, no soft-float
|
||||
* --------------------------------------------------------------- */
|
||||
static u64 fb_w, fb_h, fb_p;
|
||||
|
||||
/* double-buffer sprite for ring area (128×128 = no flicker) */
|
||||
#define SPR_SIZE 128
|
||||
static u32 g_sprite[SPR_SIZE * SPR_SIZE];
|
||||
|
||||
static void fb_fill(u32 *fb, u64 pitch, u64 w, u64 h, u32 color) {
|
||||
for (u64 y = 0; y < h; y++) {
|
||||
u32 *line = (u32 *)((u8 *)fb + y * pitch);
|
||||
@@ -80,105 +75,6 @@ static void fb_fill(u32 *fb, u64 pitch, u64 w, u64 h, u32 color) {
|
||||
}
|
||||
}
|
||||
|
||||
/* alpha-blend c2 over c1, alpha 0-255 */
|
||||
static u32 blend(u32 c1, u32 c2, u32 a) {
|
||||
u32 na = 256 - a;
|
||||
u32 r = ((c1 & 0xFF) * na + (c2 & 0xFF) * a) >> 8;
|
||||
u32 g = (((c1 >> 8) & 0xFF) * na + ((c2 >> 8) & 0xFF) * a) >> 8;
|
||||
u32 b = (((c1 >> 16) & 0xFF) * na + ((c2 >> 16) & 0xFF) * a) >> 8;
|
||||
return 0xFF000000 | (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
||||
/* integer sqrt – returns floor(sqrt(v)) */
|
||||
static u64 isqrt(u64 v) {
|
||||
u64 x = v, y = (x + 1) >> 1;
|
||||
while (y < x) { x = y; y = (y + v / y) >> 1; }
|
||||
return x;
|
||||
}
|
||||
|
||||
/* approximate atan2 in degrees (0=right, CCW). dx,dy = pixel offset from center */
|
||||
static i64 approx_angle(i64 dx, i64 dy) {
|
||||
if (dx == 0) return dy < 0 ? 90 : 270;
|
||||
i64 ax = dx < 0 ? -dx : dx;
|
||||
i64 ay = dy < 0 ? -dy : dy;
|
||||
i64 a;
|
||||
if (ax > ay) {
|
||||
a = ay * 45 / ax;
|
||||
} else {
|
||||
a = 90 - ax * 45 / (ay ? ay : 1);
|
||||
}
|
||||
/* quadrant correction */
|
||||
if (dx >= 0 && dy <= 0) return a; /* Q1 */
|
||||
else if (dx < 0 && dy <= 0) return 180 - a; /* Q2 */
|
||||
else if (dx < 0 && dy > 0) return 180 + a; /* Q3 */
|
||||
else return 360 - a; /* Q4 */
|
||||
}
|
||||
|
||||
/* draw one arc segment: rounded caps (6° head/tail), bright mid, comet-tail fade */
|
||||
static void arc_segment(u32 *fb, i64 cx, i64 cy, i64 r, i64 start, i64 sweep, u32 color, i64 thk) {
|
||||
i64 ro = r + thk, ri = r - thk;
|
||||
i64 ri2 = ri * ri, ro2 = (ro + 1) * (ro + 1);
|
||||
i64 rnd = 6; /* rounding zone at each end, in degrees */
|
||||
|
||||
for (i64 dy = -ro - 1; dy <= ro + 1; dy++) {
|
||||
i64 y = cy + dy;
|
||||
if ((u64)y >= fb_h) continue;
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
|
||||
for (i64 dx = -ro - 1; dx <= ro + 1; dx++) {
|
||||
i64 x = cx + dx;
|
||||
if ((u64)x >= fb_w) continue;
|
||||
i64 d2 = dx * dx + dy * dy;
|
||||
if (d2 < ri2 - 2 || d2 > ro2 + 2) continue;
|
||||
|
||||
i64 ang = approx_angle(dx, dy);
|
||||
i64 a = ang - start;
|
||||
if (a < 0) a += 360;
|
||||
if ((u64)a > (u64)sweep) continue;
|
||||
|
||||
/* rounded-cap fade: 0→255 over rnd°, then 255→0 over last rnd° */
|
||||
u32 fade;
|
||||
if ((u64)a < (u64)rnd) {
|
||||
fade = (u32)(a * 255 / rnd);
|
||||
} else if ((u64)a > (u64)(sweep - rnd)) {
|
||||
fade = (u32)((sweep - a) * 255 / rnd);
|
||||
} else {
|
||||
fade = 255;
|
||||
}
|
||||
|
||||
i64 dist = (i64)isqrt((u64)d2);
|
||||
u32 effective = blend(BG, color, fade);
|
||||
if (dist >= ri && dist <= ro) {
|
||||
line[(u64)x] = effective;
|
||||
} else if (dist >= ri - 2 && dist < ri) {
|
||||
line[(u64)x] = blend(BG, effective, (u32)((dist - (ri - 2)) * 85));
|
||||
} else if (dist > ro && dist <= ro + 2) {
|
||||
line[(u64)x] = blend(effective, BG, (u32)((dist - ro) * 85));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* filled disc with anti-aliased edge */
|
||||
static void fill_disc(u32 *fb, i64 cx, i64 cy, i64 r, u32 color) {
|
||||
i64 r2 = r * r, o2 = (r + 1) * (r + 1);
|
||||
for (i64 dy = -r - 2; dy <= r + 2; dy++) {
|
||||
i64 y = cy + dy;
|
||||
if ((u64)y >= fb_h) continue;
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)y * fb_p);
|
||||
for (i64 dx = -r - 2; dx <= r + 2; dx++) {
|
||||
i64 x = cx + dx;
|
||||
if ((u64)x >= fb_w) continue;
|
||||
i64 d2 = dx * dx + dy * dy;
|
||||
if (d2 <= r2) {
|
||||
line[(u64)x] = color;
|
||||
} else if (d2 <= o2) {
|
||||
u32 a = (u32)((o2 - d2) * 255 / (o2 - r2));
|
||||
line[(u64)x] = blend(BG, color, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* Driver entry
|
||||
* --------------------------------------------------------------- */
|
||||
@@ -192,61 +88,13 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
return 0;
|
||||
}
|
||||
|
||||
api->log->info("[console_fb] boot screen");
|
||||
api->log->info("[console_fb] clearing boot screen");
|
||||
|
||||
fb_w = api->fb_width; fb_h = api->fb_height; fb_p = api->fb_pitch;
|
||||
/* Solid background fill only — DSK draws the Logo next. Clearing here
|
||||
* avoids firmware/UEFI leftover garbage being visible during the
|
||||
* UTSM→DSK handoff. */
|
||||
u32 *fb = (u32 *)api->fb_address;
|
||||
i64 cx = (i64)fb_w / 2, cy = (i64)fb_h / 2, r = 48, thk = 4;
|
||||
|
||||
/* light-blue background */
|
||||
fb_fill(fb, fb_p, fb_w, fb_h, BG);
|
||||
|
||||
/* animation: 2000 frames × 2° clockwise × ~1ms, no flicker */
|
||||
i64 spr_p = SPR_SIZE * 4;
|
||||
i64 scx = SPR_SIZE / 2;
|
||||
i64 scy = SPR_SIZE / 2;
|
||||
i64 frame = 0, base = 0;
|
||||
i64 bx = cx - scx; /* screen position of sprite top-left */
|
||||
i64 by = cy - scy;
|
||||
|
||||
while (frame < 2000) {
|
||||
/* draw into sprite buffer — swap globals to sprite layout */
|
||||
u64 save_w = fb_w, save_h = fb_h, save_p = fb_p;
|
||||
fb_w = SPR_SIZE; fb_h = SPR_SIZE; fb_p = spr_p;
|
||||
|
||||
fb_fill(g_sprite, spr_p, SPR_SIZE, SPR_SIZE, BG);
|
||||
|
||||
arc_segment(g_sprite, scx, scy, r, base + 0, 82, ARC[0], thk);
|
||||
arc_segment(g_sprite, scx, scy, r, base + 90, 82, ARC[1], thk);
|
||||
arc_segment(g_sprite, scx, scy, r, base +180, 82, ARC[2], thk);
|
||||
arc_segment(g_sprite, scx, scy, r, base +270, 82, ARC[3], thk);
|
||||
|
||||
fill_disc(g_sprite, scx, scy, r - 8, blend(BG, 0xFFD0F0FF, 80));
|
||||
|
||||
/* restore screen globals for blit */
|
||||
fb_w = save_w; fb_h = save_h; fb_p = save_p;
|
||||
|
||||
/* blit sprite to screen */
|
||||
for (i64 sr = 0; sr < SPR_SIZE; sr++) {
|
||||
i64 sy = by + sr;
|
||||
if ((u64)sy >= fb_h) continue;
|
||||
u32 *dst = (u32 *)((u8 *)fb + (u64)sy * fb_p) + bx;
|
||||
u32 *src = &g_sprite[sr * SPR_SIZE];
|
||||
for (i64 sc = 0; sc < SPR_SIZE; sc++) {
|
||||
i64 sx = bx + sc;
|
||||
if ((u64)sx >= fb_w) continue;
|
||||
dst[sc] = src[sc];
|
||||
}
|
||||
}
|
||||
|
||||
for (volatile u32 d = 0; d < 72000; d++) {
|
||||
__asm__ volatile ("pause");
|
||||
}
|
||||
|
||||
base -= 2;
|
||||
if (base < 0) base += 360;
|
||||
frame++;
|
||||
}
|
||||
fb_fill(fb, api->fb_pitch, api->fb_width, api->fb_height, BG);
|
||||
|
||||
api->log->info("[console_fb] ready");
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/* DKM 共享头文件 — 消除各驱动重复的结构体/宏/PCI/TSC 代码
|
||||
*
|
||||
* 设计要点:
|
||||
* - 结构体定义与 UTSM/include/utsm/dkm.h 保持布局一致 (canonical)
|
||||
* - PCI I/O 函数使用 static __inline__, 每个 .drv 文件获得独立副本, 避免链接冲突
|
||||
* - TSC 校准函数使用 static __inline__, 每个 .drv 文件获得自己的 dkm_tsc_per_ms
|
||||
* - 驱动源文件只需 #include "../dkm_shared.h", 保留各自的 driver_desc 和 driver_init
|
||||
*
|
||||
* 使用约定:
|
||||
* 1. 在 driver_init 开头调用 dkm_tsc_calibrate() 完成校准
|
||||
* 2. 时序等待使用 dkm_delay_ms() / dkm_delay_us()
|
||||
* 3. 串口发送等待使用 dkm_serial_wait_tx(COM1)
|
||||
* 4. MMIO 寄存器读取等待使用 dkm_rdtsc() + dkm_tsc_per_ms 直接计算 deadline
|
||||
*/
|
||||
#ifndef DKM_SHARED_H
|
||||
#define DKM_SHARED_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* ---- 基本类型 (与 UTSM/types.h 一致) ---- */
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed char i8;
|
||||
typedef short i16;
|
||||
typedef int i32;
|
||||
typedef long long i64;
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
/* ---- DKM magic / ABI 版本 ---- */
|
||||
#define DKM_DRIVER_MAGIC 0x444B4D31u
|
||||
#define DKM_ABI_VERSION 1u
|
||||
|
||||
/* ---- DKM 驱动类别 (driver_desc.driver_class) ---- */
|
||||
#define DKM_CLASS_PLATFORM 1u
|
||||
#define DKM_CLASS_BUS 2u
|
||||
#define DKM_CLASS_INTERRUPT 3u
|
||||
#define DKM_CLASS_TIMER 4u
|
||||
#define DKM_CLASS_CONSOLE 5u
|
||||
#define DKM_CLASS_STORAGE 6u
|
||||
#define DKM_CLASS_FS 7u
|
||||
#define DKM_CLASS_NET 8u
|
||||
#define DKM_CLASS_INPUT 9u
|
||||
#define DKM_CLASS_GPU 10u
|
||||
#define DKM_CLASS_MISC 11u
|
||||
|
||||
/* ---- DKM 驱动标志 (driver_desc.flags) ---- */
|
||||
#define DKM_F_REQUIRED (1u << 0)
|
||||
#define DKM_F_BOOT_MODULE (1u << 1)
|
||||
#define DKM_F_NO_UNLOAD (1u << 2)
|
||||
#define DKM_F_STRONG_RECOVERY (1u << 3)
|
||||
#define DKM_F_DMA_REQUIRED (1u << 4)
|
||||
#define DKM_F_EARLY_LOG (1u << 5)
|
||||
|
||||
/* ---- 网卡链路/能力标志 ---- */
|
||||
#define DKM_NET_F_LINK_UP (1u << 0)
|
||||
#define DKM_NET_F_TX_READY (1u << 1)
|
||||
#define DKM_NET_F_RX_READY (1u << 2)
|
||||
#define DKM_NET_F_WIRELESS (1u << 3)
|
||||
|
||||
/* ---- WiFi 扫描加密类型 ---- */
|
||||
#define DKM_NET_SEC_OPEN 0u
|
||||
#define DKM_NET_SEC_WEP 1u
|
||||
#define DKM_NET_SEC_WPA 2u
|
||||
#define DKM_NET_SEC_WPA2 3u
|
||||
#define DKM_NET_SEC_WPA3 4u
|
||||
|
||||
/* ---- DKM 结构体定义 (与 UTSM/include/utsm/dkm.h 布局一致) ---- */
|
||||
struct dkm_log_api {
|
||||
void (*info)(const char *msg);
|
||||
void (*warn)(const char *msg);
|
||||
void (*error)(const char *msg);
|
||||
void (*panic)(const char *msg);
|
||||
};
|
||||
|
||||
struct dkm_dma_buffer {
|
||||
void *virt;
|
||||
u64 phys;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
struct dkm_dma_api {
|
||||
int (*alloc_pages)(u64 page_count, u64 alignment, u64 max_phys, struct dkm_dma_buffer *out);
|
||||
};
|
||||
|
||||
struct dkm_net_scan_result {
|
||||
char ssid[33];
|
||||
u8 bssid[6];
|
||||
u8 channel;
|
||||
i8 rssi;
|
||||
u8 security;
|
||||
};
|
||||
|
||||
struct dkm_net_device_desc {
|
||||
const char *name;
|
||||
u8 mac[6];
|
||||
u32 flags;
|
||||
void *ctx;
|
||||
int (*tx)(void *ctx, const void *packet, u32 length);
|
||||
int (*rx_poll)(void *ctx, void *buffer, u32 capacity, u32 *out_length);
|
||||
/* 无线扩展回调(有线驱动置 NULL,向后兼容)。 */
|
||||
int (*scan_start)(void *ctx);
|
||||
int (*scan_count)(void *ctx);
|
||||
int (*scan_result)(void *ctx, u32 n, struct dkm_net_scan_result *out);
|
||||
int (*is_wireless)(void *ctx);
|
||||
};
|
||||
|
||||
struct dkm_net_api {
|
||||
int (*register_device)(const struct dkm_net_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*device_info)(u32 index, void *out);
|
||||
int (*tx)(u32 index, const void *packet, u32 length);
|
||||
int (*rx_poll)(u32 index, void *buffer, u32 capacity, u32 *out_length);
|
||||
int (*scan_start)(u32 index);
|
||||
int (*scan_count)(u32 index);
|
||||
int (*scan_result)(u32 index, u32 n, struct dkm_net_scan_result *out);
|
||||
int (*is_wireless)(u32 index);
|
||||
};
|
||||
|
||||
typedef int (*dkm_block_read_fn)(void *ctx, u64 lba, u32 count, void *buffer);
|
||||
typedef int (*dkm_block_write_fn)(void *ctx, u64 lba, u32 count, const void *buffer);
|
||||
|
||||
struct dkm_block_device_desc {
|
||||
const char *name;
|
||||
u64 sector_size;
|
||||
u64 sector_count;
|
||||
void *ctx;
|
||||
int (*read)(void *ctx, u64 lba, u32 count, void *buffer);
|
||||
int (*write)(void *ctx, u64 lba, u32 count, const void *buffer);
|
||||
};
|
||||
|
||||
struct dkm_block_api {
|
||||
int (*register_device)(const struct dkm_block_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*read)(u32 index, u64 lba, u32 count, void *buffer);
|
||||
int (*write)(u32 index, u64 lba, u32 count, const void *buffer);
|
||||
u64 (*sector_size)(u32 index);
|
||||
const char *(*device_name)(u32 index);
|
||||
int (*set_write_fn)(u32 index, dkm_block_write_fn fn);
|
||||
};
|
||||
|
||||
/* 与 UTSM/include/utsm/dkm.h 中的 dkm_kernel_api 布局完全一致.
|
||||
* 字段顺序/类型不可调整 — UTSM 端按此偏移填充. */
|
||||
struct dkm_kernel_api {
|
||||
u32 version;
|
||||
u32 size;
|
||||
u64 feature_bits;
|
||||
const struct dkm_log_api *log;
|
||||
const void *mem;
|
||||
const void *utsm;
|
||||
const void *irq;
|
||||
const void *pci;
|
||||
const struct dkm_dma_api *dma;
|
||||
const void *vfs;
|
||||
const struct dkm_net_api *net;
|
||||
const void *timer;
|
||||
const void *drr;
|
||||
const void *rsdp_address;
|
||||
const void *fb_address;
|
||||
u64 fb_width;
|
||||
u64 fb_height;
|
||||
u64 fb_pitch;
|
||||
u16 fb_bpp;
|
||||
const void *boot_modules_response;
|
||||
int (*irq_register)(u8 irq, void *handler);
|
||||
u64 hhdm_offset;
|
||||
const struct dkm_block_api *block; /* 末尾字段, 不使用 block 的驱动可不访问 */
|
||||
};
|
||||
|
||||
struct dkm_driver_handle;
|
||||
|
||||
struct dkm_driver_desc {
|
||||
u32 magic;
|
||||
u16 abi_version;
|
||||
u16 desc_size;
|
||||
const char *name;
|
||||
const char *version;
|
||||
const char *vendor;
|
||||
u32 driver_class;
|
||||
u32 stage;
|
||||
u32 flags;
|
||||
u32 priority;
|
||||
const char *const *depends;
|
||||
u32 depends_count;
|
||||
const char *const *provides;
|
||||
u32 provides_count;
|
||||
u64 min_kernel_abi;
|
||||
u64 feature_bits;
|
||||
u64 reserved0;
|
||||
u64 reserved1;
|
||||
};
|
||||
|
||||
/* ---- PCI 配置空间常量 ---- */
|
||||
#define PCI_ADDR 0xCF8
|
||||
#define PCI_DATA 0xCFC
|
||||
#define PCI_VENDOR_ID 0x00
|
||||
#define PCI_DEVICE_ID 0x02
|
||||
#define PCI_COMMAND 0x04
|
||||
#define PCI_PROG_IF 0x09
|
||||
#define PCI_SUBCLASS 0x0A
|
||||
#define PCI_CLASS 0x0B
|
||||
#define PCI_HEADER 0x0E
|
||||
#define PCI_CAP_PTR 0x34
|
||||
#define PCI_IRQ_LINE 0x3C
|
||||
#define PCI_BAR0 0x10
|
||||
#define PCI_BAR1 0x14
|
||||
#define PCI_BAR2 0x18
|
||||
#define PCI_BAR3 0x1C
|
||||
#define PCI_BAR4 0x20
|
||||
#define PCI_BAR5 0x24
|
||||
|
||||
#define PCI_CMD_IO (1u << 0)
|
||||
#define PCI_CMD_MEM (1u << 1)
|
||||
#define PCI_CMD_BUSM (1u << 2)
|
||||
|
||||
/* ---- PCI I/O 端口内联函数 (每个 .drv 获得独立副本) ---- */
|
||||
static __inline__ void dkm_outl(u16 port, u32 value) {
|
||||
__asm__ volatile ("outl %0, %1" :: "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static __inline__ u32 dkm_inl(u16 port) {
|
||||
u32 value;
|
||||
__asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static __inline__ void dkm_outb(u16 port, u8 value) {
|
||||
__asm__ volatile ("outb %0, %1" :: "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static __inline__ u8 dkm_inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static __inline__ u32 dkm_pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
|
||||
u32 addr = (1u << 31)
|
||||
| ((u32)bus << 16)
|
||||
| ((u32)dev << 11)
|
||||
| ((u32)func << 8)
|
||||
| ((u32)reg & 0xFC);
|
||||
dkm_outl(PCI_ADDR, addr);
|
||||
return dkm_inl(PCI_DATA);
|
||||
}
|
||||
|
||||
static __inline__ void dkm_pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 value) {
|
||||
u32 addr = (1u << 31)
|
||||
| ((u32)bus << 16)
|
||||
| ((u32)dev << 11)
|
||||
| ((u32)func << 8)
|
||||
| ((u32)reg & 0xFC);
|
||||
dkm_outl(PCI_ADDR, addr);
|
||||
dkm_outl(PCI_DATA, value);
|
||||
}
|
||||
|
||||
static __inline__ u8 dkm_pci_read8(u8 bus, u8 dev, u8 func, u8 reg) {
|
||||
u32 v = dkm_pci_read(bus, dev, func, reg);
|
||||
return (u8)((v >> ((reg & 3) * 8)) & 0xff);
|
||||
}
|
||||
|
||||
/* ---- TSC 时序: 实机要求用 CPU 频率计算, 不用循环 ----
|
||||
* 每个 .drv 包含此头文件后获得自己的 file-local dkm_tsc_per_ms 副本,
|
||||
* 通过 dkm_tsc_calibrate() 在 driver_init 开头初始化.
|
||||
*/
|
||||
static u64 dkm_tsc_per_ms __attribute__((unused)) = 0;
|
||||
|
||||
static __inline__ u64 dkm_rdtsc(void) {
|
||||
u32 lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
/* 通过 PIT ch0 + TSC 校准 ~10ms 区间, 推算每毫秒 TSC 周期数. */
|
||||
static __inline__ void dkm_tsc_calibrate(void) {
|
||||
dkm_outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
|
||||
dkm_outb(0x40, 0x7c); /* 11932 low = ~10ms */
|
||||
dkm_outb(0x40, 0x2e); /* 11932 high */
|
||||
u64 tsc_start = dkm_rdtsc();
|
||||
u16 prev = 0; u64 loops = 0;
|
||||
for (;;) {
|
||||
dkm_outb(0x43, 0x00);
|
||||
u16 cur = (u16)dkm_inb(0x40) | ((u16)dkm_inb(0x40) << 8);
|
||||
if (cur > prev && loops > 10) break;
|
||||
prev = cur; loops++;
|
||||
}
|
||||
u64 tsc_end = dkm_rdtsc();
|
||||
dkm_tsc_per_ms = (tsc_end - tsc_start) / 10;
|
||||
}
|
||||
|
||||
static __inline__ void dkm_delay_ms(u32 ms) {
|
||||
if (!dkm_tsc_per_ms) {
|
||||
for (volatile u32 i = 0; i < 100000 * ms; i++) __asm__ volatile("pause");
|
||||
return;
|
||||
}
|
||||
u64 target = dkm_tsc_per_ms * ms;
|
||||
u64 start = dkm_rdtsc();
|
||||
while (dkm_rdtsc() - start < target) __asm__ volatile("pause");
|
||||
}
|
||||
|
||||
static __inline__ void dkm_delay_us(u32 us) {
|
||||
if (!dkm_tsc_per_ms) {
|
||||
for (volatile u32 i = 0; i < 100 * us; i++) __asm__ volatile("pause");
|
||||
return;
|
||||
}
|
||||
u64 target = dkm_tsc_per_ms * us / 1000;
|
||||
u64 start = dkm_rdtsc();
|
||||
while (dkm_rdtsc() - start < target) __asm__ volatile("pause");
|
||||
}
|
||||
|
||||
/* 实机: 基于 TSC 的串口发送等待 (100us 超时). com_port = 0x3F8 (COM1). */
|
||||
static __inline__ void dkm_serial_wait_tx(u16 com_port) {
|
||||
if (!dkm_tsc_per_ms) {
|
||||
for (volatile u32 i = 0; i < 100000; i++) {
|
||||
if (dkm_inb((u16)(com_port + 5)) & 0x20) break;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return;
|
||||
}
|
||||
u64 deadline = dkm_rdtsc() + dkm_tsc_per_ms / 10;
|
||||
while (dkm_rdtsc() < deadline) {
|
||||
if (dkm_inb((u16)(com_port + 5)) & 0x20) break;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DKM_SHARED_H */
|
||||
+26
-119
@@ -3,98 +3,7 @@
|
||||
* Finds e1000 via PCI, maps MMIO, reads MAC address.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DKM_DRIVER_MAGIC 0x444B4D31u
|
||||
#define DKM_ABI_VERSION 1u
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed char i8;
|
||||
typedef long long i64;
|
||||
#define NULL ((void *)0)
|
||||
|
||||
struct dkm_log_api {
|
||||
void (*info)(const char *msg);
|
||||
void (*warn)(const char *msg);
|
||||
void (*error)(const char *msg);
|
||||
void (*panic)(const char *msg);
|
||||
};
|
||||
|
||||
struct dkm_net_scan_result {
|
||||
char ssid[33];
|
||||
u8 bssid[6];
|
||||
u8 channel;
|
||||
i8 rssi;
|
||||
u8 security;
|
||||
};
|
||||
|
||||
struct dkm_net_device_desc {
|
||||
const char *name;
|
||||
u8 mac[6];
|
||||
u32 flags;
|
||||
void *ctx;
|
||||
int (*tx)(void *ctx, const void *packet, u32 length);
|
||||
int (*rx_poll)(void *ctx, void *buffer, u32 capacity, u32 *out_length);
|
||||
/* 无线扩展回调(有线驱动置 NULL,向后兼容)。 */
|
||||
int (*scan_start)(void *ctx);
|
||||
int (*scan_count)(void *ctx);
|
||||
int (*scan_result)(void *ctx, u32 n, struct dkm_net_scan_result *out);
|
||||
int (*is_wireless)(void *ctx);
|
||||
};
|
||||
|
||||
struct dkm_net_api {
|
||||
int (*register_device)(const struct dkm_net_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*device_info)(u32 index, void *out);
|
||||
int (*tx)(u32 index, const void *packet, u32 length);
|
||||
int (*rx_poll)(u32 index, void *buffer, u32 capacity, u32 *out_length);
|
||||
int (*scan_start)(u32 index);
|
||||
int (*scan_count)(u32 index);
|
||||
int (*scan_result)(u32 index, u32 n, struct dkm_net_scan_result *out);
|
||||
int (*is_wireless)(u32 index);
|
||||
};
|
||||
|
||||
struct dkm_dma_buffer {
|
||||
void *virt;
|
||||
u64 phys;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
struct dkm_dma_api {
|
||||
int (*alloc_pages)(u64 page_count, u64 alignment, u64 max_phys, struct dkm_dma_buffer *out);
|
||||
};
|
||||
|
||||
#define DKM_NET_F_LINK_UP (1u << 0)
|
||||
#define DKM_NET_F_TX_READY (1u << 1)
|
||||
#define DKM_NET_F_RX_READY (1u << 2)
|
||||
|
||||
struct dkm_kernel_api {
|
||||
u32 version; u32 size; u64 feature_bits;
|
||||
const struct dkm_log_api *log;
|
||||
const void *mem,*utsm,*irq_api,*pci_api;
|
||||
const struct dkm_dma_api *dma;
|
||||
const void *vfs_api;
|
||||
const struct dkm_net_api *net;
|
||||
const void *timer,*drr;
|
||||
const void *rsdp_address,*fb_address;
|
||||
u64 fb_width,fb_height,fb_pitch; u16 fb_bpp;
|
||||
const void *boot_modules_response;
|
||||
int (*irq_register)(u8 irq, void *handler);
|
||||
u64 hhdm_offset;
|
||||
};
|
||||
|
||||
struct dkm_driver_handle;
|
||||
struct dkm_driver_desc {
|
||||
u32 magic; u16 abi_version; u16 desc_size;
|
||||
const char *name,*version,*vendor;
|
||||
u32 driver_class,stage,flags,priority;
|
||||
const char *const *depends; u32 depends_count;
|
||||
const char *const *provides; u32 provides_count;
|
||||
u64 min_kernel_abi,feature_bits,reserved0,reserved1;
|
||||
};
|
||||
#include "../dkm_shared.h"
|
||||
|
||||
static const char *const g_depends[] = {"pci","irq"};
|
||||
static const char *const g_provides[] = {"netdev"};
|
||||
@@ -108,16 +17,6 @@ const struct dkm_driver_desc driver_desc = {
|
||||
.provides=g_provides,.provides_count=1,.min_kernel_abi=1,
|
||||
};
|
||||
|
||||
/* PCI config ports */
|
||||
#define PCI_ADDR 0xCF8
|
||||
#define PCI_DATA 0xCFC
|
||||
#define PCI_VENDOR_ID 0x00
|
||||
#define PCI_DEVICE_ID 0x02
|
||||
#define PCI_COMMAND 0x04
|
||||
#define PCI_BAR0 0x10
|
||||
#define PCI_BAR1 0x14
|
||||
#define PCI_IRQ_LINE 0x3C
|
||||
|
||||
/* e1000 MMIO registers */
|
||||
#define E1000_CTRL 0x0000
|
||||
#define E1000_STATUS 0x0008
|
||||
@@ -205,20 +104,20 @@ static u32 g_rx_tail;
|
||||
static u32 g_tx_tail;
|
||||
static int g_rings_ready;
|
||||
|
||||
static __inline__ void outl(u16 p, u32 v) { __asm__ volatile("outl %0,%1"::"a"(v),"Nd"(p):"memory"); }
|
||||
static __inline__ u32 inl(u16 p) { u32 v; __asm__ volatile("inl %1,%0":"=a"(v):"Nd"(p):"memory"); return v; }
|
||||
static u8 inb(u16 p) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(p):"memory"); return v; }
|
||||
static void outb(u16 p, u8 v) { __asm__ volatile("outb %0,%1"::"a"(v),"Nd"(p):"memory"); }
|
||||
#define COM1 0x3F8
|
||||
|
||||
/* 串口发送等待 thin wrapper — 调用 dkm 共享实现 */
|
||||
static void serial_wait_tx(void) { dkm_serial_wait_tx(COM1); }
|
||||
|
||||
static void raw_log(const char *s) {
|
||||
while (*s) {
|
||||
char c = *s++;
|
||||
if (c == '\n') {
|
||||
for (u32 i=0;i<100000;i++) if (inb(0x3F8+5)&0x20) break;
|
||||
outb(0x3F8, '\r');
|
||||
serial_wait_tx();
|
||||
dkm_outb(COM1, '\r');
|
||||
}
|
||||
for (u32 i=0;i<100000;i++) if (inb(0x3F8+5)&0x20) break;
|
||||
outb(0x3F8, (u8)c);
|
||||
serial_wait_tx();
|
||||
dkm_outb(COM1, (u8)c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,20 +126,18 @@ static void raw_hex(const char *prefix, u64 v) {
|
||||
raw_log(prefix);
|
||||
raw_log("0x");
|
||||
for (int i=15; i>=0; i--) {
|
||||
for (u32 wait=0; wait<100000; wait++) if (inb(0x3F8+5)&0x20) break;
|
||||
outb(0x3F8, (u8)h[(v >> (i * 4)) & 0xf]);
|
||||
serial_wait_tx();
|
||||
dkm_outb(COM1, (u8)h[(v >> (i * 4)) & 0xf]);
|
||||
}
|
||||
raw_log("\n");
|
||||
}
|
||||
|
||||
static u32 pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
|
||||
u32 a = (1u<<31)|((u32)bus<<16)|((u32)dev<<11)|((u32)func<<8)|((u32)reg&0xFC);
|
||||
outl(PCI_ADDR,a); return inl(PCI_DATA);
|
||||
return dkm_pci_read(bus, dev, func, reg);
|
||||
}
|
||||
|
||||
static void pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 v) {
|
||||
u32 a = (1u<<31)|((u32)bus<<16)|((u32)dev<<11)|((u32)func<<8)|((u32)reg&0xFC);
|
||||
outl(PCI_ADDR,a); outl(PCI_DATA,v);
|
||||
dkm_pci_write(bus, dev, func, reg, v);
|
||||
}
|
||||
|
||||
static int e1000_find(u8 *bus, u8 *dev) {
|
||||
@@ -262,9 +159,12 @@ static int e1000_find(u8 *bus, u8 *dev) {
|
||||
static u16 e1000_eeprom_read(u16 addr) {
|
||||
/* EERD: bit0=START, addr<<8, 完成后 bit4=DONE, data 在高 16 位 */
|
||||
g_mmio[E1000_EERD/4] = ((u32)addr << 8) | 1u;
|
||||
for (u32 i=0;i<100000;i++) {
|
||||
/* 实机: 100ms TSC 超时 */
|
||||
u64 deadline = dkm_rdtsc() + dkm_tsc_per_ms * 100;
|
||||
while (dkm_rdtsc() < deadline) {
|
||||
u32 v = g_mmio[E1000_EERD/4];
|
||||
if (v & (1u<<4)) return (u16)(v >> 16);
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return 0xffff;
|
||||
}
|
||||
@@ -382,7 +282,9 @@ static int e1000_tx(void *ctx, const void *packet, u32 length) {
|
||||
g_tx_tail = (index + 1) % E1000_TX_DESC_COUNT;
|
||||
g_mmio[E1000_TDT/4] = g_tx_tail;
|
||||
mmio_flush();
|
||||
for (u32 wait=0; wait<1000000; wait++) {
|
||||
/* 实机: 1秒 TSC 超时等待 TX 完成 */
|
||||
u64 deadline = dkm_rdtsc() + dkm_tsc_per_ms * 1000;
|
||||
while (dkm_rdtsc() < deadline) {
|
||||
dma_fence();
|
||||
if (g_tx_desc[index].status & E1000_TX_STA_DD) {
|
||||
raw_log("[e1000.raw] tx complete\n");
|
||||
@@ -428,6 +330,8 @@ static int e1000_rx_poll(void *ctx, void *buffer, u32 capacity, u32 *out_length)
|
||||
__attribute__((visibility("default")))
|
||||
int driver_init(const struct dkm_kernel_api *api,
|
||||
struct dkm_driver_handle *handle) {
|
||||
/* 实机要求: 先校准 TSC, 再使用基于 CPU 频率的延迟 */
|
||||
dkm_tsc_calibrate();
|
||||
raw_log("[e1000.raw] driver_init entered\n");
|
||||
(void)handle;
|
||||
if (!api||!api->log) return -1;
|
||||
@@ -472,8 +376,11 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
|
||||
/* 软件复位,确保 RX/TX/RAL/RAH 从已知状态开始配置。 */
|
||||
g_mmio[E1000_CTRL/4] = g_mmio[E1000_CTRL/4] | (1u << 26);
|
||||
for (u32 wait=0; wait<1000000; wait++) {
|
||||
/* 实机: 1秒 TSC 超时等待复位完成 */
|
||||
u64 deadline = dkm_rdtsc() + dkm_tsc_per_ms * 1000;
|
||||
while (dkm_rdtsc() < deadline) {
|
||||
if (!(g_mmio[E1000_CTRL/4] & (1u << 26))) break;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
raw_log("[e1000.raw] reset done\n");
|
||||
|
||||
|
||||
@@ -31,8 +31,10 @@ struct dkm_block_api {
|
||||
int (*register_device)(const void *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*read)(u32 index, u64 lba, u32 count, void *buffer);
|
||||
int (*write)(u32 index, u64 lba, u32 count, const void *buffer);
|
||||
u64 (*sector_size)(u32 index);
|
||||
const char *(*device_name)(u32 index);
|
||||
int (*set_write_fn)(u32 index, int (*fn)(void *ctx, u64 lba, u32 count, const void *buf));
|
||||
};
|
||||
|
||||
struct dkm_kernel_api {
|
||||
|
||||
@@ -4,110 +4,23 @@
|
||||
* it does not negotiate features, create virtqueues, or transmit packets.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../dkm_shared.h"
|
||||
|
||||
#define DKM_DRIVER_MAGIC 0x444B4D31u
|
||||
#define DKM_ABI_VERSION 1u
|
||||
/* virtio-specific PCI IDs and capability types (driver-local) */
|
||||
#define PCI_CLASS_REG 0x08 /* 32-bit class/subclass/prog_if/revision */
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed char i8;
|
||||
typedef long long i64;
|
||||
#define PCI_VENDOR_VIRTIO 0x1AF4u
|
||||
#define VIRTIO_TRANS_DEVICE_MIN 0x1000u
|
||||
#define VIRTIO_TRANS_DEVICE_MAX 0x103Fu
|
||||
#define VIRTIO_MODERN_DEVICE_MIN 0x1040u
|
||||
#define VIRTIO_MODERN_DEVICE_MAX 0x107Fu
|
||||
#define VIRTIO_NET_DEVICE_ID 1u
|
||||
|
||||
#define NULL ((void *)0)
|
||||
|
||||
struct dkm_log_api {
|
||||
void (*info)(const char *msg);
|
||||
void (*warn)(const char *msg);
|
||||
void (*error)(const char *msg);
|
||||
void (*panic)(const char *msg);
|
||||
};
|
||||
|
||||
struct dkm_net_scan_result {
|
||||
char ssid[33];
|
||||
u8 bssid[6];
|
||||
u8 channel;
|
||||
i8 rssi;
|
||||
u8 security;
|
||||
};
|
||||
|
||||
struct dkm_net_device_desc {
|
||||
const char *name;
|
||||
u8 mac[6];
|
||||
u32 flags;
|
||||
void *ctx;
|
||||
int (*tx)(void *ctx, const void *packet, u32 length);
|
||||
int (*rx_poll)(void *ctx, void *buffer, u32 capacity, u32 *out_length);
|
||||
/* 无线扩展回调(有线驱动置 NULL,向后兼容)。 */
|
||||
int (*scan_start)(void *ctx);
|
||||
int (*scan_count)(void *ctx);
|
||||
int (*scan_result)(void *ctx, u32 n, struct dkm_net_scan_result *out);
|
||||
int (*is_wireless)(void *ctx);
|
||||
};
|
||||
|
||||
struct dkm_net_api {
|
||||
int (*register_device)(const struct dkm_net_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*device_info)(u32 index, void *out);
|
||||
int (*tx)(u32 index, const void *packet, u32 length);
|
||||
int (*rx_poll)(u32 index, void *buffer, u32 capacity, u32 *out_length);
|
||||
int (*scan_start)(u32 index);
|
||||
int (*scan_count)(u32 index);
|
||||
int (*scan_result)(u32 index, u32 n, struct dkm_net_scan_result *out);
|
||||
int (*is_wireless)(u32 index);
|
||||
};
|
||||
|
||||
#define DKM_NET_F_LINK_UP (1u << 0)
|
||||
|
||||
struct dkm_kernel_api {
|
||||
u32 version;
|
||||
u32 size;
|
||||
u64 feature_bits;
|
||||
const struct dkm_log_api *log;
|
||||
const void *mem;
|
||||
const void *utsm;
|
||||
const void *irq;
|
||||
const void *pci;
|
||||
const void *dma;
|
||||
const void *vfs;
|
||||
const struct dkm_net_api *net;
|
||||
const void *timer;
|
||||
const void *drr;
|
||||
const void *rsdp_address;
|
||||
const void *fb_address;
|
||||
u64 fb_width;
|
||||
u64 fb_height;
|
||||
u64 fb_pitch;
|
||||
u16 fb_bpp;
|
||||
const void *boot_modules_response;
|
||||
int (*irq_register)(u8 irq, void *handler);
|
||||
u64 hhdm_offset;
|
||||
};
|
||||
|
||||
struct dkm_driver_handle;
|
||||
|
||||
struct dkm_driver_desc {
|
||||
u32 magic;
|
||||
u16 abi_version;
|
||||
u16 desc_size;
|
||||
const char *name;
|
||||
const char *version;
|
||||
const char *vendor;
|
||||
u32 driver_class;
|
||||
u32 stage;
|
||||
u32 flags;
|
||||
u32 priority;
|
||||
const char *const *depends;
|
||||
u32 depends_count;
|
||||
const char *const *provides;
|
||||
u32 provides_count;
|
||||
u64 min_kernel_abi;
|
||||
u64 feature_bits;
|
||||
u64 reserved0;
|
||||
u64 reserved1;
|
||||
};
|
||||
#define VIRTIO_PCI_CAP_COMMON_CFG 1u
|
||||
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2u
|
||||
#define VIRTIO_PCI_CAP_ISR_CFG 3u
|
||||
#define VIRTIO_PCI_CAP_DEVICE_CFG 4u
|
||||
#define VIRTIO_PCI_CAP_PCI_CFG 5u
|
||||
|
||||
static const char *const g_depends[] = { "pci", "irq" };
|
||||
static const char *const g_provides[] = { "netdev" };
|
||||
@@ -134,73 +47,18 @@ const struct dkm_driver_desc driver_desc = {
|
||||
.reserved1 = 0
|
||||
};
|
||||
|
||||
#define PCI_ADDR 0xCF8
|
||||
#define PCI_DATA 0xCFC
|
||||
#define PCI_VENDOR_ID 0x00
|
||||
#define PCI_COMMAND 0x04
|
||||
#define PCI_CLASS_REG 0x08
|
||||
#define PCI_HEADER 0x0E
|
||||
#define PCI_CAP_PTR 0x34
|
||||
#define PCI_IRQ_LINE 0x3C
|
||||
#define PCI_BAR0 0x10
|
||||
#define PCI_BAR1 0x14
|
||||
#define PCI_BAR2 0x18
|
||||
#define PCI_BAR3 0x1C
|
||||
#define PCI_BAR4 0x20
|
||||
#define PCI_BAR5 0x24
|
||||
|
||||
#define PCI_CMD_IO (1u << 0)
|
||||
#define PCI_CMD_MEM (1u << 1)
|
||||
#define PCI_CMD_BUSM (1u << 2)
|
||||
|
||||
#define PCI_VENDOR_VIRTIO 0x1AF4u
|
||||
#define VIRTIO_TRANS_DEVICE_MIN 0x1000u
|
||||
#define VIRTIO_TRANS_DEVICE_MAX 0x103Fu
|
||||
#define VIRTIO_MODERN_DEVICE_MIN 0x1040u
|
||||
#define VIRTIO_MODERN_DEVICE_MAX 0x107Fu
|
||||
#define VIRTIO_NET_DEVICE_ID 1u
|
||||
|
||||
#define VIRTIO_PCI_CAP_COMMON_CFG 1u
|
||||
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2u
|
||||
#define VIRTIO_PCI_CAP_ISR_CFG 3u
|
||||
#define VIRTIO_PCI_CAP_DEVICE_CFG 4u
|
||||
#define VIRTIO_PCI_CAP_PCI_CFG 5u
|
||||
|
||||
static const struct dkm_log_api *g_log;
|
||||
|
||||
static __inline__ void outl(u16 port, u32 value) {
|
||||
__asm__ volatile ("outl %0, %1" :: "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static __inline__ u32 inl(u16 port) {
|
||||
u32 value;
|
||||
__asm__ volatile ("inl %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static u32 pci_read(u8 bus, u8 dev, u8 func, u8 reg) {
|
||||
u32 addr = (1u << 31)
|
||||
| ((u32)bus << 16)
|
||||
| ((u32)dev << 11)
|
||||
| ((u32)func << 8)
|
||||
| ((u32)reg & 0xFC);
|
||||
outl(PCI_ADDR, addr);
|
||||
return inl(PCI_DATA);
|
||||
return dkm_pci_read(bus, dev, func, reg);
|
||||
}
|
||||
|
||||
static void pci_write(u8 bus, u8 dev, u8 func, u8 reg, u32 value) {
|
||||
u32 addr = (1u << 31)
|
||||
| ((u32)bus << 16)
|
||||
| ((u32)dev << 11)
|
||||
| ((u32)func << 8)
|
||||
| ((u32)reg & 0xFC);
|
||||
outl(PCI_ADDR, addr);
|
||||
outl(PCI_DATA, value);
|
||||
dkm_pci_write(bus, dev, func, reg, value);
|
||||
}
|
||||
|
||||
static u8 pci_read8(u8 bus, u8 dev, u8 func, u8 reg) {
|
||||
u32 v = pci_read(bus, dev, func, reg);
|
||||
return (u8)((v >> ((reg & 3) * 8)) & 0xff);
|
||||
return dkm_pci_read8(bus, dev, func, reg);
|
||||
}
|
||||
|
||||
static void log_hex(const char *prefix, u64 value) {
|
||||
@@ -320,6 +178,28 @@ static void log_virtio_caps(u8 bus, u8 dev, u8 func) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- tx/rx_poll stub: 安全占位, 不实际收发, 防止 netdev 调用 NULL ---- */
|
||||
static int virtio_net_tx(void *ctx, const void *packet, u32 length) {
|
||||
(void)ctx;
|
||||
(void)packet;
|
||||
/* 仅记录日志, 避免每次发包刷屏: 仅记录长度 */
|
||||
static u32 s_tx_log_guard = 0;
|
||||
if (s_tx_log_guard < 4) {
|
||||
g_log->info("[virtio_net] tx stub: packet dropped (virtqueues not enabled)");
|
||||
log_hex("[virtio_net] tx stub len=", length);
|
||||
s_tx_log_guard++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_net_rx_poll(void *ctx, void *buffer, u32 capacity, u32 *out_length) {
|
||||
(void)ctx;
|
||||
(void)buffer;
|
||||
(void)capacity;
|
||||
if (out_length) *out_length = 0;
|
||||
return 0; /* 无数据, virtqueues 未启用 */
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
int driver_init(const struct dkm_kernel_api *api,
|
||||
struct dkm_driver_handle *handle) {
|
||||
@@ -328,6 +208,9 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
if (!api || !api->log) return -1;
|
||||
g_log = api->log;
|
||||
|
||||
/* 实机要求: 在驱动初始化开头校准 TSC, 为后续时序提供准确计时 */
|
||||
dkm_tsc_calibrate();
|
||||
|
||||
g_log->info("[virtio_net] init begin");
|
||||
|
||||
u8 bus = 0;
|
||||
@@ -379,8 +262,8 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
for (int i = 0; i < 6; i++) netdev.mac[i] = 0;
|
||||
netdev.flags = DKM_NET_F_LINK_UP;
|
||||
netdev.ctx = 0;
|
||||
netdev.tx = 0;
|
||||
netdev.rx_poll = 0;
|
||||
netdev.tx = virtio_net_tx; /* stub: 安全占位, 不 NULL */
|
||||
netdev.rx_poll = virtio_net_rx_poll;
|
||||
int net_index = api->net->register_device(&netdev);
|
||||
log_hex("[virtio_net] netdev register rc=", (u64)(i64)net_index);
|
||||
} else {
|
||||
|
||||
@@ -5,20 +5,56 @@ u8 inb(u16 port);
|
||||
|
||||
#define COM1 0x3F8
|
||||
|
||||
/* ---- TSC-based timing (实机要求: 用 CPU 频率计算, 不用循环) ---- */
|
||||
static u64 g_tsc_per_ms = 0;
|
||||
|
||||
static inline u64 rdtsc_ser(void) {
|
||||
u32 lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
/* 用 PIT (8254, 1.193182 MHz) 校准 TSC 频率 */
|
||||
static void tsc_calibrate_ser(void) {
|
||||
outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
|
||||
outb(0x40, 0x7c); /* 11932 low = ~10ms */
|
||||
outb(0x40, 0x2e); /* 11932 high */
|
||||
u64 tsc_start = rdtsc_ser();
|
||||
u16 prev = 0; u64 loops = 0;
|
||||
for (;;) {
|
||||
outb(0x43, 0x00);
|
||||
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
|
||||
if (cur > prev && loops > 10) break;
|
||||
prev = cur; loops++;
|
||||
}
|
||||
u64 tsc_end = rdtsc_ser();
|
||||
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
|
||||
}
|
||||
|
||||
static int serial_ready(void) {
|
||||
return (inb(COM1 + 5) & 0x20) != 0;
|
||||
}
|
||||
|
||||
/* 实机: 基于 TSC 的 100ms 超时等待 */
|
||||
static int serial_wait_ready(void) {
|
||||
for (u64 spin = 0; spin < 1000000ULL; spin++) {
|
||||
if (serial_ready()) {
|
||||
return 1;
|
||||
if (!g_tsc_per_ms) {
|
||||
/* 兜底: 校准未完成时使用循环 */
|
||||
for (u64 spin = 0; spin < 1000000ULL; spin++) {
|
||||
if (serial_ready()) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
u64 deadline = rdtsc_ser() + g_tsc_per_ms * 100; /* 100ms 超时 */
|
||||
while (rdtsc_ser() < deadline) {
|
||||
if (serial_ready()) return 1;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void serial_init(void) {
|
||||
/* 实机要求: 先校准 TSC, 再使用基于 CPU 频率的延迟 */
|
||||
tsc_calibrate_ser();
|
||||
outb(COM1 + 1, 0x00);
|
||||
outb(COM1 + 3, 0x80);
|
||||
outb(COM1 + 0, 0x03);
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
#include <utsm/utsm.h>
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/pckc.h>
|
||||
#include <utsm/process.h>
|
||||
#include <utsm/log.h>
|
||||
|
||||
static utsm_segment_desc g_segments[UTSM_MAX_SEGMENTS];
|
||||
@@ -18,6 +19,8 @@ void utsm_init(void) {
|
||||
log_info("[UTSM] pckc init begin");
|
||||
utsm_pckc_init();
|
||||
log_info("[UTSM] pckc init ok");
|
||||
|
||||
utsm_process_init();
|
||||
}
|
||||
|
||||
utsm_segment_desc *utsm_get_segment(u32 slot) {
|
||||
|
||||
Binary file not shown.
@@ -248,6 +248,9 @@ int dkm_load_elf_rel(const void *address, u64 size, const struct dkm_symbol_scan
|
||||
const elf64_ehdr *ehdr = (const elf64_ehdr *)address;
|
||||
const elf64_shdr *sections = (const elf64_shdr *)((const u8 *)address + ehdr->shoff);
|
||||
u64 image_offset[64];
|
||||
/* Zero the entire array so non-ALLOC section indices yield offset 0
|
||||
* instead of stack garbage. */
|
||||
for (int zi = 0; zi < 64; zi++) image_offset[zi] = 0;
|
||||
u64 total_size = 0;
|
||||
u64 max_align = 16;
|
||||
u16 alloc_count = 0;
|
||||
@@ -353,7 +356,9 @@ int dkm_load_elf_rel(const void *address, u64 size, const struct dkm_symbol_scan
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rela->offset + 8 <= target->size) {
|
||||
/* Bounds check: use the actual write width, not always 8. */
|
||||
u32 reloc_width = (reloc_type == R_X86_64_64) ? 8 : 4;
|
||||
if (rela->offset + reloc_width <= target->size) {
|
||||
if (reloc_type == R_X86_64_32 || reloc_type == R_X86_64_32S || reloc_type == R_X86_64_PC32) {
|
||||
*(u32 *)(target_base + rela->offset) = (u32)patch;
|
||||
} else {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -6,6 +6,7 @@
|
||||
#define DKM_BLOCK_MAX_DEVICES 8u
|
||||
|
||||
typedef int (*dkm_block_read_fn)(void *ctx, u64 lba, u32 count, void *buffer);
|
||||
typedef int (*dkm_block_write_fn)(void *ctx, u64 lba, u32 count, const void *buffer);
|
||||
|
||||
typedef struct dkm_block_device_desc {
|
||||
const char *name;
|
||||
@@ -13,14 +14,17 @@ typedef struct dkm_block_device_desc {
|
||||
u64 sector_count;
|
||||
void *ctx;
|
||||
dkm_block_read_fn read;
|
||||
dkm_block_write_fn write;
|
||||
} dkm_block_device_desc;
|
||||
|
||||
typedef struct dkm_block_api {
|
||||
int (*register_device)(const dkm_block_device_desc *desc);
|
||||
u32 (*device_count)(void);
|
||||
int (*read)(u32 index, u64 lba, u32 count, void *buffer);
|
||||
int (*write)(u32 index, u64 lba, u32 count, const void *buffer);
|
||||
u64 (*sector_size)(u32 index);
|
||||
const char *(*device_name)(u32 index);
|
||||
int (*set_write_fn)(u32 index, dkm_block_write_fn fn);
|
||||
} dkm_block_api;
|
||||
|
||||
void block_init(void);
|
||||
|
||||
@@ -195,12 +195,12 @@ typedef long long du_i64;
|
||||
#define DU_ANIM_DELAY_NORMAL 100000u /* 标准动画 */
|
||||
#define DU_ANIM_DELAY_FAST 40000u /* 快速反馈 */
|
||||
|
||||
/* 弧线动画参数(DSK spinner 专用) */
|
||||
/* 弧线动画参数(DSK spinner 专用 — Sealed Arc Comet 设计) */
|
||||
#define DU_SPINNER_RADIUS 48u
|
||||
#define DU_SPINNER_THICKNESS 4u
|
||||
#define DU_SPINNER_ARC_GAP 82u /* 每弧宽度(度) */
|
||||
#define DU_SPINNER_ARC_COUNT 4u
|
||||
#define DU_SPINNER_SPEED 2u /* 每帧旋转度数 */
|
||||
#define DU_SPINNER_THICKNESS 5u
|
||||
#define DU_SPINNER_HEAD_WIDTH 40u /* 弧头宽度(度) */
|
||||
#define DU_SPINNER_TAIL_LEN 220u /* 拖尾长度(度) */
|
||||
#define DU_SPINNER_SPEED 4u /* 每帧旋转度数 */
|
||||
#define DU_SPINNER_SPRITE 128u /* 精灵缓冲边长 */
|
||||
|
||||
/* 渐变动画步进 */
|
||||
@@ -673,12 +673,13 @@ static inline void du_draw_progress(du_context *ctx,
|
||||
/* ===================================================================
|
||||
* Spinner(加载弧) — DSK 启动加载动画
|
||||
*
|
||||
* 使用 "Sealed Arc" 四弧旋转设计,弧色取自色板。
|
||||
* 使用 "Sealed Arc Comet" 单弧彗星尾设计:
|
||||
* 一个明亮的弧头 + 渐变拖尾,颜色从弧头色过渡到拖尾色。
|
||||
* =================================================================== */
|
||||
|
||||
/* 默认弧色(从亮到暗的青蓝色) */
|
||||
/* 默认弧色:[0]=弧头色(亮蓝), [1]=拖尾色(紫) */
|
||||
#define DU_SPINNER_ARCS { \
|
||||
DP_SEAL_100, DP_SEAL_300, DP_SEAL_500, DP_SEAL_700 \
|
||||
DP_SEAL_300, DP_SEAL_700, DP_SEAL_500, DP_SEAL_100 \
|
||||
}
|
||||
|
||||
/* ===================================================================
|
||||
|
||||
@@ -35,6 +35,13 @@ static int block_read_impl(u32 index, u64 lba, u32 count, void *buffer) {
|
||||
return dev->read(dev->ctx, lba, count, buffer);
|
||||
}
|
||||
|
||||
static int block_write_impl(u32 index, u64 lba, u32 count, const void *buffer) {
|
||||
if (index >= g_device_count || !buffer || count == 0) return -1;
|
||||
dkm_block_device_desc *dev = &g_devices[index];
|
||||
if (!dev->write) return -2;
|
||||
return dev->write(dev->ctx, lba, count, buffer);
|
||||
}
|
||||
|
||||
static u64 block_sector_size_impl(u32 index) {
|
||||
if (index >= g_device_count) return 0;
|
||||
return g_devices[index].sector_size;
|
||||
@@ -45,12 +52,20 @@ static const char *block_device_name_impl(u32 index) {
|
||||
return g_devices[index].name;
|
||||
}
|
||||
|
||||
static int block_set_write_fn_impl(u32 index, dkm_block_write_fn fn) {
|
||||
if (index >= g_device_count) return -1;
|
||||
g_devices[index].write = fn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const dkm_block_api g_block_api = {
|
||||
.register_device = block_register_device_impl,
|
||||
.device_count = block_device_count_impl,
|
||||
.read = block_read_impl,
|
||||
.write = block_write_impl,
|
||||
.sector_size = block_sector_size_impl,
|
||||
.device_name = block_device_name_impl
|
||||
.device_name = block_device_name_impl,
|
||||
.set_write_fn = block_set_write_fn_impl
|
||||
};
|
||||
|
||||
const dkm_block_api *block_get_api(void) {
|
||||
|
||||
Binary file not shown.
@@ -152,7 +152,8 @@ static struct limine_file *dsk_find_module(void) {
|
||||
/* ---- FAT32 block-provider file reader ---- */
|
||||
static u8 g_dsk_fat32_disk[65536]; /* 128-sector BPB+FAT+root dir buffer */
|
||||
static u8 g_dsk_fat32_cluster[4096]; /* 8-sector cluster buffer */
|
||||
static u8 g_dsk_fat32_filedata[65536]; /* file data buffer */
|
||||
/* 实机要求: 文件缓冲区足够大容纳 deshab.elf (~1.5MB) */
|
||||
static u8 g_dsk_fat32_filedata[2097152]; /* 2MB file data buffer */
|
||||
|
||||
static int dsk_load_from_block_fat32(const void **out_addr, u64 *out_size) {
|
||||
const dkm_kernel_api *api = dkm_get_kernel_api();
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -25,6 +25,9 @@ SECTIONS
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
|
||||
.bss : ALIGN(4K) {
|
||||
*(.bss*)
|
||||
} :data
|
||||
}
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
#include <utsm/utsm.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/segment.h>
|
||||
#include <utsm/arena.h>
|
||||
|
||||
int memcmp(const void *a, const void *b, usize len);
|
||||
usize strlen(const char *s);
|
||||
|
||||
int utsm_selftest_run(void) {
|
||||
utsm_process_context process;
|
||||
utsm_process_create_test(&process, 1);
|
||||
log_info("[UTSM] selftest enter");
|
||||
|
||||
/* utsm_process_context is ~8KB (256 capabilities × 32 bytes).
|
||||
* Allocate from arena instead of stack to avoid kernel stack overflow. */
|
||||
utsm_process_context *process = (utsm_process_context *)kmem_alloc(sizeof(utsm_process_context));
|
||||
if (!process) {
|
||||
log_error("[UTSM] selftest: failed to allocate process context");
|
||||
return UTSM_ERR_NO_MEMORY;
|
||||
}
|
||||
utsm_process_create_test(process, 1);
|
||||
|
||||
utsm_capability cap;
|
||||
int status = utsm_create_segment(&process, UTSM_PAGE_SIZE, UTSM_SEG_F_READ | UTSM_SEG_F_WRITE | UTSM_SEG_F_STRONG_RECOVERY, &cap);
|
||||
int status = utsm_create_segment(process, UTSM_PAGE_SIZE, UTSM_SEG_F_READ | UTSM_SEG_F_WRITE | UTSM_SEG_F_STRONG_RECOVERY, &cap);
|
||||
if (status != UTSM_OK) {
|
||||
log_error("[UTSM] selftest create segment failed");
|
||||
return status;
|
||||
|
||||
Binary file not shown.
+12
-4
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(7);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(7);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
+173
-45
@@ -32,6 +32,10 @@ static void sputc(char c) {
|
||||
static void swrite(const char *s) { while(*s) { if(*s=='\n')sputc('\r'); sputc(*s++); } }
|
||||
static void slog(const char *s) { swrite("[desktop] "); swrite(s); swrite("\n"); }
|
||||
|
||||
/* 前向声明 */
|
||||
static void redraw_all(void);
|
||||
static int ps2_mouse_poll(void);
|
||||
|
||||
/* ============================================================
|
||||
* 常量
|
||||
* ============================================================ */
|
||||
@@ -184,15 +188,15 @@ static const u8 cursor_shape[24][24] = {
|
||||
{1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
@@ -308,6 +312,22 @@ static void cursor_draw(int mx, int my) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 非阻塞延时:动画期间持续轮询鼠标,保持光标响应。
|
||||
* 将 ms 个 50000-iter pause 块拆开,每块结束后轮询一次鼠标。
|
||||
* 若鼠标有新数据包,立即擦除旧光标、在新位置保存背景并重绘光标。 */
|
||||
static void anim_delay_poll_mouse(u32 ms) {
|
||||
for (u32 i = 0; i < ms; i++) {
|
||||
for (volatile u32 j = 0; j < 50000; j++) {
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
if (ps2_mouse_poll()) {
|
||||
cursor_restore_bg();
|
||||
cursor_save_bg(g_mouse_x, g_mouse_y);
|
||||
cursor_draw(g_mouse_x, g_mouse_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 窗口管理
|
||||
* ============================================================ */
|
||||
@@ -372,6 +392,28 @@ static void win_destroy(desktop_window *w) {
|
||||
if (g_windows[i].id == w->id) { idx = i; break; }
|
||||
}
|
||||
if (idx < 0) return;
|
||||
|
||||
/* Window close animation - shrinking rectangle */
|
||||
{
|
||||
int wx = w->x, wy = w->y, ww = w->w, wh = w->h;
|
||||
w->visible = 0;
|
||||
for (int step = 5; step >= 0; step--) {
|
||||
int scale = (step + 1) * 100 / 6;
|
||||
int aw = ww * scale / 100;
|
||||
int ah = wh * scale / 100;
|
||||
int ax = wx + (ww - aw) / 2;
|
||||
int ay = wy + (wh - ah) / 2;
|
||||
cursor_restore_bg();
|
||||
redraw_all();
|
||||
/* redraw_all 末尾已绘制光标,这里先擦除以保证保存的背景干净(不含光标像素) */
|
||||
cursor_restore_bg();
|
||||
du_rect_outline(&g_fb, ax, ay, aw, ah, DS_DARK_ACCENT, DU_RADIUS_SM);
|
||||
cursor_save_bg(g_mouse_x, g_mouse_y);
|
||||
cursor_draw(g_mouse_x, g_mouse_y);
|
||||
anim_delay_poll_mouse(16);
|
||||
}
|
||||
}
|
||||
|
||||
/* 调用应用的 on_destroy */
|
||||
if (w->app_id >= 0 && w->app_id < g_app_count && g_apps[w->app_id].on_destroy && w->app_state) {
|
||||
g_apps[w->app_id].on_destroy(w->app_state);
|
||||
@@ -474,7 +516,20 @@ static void draw_taskbar(void) {
|
||||
if (w->minimized) continue;
|
||||
u32 btn_bg = w->focused ? DS_DARK_ACCENT : DP_ABYSS_600;
|
||||
du_fill_rounded_rect(&g_fb, wx, tb_y + 4, 100, 32, btn_bg, DU_RADIUS_SM);
|
||||
du_draw_string(&g_fb, w->title, wx + 4, tb_y + 8,
|
||||
/* Truncate title to fit button width (100px - 8px padding = ~11 chars) */
|
||||
char truncated[16];
|
||||
int max_chars = 11;
|
||||
int tlen = 0;
|
||||
while (w->title[tlen] && tlen < max_chars) { truncated[tlen] = w->title[tlen]; tlen++; }
|
||||
if (tlen == max_chars && w->title[tlen]) {
|
||||
/* Add ellipsis */
|
||||
if (tlen > 8) tlen = 8;
|
||||
truncated[tlen++] = '.';
|
||||
truncated[tlen++] = '.';
|
||||
truncated[tlen++] = '.';
|
||||
}
|
||||
truncated[tlen] = 0;
|
||||
du_draw_string(&g_fb, truncated, wx + 4, tb_y + 8,
|
||||
DS_DARK_TEXT_PRIMARY, btn_bg, DU_ASCII_STEP);
|
||||
wx += 104;
|
||||
if (wx > (int)g_fb_w - 200) break;
|
||||
@@ -507,7 +562,7 @@ static void draw_taskbar(void) {
|
||||
static void draw_desktop_icons(void) {
|
||||
for (int i = 0; i < g_icon_count; i++) {
|
||||
desktop_icon *ic = &g_icons[i];
|
||||
int cx = ic->x;
|
||||
int cx = ic->x + (DESKTOP_ICON_W - 32) / 2; /* center icon in slot */
|
||||
int cy = ic->y;
|
||||
/* 根据应用 ID 画不同图标 */
|
||||
switch (ic->app_id) {
|
||||
@@ -520,8 +575,8 @@ static void draw_desktop_icons(void) {
|
||||
/* 标签文字 */
|
||||
int label_len = 0;
|
||||
while (ic->label[label_len]) label_len++;
|
||||
int label_x = cx + (32 - label_len * (int)DU_ASCII_STEP) / 2;
|
||||
if (label_x < cx) label_x = cx;
|
||||
int label_x = ic->x + (DESKTOP_ICON_W - label_len * (int)DU_ASCII_STEP) / 2;
|
||||
if (label_x < ic->x) label_x = ic->x;
|
||||
du_draw_string(&g_fb, ic->label, label_x, cy + 36,
|
||||
DS_DARK_TEXT_PRIMARY, DS_DARK_BG_PRIMARY, DU_ASCII_STEP);
|
||||
}
|
||||
@@ -531,43 +586,94 @@ static void draw_desktop_icons(void) {
|
||||
* PS/2 鼠标处理
|
||||
* ============================================================ */
|
||||
|
||||
/* PS/2 控制器等待 — 输入缓冲区空(可写) */
|
||||
static int ps2_wait_write(void) {
|
||||
for (int t = 0; t < 200000; t++) {
|
||||
if (!(inb(0x64) & 0x02)) return 0;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* PS/2 控制器等待 — 输出缓冲区满(可读) */
|
||||
static int ps2_wait_read(void) {
|
||||
for (int t = 0; t < 200000; t++) {
|
||||
if (inb(0x64) & 0x01) return 0;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 排干输出缓冲区中所有残留数据(带超时) */
|
||||
static void ps2_drain(void) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!(inb(0x64) & 0x01)) break;
|
||||
inb(0x60);
|
||||
}
|
||||
}
|
||||
|
||||
static void ps2_mouse_init(void) {
|
||||
/* 启用 AUX 设备 */
|
||||
for (int t = 0; t < 100000; t++) { if (!(inb(0x64) & 2)) break; }
|
||||
/* 1. 刷新固件/上一阶段留下的残留数据 */
|
||||
ps2_drain();
|
||||
|
||||
/* 2. 启用 AUX(鼠标)端口 */
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0xA8);
|
||||
/* 启用 AUX IRQ */
|
||||
for (int t = 0; t < 100000; t++) { if (!(inb(0x64) & 2)) break; }
|
||||
|
||||
/* 3. 读取控制器配置字节 */
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0x20);
|
||||
for (int t = 0; t < 100000; t++) { if (inb(0x64) & 1) break; }
|
||||
ps2_wait_read();
|
||||
u8 cfg = inb(0x60);
|
||||
cfg |= 0x02; /* enable AUX IRQ12 */
|
||||
|
||||
/* 4. 设置配置:bit5=0(启用 AUX 时钟), bit1=1(启用 AUX IRQ12), bit6=1(Set2→Set1 转换) */
|
||||
cfg &= ~0x20; /* enable AUX clock */
|
||||
for (int t = 0; t < 100000; t++) { if (!(inb(0x64) & 2)) break; }
|
||||
cfg |= 0x02; /* enable AUX IRQ12 */
|
||||
cfg |= 0x40; /* enable Set2→Set1 translation */
|
||||
|
||||
/* 5. 写回控制器配置 */
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0x60);
|
||||
for (int t = 0; t < 100000; t++) { if (!(inb(0x64) & 2)) break; }
|
||||
ps2_wait_write();
|
||||
outb(0x60, cfg);
|
||||
/* 复位鼠标 */
|
||||
for (int t = 0; t < 100000; t++) { if (!(inb(0x64) & 2)) break; }
|
||||
|
||||
/* 6. 复位鼠标 (0xFF) — 响应为 ACK(0xFA) + 自检(0xAA) + 设备ID(0x00),共 3 字节 */
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0xD4);
|
||||
for (int t = 0; t < 100000; t++) { if (!(inb(0x64) & 2)) break; }
|
||||
ps2_wait_write();
|
||||
outb(0x60, 0xFF);
|
||||
for (int t = 0; t < 100000; t++) { if (inb(0x64) & 1) break; }
|
||||
inb(0x60); /* ACK */
|
||||
/* 启用 streaming */
|
||||
for (int t = 0; t < 100000; t++) { if (!(inb(0x64) & 2)) break; }
|
||||
/* 排干所有复位响应字节(最多 8 字节,带超时) */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (ps2_wait_read() != 0) break;
|
||||
inb(0x60);
|
||||
}
|
||||
|
||||
/* 7. 启用数据流模式 (0xF4) — 响应为 ACK(0xFA) */
|
||||
ps2_wait_write();
|
||||
outb(0x64, 0xD4);
|
||||
for (int t = 0; t < 100000; t++) { if (!(inb(0x64) & 2)) break; }
|
||||
ps2_wait_write();
|
||||
outb(0x60, 0xF4);
|
||||
for (int t = 0; t < 100000; t++) { if (inb(0x64) & 1) break; }
|
||||
inb(0x60); /* ACK */
|
||||
/* 排干 ACK */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ps2_wait_read() != 0) break;
|
||||
inb(0x60);
|
||||
}
|
||||
|
||||
/* 8. 最终刷新:丢弃任何杂散字节,确保数据包从干净状态开始 */
|
||||
ps2_drain();
|
||||
|
||||
/* 重置鼠标数据包解析状态 */
|
||||
g_mouse_idx = 0;
|
||||
g_mouse_has_pkt = 0;
|
||||
|
||||
slog("mouse init ok");
|
||||
}
|
||||
|
||||
static int ps2_mouse_poll(void) {
|
||||
u8 st = inb(0x64);
|
||||
if (!(st & 1)) return 0;
|
||||
if (!(st & 0x20)) return 0; /* 不是鼠标数据(键盘数据留给键盘处理) */
|
||||
u8 data = inb(0x60);
|
||||
if (!(st & 0x20)) return 0; /* 不是鼠标数据 */
|
||||
|
||||
g_mouse_buf[g_mouse_idx++] = data;
|
||||
if (g_mouse_idx < 3) return 0;
|
||||
@@ -578,11 +684,8 @@ static int ps2_mouse_poll(void) {
|
||||
|
||||
int dx = (int)(i8)g_mouse_buf[1];
|
||||
int dy = (int)(i8)g_mouse_buf[2];
|
||||
if (g_mouse_buf[0] & 0x10) dx = -dx; /* X sign */
|
||||
/* 注意:Y 轴方向(鼠标 Y 向上为正,屏幕 Y 向下为正) */
|
||||
if (!(g_mouse_buf[0] & 0x20)) dy = -dy; /* Y sign */
|
||||
else dy = -dy;
|
||||
dy = -dy; /* 鼠标 Y 翻转 */
|
||||
/* (i8) 转换已处理符号位,无需再检查 sign bits */
|
||||
dy = -dy; /* PS/2 Y 向上为正,屏幕 Y 向下为正,需翻转 */
|
||||
|
||||
g_mouse_x += dx;
|
||||
g_mouse_y += dy;
|
||||
@@ -591,7 +694,10 @@ static int ps2_mouse_poll(void) {
|
||||
if (g_mouse_x >= (int)g_fb_w - CURSOR_SIZE) g_mouse_x = (int)g_fb_w - CURSOR_SIZE;
|
||||
if (g_mouse_y >= (int)g_fb_h - CURSOR_SIZE) g_mouse_y = (int)g_fb_h - CURSOR_SIZE;
|
||||
|
||||
int old_btn = g_mouse_btn;
|
||||
g_mouse_btn = (g_mouse_buf[0] & 0x01) ? 1 : 0;
|
||||
/* Only signal redraw if something visual changed */
|
||||
if (dx == 0 && dy == 0 && g_mouse_btn == old_btn) return 0;
|
||||
g_mouse_has_pkt = 1;
|
||||
return 1;
|
||||
}
|
||||
@@ -1210,6 +1316,24 @@ static void launch_app(int app_id) {
|
||||
|
||||
win->app_state = app->on_create(&ctx);
|
||||
win->dirty = 1;
|
||||
|
||||
/* Window open animation - expanding rectangle */
|
||||
for (int step = 0; step < 6; step++) {
|
||||
int scale = (step + 1) * 100 / 6;
|
||||
int aw = win->w * scale / 100;
|
||||
int ah = win->h * scale / 100;
|
||||
int ax = win->x + (win->w - aw) / 2;
|
||||
int ay = win->y + (win->h - ah) / 2;
|
||||
cursor_restore_bg();
|
||||
redraw_all();
|
||||
/* redraw_all 末尾已绘制光标,这里先擦除以保证保存的背景干净(不含光标像素) */
|
||||
cursor_restore_bg();
|
||||
du_rect_outline(&g_fb, ax, ay, aw, ah, DS_DARK_ACCENT, DU_RADIUS_SM);
|
||||
cursor_save_bg(g_mouse_x, g_mouse_y);
|
||||
cursor_draw(g_mouse_x, g_mouse_y);
|
||||
anim_delay_poll_mouse(16);
|
||||
}
|
||||
|
||||
slog("app launched");
|
||||
}
|
||||
|
||||
@@ -1229,13 +1353,16 @@ static void redraw_all(void) {
|
||||
desktop_window *w = &g_windows[i];
|
||||
if (w->minimized || !w->visible) continue;
|
||||
|
||||
/* 窗口装饰(先画框架作为窗口背景:主体、标题栏、边框) */
|
||||
draw_window_frame(w);
|
||||
|
||||
/* 窗口客户区背景 */
|
||||
int cx = w->x + BORDER_W;
|
||||
int cy = w->y + TITLEBAR_H;
|
||||
int cw = w->w - 2 * BORDER_W;
|
||||
int ch = w->h - TITLEBAR_H - BORDER_W;
|
||||
|
||||
/* 调用应用绘制 */
|
||||
/* 调用应用绘制(在框架之上绘制客户区内容) */
|
||||
if (w->app_id >= 0 && w->app_id < g_app_count && g_apps[w->app_id].on_draw && w->app_state) {
|
||||
app_ctx ctx;
|
||||
ctx.fb = &g_fb;
|
||||
@@ -1247,9 +1374,6 @@ static void redraw_all(void) {
|
||||
ctx.kernel_api = g_kernel_api;
|
||||
g_apps[w->app_id].on_draw(w->app_state, &ctx);
|
||||
}
|
||||
|
||||
/* 窗口装饰(在应用内容之上) */
|
||||
draw_window_frame(w);
|
||||
}
|
||||
|
||||
/* 任务栏 */
|
||||
@@ -1301,18 +1425,17 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
|
||||
/* 轮询 PS/2 鼠标 */
|
||||
if (ps2_mouse_poll()) {
|
||||
need_redraw = 1;
|
||||
|
||||
/* 拖拽处理 */
|
||||
/* 拖拽处理 - 需要全屏重绘 */
|
||||
if (g_dragging && g_drag_win >= 0) {
|
||||
desktop_window *w = win_find(g_drag_win);
|
||||
if (w) {
|
||||
w->x = g_mouse_x - g_drag_off_x;
|
||||
w->y = g_mouse_y - g_drag_off_y;
|
||||
}
|
||||
need_redraw = 1;
|
||||
}
|
||||
|
||||
/* 鼠标点击事件 */
|
||||
/* 鼠标点击事件 - 需要全屏重绘 */
|
||||
if (g_mouse_btn) {
|
||||
/* 检查任务栏点击 */
|
||||
int tb_y = (int)g_fb_h - TASKBAR_H;
|
||||
@@ -1431,6 +1554,11 @@ next:
|
||||
if (need_redraw) {
|
||||
cursor_restore_bg();
|
||||
redraw_all();
|
||||
} else if (g_mouse_has_pkt) {
|
||||
/* 鼠标移动但无需全屏重绘:只更新光标位置 */
|
||||
cursor_restore_bg();
|
||||
cursor_save_bg(g_mouse_x, g_mouse_y);
|
||||
cursor_draw(g_mouse_x, g_mouse_y);
|
||||
}
|
||||
|
||||
__asm__("pause");
|
||||
|
||||
+4
-1
@@ -7,7 +7,10 @@ OUT := $(ROOT)/SYSTEM/system/deshab64/deshab.elf
|
||||
CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-stack-protector -fpie -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Wall -Wextra -I../UTSM/include -O2
|
||||
LDFLAGS := -nostdlib -static -pie -z max-page-size=0x1000 -T linker.ld
|
||||
|
||||
C_SOURCES := $(wildcard *.c)
|
||||
# logo_data.c is #included directly into main.c (the DSK PIE loader only
|
||||
# handles R_X86_64_RELATIVE, so the logo array must be file-local to main.o
|
||||
# rather than a cross-unit symbol). Exclude it from standalone compilation.
|
||||
C_SOURCES := $(filter-out logo_data.c, $(wildcard *.c))
|
||||
OBJECTS := $(C_SOURCES:.c=.o)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
+9
-12
@@ -2,26 +2,23 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5); /* R-X */
|
||||
rodata PT_LOAD FLAGS(4); /* R-- */
|
||||
data PT_LOAD FLAGS(6); /* RW- */
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x1000;
|
||||
|
||||
.text : ALIGN(4K) {
|
||||
*(.text*)
|
||||
} :text
|
||||
|
||||
.rodata : ALIGN(4K) {
|
||||
*(.rodata*)
|
||||
} :rodata
|
||||
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
+518
-149
@@ -12,6 +12,7 @@ typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
|
||||
typedef int (*block_read_fn)(u32 index, u64 lba, u32 count, void *buf);
|
||||
typedef int (*block_write_fn)(u32 index, u64 lba, u32 count, const void *buf);
|
||||
|
||||
static void sputc(char c) { for(unsigned i=0;i<100000;i++){if(inb(COM1+5)&0x20)break;} outb(COM1,(u8)c); }
|
||||
static void swrite(const char *s) { while(*s){if(*s=='\n')sputc('\r');sputc(*s++);} }
|
||||
@@ -61,11 +62,38 @@ typedef struct { u64 offset; u64 info; i64 addend; } elf64_rela;
|
||||
|
||||
static u64 g_fb_addr, g_fb_w, g_fb_h, g_fb_p;
|
||||
static block_read_fn g_block_read;
|
||||
static block_write_fn g_block_write;
|
||||
static u64 g_tsc_per_ms = 0;
|
||||
static u8 g_disk[131072];
|
||||
static u8 g_cluster[4096];
|
||||
static u8 g_fdata[262144];
|
||||
|
||||
static int fat32_read_sectors(u32 lba, u32 count, u8 *out) { return g_block_read ? g_block_read(0,lba,count,out) : -1; }
|
||||
static int fat32_write_sectors(u32 lba, u32 count, const u8 *buf) { return g_block_write ? g_block_write(0,lba,count,buf) : -1; }
|
||||
|
||||
/* ---- TSC-based timing ---- */
|
||||
static u64 rdtsc_dsk(void) {
|
||||
u32 lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
static void tsc_calibrate_dsk(void) {
|
||||
outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
|
||||
outb(0x40, 0x7c); /* 11932 low = ~10ms */
|
||||
outb(0x40, 0x2e); /* 11932 high */
|
||||
u64 tsc_start = rdtsc_dsk();
|
||||
u16 prev = 0; u64 loops = 0;
|
||||
for (;;) {
|
||||
outb(0x43, 0x00);
|
||||
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
|
||||
if (cur > prev && loops > 10) break;
|
||||
prev = cur; loops++;
|
||||
}
|
||||
u64 tsc_end = rdtsc_dsk();
|
||||
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
|
||||
logh("[DSK] tsc_per_ms=", g_tsc_per_ms);
|
||||
}
|
||||
|
||||
static u32 blend_color(u32 c1, u32 c2, u32 a) {
|
||||
u32 na = 256 - a;
|
||||
@@ -96,6 +124,81 @@ static void dsk_fill_gradient_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Spinner animation: comet-tail arc, clockwise, double-buffered ---- */
|
||||
/* sin×127 lookup table, 256 entries (1.40625° each). cos(d) = sin(d+64). */
|
||||
static const i8 g_sin_tab[256] = {
|
||||
0,3,6,9,12,16,19,22,25,28,31,34,37,40,43,46,
|
||||
49,51,54,57,60,63,65,68,71,73,76,78,81,83,85,88,
|
||||
90,92,94,96,98,100,102,104,106,107,109,111,112,113,115,116,
|
||||
117,118,120,121,122,122,123,124,125,125,126,126,126,127,127,127,
|
||||
127,127,127,127,126,126,126,125,125,124,123,122,122,121,120,118,
|
||||
117,116,115,113,112,111,109,107,106,104,102,100,98,96,94,92,
|
||||
90,88,85,83,81,78,76,73,71,68,65,63,60,57,54,51,
|
||||
49,46,43,40,37,34,31,28,25,22,19,16,12,9,6,3,
|
||||
0,-3,-6,-9,-12,-16,-19,-22,-25,-28,-31,-34,-37,-40,-43,-46,
|
||||
-49,-51,-54,-57,-60,-63,-65,-68,-71,-73,-76,-78,-81,-83,-85,-88,
|
||||
-90,-92,-94,-96,-98,-100,-102,-104,-106,-107,-109,-111,-112,-113,-115,-116,
|
||||
-117,-118,-120,-121,-122,-122,-123,-124,-125,-125,-126,-126,-126,-127,-127,-127,
|
||||
-127,-127,-127,-127,-126,-126,-126,-125,-125,-124,-123,-122,-122,-121,-120,-118,
|
||||
-117,-116,-115,-113,-112,-111,-109,-107,-106,-104,-102,-100,-98,-96,-94,-92,
|
||||
-90,-88,-85,-83,-81,-78,-76,-73,-71,-68,-65,-63,-60,-57,-54,-51,
|
||||
-49,-46,-43,-40,-37,-34,-31,-28,-25,-22,-19,-16,-12,-9,-6,-3,
|
||||
};
|
||||
static i64 dsk_isin(u32 deg) { return (i64)g_sin_tab[deg & 255]; }
|
||||
static i64 dsk_icos(u32 deg) { return (i64)g_sin_tab[(deg + 64) & 255]; }
|
||||
|
||||
#define SPIN_R 64
|
||||
#define SPIN_ARC 110 /* comet-tail span (of 256) ≈ 155° */
|
||||
#define SPIN_THICK 3 /* half-thickness of arc band */
|
||||
#define SPIN_BOX (SPIN_R + SPIN_THICK + 2)
|
||||
static u32 g_spin_bg[(SPIN_BOX*2+1) * (SPIN_BOX*2+1)];
|
||||
|
||||
static void spinner_save_bg(u32 *fb, i64 cx, i64 cy) {
|
||||
for (i64 dy = -SPIN_BOX; dy <= SPIN_BOX; dy++) {
|
||||
for (i64 dx = -SPIN_BOX; dx <= SPIN_BOX; dx++) {
|
||||
i64 x = cx + dx, y = cy + dy;
|
||||
u32 px = (x >= 0 && (u64)x < g_fb_w && y >= 0 && (u64)y < g_fb_h)
|
||||
? ((u32*)((u8*)fb + (u64)y * g_fb_p))[(u64)x]
|
||||
: dsk_bg_at_y(y);
|
||||
g_spin_bg[(dy + SPIN_BOX) * (SPIN_BOX*2+1) + (dx + SPIN_BOX)] = px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void spinner_restore_bg(u32 *fb, i64 cx, i64 cy) {
|
||||
for (i64 dy = -SPIN_BOX; dy <= SPIN_BOX; dy++) {
|
||||
i64 y = cy + dy;
|
||||
if (y < 0 || (u64)y >= g_fb_h) continue;
|
||||
u32 *line = (u32*)((u8*)fb + (u64)y * g_fb_p);
|
||||
for (i64 dx = -SPIN_BOX; dx <= SPIN_BOX; dx++) {
|
||||
i64 x = cx + dx;
|
||||
if (x < 0 || (u64)x >= g_fb_w) continue;
|
||||
line[(u64)x] = g_spin_bg[(dy + SPIN_BOX) * (SPIN_BOX*2+1) + (dx + SPIN_BOX)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw comet-tail arc: head at (base+SPIN_ARC) brightest, tail at base fading out.
|
||||
* Clockwise rotation by advancing `base`. Double-buffered via save/restore. */
|
||||
static void spinner_draw(u32 *fb, i64 cx, i64 cy, u32 base, u32 head_color) {
|
||||
u32 bg_ref = dsk_bg_at_y(cy);
|
||||
for (u32 d = 0; d < SPIN_ARC; d++) {
|
||||
u32 ang = (base + d) & 255;
|
||||
i64 ic = dsk_icos(ang), is = dsk_isin(ang);
|
||||
u32 alpha = ((d + 1) * 255) / SPIN_ARC; /* tail→head: 0→255 */
|
||||
u32 color = blend_color(bg_ref, head_color, alpha);
|
||||
for (i64 t = -SPIN_THICK; t <= SPIN_THICK; t++) {
|
||||
i64 r = SPIN_R + t;
|
||||
if (r <= 0) continue;
|
||||
i64 x = cx + (r * ic) / 127;
|
||||
i64 y = cy + (r * is) / 127;
|
||||
if (x < 0 || (u64)x >= g_fb_w || y < 0 || (u64)y >= g_fb_h) continue;
|
||||
u32 *line = (u32*)((u8*)fb + (u64)y * g_fb_p);
|
||||
line[(u64)x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int fat32_find_entry(const u8 *clus, u32 clus_sectors, const char *target, u32 *out_clus, u32 *out_size) {
|
||||
const fat32_de *dir = (const fat32_de *)clus;
|
||||
for (u32 e=0; e*32 < clus_sectors*512; e++) {
|
||||
@@ -174,17 +277,238 @@ static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsk_check_firstinit(int *is_first) {
|
||||
/* Write a file to the FAT32 root directory by 11-char 8.3 name.
|
||||
* If the file exists, its content is replaced. If not, a new entry is created.
|
||||
* Uses g_disk (256-sector buffer) which must already contain the BPB+FAT+root.
|
||||
* Returns 0 on success. */
|
||||
static int fat32_write_root_file(const char *name11, const u8 *data, u32 size) {
|
||||
u8 *disk = g_disk;
|
||||
const fat32_bpb *bpb = (const fat32_bpb *)disk;
|
||||
if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) return -1;
|
||||
u32 spc = bpb->spc;
|
||||
u32 fat_lba = bpb->rsvd;
|
||||
u32 fat_sectors = bpb->spf;
|
||||
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
|
||||
u32 fat_byte_off = bpb->rsvd * 512;
|
||||
u32 root_clus = bpb->root_clus;
|
||||
u32 cluster_bytes = spc * 512;
|
||||
|
||||
/* 1. Re-read BPB+FAT to ensure g_disk is fresh */
|
||||
if (fat32_read_sectors(0, 256, disk) != 0) return -2;
|
||||
|
||||
/* 2. Find file entry in root directory */
|
||||
u32 root_lba = data_lba + (root_clus - 2) * spc;
|
||||
u8 *root_buf = disk + (u64)root_lba * 512;
|
||||
u32 max_entries = cluster_bytes / 32;
|
||||
fat32_de *dir = (fat32_de *)root_buf;
|
||||
int free_entry = -1;
|
||||
u32 existing_clus = 0;
|
||||
int found = 0;
|
||||
for (u32 e = 0; e < max_entries; e++) {
|
||||
if (dir[e].name[0] == 0) { if (free_entry < 0) free_entry = (int)e; break; }
|
||||
if ((u8)dir[e].name[0] == 0xE5) { if (free_entry < 0) free_entry = (int)e; continue; }
|
||||
if (dir[e].attr == 0x0F) continue;
|
||||
if (dir[e].attr & 0x08) continue;
|
||||
if (neq11(dir[e].name, name11)) {
|
||||
existing_clus = r16((const u8*)&dir[e].clow) | ((u32)r16((const u8*)&dir[e].chigh) << 16);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 3. Allocate or reuse clusters */
|
||||
u32 bytes_needed = size > 0 ? size : 1;
|
||||
u32 clusters_needed = (bytes_needed + cluster_bytes - 1) / cluster_bytes;
|
||||
u32 first_clus = 0;
|
||||
u32 prev_clus = 0;
|
||||
|
||||
if (found && existing_clus >= 2) {
|
||||
/* Reuse existing chain, extend or shrink as needed */
|
||||
first_clus = existing_clus;
|
||||
u32 cur = existing_clus;
|
||||
u32 count = 0;
|
||||
while (cur >= 2 && cur < 0x0FFFFFF8 && count < clusters_needed) {
|
||||
prev_clus = cur;
|
||||
u32 fo = fat_byte_off + cur * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
cur = r32(disk + fo) & 0x0FFFFFFF;
|
||||
count++;
|
||||
}
|
||||
/* If we need more clusters, allocate them */
|
||||
while (count < clusters_needed) {
|
||||
/* Find a free cluster in FAT */
|
||||
u32 newc = 0;
|
||||
for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) {
|
||||
u32 fo = fat_byte_off + c * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
if ((r32(disk + fo) & 0x0FFFFFFF) == 0) { newc = c; break; }
|
||||
}
|
||||
if (newc == 0) { logl("[DSK] fat32 write: no free clusters"); return -3; }
|
||||
/* Link previous cluster to new */
|
||||
u32 pfo = fat_byte_off + prev_clus * 4;
|
||||
if (pfo + 4 <= sizeof(g_disk)) {
|
||||
disk[pfo] = (u8)(newc & 0xFF);
|
||||
disk[pfo+1] = (u8)((newc >> 8) & 0xFF);
|
||||
disk[pfo+2] = (u8)((newc >> 16) & 0xFF);
|
||||
disk[pfo+3] = (u8)((newc >> 24) & 0x0F);
|
||||
}
|
||||
prev_clus = newc;
|
||||
count++;
|
||||
}
|
||||
/* Terminate the chain */
|
||||
if (prev_clus >= 2) {
|
||||
u32 fo = fat_byte_off + prev_clus * 4;
|
||||
if (fo + 4 <= sizeof(g_disk)) {
|
||||
disk[fo] = 0xF8; disk[fo+1] = 0xFF; disk[fo+2] = 0xFF; disk[fo+3] = 0x0F;
|
||||
}
|
||||
}
|
||||
/* Free excess clusters from the old chain */
|
||||
u32 next = 0;
|
||||
u32 fo = fat_byte_off + prev_clus * 4;
|
||||
if (fo + 4 <= sizeof(g_disk)) next = r32(disk + fo) & 0x0FFFFFFF;
|
||||
while (next >= 2 && next < 0x0FFFFFF8) {
|
||||
u32 nfo = fat_byte_off + next * 4;
|
||||
u32 nn = 0;
|
||||
if (nfo + 4 <= sizeof(g_disk)) nn = r32(disk + nfo) & 0x0FFFFFFF;
|
||||
disk[nfo] = 0; disk[nfo+1] = 0; disk[nfo+2] = 0; disk[nfo+3] = 0;
|
||||
next = nn;
|
||||
}
|
||||
} else {
|
||||
/* Allocate new clusters */
|
||||
if (free_entry < 0) { logl("[DSK] fat32 write: no free dir entry"); return -4; }
|
||||
for (u32 i = 0; i < clusters_needed; i++) {
|
||||
u32 newc = 0;
|
||||
for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) {
|
||||
u32 fo = fat_byte_off + c * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
if ((r32(disk + fo) & 0x0FFFFFFF) == 0) { newc = c; break; }
|
||||
}
|
||||
if (newc == 0) { logl("[DSK] fat32 write: no free clusters"); return -3; }
|
||||
if (i == 0) first_clus = newc;
|
||||
if (prev_clus >= 2) {
|
||||
u32 pfo = fat_byte_off + prev_clus * 4;
|
||||
disk[pfo] = (u8)(newc & 0xFF);
|
||||
disk[pfo+1] = (u8)((newc >> 8) & 0xFF);
|
||||
disk[pfo+2] = (u8)((newc >> 16) & 0xFF);
|
||||
disk[pfo+3] = (u8)((newc >> 24) & 0x0F);
|
||||
}
|
||||
prev_clus = newc;
|
||||
}
|
||||
/* Terminate chain */
|
||||
if (prev_clus >= 2) {
|
||||
u32 fo = fat_byte_off + prev_clus * 4;
|
||||
disk[fo] = 0xF8; disk[fo+1] = 0xFF; disk[fo+2] = 0xFF; disk[fo+3] = 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4. Write data to clusters */
|
||||
u32 remaining = size;
|
||||
const u8 *src = data;
|
||||
u32 cur = first_clus;
|
||||
u32 ci = 0;
|
||||
while (cur >= 2 && cur < 0x0FFFFFF8 && ci < clusters_needed) {
|
||||
u32 clba = data_lba + (cur - 2) * spc;
|
||||
u32 chunk = remaining < cluster_bytes ? remaining : cluster_bytes;
|
||||
/* Read cluster into g_cluster, overlay data, write back */
|
||||
if ((u64)clba * 512 + cluster_bytes <= 256ULL * 512) {
|
||||
/* In g_disk buffer — copy data directly */
|
||||
u8 *dst = disk + (u64)clba * 512;
|
||||
for (u32 b = 0; b < chunk; b++) dst[b] = src[b];
|
||||
for (u32 b = chunk; b < cluster_bytes; b++) dst[b] = 0;
|
||||
} else {
|
||||
/* Out of buffer — use sector write */
|
||||
if (fat32_read_sectors(clba, spc, g_cluster) != 0) return -5;
|
||||
for (u32 b = 0; b < chunk; b++) g_cluster[b] = src[b];
|
||||
for (u32 b = chunk; b < cluster_bytes; b++) g_cluster[b] = 0;
|
||||
if (fat32_write_sectors(clba, spc, g_cluster) != 0) return -6;
|
||||
}
|
||||
src += chunk; remaining -= chunk; ci++;
|
||||
u32 fo = fat_byte_off + cur * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
cur = r32(disk + fo) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
/* 5. Update directory entry */
|
||||
if (!found) {
|
||||
fat32_de *e = &dir[free_entry];
|
||||
for (int i = 0; i < 11; i++) e->name[i] = name11[i];
|
||||
e->attr = 0x20; /* archive */
|
||||
e->ntr = 0; e->ctenth = 0; e->ctime = 0; e->cdate = 0;
|
||||
e->adate = 0; e->chigh = (u16)((first_clus >> 16) & 0xFFFF);
|
||||
e->wtime = 0; e->wdate = 0; e->clow = (u16)(first_clus & 0xFFFF);
|
||||
} else {
|
||||
dir[free_entry >= 0 ? (u32)free_entry : 0].chigh = (u16)((first_clus >> 16) & 0xFFFF);
|
||||
dir[free_entry >= 0 ? (u32)free_entry : 0].clow = (u16)(first_clus & 0xFFFF);
|
||||
/* Find the existing entry again to update it */
|
||||
for (u32 e2 = 0; e2 < max_entries; e2++) {
|
||||
if (neq11(dir[e2].name, name11)) {
|
||||
dir[e2].chigh = (u16)((first_clus >> 16) & 0xFFFF);
|
||||
dir[e2].clow = (u16)(first_clus & 0xFFFF);
|
||||
dir[e2].fsize = size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Set file size in the directory entry */
|
||||
for (u32 e2 = 0; e2 < max_entries; e2++) {
|
||||
if (neq11(dir[e2].name, name11)) {
|
||||
dir[e2].fsize = size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 6. Write FAT + root directory + data sectors back to disk */
|
||||
/* Write FAT (both copies) */
|
||||
for (u32 f = 0; f < bpb->fc; f++) {
|
||||
u32 flba = fat_lba + f * fat_sectors;
|
||||
if (fat32_write_sectors(flba, fat_sectors, disk + (u64)flba * 512) != 0) return -7;
|
||||
}
|
||||
/* Write root directory cluster */
|
||||
u32 root_dir_lba = data_lba + (root_clus - 2) * spc;
|
||||
if ((u64)root_dir_lba * 512 + cluster_bytes <= 256ULL * 512) {
|
||||
if (fat32_write_sectors(root_dir_lba, spc, disk + (u64)root_dir_lba * 512) != 0) return -8;
|
||||
}
|
||||
/* Write data clusters that were in the g_disk buffer */
|
||||
cur = first_clus;
|
||||
ci = 0;
|
||||
while (cur >= 2 && cur < 0x0FFFFFF8 && ci < clusters_needed) {
|
||||
u32 clba = data_lba + (cur - 2) * spc;
|
||||
if ((u64)clba * 512 + cluster_bytes <= 256ULL * 512) {
|
||||
if (fat32_write_sectors(clba, spc, disk + (u64)clba * 512) != 0) return -9;
|
||||
}
|
||||
u32 fo = fat_byte_off + cur * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
cur = r32(disk + fo) & 0x0FFFFFFF;
|
||||
ci++;
|
||||
}
|
||||
|
||||
logl("[DSK] fat32 write: success");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsk_check_firstinit(int *is_first, int *dev_mode) {
|
||||
char name[12]; /* "FIRSTINTXT" on stack — no PIE reloc */
|
||||
name[0]='F';name[1]='I';name[2]='R';name[3]='S';name[4]='T';
|
||||
name[5]='I';name[6]='N';name[7]='T';name[8]='X';name[9]='T';name[10]=0;
|
||||
u8 *data = 0; u32 size = 0;
|
||||
*dev_mode = 0;
|
||||
logl("[DSK] fat32_read_path start");
|
||||
int rc = fat32_read_root_file(name, &data, &size);
|
||||
logh("[DSK] fat32_read_path rc=", (u64)(i64)rc);
|
||||
if (rc != 0) { logl("[DSK] firstInit.txt not found"); *is_first = 1; return 0; }
|
||||
if (data[0] == '0') { logl("[DSK] firstInit=0"); *is_first = 1; return 0; }
|
||||
logl("[DSK] firstInit != 0"); *is_first = 0; return 0;
|
||||
if (data[0] == '0') { logl("[DSK] firstInit=0"); *is_first = 1; }
|
||||
else { logl("[DSK] firstInit != 0"); *is_first = 0; }
|
||||
/* 解析第二行 dev_mode 标志(firstInit.txt 格式: "0|1\n0|1") */
|
||||
u32 i = 0;
|
||||
while (i < size && data[i] != '\n') i++;
|
||||
if (i < size) {
|
||||
i++; /* 跳过换行 */
|
||||
if (i < size && data[i] == '1') {
|
||||
*dev_mode = 1;
|
||||
logl("[DSK] dev_mode=1 (developer auto-test)");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsk_load_elf(u8 *data, u32 size, void **entry_out) {
|
||||
@@ -205,8 +529,10 @@ static int dsk_load_elf(u8 *data, u32 size, void **entry_out) {
|
||||
if (!lc || min_vaddr == ~0ULL) return -4;
|
||||
u64 isize = max_vaddr - min_vaddr;
|
||||
isize = (isize + 0xFFF) & ~0xFFFULL;
|
||||
static u8 ibuf[262144];
|
||||
/* 加载缓冲:需容纳 shell.elf(~536KB,含 FAT32 读写缓冲 BSS)。1MB 留余量。 */
|
||||
static u8 ibuf[1048576];
|
||||
u8 *image = ibuf;
|
||||
if (isize > 1048576) return -5; /* 镜像过大,防止越界 */
|
||||
memset_dsk(image, 0, isize);
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const elf64_phdr *ph = (const elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
||||
@@ -247,177 +573,220 @@ static int dsk_load_elf(u8 *data, u32 size, void **entry_out) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsk_spinner_and_check(u32 *fb_arg, i64 cx, i64 cy, i64 r, i64 thk,
|
||||
const u32 arc_colors[4], u32 bg, const void *boot_ctx_ptr) {
|
||||
(void)bg;
|
||||
(void)fb_arg;
|
||||
/* Load an ELF module from the FAT32 root by 11-char 8.3 name, parse it into
|
||||
* the shared image buffer, and jump to its entry with the boot context.
|
||||
* Returns 0 if the module ran and returned, non-zero on load failure. */
|
||||
static int dsk_load_and_run(const char name11[12], const dsk_boot_context *ctx) {
|
||||
u8 *data=0; u32 size=0; void *entry=0;
|
||||
if (fat32_read_root_file(name11, &data, &size) != 0) return -1;
|
||||
if (dsk_load_elf(data, size, &entry) != 0) return -2;
|
||||
void(*fn)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))entry;
|
||||
fn(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Load desktop.elf and jump to it. Never returns on success. */
|
||||
static void dsk_run_desktop(const dsk_boot_context *ctx) {
|
||||
char dn[12]; /* DESKTOP ELF */
|
||||
dn[0]='D';dn[1]='E';dn[2]='S';dn[3]='K';dn[4]='T';dn[5]='O';dn[6]='P';dn[7]=' ';dn[8]='E';dn[9]='L';dn[10]='F';
|
||||
if (dsk_load_and_run(dn, ctx) != 0) logl("[DSK] desktop load failed");
|
||||
for(;;)__asm__("hlt");
|
||||
}
|
||||
|
||||
/* After FirstInit returns, persist the encrypted user.conf buffer (left in
|
||||
* ctx->reserved[0/1]) to the FAT32 root as USER.CONF, then flip firstInit.txt
|
||||
* from '0' to '1' so subsequent boots skip the wizard and go to login. */
|
||||
static void dsk_persist_userconf(const dsk_boot_context *ctx) {
|
||||
dsk_boot_context *ctx_mut = (dsk_boot_context *)ctx;
|
||||
u64 conf_ptr = ctx_mut->reserved[0];
|
||||
u64 conf_sz = ctx_mut->reserved[1];
|
||||
if (!conf_ptr || !conf_sz) {
|
||||
logl("[DSK] no conf buffer from FirstInit, skipping persist");
|
||||
return;
|
||||
}
|
||||
if (!g_block_write) {
|
||||
logl("[DSK] no block_write, cannot persist user.conf");
|
||||
return;
|
||||
}
|
||||
const u8 *conf = (const u8 *)conf_ptr;
|
||||
|
||||
/* 1. Write USER.CONF (encrypted buffer as-is; login decrypts with password) */
|
||||
char cn[12]; /* USER CON */
|
||||
cn[0]='U';cn[1]='S';cn[2]='E';cn[3]='R';cn[4]=' ';cn[5]=' ';cn[6]=' ';cn[7]=' ';cn[8]='C';cn[9]='O';cn[10]='N';
|
||||
logl("[DSK] writing USER.CONF");
|
||||
int wrc = fat32_write_root_file(cn, conf, (u32)conf_sz);
|
||||
logh("[DSK] USER.CONF write rc=", (u64)(i64)wrc);
|
||||
|
||||
/* 2. Flip firstInit.txt: '0' -> '1',保留第二行 dev_mode 标志 */
|
||||
char fn[12]; /* FIRSTINTXT */
|
||||
fn[0]='F';fn[1]='I';fn[2]='R';fn[3]='S';fn[4]='T';fn[5]='I';fn[6]='N';fn[7]='T';fn[8]='X';fn[9]='T';fn[10]=0;
|
||||
/* 读取当前 firstInit.txt 以保留 dev_mode(第二行),格式 "0|1\n0|1" */
|
||||
u8 dev_mode_byte = '0';
|
||||
u8 *fi_data = 0; u32 fi_size = 0;
|
||||
if (fat32_read_root_file(fn, &fi_data, &fi_size) == 0) {
|
||||
u32 i = 0;
|
||||
while (i < fi_size && fi_data[i] != '\n') i++;
|
||||
if (i < fi_size) { i++; if (i < fi_size) dev_mode_byte = fi_data[i]; }
|
||||
}
|
||||
u8 fi_buf[3]; fi_buf[0] = '1'; fi_buf[1] = '\n'; fi_buf[2] = dev_mode_byte;
|
||||
int frc = fat32_write_root_file(fn, fi_buf, 3);
|
||||
logh("[DSK] firstInit.txt flip rc=", (u64)(i64)frc);
|
||||
|
||||
/* Clear reserved so login path doesn't see stale pointer */
|
||||
ctx_mut->reserved[0] = 0;
|
||||
ctx_mut->reserved[1] = 0;
|
||||
}
|
||||
|
||||
/* Draw the spinning loader (comet-tail arc) on the gradient background,
|
||||
* then run the firstInit check and dispatch system component loading. */
|
||||
static void dsk_spinner_and_check(const void *boot_ctx_ptr) {
|
||||
const dsk_boot_context *ctx = (const dsk_boot_context *)boot_ctx_ptr;
|
||||
{ u64 api = ctx->dkm_kernel_api;
|
||||
g_block_read = (block_read_fn)*(u64 *)(api + 0xA8);
|
||||
if (g_block_read) g_block_read = (block_read_fn)*(u64 *)((u64)g_block_read + 16); }
|
||||
|
||||
#define SPR 128
|
||||
static u32 sprite[SPR*SPR];
|
||||
i64 sp=SPR*4, scx=SPR/2, scy=SPR/2, bx=cx-scx, by=cy-scy;
|
||||
i64 frame=0, base=0; int checked=0; void *fe_entry=0;
|
||||
u64 blk = *(u64 *)(api + 0xA8);
|
||||
g_block_read = blk ? (block_read_fn)*(u64 *)(blk + 16) : 0; /* block_api.read */
|
||||
g_block_write = blk ? (block_write_fn)*(u64 *)(blk + 24) : 0; /* block_api.write */ }
|
||||
|
||||
g_fb_addr=ctx->framebuffer_address; g_fb_w=ctx->framebuffer_width;
|
||||
g_fb_h=ctx->framebuffer_height; g_fb_p=ctx->framebuffer_pitch;
|
||||
u32 *sfb=(u32*)(u64)g_fb_addr;
|
||||
dsk_fill_gradient_rect(sfb, 0, 0, (i64)g_fb_w, (i64)g_fb_h);
|
||||
u64 sw=g_fb_w, sh=g_fb_h, spv=g_fb_p;
|
||||
logh("[DSK] block_read ptr=", (u64)g_block_read);
|
||||
logl("[DSK] entering spinner loop");
|
||||
|
||||
while (1) {
|
||||
g_fb_w=SPR; g_fb_h=SPR; g_fb_p=sp;
|
||||
/* per-row gradient so sprite interior matches background */
|
||||
static u32 row_bg[SPR];
|
||||
for (i64 y0=0; y0<SPR; y0++) {
|
||||
i64 ry = by + y0;
|
||||
if (ry < 0) ry = 0;
|
||||
if ((u64)ry >= sh) ry = (i64)sh - 1;
|
||||
row_bg[y0] = blend_color(BG_TOP, BG_BOTTOM, (u32)(((u64)ry * 255ULL) / (sh - 1)));
|
||||
u32 *ln=&sprite[y0*SPR]; for(i64 x0=0;x0<SPR;x0++) ln[x0]=row_bg[y0];
|
||||
}
|
||||
{
|
||||
i64 ro=r+thk, ri=r-thk;
|
||||
for (i64 dq=0; dq<4; dq++) {
|
||||
i64 sa=base+dq*90, sw2=82; u32 clr=arc_colors[dq];
|
||||
for(i64 dy=-ro-1;dy<=ro+1;dy++){i64 yy=scy+dy; if(yy<0||yy>=SPR)continue;
|
||||
u32 sbg=row_bg[yy];
|
||||
for(i64 dx=-ro-1;dx<=ro+1;dx++){i64 xx=scx+dx; if(xx<0||xx>=SPR)continue;
|
||||
i64 d2=dx*dx+dy*dy; if(d2<ri*ri-2||d2>(ro+1)*(ro+1)+2)continue;
|
||||
i64 ang; if(dx==0)ang=dy<0?90:270;
|
||||
else{i64 ax=dx<0?-dx:dx,ay=dy<0?-dy:dy,a0=ax>ay?ay*45/ax:90-ax*45/(ay?ay:1);
|
||||
if(dx>=0&&dy<=0)ang=a0;else if(dx<0&&dy<=0)ang=180-a0;
|
||||
else if(dx<0&&dy>0)ang=180+a0;else ang=360-a0;}
|
||||
i64 a=ang-sa; if(a<0)a+=360; if((u64)a>(u64)sw2)continue;
|
||||
u32 fade; if((u64)a<6)fade=(u32)(a*255/6);else if((u64)a>(u64)(sw2-6))fade=(u32)((sw2-a)*255/6);else fade=255;
|
||||
u64 vv=(u64)d2; u64 xr=vv,yr=(xr+1)>>1; while(yr<xr){xr=yr;yr=(yr+vv/yr)>>1;} i64 dist=(i64)xr;
|
||||
u32 eff=((sbg&0xFF)*(256-fade)+(clr&0xFF)*fade)>>8;
|
||||
u32 ge=(((sbg>>8)&0xFF)*(256-fade)+((clr>>8)&0xFF)*fade)>>8;
|
||||
u32 be=(((sbg>>16)&0xFF)*(256-fade)+((clr>>16)&0xFF)*fade)>>8;
|
||||
eff=0xFF000000|(be<<16)|(ge<<8)|eff;
|
||||
if(dist>=ri&&dist<=ro)sprite[(u64)yy*SPR+(u64)xx]=eff;
|
||||
}}
|
||||
}
|
||||
i64 ri2=r-8;
|
||||
for(i64 dy=-ri2-2;dy<=ri2+2;dy++){i64 yy2=scy+dy; if(yy2<0||yy2>=SPR)continue;
|
||||
u32 sbg2=row_bg[yy2];
|
||||
for(i64 dx=-ri2-2;dx<=ri2+2;dx++){i64 xx2=scx+dx; if(xx2<0||xx2>=SPR)continue;
|
||||
i64 d2=dx*dx+dy*dy;
|
||||
if(d2<=ri2*ri2){
|
||||
u32 ic=((sbg2&0xFF)*176+0xD0*80)>>8;
|
||||
u32 ig=(((sbg2>>8)&0xFF)*176+0xF0*80)>>8;
|
||||
u32 ib=(((sbg2>>16)&0xFF)*176+0xFF*80)>>8;
|
||||
sprite[(u64)yy2*SPR+(u64)xx2]=0xFF000000|(ib<<16)|(ig<<8)|ic;
|
||||
}
|
||||
}}
|
||||
}
|
||||
g_fb_w=sw; g_fb_h=sh; g_fb_p=spv;
|
||||
dsk_fill_gradient_rect(sfb, bx, by, SPR, SPR);
|
||||
for(i64 sr=0;sr<SPR;sr++){i64 sy=by+sr; if(sy<0||(u64)sy>=g_fb_h)continue;
|
||||
u32 *dst=(u32*)((u8*)sfb+(u64)sy*g_fb_p)+bx; u32 *src=&sprite[sr*SPR];
|
||||
for(i64 sc=0;sc<SPR;sc++){i64 sx=bx+sc; if(sx<0||(u64)sx>=g_fb_w)continue; dst[sc]=src[sc];}}
|
||||
for(volatile u32 d=0;d<72000;d++)__asm__("pause");
|
||||
base-=2; if(base<0)base+=360; frame++;
|
||||
tsc_calibrate_dsk();
|
||||
|
||||
if(frame>=100&&!checked){checked=1; /* was 540, reduced for test */
|
||||
logl("[DSK] checking firstInit...");
|
||||
if(g_block_read){logl("[DSK] have block read, calling dsk_check_firstinit");
|
||||
int is_first=0;
|
||||
if(dsk_check_firstinit(&is_first)==0){
|
||||
if(is_first){
|
||||
logl("[DSK] first init detected; running system initializers");
|
||||
/* Gradient background + spinning loader (~1.1s, or 800ms without block dev). */
|
||||
i64 cx = (i64)g_fb_w / 2;
|
||||
i64 cy = (i64)g_fb_h / 2;
|
||||
dsk_fill_gradient_rect(sfb, 0, 0, (i64)g_fb_w, (i64)g_fb_h);
|
||||
spinner_save_bg(sfb, cx, cy);
|
||||
|
||||
/* DSK owns system component initialization. FirstInit is only user setup. */
|
||||
char mn[12]; /* MOUSE ELF */
|
||||
mn[0]='M';mn[1]='O';mn[2]='U';mn[3]='S';mn[4]='E';mn[5]=' ';mn[6]=' ';mn[7]=' ';mn[8]='E';mn[9]='L';mn[10]='F';
|
||||
u8 *md=0; u32 ms=0; void *me=0;
|
||||
if(fat32_read_root_file(mn,&md,&ms)==0){
|
||||
if(dsk_load_elf(md,ms,&me)==0){
|
||||
logl("[DSK] jumping to mouseInit");
|
||||
void(*mentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))me;
|
||||
mentry(ctx);
|
||||
logl("[DSK] mouseInit returned");
|
||||
}
|
||||
}
|
||||
u32 base = 0;
|
||||
u32 head_color = 0xFFE8F2FC; /* nearly-white light blue */
|
||||
u64 spin_start = rdtsc_dsk();
|
||||
u64 spin_budget = g_tsc_per_ms * (g_block_read ? 1100 : 800);
|
||||
while (rdtsc_dsk() - spin_start < spin_budget) {
|
||||
spinner_restore_bg(sfb, cx, cy);
|
||||
spinner_draw(sfb, cx, cy, base, head_color);
|
||||
base = (base + 6) & 255; /* clockwise advance */
|
||||
u64 fs = rdtsc_dsk();
|
||||
while (rdtsc_dsk() - fs < g_tsc_per_ms * 33) __asm__("pause"); /* ~30fps */
|
||||
}
|
||||
spinner_restore_bg(sfb, cx, cy);
|
||||
|
||||
char nn[12]; /* NETMAN ELF */
|
||||
nn[0]='N';nn[1]='E';nn[2]='T';nn[3]='M';nn[4]='A';nn[5]='N';nn[6]=' ';nn[7]=' ';nn[8]='E';nn[9]='L';nn[10]='F';
|
||||
u8 *nd=0; u32 ns=0; void *ne=0;
|
||||
if(fat32_read_root_file(nn,&nd,&ns)==0){
|
||||
if(dsk_load_elf(nd,ns,&ne)==0){
|
||||
logl("[DSK] jumping to netman");
|
||||
void(*nentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))ne;
|
||||
nentry(ctx);
|
||||
logl("[DSK] netman returned");
|
||||
}
|
||||
}
|
||||
if (!g_block_read) {
|
||||
logl("[DSK] no block device, halting");
|
||||
for(;;)__asm__("hlt");
|
||||
}
|
||||
|
||||
logl("[DSK] loading FirstInit.elf");
|
||||
char en[12]; /* FIRSTINIT */
|
||||
en[0]='F';en[1]='I';en[2]='R';en[3]='S';en[4]='T';
|
||||
en[5]='I';en[6]='N';en[7]='I';en[8]='T';en[9]=' ';en[10]=0;
|
||||
u8 *fd=0; u32 fs=0;
|
||||
if(fat32_read_root_file(en,&fd,&fs)==0){
|
||||
if(dsk_load_elf(fd,fs,&fe_entry)==0) logl("[DSK] FirstInit.elf loaded");
|
||||
}
|
||||
logl("[DSK] checking firstInit...");
|
||||
int is_first = 0, dev_mode = 0;
|
||||
if (dsk_check_firstinit(&is_first, &dev_mode) != 0) {
|
||||
logl("[DSK] firstInit check failed, halting");
|
||||
for(;;)__asm__("hlt");
|
||||
}
|
||||
|
||||
/* 开发者模式:加载 shell.elf 自动测试命令序列(cp/mv/echo/ls/cat/rm) */
|
||||
if (dev_mode) {
|
||||
logl("[DSK] dev mode: loading shell.elf for auto-test");
|
||||
char sn[12]; /* SHELL ELF */
|
||||
sn[0]='S';sn[1]='H';sn[2]='E';sn[3]='L';sn[4]='L';sn[5]=' ';sn[6]=' ';sn[7]=' ';sn[8]='E';sn[9]='L';sn[10]='F';
|
||||
dsk_boot_context *ctx_mut = (dsk_boot_context *)ctx;
|
||||
ctx_mut->reserved[3] = 1; /* dev mode flag for shell */
|
||||
if (dsk_load_and_run(sn, ctx) == 0) logl("[DSK] shell auto-test returned");
|
||||
else logl("[DSK] shell.elf not found, skipping dev test");
|
||||
ctx_mut->reserved[3] = 0;
|
||||
}
|
||||
|
||||
if (!is_first) {
|
||||
logl("[DSK] firstInit=1, attempting login before desktop");
|
||||
|
||||
/* Load login.elf first (into g_fdata, then dsk_load_elf copies to ibuf) */
|
||||
char ln[12]; /* LOGIN ELF */
|
||||
ln[0]='L';ln[1]='O';ln[2]='G';ln[3]='I';ln[4]='N';ln[5]=' ';ln[6]=' ';ln[7]=' ';ln[8]='E';ln[9]='L';ln[10]='F';
|
||||
u8 *ld=0; u32 ls=0; void *le=0;
|
||||
int login_ok = 0;
|
||||
if (fat32_read_root_file(ln, &ld, &ls) == 0) {
|
||||
if (dsk_load_elf(ld, ls, &le) == 0) {
|
||||
/* Now read USER.CONF into g_fdata (login.elf already copied to ibuf) */
|
||||
char cn[12]; /* USER CON */
|
||||
cn[0]='U';cn[1]='S';cn[2]='E';cn[3]='R';cn[4]=' ';cn[5]=' ';cn[6]=' ';cn[7]=' ';cn[8]='C';cn[9]='O';cn[10]='N';
|
||||
u8 *conf_data=0; u32 conf_size=0;
|
||||
if (fat32_read_root_file(cn, &conf_data, &conf_size) == 0) {
|
||||
logl("[DSK] USER.CONF found, passing to login");
|
||||
dsk_boot_context *ctx_mut = (dsk_boot_context *)ctx;
|
||||
ctx_mut->reserved[0] = (u64)conf_data;
|
||||
ctx_mut->reserved[1] = (u64)conf_size;
|
||||
ctx_mut->reserved[2] = 0; /* login success flag */
|
||||
|
||||
logl("[DSK] jumping to login");
|
||||
void(*lentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))le;
|
||||
lentry(ctx);
|
||||
logl("[DSK] login returned");
|
||||
|
||||
if (ctx_mut->reserved[2] == 1) {
|
||||
logl("[DSK] login success");
|
||||
login_ok = 1;
|
||||
} else {
|
||||
logl("[DSK] firstInit=1, skipping user setup, loading shell directly");
|
||||
logl("[DSK] login skipped or failed");
|
||||
}
|
||||
} else {
|
||||
logl("[DSK] USER.CONF not found, skipping login");
|
||||
}
|
||||
} else {
|
||||
logl("[DSK] login.elf load failed, skipping login");
|
||||
}
|
||||
} else {
|
||||
logl("[DSK] login.elf not found, skipping login");
|
||||
}
|
||||
if(fe_entry&&frame>150){logl("[DSK] jumping to FirstInit"); /* was 600 */
|
||||
void(*entry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))fe_entry;
|
||||
entry(ctx);
|
||||
logl("[DSK] FirstInit returned, loading desktop");
|
||||
/* FirstInit 返回后加载 desktop */
|
||||
char dn[12]; /* DESKTOP ELF */
|
||||
dn[0]='D';dn[1]='E';dn[2]='S';dn[3]='K';dn[4]='T';dn[5]='O';dn[6]='P';dn[7]=' ';dn[8]='E';dn[9]='L';dn[10]='F';
|
||||
u8 *dd=0; u32 ds=0; void *de=0;
|
||||
if(fat32_read_root_file(dn,&dd,&ds)==0){
|
||||
if(dsk_load_elf(dd,ds,&de)==0){
|
||||
logl("[DSK] jumping to desktop");
|
||||
void(*dentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))de;
|
||||
dentry(ctx);
|
||||
}
|
||||
}
|
||||
for(;;)__asm__("hlt");
|
||||
(void)login_ok;
|
||||
|
||||
logl("[DSK] loading desktop");
|
||||
dsk_run_desktop(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* First boot: run system initializers, then FirstInit, then desktop */
|
||||
logl("[DSK] first init detected; running system initializers");
|
||||
|
||||
/* mouseInit.elf — safe PS/2 mouse init */
|
||||
{ char mn[12]; /* MOUSE ELF */
|
||||
mn[0]='M';mn[1]='O';mn[2]='U';mn[3]='S';mn[4]='E';mn[5]=' ';mn[6]=' ';mn[7]=' ';mn[8]='E';mn[9]='L';mn[10]='F';
|
||||
logl("[DSK] loading mouseInit");
|
||||
if (dsk_load_and_run(mn, ctx) == 0) logl("[DSK] mouseInit returned");
|
||||
else logl("[DSK] mouseInit not found");
|
||||
}
|
||||
|
||||
/* netman.elf — network configuration */
|
||||
{ char nn[12]; /* NETMAN ELF */
|
||||
nn[0]='N';nn[1]='E';nn[2]='T';nn[3]='M';nn[4]='A';nn[5]='N';nn[6]=' ';nn[7]=' ';nn[8]='E';nn[9]='L';nn[10]='F';
|
||||
logl("[DSK] loading netman");
|
||||
if (dsk_load_and_run(nn, ctx) == 0) logl("[DSK] netman returned");
|
||||
else logl("[DSK] netman not found");
|
||||
}
|
||||
|
||||
/* FirstInit.elf — user setup wizard; returns to DSK when done */
|
||||
{ char en[12]; /* FIRSTINIT */
|
||||
en[0]='F';en[1]='I';en[2]='R';en[3]='S';en[4]='T';
|
||||
en[5]='I';en[6]='N';en[7]='I';en[8]='T';en[9]=' ';en[10]=0;
|
||||
logl("[DSK] loading FirstInit");
|
||||
if (dsk_load_and_run(en, ctx) != 0) {
|
||||
logl("[DSK] FirstInit not found, loading desktop directly");
|
||||
dsk_run_desktop(ctx);
|
||||
return;
|
||||
}
|
||||
/* 非首次启动:直接加载 desktop */
|
||||
if(checked&&!fe_entry&&frame>150){
|
||||
logl("[DSK] loading desktop directly (non-first boot)");
|
||||
char dn[12]; /* DESKTOP ELF */
|
||||
dn[0]='D';dn[1]='E';dn[2]='S';dn[3]='K';dn[4]='T';dn[5]='O';dn[6]='P';dn[7]=' ';dn[8]='E';dn[9]='L';dn[10]='F';
|
||||
u8 *dd=0; u32 ds=0; void *de=0;
|
||||
if(fat32_read_root_file(dn,&dd,&ds)==0){
|
||||
if(dsk_load_elf(dd,ds,&de)==0){
|
||||
logl("[DSK] jumping to desktop");
|
||||
void(*dentry)(const dsk_boot_context*)=(void(*)(const dsk_boot_context*))de;
|
||||
dentry(ctx);
|
||||
}
|
||||
}
|
||||
for(;;)__asm__("hlt");
|
||||
}
|
||||
if(!g_block_read&&frame>800){logl("[DSK] no block device, skipping firstInit");break;}
|
||||
if(checked&&!fe_entry&&frame>800){logl("[DSK] firstInit not found, continuing normal boot");break;}
|
||||
logl("[DSK] FirstInit returned, persisting user.conf");
|
||||
dsk_persist_userconf(ctx);
|
||||
logl("[DSK] loading desktop");
|
||||
dsk_run_desktop(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noreturn, visibility("default")))
|
||||
void dsk_entry(const dsk_boot_context *ctx) {
|
||||
__asm__ volatile("cli"); /* disable IRQs — ps2kbd/IRQ1 & mouse/IRQ12 handlers crash during spinner */
|
||||
__asm__ volatile("cli"); /* disable IRQs — ps2kbd/IRQ1 & mouse/IRQ12 handlers crash during boot */
|
||||
logl("[DSK] boot");
|
||||
if(!ctx||ctx->magic!=DSK_BOOT_MAGIC){logl("[DSK] bad context");for(;;)__asm__("hlt");}
|
||||
logl("[DSK] context ok");
|
||||
g_fb_addr=ctx->framebuffer_address; g_fb_w=ctx->framebuffer_width;
|
||||
g_fb_h=ctx->framebuffer_height; g_fb_p=ctx->framebuffer_pitch;
|
||||
u32 bg=BG_MID, arcs[4]={0xFF4488CC,0xFF2266AA,0xFF66AAEE,0xFF88CCFF};
|
||||
i64 cx=(i64)g_fb_w/2,cy=(i64)g_fb_h/2,r=48,thk=4;
|
||||
dsk_spinner_and_check((u32*)(u64)g_fb_addr,cx,cy,r,thk,arcs,bg,ctx);
|
||||
dsk_spinner_and_check(ctx);
|
||||
logl("[DSK] SELFTEST PASS");
|
||||
for(;;)__asm__("hlt");
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
+559
-143
@@ -16,6 +16,42 @@ typedef long long i64;
|
||||
static __inline__ void outb(u16 port, u8 value) { __asm__ volatile("outb %0,%1"::"a"(value),"Nd"(port)); }
|
||||
static __inline__ u8 inb(u16 port) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(port)); return v; }
|
||||
|
||||
/* ---- TSC-based timing (实机要求: 用 CPU 频率计算, 不用循环) ---- */
|
||||
static u64 g_tsc_per_ms = 0;
|
||||
|
||||
static __inline__ u64 rdtsc_fi(void) {
|
||||
u32 lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
/* 用 PIT (8254, 1.193182 MHz) 校准 TSC 频率 */
|
||||
static void tsc_calibrate_fi(void) {
|
||||
outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
|
||||
outb(0x40, 0x7c); /* 11932 low = ~10ms */
|
||||
outb(0x40, 0x2e); /* 11932 high */
|
||||
u64 tsc_start = rdtsc_fi();
|
||||
u16 prev = 0; u64 loops = 0;
|
||||
for (;;) {
|
||||
outb(0x43, 0x00);
|
||||
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
|
||||
if (cur > prev && loops > 10) break;
|
||||
prev = cur; loops++;
|
||||
}
|
||||
u64 tsc_end = rdtsc_fi();
|
||||
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
|
||||
}
|
||||
|
||||
static void delay_ms_fi(u32 ms) {
|
||||
if (!g_tsc_per_ms) {
|
||||
for (volatile u32 i = 0; i < 100000 * ms; i++) __asm__ volatile("pause");
|
||||
return;
|
||||
}
|
||||
u64 target = g_tsc_per_ms * ms;
|
||||
u64 start = rdtsc_fi();
|
||||
while (rdtsc_fi() - start < target) __asm__ volatile("pause");
|
||||
}
|
||||
|
||||
static void sputc(char c) {
|
||||
for (unsigned int i=0; i<100000; i++) { if (inb(COM1+5)&0x20) break; }
|
||||
outb(COM1, (unsigned char)c);
|
||||
@@ -23,16 +59,20 @@ static void sputc(char c) {
|
||||
static void swrite(const char *s) { while(*s) { if(*s=='\n')sputc('\r'); sputc(*s++); } }
|
||||
static void logl(const char *s) { swrite(s); swrite("\n"); }
|
||||
|
||||
/* ---- PS/2 controller / mouse helpers (timeout-protected) ---- */
|
||||
/* ---- PS/2 controller / mouse helpers (timeout-protected, TSC-based) ---- */
|
||||
static int ps2_wait_write(void) {
|
||||
for (volatile u32 i = 0; i < 100000; i++) {
|
||||
u64 deadline = rdtsc_fi() + g_tsc_per_ms * 100; /* 100ms 超时 */
|
||||
while (rdtsc_fi() < deadline) {
|
||||
if (!(inb(0x64) & 0x02)) return 0; /* input buffer empty */
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static int ps2_wait_read(void) {
|
||||
for (volatile u32 i = 0; i < 100000; i++) {
|
||||
u64 deadline = rdtsc_fi() + g_tsc_per_ms * 100; /* 100ms 超时 */
|
||||
while (rdtsc_fi() < deadline) {
|
||||
if (inb(0x64) & 0x01) return 0; /* output buffer full */
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -81,12 +121,12 @@ static void mouse_init(void) {
|
||||
logl("[mouse] init done");
|
||||
}
|
||||
|
||||
#define BG_TOP 0xFFC8E0F0u
|
||||
#define BG_BOTTOM 0xFF49306Fu
|
||||
#define BG_MID 0xFF8888B0u
|
||||
#define CARD_BG 0xFFEAF5FBu
|
||||
#define INPUT_BG 0xFFF0F5FAu
|
||||
#define TEXT_FG 0xFF5F7FA6u
|
||||
#define BG_TOP 0xFF2D2D30u
|
||||
#define BG_BOTTOM 0xFF1A1A1Eu
|
||||
#define BG_MID 0xFF3C3C40u
|
||||
#define CARD_BG 0xFF353539u
|
||||
#define INPUT_BG 0xFF2A2A2Eu
|
||||
#define TEXT_FG 0xFFE0E0E0u
|
||||
#define WELCOME_FG 0xFFE8F2FCu
|
||||
|
||||
static u64 fb_a, fb_w, fb_h, fb_p;
|
||||
@@ -127,6 +167,38 @@ static void fb_text(u32 *fb, const char *s, i64 x, i64 y, u32 fg, u32 bg) {
|
||||
for (i64 i=0; s[i]; i++) fb_char(fb, (u32)(u8)s[i], x+i*ASCII_STEP, y, fg, bg);
|
||||
}
|
||||
|
||||
/* width of an ASCII string in pixels (used to center English subtitles) */
|
||||
static i64 fb_text_width(const char *s) {
|
||||
i64 n = 0;
|
||||
while (s[n]) n++;
|
||||
return n * ASCII_STEP;
|
||||
}
|
||||
|
||||
/* Alpha-blended ASCII text — same as fb_text but multiplied by a global alpha,
|
||||
* used to fade English subtitles in/out alongside the Chinese bitmaps. */
|
||||
static void fb_text_alpha(u32 *fb, const char *s, i64 x, i64 y, u32 fg, u32 bg, u32 global_alpha) {
|
||||
for (i64 i=0; s[i]; i++) {
|
||||
u32 ch = (u32)(u8)s[i];
|
||||
if (ch < ' ' || ch > '~') ch = ' ';
|
||||
u32 idx = ch - ' ';
|
||||
const u8 *g = g_ascii[idx];
|
||||
for (i64 r=0; r<ASCII_H; r++) {
|
||||
i64 yy = y + r;
|
||||
if (yy < 0 || (u64)yy >= fb_h) continue;
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)yy * fb_p);
|
||||
for (i64 c=0; c<ASCII_W; c++) {
|
||||
u32 a = g[r * ASCII_W + c];
|
||||
if (a == 0) continue;
|
||||
u32 eff_a = ((u32)a * global_alpha) >> 8;
|
||||
if (eff_a == 0) continue;
|
||||
i64 xx = x + i*ASCII_STEP + c;
|
||||
if (xx < 0 || (u64)xx >= fb_w) continue;
|
||||
line[(u64)xx] = (eff_a == 255) ? fg : blend(bg, fg, eff_a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* draw pre-rendered grayscale bitmap – writes only, no framebuffer read */
|
||||
static void fb_bitmap_alpha(u32 *fb, const u8 *data, i64 w, i64 h, i64 x, i64 y, u32 fg, u32 bg, u32 global_alpha) {
|
||||
for (i64 r=0; r<h; r++) {
|
||||
@@ -136,7 +208,9 @@ static void fb_bitmap_alpha(u32 *fb, const u8 *data, i64 w, i64 h, i64 x, i64 y,
|
||||
for (i64 c=0; c<w; c++) {
|
||||
i64 xx = x + c;
|
||||
if (xx < 0 || (u64)xx >= fb_w) continue;
|
||||
u32 a = ((u32)data[r*(u64)w + (u64)c] * global_alpha) >> 8;
|
||||
u8 val = data[r*(u64)w + (u64)c];
|
||||
if (val == 0) continue; /* skip transparent – let background show through */
|
||||
u32 a = ((u32)val * global_alpha) >> 8;
|
||||
line[(u64)xx] = blend(bg, fg, a);
|
||||
}
|
||||
}
|
||||
@@ -228,25 +302,21 @@ static void stroke_rounded_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h, i64 radius,
|
||||
}
|
||||
|
||||
static void delay_frame(void) {
|
||||
for (volatile u32 d=0; d<300000; d++) __asm__("pause");
|
||||
delay_ms_fi(33); /* 实机: 基于 TSC 的 33ms 帧间隔 (~30fps) */
|
||||
}
|
||||
|
||||
#include "text_bitmaps.c"
|
||||
|
||||
static void fade_ring(u32 *fb, i64 cx, i64 cy, u32 bg) {
|
||||
/* Smoothly erase a square sprite area with the same vertical gradient as DSK. */
|
||||
/* Erase the spinner sprite area with gradient background in one frame. */
|
||||
(void)bg;
|
||||
i64 r = 72;
|
||||
for (int step=0; step<12; step++) {
|
||||
(void)step;
|
||||
fill_gradient_rect(fb, cx-r, cy-r, r*2+1, r*2+1);
|
||||
delay_frame();
|
||||
}
|
||||
fill_gradient_rect(fb, cx-r, cy-r, r*2+1, r*2+1);
|
||||
}
|
||||
|
||||
static void draw_card(u32 *fb, i64 x, i64 y, i64 w, i64 h, u32 card, u32 bg_color) {
|
||||
(void)bg_color;
|
||||
fill_rounded_rect(fb, x, y, w, h, 12, card);
|
||||
fill_rounded_rect(fb, x, y, w, h, 4, card);
|
||||
}
|
||||
|
||||
/* Draw gradient background + card in a single pass — per-row blend eliminates flicker */
|
||||
@@ -266,9 +336,9 @@ static void draw_card_fade(u32 *fb, i64 x, i64 y, i64 w, i64 h, i64 radius, u32
|
||||
}
|
||||
|
||||
static void draw_rounded_input(u32 *fb, i64 x, i64 y, i64 w, i64 h, const char *value, int mask, u32 fg, u32 card_bg, int active) {
|
||||
u32 fill = active ? 0xFFFFFFFF : INPUT_BG;
|
||||
fill_rounded_rect(fb, x, y, w, h, 8, fill);
|
||||
stroke_rounded_rect(fb, x, y, w, h, 8, 1, active ? 0xFFB6C9DD : card_bg);
|
||||
u32 fill = active ? 0xFF45454Au : INPUT_BG;
|
||||
fill_rounded_rect(fb, x, y, w, h, 2, fill);
|
||||
stroke_rounded_rect(fb, x, y, w, h, 2, 1, active ? 0xFF6C6C72 : 0xFF404044);
|
||||
char out[64]; int i=0;
|
||||
while(value[i] && i<60) { out[i] = mask ? '*' : value[i]; i++; }
|
||||
out[i]=0;
|
||||
@@ -387,17 +457,35 @@ static void cursor_draw(u32 *fb, i64 mx, i64 my) {
|
||||
|
||||
static void redraw_setup_card(u32 *fb, i64 card_x, i64 card_y, char *pc, char *user, char *pass, int active, u32 bg, u32 fg, i64 mx, i64 my) {
|
||||
u32 card = CARD_BG;
|
||||
u32 sub_fg = 0xFF9098A0; /* dimmer English subtitle color on card */
|
||||
cursor_erase(fb);
|
||||
fill_gradient_rect(fb, card_x - 24, card_y - 24, 948, 648);
|
||||
draw_card(fb, card_x, card_y, 900, 600, card, bg);
|
||||
fb_bitmap_alpha(fb, g_txt_title, g_txt_title_w, g_txt_title_h, card_x+40, card_y+40, fg, card, 255);
|
||||
fb_text(fb, "Account Setup", card_x+40, card_y+40+g_txt_title_h+2, sub_fg, card);
|
||||
fb_bitmap_alpha(fb, g_txt_computer, g_txt_computer_w, g_txt_computer_h, card_x+40, card_y+130, fg, card, 255);
|
||||
fb_text(fb, "Computer Name", card_x+40, card_y+130+g_txt_computer_h+2, sub_fg, card);
|
||||
draw_rounded_input(fb, card_x+40, card_y+180, 820, 44, pc, 0, fg, card, active==0);
|
||||
fb_bitmap_alpha(fb, g_txt_username, g_txt_username_w, g_txt_username_h, card_x+40, card_y+280, fg, card, 255);
|
||||
fb_text(fb, "Username", card_x+40, card_y+280+g_txt_username_h+2, sub_fg, card);
|
||||
draw_rounded_input(fb, card_x+40, card_y+330, 820, 44, user, 0, fg, card, active==1);
|
||||
fb_bitmap_alpha(fb, g_txt_password, g_txt_password_w, g_txt_password_h, card_x+40, card_y+430, fg, card, 255);
|
||||
fb_text(fb, "Password", card_x+40, card_y+430+g_txt_password_h+2, sub_fg, card);
|
||||
draw_rounded_input(fb, card_x+40, card_y+480, 820, 44, pass, 1, fg, card, active==2);
|
||||
fb_bitmap_alpha(fb, g_txt_hint, g_txt_hint_w, g_txt_hint_h, card_x+40, card_y+555, 0xFF7F97AC, card, 255);
|
||||
fb_text(fb, "Press Enter to confirm each field", card_x+40, card_y+555+g_txt_hint_h+2, 0xFF6F7F8C, card);
|
||||
cursor_draw(fb, mx, my);
|
||||
}
|
||||
|
||||
/* 仅重绘当前活动输入框,避免每次按键重绘整个卡片导致闪烁 */
|
||||
static void redraw_input_only(u32 *fb, i64 card_x, i64 card_y, int field, char *pc, char *user, char *pass, i64 mx, i64 my, u32 fg) {
|
||||
u32 card = CARD_BG;
|
||||
char *buf = field==0 ? pc : (field==1 ? user : pass);
|
||||
int mask = (field == 2) ? 1 : 0;
|
||||
i64 fy = card_y + 180 + (i64)field * 150;
|
||||
cursor_erase(fb);
|
||||
fill_rect(fb, card_x + 40, fy, 820, 44, card);
|
||||
draw_rounded_input(fb, card_x+40, fy, 820, 44, buf, mask, fg, card, 1);
|
||||
cursor_draw(fb, mx, my);
|
||||
}
|
||||
|
||||
@@ -474,7 +562,7 @@ static int read_field(u32 *fb, i64 card_x, i64 card_y, int field, char *pc, char
|
||||
buf[len++] = c;
|
||||
buf[len] = 0;
|
||||
}
|
||||
redraw_setup_card(fb, card_x, card_y, pc, user, pass, field, bg, fg, *mx, *my);
|
||||
redraw_input_only(fb, card_x, card_y, field, pc, user, pass, *mx, *my, fg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,15 +574,64 @@ typedef struct {
|
||||
int theme;
|
||||
} setup_prefs;
|
||||
|
||||
static const char *pref_value(int row, int val) {
|
||||
if (row == 0) return val ? "English" : "Simplified Chinese";
|
||||
if (row == 1) return val ? "Global" : "China Mainland";
|
||||
if (row == 2) return val ? "UTC" : "Asia/Shanghai";
|
||||
if (row == 3) return val ? "CN-QWERTY" : "US-QWERTY";
|
||||
if (row == 4) return val ? "Dark" : "Light";
|
||||
/* 语言选项: 索引 0-11 */
|
||||
static const char *lang_names[] = {
|
||||
"Simplified Chinese", "English (US)", "English (UK)", "Japanese",
|
||||
"Korean", "French", "German", "Spanish",
|
||||
"Portuguese", "Russian", "Arabic", "Hindi"
|
||||
};
|
||||
#define LANG_COUNT 12
|
||||
|
||||
/* 键盘布局选项: 索引 0-8 */
|
||||
static const char *kb_names[] = {
|
||||
"US-QWERTY", "CN-QWERTY", "UK-QWERTY", "JP-JIS",
|
||||
"KR-104", "FR-AZERTY", "DE-QWERTZ", "ES-QWERTY",
|
||||
"RU-JCUKEN"
|
||||
};
|
||||
#define KB_COUNT 9
|
||||
|
||||
/* 区域选项 */
|
||||
static const char *region_names[] = {
|
||||
"China Mainland", "Global", "United States", "United Kingdom",
|
||||
"Japan", "Korea", "France", "Germany",
|
||||
"Spain", "Russia"
|
||||
};
|
||||
#define REGION_COUNT 10
|
||||
|
||||
/* 时区选项 */
|
||||
static const char *tz_names[] = {
|
||||
"Asia/Shanghai", "UTC", "America/New_York", "America/Los_Angeles",
|
||||
"Europe/London", "Asia/Tokyo", "Asia/Seoul", "Europe/Paris",
|
||||
"Europe/Berlin", "Europe/Moscow"
|
||||
};
|
||||
#define TZ_COUNT 10
|
||||
|
||||
/* 主题选项 */
|
||||
static const char *theme_names[] = { "Light", "Dark", "Auto" };
|
||||
#define THEME_COUNT 3
|
||||
|
||||
static int pref_option_count(int row) {
|
||||
if (row == 0) return LANG_COUNT;
|
||||
if (row == 1) return REGION_COUNT;
|
||||
if (row == 2) return TZ_COUNT;
|
||||
if (row == 3) return KB_COUNT;
|
||||
if (row == 4) return THEME_COUNT;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static const char *pref_option_name(int row, int opt) {
|
||||
if (row == 0) return lang_names[opt];
|
||||
if (row == 1) return region_names[opt];
|
||||
if (row == 2) return tz_names[opt];
|
||||
if (row == 3) return kb_names[opt];
|
||||
if (row == 4) return theme_names[opt];
|
||||
return "";
|
||||
}
|
||||
|
||||
static const char *pref_value(int row, int val) {
|
||||
return pref_option_name(row, val);
|
||||
}
|
||||
|
||||
static int pref_get(const setup_prefs *p, int row) {
|
||||
if (row == 0) return p->language;
|
||||
if (row == 1) return p->region;
|
||||
@@ -504,22 +641,41 @@ static int pref_get(const setup_prefs *p, int row) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pref_set(setup_prefs *p, int row, int val) {
|
||||
if (row == 0) p->language = val;
|
||||
else if (row == 1) p->region = val;
|
||||
else if (row == 2) p->timezone = val;
|
||||
else if (row == 3) p->keyboard = val;
|
||||
else if (row == 4) p->theme = val;
|
||||
}
|
||||
|
||||
static void pref_toggle(setup_prefs *p, int row) {
|
||||
if (row == 0) p->language ^= 1;
|
||||
else if (row == 1) p->region ^= 1;
|
||||
else if (row == 2) p->timezone ^= 1;
|
||||
else if (row == 3) p->keyboard ^= 1;
|
||||
else if (row == 4) p->theme ^= 1;
|
||||
int count = pref_option_count(row);
|
||||
int cur = pref_get(p, row);
|
||||
pref_set(p, row, (cur + 1) % count);
|
||||
}
|
||||
|
||||
static void draw_option_row(u32 *fb, i64 x, i64 y, i64 w, i64 h,
|
||||
const u8 *label, i64 lw, i64 lh,
|
||||
const char *value, int active, u32 fg, u32 card) {
|
||||
u32 fill = active ? 0xFFFFFFFF : INPUT_BG;
|
||||
const char *value, int active, u32 fg, u32 card,
|
||||
const char *en) {
|
||||
u32 fill = active ? 0xFF45454Au : INPUT_BG;
|
||||
fb_bitmap_alpha(fb, label, lw, lh, x, y + 4, fg, card, 255);
|
||||
fill_rounded_rect(fb, x + 220, y, w - 220, h, 8, fill);
|
||||
stroke_rounded_rect(fb, x + 220, y, w - 220, h, 8, 1, active ? 0xFFB6C9DD : card);
|
||||
if (en) fb_text(fb, en, x, y + 4 + lh + 1, 0xFF9098A0, card);
|
||||
fill_rounded_rect(fb, x + 220, y, w - 220, h, 2, fill);
|
||||
stroke_rounded_rect(fb, x + 220, y, w - 220, h, 2, 1, active ? 0xFF6C6C72 : 0xFF404044);
|
||||
fb_text(fb, value, x + 238, y + (h - ASCII_H) / 2, fg, fill);
|
||||
/* dropdown arrow */
|
||||
{
|
||||
i64 ax = x + w - 22;
|
||||
i64 ay = y + (h - 6) / 2;
|
||||
fill_rect(fb, ax, ay, 11, 1, fg);
|
||||
fill_rect(fb, ax + 1, ay + 1, 9, 1, fg);
|
||||
fill_rect(fb, ax + 2, ay + 2, 7, 1, fg);
|
||||
fill_rect(fb, ax + 3, ay + 3, 5, 1, fg);
|
||||
fill_rect(fb, ax + 4, ay + 4, 3, 1, fg);
|
||||
fill_rect(fb, ax + 5, ay + 5, 1, 1, fg);
|
||||
}
|
||||
}
|
||||
|
||||
static void redraw_prefs_card(u32 *fb, i64 card_x, i64 card_y, setup_prefs *prefs, int active, i64 mx, i64 my, u32 bg, u32 fg) {
|
||||
@@ -528,12 +684,14 @@ static void redraw_prefs_card(u32 *fb, i64 card_x, i64 card_y, setup_prefs *pref
|
||||
fill_gradient_rect(fb, card_x - 24, card_y - 24, 948, 648);
|
||||
draw_card(fb, card_x, card_y, 900, 600, card, bg);
|
||||
fb_bitmap_alpha(fb, g_txt_prefs_title, g_txt_prefs_title_w, g_txt_prefs_title_h, card_x+40, card_y+40, fg, card, 255);
|
||||
draw_option_row(fb, card_x+40, card_y+120, 820, 42, g_txt_prefs_language, g_txt_prefs_language_w, g_txt_prefs_language_h, pref_value(0, pref_get(prefs, 0)), active==0, fg, card);
|
||||
draw_option_row(fb, card_x+40, card_y+200, 820, 42, g_txt_prefs_region, g_txt_prefs_region_w, g_txt_prefs_region_h, pref_value(1, pref_get(prefs, 1)), active==1, fg, card);
|
||||
draw_option_row(fb, card_x+40, card_y+280, 820, 42, g_txt_prefs_timezone, g_txt_prefs_timezone_w, g_txt_prefs_timezone_h, pref_value(2, pref_get(prefs, 2)), active==2, fg, card);
|
||||
draw_option_row(fb, card_x+40, card_y+360, 820, 42, g_txt_prefs_keyboard, g_txt_prefs_keyboard_w, g_txt_prefs_keyboard_h, pref_value(3, pref_get(prefs, 3)), active==3, fg, card);
|
||||
draw_option_row(fb, card_x+40, card_y+440, 820, 42, g_txt_prefs_theme, g_txt_prefs_theme_w, g_txt_prefs_theme_h, pref_value(4, pref_get(prefs, 4)), active==4, fg, card);
|
||||
fb_text(fb, "Preferences", card_x+40, card_y+40+g_txt_prefs_title_h+2, 0xFF9098A0, card);
|
||||
draw_option_row(fb, card_x+40, card_y+120, 820, 42, g_txt_prefs_language, g_txt_prefs_language_w, g_txt_prefs_language_h, pref_value(0, pref_get(prefs, 0)), active==0, fg, card, "Language");
|
||||
draw_option_row(fb, card_x+40, card_y+200, 820, 42, g_txt_prefs_region, g_txt_prefs_region_w, g_txt_prefs_region_h, pref_value(1, pref_get(prefs, 1)), active==1, fg, card, "Region");
|
||||
draw_option_row(fb, card_x+40, card_y+280, 820, 42, g_txt_prefs_timezone, g_txt_prefs_timezone_w, g_txt_prefs_timezone_h, pref_value(2, pref_get(prefs, 2)), active==2, fg, card, "Timezone");
|
||||
draw_option_row(fb, card_x+40, card_y+360, 820, 42, g_txt_prefs_keyboard, g_txt_prefs_keyboard_w, g_txt_prefs_keyboard_h, pref_value(3, pref_get(prefs, 3)), active==3, fg, card, "Keyboard");
|
||||
draw_option_row(fb, card_x+40, card_y+440, 820, 42, g_txt_prefs_theme, g_txt_prefs_theme_w, g_txt_prefs_theme_h, pref_value(4, pref_get(prefs, 4)), active==4, fg, card, "Theme");
|
||||
fb_bitmap_alpha(fb, g_txt_prefs_hint, g_txt_prefs_hint_w, g_txt_prefs_hint_h, card_x+40, card_y+555, 0xFF7F97AC, card, 255);
|
||||
fb_text(fb, "Tab/arrows to navigate, Enter to confirm", card_x+40, card_y+555+g_txt_prefs_hint_h+2, 0xFF6F7F8C, card);
|
||||
cursor_draw(fb, mx, my);
|
||||
}
|
||||
|
||||
@@ -541,21 +699,52 @@ static void redraw_prefs_row(u32 *fb, i64 card_x, i64 card_y, setup_prefs *prefs
|
||||
u32 card = CARD_BG;
|
||||
i64 ry = card_y + 120 + (i64)row * 80;
|
||||
cursor_erase(fb);
|
||||
fill_rect(fb, card_x + 36, ry - 8, 832, 58, card);
|
||||
if (row == 0) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_language, g_txt_prefs_language_w, g_txt_prefs_language_h, pref_value(0, pref_get(prefs, 0)), active==0, fg, card);
|
||||
else if (row == 1) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_region, g_txt_prefs_region_w, g_txt_prefs_region_h, pref_value(1, pref_get(prefs, 1)), active==1, fg, card);
|
||||
else if (row == 2) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_timezone, g_txt_prefs_timezone_w, g_txt_prefs_timezone_h, pref_value(2, pref_get(prefs, 2)), active==2, fg, card);
|
||||
else if (row == 3) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_keyboard, g_txt_prefs_keyboard_w, g_txt_prefs_keyboard_h, pref_value(3, pref_get(prefs, 3)), active==3, fg, card);
|
||||
else if (row == 4) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_theme, g_txt_prefs_theme_w, g_txt_prefs_theme_h, pref_value(4, pref_get(prefs, 4)), active==4, fg, card);
|
||||
fill_rounded_rect(fb, card_x + 36, ry - 8, 832, 58, 2, card);
|
||||
if (row == 0) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_language, g_txt_prefs_language_w, g_txt_prefs_language_h, pref_value(0, pref_get(prefs, 0)), active==0, fg, card, "Language");
|
||||
else if (row == 1) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_region, g_txt_prefs_region_w, g_txt_prefs_region_h, pref_value(1, pref_get(prefs, 1)), active==1, fg, card, "Region");
|
||||
else if (row == 2) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_timezone, g_txt_prefs_timezone_w, g_txt_prefs_timezone_h, pref_value(2, pref_get(prefs, 2)), active==2, fg, card, "Timezone");
|
||||
else if (row == 3) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_keyboard, g_txt_prefs_keyboard_w, g_txt_prefs_keyboard_h, pref_value(3, pref_get(prefs, 3)), active==3, fg, card, "Keyboard");
|
||||
else if (row == 4) draw_option_row(fb, card_x+40, ry, 820, 42, g_txt_prefs_theme, g_txt_prefs_theme_w, g_txt_prefs_theme_h, pref_value(4, pref_get(prefs, 4)), active==4, fg, card, "Theme");
|
||||
cursor_draw(fb, mx, my);
|
||||
}
|
||||
|
||||
/* 绘制下拉菜单:最多显示 6 项,超出时显示滚动指示 */
|
||||
static void draw_dropdown_menu(u32 *fb, i64 card_x, i64 card_y, int row, const setup_prefs *prefs, u32 fg) {
|
||||
i64 dd_x = card_x + 260;
|
||||
i64 dd_y = card_y + 120 + (i64)row * 80 + 42;
|
||||
i64 dd_w = 600;
|
||||
int current = pref_get(prefs, row);
|
||||
int opt_count = pref_option_count(row);
|
||||
int visible = opt_count > 6 ? 6 : opt_count;
|
||||
i64 opt_h = 32;
|
||||
i64 total_h = visible * opt_h + (opt_count > 6 ? 20 : 0);
|
||||
/* 深色背景 */
|
||||
fill_rect(fb, dd_x, dd_y, dd_w, total_h, 0xFF2A2A2E);
|
||||
/* 选项 */
|
||||
for (int opt = 0; opt < visible; opt++) {
|
||||
u32 bg_opt = (opt == current) ? 0xFF45454A : 0xFF2A2A2E;
|
||||
fill_rect(fb, dd_x, dd_y + opt * opt_h, dd_w, opt_h, bg_opt);
|
||||
fb_text(fb, pref_option_name(row, opt), dd_x + 18, dd_y + opt * opt_h + (opt_h - ASCII_H) / 2, fg, bg_opt);
|
||||
}
|
||||
/* 超过 6 项时显示滚动指示 */
|
||||
if (opt_count > 6) {
|
||||
fill_rect(fb, dd_x, dd_y + visible * opt_h, dd_w, 20, 0xFF252528);
|
||||
fb_text(fb, "...more", dd_x + 18, dd_y + visible * opt_h + 1, 0xFF808088, 0xFF252528);
|
||||
}
|
||||
/* 边框 */
|
||||
fill_rect(fb, dd_x, dd_y, dd_w, 1, 0xFF505055);
|
||||
fill_rect(fb, dd_x, dd_y + total_h - 1, dd_w, 1, 0xFF505055);
|
||||
fill_rect(fb, dd_x, dd_y, 1, total_h, 0xFF505055);
|
||||
fill_rect(fb, dd_x + dd_w - 1, dd_y, 1, total_h, 0xFF505055);
|
||||
}
|
||||
|
||||
static void read_prefs_page(u32 *fb, i64 card_x, i64 card_y, setup_prefs *prefs, i64 *mx, i64 *my, u32 bg, u32 fg) {
|
||||
int active = 0;
|
||||
int mcnt = 0;
|
||||
u8 mpkt[3];
|
||||
u8 prev_btns = 0;
|
||||
int e0 = 0;
|
||||
int dropdown_open = -1;
|
||||
redraw_prefs_card(fb, card_x, card_y, prefs, active, *mx, *my, bg, fg);
|
||||
for (;;) {
|
||||
u8 st = inb(0x64);
|
||||
@@ -579,14 +768,40 @@ static void read_prefs_page(u32 *fb, i64 card_x, i64 card_y, setup_prefs *prefs,
|
||||
cursor_draw(fb, *mx, *my);
|
||||
}
|
||||
if ((btns & 1) && !(prev_btns & 1)) {
|
||||
for (int r = 0; r < 5; r++) {
|
||||
i64 ry = card_y + 120 + (i64)r * 80;
|
||||
if (*mx >= card_x + 260 && *mx < card_x + 860 && *my >= ry && *my < ry + 42) {
|
||||
int old = active;
|
||||
active = r;
|
||||
pref_toggle(prefs, active);
|
||||
if (old != active) redraw_prefs_row(fb, card_x, card_y, prefs, old, active, *mx, *my, fg);
|
||||
redraw_prefs_row(fb, card_x, card_y, prefs, active, active, *mx, *my, fg);
|
||||
if (dropdown_open >= 0) {
|
||||
/* 检查点击是否在下拉选项上 */
|
||||
i64 dd_x = card_x + 260;
|
||||
i64 dd_y = card_y + 120 + (i64)dropdown_open * 80 + 42;
|
||||
i64 dd_w = 600;
|
||||
int opt_count = pref_option_count(dropdown_open);
|
||||
int visible = opt_count > 6 ? 6 : opt_count;
|
||||
i64 opt_h = 32;
|
||||
int clicked_opt = -1;
|
||||
for (int opt = 0; opt < visible; opt++) {
|
||||
i64 opt_y = dd_y + opt * opt_h;
|
||||
if (*mx >= dd_x && *mx < dd_x + dd_w && *my >= opt_y && *my < opt_y + opt_h) {
|
||||
clicked_opt = opt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (clicked_opt >= 0) {
|
||||
pref_set(prefs, dropdown_open, clicked_opt);
|
||||
}
|
||||
dropdown_open = -1;
|
||||
redraw_prefs_card(fb, card_x, card_y, prefs, active, *mx, *my, bg, fg);
|
||||
} else {
|
||||
/* No dropdown open - check for value area clicks */
|
||||
for (int r = 0; r < 5; r++) {
|
||||
i64 ry = card_y + 120 + (i64)r * 80;
|
||||
if (*mx >= card_x + 260 && *mx < card_x + 860 && *my >= ry && *my < ry + 42) {
|
||||
active = r;
|
||||
dropdown_open = r;
|
||||
redraw_prefs_card(fb, card_x, card_y, prefs, active, *mx, *my, bg, fg);
|
||||
cursor_erase(fb);
|
||||
draw_dropdown_menu(fb, card_x, card_y, r, prefs, fg);
|
||||
cursor_draw(fb, *mx, *my);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,6 +811,13 @@ static void read_prefs_page(u32 *fb, i64 card_x, i64 card_y, setup_prefs *prefs,
|
||||
u8 sc = data;
|
||||
if (sc == 0xE0) { e0 = 1; continue; }
|
||||
if (sc & 0x80) { e0 = 0; continue; }
|
||||
/* Close dropdown on any real key press */
|
||||
if (dropdown_open >= 0) {
|
||||
dropdown_open = -1;
|
||||
redraw_prefs_card(fb, card_x, card_y, prefs, active, *mx, *my, bg, fg);
|
||||
e0 = 0;
|
||||
continue;
|
||||
}
|
||||
if (e0 && sc == 0x48) {
|
||||
if (active > 0) { int old = active; active--; redraw_prefs_row(fb, card_x, card_y, prefs, old, active, *mx, *my, fg); redraw_prefs_row(fb, card_x, card_y, prefs, active, active, *mx, *my, fg); }
|
||||
e0 = 0; continue;
|
||||
@@ -617,6 +839,9 @@ static void read_prefs_page(u32 *fb, i64 card_x, i64 card_y, setup_prefs *prefs,
|
||||
redraw_prefs_row(fb, card_x, card_y, prefs, old, active, *mx, *my, fg);
|
||||
redraw_prefs_row(fb, card_x, card_y, prefs, active, active, *mx, *my, fg);
|
||||
} else {
|
||||
cursor_bg_valid = 0;
|
||||
cursor_cur_x = -100;
|
||||
cursor_cur_y = -100;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -710,10 +935,11 @@ static void wifi_query_scan(u64 kernel_api) {
|
||||
net_scan_count_fn scount = (net_scan_count_fn)*(u64 *)(net_api + 48);
|
||||
net_scan_result_fn sresult = (net_scan_result_fn)*(u64 *)(net_api + 56);
|
||||
net_is_wireless_fn iswl = (net_is_wireless_fn)*(u64 *)(net_api + 64);
|
||||
if (!dcount || !iswl || !scount || !sresult) {
|
||||
logl("[FirstInit] net scan api incomplete");
|
||||
return;
|
||||
}
|
||||
if (!dcount) { logl("[FirstInit] net device_count fn is null"); return; }
|
||||
if (!sstart) { logl("[FirstInit] net scan_start fn is null"); return; }
|
||||
if (!scount) { logl("[FirstInit] net scan_count fn is null"); return; }
|
||||
if (!sresult) { logl("[FirstInit] net scan_result fn is null"); return; }
|
||||
if (!iswl) { logl("[FirstInit] net is_wireless fn is null"); return; }
|
||||
u32 ndev = dcount();
|
||||
/* 串口日志:设备数 */
|
||||
{
|
||||
@@ -723,11 +949,21 @@ static void wifi_query_scan(u64 kernel_api) {
|
||||
b[p++]='0'+(ndev/10); b[p++]='0'+(ndev%10); b[p]=0;
|
||||
logl(b);
|
||||
}
|
||||
/* 找第一个无线设备 */
|
||||
/* 找第一个无线设备 - 通过 device_info 检查 flags 而非调用 is_wireless */
|
||||
int wifi_idx = -1;
|
||||
for (u32 i = 0; i < ndev; i++) {
|
||||
int rc = iswl(i);
|
||||
if (rc == 1) { wifi_idx = (int)i; break; }
|
||||
/* 使用 device_info 获取 flags,避免直接调用 is_wireless 导致崩溃 */
|
||||
u64 devinfo_fn = *(u64 *)(net_api + 16);
|
||||
if (devinfo_fn) {
|
||||
/* dkm_net_device_info 布局: name(8) + mac(6) + pad(2) + flags(4) = 20 字节 */
|
||||
u8 info[24];
|
||||
for (int k = 0; k < 24; k++) info[k] = 0;
|
||||
int rc = ((int (*)(u32, void *))devinfo_fn)(i, info);
|
||||
if (rc == 0) {
|
||||
u32 flags = *(u32 *)(info + 16);
|
||||
if (flags & 8) { wifi_idx = (int)i; break; } /* DKM_NET_F_WIRELESS = (1<<3) */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wifi_idx < 0) {
|
||||
logl("[FirstInit] no wireless device found");
|
||||
@@ -806,63 +1042,84 @@ static void net_select(setup_net *net, int idx) {
|
||||
static void draw_wifi_row(u32 *fb, i64 card_x, i64 card_y, setup_net *net, int row, int active, u32 fg) {
|
||||
u32 card = CARD_BG;
|
||||
i64 x = card_x + 40;
|
||||
i64 y = card_y + 132 + (i64)row * 64;
|
||||
u32 fill = active == row ? 0xFFFFFFFF : (net->selected == row ? 0xFFDCECF8 : INPUT_BG);
|
||||
fill_rounded_rect(fb, x, y, 390, 50, 9, fill);
|
||||
stroke_rounded_rect(fb, x, y, 390, 50, 9, 1, active == row ? 0xFF7FA7C8 : card);
|
||||
fb_text(fb, net->selected == row ? ">" : " ", x + 12, y + 16, fg, fill);
|
||||
i64 y = card_y + 132 + (i64)row * 56;
|
||||
u32 fill = active == row ? 0xFF45454A : (net->selected == row ? 0xFF3A3A3E : INPUT_BG);
|
||||
fill_rounded_rect(fb, x, y, 390, 46, 3, fill);
|
||||
stroke_rounded_rect(fb, x, y, 390, 46, 3, 1, active == row ? 0xFF6C6C72 : 0xFF404044);
|
||||
fb_text(fb, net->selected == row ? ">" : " ", x + 12, y + 14, fg, fill);
|
||||
if (row < g_wifi_scan_count) {
|
||||
fb_text(fb, g_wifi_ssids[row], x + 42, y + 8, fg, fill);
|
||||
fb_text(fb, g_wifi_meta[row], x + 42, y + 28, 0xFF7F97AC, fill);
|
||||
fb_text(fb, g_wifi_ssids[row], x + 42, y + 6, fg, fill);
|
||||
fb_text(fb, g_wifi_meta[row], x + 42, y + 26, 0xFF808088, fill);
|
||||
} else {
|
||||
/* 无扫描结果时的占位行 */
|
||||
const char *placeholder = (g_wifi_scan_tried && g_wifi_scan_count == 0)
|
||||
? "No networks found" : "(empty)";
|
||||
fb_text(fb, placeholder, x + 42, y + 16, 0xFF9AACC0, fill);
|
||||
fb_text(fb, placeholder, x + 42, y + 14, 0xFF606068, fill);
|
||||
}
|
||||
}
|
||||
|
||||
/* 网络页面活跃元素索引 */
|
||||
#define NET_ACT_WIFI_BASE 0
|
||||
#define NET_ACT_SSID 4
|
||||
#define NET_ACT_PASS 5
|
||||
#define NET_ACT_SAVE 6
|
||||
#define NET_ACT_CONNECT 7
|
||||
#define NET_ACT_COUNT 8
|
||||
|
||||
static void redraw_network_card(u32 *fb, i64 card_x, i64 card_y, setup_net *net, int active, i64 mx, i64 my, u32 bg, u32 fg) {
|
||||
u32 card = CARD_BG;
|
||||
cursor_erase(fb);
|
||||
fill_gradient_rect(fb, card_x - 24, card_y - 24, 948, 648);
|
||||
draw_card(fb, card_x, card_y, 900, 600, card, bg);
|
||||
fb_bitmap_alpha(fb, g_txt_network_title, g_txt_network_title_w, g_txt_network_title_h, card_x+40, card_y+40, fg, card, 255);
|
||||
fb_text(fb, "Choose a network", card_x + 40, card_y + 88, 0xFF7F97AC, card);
|
||||
fb_text(fb, "Network", card_x+40, card_y+40+g_txt_network_title_h+2, 0xFF9098A0, card);
|
||||
fb_text(fb, "Choose or enter network", card_x + 40, card_y + 92, 0xFF808088, card);
|
||||
|
||||
/* 左侧: WiFi 列表 */
|
||||
for (int r=0; r<WIFI_SCAN_COUNT; r++) draw_wifi_row(fb, card_x, card_y, net, r, active, fg);
|
||||
|
||||
fill_rounded_rect(fb, card_x + 470, card_y + 120, 390, 260, 12, INPUT_BG);
|
||||
stroke_rounded_rect(fb, card_x + 470, card_y + 120, 390, 260, 12, 1, 0xFFD2E3F0);
|
||||
fb_text(fb, "Highlighted network", card_x + 494, card_y + 148, 0xFF7F97AC, INPUT_BG);
|
||||
int preview = active < WIFI_SCAN_COUNT ? active : net->selected;
|
||||
if (preview < g_wifi_scan_count) {
|
||||
fb_text(fb, g_wifi_ssids[preview], card_x + 494, card_y + 182, fg, INPUT_BG);
|
||||
fb_text(fb, g_wifi_meta[preview], card_x + 494, card_y + 210, 0xFF7F97AC, INPUT_BG);
|
||||
} else {
|
||||
fb_text(fb, g_wifi_scan_tried ? "No networks found" : "WiFi not initialized",
|
||||
card_x + 494, card_y + 182, 0xFF9AACC0, INPUT_BG);
|
||||
fb_text(fb, g_wifi_scan_tried ? "Check ath9k driver" : "Run ath9k driver first",
|
||||
card_x + 494, card_y + 210, 0xFF9AACC0, INPUT_BG);
|
||||
}
|
||||
fb_text(fb, "Use Up/Down or click menu", card_x + 494, card_y + 260, 0xFF7F97AC, INPUT_BG);
|
||||
fb_text(fb, "Enter selects highlighted item", card_x + 494, card_y + 288, 0xFF7F97AC, INPUT_BG);
|
||||
/* 右侧: 手动输入区 */
|
||||
fb_text(fb, "Network name (SSID)", card_x + 470, card_y + 120, 0xFF808088, card);
|
||||
draw_rounded_input(fb, card_x + 470, card_y + 148, 390, 44, net->ssid, 0, fg, card, active == NET_ACT_SSID);
|
||||
|
||||
fb_text(fb, "Password", card_x + 470, card_y + 210, 0xFF808088, card);
|
||||
draw_rounded_input(fb, card_x + 470, card_y + 238, 390, 44, net->password, 1, fg, card, active == NET_ACT_PASS);
|
||||
|
||||
/* 保存按钮 */
|
||||
{
|
||||
u32 btn_bg = active == NET_ACT_SAVE ? 0xFF45454A : 0xFF3A3A3E;
|
||||
fill_rounded_rect(fb, card_x + 470, card_y + 310, 180, 44, 3, btn_bg);
|
||||
stroke_rounded_rect(fb, card_x + 470, card_y + 310, 180, 44, 3, 1, active == NET_ACT_SAVE ? 0xFF6C6C72 : 0xFF404044);
|
||||
fb_text(fb, "Save", card_x + 530, card_y + 322, fg, btn_bg);
|
||||
}
|
||||
/* 连接按钮 */
|
||||
{
|
||||
u32 btn_bg = active == NET_ACT_CONNECT ? 0xFF4A6A8A : 0xFF3A5070;
|
||||
fill_rounded_rect(fb, card_x + 680, card_y + 310, 180, 44, 3, btn_bg);
|
||||
stroke_rounded_rect(fb, card_x + 680, card_y + 310, 180, 44, 3, 1, active == NET_ACT_CONNECT ? 0xFF6A8AAA : 0xFF404060);
|
||||
fb_text(fb, "Connect", card_x + 725, card_y + 322, 0xFFE0E0E0, btn_bg);
|
||||
}
|
||||
|
||||
/* 状态提示 */
|
||||
if (net->connected) {
|
||||
fb_text(fb, "Network profile saved", card_x + 470, card_y + 380, 0xFF5FAF6F, card);
|
||||
} else if (net->ssid[0]) {
|
||||
fb_text(fb, "Press Save or Connect", card_x + 470, card_y + 380, 0xFF808088, card);
|
||||
} else {
|
||||
fb_text(fb, "Select network or type SSID", card_x + 470, card_y + 380, 0xFF606068, card);
|
||||
}
|
||||
fb_text(fb, "Save=save config only", card_x + 470, card_y + 510, 0xFF606068, card);
|
||||
fb_text(fb, "Connect=save and connect", card_x + 470, card_y + 535, 0xFF606068, card);
|
||||
|
||||
fb_text(fb, "Password", card_x + 470, card_y + 400, fg, card);
|
||||
draw_rounded_input(fb, card_x + 470, card_y + 430, 390, 44, net->password, 1, fg, card, active == WIFI_SCAN_COUNT);
|
||||
u32 btn = active == WIFI_SCAN_COUNT + 1 ? 0xFFFFFFFF : 0xFFDCECF8;
|
||||
fill_rounded_rect(fb, card_x + 620, card_y + 500, 240, 48, 10, btn);
|
||||
stroke_rounded_rect(fb, card_x + 620, card_y + 500, 240, 48, 10, 1, active == WIFI_SCAN_COUNT + 1 ? 0xFFB6C9DD : card);
|
||||
fb_text(fb, "Connect", card_x + 690, card_y + 516, fg, btn);
|
||||
if (net->connected) fb_text(fb, "Connection profile saved", card_x + 40, card_y + 515, 0xFF4F8A5F, card);
|
||||
else fb_text(fb, "Select SSID, enter password, then Connect", card_x + 40, card_y + 555, 0xFF7F97AC, card);
|
||||
cursor_draw(fb, mx, my);
|
||||
}
|
||||
|
||||
static void read_network_page(u32 *fb, i64 card_x, i64 card_y, setup_net *net, i64 *mx, i64 *my, u32 bg, u32 fg) {
|
||||
int active = 0, mcnt = 0, e0 = 0, shift = 0;
|
||||
u8 mpkt[3]; u8 prev_btns = 0;
|
||||
int len = 0;
|
||||
while (net->password[len]) len++;
|
||||
int plen = 0;
|
||||
int slen = 0;
|
||||
while (net->password[plen]) plen++;
|
||||
while (net->ssid[slen]) slen++;
|
||||
net_select(net, net->selected);
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
for (;;) {
|
||||
@@ -885,23 +1142,41 @@ static void read_network_page(u32 *fb, i64 card_x, i64 card_y, setup_net *net, i
|
||||
cursor_draw(fb, *mx, *my);
|
||||
}
|
||||
if ((btns & 1) && !(prev_btns & 1)) {
|
||||
/* WiFi 列表点击 */
|
||||
for (int r=0; r<WIFI_SCAN_COUNT; r++) {
|
||||
i64 ry = card_y + 132 + (i64)r * 64;
|
||||
if (*mx >= card_x + 40 && *mx < card_x + 430 && *my >= ry && *my < ry + 50) {
|
||||
i64 ry = card_y + 132 + (i64)r * 56;
|
||||
if (*mx >= card_x + 40 && *mx < card_x + 430 && *my >= ry && *my < ry + 46) {
|
||||
active = r;
|
||||
net_select(net, r);
|
||||
len = 0;
|
||||
slen = 0;
|
||||
while (net->ssid[slen]) slen++;
|
||||
plen = 0;
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
}
|
||||
}
|
||||
if (*mx >= card_x + 470 && *mx < card_x + 860 && *my >= card_y + 430 && *my < card_y + 474) {
|
||||
active = WIFI_SCAN_COUNT;
|
||||
/* SSID 输入框 */
|
||||
if (*mx >= card_x + 470 && *mx < card_x + 860 && *my >= card_y + 148 && *my < card_y + 192) {
|
||||
active = NET_ACT_SSID;
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
}
|
||||
if (*mx >= card_x + 620 && *mx < card_x + 860 && *my >= card_y + 500 && *my < card_y + 548) {
|
||||
/* 密码输入框 */
|
||||
if (*mx >= card_x + 470 && *mx < card_x + 860 && *my >= card_y + 238 && *my < card_y + 282) {
|
||||
active = NET_ACT_PASS;
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
}
|
||||
/* 保存按钮 */
|
||||
if (*mx >= card_x + 470 && *mx < card_x + 650 && *my >= card_y + 310 && *my < card_y + 354) {
|
||||
net->connected = 1;
|
||||
logl("[FirstInit] wireless profile selected");
|
||||
redraw_network_card(fb, card_x, card_y, net, WIFI_SCAN_COUNT + 1, *mx, *my, bg, fg);
|
||||
logl("[FirstInit] network profile saved");
|
||||
redraw_network_card(fb, card_x, card_y, net, NET_ACT_SAVE, *mx, *my, bg, fg);
|
||||
for (int i=0;i<30;i++) delay_frame();
|
||||
return;
|
||||
}
|
||||
/* 连接按钮 */
|
||||
if (*mx >= card_x + 680 && *mx < card_x + 860 && *my >= card_y + 310 && *my < card_y + 354) {
|
||||
net->connected = 1;
|
||||
logl("[FirstInit] network connect requested");
|
||||
redraw_network_card(fb, card_x, card_y, net, NET_ACT_CONNECT, *mx, *my, bg, fg);
|
||||
for (int i=0;i<30;i++) delay_frame();
|
||||
return;
|
||||
}
|
||||
@@ -920,7 +1195,7 @@ static void read_network_page(u32 *fb, i64 card_x, i64 card_y, setup_net *net, i
|
||||
e0=0; continue;
|
||||
}
|
||||
if (e0 && sc == 0x50) {
|
||||
if (active < WIFI_SCAN_COUNT + 1) active++;
|
||||
if (active < NET_ACT_COUNT - 1) active++;
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
e0=0; continue;
|
||||
}
|
||||
@@ -930,13 +1205,22 @@ static void read_network_page(u32 *fb, i64 card_x, i64 card_y, setup_net *net, i
|
||||
if (c == '\n') {
|
||||
if (active < WIFI_SCAN_COUNT) {
|
||||
net_select(net, active);
|
||||
len = 0;
|
||||
active = WIFI_SCAN_COUNT;
|
||||
} else if (active == WIFI_SCAN_COUNT) {
|
||||
active = WIFI_SCAN_COUNT + 1;
|
||||
} else {
|
||||
slen = 0;
|
||||
while (net->ssid[slen]) slen++;
|
||||
active = NET_ACT_PASS;
|
||||
} else if (active == NET_ACT_SSID) {
|
||||
active = NET_ACT_PASS;
|
||||
} else if (active == NET_ACT_PASS) {
|
||||
active = NET_ACT_CONNECT;
|
||||
} else if (active == NET_ACT_SAVE) {
|
||||
net->connected = 1;
|
||||
logl("[FirstInit] wireless profile selected");
|
||||
logl("[FirstInit] network profile saved");
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
for (int i=0;i<30;i++) delay_frame();
|
||||
return;
|
||||
} else if (active == NET_ACT_CONNECT) {
|
||||
net->connected = 1;
|
||||
logl("[FirstInit] network connect requested");
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
for (int i=0;i<30;i++) delay_frame();
|
||||
return;
|
||||
@@ -945,16 +1229,28 @@ static void read_network_page(u32 *fb, i64 card_x, i64 card_y, setup_net *net, i
|
||||
continue;
|
||||
}
|
||||
if (c == '\t') {
|
||||
active = (active + 1) % (WIFI_SCAN_COUNT + 2);
|
||||
active = (active + 1) % NET_ACT_COUNT;
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
continue;
|
||||
}
|
||||
if (active == WIFI_SCAN_COUNT) {
|
||||
/* SSID 输入 */
|
||||
if (active == NET_ACT_SSID) {
|
||||
if (c == 8) {
|
||||
if (len > 0) net->password[--len] = 0;
|
||||
} else if (len < 63 && c >= 32 && c <= 126) {
|
||||
net->password[len++] = c;
|
||||
net->password[len] = 0;
|
||||
if (slen > 0) net->ssid[--slen] = 0;
|
||||
} else if (slen < 31 && c >= 32 && c <= 126) {
|
||||
net->ssid[slen++] = c;
|
||||
net->ssid[slen] = 0;
|
||||
}
|
||||
net->connected = 0;
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
}
|
||||
/* 密码输入 */
|
||||
if (active == NET_ACT_PASS) {
|
||||
if (c == 8) {
|
||||
if (plen > 0) net->password[--plen] = 0;
|
||||
} else if (plen < 63 && c >= 32 && c <= 126) {
|
||||
net->password[plen++] = c;
|
||||
net->password[plen] = 0;
|
||||
}
|
||||
net->connected = 0;
|
||||
redraw_network_card(fb, card_x, card_y, net, active, *mx, *my, bg, fg);
|
||||
@@ -981,9 +1277,12 @@ static void sha256(const char *msg, u8 out[32]) {
|
||||
for(int i=0;i<8;i++){out[i*4]=(u8)(h[i]>>24);out[i*4+1]=(u8)(h[i]>>16);out[i*4+2]=(u8)(h[i]>>8);out[i*4+3]=(u8)h[i];}
|
||||
}
|
||||
|
||||
static u8 g_conf_data[1024];
|
||||
static u32 g_conf_size;
|
||||
|
||||
static void build_user_conf(const char *pc, const char *user, const char *pass, const setup_prefs *prefs, const setup_net *net) {
|
||||
u8 hash[32]; sha256(pass, hash);
|
||||
static char conf[1024]; int p=0;
|
||||
char *conf = (char *)g_conf_data; int p=0;
|
||||
const char *pre="DESHAB_USERCONF_V1\ncomputer=";
|
||||
for(int i=0;pre[i];i++) conf[p++]=pre[i];
|
||||
for(int i=0;pc[i]&&p<740;i++) conf[p++]=pc[i];
|
||||
@@ -1011,15 +1310,18 @@ static void build_user_conf(const char *pc, const char *user, const char *pass,
|
||||
const char *ni="\nnetwork.ip=dhcp"; for(int i=0;ni[i];i++) conf[p++]=ni[i];
|
||||
const char *dns="\nnetwork.dns=auto"; for(int i=0;dns[i];i++) conf[p++]=dns[i];
|
||||
conf[p++]='\n';
|
||||
/* XOR encrypt buffer with hash-derived stream; real disk write waits for FAT32 write support. */
|
||||
/* XOR encrypt buffer with hash-derived stream; DSK writes to FAT32 after return. */
|
||||
for(int i=0;i<p;i++) conf[i]^=hash[i&31];
|
||||
logl("[FirstInit] user.conf encrypted in memory (disk write pending)");
|
||||
g_conf_size = (u32)p;
|
||||
logl("[FirstInit] user.conf built and encrypted");
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void dsk_entry(const dsk_boot_context *ctx) {
|
||||
__asm__ volatile("cli"); /* prevent IRQ1 (ps2kbd) from racing with our polling */
|
||||
logl("[FirstInit] boot");
|
||||
logl("[FirstInit] calibrating TSC (实机 CPU 频率计算)");
|
||||
tsc_calibrate_fi();
|
||||
|
||||
if (!ctx || ctx->magic != 0x44534B31424F4F54ULL) {
|
||||
logl("[FirstInit] bad context");
|
||||
@@ -1049,13 +1351,20 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
fade_ring(fb, cx, cy, bg);
|
||||
logl("[FirstInit] ring faded");
|
||||
|
||||
/* center text: Chinese bitmaps */
|
||||
/* center text: Chinese bitmaps + English subtitle below */
|
||||
i64 tw = g_txt_welcome_w, tx = cx - tw/2, ty = cy - g_txt_welcome_h/2;
|
||||
/* English subtitle sits below the Chinese bitmap, centered independently */
|
||||
const char *welcome_en = "Welcome to Deshab";
|
||||
i64 en_w = fb_text_width(welcome_en);
|
||||
i64 en_x = cx - en_w/2, en_y = ty + g_txt_welcome_h + 6;
|
||||
/* subtitle color: dimmer than WELCOME_FG so it reads as secondary */
|
||||
u32 sub_fg = 0xFFA8B8C8;
|
||||
|
||||
logl("[FirstInit] fading in welcome");
|
||||
for (u32 a=0; a<=255; a+=17) {
|
||||
fill_gradient_rect(fb, tx-4, ty-4, tw+8, g_txt_welcome_h+8);
|
||||
fill_gradient_rect(fb, tx-4, ty-4, tw+8, g_txt_welcome_h + 6 + ASCII_H + 4);
|
||||
fb_bitmap_alpha(fb, g_txt_welcome, tw, g_txt_welcome_h, tx, ty, WELCOME_FG, bg_at_y(ty + g_txt_welcome_h / 2), a);
|
||||
fb_text_alpha(fb, welcome_en, en_x, en_y, sub_fg, bg_at_y(en_y + ASCII_H/2), a);
|
||||
delay_frame();
|
||||
}
|
||||
logl("[FirstInit] welcome drawn");
|
||||
@@ -1064,16 +1373,26 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
|
||||
logl("[FirstInit] cross-fading to setup message");
|
||||
i64 tw2 = g_txt_setup_w, tx2 = cx - tw2/2;
|
||||
i64 area_x = tx2 < tx ? tx2 : tx;
|
||||
i64 area_w = (tx2 + tw2 > tx + tw ? tx2 + tw2 : tx + tw) - area_x;
|
||||
i64 area_h = (g_txt_setup_h > g_txt_welcome_h ? g_txt_setup_h : g_txt_welcome_h) + 8;
|
||||
const char *setup_en = "Let's set up your system";
|
||||
i64 en2_w = fb_text_width(setup_en);
|
||||
i64 en2_x = cx - en2_w/2;
|
||||
i64 area_x = (tx2 < tx ? tx2 : tx);
|
||||
if (en_x < area_x) area_x = en_x;
|
||||
if (en2_x < area_x) area_x = en2_x;
|
||||
i64 area_right = tx + tw; if (tx2 + tw2 > area_right) area_right = tx2 + tw2;
|
||||
if (en_x + en_w > area_right) area_right = en_x + en_w;
|
||||
if (en2_x + en2_w > area_right) area_right = en2_x + en2_w;
|
||||
i64 area_w = area_right - area_x;
|
||||
i64 area_h = (g_txt_setup_h > g_txt_welcome_h ? g_txt_setup_h : g_txt_welcome_h) + 6 + ASCII_H + 8;
|
||||
|
||||
for (u32 step=0; step<=15; step++) {
|
||||
u32 a2 = step * 17;
|
||||
u32 a1 = 255 - a2;
|
||||
fill_gradient_rect(fb, area_x-4, ty-4, area_w+8, area_h);
|
||||
fb_bitmap_alpha(fb, g_txt_welcome, tw, g_txt_welcome_h, tx, ty, WELCOME_FG, bg_at_y(ty + g_txt_welcome_h / 2), a1);
|
||||
fb_text_alpha(fb, welcome_en, en_x, en_y, sub_fg, bg_at_y(en_y + ASCII_H/2), a1);
|
||||
fb_bitmap_alpha(fb, g_txt_setup, tw2, g_txt_setup_h, tx2, ty, WELCOME_FG, bg_at_y(ty + g_txt_setup_h / 2), a2);
|
||||
fb_text_alpha(fb, setup_en, en2_x, en_y, sub_fg, bg_at_y(en_y + ASCII_H/2), a2);
|
||||
delay_frame();
|
||||
}
|
||||
logl("[FirstInit] setup message drawn");
|
||||
@@ -1089,13 +1408,14 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
logl("[FI] fadein start");
|
||||
/* Phase 1: fade in card background only (no title) — avoids title/card color mismatch flicker */
|
||||
for (u32 a=0; a<=255; a+=17) {
|
||||
draw_card_fade(fb, card_x, card_y, 900, 600, 12, a);
|
||||
draw_card_fade(fb, card_x, card_y, 900, 600, 4, a);
|
||||
delay_frame();
|
||||
}
|
||||
/* Phase 2: draw title once on fully-rendered card */
|
||||
{
|
||||
u32 title_bg = blend(bg_at_y(card_y + 40 + g_txt_title_h/2), CARD_BG, 255);
|
||||
fb_bitmap_alpha(fb, g_txt_title, g_txt_title_w, g_txt_title_h, card_x+40, card_y+40, fg, title_bg, 255);
|
||||
fb_text(fb, "Account Setup", card_x+40, card_y+40+g_txt_title_h+2, 0xFF9098A0, title_bg);
|
||||
}
|
||||
logl("[FI] fadein done");
|
||||
logl("[FirstInit] initializing PS/2 mouse");
|
||||
@@ -1103,10 +1423,89 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
i64 mx = cx, my = cy;
|
||||
{
|
||||
int field = 0;
|
||||
while (field < 3) {
|
||||
field = read_field(fb, card_x, card_y, field, pc, user, pass, &mx, &my, bg, fg);
|
||||
for (;;) {
|
||||
while (field < 3) {
|
||||
field = read_field(fb, card_x, card_y, field, pc, user, pass, &mx, &my, bg, fg);
|
||||
}
|
||||
/* Validate: all fields must be non-empty */
|
||||
if (pc[0] != 0 && user[0] != 0 && pass[0] != 0) break;
|
||||
/* Show warning message on card (overwrite hint area) */
|
||||
cursor_erase(fb);
|
||||
{
|
||||
u32 card = CARD_BG;
|
||||
fill_rect(fb, card_x + 40, card_y + 550, 820, 45, card);
|
||||
fb_text(fb, "Please fill in all fields", card_x + 40, card_y + 555, 0xFFFF6B6B, card);
|
||||
fb_text(fb, "Press Enter to continue", card_x + 40, card_y + 575, 0xFFC0C0C0, card);
|
||||
}
|
||||
cursor_draw(fb, mx, my); /* 重绘鼠标光标,避免校验失败时光标消失 */
|
||||
logl("[FI] validation failed: empty field(s)");
|
||||
/* 等待用户确认:Enter/任意键回到 field 0,或点击输入框切换字段。
|
||||
* 避免死等 Enter 导致用户点击/输入无响应。 */
|
||||
int next_field = 0;
|
||||
{
|
||||
int release = 0;
|
||||
int mcnt = 0;
|
||||
u8 mpkt[3];
|
||||
u8 prev_btns = 0;
|
||||
int done = 0;
|
||||
while (!done) {
|
||||
u8 st = inb(0x64);
|
||||
if (!(st & 1)) { __asm__("pause"); continue; }
|
||||
u8 data = inb(0x60);
|
||||
if (st & 0x20) {
|
||||
/* 鼠标数据:组装 3 字节包,同步位 bit 3 */
|
||||
if (mcnt == 0 && !(data & 0x08)) continue;
|
||||
mpkt[mcnt++] = data;
|
||||
if (mcnt < 3) continue;
|
||||
mcnt = 0;
|
||||
i64 dx = (i64)(i8)mpkt[1];
|
||||
i64 dy = (i64)(i8)mpkt[2];
|
||||
u8 btns = mpkt[0] & 0x07;
|
||||
if (dx != 0 || dy != 0) {
|
||||
cursor_erase(fb);
|
||||
mx += dx;
|
||||
my -= dy; /* invert Y: 鼠标上移 = 屏幕上移 */
|
||||
if (mx < 0) mx = 0;
|
||||
if (my < 0) my = 0;
|
||||
if ((u64)mx >= fb_w) mx = (i64)fb_w - 1;
|
||||
if ((u64)my >= fb_h) my = (i64)fb_h - 1;
|
||||
cursor_draw(fb, mx, my);
|
||||
}
|
||||
/* 左键点击输入框:切换到该字段重新输入 */
|
||||
if ((btns & 1) && !(prev_btns & 1)) {
|
||||
for (int f = 0; f < 3; f++) {
|
||||
i64 fy = card_y + 180 + (i64)f * 150;
|
||||
if (my >= fy && my < fy + 44 && mx >= card_x + 40 && mx < card_x + 860) {
|
||||
next_field = f;
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_btns = btns;
|
||||
continue;
|
||||
}
|
||||
u8 sc = data;
|
||||
if (sc == 0xF0) { release = 1; continue; }
|
||||
if (release) { release = 0; continue; }
|
||||
if (sc & 0x80) continue; /* Set 1 release code */
|
||||
/* Enter 或任意按键:退出等待,回到 field 0 重新输入 */
|
||||
next_field = 0;
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
/* Reset all fields and restart input from next_field.
|
||||
* read_field() will call redraw_setup_card() which fully
|
||||
* redraws the card (title, labels, inputs, hint) and cursor. */
|
||||
pc[0] = 0; user[0] = 0; pass[0] = 0;
|
||||
field = next_field;
|
||||
}
|
||||
}
|
||||
logl("[FI] all fields done");
|
||||
/* 重置光标状态,避免页面切换时崩溃 */
|
||||
cursor_bg_valid = 0;
|
||||
cursor_cur_x = -100;
|
||||
cursor_cur_y = -100;
|
||||
setup_prefs prefs;
|
||||
prefs.language = 0; /* zh-CN */
|
||||
prefs.region = 0; /* CN */
|
||||
@@ -1114,6 +1513,10 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
prefs.keyboard = 0; /* US-QWERTY */
|
||||
prefs.theme = 0; /* Light */
|
||||
read_prefs_page(fb, card_x, card_y, &prefs, &mx, &my, bg, fg);
|
||||
/* 重置光标状态,避免页面切换时崩溃 */
|
||||
cursor_bg_valid = 0;
|
||||
cursor_cur_x = -100;
|
||||
cursor_cur_y = -100;
|
||||
/* 查询真实 WiFi 扫描结果(来自 ath9k 驱动通过 kernel_api.net.scan_*) */
|
||||
wifi_query_scan(ctx->dkm_kernel_api);
|
||||
setup_net net;
|
||||
@@ -1121,23 +1524,36 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
net.connected = 0;
|
||||
net.ssid[0] = 0;
|
||||
net.password[0] = 0;
|
||||
if (g_no_wireless_device) {
|
||||
/* QEMU 或无无线网卡场景:跳过 WiFi 设置页面,network.mode=disabled */
|
||||
logl("[FirstInit] no wireless device, skipping WiFi setup page");
|
||||
net.connected = 0;
|
||||
} else {
|
||||
cursor_bg_valid = 0;
|
||||
cursor_cur_x = -100;
|
||||
cursor_cur_y = -100;
|
||||
logl("[FirstInit] entering wireless setup page");
|
||||
read_network_page(fb, card_x, card_y, &net, &mx, &my, bg, fg);
|
||||
logl("[FirstInit] wireless setup page returned");
|
||||
}
|
||||
/* 始终显示网络设置页面,即使无无线设备也展示页面让用户确认 */
|
||||
cursor_bg_valid = 0;
|
||||
cursor_cur_x = -100;
|
||||
cursor_cur_y = -100;
|
||||
logl("[FirstInit] entering network setup page");
|
||||
read_network_page(fb, card_x, card_y, &net, &mx, &my, bg, fg);
|
||||
logl("[FirstInit] network setup page returned");
|
||||
build_user_conf(pc, user, pass, &prefs, &net);
|
||||
|
||||
/* Pass config buffer to DSK via boot context reserved fields */
|
||||
{
|
||||
dsk_boot_context *ctx_mut = (dsk_boot_context *)ctx;
|
||||
ctx_mut->reserved[0] = (u64)(u64*)g_conf_data;
|
||||
ctx_mut->reserved[1] = (u64)g_conf_size;
|
||||
}
|
||||
logl("[FirstInit] config ready for DSK to write");
|
||||
|
||||
cursor_erase(fb);
|
||||
fill_gradient_rect(fb, card_x - 24, card_y - 24, 948, 648);
|
||||
fb_bitmap_alpha(fb, g_txt_done, g_txt_done_w, g_txt_done_h, cx - g_txt_done_w/2, cy - 20, fg, bg_at_y(cy), 255);
|
||||
fb_bitmap_alpha(fb, g_txt_done, g_txt_done_w, g_txt_done_h, cx - g_txt_done_w/2, cy - 30, fg, bg_at_y(cy), 255);
|
||||
/* English subtitle below the Chinese done bitmap */
|
||||
{ const char *done_en = "Setup Complete";
|
||||
i64 dw = fb_text_width(done_en);
|
||||
fb_text(fb, done_en, cx - dw/2, cy + 2, 0xFFA8B8C8, bg_at_y(cy + 10));
|
||||
}
|
||||
/* status line below the subtitle */
|
||||
{ const char *status = "System starting...";
|
||||
i64 sw = fb_text_width(status);
|
||||
fb_text(fb, status, cx - sw/2, cy + 28, 0xFF808088, bg_at_y(cy + 36));
|
||||
}
|
||||
logl("[FirstInit] user setup finished");
|
||||
|
||||
/* 短暂停留后返回,由 DSK 接管加载 shell */
|
||||
|
||||
Binary file not shown.
@@ -1,97 +1,97 @@
|
||||
/* Auto-generated */
|
||||
|
||||
static const int g_txt_welcome_w = 360;
|
||||
static const int g_txt_welcome_h = 54;
|
||||
static const unsigned char g_txt_welcome[360*54] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 61, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 202, 137, 76, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 123, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 166, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 207, 118, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 255, 255, 247, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 255, 255, 255, 252, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 218, 255, 255, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 144, 243, 255, 255, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 255, 255, 250, 173, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 255, 255, 255, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 148, 255, 255, 255, 161, 0, 0, 0, 0, 0, 0, 0, 0, 20, 70, 132, 209, 255, 255, 255, 255, 255, 226, 27, 5, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 228, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 255, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 245, 255, 255, 255, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 255, 255, 255, 242, 8, 0, 0, 0, 0, 0, 0, 198, 255, 255, 255, 255, 255, 255, 255, 255, 254, 215, 120, 26, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 255, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 255, 255, 255, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 255, 255, 255, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 217, 255, 255, 255, 82, 0, 0, 0, 0, 0, 0, 215, 255, 255, 255, 255, 251, 198, 136, 74, 17, 0, 0, 17, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 239, 255, 255, 242, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 255, 255, 255, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 255, 255, 255, 238, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 252, 255, 255, 252, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 246, 255, 255, 255, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 255, 255, 255, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 168, 0, 0, 0, 0, 0, 0, 207, 255, 255, 237, 72, 12, 0, 0, 0, 0, 0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 255, 255, 255, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 255, 255, 255, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 51, 199, 188, 176, 169, 165, 161, 160, 160, 160, 160, 160, 160, 160, 160, 160, 130, 0, 0, 0, 0, 157, 255, 255, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 255, 255, 255, 244, 8, 0, 0, 0, 0, 0, 200, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 255, 255, 255, 54, 0, 47, 245, 232, 222, 215, 211, 209, 208, 208, 208, 208, 208, 208, 220, 255, 255, 255, 223, 208, 208, 208, 208, 208, 208, 211, 214, 217, 222, 232, 242, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 252, 236, 217, 196, 142, 77, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 169, 0, 0, 0, 0, 213, 255, 255, 248, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 209, 255, 255, 255, 76, 0, 0, 0, 0, 0, 193, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 249, 255, 255, 215, 0, 0, 48, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 244, 137, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 121, 0, 0, 0, 16, 254, 255, 255, 234, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 255, 255, 255, 152, 0, 0, 0, 0, 0, 185, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 255, 129, 0, 0, 48, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 241, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 35, 139, 131, 124, 116, 109, 101, 96, 96, 96, 96, 96, 114, 255, 255, 255, 72, 0, 0, 0, 71, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 247, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 255, 255, 231, 140, 0, 0, 0, 0, 0, 178, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 233, 255, 255, 255, 112, 0, 0, 17, 87, 73, 64, 57, 52, 50, 48, 48, 48, 48, 48, 48, 100, 255, 255, 255, 113, 48, 48, 48, 48, 48, 49, 52, 55, 58, 63, 74, 84, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 186, 144, 147, 167, 193, 248, 255, 255, 255, 255, 255, 251, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 255, 255, 255, 24, 0, 0, 0, 136, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 134, 53, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 255, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 11, 91, 223, 255, 255, 255, 255, 251, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 255, 255, 230, 0, 0, 0, 0, 206, 255, 255, 214, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 212, 255, 255, 255, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 221, 255, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 8, 176, 255, 255, 255, 255, 211, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 255, 255, 172, 0, 0, 0, 27, 254, 255, 255, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 255, 255, 224, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 255, 255, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 255, 255, 255, 121, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 226, 255, 255, 226, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 181, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 4, 187, 255, 255, 255, 255, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 0, 0, 210, 255, 255, 114, 0, 0, 0, 119, 255, 255, 253, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 255, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 220, 255, 255, 255, 255, 255, 112, 0, 0, 0, 0, 84, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 196, 255, 255, 255, 201, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 32, 250, 255, 255, 255, 186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 86, 239, 121, 0, 0, 0, 0, 0, 15, 253, 255, 255, 57, 0, 0, 0, 213, 255, 255, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 255, 255, 255, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 255, 255, 255, 255, 255, 255, 112, 0, 0, 0, 0, 112, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 255, 255, 255, 250, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 143, 255, 255, 251, 61, 0, 0, 0, 0, 79, 255, 255, 248, 6, 0, 0, 75, 255, 255, 255, 94, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 237, 2, 0, 0, 0, 0, 0, 0, 0, 80, 96, 84, 74, 69, 65, 64, 64, 64, 27, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 11, 231, 255, 255, 208, 240, 255, 255, 112, 0, 0, 0, 0, 97, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 255, 220, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 248, 255, 255, 248, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 236, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 255, 255, 255, 255, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 167, 255, 255, 255, 231, 24, 0, 0, 0, 153, 255, 255, 195, 0, 0, 0, 197, 255, 255, 243, 11, 0, 0, 0, 192, 235, 205, 170, 100, 0, 0, 0, 53, 255, 255, 255, 171, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 105, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 134, 255, 255, 255, 85, 240, 255, 255, 112, 0, 0, 0, 0, 90, 255, 255, 255, 88, 32, 32, 32, 32, 32, 32, 88, 255, 255, 255, 102, 32, 32, 32, 32, 32, 32, 32, 255, 255, 255, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 255, 255, 255, 255, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 43, 64, 72, 51, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 57, 72, 72, 55, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 4, 43, 69, 73, 55, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 58, 74, 69, 52, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 11, 77, 108, 118, 94, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 8, 201, 255, 255, 255, 191, 3, 0, 0, 227, 255, 255, 128, 0, 0, 64, 255, 255, 255, 159, 0, 0, 0, 0, 194, 255, 255, 255, 154, 0, 0, 0, 53, 153, 198, 249, 107, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 97, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 36, 248, 255, 255, 214, 2, 240, 255, 255, 112, 0, 0, 0, 0, 86, 255, 255, 255, 64, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227, 255, 255, 255, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 179, 244, 255, 255, 255, 255, 250, 191, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 136, 225, 255, 255, 255, 255, 255, 255, 210, 112, 7, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 29, 155, 241, 255, 255, 255, 255, 250, 175, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 130, 222, 255, 255, 255, 255, 255, 253, 202, 100, 3, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 5, 137, 242, 255, 255, 255, 255, 255, 212, 79, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 24, 229, 255, 255, 255, 130, 0, 49, 255, 255, 255, 61, 0, 0, 185, 255, 255, 255, 65, 0, 0, 0, 0, 197, 255, 255, 255, 120, 0, 0, 0, 0, 0, 0, 8, 11, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 250, 245, 248, 255, 255, 255, 89, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 2, 194, 255, 255, 255, 90, 0, 240, 255, 255, 112, 0, 0, 0, 0, 81, 255, 255, 255, 64, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 193, 255, 255, 255, 194, 0, 0, 0, 0, 0, 0, 0, 25, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 181, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 239, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 217, 37, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 71, 238, 255, 255, 255, 255, 255, 255, 255, 255, 243, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 237, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 198, 21, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 12, 199, 255, 255, 255, 255, 255, 255, 255, 255, 255, 160, 5, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 58, 250, 255, 255, 252, 57, 125, 255, 255, 234, 3, 0, 0, 22, 101, 201, 227, 2, 0, 0, 0, 0, 202, 255, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 16, 3, 0, 0, 128, 255, 255, 255, 80, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 26, 223, 255, 255, 216, 2, 0, 240, 255, 255, 112, 0, 0, 0, 0, 87, 255, 255, 255, 64, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 255, 255, 255, 214, 0, 0, 0, 0, 0, 0, 44, 229, 255, 255, 255, 255, 252, 230, 237, 255, 255, 255, 255, 255, 208, 9, 0, 0, 0, 0, 0, 0, 0, 0, 74, 252, 255, 255, 255, 255, 249, 231, 236, 254, 255, 255, 255, 255, 228, 18, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 87, 253, 255, 255, 245, 198, 185, 233, 255, 255, 255, 255, 233, 17, 0, 0, 0, 0, 0, 0, 0, 90, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 199, 3, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 175, 255, 255, 255, 250, 231, 249, 255, 255, 255, 255, 255, 173, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 110, 255, 255, 255, 220, 208, 255, 255, 153, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 210, 255, 255, 255, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 74, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 17, 192, 255, 90, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 95, 255, 255, 255, 64, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 255, 255, 255, 228, 0, 0, 0, 0, 0, 19, 222, 255, 255, 255, 217, 89, 11, 0, 0, 26, 126, 247, 255, 255, 255, 154, 0, 0, 0, 0, 0, 0, 0, 7, 231, 255, 255, 255, 194, 58, 4, 0, 0, 8, 82, 206, 255, 255, 255, 142, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 154, 247, 255, 251, 130, 15, 0, 0, 3, 117, 254, 255, 255, 255, 123, 0, 0, 0, 0, 0, 0, 29, 243, 255, 255, 255, 226, 104, 42, 20, 26, 55, 130, 248, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 231, 90, 6, 0, 2, 66, 200, 255, 255, 255, 255, 109, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 184, 255, 255, 255, 255, 255, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 255, 255, 255, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 71, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 21, 183, 2, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 103, 255, 255, 255, 112, 64, 64, 64, 64, 64, 64, 112, 255, 255, 255, 124, 64, 64, 64, 64, 64, 64, 64, 255, 255, 255, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 148, 255, 255, 255, 235, 0, 0, 0, 0, 0, 164, 255, 255, 255, 193, 12, 0, 0, 0, 0, 0, 0, 72, 255, 255, 255, 252, 29, 0, 0, 0, 0, 0, 0, 75, 255, 255, 255, 215, 7, 0, 0, 0, 0, 0, 0, 18, 241, 255, 255, 227, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 255, 255, 247, 71, 0, 0, 0, 0, 0, 0, 139, 255, 255, 255, 201, 0, 0, 0, 0, 0, 0, 139, 255, 255, 255, 231, 30, 0, 0, 0, 0, 0, 0, 93, 255, 255, 255, 188, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 226, 29, 0, 0, 0, 0, 0, 4, 182, 255, 255, 255, 238, 10, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 239, 255, 255, 255, 255, 241, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 255, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 68, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 111, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 255, 255, 255, 236, 0, 0, 0, 0, 37, 252, 255, 255, 244, 25, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 129, 0, 0, 0, 0, 0, 0, 106, 255, 255, 255, 138, 0, 0, 0, 0, 0, 0, 0, 0, 164, 224, 224, 223, 4, 0, 0, 0, 0, 0, 96, 255, 255, 255, 255, 255, 87, 0, 0, 0, 0, 0, 0, 0, 21, 253, 255, 255, 240, 0, 0, 0, 0, 0, 0, 215, 255, 255, 255, 109, 0, 0, 0, 0, 0, 0, 0, 1, 224, 255, 255, 243, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 22, 243, 255, 255, 255, 103, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 255, 255, 255, 255, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 255, 255, 255, 255, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 65, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 160, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 119, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 255, 255, 255, 166, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 236, 255, 255, 236, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 206, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 255, 255, 255, 229, 0, 0, 0, 0, 132, 255, 255, 255, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 255, 255, 255, 190, 0, 0, 0, 0, 0, 0, 90, 255, 255, 255, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 255, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 215, 255, 255, 255, 0, 0, 0, 0, 0, 0, 62, 64, 64, 64, 11, 0, 0, 0, 0, 0, 0, 0, 0, 193, 255, 255, 255, 9, 0, 0, 0, 0, 0, 192, 255, 255, 255, 186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 255, 255, 255, 176, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 226, 255, 255, 255, 239, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 255, 255, 255, 255, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 0, 0, 9, 125, 16, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 170, 255, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 94, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 220, 255, 255, 255, 199, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 255, 255, 255, 217, 0, 0, 0, 0, 198, 255, 255, 255, 153, 112, 112, 112, 112, 112, 112, 112, 112, 112, 138, 255, 255, 255, 241, 1, 0, 0, 0, 0, 0, 35, 255, 255, 255, 252, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 254, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 140, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 255, 255, 255, 232, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 255, 255, 255, 255, 255, 186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 255, 255, 255, 255, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 0, 176, 255, 255, 224, 0, 0, 1, 90, 226, 255, 32, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 0, 210, 255, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 9, 14, 0, 0, 0, 0, 0, 0, 126, 255, 255, 255, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, 255, 255, 255, 194, 0, 0, 0, 0, 247, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 184, 255, 255, 255, 254, 187, 115, 66, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 64, 108, 157, 219, 255, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 255, 255, 255, 255, 13, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 255, 255, 255, 255, 255, 255, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 255, 255, 246, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 0, 179, 255, 255, 224, 0, 65, 202, 255, 255, 255, 56, 0, 0, 240, 255, 255, 160, 0, 0, 0, 0, 0, 95, 255, 255, 255, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 0, 18, 197, 175, 0, 0, 0, 0, 0, 0, 145, 255, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 255, 255, 255, 199, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 244, 255, 255, 244, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 226, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 255, 255, 255, 165, 0, 0, 0, 12, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 0, 0, 0, 0, 0, 0, 29, 227, 255, 255, 255, 255, 255, 255, 255, 232, 181, 112, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 4, 83, 164, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 253, 255, 255, 255, 30, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 254, 255, 255, 206, 255, 255, 255, 233, 16, 0, 0, 0, 0, 0, 0, 0, 0, 2, 237, 255, 255, 255, 255, 255, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 0, 214, 255, 255, 238, 189, 255, 255, 255, 255, 255, 90, 0, 0, 240, 255, 255, 160, 0, 0, 99, 176, 219, 255, 255, 255, 255, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 55, 227, 255, 255, 119, 0, 0, 0, 0, 0, 175, 255, 255, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 255, 255, 255, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 252, 255, 255, 255, 124, 0, 0, 0, 27, 255, 255, 255, 255, 145, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 24, 0, 0, 0, 0, 0, 0, 0, 22, 160, 250, 255, 255, 255, 255, 255, 255, 255, 255, 254, 178, 35, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 73, 222, 255, 255, 255, 255, 255, 255, 255, 255, 234, 160, 209, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 255, 255, 255, 43, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 255, 255, 255, 46, 179, 255, 255, 255, 145, 0, 0, 0, 0, 0, 0, 0, 0, 67, 255, 255, 255, 231, 255, 255, 222, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 47, 255, 255, 255, 255, 255, 255, 255, 255, 222, 117, 22, 0, 0, 240, 255, 255, 160, 0, 0, 56, 255, 255, 255, 255, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 19, 219, 255, 255, 254, 85, 0, 0, 0, 0, 210, 255, 255, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 255, 255, 255, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 255, 255, 255, 255, 69, 0, 0, 0, 14, 255, 255, 255, 255, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 94, 154, 199, 242, 255, 255, 255, 255, 255, 255, 243, 55, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 102, 254, 255, 255, 255, 255, 230, 184, 143, 98, 47, 2, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 255, 255, 32, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 52, 254, 255, 255, 185, 0, 42, 252, 255, 255, 251, 42, 0, 0, 0, 0, 0, 0, 0, 179, 255, 255, 252, 61, 254, 255, 255, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 202, 255, 255, 255, 255, 255, 255, 212, 89, 3, 0, 0, 0, 0, 240, 255, 255, 160, 0, 0, 0, 203, 255, 255, 255, 255, 177, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 0, 39, 239, 255, 255, 247, 66, 0, 0, 8, 250, 255, 255, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 255, 255, 252, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 255, 255, 255, 247, 11, 0, 0, 0, 0, 250, 255, 255, 255, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 34, 95, 176, 252, 255, 255, 255, 225, 8, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 39, 251, 255, 255, 255, 168, 45, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 255, 255, 255, 255, 15, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 191, 255, 255, 255, 67, 0, 0, 149, 255, 255, 255, 187, 0, 0, 0, 0, 0, 0, 36, 253, 255, 255, 175, 0, 182, 255, 255, 238, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 124, 255, 255, 255, 255, 217, 88, 2, 0, 0, 0, 0, 0, 0, 244, 255, 255, 166, 0, 0, 0, 118, 251, 208, 143, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 64, 249, 255, 255, 246, 69, 0, 60, 255, 255, 255, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 255, 255, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 17, 240, 255, 255, 255, 172, 0, 0, 0, 0, 0, 207, 255, 255, 255, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 16, 16, 16, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 248, 255, 255, 255, 88, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 150, 255, 255, 255, 185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 255, 255, 255, 238, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 85, 255, 255, 255, 191, 0, 0, 0, 19, 238, 255, 255, 255, 80, 0, 0, 0, 0, 0, 168, 255, 255, 255, 59, 0, 64, 255, 255, 255, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 8, 222, 255, 228, 101, 3, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 255, 173, 0, 0, 0, 7, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 88, 254, 255, 255, 249, 96, 134, 255, 255, 254, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 254, 255, 255, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 158, 255, 255, 255, 255, 64, 0, 0, 0, 0, 0, 141, 255, 255, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 255, 255, 255, 66, 0, 0, 0, 0, 0, 125, 128, 128, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 255, 255, 255, 142, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 212, 255, 255, 255, 81, 0, 0, 0, 0, 0, 0, 0, 0, 12, 226, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142, 255, 255, 255, 182, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 17, 228, 255, 255, 255, 55, 0, 0, 0, 0, 111, 255, 255, 255, 221, 7, 0, 0, 0, 69, 255, 255, 255, 189, 0, 0, 0, 189, 255, 255, 255, 109, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 0, 74, 121, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 255, 255, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 255, 255, 255, 255, 244, 255, 255, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 255, 255, 255, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 1, 145, 255, 255, 255, 255, 185, 0, 0, 0, 0, 0, 0, 50, 255, 255, 255, 247, 38, 0, 0, 0, 0, 0, 0, 0, 0, 67, 255, 255, 255, 249, 14, 0, 0, 0, 0, 0, 232, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 255, 255, 255, 151, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 233, 255, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 2, 169, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 253, 56, 0, 0, 0, 0, 0, 0, 0, 19, 238, 255, 255, 255, 112, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 170, 255, 255, 255, 174, 0, 0, 0, 0, 0, 4, 217, 255, 245, 114, 2, 0, 0, 20, 228, 255, 255, 254, 55, 0, 0, 0, 51, 253, 255, 255, 250, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 255, 255, 255, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 255, 255, 255, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 255, 255, 255, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 96, 0, 0, 0, 0, 2, 68, 202, 255, 255, 255, 255, 236, 31, 0, 0, 0, 0, 0, 0, 0, 181, 255, 255, 255, 215, 33, 0, 0, 0, 0, 0, 0, 20, 216, 255, 255, 255, 164, 0, 0, 0, 0, 0, 0, 182, 255, 255, 255, 68, 0, 0, 0, 0, 0, 0, 0, 0, 169, 255, 255, 255, 122, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 218, 255, 255, 255, 142, 0, 0, 0, 0, 0, 0, 23, 178, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 223, 29, 0, 0, 0, 0, 0, 4, 179, 255, 255, 255, 243, 15, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 96, 255, 255, 255, 247, 34, 0, 0, 0, 0, 0, 0, 80, 188, 34, 0, 0, 0, 5, 191, 255, 255, 255, 158, 0, 0, 0, 0, 0, 154, 255, 255, 255, 245, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 255, 255, 255, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 255, 255, 255, 255, 255, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 232, 255, 255, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 176, 128, 131, 149, 174, 236, 255, 255, 255, 255, 255, 234, 55, 0, 0, 0, 0, 0, 0, 0, 0, 32, 236, 255, 255, 255, 240, 128, 41, 1, 0, 19, 95, 225, 255, 255, 255, 242, 33, 0, 0, 0, 0, 0, 0, 87, 255, 255, 255, 242, 120, 33, 0, 0, 0, 0, 23, 150, 255, 255, 255, 255, 45, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 160, 255, 255, 255, 253, 128, 23, 0, 16, 63, 155, 243, 255, 255, 255, 255, 255, 255, 24, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 233, 100, 15, 0, 10, 77, 204, 255, 255, 255, 255, 120, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 50, 244, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 167, 255, 255, 255, 229, 19, 0, 0, 0, 0, 0, 15, 221, 255, 255, 255, 248, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 255, 255, 255, 199, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 255, 255, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 255, 255, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 247, 255, 255, 255, 255, 246, 102, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 255, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 255, 255, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 206, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 242, 255, 255, 255, 255, 255, 252, 245, 255, 255, 255, 255, 255, 249, 79, 0, 0, 0, 0, 0, 0, 0, 0, 181, 255, 255, 255, 255, 255, 230, 207, 196, 217, 253, 255, 255, 255, 255, 159, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 47, 251, 255, 255, 255, 255, 255, 248, 255, 255, 255, 255, 255, 244, 220, 255, 255, 255, 62, 0, 0, 0, 0, 0, 192, 255, 255, 255, 195, 255, 255, 255, 255, 246, 255, 255, 255, 255, 255, 255, 180, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 28, 229, 255, 255, 255, 220, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 166, 255, 255, 255, 253, 65, 0, 0, 0, 0, 0, 0, 0, 41, 236, 255, 255, 255, 255, 158, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 247, 255, 255, 255, 255, 253, 172, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 144, 144, 144, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 245, 255, 255, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 235, 255, 255, 255, 255, 255, 255, 255, 198, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 255, 255, 255, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 255, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 103, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 218, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 228, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 169, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 164, 7, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 93, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 229, 55, 152, 255, 255, 255, 152, 0, 0, 0, 0, 0, 192, 255, 255, 255, 21, 216, 255, 255, 255, 255, 255, 255, 255, 255, 255, 161, 6, 0, 0, 0, 0, 0,
|
||||
0, 0, 7, 208, 255, 255, 255, 254, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 194, 255, 255, 255, 255, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 233, 255, 255, 255, 255, 226, 100, 4, 0, 0, 0, 0, 0, 0, 0, 0, 120, 254, 255, 255, 255, 255, 255, 255, 255, 255, 216, 130, 58, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 255, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 241, 255, 255, 255, 160, 199, 255, 255, 255, 255, 255, 201, 102, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 254, 255, 255, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 255, 255, 234, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 248, 255, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 255, 250, 232, 202, 138, 71, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 105, 211, 255, 255, 255, 255, 255, 255, 230, 127, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 176, 248, 255, 255, 255, 255, 255, 255, 253, 187, 72, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 46, 179, 252, 255, 255, 255, 255, 255, 222, 123, 10, 0, 73, 255, 255, 255, 250, 48, 0, 0, 0, 0, 192, 255, 255, 255, 0, 11, 147, 243, 255, 255, 255, 255, 255, 202, 74, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 77, 225, 255, 255, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 99, 238, 255, 255, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 216, 255, 255, 255, 255, 255, 223, 132, 31, 0, 0, 0, 0, 1, 144, 255, 255, 255, 219, 85, 70, 173, 255, 255, 255, 255, 255, 255, 244, 194, 143, 104, 66, 36, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 26, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 255, 255, 122, 0, 0, 0, 0, 0, 0, 0, 31, 179, 255, 255, 255, 255, 136, 0, 3, 122, 245, 255, 255, 255, 255, 255, 251, 199, 135, 81, 38, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 255, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 255, 255, 242, 0, 0, 0, 0, 0, 0, 119, 229, 229, 242, 255, 255, 255, 255, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 16, 16, 16, 16, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 76, 97, 105, 86, 43, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 50, 86, 101, 108, 96, 66, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 16, 16, 16, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 73, 101, 104, 81, 41, 0, 0, 0, 0, 0, 15, 16, 16, 16, 8, 0, 0, 0, 0, 12, 16, 16, 16, 0, 0, 0, 9, 67, 95, 103, 80, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 14, 169, 222, 12, 0, 0, 0, 0, 0, 0, 0, 0, 2, 80, 207, 255, 255, 255, 255, 255, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 178, 255, 255, 255, 255, 255, 227, 21, 0, 0, 0, 4, 163, 255, 255, 255, 222, 24, 0, 0, 0, 54, 175, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 244, 230, 217, 205, 198, 191, 186, 182, 178, 176, 176, 176, 180, 184, 190, 198, 209, 223, 240, 254, 230, 10, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 129, 0, 0, 0, 0, 0, 36, 157, 250, 255, 255, 255, 249, 109, 0, 0, 0, 0, 29, 163, 252, 255, 255, 255, 255, 255, 255, 255, 255, 251, 228, 202, 183, 173, 69, 0, 0, 0, 0, 0, 63, 255, 255, 255, 239, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 255, 255, 252, 0, 0, 0, 0, 0, 0, 27, 253, 255, 255, 255, 255, 255, 255, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 255, 255, 255, 251, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 114, 249, 255, 255, 253, 57, 0, 0, 0, 7, 175, 255, 255, 255, 246, 48, 0, 0, 0, 0, 0, 0, 33, 132, 219, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 255, 255, 255, 137, 0, 0, 15, 95, 184, 252, 255, 255, 255, 255, 219, 51, 0, 0, 0, 0, 0, 0, 0, 34, 148, 239, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 190, 1, 0, 0, 0, 0, 8, 217, 255, 255, 255, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 255, 255, 255, 255, 6, 0, 0, 0, 0, 0, 0, 205, 255, 255, 255, 255, 255, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 255, 255, 255, 236, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 210, 255, 152, 0, 0, 0, 0, 14, 184, 255, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 120, 184, 231, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 244, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 255, 255, 255, 145, 0, 12, 194, 255, 255, 255, 255, 255, 249, 141, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 85, 163, 235, 255, 255, 255, 255, 255, 255, 255, 54, 0, 0, 0, 0, 0, 25, 141, 229, 255, 246, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 112, 112, 112, 112, 5, 0, 0, 0, 0, 0, 0, 150, 255, 252, 207, 126, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121, 255, 193, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 124, 20, 0, 0, 0, 0, 0, 3, 149, 255, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 66, 99, 127, 152, 175, 195, 214, 231, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 255, 255, 255, 153, 0, 0, 5, 168, 255, 255, 254, 172, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 39, 92, 135, 171, 201, 219, 199, 0, 0, 0, 0, 0, 0, 0, 0, 8, 118, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 52, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 17, 29, 39, 47, 54, 61, 66, 70, 74, 77, 78, 79, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 80, 80, 80, 49, 0, 0, 0, 8, 210, 143, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
static const int g_txt_welcome_w = 270;
|
||||
static const int g_txt_welcome_h = 42;
|
||||
static const unsigned char g_txt_welcome[270*42] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 105, 70, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 237, 178, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 134, 212, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 118, 242, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 226, 128, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 255, 255, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 254, 255, 255, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, 255, 255, 108, 0, 0, 0, 0, 0, 0, 33, 90, 166, 242, 255, 255, 243, 47, 12, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 193, 255, 255, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 255, 255, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 255, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 255, 255, 198, 0, 0, 0, 0, 0, 216, 255, 255, 255, 255, 255, 238, 183, 105, 82, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 250, 255, 244, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 255, 255, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 255, 255, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 245, 255, 254, 30, 0, 0, 0, 0, 222, 255, 251, 174, 109, 46, 1, 0, 0, 73, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 255, 255, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 255, 255, 191, 104, 104, 104, 104, 104, 104, 104, 165, 255, 255, 165, 104, 104, 104, 104, 104, 104, 104, 106, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 28, 147, 136, 127, 123, 120, 120, 120, 120, 120, 120, 120, 103, 0, 0, 0, 174, 255, 255, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 255, 255, 114, 0, 0, 0, 0, 215, 255, 232, 0, 0, 0, 0, 0, 0, 64, 255, 255, 154, 64, 64, 64, 64, 154, 255, 255, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 255, 255, 53, 0, 166, 174, 164, 160, 157, 156, 156, 156, 156, 174, 255, 255, 204, 156, 156, 156, 156, 157, 160, 163, 170, 180, 114, 0, 0, 0, 0, 0, 0, 0, 39, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 192, 192, 192, 192, 187, 170, 150, 98, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 192, 192, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 192, 192, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 48, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 185, 0, 0, 0, 231, 255, 242, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 255, 255, 193, 0, 0, 0, 0, 208, 255, 232, 0, 0, 0, 0, 0, 0, 59, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 65, 0, 0, 0, 0, 0, 0, 0, 0, 29, 252, 255, 215, 0, 0, 228, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 156, 0, 0, 0, 0, 0, 0, 0, 33, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 255, 255, 255, 255, 255, 255, 255, 182, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 44, 231, 224, 216, 209, 201, 200, 200, 200, 203, 255, 255, 137, 0, 0, 32, 255, 255, 252, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 235, 36, 0, 0, 0, 0, 0, 0, 11, 247, 255, 251, 12, 0, 0, 0, 200, 255, 232, 0, 0, 0, 0, 0, 0, 56, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 58, 0, 0, 0, 0, 0, 0, 0, 0, 139, 255, 255, 150, 0, 0, 173, 184, 174, 170, 166, 164, 164, 164, 164, 181, 255, 255, 208, 164, 164, 164, 164, 166, 169, 172, 180, 190, 120, 0, 0, 0, 0, 0, 0, 0, 31, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 251, 236, 241, 255, 255, 255, 255, 255, 250, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 255, 255, 88, 0, 0, 93, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 130, 93, 23, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 53, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 0, 0, 14, 240, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 6, 58, 149, 251, 255, 255, 255, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 255, 255, 37, 0, 0, 163, 255, 249, 88, 84, 84, 84, 84, 84, 84, 84, 84, 179, 255, 255, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 0, 0, 122, 255, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 57, 240, 255, 255, 225, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 255, 235, 0, 0, 7, 238, 255, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 255, 247, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 0, 12, 235, 255, 255, 255, 148, 0, 0, 0, 42, 68, 68, 68, 68, 68, 68, 68, 103, 255, 255, 159, 68, 68, 68, 68, 68, 68, 68, 68, 3, 0, 0, 0, 0, 0, 0, 0, 0, 26, 255, 255, 207, 140, 140, 140, 140, 140, 140, 140, 187, 255, 255, 187, 140, 140, 140, 140, 140, 140, 140, 141, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 85, 255, 255, 255, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 21, 176, 68, 0, 0, 0, 0, 199, 255, 178, 0, 0, 84, 255, 255, 86, 0, 0, 0, 0, 0, 0, 0, 0, 28, 254, 255, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 0, 127, 255, 255, 255, 255, 148, 0, 0, 0, 150, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 25, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 207, 255, 255, 185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 28, 226, 255, 232, 25, 0, 0, 11, 250, 255, 120, 0, 0, 199, 255, 241, 9, 0, 4, 59, 29, 2, 0, 0, 0, 115, 255, 255, 107, 0, 0, 0, 0, 0, 45, 137, 125, 117, 113, 112, 112, 63, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 22, 242, 255, 205, 244, 255, 148, 0, 0, 0, 136, 255, 255, 223, 216, 216, 216, 216, 223, 255, 255, 235, 216, 216, 216, 216, 216, 246, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 255, 255, 208, 144, 144, 144, 144, 144, 144, 144, 189, 255, 255, 189, 144, 144, 144, 144, 144, 144, 144, 145, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 122, 255, 255, 244, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 172, 255, 255, 194, 3, 0, 80, 255, 255, 57, 0, 66, 255, 255, 155, 0, 0, 17, 255, 255, 249, 58, 0, 0, 173, 255, 255, 39, 0, 0, 0, 0, 0, 80, 255, 255, 255, 255, 255, 255, 140, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 157, 255, 255, 80, 244, 255, 148, 0, 0, 0, 130, 255, 255, 48, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 192, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 65, 255, 255, 255, 37, 0, 0, 0, 0, 0, 0, 5, 79, 145, 173, 179, 152, 88, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 111, 159, 179, 180, 156, 101, 17, 0, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 13, 103, 154, 180, 171, 123, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 109, 160, 181, 177, 152, 96, 12, 0, 0, 0, 0, 0, 0, 80, 255, 255, 128, 0, 55, 159, 205, 214, 182, 105, 8, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 10, 207, 255, 255, 136, 0, 155, 255, 242, 4, 0, 187, 255, 255, 60, 0, 0, 20, 255, 255, 255, 34, 0, 0, 0, 15, 71, 0, 0, 0, 0, 0, 0, 80, 255, 255, 250, 249, 255, 255, 131, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 63, 254, 255, 210, 1, 244, 255, 148, 0, 0, 0, 125, 255, 255, 48, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 192, 255, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 24, 255, 255, 255, 75, 0, 0, 0, 0, 0, 76, 223, 255, 255, 255, 255, 255, 255, 225, 63, 0, 0, 0, 0, 0, 0, 0, 1, 132, 251, 255, 255, 255, 255, 255, 255, 241, 93, 0, 0, 0, 0, 0, 8, 255, 255, 200, 0, 79, 240, 255, 255, 255, 255, 255, 245, 76, 0, 0, 0, 0, 0, 0, 2, 131, 250, 255, 255, 255, 255, 255, 255, 236, 76, 0, 0, 0, 0, 0, 80, 255, 255, 128, 121, 253, 255, 255, 255, 255, 255, 223, 48, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 33, 238, 255, 254, 66, 229, 255, 167, 0, 0, 26, 111, 184, 1, 0, 0, 25, 255, 255, 254, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 14, 2, 0, 96, 255, 255, 123, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 92, 249, 255, 84, 0, 244, 255, 148, 0, 0, 0, 130, 255, 255, 48, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 192, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 1, 255, 255, 255, 91, 0, 0, 0, 0, 108, 254, 255, 255, 228, 182, 191, 239, 255, 255, 250, 62, 0, 0, 0, 0, 0, 0, 141, 255, 255, 255, 210, 175, 180, 222, 255, 255, 254, 78, 0, 0, 0, 0, 8, 255, 255, 200, 93, 254, 255, 208, 144, 165, 239, 255, 255, 242, 25, 0, 0, 0, 0, 0, 154, 255, 255, 255, 244, 214, 214, 248, 255, 255, 249, 50, 0, 0, 0, 0, 80, 255, 255, 210, 255, 255, 219, 175, 197, 252, 255, 255, 242, 40, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 80, 255, 255, 239, 255, 255, 84, 0, 0, 0, 0, 0, 0, 0, 0, 36, 255, 255, 242, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 118, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 72, 206, 1, 0, 244, 255, 148, 0, 0, 0, 138, 255, 255, 48, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 192, 255, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 246, 255, 255, 104, 0, 0, 0, 64, 252, 255, 245, 95, 3, 0, 0, 13, 150, 255, 255, 225, 4, 0, 0, 0, 0, 29, 253, 255, 249, 71, 0, 0, 0, 0, 95, 255, 255, 206, 0, 0, 0, 0, 8, 255, 255, 235, 249, 251, 101, 0, 0, 0, 31, 225, 255, 255, 124, 0, 0, 0, 0, 62, 255, 255, 254, 112, 5, 0, 0, 10, 153, 255, 255, 174, 0, 0, 0, 0, 80, 255, 255, 255, 253, 107, 0, 0, 0, 35, 211, 255, 255, 202, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 157, 255, 255, 255, 248, 12, 0, 0, 0, 0, 0, 0, 0, 0, 58, 255, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 115, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 0, 19, 0, 0, 244, 255, 148, 0, 0, 0, 146, 255, 255, 243, 240, 240, 240, 240, 243, 255, 255, 247, 240, 240, 240, 240, 240, 252, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 37, 255, 255, 148, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 239, 255, 255, 111, 0, 0, 0, 202, 255, 255, 96, 0, 0, 0, 0, 0, 2, 211, 255, 255, 83, 0, 0, 0, 0, 76, 255, 255, 179, 0, 0, 0, 0, 0, 0, 200, 232, 229, 2, 0, 0, 0, 8, 255, 255, 255, 255, 92, 0, 0, 0, 0, 0, 98, 255, 255, 176, 0, 0, 0, 0, 153, 255, 255, 160, 0, 0, 0, 0, 0, 9, 238, 255, 240, 0, 0, 0, 0, 80, 255, 255, 255, 130, 0, 0, 0, 0, 0, 34, 249, 255, 255, 63, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 17, 233, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 255, 255, 246, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 2, 0, 52, 255, 255, 120, 0, 0, 0, 0, 120, 255, 255, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 154, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 9, 0, 0, 0, 0, 0, 0, 0, 0, 45, 255, 255, 205, 136, 136, 136, 136, 136, 136, 136, 184, 255, 255, 184, 136, 136, 136, 136, 136, 136, 136, 137, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 98, 0, 0, 43, 255, 255, 223, 2, 0, 0, 0, 0, 0, 0, 125, 255, 255, 148, 0, 0, 0, 0, 62, 255, 255, 205, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 255, 172, 0, 0, 0, 0, 0, 0, 40, 255, 255, 191, 0, 0, 0, 0, 35, 48, 48, 18, 0, 0, 0, 0, 0, 4, 220, 255, 255, 8, 0, 0, 0, 80, 255, 255, 243, 11, 0, 0, 0, 0, 0, 0, 166, 255, 255, 139, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 188, 255, 255, 255, 74, 0, 0, 0, 0, 0, 0, 0, 0, 129, 255, 255, 255, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 196, 255, 232, 0, 0, 11, 131, 138, 0, 52, 255, 255, 120, 0, 0, 0, 0, 140, 255, 255, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 49, 80, 80, 80, 80, 80, 80, 80, 144, 255, 255, 134, 80, 80, 80, 80, 80, 80, 80, 80, 4, 0, 0, 0, 0, 0, 0, 0, 0, 54, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 5, 255, 255, 255, 84, 0, 0, 106, 255, 255, 241, 212, 212, 212, 212, 212, 212, 212, 227, 255, 255, 195, 0, 0, 0, 0, 9, 237, 255, 255, 159, 47, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 255, 57, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 62, 125, 214, 255, 255, 255, 12, 0, 0, 0, 80, 255, 255, 179, 0, 0, 0, 0, 0, 0, 0, 99, 255, 255, 190, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 50, 255, 255, 255, 255, 227, 12, 0, 0, 0, 0, 0, 0, 0, 186, 255, 255, 255, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 198, 255, 232, 3, 100, 230, 255, 166, 0, 52, 255, 255, 120, 0, 0, 0, 17, 223, 255, 255, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 0, 0, 125, 107, 0, 0, 0, 0, 116, 255, 255, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 255, 255, 224, 184, 184, 184, 184, 184, 184, 184, 213, 255, 255, 213, 184, 184, 184, 184, 184, 184, 184, 185, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 38, 255, 255, 255, 61, 0, 0, 135, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 213, 0, 0, 0, 0, 0, 94, 254, 255, 255, 255, 244, 204, 155, 92, 18, 0, 0, 0, 0, 0, 0, 8, 255, 255, 240, 2, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 0, 0, 0, 28, 113, 175, 223, 254, 255, 255, 255, 255, 255, 255, 12, 0, 0, 0, 80, 255, 255, 142, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 212, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 176, 255, 254, 191, 255, 255, 140, 0, 0, 0, 0, 0, 0, 7, 246, 255, 255, 255, 220, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 1, 232, 255, 246, 218, 255, 255, 255, 190, 0, 52, 255, 255, 120, 0, 73, 200, 246, 255, 255, 250, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 0, 153, 255, 249, 58, 0, 0, 0, 143, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 255, 255, 118, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 79, 255, 255, 254, 13, 0, 0, 147, 255, 255, 184, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 94, 0, 0, 0, 0, 0, 0, 66, 191, 252, 255, 255, 255, 255, 255, 247, 141, 8, 0, 0, 0, 0, 8, 255, 255, 211, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 0, 4, 139, 250, 255, 255, 255, 255, 251, 205, 130, 215, 255, 255, 12, 0, 0, 0, 80, 255, 255, 131, 0, 0, 0, 0, 0, 0, 0, 55, 255, 255, 223, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 52, 255, 255, 182, 27, 246, 255, 250, 40, 0, 0, 0, 0, 0, 93, 255, 255, 175, 255, 255, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 97, 255, 255, 255, 255, 255, 209, 91, 6, 0, 52, 255, 255, 120, 0, 13, 241, 255, 255, 255, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 0, 44, 241, 255, 236, 39, 0, 0, 178, 255, 245, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 150, 255, 255, 215, 0, 0, 0, 132, 255, 255, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 69, 113, 161, 226, 255, 255, 255, 172, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 0, 153, 255, 255, 242, 152, 91, 48, 8, 0, 0, 196, 255, 255, 12, 0, 0, 0, 80, 255, 255, 145, 0, 0, 0, 0, 0, 0, 0, 68, 255, 255, 209, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 190, 255, 255, 66, 0, 131, 255, 255, 184, 0, 0, 0, 0, 0, 204, 255, 250, 22, 206, 255, 228, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 112, 255, 255, 255, 210, 81, 1, 0, 0, 0, 55, 255, 255, 123, 0, 0, 163, 233, 177, 88, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 0, 0, 70, 251, 255, 229, 38, 2, 239, 255, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 255, 255, 41, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 13, 234, 255, 255, 130, 0, 0, 0, 98, 255, 255, 182, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 88, 251, 255, 255, 53, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 37, 254, 255, 248, 42, 0, 0, 0, 0, 0, 0, 196, 255, 255, 12, 0, 0, 0, 80, 255, 255, 189, 0, 0, 0, 0, 0, 0, 0, 107, 255, 255, 184, 0, 0,
|
||||
0, 0, 0, 0, 0, 84, 255, 255, 191, 0, 0, 11, 229, 255, 255, 78, 0, 0, 0, 91, 255, 255, 156, 0, 93, 255, 255, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 4, 213, 223, 92, 2, 0, 0, 0, 0, 0, 58, 255, 255, 131, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 0, 0, 0, 100, 255, 255, 235, 112, 255, 255, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 217, 255, 237, 2, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 0, 0, 150, 255, 255, 252, 28, 0, 0, 0, 33, 255, 255, 244, 16, 0, 0, 0, 0, 0, 0, 64, 255, 255, 235, 0, 0, 0, 0, 115, 160, 160, 14, 0, 0, 0, 0, 0, 0, 155, 255, 255, 109, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 99, 255, 255, 183, 0, 0, 0, 0, 0, 0, 34, 241, 255, 255, 12, 0, 0, 0, 80, 255, 255, 250, 24, 0, 0, 0, 0, 0, 0, 183, 255, 255, 129, 0, 0,
|
||||
0, 0, 0, 0, 21, 232, 255, 255, 55, 0, 0, 0, 93, 255, 255, 159, 0, 0, 18, 233, 255, 250, 34, 0, 2, 208, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 33, 7, 0, 0, 0, 0, 0, 0, 0, 63, 255, 255, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 0, 0, 0, 0, 117, 255, 255, 255, 255, 255, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 174, 0, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 200, 0, 0, 0, 0, 17, 155, 255, 255, 255, 127, 0, 0, 0, 0, 0, 185, 255, 255, 157, 1, 0, 0, 0, 0, 1, 178, 255, 255, 163, 0, 0, 0, 0, 159, 255, 255, 69, 0, 0, 0, 0, 0, 0, 160, 255, 255, 104, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 108, 255, 255, 196, 0, 0, 0, 0, 0, 31, 208, 255, 255, 255, 12, 0, 0, 0, 80, 255, 255, 255, 169, 1, 0, 0, 0, 0, 65, 255, 255, 255, 45, 0, 0,
|
||||
0, 0, 0, 0, 177, 255, 255, 167, 0, 0, 0, 0, 1, 189, 103, 1, 0, 5, 189, 255, 255, 137, 0, 0, 0, 68, 255, 255, 249, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 255, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 148, 0, 0, 0, 0, 0, 0, 0, 0, 131, 255, 255, 255, 237, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 255, 255, 107, 0, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 104, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 221, 96, 100, 119, 169, 241, 255, 255, 255, 177, 2, 0, 0, 0, 0, 0, 46, 246, 255, 255, 183, 59, 4, 4, 44, 169, 255, 255, 248, 42, 0, 0, 0, 0, 78, 255, 255, 223, 78, 7, 0, 0, 5, 101, 252, 255, 255, 45, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 66, 255, 255, 255, 120, 12, 3, 41, 129, 241, 255, 255, 255, 255, 16, 0, 0, 0, 80, 255, 255, 255, 255, 171, 37, 0, 14, 101, 240, 255, 255, 173, 0, 0, 0,
|
||||
0, 0, 0, 120, 255, 255, 242, 26, 0, 0, 0, 0, 0, 0, 0, 0, 1, 162, 255, 255, 217, 11, 0, 0, 0, 0, 144, 255, 255, 251, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 255, 255, 224, 81, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 255, 255, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 255, 150, 0, 0, 0, 0, 0, 0, 0, 0, 61, 250, 255, 255, 255, 203, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 255, 253, 26, 0, 0, 0, 0, 0, 0, 0, 0, 108, 255, 255, 107, 0, 0, 0, 0, 0, 0, 0, 5, 255, 255, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 255, 255, 255, 255, 255, 255, 255, 251, 134, 2, 0, 0, 0, 0, 0, 0, 0, 79, 246, 255, 255, 255, 253, 252, 255, 255, 255, 251, 89, 0, 0, 0, 0, 0, 0, 171, 255, 255, 255, 247, 222, 218, 245, 255, 255, 255, 156, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 2, 200, 255, 255, 255, 255, 252, 255, 255, 255, 226, 215, 255, 255, 56, 0, 0, 0, 80, 255, 255, 190, 251, 255, 255, 250, 255, 255, 255, 255, 215, 18, 0, 0, 0,
|
||||
0, 0, 85, 254, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 9, 167, 255, 255, 244, 48, 0, 0, 0, 0, 0, 4, 169, 255, 255, 255, 179, 33, 0, 0, 0, 0, 0, 0, 0, 111, 253, 255, 255, 255, 255, 211, 110, 25, 0, 0, 0, 0, 0, 0, 0, 0, 15, 44, 44, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 255, 152, 0, 0, 0, 0, 0, 0, 0, 77, 245, 255, 252, 235, 255, 255, 251, 159, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 255, 255, 186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 255, 255, 110, 0, 0, 0, 0, 0, 0, 0, 46, 255, 255, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 255, 255, 255, 255, 255, 224, 149, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 191, 255, 255, 255, 255, 255, 255, 207, 57, 0, 0, 0, 0, 0, 0, 0, 4, 126, 241, 255, 255, 255, 255, 255, 255, 244, 125, 2, 0, 0, 0, 0, 8, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 192, 0, 0, 0, 0, 19, 178, 255, 255, 255, 255, 255, 254, 170, 26, 148, 255, 255, 165, 0, 0, 0, 80, 255, 255, 128, 80, 238, 255, 255, 255, 255, 254, 166, 16, 0, 0, 0, 0,
|
||||
0, 0, 96, 238, 255, 196, 2, 0, 0, 0, 0, 0, 0, 0, 57, 213, 255, 255, 249, 72, 0, 0, 0, 0, 0, 0, 0, 3, 154, 255, 255, 255, 250, 158, 61, 0, 0, 0, 0, 137, 255, 255, 210, 113, 179, 255, 255, 255, 255, 210, 152, 102, 63, 30, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 18, 0, 0, 0, 0, 0, 0, 0, 252, 255, 155, 0, 0, 0, 0, 0, 17, 156, 255, 255, 248, 80, 18, 158, 255, 255, 255, 255, 214, 141, 79, 34, 2, 0, 0, 0, 0, 0, 0, 0, 0, 181, 255, 255, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 255, 255, 116, 0, 0, 0, 0, 115, 170, 179, 232, 255, 255, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 76, 76, 76, 76, 71, 53, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 106, 135, 141, 115, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 71, 117, 138, 143, 126, 81, 12, 0, 0, 0, 0, 0, 0, 2, 76, 76, 59, 0, 0, 0, 0, 0, 0, 0, 4, 76, 76, 57, 0, 0, 0, 0, 0, 0, 43, 112, 141, 134, 100, 30, 0, 0, 21, 76, 76, 75, 5, 0, 0, 23, 76, 76, 38, 0, 14, 91, 132, 139, 109, 36, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 28, 185, 37, 0, 0, 0, 0, 0, 0, 51, 171, 255, 255, 255, 245, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 249, 255, 255, 255, 98, 0, 0, 2, 156, 255, 255, 209, 14, 0, 0, 54, 171, 251, 255, 255, 255, 255, 255, 255, 255, 241, 228, 218, 212, 206, 201, 197, 198, 199, 201, 207, 217, 227, 243, 255, 105, 0, 0, 0, 0, 0, 0, 2, 255, 255, 162, 0, 0, 0, 24, 135, 242, 255, 255, 229, 61, 0, 0, 0, 65, 193, 255, 255, 255, 255, 255, 255, 249, 225, 203, 170, 12, 0, 0, 0, 80, 255, 255, 231, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 255, 255, 126, 0, 0, 0, 0, 77, 255, 255, 255, 255, 253, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 248, 255, 255, 228, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 212, 255, 171, 0, 0, 0, 115, 255, 255, 240, 36, 0, 0, 0, 0, 0, 25, 111, 189, 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 229, 6, 0, 0, 0, 0, 0, 0, 10, 255, 255, 170, 0, 64, 188, 252, 255, 255, 255, 174, 20, 0, 0, 0, 0, 0, 0, 45, 153, 233, 255, 255, 255, 255, 255, 255, 88, 0, 0, 0, 0, 190, 255, 255, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 212, 212, 112, 0, 0, 0, 0, 13, 253, 255, 252, 191, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 247, 186, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 134, 31, 0, 0, 0, 3, 148, 254, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 52, 99, 136, 164, 188, 209, 228, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 143, 0, 0, 0, 0, 0, 0, 0, 18, 255, 255, 178, 0, 6, 161, 255, 255, 207, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 107, 158, 185, 211, 215, 2, 0, 0, 0, 0, 0, 67, 188, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 74, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 16, 27, 35, 42, 48, 53, 56, 58, 59, 21, 0, 0, 0, 0, 0, 0, 0, 5, 60, 60, 42, 0, 0, 4, 152, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const int g_txt_setup_w = 384;
|
||||
static const int g_txt_setup_h = 30;
|
||||
static const unsigned char g_txt_setup[384*30] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 42, 56, 14, 0, 0, 0, 0, 0, 0, 0, 82, 158, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 56, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 47, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 130, 42, 0, 0, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 56, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 3, 0, 0, 0, 0, 0, 0, 1, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 115, 14, 0, 0, 0, 29, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 115, 14, 0, 0, 0, 29, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 17, 0, 0, 0, 0, 0, 0, 0, 40, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 51, 103, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 89, 111, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 172, 255, 44, 0, 0, 0, 0, 0, 0, 0, 140, 255, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 161, 4, 0, 0, 0, 0, 0, 0, 0, 4, 192, 192, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 72, 0, 0, 220, 255, 32, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 255, 234, 15, 13, 183, 173, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 255, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 33, 27, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0, 156, 255, 107, 0, 0, 0, 0, 0, 0, 4, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 255, 235, 15, 0, 0, 116, 255, 196, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 222, 198, 14, 0, 0, 0, 0, 60, 120, 120, 120, 120, 120, 120, 120, 43, 0, 0, 0, 0, 0, 0, 0, 0, 87, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 128, 0, 0, 0, 0, 0, 0, 0, 0, 75, 255, 235, 15, 0, 0, 116, 255, 196, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 250, 147, 0, 0, 0, 0, 0, 0, 159, 245, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 14, 34, 58, 91, 124, 157, 198, 247, 255, 255, 156, 0, 0, 0, 0, 0, 0, 0, 88, 186, 79, 0, 0, 0, 0, 0, 0, 19, 237, 250, 39, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 153, 255, 25, 0, 0, 36, 46, 40, 40, 40, 103, 255, 202, 40, 40, 40, 46, 58, 19, 0, 0, 91, 177, 170, 164, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 164, 171, 177, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 255, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 255, 165, 1, 0, 0, 0, 0, 0, 0, 0, 254, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 72, 147, 232, 255, 93, 0, 215, 255, 11, 26, 218, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 152, 255, 110, 0, 19, 224, 255, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 255, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 0, 0, 0, 149, 255, 100, 0, 0, 0, 0, 0, 0, 0, 240, 255, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 201, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 255, 124, 0, 0, 0, 198, 255, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 177, 255, 197, 9, 0, 0, 0, 130, 255, 255, 255, 255, 255, 255, 255, 82, 0, 0, 0, 0, 0, 0, 0, 0, 145, 255, 190, 168, 168, 184, 255, 179, 168, 168, 179, 255, 201, 168, 168, 168, 253, 221, 0, 0, 0, 0, 0, 0, 0, 0, 158, 255, 124, 0, 0, 0, 198, 255, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 255, 101, 0, 0, 0, 0, 0, 0, 220, 255, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 203, 211, 215, 222, 229, 241, 253, 255, 255, 255, 255, 255, 237, 208, 184, 161, 145, 132, 32, 0, 0, 0, 0, 0, 0, 175, 255, 156, 0, 0, 0, 0, 0, 0, 0, 117, 255, 167, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 160, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 80, 0, 0, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 104, 0, 0, 0, 5, 46, 36, 32, 32, 32, 32, 32, 39, 255, 221, 32, 32, 32, 32, 32, 33, 42, 46, 0, 0, 0, 0, 0, 0, 13, 208, 255, 130, 0, 0, 0, 0, 0, 0, 0, 247, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 88, 116, 158, 208, 252, 255, 255, 233, 175, 94, 0, 211, 255, 3, 58, 240, 254, 107, 0, 0, 0, 0, 0, 0, 0, 0, 8, 236, 230, 8, 0, 0, 54, 250, 252, 57, 0, 108, 166, 157, 152, 152, 152, 112, 0, 0, 0, 0, 5, 46, 36, 32, 32, 32, 32, 32, 39, 255, 221, 32, 32, 32, 32, 32, 33, 42, 46, 0, 0, 0, 0, 0, 0, 149, 144, 138, 132, 128, 128, 128, 128, 248, 252, 0, 0, 0, 0, 0, 142, 255, 93, 0, 0, 0, 0, 0, 0, 0, 225, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 255, 32, 0, 0, 0, 0, 0, 0, 0, 0, 20, 245, 229, 10, 0, 0, 40, 255, 210, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 188, 255, 177, 2, 0, 0, 135, 255, 73, 8, 8, 8, 155, 255, 75, 0, 0, 0, 0, 0, 0, 0, 0, 138, 255, 64, 0, 0, 48, 255, 32, 0, 0, 32, 255, 96, 0, 0, 0, 248, 211, 0, 0, 0, 0, 0, 0, 0, 20, 245, 229, 10, 0, 0, 40, 255, 210, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 252, 20, 0, 0, 0, 0, 0, 34, 255, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 200, 183, 170, 157, 147, 137, 239, 246, 99, 35, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 252, 232, 15, 0, 0, 38, 45, 37, 32, 32, 46, 154, 48, 32, 32, 33, 41, 49, 17, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 67, 95, 89, 88, 88, 88, 88, 88, 100, 113, 88, 92, 103, 34, 0, 0, 31, 58, 51, 45, 40, 40, 40, 40, 40, 188, 255, 100, 40, 40, 40, 40, 40, 40, 43, 47, 56, 25, 0, 0, 0, 24, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 232, 0, 0, 0, 0, 0, 0, 0, 27, 228, 253, 42, 0, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 186, 255, 255, 218, 210, 255, 102, 0, 0, 0, 0, 207, 255, 0, 0, 48, 236, 255, 110, 0, 0, 0, 0, 0, 0, 0, 98, 255, 116, 0, 0, 0, 0, 125, 255, 150, 0, 160, 255, 255, 255, 255, 255, 181, 0, 0, 0, 0, 24, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 245, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 255, 34, 0, 0, 0, 0, 0, 0, 0, 0, 134, 255, 104, 0, 0, 0, 150, 255, 225, 192, 192, 192, 192, 192, 192, 192, 192, 192, 34, 0, 0, 0, 0, 0, 17, 220, 248, 58, 0, 0, 161, 255, 55, 0, 0, 0, 152, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 145, 255, 136, 96, 96, 126, 255, 116, 96, 96, 116, 255, 156, 96, 96, 96, 251, 211, 0, 0, 0, 0, 0, 0, 0, 134, 255, 104, 0, 0, 0, 150, 255, 225, 192, 192, 192, 192, 192, 192, 192, 192, 192, 34, 0, 0, 0, 0, 0, 0, 235, 195, 0, 0, 0, 0, 0, 0, 119, 255, 140, 48, 48, 48, 48, 48, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 255, 254, 134, 0, 0, 0, 7, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 255, 94, 0, 0, 0, 184, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 80, 0,
|
||||
0, 216, 230, 212, 236, 255, 214, 218, 99, 0, 0, 22, 145, 21, 0, 0, 0, 75, 246, 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 151, 129, 121, 120, 120, 120, 120, 124, 255, 234, 120, 120, 120, 120, 120, 122, 141, 144, 0, 0, 0, 0, 0, 0, 0, 0, 48, 75, 0, 0, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 72, 18, 0, 112, 255, 88, 0, 0, 0, 0, 204, 255, 0, 0, 0, 64, 250, 177, 2, 0, 0, 0, 0, 0, 3, 218, 255, 28, 0, 3, 40, 38, 6, 98, 0, 0, 39, 42, 30, 24, 53, 255, 173, 0, 0, 0, 0, 15, 151, 129, 121, 120, 120, 120, 120, 124, 255, 234, 120, 120, 120, 120, 120, 122, 141, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 241, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 224, 255, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 247, 255, 40, 0, 0, 0, 0, 0, 0, 0, 25, 241, 255, 5, 0, 0, 31, 249, 246, 216, 216, 216, 216, 216, 216, 216, 226, 255, 220, 0, 0, 0, 0, 0, 0, 0, 44, 60, 0, 0, 0, 195, 255, 24, 0, 0, 0, 152, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 131, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 188, 0, 0, 0, 0, 0, 0, 25, 241, 255, 5, 0, 0, 31, 249, 246, 216, 216, 216, 216, 216, 216, 216, 226, 255, 220, 0, 0, 0, 0, 153, 208, 208, 255, 236, 208, 208, 208, 158, 0, 0, 209, 255, 255, 255, 255, 255, 255, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 250, 232, 70, 0, 0, 0, 31, 203, 205, 59, 0, 0, 0, 0, 0, 0, 0, 31, 248, 198, 1, 0, 157, 85, 85, 107, 100, 96, 151, 193, 96, 96, 96, 96, 97, 105, 114, 37, 0,
|
||||
0, 192, 212, 202, 233, 255, 207, 211, 96, 0, 0, 150, 255, 156, 0, 0, 0, 135, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 160, 9, 0, 0, 8, 255, 216, 0, 0, 0, 79, 188, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 255, 88, 0, 0, 0, 0, 202, 255, 0, 0, 0, 0, 60, 3, 0, 0, 0, 0, 0, 0, 99, 255, 255, 24, 0, 14, 255, 235, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 169, 0, 0, 0, 0, 0, 0, 0, 30, 160, 9, 0, 0, 8, 255, 216, 0, 0, 0, 79, 188, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 248, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 224, 255, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 35, 3, 0, 0, 0, 0, 0, 0, 174, 255, 255, 0, 0, 0, 158, 255, 120, 0, 0, 0, 0, 0, 0, 0, 125, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 250, 224, 0, 0, 0, 0, 152, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 186, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 255, 255, 0, 0, 0, 158, 255, 120, 0, 0, 0, 0, 0, 0, 0, 125, 255, 124, 0, 0, 0, 0, 180, 255, 207, 200, 200, 200, 205, 255, 186, 0, 61, 255, 204, 128, 128, 128, 128, 128, 236, 223, 0, 0, 0, 0, 0, 0, 0, 0, 5, 121, 253, 198, 25, 0, 0, 0, 81, 237, 255, 234, 120, 5, 0, 0, 0, 0, 0, 0, 180, 252, 48, 0, 49, 255, 254, 65, 0, 0, 0, 173, 255, 149, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 0, 0, 19, 244, 253, 45, 0, 0, 214, 246, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 255, 163, 0, 0, 8, 255, 216, 0, 0, 7, 222, 253, 51, 0, 0, 0, 0, 0, 0, 28, 61, 51, 48, 48, 31, 0, 0, 0, 0, 0, 0, 0, 240, 241, 24, 24, 24, 25, 30, 35, 0, 0, 0, 46, 84, 78, 74, 72, 152, 255, 135, 72, 72, 72, 72, 216, 255, 72, 72, 72, 72, 73, 77, 85, 46, 0, 0, 0, 12, 230, 255, 255, 24, 0, 5, 255, 226, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 0, 0, 0, 0, 123, 255, 163, 0, 0, 8, 255, 216, 0, 0, 7, 222, 253, 51, 0, 0, 0, 0, 0, 0, 0, 0, 151, 240, 240, 240, 240, 240, 240, 240, 255, 255, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 205, 74, 2, 0, 0, 0, 88, 255, 255, 255, 0, 0, 65, 253, 232, 11, 0, 0, 44, 48, 1, 0, 2, 225, 254, 30, 0, 0, 0, 41, 33, 25, 24, 24, 4, 0, 1, 170, 255, 125, 0, 0, 0, 0, 152, 255, 147, 39, 40, 55, 26, 0, 0, 0, 79, 136, 129, 122, 120, 120, 120, 120, 120, 232, 255, 138, 120, 120, 120, 120, 122, 127, 136, 40, 0, 0, 0, 0, 88, 255, 255, 255, 0, 0, 65, 253, 232, 11, 0, 0, 44, 48, 1, 0, 2, 225, 254, 30, 0, 0, 0, 0, 173, 255, 32, 0, 0, 0, 24, 255, 180, 0, 184, 255, 63, 0, 0, 0, 0, 0, 221, 219, 0, 0, 0, 0, 0, 0, 30, 146, 225, 255, 212, 78, 72, 72, 72, 156, 255, 240, 116, 9, 0, 0, 0, 0, 0, 0, 9, 149, 255, 179, 60, 68, 187, 255, 137, 0, 0, 0, 49, 252, 218, 18, 0, 0, 10, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 45, 35, 16, 120, 98, 24, 16, 53, 255, 171, 16, 19, 38, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 200, 255, 76, 0, 8, 255, 216, 0, 0, 118, 255, 152, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 255, 255, 162, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 255, 216, 0, 0, 0, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 0, 0, 140, 255, 254, 255, 24, 0, 1, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 0, 0, 0, 0, 4, 200, 255, 76, 0, 8, 255, 216, 0, 0, 118, 255, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 255, 170, 144, 144, 144, 144, 144, 144, 144, 3, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 222, 255, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 255, 244, 14, 0, 0, 48, 244, 243, 225, 255, 0, 20, 229, 255, 99, 0, 0, 0, 229, 252, 0, 0, 64, 254, 189, 0, 0, 0, 0, 248, 255, 255, 255, 255, 41, 6, 155, 255, 207, 8, 0, 0, 0, 0, 134, 255, 255, 255, 255, 255, 86, 0, 0, 0, 144, 255, 250, 244, 240, 240, 240, 240, 240, 255, 251, 240, 240, 240, 240, 240, 243, 247, 255, 72, 0, 0, 0, 48, 244, 243, 225, 255, 0, 20, 229, 255, 99, 0, 0, 0, 229, 252, 0, 0, 64, 254, 189, 0, 0, 0, 0, 0, 170, 255, 32, 0, 0, 0, 24, 255, 177, 66, 255, 196, 0, 0, 0, 0, 0, 0, 226, 214, 0, 0, 0, 0, 0, 0, 14, 250, 255, 255, 255, 255, 255, 255, 255, 254, 160, 21, 0, 0, 0, 0, 0, 0, 0, 0, 11, 236, 255, 255, 255, 255, 255, 212, 6, 0, 0, 5, 206, 244, 41, 0, 0, 61, 227, 112, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 208, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 120, 179, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 253, 196, 0, 8, 255, 216, 0, 20, 240, 235, 18, 0, 0, 0, 0, 0, 0, 0, 41, 92, 84, 136, 255, 155, 0, 0, 0, 0, 0, 0, 0, 240, 246, 104, 104, 104, 105, 110, 102, 0, 0, 0, 38, 69, 62, 59, 57, 143, 255, 124, 56, 56, 56, 56, 187, 255, 81, 56, 56, 56, 57, 61, 70, 38, 0, 0, 56, 252, 218, 204, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 0, 0, 0, 0, 0, 49, 253, 196, 0, 8, 255, 216, 0, 20, 240, 235, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 187, 255, 238, 182, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 192, 247, 255, 144, 0, 0, 0, 204, 255, 104, 200, 255, 0, 109, 244, 188, 0, 0, 0, 0, 220, 243, 0, 0, 0, 21, 33, 0, 0, 0, 0, 141, 135, 131, 216, 255, 31, 22, 172, 212, 24, 0, 0, 0, 0, 0, 16, 127, 151, 152, 152, 152, 57, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 29, 255, 171, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 204, 255, 104, 200, 255, 0, 109, 244, 188, 0, 0, 0, 0, 220, 243, 0, 0, 0, 21, 33, 0, 0, 0, 0, 0, 168, 255, 32, 0, 0, 0, 24, 255, 176, 199, 255, 59, 0, 0, 0, 0, 0, 0, 230, 207, 0, 0, 0, 0, 0, 0, 0, 97, 91, 61, 43, 57, 195, 255, 214, 62, 0, 0, 45, 150, 18, 0, 0, 0, 0, 0, 0, 96, 130, 91, 61, 216, 253, 55, 0, 0, 1, 157, 255, 90, 0, 0, 0, 41, 239, 253, 79, 0, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 43, 128, 52, 106, 118, 112, 112, 141, 130, 112, 112, 112, 112, 112, 112, 119, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 24, 237, 255, 204, 21, 0, 0, 0, 0, 0, 0, 0, 18, 35, 27, 24, 24, 24, 101, 35, 24, 31, 255, 219, 24, 26, 99, 99, 24, 24, 24, 28, 37, 18, 0, 0, 0, 0, 0, 80, 255, 147, 0, 0, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 255, 88, 0, 0, 0, 0, 149, 255, 52, 0, 0, 0, 97, 69, 0, 0, 0, 5, 218, 255, 73, 200, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 18, 35, 27, 24, 24, 24, 101, 35, 24, 31, 255, 219, 24, 26, 99, 99, 24, 24, 24, 28, 37, 18, 0, 0, 0, 0, 182, 255, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 47, 195, 230, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 222, 175, 17, 0, 0, 0, 23, 151, 1, 200, 255, 0, 0, 16, 24, 0, 0, 0, 0, 217, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 27, 0, 57, 122, 100, 97, 96, 96, 96, 96, 96, 96, 96, 96, 26, 0, 0, 0, 0, 0, 0, 0, 0, 123, 192, 192, 192, 192, 204, 255, 229, 192, 192, 192, 192, 192, 141, 0, 0, 0, 0, 0, 0, 23, 151, 1, 200, 255, 0, 0, 16, 24, 0, 0, 0, 0, 217, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 255, 32, 0, 0, 0, 24, 255, 176, 12, 106, 17, 142, 98, 0, 0, 0, 0, 237, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 104, 237, 246, 122, 5, 0, 0, 3, 167, 255, 222, 42, 0, 0, 0, 0, 0, 0, 0, 0, 92, 255, 142, 0, 0, 44, 183, 255, 143, 0, 2, 18, 38, 62, 153, 255, 241, 36, 0, 0,
|
||||
0, 0, 0, 0, 159, 255, 247, 255, 76, 0, 0, 0, 0, 142, 248, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 44, 230, 255, 216, 27, 0, 0, 0, 0, 0, 0, 104, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 104, 0, 0, 0, 0, 0, 80, 255, 144, 0, 0, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 255, 88, 0, 0, 1, 0, 125, 255, 77, 0, 0, 3, 224, 255, 93, 0, 0, 0, 36, 131, 0, 200, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 104, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 104, 0, 0, 0, 0, 197, 255, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 160, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 0, 0, 0, 5, 83, 2, 0, 216, 240, 0, 3, 111, 35, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 24, 0, 120, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 245, 13, 0, 0, 0, 0, 0, 0, 0, 0, 158, 249, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 238, 181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 0, 0, 0, 5, 83, 2, 0, 216, 240, 0, 3, 111, 35, 0, 0, 0, 0, 0, 0, 168, 255, 151, 136, 136, 136, 147, 255, 176, 0, 0, 54, 254, 225, 6, 0, 0, 0, 242, 192, 0, 0, 0, 0, 0, 0, 0, 23, 111, 219, 255, 177, 33, 0, 0, 0, 0, 0, 0, 116, 253, 240, 66, 0, 0, 0, 0, 0, 0, 18, 233, 222, 10, 0, 0, 61, 255, 255, 237, 242, 254, 255, 255, 255, 255, 255, 255, 206, 7, 0,
|
||||
1, 50, 121, 204, 255, 255, 198, 81, 29, 53, 35, 32, 33, 231, 255, 84, 32, 32, 32, 32, 32, 38, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 35, 225, 255, 220, 29, 0, 0, 0, 0, 0, 69, 153, 135, 128, 128, 128, 128, 138, 254, 247, 255, 254, 255, 209, 128, 128, 128, 128, 130, 138, 145, 61, 0, 0, 0, 0, 0, 80, 255, 144, 0, 0, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 255, 121, 101, 172, 164, 0, 89, 255, 115, 0, 0, 100, 255, 197, 3, 0, 0, 0, 0, 0, 0, 200, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 69, 153, 135, 128, 128, 128, 128, 138, 254, 247, 255, 254, 255, 209, 128, 128, 128, 128, 130, 138, 145, 61, 0, 0, 0, 0, 213, 255, 203, 200, 200, 200, 200, 200, 200, 200, 34, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 255, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 0, 0, 0, 113, 255, 172, 0, 216, 240, 0, 83, 255, 199, 3, 0, 0, 0, 0, 0, 0, 0, 176, 255, 24, 0, 15, 32, 212, 252, 44, 32, 32, 32, 32, 134, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 150, 242, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 221, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 0, 0, 0, 113, 255, 172, 0, 216, 240, 0, 83, 255, 199, 3, 0, 0, 0, 0, 0, 168, 255, 255, 255, 255, 255, 255, 255, 176, 0, 0, 0, 172, 255, 102, 0, 0, 0, 250, 185, 0, 0, 0, 0, 0, 98, 224, 254, 255, 255, 181, 122, 135, 147, 159, 171, 182, 193, 204, 215, 248, 255, 249, 87, 0, 0, 0, 0, 0, 167, 255, 68, 0, 0, 3, 10, 239, 235, 221, 255, 203, 122, 209, 255, 59, 23, 216, 176, 17, 0,
|
||||
5, 226, 255, 245, 226, 255, 24, 0, 96, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 32, 223, 255, 220, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 255, 115, 255, 217, 206, 251, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 144, 0, 0, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 37, 85, 136, 211, 255, 255, 255, 251, 162, 0, 47, 255, 162, 0, 16, 229, 246, 36, 0, 0, 0, 0, 0, 0, 0, 200, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 255, 115, 255, 217, 206, 251, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 184, 184, 184, 184, 184, 184, 184, 252, 255, 16, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 97, 136, 130, 124, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 155, 255, 205, 120, 120, 123, 130, 122, 0, 0, 0, 0, 0, 200, 255, 0, 0, 0, 21, 240, 254, 64, 0, 216, 240, 0, 0, 187, 255, 127, 0, 0, 0, 0, 0, 0, 0, 176, 255, 24, 0, 0, 0, 115, 255, 88, 0, 0, 0, 1, 213, 255, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 0, 0, 21, 240, 254, 64, 0, 216, 240, 0, 0, 187, 255, 127, 0, 0, 0, 0, 0, 168, 255, 46, 16, 16, 16, 38, 255, 176, 0, 0, 0, 54, 255, 220, 2, 0, 2, 255, 177, 0, 0, 0, 0, 0, 59, 255, 255, 255, 244, 233, 223, 217, 219, 255, 235, 196, 183, 170, 159, 148, 158, 255, 254, 100, 0, 0, 18, 156, 255, 226, 147, 177, 212, 249, 40, 16, 0, 64, 255, 132, 0, 176, 255, 24, 0, 26, 1, 0, 0,
|
||||
0, 125, 148, 22, 152, 255, 24, 0, 43, 104, 97, 96, 237, 250, 107, 96, 96, 148, 255, 168, 96, 98, 108, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 0, 35, 230, 255, 216, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 255, 181, 9, 255, 216, 45, 245, 247, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 144, 0, 0, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 247, 255, 255, 255, 255, 255, 169, 71, 12, 0, 0, 3, 241, 225, 1, 167, 255, 111, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 255, 181, 9, 255, 216, 45, 245, 247, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 255, 241, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 224, 0, 0, 0, 0, 0, 200, 255, 0, 0, 0, 160, 255, 153, 0, 0, 216, 240, 0, 0, 33, 244, 251, 51, 0, 0, 0, 0, 0, 0, 176, 255, 24, 0, 0, 0, 17, 242, 207, 1, 0, 0, 88, 255, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 241, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 219, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 0, 0, 160, 255, 153, 0, 0, 216, 240, 0, 0, 33, 244, 251, 51, 0, 0, 0, 0, 168, 255, 32, 0, 0, 0, 24, 255, 176, 0, 0, 0, 0, 203, 255, 79, 0, 12, 255, 166, 0, 0, 0, 0, 0, 1, 55, 25, 5, 0, 0, 0, 0, 48, 255, 152, 0, 0, 0, 0, 0, 0, 117, 167, 18, 0, 0, 51, 255, 255, 255, 255, 244, 212, 173, 0, 0, 0, 71, 255, 122, 0, 176, 255, 24, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 0, 0, 85, 255, 127, 0, 0, 0, 174, 250, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 0, 0, 46, 237, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 255, 219, 18, 8, 255, 216, 0, 78, 251, 255, 133, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 144, 0, 27, 61, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 255, 220, 149, 81, 127, 255, 88, 0, 0, 0, 0, 0, 174, 255, 178, 255, 186, 1, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 0, 0, 0, 0, 0, 129, 255, 219, 18, 8, 255, 216, 0, 78, 251, 255, 133, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 255, 210, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 20, 25, 19, 14, 14, 24, 8, 8, 8, 8, 8, 8, 8, 8, 70, 255, 163, 8, 8, 12, 18, 24, 0, 0, 0, 0, 0, 200, 255, 0, 0, 105, 255, 221, 13, 0, 0, 216, 240, 0, 0, 0, 117, 255, 209, 5, 0, 0, 0, 0, 0, 176, 255, 24, 50, 69, 0, 0, 132, 255, 117, 0, 17, 230, 249, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 251, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 243, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 0, 105, 255, 221, 13, 0, 0, 216, 240, 0, 0, 0, 117, 255, 209, 5, 0, 0, 0, 168, 255, 32, 0, 0, 0, 24, 255, 176, 0, 0, 0, 0, 105, 201, 56, 0, 22, 255, 152, 0, 0, 0, 0, 0, 0, 0, 7, 92, 1, 0, 0, 0, 48, 255, 152, 0, 0, 5, 115, 6, 0, 0, 0, 0, 0, 0, 0, 159, 121, 70, 27, 0, 0, 0, 0, 0, 0, 99, 255, 96, 0, 176, 255, 24, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 0, 9, 224, 255, 154, 50, 0, 59, 254, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 8, 155, 255, 233, 36, 0, 8, 255, 216, 0, 0, 86, 249, 255, 207, 64, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 144, 21, 214, 212, 3, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 39, 0, 0, 0, 112, 255, 88, 0, 0, 0, 0, 0, 76, 255, 255, 217, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 0, 0, 0, 8, 155, 255, 233, 36, 0, 8, 255, 216, 0, 0, 86, 249, 255, 207, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 255, 177, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 15, 183, 186, 3, 0, 0, 0, 0, 0, 0, 0, 64, 255, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 61, 250, 251, 57, 0, 0, 0, 216, 240, 0, 0, 0, 6, 220, 255, 124, 0, 0, 0, 0, 0, 176, 255, 60, 229, 194, 0, 0, 10, 223, 252, 90, 186, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 251, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 244, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 61, 250, 251, 57, 0, 0, 0, 216, 240, 0, 0, 0, 6, 220, 255, 124, 0, 0, 0, 168, 255, 32, 0, 0, 0, 24, 255, 176, 0, 0, 0, 0, 5, 1, 0, 0, 36, 255, 137, 0, 0, 0, 0, 0, 0, 0, 162, 255, 187, 10, 0, 0, 48, 255, 152, 0, 0, 160, 255, 205, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 160, 255, 48, 0, 176, 255, 24, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 0, 2, 78, 187, 255, 255, 194, 214, 237, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 211, 255, 227, 40, 0, 0, 8, 255, 216, 0, 0, 0, 58, 232, 255, 255, 182, 81, 9, 0, 0, 0, 0, 0, 80, 255, 171, 213, 255, 138, 1, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 255, 88, 0, 0, 0, 0, 19, 178, 255, 255, 92, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 200, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 0, 0, 58, 211, 255, 227, 40, 0, 0, 8, 255, 216, 0, 0, 0, 58, 232, 255, 255, 182, 81, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 255, 144, 0, 0, 0, 0, 0, 136, 255, 88, 0, 0, 0, 0, 0, 0, 0, 10, 213, 255, 133, 0, 0, 0, 0, 0, 0, 0, 64, 255, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 97, 251, 111, 0, 0, 0, 0, 216, 240, 0, 0, 0, 0, 81, 231, 83, 0, 0, 0, 0, 0, 177, 255, 238, 255, 167, 2, 0, 0, 56, 248, 255, 255, 188, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 245, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 229, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 0, 97, 251, 111, 0, 0, 0, 0, 216, 240, 0, 0, 0, 0, 81, 231, 83, 0, 0, 0, 168, 255, 32, 0, 0, 0, 24, 255, 176, 0, 0, 0, 0, 0, 0, 0, 0, 55, 255, 122, 0, 0, 0, 0, 0, 0, 148, 255, 222, 52, 0, 0, 0, 48, 255, 152, 0, 0, 29, 192, 255, 244, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 108, 190, 140, 0, 26, 247, 230, 2, 0, 176, 255, 24, 0, 0, 5, 0, 0,
|
||||
0, 0, 0, 0, 152, 255, 24, 0, 0, 0, 0, 0, 0, 41, 191, 255, 255, 236, 113, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 168, 254, 255, 199, 24, 0, 0, 0, 10, 255, 216, 0, 0, 0, 0, 29, 194, 255, 255, 255, 140, 0, 0, 0, 0, 0, 88, 255, 255, 255, 119, 0, 0, 0, 0, 0, 240, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 255, 88, 0, 0, 1, 90, 232, 255, 213, 251, 231, 33, 0, 0, 235, 175, 10, 0, 0, 0, 0, 201, 255, 24, 0, 0, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 168, 0, 0, 0, 44, 168, 254, 255, 199, 24, 0, 0, 0, 10, 255, 216, 0, 0, 0, 0, 29, 194, 255, 255, 255, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 255, 108, 0, 0, 0, 0, 0, 138, 255, 91, 0, 0, 0, 0, 0, 0, 0, 0, 44, 247, 252, 56, 0, 0, 0, 0, 0, 0, 64, 255, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 255, 0, 0, 42, 0, 0, 0, 0, 0, 216, 240, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 205, 255, 255, 157, 2, 0, 0, 0, 41, 222, 255, 255, 140, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 255, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 254, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 255, 0, 0, 42, 0, 0, 0, 0, 0, 216, 240, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 170, 255, 249, 248, 248, 248, 248, 255, 178, 0, 0, 0, 0, 0, 0, 0, 0, 86, 255, 108, 0, 0, 0, 0, 7, 165, 255, 202, 22, 0, 0, 0, 0, 48, 255, 152, 0, 0, 0, 3, 137, 255, 255, 142, 1, 0, 0, 28, 73, 120, 173, 229, 255, 255, 244, 110, 0, 170, 255, 128, 0, 0, 176, 255, 24, 0, 6, 218, 106, 1,
|
||||
0, 0, 0, 0, 190, 255, 22, 0, 0, 0, 0, 0, 50, 159, 253, 242, 151, 242, 255, 233, 117, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 255, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 238, 254, 150, 7, 0, 0, 0, 0, 17, 255, 220, 0, 0, 0, 0, 0, 1, 93, 218, 191, 1, 0, 0, 0, 0, 0, 153, 255, 255, 116, 34, 83, 69, 54, 48, 48, 243, 243, 48, 48, 48, 50, 56, 70, 60, 0, 0, 0, 0, 0, 0, 0, 156, 255, 85, 7, 88, 207, 255, 251, 133, 5, 114, 255, 225, 52, 40, 255, 227, 1, 0, 0, 0, 0, 204, 255, 27, 0, 1, 255, 224, 0, 0, 0, 0, 0, 0, 0, 0, 57, 255, 168, 0, 0, 0, 61, 238, 254, 150, 7, 0, 0, 0, 0, 17, 255, 220, 0, 0, 0, 0, 0, 1, 93, 218, 191, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 229, 255, 68, 0, 0, 0, 0, 0, 141, 255, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 255, 164, 0, 0, 0, 0, 0, 0, 112, 255, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 255, 3, 0, 0, 0, 0, 0, 0, 23, 243, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 253, 255, 162, 1, 0, 0, 20, 139, 247, 251, 157, 221, 255, 229, 130, 42, 1, 0, 0, 0, 0, 0, 0, 0, 0, 144, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 255, 3, 0, 0, 0, 0, 0, 0, 23, 243, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 172, 160, 160, 160, 169, 255, 183, 0, 0, 0, 0, 0, 0, 0, 15, 186, 255, 83, 0, 0, 0, 43, 208, 255, 186, 12, 0, 0, 0, 0, 0, 95, 255, 148, 0, 0, 0, 0, 0, 99, 253, 252, 59, 0, 0, 169, 255, 255, 255, 206, 136, 65, 6, 0, 126, 255, 221, 12, 0, 0, 176, 255, 35, 0, 67, 255, 210, 0,
|
||||
0, 28, 206, 207, 255, 243, 1, 0, 47, 120, 169, 222, 255, 255, 179, 35, 0, 21, 151, 252, 255, 232, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, 255, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 67, 0, 0, 0, 0, 0, 0, 32, 255, 227, 0, 0, 0, 0, 0, 0, 0, 2, 22, 0, 0, 0, 0, 0, 1, 192, 255, 133, 0, 96, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 176, 0, 0, 0, 0, 58, 190, 218, 255, 255, 49, 60, 245, 255, 204, 50, 0, 0, 0, 135, 255, 253, 240, 255, 131, 0, 0, 0, 0, 0, 207, 255, 30, 0, 4, 255, 224, 0, 0, 0, 0, 0, 0, 171, 201, 241, 255, 157, 0, 0, 0, 0, 61, 67, 0, 0, 0, 0, 0, 0, 32, 255, 227, 0, 0, 0, 0, 0, 0, 0, 2, 22, 0, 0, 0, 0, 0, 0, 0, 125, 225, 225, 233, 254, 255, 238, 15, 0, 0, 0, 0, 0, 148, 255, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 104, 2, 0, 0, 0, 72, 212, 231, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 8, 0, 0, 0, 0, 131, 220, 250, 255, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 199, 197, 7, 17, 78, 167, 248, 255, 180, 42, 0, 7, 115, 228, 255, 255, 237, 194, 145, 0, 0, 115, 225, 219, 213, 235, 253, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 248, 239, 209, 213, 221, 135, 0, 0, 0, 0, 0, 208, 255, 8, 0, 0, 0, 0, 131, 220, 250, 255, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 255, 32, 0, 0, 0, 24, 255, 190, 0, 0, 0, 0, 123, 203, 216, 249, 255, 230, 14, 0, 0, 0, 16, 173, 168, 6, 0, 0, 0, 35, 232, 244, 255, 255, 116, 0, 0, 0, 0, 0, 0, 91, 90, 0, 0, 0, 38, 197, 107, 28, 0, 0, 0, 6, 146, 255, 241, 48, 0, 0, 0, 158, 255, 207, 160, 225, 255, 106, 0,
|
||||
0, 0, 195, 255, 241, 94, 0, 0, 48, 255, 255, 225, 143, 48, 0, 0, 0, 0, 0, 48, 202, 224, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 176, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 200, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 123, 1, 0, 38, 95, 85, 82, 80, 80, 80, 80, 80, 80, 80, 81, 84, 92, 69, 0, 0, 0, 0, 2, 219, 255, 226, 110, 0, 0, 93, 100, 2, 0, 0, 0, 0, 0, 94, 233, 255, 225, 17, 0, 0, 0, 0, 0, 215, 255, 38, 0, 12, 255, 224, 0, 0, 0, 0, 0, 0, 125, 255, 255, 223, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 200, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 255, 255, 255, 250, 192, 56, 0, 0, 0, 0, 0, 0, 156, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 242, 255, 228, 122, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 16, 0, 0, 0, 0, 49, 255, 253, 196, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 22, 8, 181, 255, 252, 174, 56, 0, 0, 0, 0, 0, 5, 84, 174, 245, 255, 82, 0, 0, 63, 122, 116, 109, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 107, 110, 118, 74, 0, 0, 0, 0, 0, 216, 255, 16, 0, 0, 0, 0, 49, 255, 253, 196, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 176, 22, 0, 0, 0, 12, 128, 98, 0, 0, 0, 0, 48, 255, 255, 229, 154, 32, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 189, 255, 223, 152, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 250, 238, 57, 0, 0, 0, 0, 47, 213, 247, 248, 245, 163, 4, 0,
|
||||
0, 0, 47, 52, 6, 0, 0, 0, 0, 79, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 48, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 54, 15, 0, 0, 0, 0, 0, 0, 117, 136, 24, 0, 9, 112, 98, 0, 0, 0, 0, 0, 0, 28, 85, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 80, 61, 35, 5, 0, 0, 0, 0, 0, 0, 0, 0, 10, 16, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 45, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 40, 3, 0, 0, 0, 0, 0, 63, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 101, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 58, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 40, 3, 0, 0, 0, 0, 0, 63, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 69, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
static const int g_txt_setup_w = 576;
|
||||
static const int g_txt_setup_h = 42;
|
||||
static const unsigned char g_txt_setup[576*42] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 64, 126, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 89, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 94, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 129, 212, 212, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 255, 255, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 212, 212, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 32, 32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 219, 191, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 255, 243, 168, 30, 0, 0, 14, 148, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 212, 212, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 140, 140, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 207, 107, 16, 0, 0, 0, 0, 130, 198, 112, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 188, 117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 207, 107, 16, 0, 0, 0, 0, 130, 198, 112, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 168, 86, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 210, 108, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 81, 137, 192, 244, 255, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 230, 255, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 122, 255, 255, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 255, 255, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 255, 255, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 156, 249, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 113, 50, 0, 0, 73, 255, 255, 171, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 207, 3, 0, 29, 210, 255, 185, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 255, 255, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 62, 52, 44, 40, 37, 36, 36, 36, 36, 36, 36, 36, 36, 36, 19, 0, 0, 0, 0, 0, 0, 0, 105, 255, 255, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 230, 16, 0, 0, 0, 0, 193, 255, 255, 203, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 182, 255, 255, 130, 0, 0, 0, 0, 0, 0, 0, 45, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 197, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 255, 255, 230, 16, 0, 0, 0, 0, 193, 255, 255, 203, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 255, 255, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 255, 255, 237, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 17, 36, 56, 79, 111, 145, 178, 211, 244, 255, 255, 255, 255, 255, 255, 240, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 255, 232, 136, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 208, 255, 255, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 102, 255, 255, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 244, 255, 254, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 139, 132, 126, 119, 113, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 114, 120, 127, 133, 140, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 255, 255, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 252, 255, 249, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 72, 155, 241, 255, 215, 9, 0, 69, 255, 255, 148, 0, 0, 61, 241, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 255, 255, 70, 0, 0, 43, 244, 255, 255, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 255, 255, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 133, 0, 0, 0, 0, 0, 0, 0, 97, 255, 255, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 255, 255, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 254, 255, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 94, 0, 0, 0, 0, 23, 252, 255, 252, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 252, 255, 255, 125, 0, 0, 0, 0, 0, 0, 66, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 255, 255, 252, 252, 252, 252, 252, 255, 255, 252, 252, 252, 252, 252, 252, 255, 255, 252, 252, 252, 252, 252, 253, 255, 255, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 94, 0, 0, 0, 0, 23, 252, 255, 252, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 255, 255, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 255, 255, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 186, 189, 191, 196, 203, 210, 218, 230, 243, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 246, 227, 212, 198, 161, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 255, 255, 243, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 255, 255, 224, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 202, 199, 192, 188, 188, 188, 188, 188, 243, 255, 255, 206, 188, 188, 188, 188, 193, 208, 218, 104, 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 255, 255, 243, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 70, 125, 187, 245, 255, 255, 255, 255, 255, 141, 0, 64, 255, 255, 138, 0, 35, 243, 255, 251, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 255, 255, 196, 0, 0, 0, 0, 88, 255, 255, 254, 71, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 122, 0, 0, 0, 0, 0, 0, 0, 90, 255, 255, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 255, 255, 205, 1, 0, 0, 0, 0, 113, 255, 255, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 253, 255, 255, 102, 0, 0, 0, 0, 0, 68, 255, 255, 188, 140, 140, 140, 140, 140, 185, 255, 255, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 255, 224, 0, 0, 0, 0, 0, 200, 255, 48, 0, 0, 0, 0, 48, 255, 255, 16, 0, 0, 0, 0, 116, 255, 255, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 255, 255, 205, 1, 0, 0, 0, 0, 113, 255, 255, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, 255, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 243, 255, 245, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 250, 225, 200, 174, 147, 121, 94, 65, 38, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 255, 255, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 251, 162, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 120, 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 156, 0, 0, 0, 0, 0, 0, 50, 66, 55, 51, 48, 48, 48, 48, 48, 48, 48, 48, 161, 255, 255, 103, 48, 48, 48, 48, 48, 48, 48, 48, 51, 58, 71, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 227, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 127, 150, 184, 226, 255, 255, 255, 255, 255, 255, 252, 207, 149, 89, 21, 0, 60, 255, 255, 131, 0, 0, 113, 254, 255, 253, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 255, 255, 70, 0, 0, 0, 0, 0, 154, 255, 255, 231, 21, 0, 0, 239, 244, 235, 231, 228, 228, 228, 228, 228, 138, 0, 0, 0, 0, 0, 0, 0, 50, 66, 55, 51, 48, 48, 48, 48, 48, 48, 48, 48, 161, 255, 255, 103, 48, 48, 48, 48, 48, 48, 48, 48, 51, 58, 71, 29, 0, 0, 0, 0, 0, 0, 0, 0, 49, 95, 89, 83, 78, 72, 66, 64, 64, 64, 64, 64, 142, 255, 255, 113, 0, 0, 0, 0, 0, 0, 0, 83, 255, 255, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 255, 255, 68, 0, 0, 0, 0, 0, 214, 255, 252, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 255, 255, 252, 71, 0, 0, 0, 0, 78, 255, 255, 100, 0, 0, 0, 0, 0, 100, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 255, 224, 0, 0, 0, 0, 0, 200, 255, 48, 0, 0, 0, 0, 48, 255, 255, 16, 0, 0, 0, 0, 116, 255, 255, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 255, 255, 68, 0, 0, 0, 0, 0, 214, 255, 252, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 255, 255, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 184, 177, 159, 143, 129, 116, 104, 94, 83, 74, 212, 255, 241, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 255, 255, 202, 2, 0, 0, 0, 6, 79, 70, 62, 54, 48, 48, 48, 48, 105, 81, 48, 48, 48, 48, 48, 50, 54, 60, 72, 37, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 150, 146, 138, 133, 132, 132, 132, 132, 132, 132, 132, 132, 133, 132, 132, 132, 135, 146, 157, 77, 0, 0, 0, 0, 70, 88, 81, 75, 68, 61, 60, 60, 60, 60, 60, 60, 60, 164, 255, 255, 142, 60, 60, 60, 60, 60, 60, 60, 60, 60, 61, 65, 68, 77, 86, 56, 0, 0, 0, 0, 0, 0, 164, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 255, 255, 191, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 255, 255, 255, 255, 255, 253, 255, 255, 154, 10, 0, 0, 0, 0, 0, 56, 255, 255, 128, 0, 0, 0, 98, 253, 255, 254, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 237, 255, 204, 0, 0, 0, 0, 0, 0, 9, 219, 255, 255, 145, 0, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 146, 0, 0, 0, 0, 0, 0, 0, 164, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 109, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 249, 255, 190, 0, 0, 0, 0, 0, 64, 255, 255, 236, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 255, 255, 236, 15, 0, 0, 0, 107, 255, 255, 88, 0, 0, 0, 0, 0, 100, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 255, 226, 16, 16, 16, 16, 16, 203, 255, 61, 16, 16, 16, 16, 61, 255, 255, 31, 16, 16, 16, 16, 124, 255, 255, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 249, 255, 190, 0, 0, 0, 0, 0, 64, 255, 255, 236, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 255, 255, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 255, 255, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 255, 255, 255, 225, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 255, 254, 53, 0, 0, 0, 0, 20, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 120, 0, 0,
|
||||
0, 38, 106, 80, 66, 57, 134, 255, 255, 85, 63, 75, 57, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 64, 186, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 200, 245, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 255, 222, 168, 113, 58, 48, 255, 255, 132, 0, 0, 0, 0, 0, 0, 52, 255, 255, 128, 0, 0, 0, 0, 111, 255, 255, 254, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 255, 255, 86, 0, 0, 0, 0, 0, 0, 0, 67, 254, 137, 7, 0, 0, 209, 197, 178, 171, 164, 164, 181, 255, 255, 136, 0, 0, 0, 0, 0, 0, 0, 164, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 105, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 253, 255, 183, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 255, 255, 56, 0, 0, 0, 0, 0, 182, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 251, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 196, 230, 55, 0, 0, 0, 0, 136, 255, 255, 63, 0, 0, 0, 0, 0, 100, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 219, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 255, 255, 56, 0, 0, 0, 0, 0, 182, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 251, 22, 0, 0, 0, 0, 0, 34, 56, 56, 56, 150, 255, 245, 58, 56, 56, 56, 56, 56, 9, 0, 0, 5, 237, 255, 254, 200, 200, 200, 200, 200, 200, 200, 200, 200, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 245, 255, 255, 162, 14, 0, 0, 0, 0, 0, 28, 152, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 255, 255, 157, 0, 0, 0, 34, 0, 20, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 120, 0, 0,
|
||||
0, 80, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 168, 0, 0, 0, 0, 50, 189, 176, 0, 0, 0, 0, 0, 0, 117, 255, 255, 176, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 91, 68, 60, 52, 52, 52, 52, 52, 52, 52, 52, 163, 255, 255, 106, 52, 52, 52, 52, 52, 52, 52, 52, 61, 73, 100, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 21, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 50, 255, 255, 128, 0, 0, 0, 0, 0, 149, 255, 181, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 230, 255, 255, 36, 0, 0, 0, 38, 60, 60, 26, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 130, 0, 0, 0, 0, 0, 0, 0, 73, 91, 68, 60, 52, 52, 52, 52, 52, 52, 52, 52, 163, 255, 255, 106, 52, 52, 52, 52, 52, 52, 52, 52, 61, 73, 100, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 107, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 253, 255, 255, 0, 0, 0, 0, 0, 49, 255, 255, 235, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 218, 255, 255, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 32, 0, 0, 0, 0, 0, 179, 255, 255, 26, 0, 0, 0, 0, 0, 100, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 253, 255, 255, 0, 0, 0, 0, 0, 49, 255, 255, 235, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 218, 255, 255, 179, 0, 0, 0, 0, 0, 0, 152, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 34, 0, 0, 85, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 239, 255, 249, 107, 0, 0, 0, 0, 0, 0, 66, 233, 255, 241, 121, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 255, 239, 21, 0, 0, 62, 250, 143, 28, 46, 35, 25, 20, 16, 16, 133, 204, 47, 16, 16, 16, 16, 16, 16, 19, 28, 36, 44, 23, 0, 0,
|
||||
0, 80, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 168, 0, 0, 0, 17, 239, 255, 255, 70, 0, 0, 0, 0, 0, 181, 255, 255, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 132, 37, 0, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 0, 3, 183, 126, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 47, 255, 255, 128, 0, 0, 0, 0, 0, 6, 122, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 255, 255, 255, 36, 0, 0, 0, 152, 255, 255, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 132, 37, 0, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 0, 3, 183, 126, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 255, 255, 115, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 213, 255, 255, 255, 0, 0, 0, 0, 0, 190, 255, 255, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 255, 255, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 244, 255, 227, 0, 0, 0, 0, 0, 0, 100, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 185, 155, 143, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 213, 255, 255, 255, 0, 0, 0, 0, 0, 190, 255, 255, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 255, 255, 83, 0, 0, 0, 0, 0, 0, 141, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 24, 0, 0, 193, 255, 255, 193, 192, 192, 192, 192, 192, 192, 192, 241, 255, 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 247, 255, 230, 58, 0, 0, 0, 0, 0, 3, 128, 253, 255, 255, 255, 210, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 255, 255, 106, 0, 0, 0, 169, 255, 255, 238, 23, 0, 0, 0, 0, 1, 215, 255, 245, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 24, 73, 64, 54, 45, 126, 255, 255, 75, 52, 64, 49, 0, 0, 0, 0, 108, 255, 255, 213, 3, 0, 0, 0, 9, 245, 255, 222, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 189, 255, 211, 11, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 0, 105, 255, 255, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 46, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 238, 255, 255, 255, 36, 0, 0, 0, 140, 255, 255, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 189, 255, 211, 11, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 0, 105, 255, 255, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 165, 255, 255, 122, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 0, 96, 1, 0, 0, 0, 0, 0, 0, 0, 0, 130, 255, 255, 255, 255, 0, 0, 0, 0, 84, 255, 255, 207, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 241, 255, 236, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 145, 0, 0, 0, 0, 0, 0, 100, 255, 255, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 255, 255, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 255, 255, 255, 255, 0, 0, 0, 0, 84, 255, 255, 207, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 241, 255, 236, 6, 0, 0, 0, 0, 0, 0, 134, 255, 255, 83, 44, 44, 44, 44, 44, 44, 179, 255, 255, 16, 0, 49, 255, 255, 185, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 59, 184, 255, 255, 197, 25, 0, 0, 0, 0, 0, 33, 196, 255, 255, 255, 202, 79, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 243, 255, 204, 2, 0, 0, 43, 253, 255, 255, 91, 0, 0, 0, 0, 0, 80, 255, 255, 231, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 5, 224, 255, 255, 100, 0, 0, 0, 79, 255, 255, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 255, 255, 166, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 16, 236, 255, 250, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 95, 85, 75, 72, 72, 72, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 235, 36, 36, 36, 36, 36, 39, 43, 54, 50, 0, 0, 0, 0, 0, 104, 129, 121, 116, 112, 109, 108, 131, 255, 255, 184, 108, 108, 108, 108, 108, 108, 133, 255, 255, 182, 108, 108, 108, 108, 108, 108, 110, 114, 120, 131, 105, 0, 0, 0, 0, 0, 0, 144, 255, 255, 255, 255, 36, 0, 0, 0, 134, 255, 255, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 255, 255, 166, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 16, 236, 255, 250, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 129, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 254, 200, 86, 5, 0, 0, 0, 0, 0, 54, 250, 255, 255, 255, 255, 0, 0, 0, 20, 233, 255, 255, 75, 0, 0, 0, 0, 64, 72, 72, 2, 0, 0, 0, 99, 255, 255, 147, 0, 0, 0, 0, 0, 31, 62, 53, 43, 36, 36, 36, 36, 9, 0, 0, 0, 58, 247, 255, 250, 33, 0, 0, 0, 0, 0, 0, 100, 255, 255, 218, 78, 52, 54, 69, 87, 59, 0, 0, 0, 0, 0, 73, 207, 197, 188, 184, 181, 180, 180, 180, 180, 180, 180, 180, 199, 255, 255, 225, 180, 180, 180, 180, 180, 180, 180, 181, 185, 192, 201, 194, 0, 0, 0, 0, 0, 0, 0, 54, 250, 255, 255, 255, 255, 0, 0, 0, 20, 233, 255, 255, 75, 0, 0, 0, 0, 64, 72, 72, 2, 0, 0, 0, 99, 255, 255, 147, 0, 0, 0, 0, 0, 0, 0, 130, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 12, 0, 181, 255, 255, 65, 0, 0, 0, 0, 0, 0, 0, 0, 205, 255, 199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 231, 255, 255, 255, 232, 114, 108, 108, 108, 108, 108, 126, 243, 255, 255, 219, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 234, 255, 255, 128, 88, 98, 104, 192, 255, 255, 160, 0, 0, 0, 0, 0, 6, 218, 255, 247, 53, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0, 112, 200, 99, 18, 0, 0, 0, 167, 255, 249, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 214, 255, 255, 76, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 142, 255, 255, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 255, 255, 255, 255, 255, 255, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 196, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 192, 0, 0, 0, 0, 0, 47, 252, 255, 255, 255, 255, 36, 0, 0, 0, 130, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 214, 255, 255, 76, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 142, 255, 255, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 246, 255, 250, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 115, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 255, 255, 253, 33, 0, 0, 0, 0, 28, 230, 255, 255, 228, 255, 255, 0, 0, 0, 174, 255, 255, 189, 0, 0, 0, 0, 0, 219, 255, 253, 1, 0, 0, 0, 210, 255, 255, 52, 0, 0, 0, 0, 0, 116, 255, 255, 255, 255, 255, 255, 255, 65, 0, 0, 55, 237, 255, 255, 117, 0, 0, 0, 0, 0, 0, 0, 89, 255, 255, 255, 255, 255, 255, 255, 255, 132, 0, 0, 0, 0, 0, 88, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 236, 0, 0, 0, 0, 0, 0, 28, 230, 255, 255, 228, 255, 255, 0, 0, 0, 174, 255, 255, 189, 0, 0, 0, 0, 0, 219, 255, 253, 1, 0, 0, 0, 210, 255, 255, 52, 0, 0, 0, 0, 0, 0, 0, 126, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 9, 60, 255, 255, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 255, 196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 246, 123, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, 255, 255, 255, 255, 255, 255, 255, 255, 255, 228, 15, 0, 0, 0, 0, 0, 137, 255, 255, 94, 0, 0, 0, 0, 24, 177, 222, 24, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 48, 210, 188, 161, 152, 156, 152, 152, 152, 152, 152, 152, 245, 255, 233, 152, 152, 153, 169, 191, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 85, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 254, 255, 220, 7, 0, 0, 140, 255, 255, 68, 0, 0, 35, 249, 255, 228, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 255, 255, 254, 250, 255, 255, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 196, 0, 0, 0, 0, 0, 183, 234, 226, 220, 217, 215, 214, 219, 255, 255, 234, 212, 212, 212, 212, 212, 212, 213, 255, 255, 240, 212, 212, 212, 212, 212, 212, 215, 219, 224, 235, 183, 0, 0, 0, 0, 3, 200, 255, 255, 222, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 254, 255, 220, 7, 0, 0, 140, 255, 255, 68, 0, 0, 35, 249, 255, 228, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 255, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, 255, 255, 180, 44, 11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 19, 60, 200, 255, 255, 179, 0, 0, 0, 0, 10, 206, 255, 255, 155, 172, 255, 255, 0, 0, 119, 255, 255, 245, 34, 0, 0, 0, 0, 0, 207, 255, 243, 0, 0, 0, 7, 111, 175, 194, 0, 0, 0, 0, 0, 0, 116, 255, 255, 255, 255, 255, 255, 255, 55, 0, 60, 249, 255, 255, 160, 1, 0, 0, 0, 0, 0, 0, 0, 20, 229, 255, 255, 255, 255, 255, 255, 255, 132, 0, 0, 0, 0, 0, 47, 132, 122, 113, 109, 106, 104, 104, 104, 104, 104, 104, 104, 193, 255, 255, 116, 104, 104, 104, 104, 104, 104, 104, 107, 111, 117, 127, 125, 0, 0, 0, 0, 0, 10, 206, 255, 255, 155, 172, 255, 255, 0, 0, 119, 255, 255, 245, 34, 0, 0, 0, 0, 0, 207, 255, 243, 0, 0, 0, 7, 111, 175, 194, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 15, 214, 255, 255, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 255, 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 255, 255, 238, 212, 196, 185, 180, 180, 248, 255, 255, 255, 179, 32, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 250, 255, 255, 253, 226, 196, 250, 255, 255, 75, 0, 0, 0, 0, 0, 74, 253, 255, 156, 0, 0, 0, 0, 0, 178, 255, 255, 204, 10, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 56, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 116, 255, 206, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 255, 245, 63, 0, 0, 140, 255, 255, 68, 0, 0, 170, 255, 255, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 2, 0, 0, 248, 255, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 234, 28, 28, 28, 28, 28, 31, 35, 45, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 249, 255, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 173, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 255, 245, 63, 0, 0, 140, 255, 255, 68, 0, 0, 170, 255, 255, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 255, 255, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 57, 0, 0, 0, 0, 75, 250, 255, 228, 14, 172, 255, 255, 0, 5, 148, 229, 255, 113, 0, 0, 0, 0, 0, 0, 202, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 89, 76, 71, 67, 166, 255, 255, 45, 0, 0, 71, 238, 158, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 80, 99, 100, 100, 100, 100, 100, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 255, 246, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 250, 255, 228, 14, 172, 255, 255, 0, 5, 148, 229, 255, 113, 0, 0, 0, 0, 0, 0, 202, 255, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 78, 247, 255, 180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 221, 255, 182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 43, 10, 0, 0, 0, 0, 43, 198, 255, 255, 229, 83, 0, 0, 0, 0, 35, 180, 216, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 78, 38, 5, 0, 81, 255, 255, 165, 0, 0, 0, 0, 0, 54, 242, 255, 205, 8, 0, 0, 0, 0, 0, 19, 219, 255, 255, 171, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 5, 94, 66, 44, 193, 180, 171, 168, 168, 168, 169, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 173, 182, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 53, 255, 255, 255, 227, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 147, 25, 0, 0, 0, 140, 255, 255, 68, 0, 0, 34, 138, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 228, 255, 200, 0, 0, 0, 0, 0, 0, 103, 31, 0, 0, 0, 0, 0, 0, 69, 252, 255, 245, 32, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 147, 25, 0, 0, 0, 140, 255, 255, 68, 0, 0, 34, 138, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 255, 255, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 208, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 148, 0, 0, 0, 0, 0, 0, 52, 234, 83, 0, 172, 255, 255, 0, 0, 0, 4, 84, 2, 0, 0, 0, 0, 0, 0, 198, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 41, 0, 0, 10, 77, 33, 23, 20, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 160, 160, 160, 160, 160, 160, 160, 237, 255, 243, 160, 160, 160, 160, 160, 160, 160, 160, 160, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 234, 83, 0, 172, 255, 255, 0, 0, 0, 4, 84, 2, 0, 0, 0, 0, 0, 0, 198, 255, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 28, 195, 43, 0, 52, 176, 13, 0, 0, 0, 0, 0, 0, 226, 255, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 137, 250, 255, 253, 146, 14, 0, 0, 0, 0, 8, 196, 255, 255, 243, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 221, 255, 234, 20, 0, 0, 0, 8, 104, 244, 255, 236, 32, 0, 0, 0, 0, 0, 0, 0, 41, 244, 255, 255, 117, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 134, 226, 255, 103, 0, 0, 0, 0, 0, 0, 0, 148, 170, 68, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 105, 253, 255, 255, 236, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 185, 173, 167, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 214, 255, 255, 188, 164, 164, 164, 164, 164, 164, 164, 164, 164, 166, 170, 176, 187, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 207, 255, 222, 0, 0, 0, 0, 0, 15, 243, 240, 117, 8, 0, 0, 0, 0, 53, 203, 255, 119, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 119, 185, 173, 167, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 214, 255, 255, 188, 164, 164, 164, 164, 164, 164, 164, 164, 164, 166, 170, 176, 187, 119, 0, 0, 0, 0, 0, 0, 27, 255, 255, 175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 56, 88, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 91, 80, 39, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 38, 0, 0, 52, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 0, 1, 0, 117, 254, 255, 123, 0, 0, 0, 0, 0, 0, 232, 255, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 107, 232, 255, 255, 201, 50, 0, 0, 0, 0, 0, 0, 0, 5, 148, 255, 255, 253, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 89, 0, 0, 0, 0, 160, 255, 255, 255, 158, 100, 110, 124, 141, 161, 181, 203, 228, 251, 255, 255, 255, 252, 61, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 117, 255, 255, 255, 255, 255, 119, 0, 0, 0, 0, 0, 0, 2, 229, 255, 255, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 90, 251, 255, 255, 243, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 3, 0, 0, 182, 255, 249, 3, 0, 0, 0, 0, 114, 255, 255, 243, 43, 0, 0, 0, 0, 0, 6, 125, 4, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 156, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 156, 0, 0, 0, 0, 0, 0, 44, 255, 255, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 240, 240, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 0, 0, 92, 103, 5, 0, 0, 196, 255, 232, 0, 0, 7, 127, 196, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 36, 0, 0, 52, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 232, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 233, 255, 156, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 132, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 0, 0, 92, 103, 5, 0, 0, 196, 255, 232, 0, 0, 7, 127, 196, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 213, 204, 204, 204, 204, 204, 204, 237, 255, 255, 8, 0, 0, 0, 45, 252, 255, 237, 13, 0, 0, 0, 0, 0, 238, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 144, 232, 255, 255, 236, 102, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 250, 255, 255, 144, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 249, 255, 179, 0, 0, 0, 0, 0, 68, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 227, 18, 0, 0,
|
||||
0, 0, 0, 35, 113, 201, 255, 255, 255, 255, 208, 92, 5, 0, 0, 0, 0, 0, 0, 70, 255, 255, 227, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 78, 248, 255, 255, 244, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 236, 212, 201, 192, 192, 192, 192, 192, 192, 192, 220, 255, 255, 255, 255, 255, 255, 255, 240, 192, 192, 192, 192, 192, 192, 192, 197, 204, 212, 220, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 41, 111, 192, 125, 0, 0, 144, 255, 255, 35, 0, 0, 0, 11, 231, 255, 255, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 154, 236, 212, 201, 192, 192, 192, 192, 192, 192, 192, 220, 255, 255, 255, 255, 255, 255, 255, 240, 192, 192, 192, 192, 192, 192, 192, 197, 204, 212, 220, 137, 0, 0, 0, 0, 0, 0, 60, 255, 255, 222, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 135, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 0, 11, 232, 255, 220, 39, 0, 196, 255, 232, 0, 0, 156, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 36, 0, 0, 9, 48, 48, 214, 255, 247, 52, 48, 48, 48, 48, 48, 48, 48, 169, 255, 255, 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 255, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 0, 11, 232, 255, 220, 39, 0, 196, 255, 232, 0, 0, 156, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 8, 0, 0, 0, 0, 161, 255, 255, 122, 0, 0, 0, 0, 0, 247, 255, 152, 0, 0, 0, 0, 0, 0, 0, 0, 134, 197, 240, 255, 255, 255, 255, 182, 64, 59, 72, 84, 96, 108, 121, 132, 143, 154, 165, 176, 187, 197, 239, 255, 255, 255, 169, 7, 0, 0, 0, 0, 0, 0, 0, 4, 198, 255, 241, 27, 0, 0, 0, 0, 0, 5, 245, 255, 255, 255, 255, 255, 249, 202, 176, 211, 255, 255, 92, 37, 36, 235, 255, 209, 38, 0, 0,
|
||||
0, 100, 220, 255, 255, 255, 255, 255, 255, 90, 0, 0, 15, 227, 203, 184, 176, 176, 176, 218, 255, 255, 222, 176, 176, 176, 176, 176, 176, 176, 176, 177, 188, 201, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 71, 247, 255, 255, 246, 67, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 211, 255, 248, 182, 255, 255, 223, 255, 252, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 255, 255, 224, 233, 255, 255, 255, 154, 0, 0, 103, 255, 255, 75, 0, 0, 0, 126, 255, 255, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 211, 255, 248, 182, 255, 255, 223, 255, 252, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 176, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 255, 255, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 0, 126, 255, 255, 213, 5, 0, 196, 255, 232, 0, 0, 33, 244, 255, 252, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 117, 255, 255, 66, 0, 0, 0, 0, 0, 0, 6, 235, 255, 251, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 255, 208, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 197, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 0, 126, 255, 255, 213, 5, 0, 196, 255, 232, 0, 0, 33, 244, 255, 252, 59, 0, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 171, 152, 152, 152, 152, 152, 152, 218, 255, 255, 8, 0, 0, 0, 0, 40, 254, 255, 234, 9, 0, 0, 0, 0, 254, 255, 144, 0, 0, 0, 0, 0, 0, 0, 0, 152, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 191, 15, 0, 0, 0, 0, 0, 0, 152, 255, 255, 103, 0, 5, 34, 72, 112, 141, 1, 132, 130, 88, 61, 229, 255, 201, 0, 0, 136, 255, 255, 36, 0, 0, 77, 164, 6, 0, 0, 0,
|
||||
0, 60, 255, 255, 255, 232, 188, 255, 255, 36, 0, 0, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 70, 247, 255, 255, 245, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 168, 255, 255, 117, 140, 255, 255, 99, 245, 255, 238, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 68, 116, 165, 217, 254, 255, 255, 255, 255, 255, 255, 222, 117, 0, 0, 60, 255, 255, 131, 0, 0, 36, 244, 255, 234, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 168, 255, 255, 117, 140, 255, 255, 99, 245, 255, 238, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 194, 255, 255, 145, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 6, 210, 201, 191, 186, 183, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 208, 255, 255, 213, 180, 180, 180, 184, 189, 198, 207, 66, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 36, 247, 255, 253, 58, 0, 0, 196, 255, 232, 0, 0, 0, 112, 255, 255, 222, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 24, 251, 255, 157, 0, 0, 0, 0, 0, 0, 95, 255, 255, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 0, 36, 247, 255, 253, 58, 0, 0, 196, 255, 232, 0, 0, 0, 112, 255, 255, 222, 13, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 0, 0, 0, 0, 0, 183, 255, 255, 107, 0, 0, 0, 6, 255, 255, 137, 0, 0, 0, 0, 0, 0, 0, 0, 67, 255, 255, 255, 255, 247, 234, 222, 212, 204, 196, 191, 205, 255, 255, 209, 169, 156, 143, 131, 118, 107, 96, 86, 122, 254, 255, 255, 204, 5, 0, 0, 0, 40, 179, 255, 255, 253, 199, 228, 253, 255, 255, 255, 166, 0, 0, 0, 0, 0, 223, 255, 198, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 214, 238, 117, 9, 100, 255, 255, 36, 0, 0, 11, 166, 151, 146, 144, 144, 221, 255, 255, 169, 144, 144, 144, 144, 185, 255, 255, 176, 144, 144, 148, 156, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 74, 250, 255, 255, 243, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 255, 255, 190, 2, 140, 255, 255, 68, 101, 255, 255, 237, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 181, 237, 255, 255, 255, 255, 255, 255, 255, 255, 229, 154, 90, 27, 0, 0, 0, 0, 7, 247, 255, 192, 0, 3, 198, 255, 255, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, 255, 255, 190, 2, 140, 255, 255, 68, 101, 255, 255, 237, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 255, 255, 114, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 8, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 1, 189, 255, 255, 144, 0, 0, 0, 196, 255, 232, 0, 0, 0, 2, 199, 255, 255, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 0, 165, 255, 250, 30, 0, 0, 0, 0, 5, 221, 255, 254, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 125, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 94, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 1, 189, 255, 255, 144, 0, 0, 0, 196, 255, 232, 0, 0, 0, 2, 199, 255, 255, 157, 0, 0, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 0, 0, 0, 0, 0, 75, 255, 255, 218, 1, 0, 0, 17, 255, 255, 126, 0, 0, 0, 0, 0, 0, 0, 0, 3, 89, 56, 31, 9, 0, 0, 0, 0, 0, 0, 0, 72, 255, 255, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 255, 199, 42, 0, 0, 0, 0, 99, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 110, 0, 0, 0, 0, 0, 230, 255, 190, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 63, 18, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 28, 247, 255, 188, 1, 0, 0, 0, 0, 166, 255, 236, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 89, 254, 255, 245, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 230, 23, 0, 140, 255, 255, 68, 0, 154, 255, 255, 249, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 255, 255, 255, 231, 182, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 189, 255, 251, 24, 152, 255, 255, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 255, 255, 230, 23, 0, 140, 255, 255, 68, 0, 154, 255, 255, 249, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 255, 255, 83, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 5, 173, 167, 161, 155, 150, 144, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 183, 255, 255, 190, 140, 140, 141, 145, 149, 159, 168, 54, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 117, 255, 255, 219, 10, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 42, 249, 255, 255, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 36, 0, 0, 15, 0, 0, 0, 42, 254, 255, 169, 0, 0, 0, 0, 115, 255, 255, 167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 108, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 73, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 0, 117, 255, 255, 219, 10, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 42, 249, 255, 255, 69, 0, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 0, 0, 0, 0, 0, 2, 227, 255, 255, 65, 0, 0, 26, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 255, 255, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 4, 0, 0, 0, 0, 0, 16, 249, 255, 255, 242, 201, 158, 121, 87, 54, 22, 0, 0, 0, 0, 0, 1, 248, 255, 165, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 161, 255, 245, 32, 0, 0, 0, 0, 33, 251, 255, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 238, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 255, 255, 247, 57, 0, 0, 140, 255, 255, 68, 0, 4, 179, 255, 255, 255, 145, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 0, 4, 167, 25, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 255, 247, 184, 114, 44, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 113, 255, 255, 209, 255, 255, 222, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 255, 255, 247, 57, 0, 0, 140, 255, 255, 68, 0, 4, 179, 255, 255, 255, 145, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, 255, 255, 51, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 57, 251, 255, 251, 55, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 139, 255, 255, 223, 11, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 36, 0, 114, 141, 0, 0, 0, 0, 165, 255, 255, 94, 0, 0, 40, 247, 255, 244, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 0, 57, 251, 255, 251, 55, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 139, 255, 255, 223, 11, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 0, 0, 0, 0, 0, 0, 132, 208, 73, 0, 0, 0, 37, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 169, 39, 0, 0, 0, 0, 0, 0, 72, 255, 255, 100, 0, 0, 0, 0, 102, 171, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 102, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 136, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 0, 0, 54, 254, 255, 213, 70, 2, 0, 0, 0, 169, 255, 244, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 155, 255, 255, 253, 82, 0, 0, 0, 140, 255, 255, 68, 0, 0, 7, 183, 255, 255, 255, 207, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 0, 2, 162, 255, 155, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 77, 10, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 19, 248, 255, 255, 255, 240, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 155, 255, 255, 253, 82, 0, 0, 0, 140, 255, 255, 68, 0, 0, 7, 183, 255, 255, 255, 207, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 255, 19, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 198, 217, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 33, 232, 255, 255, 125, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 14, 234, 255, 255, 145, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 36, 82, 252, 238, 18, 0, 0, 0, 23, 239, 255, 247, 67, 17, 214, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 33, 232, 255, 255, 125, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 14, 234, 255, 255, 145, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 0, 0, 0, 0, 0, 0, 12, 2, 0, 0, 0, 0, 52, 255, 255, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 186, 255, 246, 119, 4, 0, 0, 0, 0, 72, 255, 255, 100, 0, 0, 0, 87, 249, 255, 222, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 255, 255, 86, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 0, 0, 123, 249, 255, 255, 255, 226, 124, 18, 68, 255, 255, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 206, 255, 255, 252, 94, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 6, 166, 255, 255, 255, 253, 165, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 216, 2, 156, 255, 255, 236, 11, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 9, 210, 255, 255, 249, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 206, 255, 255, 252, 94, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 6, 166, 255, 255, 255, 253, 165, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 255, 255, 241, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, 255, 255, 180, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 7, 215, 255, 255, 188, 3, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 103, 255, 255, 248, 27, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 117, 250, 255, 255, 116, 0, 0, 0, 0, 96, 255, 255, 246, 206, 255, 255, 186, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 115, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 82, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 7, 215, 255, 255, 188, 3, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 103, 255, 255, 248, 27, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 255, 255, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 159, 255, 255, 254, 151, 16, 0, 0, 0, 0, 72, 255, 255, 100, 0, 0, 0, 99, 244, 255, 255, 251, 120, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 92, 48, 0, 0, 0, 185, 255, 255, 29, 0, 0, 136, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 23, 126, 230, 255, 255, 255, 241, 232, 255, 213, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 123, 246, 255, 255, 249, 87, 0, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 0, 1, 132, 254, 255, 255, 255, 255, 193, 97, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 222, 167, 255, 255, 223, 41, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 44, 212, 255, 255, 255, 240, 32, 0, 0, 0, 0, 39, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 0, 0, 7, 123, 246, 255, 255, 249, 87, 0, 0, 0, 0, 0, 140, 255, 255, 68, 0, 0, 0, 0, 1, 132, 254, 255, 255, 255, 255, 193, 97, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 255, 255, 208, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 246, 255, 255, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 85, 244, 224, 20, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 3, 210, 200, 46, 0, 0, 0, 0, 0, 0, 0, 0, 137, 255, 255, 255, 255, 255, 177, 8, 0, 0, 0, 0, 0, 148, 255, 255, 255, 255, 226, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 182, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 164, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 255, 255, 0, 0, 85, 244, 224, 20, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 3, 210, 200, 46, 0, 0, 0, 0, 0, 124, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 255, 255, 52, 0, 0, 0, 0, 0, 0, 0, 0, 1, 157, 255, 255, 240, 75, 0, 0, 0, 0, 0, 0, 72, 255, 255, 100, 0, 0, 0, 0, 36, 206, 255, 255, 255, 182, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 108, 180, 249, 255, 73, 0, 0, 59, 255, 255, 199, 0, 0, 0, 136, 255, 255, 36, 0, 0, 0, 12, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 100, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 89, 199, 255, 255, 255, 255, 211, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 255, 255, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 93, 220, 255, 255, 255, 237, 62, 0, 0, 0, 0, 0, 0, 141, 255, 255, 68, 0, 0, 0, 0, 0, 0, 76, 237, 255, 255, 255, 255, 255, 235, 32, 0, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 255, 255, 216, 27, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 255, 255, 132, 0, 0, 0, 0, 0, 7, 127, 248, 255, 255, 252, 255, 255, 202, 9, 0, 0, 0, 89, 253, 154, 29, 0, 0, 0, 0, 0, 0, 0, 173, 255, 255, 36, 0, 0, 0, 128, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 0, 3, 93, 220, 255, 255, 255, 237, 62, 0, 0, 0, 0, 0, 0, 141, 255, 255, 68, 0, 0, 0, 0, 0, 0, 76, 237, 255, 255, 255, 255, 255, 235, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74, 255, 255, 171, 0, 0, 0, 0, 0, 0, 0, 0, 79, 255, 255, 134, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 255, 255, 249, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 255, 255, 0, 0, 0, 47, 49, 0, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 0, 27, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 255, 255, 255, 255, 167, 4, 0, 0, 0, 0, 0, 0, 58, 252, 255, 255, 255, 134, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 255, 255, 0, 0, 0, 47, 49, 0, 0, 0, 0, 0, 0, 0, 196, 255, 232, 0, 0, 0, 0, 0, 0, 0, 27, 2, 0, 0, 0, 0, 0, 0, 126, 255, 255, 246, 244, 244, 244, 244, 244, 244, 251, 255, 255, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 255, 255, 37, 0, 0, 0, 0, 0, 0, 0, 10, 172, 255, 255, 229, 44, 0, 0, 0, 0, 0, 0, 0, 72, 255, 255, 100, 0, 0, 0, 0, 0, 7, 153, 255, 255, 255, 224, 46, 0, 0, 0, 0, 0, 0, 0, 16, 65, 119, 172, 230, 255, 255, 255, 255, 255, 80, 0, 6, 202, 255, 255, 98, 0, 0, 0, 136, 255, 255, 36, 0, 0, 0, 122, 180, 55, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 109, 255, 255, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 163, 255, 255, 255, 255, 255, 255, 204, 79, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 255, 255, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 196, 255, 255, 255, 255, 207, 33, 0, 0, 0, 0, 0, 0, 0, 149, 255, 255, 72, 0, 0, 0, 0, 0, 0, 0, 23, 165, 254, 255, 255, 245, 50, 0, 0, 0, 0, 0, 0, 0, 0, 25, 255, 255, 255, 255, 211, 23, 0, 0, 0, 0, 0, 0, 0, 0, 232, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 132, 0, 0, 0, 2, 88, 218, 255, 255, 255, 193, 36, 191, 255, 255, 186, 8, 0, 0, 131, 255, 255, 149, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 37, 0, 0, 0, 129, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 124, 0, 0, 0, 0, 5, 196, 255, 255, 255, 255, 207, 33, 0, 0, 0, 0, 0, 0, 0, 149, 255, 255, 72, 0, 0, 0, 0, 0, 0, 0, 23, 165, 254, 255, 255, 245, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 255, 255, 134, 0, 0, 0, 0, 0, 0, 0, 0, 82, 255, 255, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 255, 255, 205, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 215, 255, 255, 255, 163, 3, 0, 0, 0, 0, 0, 9, 128, 250, 255, 255, 255, 255, 255, 203, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 172, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 153, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 255, 255, 23, 0, 0, 0, 0, 0, 0, 34, 205, 255, 255, 218, 31, 0, 0, 0, 0, 0, 0, 0, 0, 76, 255, 255, 100, 0, 0, 0, 0, 0, 0, 0, 110, 253, 255, 255, 240, 62, 0, 0, 0, 45, 182, 227, 255, 255, 255, 255, 255, 255, 254, 209, 138, 68, 7, 0, 147, 255, 255, 214, 3, 0, 0, 0, 136, 255, 255, 36, 0, 0, 0, 169, 255, 255, 115, 0,
|
||||
0, 0, 0, 0, 0, 0, 178, 255, 255, 34, 0, 0, 0, 0, 0, 0, 0, 0, 52, 144, 245, 255, 255, 226, 85, 164, 254, 255, 255, 255, 207, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 255, 255, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 215, 255, 255, 150, 9, 0, 0, 0, 0, 0, 0, 0, 0, 156, 255, 255, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 181, 255, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 255, 255, 255, 218, 23, 8, 131, 109, 90, 81, 74, 72, 72, 72, 238, 255, 238, 72, 72, 72, 72, 72, 77, 83, 92, 111, 132, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 255, 255, 126, 0, 16, 107, 214, 255, 255, 255, 246, 115, 2, 0, 23, 224, 255, 255, 203, 35, 0, 203, 255, 255, 66, 0, 0, 0, 0, 0, 0, 0, 178, 255, 255, 40, 0, 0, 0, 131, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 255, 255, 124, 0, 0, 0, 0, 0, 31, 215, 255, 255, 150, 9, 0, 0, 0, 0, 0, 0, 0, 0, 156, 255, 255, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 181, 255, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 239, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 85, 255, 255, 139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 245, 255, 212, 30, 0, 0, 0, 0, 0, 0, 0, 0, 7, 188, 255, 255, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 249, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 255, 255, 255, 174, 3, 0, 0, 0, 0, 8, 104, 226, 255, 255, 246, 127, 104, 235, 255, 255, 255, 219, 123, 45, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 255, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 255, 252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 249, 255, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 255, 255, 139, 112, 112, 112, 112, 112, 112, 204, 255, 255, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 88, 250, 255, 240, 2, 0, 0, 0, 0, 0, 97, 243, 255, 255, 205, 21, 0, 0, 0, 0, 0, 0, 0, 0, 4, 153, 255, 255, 93, 0, 0, 0, 0, 0, 0, 0, 0, 78, 249, 255, 245, 70, 0, 0, 0, 4, 212, 255, 255, 255, 255, 234, 165, 94, 24, 0, 0, 0, 0, 124, 255, 255, 250, 57, 0, 0, 0, 0, 136, 255, 255, 61, 0, 0, 12, 240, 255, 255, 46, 0,
|
||||
0, 0, 57, 188, 170, 190, 255, 255, 253, 13, 0, 0, 0, 9, 48, 99, 155, 219, 255, 255, 255, 254, 166, 17, 0, 0, 48, 189, 255, 255, 255, 255, 204, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 255, 255, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 199, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 255, 255, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 14, 0, 0, 0, 0, 0, 0, 0, 0, 2, 218, 255, 255, 226, 30, 0, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 90, 154, 171, 209, 255, 255, 255, 95, 0, 136, 255, 255, 255, 255, 191, 36, 0, 0, 0, 0, 37, 232, 255, 255, 250, 212, 255, 255, 222, 2, 0, 0, 0, 0, 0, 0, 0, 181, 255, 255, 44, 0, 0, 0, 135, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 69, 172, 171, 187, 247, 255, 255, 117, 0, 0, 0, 0, 0, 0, 33, 199, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171, 255, 255, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 197, 210, 208, 210, 218, 238, 255, 255, 255, 255, 35, 0, 0, 0, 0, 0, 0, 0, 0, 92, 255, 255, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 133, 6, 0, 0, 0, 0, 0, 24, 186, 192, 210, 244, 255, 255, 255, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 183, 255, 255, 11, 0, 0, 0, 0, 0, 0, 17, 183, 196, 221, 255, 255, 255, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 218, 255, 197, 7, 0, 0, 0, 49, 148, 238, 255, 255, 254, 167, 31, 0, 0, 16, 141, 244, 255, 255, 255, 255, 242, 188, 157, 136, 52, 0, 0, 0, 163, 212, 206, 200, 194, 187, 244, 255, 213, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 203, 255, 254, 185, 187, 190, 196, 206, 191, 0, 0, 0, 0, 0, 0, 0, 0, 183, 255, 255, 11, 0, 0, 0, 0, 0, 0, 17, 183, 196, 221, 255, 255, 255, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 28, 0, 0, 0, 0, 0, 11, 170, 172, 178, 197, 237, 255, 255, 255, 153, 0, 0, 0, 0, 0, 0, 36, 199, 255, 189, 13, 0, 0, 0, 0, 0, 1, 185, 224, 233, 251, 255, 255, 255, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 240, 65, 0, 0, 0, 0, 0, 84, 255, 224, 138, 58, 2, 0, 0, 0, 0, 0, 3, 142, 255, 255, 255, 109, 0, 0, 0, 0, 0, 119, 255, 255, 212, 118, 112, 187, 255, 255, 199, 0, 0,
|
||||
0, 0, 2, 224, 255, 255, 255, 255, 183, 0, 0, 0, 50, 252, 255, 255, 255, 255, 255, 253, 172, 46, 0, 0, 0, 0, 0, 0, 80, 223, 255, 255, 255, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 255, 255, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 206, 243, 46, 0, 0, 16, 255, 255, 255, 254, 250, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 254, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 34, 250, 255, 255, 255, 255, 226, 15, 0, 0, 161, 255, 231, 93, 0, 0, 0, 0, 0, 0, 0, 34, 216, 255, 255, 255, 255, 255, 105, 0, 0, 0, 0, 0, 0, 0, 0, 189, 255, 255, 50, 0, 0, 0, 139, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 16, 243, 255, 255, 255, 255, 255, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, 255, 255, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135, 255, 255, 255, 255, 255, 255, 255, 255, 150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 255, 255, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, 255, 255, 255, 255, 255, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, 255, 255, 17, 0, 0, 0, 0, 0, 0, 0, 159, 255, 255, 255, 255, 255, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 222, 27, 0, 78, 166, 228, 255, 255, 255, 255, 185, 51, 0, 0, 0, 0, 0, 0, 18, 124, 229, 255, 255, 255, 255, 255, 221, 13, 0, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 228, 0, 0, 0, 0, 0, 0, 0, 0, 190, 255, 255, 17, 0, 0, 0, 0, 0, 0, 0, 159, 255, 255, 255, 255, 255, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 255, 255, 48, 0, 0, 0, 0, 0, 0, 164, 255, 255, 37, 0, 0, 0, 0, 0, 0, 146, 255, 255, 255, 255, 255, 255, 196, 16, 0, 0, 0, 0, 0, 0, 0, 8, 118, 7, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 255, 255, 223, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 2, 60, 1, 0, 0, 0, 0, 0, 0, 0, 34, 198, 255, 255, 255, 128, 0, 0, 0, 0, 0, 0, 56, 255, 255, 255, 255, 255, 255, 255, 253, 62, 0, 0,
|
||||
0, 0, 0, 137, 255, 255, 250, 170, 20, 0, 0, 0, 0, 161, 255, 255, 252, 196, 117, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 139, 253, 185, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 136, 136, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 172, 172, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 71, 0, 0, 0, 1, 22, 11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 12, 23, 0, 0, 0, 0, 0, 0, 0, 0, 170, 255, 255, 233, 148, 25, 0, 0, 0, 15, 119, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 139, 245, 255, 255, 187, 3, 0, 0, 0, 0, 0, 0, 0, 0, 197, 255, 255, 57, 0, 0, 0, 148, 255, 255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 165, 255, 255, 255, 230, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 172, 172, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 255, 255, 255, 255, 255, 244, 187, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 255, 255, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 255, 255, 254, 195, 94, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 255, 27, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 252, 195, 95, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 22, 197, 255, 255, 248, 164, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 66, 155, 231, 255, 255, 91, 0, 0, 0, 0, 46, 56, 50, 44, 37, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 33, 36, 42, 51, 53, 0, 0, 0, 0, 0, 0, 0, 0, 200, 255, 255, 27, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 252, 195, 95, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 136, 136, 25, 0, 0, 0, 0, 0, 0, 41, 64, 64, 10, 0, 0, 0, 0, 0, 0, 52, 255, 255, 255, 233, 163, 82, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 251, 255, 244, 193, 127, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 191, 255, 254, 122, 0, 0, 0, 0, 0, 0, 0, 0, 104, 214, 242, 244, 244, 244, 223, 91, 0, 0, 0,
|
||||
0, 0, 0, 48, 107, 68, 15, 0, 0, 0, 0, 0, 0, 53, 130, 74, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 117, 58, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 78, 74, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, 204, 204, 53, 0, 0, 0, 104, 168, 168, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 137, 96, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 123, 106, 87, 61, 30, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 24, 24, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 139, 83, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 60, 60, 8, 0, 0, 0, 0, 0, 0, 0, 0, 107, 69, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 169, 94, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 103, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 60, 60, 8, 0, 0, 0, 0, 0, 0, 0, 0, 107, 69, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 113, 77, 37, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 40, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 145, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const int g_txt_title_w = 240;
|
||||
|
||||
@@ -4,8 +4,8 @@ from PIL import Image, ImageFont, ImageDraw
|
||||
ttf = "SYSTEM/system/font/simhei.ttf"
|
||||
|
||||
texts = [
|
||||
("welcome", "欢迎使用 Deshab", 48), # only welcome stays large
|
||||
("setup", "接下来让我们来引导你设置你的系统", 24), # 32 -> 24
|
||||
("welcome", "欢迎使用 Deshab", 36),
|
||||
("setup", "接下来让我们来引导你设置你的系统", 36),
|
||||
("title", "创建你的 Deshab 账户", 24),
|
||||
("computer", "计算机名", 24),
|
||||
("username", "用户名", 24),
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
CC := clang
|
||||
LD := ld.lld
|
||||
|
||||
ROOT := ../../..
|
||||
OUT := $(ROOT)/SYSTEM/system/deshab64/tools/bash.elf
|
||||
ROOT := ../..
|
||||
OUT := $(ROOT)/SYSTEM/system/user/use/login.elf
|
||||
|
||||
CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-stack-protector -fpie -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Wall -Wextra -I.. -I../../UTSM/include -O2
|
||||
CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-stack-protector -fpie -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Wall -Wextra -I../UTSM/include -I../firstInit -O2
|
||||
LDFLAGS := -nostdlib -static -pie -z max-page-size=0x1000 -T linker.ld
|
||||
|
||||
C_SOURCES := main.c
|
||||
@@ -15,7 +15,7 @@ OBJECTS := $(C_SOURCES:.c=.o)
|
||||
all: $(OUT)
|
||||
|
||||
$(OUT): $(OBJECTS) linker.ld
|
||||
@if not exist "$(ROOT)\SYSTEM\system\deshab64\tools" mkdir "$(ROOT)\SYSTEM\system\deshab64\tools"
|
||||
@if not exist "$(ROOT)\SYSTEM\system\user\use" mkdir "$(ROOT)\SYSTEM\system\user\use"
|
||||
$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
|
||||
|
||||
%.o: %.c
|
||||
@@ -0,0 +1,24 @@
|
||||
ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
@@ -0,0 +1,565 @@
|
||||
/* login.elf — Deshab login screen
|
||||
* Shown on non-first boot (firstInit=1) before loading desktop.
|
||||
* Reads USER.CONF via boot context (ctx->reserved[0/1]),
|
||||
* extracts username + password hash, prompts for password,
|
||||
* verifies via SHA256 comparison, sets ctx->reserved[2]=1 on success.
|
||||
*
|
||||
* Returns to DSK in all cases (success, skip via Esc, or fatal error).
|
||||
* DSK loads desktop.elf after this returns.
|
||||
*/
|
||||
|
||||
#include "../UTSM/include/utsm/dsk.h"
|
||||
|
||||
typedef signed char i8;
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long i64;
|
||||
|
||||
#define COM1 0x3F8
|
||||
|
||||
static __inline__ void outb(u16 port, u8 value) { __asm__ volatile("outb %0,%1"::"a"(value),"Nd"(port)); }
|
||||
static __inline__ u8 inb(u16 port) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(port)); return v; }
|
||||
|
||||
/* ---- TSC-based timing (PIT-calibrated) ---- */
|
||||
static u64 g_tsc_per_ms = 0;
|
||||
|
||||
static __inline__ u64 rdtsc_fi(void) {
|
||||
u32 lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
static void tsc_calibrate_fi(void) {
|
||||
outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
|
||||
outb(0x40, 0x7c); /* 11932 low = ~10ms */
|
||||
outb(0x40, 0x2e); /* 11932 high */
|
||||
u64 tsc_start = rdtsc_fi();
|
||||
u16 prev = 0; u64 loops = 0;
|
||||
for (;;) {
|
||||
outb(0x43, 0x00);
|
||||
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
|
||||
if (cur > prev && loops > 10) break;
|
||||
prev = cur; loops++;
|
||||
}
|
||||
u64 tsc_end = rdtsc_fi();
|
||||
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
|
||||
}
|
||||
|
||||
static void delay_ms_fi(u32 ms) {
|
||||
if (!g_tsc_per_ms) {
|
||||
for (volatile u32 i = 0; i < 100000 * ms; i++) __asm__ volatile("pause");
|
||||
return;
|
||||
}
|
||||
u64 target = g_tsc_per_ms * ms;
|
||||
u64 start = rdtsc_fi();
|
||||
while (rdtsc_fi() - start < target) __asm__ volatile("pause");
|
||||
}
|
||||
|
||||
static void delay_frame(void) { delay_ms_fi(33); }
|
||||
|
||||
/* ---- Serial logging (COM1) ---- */
|
||||
static void sputc(char c) {
|
||||
for (unsigned int i=0; i<100000; i++) { if (inb(COM1+5)&0x20) break; }
|
||||
outb(COM1, (unsigned char)c);
|
||||
}
|
||||
static void swrite(const char *s) { while(*s) { if(*s=='\n')sputc('\r'); sputc(*s++); } }
|
||||
static void logl(const char *s) { swrite(s); swrite("\n"); }
|
||||
|
||||
/* ---- Colors (dark theme matching FirstInit) ---- */
|
||||
#define BG_TOP 0xFF2D2D30u
|
||||
#define BG_BOTTOM 0xFF1A1A1Eu
|
||||
#define CARD_BG 0xFF353539u
|
||||
#define INPUT_BG 0xFF2A2A2Eu
|
||||
#define TEXT_FG 0xFFE0E0E0u
|
||||
#define ACCENT 0xFF5A8AC8u
|
||||
#define ERROR_FG 0xFFE05050u
|
||||
#define DIM_FG 0xFF808088u
|
||||
|
||||
static u64 fb_a, fb_w, fb_h, fb_p;
|
||||
|
||||
static u32 blend(u32 c1, u32 c2, u32 a) {
|
||||
u32 na=256-a;
|
||||
u32 r=((c1&0xFF)*na+(c2&0xFF)*a)>>8;
|
||||
u32 g=(((c1>>8)&0xFF)*na+((c2>>8)&0xFF)*a)>>8;
|
||||
u32 b=(((c1>>16)&0xFF)*na+((c2>>16)&0xFF)*a)>>8;
|
||||
return 0xFF000000|(b<<16)|(g<<8)|r;
|
||||
}
|
||||
|
||||
/* ---- ASCII font (Consolas 18px grayscale) — shared from firstInit ---- */
|
||||
#include "../firstInit/ascii_bitmaps.c"
|
||||
#define ASCII_W 11
|
||||
#define ASCII_H 18
|
||||
#define ASCII_STEP 11
|
||||
|
||||
static void fb_char(u32 *fb, u32 ch, i64 x, i64 y, u32 fg, u32 bg) {
|
||||
if (ch < ' ' || ch > '~') ch = ' ';
|
||||
u32 idx = (u32)(ch - ' ');
|
||||
const u8 *g = g_ascii[idx];
|
||||
for (i64 r=0; r<ASCII_H; r++) {
|
||||
i64 yy = y + r;
|
||||
if (yy < 0 || (u64)yy >= fb_h) continue;
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)yy * fb_p);
|
||||
for (i64 c=0; c<ASCII_W; c++) {
|
||||
u32 a = g[r * ASCII_W + c];
|
||||
if (a == 0) continue;
|
||||
i64 xx = x + c;
|
||||
if (xx < 0 || (u64)xx >= fb_w) continue;
|
||||
line[(u64)xx] = (a == 255) ? fg : blend(bg, fg, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fb_text(u32 *fb, const char *s, i64 x, i64 y, u32 fg, u32 bg) {
|
||||
for (i64 i=0; s[i]; i++) fb_char(fb, (u32)(u8)s[i], x+i*ASCII_STEP, y, fg, bg);
|
||||
}
|
||||
|
||||
static void fill_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h, u32 color) {
|
||||
for (i64 r=0; r<h; r++) {
|
||||
i64 yy = y + r;
|
||||
if (yy < 0 || (u64)yy >= fb_h) continue;
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)yy * fb_p);
|
||||
for (i64 c=0; c<w; c++) {
|
||||
i64 xx = x + c;
|
||||
if (xx < 0 || (u64)xx >= fb_w) continue;
|
||||
line[(u64)xx] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u32 bg_at_y(i64 y) {
|
||||
if (fb_h <= 1) return BG_TOP;
|
||||
if (y < 0) y = 0;
|
||||
if ((u64)y >= fb_h) y = (i64)fb_h - 1;
|
||||
return blend(BG_TOP, BG_BOTTOM, (u32)(((u64)y * 255ULL) / (fb_h - 1)));
|
||||
}
|
||||
|
||||
static void fill_gradient_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h) {
|
||||
for (i64 r=0; r<h; r++) {
|
||||
i64 yy = y + r;
|
||||
if (yy < 0 || (u64)yy >= fb_h) continue;
|
||||
u32 color = bg_at_y(yy);
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)yy * fb_p);
|
||||
for (i64 c=0; c<w; c++) {
|
||||
i64 xx = x + c;
|
||||
if (xx < 0 || (u64)xx >= fb_w) continue;
|
||||
line[(u64)xx] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int rounded_rect_contains(i64 px, i64 py, i64 x, i64 y, i64 w, i64 h, i64 radius) {
|
||||
if (px < x || py < y || px >= x + w || py >= y + h) return 0;
|
||||
if (radius <= 0) return 1;
|
||||
if (radius * 2 > w) radius = w / 2;
|
||||
if (radius * 2 > h) radius = h / 2;
|
||||
i64 left = x + radius;
|
||||
i64 right = x + w - radius - 1;
|
||||
i64 top = y + radius;
|
||||
i64 bottom = y + h - radius - 1;
|
||||
if (px >= left && px <= right) return 1;
|
||||
if (py >= top && py <= bottom) return 1;
|
||||
i64 cx = px < left ? left : right;
|
||||
i64 cy = py < top ? top : bottom;
|
||||
i64 dx = px - cx;
|
||||
i64 dy = py - cy;
|
||||
return dx * dx + dy * dy <= radius * radius;
|
||||
}
|
||||
|
||||
static void fill_rounded_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h, i64 radius, u32 color) {
|
||||
if (w <= 0 || h <= 0) return;
|
||||
for (i64 r=0; r<h; r++) {
|
||||
i64 yy = y + r;
|
||||
if (yy < 0 || (u64)yy >= fb_h) continue;
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)yy * fb_p);
|
||||
for (i64 c=0; c<w; c++) {
|
||||
i64 xx = x + c;
|
||||
if (xx < 0 || (u64)xx >= fb_w) continue;
|
||||
if (rounded_rect_contains(xx, yy, x, y, w, h, radius)) line[(u64)xx] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stroke_rounded_rect(u32 *fb, i64 x, i64 y, i64 w, i64 h, i64 radius, i64 thickness, u32 color) {
|
||||
if (w <= 0 || h <= 0 || thickness <= 0) return;
|
||||
for (i64 r=0; r<h; r++) {
|
||||
i64 yy = y + r;
|
||||
if (yy < 0 || (u64)yy >= fb_h) continue;
|
||||
u32 *line = (u32 *)((u8 *)fb + (u64)yy * fb_p);
|
||||
for (i64 c=0; c<w; c++) {
|
||||
i64 xx = x + c;
|
||||
if (xx < 0 || (u64)xx >= fb_w) continue;
|
||||
int outer = rounded_rect_contains(xx, yy, x, y, w, h, radius);
|
||||
int inner = rounded_rect_contains(xx, yy, x + thickness, y + thickness, w - thickness * 2, h - thickness * 2, radius - thickness);
|
||||
if (outer && !inner) line[(u64)xx] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_card(u32 *fb, i64 x, i64 y, i64 w, i64 h, u32 card) {
|
||||
fill_rounded_rect(fb, x, y, w, h, 4, card);
|
||||
}
|
||||
|
||||
static void draw_rounded_input(u32 *fb, i64 x, i64 y, i64 w, i64 h, const char *value, int mask, u32 fg, u32 card_bg, int active) {
|
||||
(void)card_bg;
|
||||
u32 fill = active ? 0xFF45454Au : INPUT_BG;
|
||||
fill_rounded_rect(fb, x, y, w, h, 2, fill);
|
||||
stroke_rounded_rect(fb, x, y, w, h, 2, 1, active ? 0xFF6C6C72 : 0xFF404044);
|
||||
char out[80]; int i=0;
|
||||
while(value[i] && i<76) { out[i] = mask ? '*' : value[i]; i++; }
|
||||
out[i]=0;
|
||||
if (out[0]) fb_text(fb, out, x+14, y+(h-ASCII_H)/2, fg, fill);
|
||||
if (active) {
|
||||
i64 cx2 = x + 14 + i * ASCII_STEP;
|
||||
fill_rect(fb, cx2, y+10, 2, h-20, fg);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- PS/2 scan code set 1 → ASCII ---- */
|
||||
static char scan_to_ascii(u8 sc, int shift) {
|
||||
static const char normal[58] = {
|
||||
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=', 8, '\t',
|
||||
'q','w','e','r','t','y','u','i','o','p','[',']','\n',0,
|
||||
'a','s','d','f','g','h','j','k','l',';','\'', '`',0,'\\',
|
||||
'z','x','c','v','b','n','m',',','.','/',0,'*',0,' '
|
||||
};
|
||||
static const char shifted[58] = {
|
||||
0, 27, '!','@','#','$','%','^','&','*','(',')','_','+', 8, '\t',
|
||||
'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',0,
|
||||
'A','S','D','F','G','H','J','K','L',':','"','~',0,'|',
|
||||
'Z','X','C','V','B','N','M','<','>','?',0,'*',0,' '
|
||||
};
|
||||
if (sc >= 58) return 0;
|
||||
return shift ? shifted[sc] : normal[sc];
|
||||
}
|
||||
|
||||
/* ---- SHA-256 (compact, copied from FirstInit) ---- */
|
||||
#define ROR(x,n) (((x)>>(n))|((x)<<(32-(n))))
|
||||
static const u32 K256[64] = {0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};
|
||||
static void sha256(const char *msg, u8 out[32]) {
|
||||
u32 h[8]={0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19};
|
||||
u8 block[64]; u64 len=0; while(msg[len]) len++;
|
||||
for(int i=0;i<64;i++) block[i]=0;
|
||||
for(u64 i=0;i<len && i<55;i++) block[i]=(u8)msg[i];
|
||||
block[len]=0x80; u64 bit=len*8;
|
||||
for(int i=0;i<8;i++) block[63-i]=(u8)(bit>>(i*8));
|
||||
u32 w[64];
|
||||
for(int i=0;i<16;i++) w[i]=((u32)block[i*4]<<24)|((u32)block[i*4+1]<<16)|((u32)block[i*4+2]<<8)|block[i*4+3];
|
||||
for(int i=16;i<64;i++){u32 s0=ROR(w[i-15],7)^ROR(w[i-15],18)^(w[i-15]>>3);u32 s1=ROR(w[i-2],17)^ROR(w[i-2],19)^(w[i-2]>>10);w[i]=w[i-16]+s0+w[i-7]+s1;}
|
||||
u32 a=h[0],b=h[1],c=h[2],d=h[3],e=h[4],f=h[5],g=h[6],hh=h[7];
|
||||
for(int i=0;i<64;i++){u32 S1=ROR(e,6)^ROR(e,11)^ROR(e,25);u32 ch=(e&f)^((~e)&g);u32 t1=hh+S1+ch+K256[i]+w[i];u32 S0=ROR(a,2)^ROR(a,13)^ROR(a,22);u32 maj=(a&b)^(a&c)^(b&c);u32 t2=S0+maj;hh=g;g=f;f=e;e=d+t1;d=c;c=b;b=a;a=t1+t2;}
|
||||
h[0]+=a;h[1]+=b;h[2]+=c;h[3]+=d;h[4]+=e;h[5]+=f;h[6]+=g;h[7]+=hh;
|
||||
for(int i=0;i<8;i++){out[i*4]=(u8)(h[i]>>24);out[i*4+1]=(u8)(h[i]>>16);out[i*4+2]=(u8)(h[i]>>8);out[i*4+3]=(u8)h[i];}
|
||||
}
|
||||
|
||||
/* ---- conf parsing ----
|
||||
* USER.CONF format (built by FirstInit's build_user_conf, but stored unencrypted
|
||||
* on disk for login.elf to parse):
|
||||
* DESHAB_USERCONF_V1
|
||||
* computer=<pc>
|
||||
* username=<user>
|
||||
* passwordSha256=<64 hex chars>
|
||||
* ...
|
||||
*
|
||||
* If the buffer does NOT start with "DESHAB_USERCONF_V1", it may be XOR-encrypted
|
||||
* with the password hash stream. In that case, the user's entered password is
|
||||
* used to decrypt: SHA256(password) → hash, then buf[i] ^= hash[i & 31].
|
||||
* If the decrypted buffer starts with the magic, the password is correct.
|
||||
*/
|
||||
|
||||
static int streq_n(const char *a, const char *b, u32 n) {
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
if (a[i] != b[i]) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find "key=" in buf, copy value (up to newline) into out (NUL-terminated).
|
||||
* Returns 0 on success, -1 if key not found. */
|
||||
static int conf_get_value(const u8 *buf, u32 size, const char *key, char *out, u32 out_cap) {
|
||||
u32 klen = 0; while (key[klen]) klen++;
|
||||
for (u32 i = 0; i + klen + 1 < size; i++) {
|
||||
/* Match key at start of line (or start of buffer) */
|
||||
if (i > 0 && buf[i-1] != '\n') continue;
|
||||
if (buf[i + klen] != '=') continue;
|
||||
if (!streq_n((const char *)buf + i, key, klen)) continue;
|
||||
/* Found key=, copy value until newline or end */
|
||||
u32 vstart = i + klen + 1;
|
||||
u32 j = 0;
|
||||
while (vstart + j < size && buf[vstart + j] != '\n' && buf[vstart + j] != '\r' && j + 1 < out_cap) {
|
||||
out[j] = (char)buf[vstart + j];
|
||||
j++;
|
||||
}
|
||||
out[j] = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int starts_with(const u8 *buf, u32 size, const char *prefix) {
|
||||
u32 i = 0;
|
||||
while (prefix[i]) {
|
||||
if (i >= size) return 0;
|
||||
if (buf[i] != (u8)prefix[i]) return 0;
|
||||
i++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---- hex string comparison ---- */
|
||||
static int hexeq(const u8 *hash32, const char *hex64) {
|
||||
static const char hx[] = "0123456789abcdef";
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (hex64[i*2] != hx[hash32[i] >> 4]) return 0;
|
||||
if (hex64[i*2+1] != hx[hash32[i] & 0xf]) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---- login state ---- */
|
||||
static char g_username[64];
|
||||
static char g_password_hash[80]; /* 64 hex chars + NUL */
|
||||
static int g_has_user; /* 1 if username extracted */
|
||||
static int g_has_hash; /* 1 if passwordSha256 extracted */
|
||||
static int g_is_encrypted; /* 1 if conf buffer is XOR-encrypted */
|
||||
|
||||
/* ---- UI layout ---- */
|
||||
#define CARD_W 560
|
||||
#define CARD_H 400
|
||||
|
||||
static void draw_login_card(u32 *fb, i64 card_x, i64 card_y, const char *pass, int active,
|
||||
const char *msg, u32 msg_color, u32 fg) {
|
||||
u32 card = CARD_BG;
|
||||
u32 sub_fg = 0xFF9098A0;
|
||||
/* Background + card */
|
||||
fill_gradient_rect(fb, card_x - 24, card_y - 24, CARD_W + 48, CARD_H + 48);
|
||||
draw_card(fb, card_x, card_y, CARD_W, CARD_H, card);
|
||||
/* Title */
|
||||
fb_text(fb, "Deshab Login", card_x + 40, card_y + 40, fg, card);
|
||||
fb_text(fb, "Enter your password to continue", card_x + 40, card_y + 70, sub_fg, card);
|
||||
/* Username field */
|
||||
fb_text(fb, "Username", card_x + 40, card_y + 120, sub_fg, card);
|
||||
draw_rounded_input(fb, card_x + 40, card_y + 150, CARD_W - 80, 44,
|
||||
g_has_user ? g_username : "(unknown)", 0, fg, card, 0);
|
||||
/* Password field */
|
||||
fb_text(fb, "Password", card_x + 40, card_y + 210, sub_fg, card);
|
||||
draw_rounded_input(fb, card_x + 40, card_y + 240, CARD_W - 80, 44, pass, 1, fg, card, active);
|
||||
/* Login button */
|
||||
{
|
||||
u32 btn_bg = ACCENT;
|
||||
fill_rounded_rect(fb, card_x + 40, card_y + 310, 160, 44, 3, btn_bg);
|
||||
fb_text(fb, "Login", card_x + 40 + 56, card_y + 310 + (44 - ASCII_H) / 2,
|
||||
0xFFFFFFFFu, btn_bg);
|
||||
}
|
||||
/* Status / error message */
|
||||
if (msg && msg[0]) {
|
||||
fb_text(fb, msg, card_x + 220, card_y + 322, msg_color, card);
|
||||
}
|
||||
/* Bottom hint */
|
||||
fb_text(fb, "Enter=login Esc=skip Backspace=delete",
|
||||
card_x + 40, card_y + CARD_H - 28, DIM_FG, card);
|
||||
}
|
||||
|
||||
/* Redraw only the password input field (avoids full card redraw on each keystroke) */
|
||||
static void redraw_password_only(u32 *fb, i64 card_x, i64 card_y, const char *pass, u32 fg) {
|
||||
u32 card = CARD_BG;
|
||||
i64 fy = card_y + 240;
|
||||
fill_rect(fb, card_x + 40, fy, CARD_W - 80, 44, card);
|
||||
draw_rounded_input(fb, card_x + 40, fy, CARD_W - 80, 44, pass, 1, fg, card, 1);
|
||||
}
|
||||
|
||||
/* ---- verify password against stored hash or encrypted conf ----
|
||||
* Returns 1 if password is correct, 0 otherwise.
|
||||
* For encrypted conf: XOR-decrypt with SHA256(password); if magic matches, correct.
|
||||
* For unencrypted conf: SHA256(password) == stored passwordSha256 hex string.
|
||||
*/
|
||||
static int verify_password(const u8 *conf_buf, u32 conf_size, const char *password) {
|
||||
if (g_is_encrypted) {
|
||||
/* Decrypt a copy and check magic */
|
||||
u8 hash[32];
|
||||
sha256(password, hash);
|
||||
static u8 scratch[2048];
|
||||
u32 sz = conf_size;
|
||||
if (sz > sizeof(scratch)) sz = sizeof(scratch);
|
||||
for (u32 i = 0; i < sz; i++) scratch[i] = conf_buf[i] ^ hash[i & 31];
|
||||
if (starts_with(scratch, sz, "DESHAB_USERCONF_V1")) {
|
||||
/* Also extract username from decrypted buffer for display */
|
||||
if (!g_has_user) {
|
||||
conf_get_value(scratch, sz, "username", g_username, sizeof(g_username));
|
||||
if (g_username[0]) g_has_user = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else if (g_has_hash) {
|
||||
u8 hash[32];
|
||||
sha256(password, hash);
|
||||
return hexeq(hash, g_password_hash);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void dsk_entry(const dsk_boot_context *ctx) {
|
||||
__asm__ volatile("cli"); /* prevent IRQ1 (ps2kbd) from racing with our polling */
|
||||
logl("[login] boot");
|
||||
logl("[login] calibrating TSC");
|
||||
tsc_calibrate_fi();
|
||||
|
||||
if (!ctx || ctx->magic != 0x44534B31424F4F54ULL) {
|
||||
logl("[login] bad context");
|
||||
return;
|
||||
}
|
||||
|
||||
fb_a = ctx->framebuffer_address;
|
||||
fb_w = ctx->framebuffer_width;
|
||||
fb_h = ctx->framebuffer_height;
|
||||
fb_p = ctx->framebuffer_pitch;
|
||||
|
||||
logl("[login] framebuffer ready");
|
||||
|
||||
/* Get conf data from boot context (passed by DSK) */
|
||||
const u8 *conf_buf = (const u8 *)(u64)ctx->reserved[0];
|
||||
u32 conf_size = (u32)ctx->reserved[1];
|
||||
if (!conf_buf || conf_size == 0) {
|
||||
logl("[login] no conf data, cannot login");
|
||||
/* Mark as skipped (reserved[2]=0) and return */
|
||||
((dsk_boot_context *)ctx)->reserved[2] = 0;
|
||||
return;
|
||||
}
|
||||
logl("[login] conf data received");
|
||||
|
||||
/* Initialize state */
|
||||
g_username[0] = 0;
|
||||
g_password_hash[0] = 0;
|
||||
g_has_user = 0;
|
||||
g_has_hash = 0;
|
||||
g_is_encrypted = 0;
|
||||
|
||||
/* Check if conf is unencrypted (starts with magic) or encrypted */
|
||||
if (starts_with(conf_buf, conf_size, "DESHAB_USERCONF_V1")) {
|
||||
logl("[login] conf is plaintext, parsing");
|
||||
g_is_encrypted = 0;
|
||||
if (conf_get_value(conf_buf, conf_size, "username", g_username, sizeof(g_username)) == 0) {
|
||||
g_has_user = 1;
|
||||
logl("[login] username found");
|
||||
} else {
|
||||
logl("[login] username not found in conf");
|
||||
}
|
||||
if (conf_get_value(conf_buf, conf_size, "passwordSha256", g_password_hash, sizeof(g_password_hash)) == 0) {
|
||||
g_has_hash = 1;
|
||||
logl("[login] password hash found");
|
||||
} else {
|
||||
logl("[login] passwordSha256 not found in conf");
|
||||
}
|
||||
} else {
|
||||
logl("[login] conf appears encrypted, will verify by password decryption");
|
||||
g_is_encrypted = 1;
|
||||
/* Username will be extracted after successful decryption */
|
||||
}
|
||||
|
||||
u32 fg = TEXT_FG;
|
||||
u32 *fb = (u32 *)(u64)fb_a;
|
||||
|
||||
/* Fill background */
|
||||
fill_gradient_rect(fb, 0, 0, (i64)fb_w, (i64)fb_h);
|
||||
|
||||
/* Card position (centered) */
|
||||
i64 card_x = ((i64)fb_w - CARD_W) / 2;
|
||||
i64 card_y = ((i64)fb_h - CARD_H) / 2;
|
||||
|
||||
/* Initial message */
|
||||
const char *msg = "Enter password and press Enter";
|
||||
u32 msg_color = DIM_FG;
|
||||
|
||||
/* Password input buffer */
|
||||
char pass[64];
|
||||
pass[0] = 0;
|
||||
int plen = 0;
|
||||
|
||||
/* Draw initial UI */
|
||||
draw_login_card(fb, card_x, card_y, pass, 1, msg, msg_color, fg);
|
||||
|
||||
/* Input loop */
|
||||
int shift = 0;
|
||||
int release = 0;
|
||||
for (;;) {
|
||||
u8 st = inb(0x64);
|
||||
if (!(st & 1)) { __asm__("pause"); continue; }
|
||||
u8 data = inb(0x60);
|
||||
/* Skip mouse data (bit 5 of status) */
|
||||
if (st & 0x20) continue;
|
||||
|
||||
u8 sc = data;
|
||||
/* Handle extended (E0) sequences — ignore (no arrow keys needed for login) */
|
||||
if (sc == 0xE0) { continue; }
|
||||
/* Handle release (F0 in Set 2, or high bit in Set 1) */
|
||||
if (sc == 0xF0) { release = 1; continue; }
|
||||
if (release) { release = 0; /* track shift release below */ }
|
||||
|
||||
/* Shift press/release */
|
||||
if (sc == 0x2A || sc == 0x36) { shift = 1; continue; }
|
||||
if (sc == 0xAA || sc == 0xB6) { shift = 0; continue; }
|
||||
|
||||
/* Ignore high-bit (release in Set 1) */
|
||||
if (sc & 0x80) continue;
|
||||
|
||||
/* Escape (sc 0x01) — skip login */
|
||||
if (sc == 0x01) {
|
||||
logl("[login] Esc pressed, skipping login");
|
||||
((dsk_boot_context *)ctx)->reserved[2] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
char c = scan_to_ascii(sc, shift);
|
||||
if (!c) continue;
|
||||
|
||||
if (c == '\n') {
|
||||
/* Submit password */
|
||||
if (plen == 0) {
|
||||
/* Empty password — show hint, don't verify */
|
||||
msg = "Password is empty";
|
||||
msg_color = ERROR_FG;
|
||||
draw_login_card(fb, card_x, card_y, pass, 1, msg, msg_color, fg);
|
||||
continue;
|
||||
}
|
||||
logl("[login] verifying password");
|
||||
int ok = verify_password(conf_buf, conf_size, pass);
|
||||
if (ok) {
|
||||
logl("[login] password correct");
|
||||
((dsk_boot_context *)ctx)->reserved[2] = 1;
|
||||
/* Show success message briefly */
|
||||
draw_login_card(fb, card_x, card_y, pass, 0,
|
||||
"Login successful", 0xFF5FAF6Fu, fg);
|
||||
for (int i = 0; i < 30; i++) delay_frame();
|
||||
return;
|
||||
} else {
|
||||
logl("[login] password wrong");
|
||||
msg = "Wrong password, try again";
|
||||
msg_color = ERROR_FG;
|
||||
/* Clear password */
|
||||
pass[0] = 0;
|
||||
plen = 0;
|
||||
draw_login_card(fb, card_x, card_y, pass, 1, msg, msg_color, fg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == 8) {
|
||||
/* Backspace */
|
||||
if (plen > 0) {
|
||||
pass[--plen] = 0;
|
||||
redraw_password_only(fb, card_x, card_y, pass, fg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Regular character */
|
||||
if (plen < 62 && c >= 32 && c <= 126) {
|
||||
pass[plen++] = c;
|
||||
pass[plen] = 0;
|
||||
redraw_password_only(fb, card_x, card_y, pass, fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-4
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
+12
-4
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
+43
-1
@@ -249,8 +249,48 @@ static u16 udp_checksum_ipv4(const u8 *ip, const u8 *udp, u32 udp_len) {
|
||||
return out ? out : 0xffff;
|
||||
}
|
||||
|
||||
/* ---- TSC-based timing (实机要求: 用 CPU 频率计算, 不用循环) ---- */
|
||||
static u64 g_tsc_per_ms = 0;
|
||||
|
||||
static inline u64 rdtsc_nm(void) {
|
||||
u32 lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
static void tsc_calibrate_nm(void) {
|
||||
outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
|
||||
outb(0x40, 0x7c); /* 11932 low = ~10ms */
|
||||
outb(0x40, 0x2e); /* 11932 high */
|
||||
u64 tsc_start = rdtsc_nm();
|
||||
u16 prev = 0; u64 loops = 0;
|
||||
for (;;) {
|
||||
outb(0x43, 0x00);
|
||||
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
|
||||
if (cur > prev && loops > 10) break;
|
||||
prev = cur; loops++;
|
||||
}
|
||||
u64 tsc_end = rdtsc_nm();
|
||||
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
|
||||
}
|
||||
|
||||
static void delay_ms_nm(u32 ms) {
|
||||
if (!g_tsc_per_ms) {
|
||||
for (volatile u32 i = 0; i < 100000 * ms; i++) __asm__ volatile("pause");
|
||||
return;
|
||||
}
|
||||
u64 target = g_tsc_per_ms * ms;
|
||||
u64 start = rdtsc_nm();
|
||||
while (rdtsc_nm() - start < target) __asm__ volatile("pause");
|
||||
}
|
||||
|
||||
static void delay_spin(u32 loops) {
|
||||
for (volatile u32 i=0;i<loops;i++) { __asm__ volatile("pause"); }
|
||||
/* 兼容旧调用: 粗略转换为 ms (实机以 TSC 为准) */
|
||||
if (g_tsc_per_ms) {
|
||||
delay_ms_nm(loops / 10000 + 1);
|
||||
} else {
|
||||
for (volatile u32 i=0;i<loops;i++) { __asm__ volatile("pause"); }
|
||||
}
|
||||
}
|
||||
|
||||
/* 构造并发送一个 DHCP 报文。type: 1=DISCOVER 3=REQUEST */
|
||||
@@ -617,6 +657,8 @@ __attribute__((visibility("default")))
|
||||
void dsk_entry(const dsk_boot_context *ctx) {
|
||||
logl("[netman] boot");
|
||||
if (!ctx || ctx->magic != DSK_BOOT_MAGIC) { logl("[netman] bad context"); return; }
|
||||
logl("[netman] calibrating TSC (实机 CPU 频率计算)");
|
||||
tsc_calibrate_nm();
|
||||
u64 api = ctx->dkm_kernel_api;
|
||||
if (api) {
|
||||
u64 block_api = *(u64 *)(api + 0xA8);
|
||||
|
||||
Binary file not shown.
+12
-4
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
+1276
-14
@@ -15,9 +15,55 @@ typedef long long i64;
|
||||
|
||||
static __inline__ void outb(u16 port, u8 value) { __asm__ volatile("outb %0,%1"::"a"(value),"Nd"(port)); }
|
||||
static __inline__ u8 inb(u16 port) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(port)); return v; }
|
||||
static __inline__ void outl(u16 port, u32 value) { __asm__ volatile("outl %0,%1"::"a"(value),"Nd"(port)); }
|
||||
static __inline__ u32 inl(u16 port) { u32 v; __asm__ volatile("inl %1,%0":"=a"(v):"Nd"(port)); return v; }
|
||||
|
||||
/* ---- TSC-based timing (实机要求: 用 CPU 频率计算, 不用循环) ---- */
|
||||
static u64 g_tsc_per_ms = 0;
|
||||
|
||||
static __inline__ u64 rdtsc_shell(void) {
|
||||
u32 lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
/* 通过 PIT ch0 (16-bit mode 0) 校准 TSC ~10ms 计数 */
|
||||
static void tsc_calibrate_shell(void) {
|
||||
outb(0x43, 0x30); /* ch0, lo+hi, mode 0, binary */
|
||||
outb(0x40, 0x7c); /* 11932 low = ~10ms */
|
||||
outb(0x40, 0x2e); /* 11932 high */
|
||||
u64 tsc_start = rdtsc_shell();
|
||||
u16 prev = 0; u64 loops = 0;
|
||||
for (;;) {
|
||||
outb(0x43, 0x00);
|
||||
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
|
||||
if (cur > prev && loops > 10) break;
|
||||
prev = cur; loops++;
|
||||
}
|
||||
u64 tsc_end = rdtsc_shell();
|
||||
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
|
||||
}
|
||||
|
||||
/* 串口发送等待: TSC 100us 超时, 校准失败时回退到循环 */
|
||||
static void serial_wait_tx_shell(void) {
|
||||
if (g_tsc_per_ms == 0) {
|
||||
tsc_calibrate_shell();
|
||||
}
|
||||
if (g_tsc_per_ms == 0) {
|
||||
for (u32 i = 0; i < 100000; i++) {
|
||||
if (inb(COM1 + 5) & 0x20) break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
u64 deadline = rdtsc_shell() + g_tsc_per_ms / 10; /* 100us 超时 */
|
||||
while (rdtsc_shell() < deadline) {
|
||||
if (inb(COM1 + 5) & 0x20) break;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
}
|
||||
|
||||
static void sputc(char c) {
|
||||
for (unsigned int i=0; i<100000; i++) { if (inb(COM1+5)&0x20) break; }
|
||||
serial_wait_tx_shell();
|
||||
outb(COM1, (unsigned char)c);
|
||||
}
|
||||
static void swrite(const char *s) { while(*s) { if(*s=='\n')sputc('\r'); sputc(*s++); } }
|
||||
@@ -26,6 +72,430 @@ static void logl(const char *s) { swrite(s); swrite("\n"); }
|
||||
/* ASCII 字体 — 必须在 deshab_ui.h 之前包含,因为 du_draw_char 引用 g_ascii */
|
||||
#include "../firstInit/ascii_bitmaps.c"
|
||||
#include "../UTSM/include/utsm/deshab_ui.h"
|
||||
/* 用户态共享协议栈(ping/curl 内建命令使用) */
|
||||
#include "../tools/net_stack.h"
|
||||
|
||||
/* ============================================================
|
||||
* Block 设备 + FAT32 读写(移植自 DSK,支持 cp/mv/cat/ls)
|
||||
* ============================================================ */
|
||||
|
||||
typedef int (*shell_block_read_fn)(u32 index, u64 lba, u32 count, void *buf);
|
||||
typedef int (*shell_block_write_fn)(u32 index, u64 lba, u32 count, const void *buf);
|
||||
|
||||
static shell_block_read_fn g_block_read;
|
||||
static shell_block_write_fn g_block_write;
|
||||
|
||||
/* FAT32 BPB / 目录项结构(与 DSK 一致,packed) */
|
||||
typedef struct __attribute__((packed)) {
|
||||
u8 jmp[3]; char oem[8]; u16 bps; u8 spc; u16 rsvd; u8 fc; u16 root_ent;
|
||||
u16 ts16; u8 media; u16 spf16; u16 spt; u16 heads; u32 hidden; u32 ts32;
|
||||
u32 spf; u16 flags; u16 ver; u32 root_clus; u16 fsi; u16 bkboot;
|
||||
u8 res[12]; u8 drv; u8 ntfl; u8 sig; u32 ser; char lbl[11]; char typ[8];
|
||||
u8 code[420]; u16 boot_sig;
|
||||
} shell_fat32_bpb;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
char name[11]; u8 attr; u8 ntr; u8 ctenth;
|
||||
u16 ctime; u16 cdate; u16 adate; u16 chigh;
|
||||
u16 wtime; u16 wdate; u16 clow; u32 fsize;
|
||||
} shell_fat32_de;
|
||||
|
||||
static u32 sh_r32(const u8 *p) { return (u32)p[0]|((u32)p[1]<<8)|((u32)p[2]<<16)|((u32)p[3]<<24); }
|
||||
static u16 sh_r16(const u8 *p) { return (u16)p[0]|((u16)p[1]<<8); }
|
||||
static int sh_neq11(const char *a, const char *b) { for(int i=0;i<11;i++) if(a[i]!=b[i]) return 0; return 1; }
|
||||
|
||||
/* 批量读写缓冲区(与 DSK 对齐:256 扇区覆盖 BPB+FAT+根目录+小文件) */
|
||||
static u8 g_disk[131072]; /* 256 扇区 BPB+FAT+根目录缓存 */
|
||||
static u8 g_cluster[4096]; /* 单簇缓冲 */
|
||||
static u8 g_fdata[262144]; /* 文件数据缓冲(最大 256KB) */
|
||||
static int g_disk_loaded = 0; /* g_disk 是否已加载 BPB+FAT */
|
||||
|
||||
static int sh_read_sectors(u32 lba, u32 count, u8 *out) { return g_block_read ? g_block_read(0,lba,count,out) : -1; }
|
||||
static int sh_write_sectors(u32 lba, u32 count, const u8 *buf) { return g_block_write ? g_block_write(0,lba,count,buf) : -1; }
|
||||
|
||||
/* 确保 g_disk 已加载 BPB+FAT+根目录(256 扇区) */
|
||||
static int sh_disk_load(void) {
|
||||
if (g_disk_loaded) return 0;
|
||||
if (sh_read_sectors(0, 256, g_disk) != 0) return -1;
|
||||
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
|
||||
if (bpb->boot_sig != 0xAA55 || bpb->bps != 512) return -2;
|
||||
if (bpb->spf == 0 || bpb->root_clus < 2) return -3;
|
||||
g_disk_loaded = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 把 "file.txt" / "NAME" 转为 11 字符 8.3 名(大写,空格填充)
|
||||
* 返回 0 成功,-1 失败(过长或非法字符) */
|
||||
static int name_to_83(const char *in, char out[11]) {
|
||||
for (int i = 0; i < 11; i++) out[i] = ' ';
|
||||
int inlen = 0;
|
||||
while (in[inlen] && inlen < 13) inlen++;
|
||||
if (inlen == 0 || inlen > 12) return -1;
|
||||
int dot = -1;
|
||||
for (int i = 0; i < inlen; i++) if (in[i] == '.') dot = i;
|
||||
int base_end = (dot >= 0) ? dot : inlen;
|
||||
if (base_end == 0 || base_end > 8) return -1;
|
||||
for (int j = 0; j < base_end; j++) {
|
||||
char c = in[j];
|
||||
if (c >= 'a' && c <= 'z') c -= 32;
|
||||
if (c == '.' || c == ' ' || c == '/' || c == '\\') return -1;
|
||||
out[j] = c;
|
||||
}
|
||||
if (dot >= 0) {
|
||||
int extlen = inlen - dot - 1;
|
||||
if (extlen > 3) return -1;
|
||||
for (int j = 0; j < extlen; j++) {
|
||||
char c = in[dot + 1 + j];
|
||||
if (c >= 'a' && c <= 'z') c -= 32;
|
||||
if (c == '.' || c == ' ' || c == '/' || c == '\\') return -1;
|
||||
out[8 + j] = c;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 把 11 字符 8.3 名转为可显示字符串(如 "README.TXT") */
|
||||
static void name_from_83(const char in[11], char out[13]) {
|
||||
int p = 0;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (in[j] == ' ') break;
|
||||
out[p++] = in[j];
|
||||
}
|
||||
if (in[8] != ' ') {
|
||||
out[p++] = '.';
|
||||
for (int j = 8; j < 11; j++) {
|
||||
if (in[j] == ' ') break;
|
||||
out[p++] = in[j];
|
||||
}
|
||||
}
|
||||
out[p] = 0;
|
||||
}
|
||||
|
||||
/* 在根目录簇链中查找 11 字符名,输出首簇号与文件大小 */
|
||||
static int fat32_find_in_root(const u8 *clus, u32 clus_sectors, const char *target,
|
||||
u32 *out_clus, u32 *out_size, u32 *out_idx) {
|
||||
const shell_fat32_de *dir = (const shell_fat32_de *)clus;
|
||||
for (u32 e = 0; e * 32 < clus_sectors * 512; e++) {
|
||||
if (dir[e].name[0] == 0) break;
|
||||
if ((u8)dir[e].name[0] == 0xE5) continue;
|
||||
if (dir[e].attr == 0x0F) continue;
|
||||
if (dir[e].attr & 0x08) continue;
|
||||
if (sh_neq11(dir[e].name, target)) {
|
||||
*out_clus = (u32)sh_r16((const u8*)&dir[e].clow) | ((u32)sh_r16((const u8*)&dir[e].chigh) << 16);
|
||||
*out_size = dir[e].fsize;
|
||||
if (out_idx) *out_idx = e;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 读取根目录下指定 8.3 名文件到 g_fdata。
|
||||
* 返回 0 成功,*out_data 指向 g_fdata,*out_size 为字节数;非 0 失败。 */
|
||||
static int fat32_read_root_file(const char *name11, u8 **out_data, u32 *out_size) {
|
||||
if (sh_disk_load() != 0) return -1;
|
||||
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
|
||||
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
|
||||
u32 fat_byte_off = bpb->rsvd * 512;
|
||||
u32 spc = bpb->spc;
|
||||
|
||||
u32 clus = bpb->root_clus;
|
||||
u32 found_clus = 0, found_size = 0;
|
||||
int found = 0;
|
||||
while (clus >= 2 && clus < 0x0FFFFFF8 && !found) {
|
||||
u32 lba = data_lba + (clus - 2) * spc;
|
||||
const u8 *cb;
|
||||
if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512)
|
||||
cb = g_disk + (u64)lba * 512;
|
||||
else {
|
||||
if (sh_read_sectors(lba, 8, g_cluster) != 0) return -4;
|
||||
cb = g_cluster;
|
||||
}
|
||||
if (fat32_find_in_root(cb, spc, name11, &found_clus, &found_size, 0) == 0) { found = 1; break; }
|
||||
u32 fo = fat_byte_off + clus * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
clus = sh_r32(g_disk + fo) & 0x0FFFFFFF;
|
||||
}
|
||||
if (!found) return -5;
|
||||
if (found_size > sizeof(g_fdata)) return -6;
|
||||
|
||||
u8 *dst = g_fdata; u32 remaining = found_size; u32 fc = found_clus;
|
||||
while (fc >= 2 && fc < 0x0FFFFFF8 && remaining > 0) {
|
||||
u32 fc_lba = data_lba + (fc - 2) * spc;
|
||||
u32 fc_bytes = spc * 512;
|
||||
if (fc_bytes > remaining) fc_bytes = remaining;
|
||||
const u8 *fb;
|
||||
if ((u64)fc_lba * 512 + (u64)spc * 512 <= 256ULL * 512)
|
||||
fb = g_disk + (u64)fc_lba * 512;
|
||||
else {
|
||||
if (sh_read_sectors(fc_lba, 8, g_cluster) != 0) return -7;
|
||||
fb = g_cluster;
|
||||
}
|
||||
for (u32 b = 0; b < fc_bytes; b++) dst[b] = fb[b];
|
||||
dst += fc_bytes; remaining -= fc_bytes;
|
||||
u32 fo = fat_byte_off + fc * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
fc = sh_r32(g_disk + fo) & 0x0FFFFFFF;
|
||||
}
|
||||
*out_data = g_fdata; *out_size = found_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 写入根目录下指定 8.3 名文件(存在则替换,不存在则新建)。
|
||||
* 依赖 g_disk 已加载 BPB+FAT。返回 0 成功。 */
|
||||
static int fat32_write_root_file(const char *name11, const u8 *data, u32 size) {
|
||||
if (sh_disk_load() != 0) return -1;
|
||||
/* 写入前重新加载 BPB+FAT,保证与盘上一致 */
|
||||
if (sh_read_sectors(0, 256, g_disk) != 0) return -2;
|
||||
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
|
||||
u32 spc = bpb->spc;
|
||||
u32 fat_lba = bpb->rsvd;
|
||||
u32 fat_sectors = bpb->spf;
|
||||
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
|
||||
u32 fat_byte_off = bpb->rsvd * 512;
|
||||
u32 root_clus = bpb->root_clus;
|
||||
u32 cluster_bytes = spc * 512;
|
||||
|
||||
u32 root_lba = data_lba + (root_clus - 2) * spc;
|
||||
u8 *root_buf = g_disk + (u64)root_lba * 512;
|
||||
u32 max_entries = cluster_bytes / 32;
|
||||
shell_fat32_de *dir = (shell_fat32_de *)root_buf;
|
||||
int free_entry = -1;
|
||||
u32 existing_clus = 0;
|
||||
int found = 0;
|
||||
u32 existing_idx = 0;
|
||||
for (u32 e = 0; e < max_entries; e++) {
|
||||
if (dir[e].name[0] == 0) { if (free_entry < 0) free_entry = (int)e; break; }
|
||||
if ((u8)dir[e].name[0] == 0xE5) { if (free_entry < 0) free_entry = (int)e; continue; }
|
||||
if (dir[e].attr == 0x0F) continue;
|
||||
if (dir[e].attr & 0x08) continue;
|
||||
if (sh_neq11(dir[e].name, name11)) {
|
||||
existing_clus = (u32)sh_r16((const u8*)&dir[e].clow) | ((u32)sh_r16((const u8*)&dir[e].chigh) << 16);
|
||||
found = 1; existing_idx = e;
|
||||
if (free_entry < 0) free_entry = (int)e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 bytes_needed = size > 0 ? size : 1;
|
||||
u32 clusters_needed = (bytes_needed + cluster_bytes - 1) / cluster_bytes;
|
||||
u32 first_clus = 0;
|
||||
u32 prev_clus = 0;
|
||||
|
||||
if (found && existing_clus >= 2) {
|
||||
first_clus = existing_clus;
|
||||
u32 cur = existing_clus;
|
||||
u32 count = 0;
|
||||
while (cur >= 2 && cur < 0x0FFFFFF8 && count < clusters_needed) {
|
||||
prev_clus = cur;
|
||||
u32 fo = fat_byte_off + cur * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
cur = sh_r32(g_disk + fo) & 0x0FFFFFFF;
|
||||
count++;
|
||||
}
|
||||
while (count < clusters_needed) {
|
||||
u32 newc = 0;
|
||||
for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) {
|
||||
u32 fo = fat_byte_off + c * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
if ((sh_r32(g_disk + fo) & 0x0FFFFFFF) == 0) { newc = c; break; }
|
||||
}
|
||||
if (newc == 0) return -3;
|
||||
u32 pfo = fat_byte_off + prev_clus * 4;
|
||||
if (pfo + 4 <= sizeof(g_disk)) {
|
||||
g_disk[pfo] = (u8)(newc & 0xFF);
|
||||
g_disk[pfo+1] = (u8)((newc >> 8) & 0xFF);
|
||||
g_disk[pfo+2] = (u8)((newc >> 16) & 0xFF);
|
||||
g_disk[pfo+3] = (u8)((newc >> 24) & 0x0F);
|
||||
}
|
||||
prev_clus = newc;
|
||||
count++;
|
||||
}
|
||||
if (prev_clus >= 2) {
|
||||
u32 fo = fat_byte_off + prev_clus * 4;
|
||||
if (fo + 4 <= sizeof(g_disk)) {
|
||||
g_disk[fo] = 0xF8; g_disk[fo+1] = 0xFF; g_disk[fo+2] = 0xFF; g_disk[fo+3] = 0x0F;
|
||||
}
|
||||
}
|
||||
/* 释放多余旧簇 */
|
||||
u32 next = 0;
|
||||
u32 fo = fat_byte_off + prev_clus * 4;
|
||||
if (fo + 4 <= sizeof(g_disk)) next = sh_r32(g_disk + fo) & 0x0FFFFFFF;
|
||||
while (next >= 2 && next < 0x0FFFFFF8) {
|
||||
u32 nfo = fat_byte_off + next * 4;
|
||||
u32 nn = 0;
|
||||
if (nfo + 4 <= sizeof(g_disk)) nn = sh_r32(g_disk + nfo) & 0x0FFFFFFF;
|
||||
g_disk[nfo] = 0; g_disk[nfo+1] = 0; g_disk[nfo+2] = 0; g_disk[nfo+3] = 0;
|
||||
next = nn;
|
||||
}
|
||||
} else {
|
||||
if (free_entry < 0) return -4;
|
||||
for (u32 i = 0; i < clusters_needed; i++) {
|
||||
u32 newc = 0;
|
||||
for (u32 c = 2; c < (fat_sectors * 512) / 4; c++) {
|
||||
u32 fo = fat_byte_off + c * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
if ((sh_r32(g_disk + fo) & 0x0FFFFFFF) == 0) { newc = c; break; }
|
||||
}
|
||||
if (newc == 0) return -3;
|
||||
if (i == 0) first_clus = newc;
|
||||
if (prev_clus >= 2) {
|
||||
u32 pfo = fat_byte_off + prev_clus * 4;
|
||||
g_disk[pfo] = (u8)(newc & 0xFF);
|
||||
g_disk[pfo+1] = (u8)((newc >> 8) & 0xFF);
|
||||
g_disk[pfo+2] = (u8)((newc >> 16) & 0xFF);
|
||||
g_disk[pfo+3] = (u8)((newc >> 24) & 0x0F);
|
||||
}
|
||||
prev_clus = newc;
|
||||
}
|
||||
if (prev_clus >= 2) {
|
||||
u32 fo = fat_byte_off + prev_clus * 4;
|
||||
g_disk[fo] = 0xF8; g_disk[fo+1] = 0xFF; g_disk[fo+2] = 0xFF; g_disk[fo+3] = 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
/* 写数据到簇 */
|
||||
u32 remaining = size;
|
||||
const u8 *src = data;
|
||||
u32 cur = first_clus;
|
||||
u32 ci = 0;
|
||||
while (cur >= 2 && cur < 0x0FFFFFF8 && ci < clusters_needed) {
|
||||
u32 clba = data_lba + (cur - 2) * spc;
|
||||
u32 chunk = remaining < cluster_bytes ? remaining : cluster_bytes;
|
||||
if ((u64)clba * 512 + cluster_bytes <= 256ULL * 512) {
|
||||
u8 *dst = g_disk + (u64)clba * 512;
|
||||
for (u32 b = 0; b < chunk; b++) dst[b] = src[b];
|
||||
for (u32 b = chunk; b < cluster_bytes; b++) dst[b] = 0;
|
||||
} else {
|
||||
if (sh_read_sectors(clba, spc, g_cluster) != 0) return -5;
|
||||
for (u32 b = 0; b < chunk; b++) g_cluster[b] = src[b];
|
||||
for (u32 b = chunk; b < cluster_bytes; b++) g_cluster[b] = 0;
|
||||
if (sh_write_sectors(clba, spc, g_cluster) != 0) return -6;
|
||||
}
|
||||
src += chunk; remaining -= chunk; ci++;
|
||||
u32 fo = fat_byte_off + cur * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
cur = sh_r32(g_disk + fo) & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
/* 更新目录项 */
|
||||
u32 entry_idx = found ? existing_idx : (u32)free_entry;
|
||||
shell_fat32_de *e = &dir[entry_idx];
|
||||
if (!found) {
|
||||
for (int i = 0; i < 11; i++) e->name[i] = name11[i];
|
||||
e->attr = 0x20; e->ntr = 0; e->ctenth = 0; e->ctime = 0; e->cdate = 0; e->adate = 0;
|
||||
}
|
||||
e->chigh = (u16)((first_clus >> 16) & 0xFFFF);
|
||||
e->clow = (u16)(first_clus & 0xFFFF);
|
||||
e->fsize = size;
|
||||
|
||||
/* 回写 FAT(两份)+ 根目录 + 缓冲区内的数据簇 */
|
||||
for (u32 f = 0; f < bpb->fc; f++) {
|
||||
u32 flba = fat_lba + f * fat_sectors;
|
||||
if (sh_write_sectors(flba, fat_sectors, g_disk + (u64)flba * 512) != 0) return -7;
|
||||
}
|
||||
u32 root_dir_lba = data_lba + (root_clus - 2) * spc;
|
||||
if ((u64)root_dir_lba * 512 + cluster_bytes <= 256ULL * 512) {
|
||||
if (sh_write_sectors(root_dir_lba, spc, g_disk + (u64)root_dir_lba * 512) != 0) return -8;
|
||||
}
|
||||
cur = first_clus; ci = 0;
|
||||
while (cur >= 2 && cur < 0x0FFFFFF8 && ci < clusters_needed) {
|
||||
u32 clba = data_lba + (cur - 2) * spc;
|
||||
if ((u64)clba * 512 + cluster_bytes <= 256ULL * 512) {
|
||||
if (sh_write_sectors(clba, spc, g_disk + (u64)clba * 512) != 0) return -9;
|
||||
}
|
||||
u32 fo = fat_byte_off + cur * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
cur = sh_r32(g_disk + fo) & 0x0FFFFFFF;
|
||||
ci++;
|
||||
}
|
||||
g_disk_loaded = 0; /* 下次操作重新加载,避免使用脏缓存 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 删除根目录下指定 8.3 名文件:清空簇链 + 标记目录项为 0xE5。
|
||||
* 返回 0 成功,-1 未找到,其他负值失败。 */
|
||||
static int fat32_delete_root_file(const char *name11) {
|
||||
if (sh_disk_load() != 0) return -2;
|
||||
if (sh_read_sectors(0, 256, g_disk) != 0) return -3;
|
||||
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
|
||||
u32 spc = bpb->spc;
|
||||
u32 fat_lba = bpb->rsvd;
|
||||
u32 fat_sectors = bpb->spf;
|
||||
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
|
||||
u32 fat_byte_off = bpb->rsvd * 512;
|
||||
u32 root_clus = bpb->root_clus;
|
||||
|
||||
u32 root_lba = data_lba + (root_clus - 2) * spc;
|
||||
u8 *root_buf = g_disk + (u64)root_lba * 512;
|
||||
u32 max_entries = (spc * 512) / 32;
|
||||
shell_fat32_de *dir = (shell_fat32_de *)root_buf;
|
||||
u32 found_idx = 0xFFFFFFFFu;
|
||||
for (u32 e = 0; e < max_entries; e++) {
|
||||
if (dir[e].name[0] == 0) break;
|
||||
if ((u8)dir[e].name[0] == 0xE5) continue;
|
||||
if (dir[e].attr == 0x0F) continue;
|
||||
if (dir[e].attr & 0x08) continue;
|
||||
if (sh_neq11(dir[e].name, name11)) { found_idx = e; break; }
|
||||
}
|
||||
if (found_idx == 0xFFFFFFFFu) return -1;
|
||||
|
||||
/* 释放簇链 */
|
||||
u32 cur = (u32)sh_r16((const u8*)&dir[found_idx].clow) | ((u32)sh_r16((const u8*)&dir[found_idx].chigh) << 16);
|
||||
while (cur >= 2 && cur < 0x0FFFFFF8) {
|
||||
u32 fo = fat_byte_off + cur * 4;
|
||||
u32 next = 0;
|
||||
if (fo + 4 <= sizeof(g_disk)) next = sh_r32(g_disk + fo) & 0x0FFFFFFF;
|
||||
g_disk[fo] = 0; g_disk[fo+1] = 0; g_disk[fo+2] = 0; g_disk[fo+3] = 0;
|
||||
cur = next;
|
||||
}
|
||||
/* 标记目录项为已删除 */
|
||||
dir[found_idx].name[0] = (char)0xE5;
|
||||
|
||||
/* 回写 FAT + 根目录 */
|
||||
for (u32 f = 0; f < bpb->fc; f++) {
|
||||
u32 flba = fat_lba + f * fat_sectors;
|
||||
if (sh_write_sectors(flba, fat_sectors, g_disk + (u64)flba * 512) != 0) return -4;
|
||||
}
|
||||
if (sh_write_sectors(root_lba, spc, g_disk + (u64)root_lba * 512) != 0) return -5;
|
||||
g_disk_loaded = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 列出根目录所有文件/目录,调用回调输出 */
|
||||
static int fat32_list_root(int (*emit)(const char *name, u32 size, u8 attr, void *u), void *u) {
|
||||
if (sh_disk_load() != 0) return -1;
|
||||
const shell_fat32_bpb *bpb = (const shell_fat32_bpb *)g_disk;
|
||||
u32 data_lba = bpb->rsvd + (u32)bpb->fc * bpb->spf;
|
||||
u32 fat_byte_off = bpb->rsvd * 512;
|
||||
u32 spc = bpb->spc;
|
||||
u32 clus = bpb->root_clus;
|
||||
while (clus >= 2 && clus < 0x0FFFFFF8) {
|
||||
u32 lba = data_lba + (clus - 2) * spc;
|
||||
const u8 *cb;
|
||||
if ((u64)lba * 512 + (u64)spc * 512 <= 256ULL * 512)
|
||||
cb = g_disk + (u64)lba * 512;
|
||||
else {
|
||||
if (sh_read_sectors(lba, 8, g_cluster) != 0) return -4;
|
||||
cb = g_cluster;
|
||||
}
|
||||
const shell_fat32_de *dir = (const shell_fat32_de *)cb;
|
||||
for (u32 e = 0; e * 32 < spc * 512; e++) {
|
||||
if (dir[e].name[0] == 0) goto done;
|
||||
if ((u8)dir[e].name[0] == 0xE5) continue;
|
||||
if (dir[e].attr == 0x0F) continue;
|
||||
if (dir[e].attr & 0x08) continue;
|
||||
char disp[13];
|
||||
name_from_83(dir[e].name, disp);
|
||||
if (emit(disp, dir[e].fsize, dir[e].attr, u) != 0) goto done;
|
||||
}
|
||||
u32 fo = fat_byte_off + clus * 4;
|
||||
if (fo + 4 > sizeof(g_disk)) break;
|
||||
clus = sh_r32(g_disk + fo) & 0x0FFFFFFF;
|
||||
}
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- 风格令牌(引用 deshab_ui.h 语义色) ---- */
|
||||
#define BG_COLOR DS_DARK_BG_PRIMARY
|
||||
@@ -114,7 +584,11 @@ static void term_newline(void) {
|
||||
if (cur_row >= term_h) term_scroll();
|
||||
}
|
||||
|
||||
/* dev_mode 串口镜像:reserved[3]=1 时终端输出同步写 COM1,便于自动化验证 */
|
||||
static int g_serial_mirror = 0;
|
||||
|
||||
static void term_putc_color(char c, u32 color) {
|
||||
if (g_serial_mirror) { if (c == '\n') sputc('\r'); sputc(c); }
|
||||
if (c == '\n') { term_newline(); return; }
|
||||
if (c == '\r') { cur_col = 0; return; }
|
||||
if (c == '\t') {
|
||||
@@ -220,6 +694,74 @@ static char input_buf[256];
|
||||
static int input_len = 0;
|
||||
static int input_cursor = 0;
|
||||
|
||||
/* ---- 命令历史(上下箭头浏览) ---- */
|
||||
/* 前向声明: redraw_input_line 在下方定义 */
|
||||
static void redraw_input_line(void);
|
||||
|
||||
#define HISTORY_MAX 32
|
||||
static char g_history[HISTORY_MAX][256];
|
||||
static int g_history_count = 0; /* 已记录命令条数 (0..HISTORY_MAX) */
|
||||
static int g_history_view = -1; /* 当前浏览索引, -1 表示正在编辑新输入 */
|
||||
|
||||
/* 将命令推入历史。空字符串或纯空白不入历史;与最近一条相同时跳过。 */
|
||||
static void history_push(const char *cmd) {
|
||||
const char *p = cmd;
|
||||
while (*p == ' ') p++;
|
||||
if (*p == 0) return;
|
||||
/* 与最近一条相同则跳过 */
|
||||
if (g_history_count > 0) {
|
||||
const char *latest = g_history[(g_history_count - 1) % HISTORY_MAX];
|
||||
const char *a = latest;
|
||||
const char *b = p;
|
||||
while (*a && *b && *a == *b) { a++; b++; }
|
||||
if (*a == 0 && *b == 0) return;
|
||||
}
|
||||
int idx = g_history_count % HISTORY_MAX;
|
||||
int i = 0;
|
||||
while (p[i] && i < 255) { g_history[idx][i] = p[i]; i++; }
|
||||
g_history[idx][i] = 0;
|
||||
if (g_history_count < HISTORY_MAX) g_history_count++;
|
||||
}
|
||||
|
||||
/* 加载历史条目到 input_buf 并刷新显示 */
|
||||
static void history_load(int idx) {
|
||||
const char *src = g_history[idx % HISTORY_MAX];
|
||||
int i = 0;
|
||||
while (src[i] && i < 255) { input_buf[i] = src[i]; i++; }
|
||||
input_buf[i] = 0;
|
||||
input_len = i;
|
||||
input_cursor = i;
|
||||
redraw_input_line();
|
||||
}
|
||||
|
||||
/* 上箭头: 浏览更早的命令 */
|
||||
static void history_prev(void) {
|
||||
if (g_history_count == 0) return;
|
||||
if (g_history_view == -1) {
|
||||
g_history_view = g_history_count - 1;
|
||||
} else if (g_history_view > 0) {
|
||||
g_history_view--;
|
||||
} else {
|
||||
return; /* 已到达最早一条 */
|
||||
}
|
||||
history_load(g_history_view);
|
||||
}
|
||||
|
||||
/* 下箭头: 浏览更新的命令; 超过最新则回到空输入 */
|
||||
static void history_next(void) {
|
||||
if (g_history_view == -1) return;
|
||||
g_history_view++;
|
||||
if (g_history_view >= g_history_count) {
|
||||
g_history_view = -1;
|
||||
input_len = 0;
|
||||
input_cursor = 0;
|
||||
input_buf[0] = 0;
|
||||
redraw_input_line();
|
||||
return;
|
||||
}
|
||||
history_load(g_history_view);
|
||||
}
|
||||
|
||||
/* ---- 键盘扫描码 → ASCII(Set 1) ---- */
|
||||
static char scan_to_ascii(u8 sc, int shift) {
|
||||
static const char normal[58] = {
|
||||
@@ -248,16 +790,25 @@ static void cmd_help(void) {
|
||||
term_puts_color("Deshab Shell — 内置命令列表:\n", PROMPT_FG);
|
||||
term_puts(" help 显示此帮助\n");
|
||||
term_puts(" clear 清屏\n");
|
||||
term_puts(" echo <text> 显示文本\n");
|
||||
term_puts(" version 显示系统版本\n");
|
||||
term_puts(" echo <text> 显示文本(-n 不换行, > file 重定向写盘)\n");
|
||||
term_puts(" ls / dir 列出根目录文件\n");
|
||||
term_puts(" cat <file> 显示文件内容\n");
|
||||
term_puts(" cp <s> <d> 复制文件\n");
|
||||
term_puts(" mv <s> <d> 移动/重命名文件\n");
|
||||
term_puts(" rm <file> 删除文件\n");
|
||||
term_puts(" pwd 显示当前目录\n");
|
||||
term_puts(" whoami 显示当前用户\n");
|
||||
term_puts(" id 显示用户ID\n");
|
||||
term_puts(" version/ver 显示系统版本\n");
|
||||
term_puts(" uname 显示系统名称\n");
|
||||
term_puts(" date 显示当前日期\n");
|
||||
term_puts(" ver 显示内核版本(同 version)\n");
|
||||
term_puts(" about 关于 Deshab\n");
|
||||
term_puts(" pci 列出 PCI 设备\n");
|
||||
term_puts(" ping [ip] ICMP echo 测试(缺省网关 10.0.2.2)\n");
|
||||
term_puts(" curl <url> HTTP GET 请求(http://host[:port]/path)\n");
|
||||
term_puts(" run <NAME.ELF> 运行根目录下的工具程序\n");
|
||||
term_puts(" reboot 重启系统\n");
|
||||
term_puts(" halt 关机(停止 CPU)\n");
|
||||
term_puts(" ls 列出根目录文件(暂未实现,需要 VFS)\n");
|
||||
term_puts(" pci 列出 PCI 设备(暂未实现)\n");
|
||||
}
|
||||
|
||||
static void cmd_version(void) {
|
||||
@@ -301,9 +852,45 @@ static void cmd_halt(void) {
|
||||
for(;;) __asm__("hlt");
|
||||
}
|
||||
|
||||
/* echo:支持 -n(不换行)和 " > file" 重定向写盘 */
|
||||
static void cmd_echo(const char *args) {
|
||||
int newline = 1;
|
||||
if (args && args[0] == '-' && args[1] == 'n' && (args[2] == ' ' || args[2] == 0)) {
|
||||
newline = 0;
|
||||
args += 2;
|
||||
while (*args == ' ') args++;
|
||||
}
|
||||
/* 检测 " > file" 重定向 */
|
||||
const char *redir = 0;
|
||||
if (args) {
|
||||
const char *p = args;
|
||||
while (*p) { if (*p == '>') { redir = p; break; } p++; }
|
||||
}
|
||||
if (redir) {
|
||||
int text_len = (int)(redir - args);
|
||||
while (text_len > 0 && args[text_len-1] == ' ') text_len--;
|
||||
const char *fname = redir + 1;
|
||||
while (*fname == ' ') fname++;
|
||||
char fnbuf[64]; int fl = 0;
|
||||
while (*fname && *fname != ' ' && fl < 63) fnbuf[fl++] = *fname++;
|
||||
fnbuf[fl] = 0;
|
||||
if (fl == 0) { term_puts_color("echo: 重定向缺少文件名\n", ERROR_FG); return; }
|
||||
char n83[11];
|
||||
if (name_to_83(fnbuf, n83) != 0) { term_puts_color("echo: 无效文件名\n", ERROR_FG); return; }
|
||||
static char echo_buf[4096];
|
||||
int el = 0;
|
||||
for (int i = 0; i < text_len && el < 4095; i++) echo_buf[el++] = args[i];
|
||||
if (newline) echo_buf[el++] = '\n';
|
||||
if (!g_block_write) { term_puts_color("echo: 无块设备写能力\n", ERROR_FG); return; }
|
||||
int rc = fat32_write_root_file(n83, (const u8 *)echo_buf, (u32)el);
|
||||
if (rc != 0) { term_puts_color("echo: 写入失败\n", ERROR_FG); return; }
|
||||
term_puts_color("echo: 已写入 ", OK_FG);
|
||||
term_puts_color(fnbuf, OK_FG);
|
||||
term_putc('\n');
|
||||
return;
|
||||
}
|
||||
if (args && *args) term_puts_color(args, TEXT_FG);
|
||||
term_putc('\n');
|
||||
if (newline) term_putc('\n');
|
||||
}
|
||||
|
||||
static u8 read_rtc_reg(u8 reg);
|
||||
@@ -347,6 +934,598 @@ static void cmd_not_impl(const char *cmd) {
|
||||
term_puts_color(": 此命令尚未实现\n", ERROR_FG);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 文件命令:ls / cat / cp / mv / rm(FAT32 根目录)
|
||||
* ============================================================ */
|
||||
|
||||
/* 从 args 解析一个空白分隔 token 到 out(最多 max-1 字符),返回剩余 args 指针 */
|
||||
static const char *parse_token(const char *args, char *out, int max) {
|
||||
int n = 0;
|
||||
while (*args == ' ') args++;
|
||||
while (*args && *args != ' ' && n < max - 1) out[n++] = *args++;
|
||||
out[n] = 0;
|
||||
return args;
|
||||
}
|
||||
|
||||
/* u32 → 十进制字符串 */
|
||||
static void u32_to_dec(char *buf, u32 v) {
|
||||
char tmp[12]; int n = 0;
|
||||
if (v == 0) { buf[0] = '0'; buf[1] = 0; return; }
|
||||
while (v && n < 11) { tmp[n++] = (char)('0' + v % 10); v /= 10; }
|
||||
for (int i = 0; i < n; i++) buf[i] = tmp[n - 1 - i];
|
||||
buf[n] = 0;
|
||||
}
|
||||
|
||||
/* ls 回调:每行打印一个条目 */
|
||||
static int ls_emit(const char *name, u32 size, u8 attr, void *u) {
|
||||
(void)u;
|
||||
if (attr & 0x10) term_puts_color("[DIR] ", ACCENT_FG);
|
||||
else term_puts_color(" ", TEXT_FG);
|
||||
term_puts_color(name, TEXT_FG);
|
||||
/* 名字对齐填充 */
|
||||
int nl = 0; while (name[nl]) nl++;
|
||||
for (int i = nl; i < 14; i++) term_putc(' ');
|
||||
if (!(attr & 0x10)) {
|
||||
char sz[12]; u32_to_dec(sz, size);
|
||||
term_puts_color(sz, DIM_FG);
|
||||
term_puts_color(" B", DIM_FG);
|
||||
}
|
||||
term_putc('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmd_ls(void) {
|
||||
if (!g_block_read) { term_puts_color("ls: 无块设备\n", ERROR_FG); return; }
|
||||
if (fat32_list_root(ls_emit, 0) != 0) {
|
||||
term_puts_color("ls: 读取根目录失败\n", ERROR_FG);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_cat(const char *args) {
|
||||
if (!g_block_read) { term_puts_color("cat: 无块设备\n", ERROR_FG); return; }
|
||||
char fn[64];
|
||||
parse_token(args, fn, 64);
|
||||
if (fn[0] == 0) { term_puts_color("用法: cat <文件>\n", ERROR_FG); return; }
|
||||
char n83[11];
|
||||
if (name_to_83(fn, n83) != 0) { term_puts_color("cat: 无效文件名\n", ERROR_FG); return; }
|
||||
u8 *data = 0; u32 size = 0;
|
||||
if (fat32_read_root_file(n83, &data, &size) != 0) {
|
||||
term_puts_color("cat: 文件不存在\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
for (u32 i = 0; i < size; i++) term_putc((char)data[i]);
|
||||
}
|
||||
|
||||
static void cmd_cp(const char *args) {
|
||||
if (!g_block_read || !g_block_write) { term_puts_color("cp: 需要块设备读写能力\n", ERROR_FG); return; }
|
||||
char src[64], dst[64];
|
||||
args = parse_token(args, src, 64);
|
||||
parse_token(args, dst, 64);
|
||||
if (src[0] == 0 || dst[0] == 0) {
|
||||
term_puts_color("用法: cp <源文件> <目标文件>\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
char s83[11], d83[11];
|
||||
if (name_to_83(src, s83) != 0) { term_puts_color("cp: 无效源文件名\n", ERROR_FG); return; }
|
||||
if (name_to_83(dst, d83) != 0) { term_puts_color("cp: 无效目标文件名\n", ERROR_FG); return; }
|
||||
u8 *data = 0; u32 size = 0;
|
||||
if (fat32_read_root_file(s83, &data, &size) != 0) {
|
||||
term_puts_color("cp: 源文件不存在或读取失败\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
if (fat32_write_root_file(d83, data, size) != 0) {
|
||||
term_puts_color("cp: 写入目标失败\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
term_puts_color("cp: ", OK_FG);
|
||||
term_puts_color(src, OK_FG);
|
||||
term_puts_color(" -> ", OK_FG);
|
||||
term_puts_color(dst, OK_FG);
|
||||
term_puts_color(" (", DIM_FG);
|
||||
char sz[12]; u32_to_dec(sz, size);
|
||||
term_puts_color(sz, DIM_FG);
|
||||
term_puts_color(" bytes)\n", DIM_FG);
|
||||
}
|
||||
|
||||
static void cmd_mv(const char *args) {
|
||||
if (!g_block_read || !g_block_write) { term_puts_color("mv: 需要块设备读写能力\n", ERROR_FG); return; }
|
||||
char src[64], dst[64];
|
||||
args = parse_token(args, src, 64);
|
||||
parse_token(args, dst, 64);
|
||||
if (src[0] == 0 || dst[0] == 0) {
|
||||
term_puts_color("用法: mv <源文件> <目标文件>\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
char s83[11], d83[11];
|
||||
if (name_to_83(src, s83) != 0) { term_puts_color("mv: 无效源文件名\n", ERROR_FG); return; }
|
||||
if (name_to_83(dst, d83) != 0) { term_puts_color("mv: 无效目标文件名\n", ERROR_FG); return; }
|
||||
u8 *data = 0; u32 size = 0;
|
||||
if (fat32_read_root_file(s83, &data, &size) != 0) {
|
||||
term_puts_color("mv: 源文件不存在或读取失败\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
if (fat32_write_root_file(d83, data, size) != 0) {
|
||||
term_puts_color("mv: 写入目标失败\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
/* 写入后 g_disk 缓存已失效,delete 会重新加载 BPB+FAT */
|
||||
if (fat32_delete_root_file(s83) != 0) {
|
||||
term_puts_color("mv: 警告 — 源文件删除失败,目标已写入\n", DP_WARNING);
|
||||
return;
|
||||
}
|
||||
term_puts_color("mv: ", OK_FG);
|
||||
term_puts_color(src, OK_FG);
|
||||
term_puts_color(" -> ", OK_FG);
|
||||
term_puts_color(dst, OK_FG);
|
||||
term_putc('\n');
|
||||
}
|
||||
|
||||
static void cmd_rm(const char *args) {
|
||||
if (!g_block_write) { term_puts_color("rm: 需要块设备写能力\n", ERROR_FG); return; }
|
||||
char fn[64];
|
||||
parse_token(args, fn, 64);
|
||||
if (fn[0] == 0) { term_puts_color("用法: rm <文件>\n", ERROR_FG); return; }
|
||||
char n83[11];
|
||||
if (name_to_83(fn, n83) != 0) { term_puts_color("rm: 无效文件名\n", ERROR_FG); return; }
|
||||
int rc = fat32_delete_root_file(n83);
|
||||
if (rc == -1) { term_puts_color("rm: 文件不存在\n", ERROR_FG); return; }
|
||||
if (rc != 0) { term_puts_color("rm: 删除失败\n", ERROR_FG); return; }
|
||||
term_puts_color("rm: 已删除 ", OK_FG);
|
||||
term_puts_color(fn, OK_FG);
|
||||
term_putc('\n');
|
||||
}
|
||||
|
||||
/* ---- PCI 设备列表 ---- */
|
||||
static u32 pci_config_read(u8 bus, u8 dev, u8 func, u8 reg) {
|
||||
u32 addr = 0x80000000u | ((u32)bus << 16) | ((u32)dev << 11)
|
||||
| ((u32)func << 8) | ((u32)reg & 0xFCu);
|
||||
outl(0xCF8, addr);
|
||||
return inl(0xCFC);
|
||||
}
|
||||
|
||||
static void hex_nibble(char *buf, u8 v) {
|
||||
v = (u8)(v & 0x0F);
|
||||
buf[0] = (char)(v < 10 ? '0' + v : 'A' + (v - 10));
|
||||
}
|
||||
|
||||
static void u8_to_hex(char *buf, u8 v) {
|
||||
hex_nibble(buf, (u8)(v >> 4));
|
||||
hex_nibble(buf + 1, v);
|
||||
buf[2] = 0;
|
||||
}
|
||||
|
||||
static void u16_to_hex(char *buf, u16 v) {
|
||||
hex_nibble(buf, (u8)(v >> 12));
|
||||
hex_nibble(buf+1, (u8)(v >> 8));
|
||||
hex_nibble(buf+2, (u8)(v >> 4));
|
||||
hex_nibble(buf+3, v);
|
||||
buf[4] = 0;
|
||||
}
|
||||
|
||||
static void u8_to_dec(char *buf, u8 v) {
|
||||
if (v >= 100) {
|
||||
buf[0] = (char)('0' + v / 100);
|
||||
buf[1] = (char)('0' + (v / 10) % 10);
|
||||
buf[2] = (char)('0' + v % 10);
|
||||
buf[3] = 0;
|
||||
} else if (v >= 10) {
|
||||
buf[0] = (char)('0' + v / 10);
|
||||
buf[1] = (char)('0' + v % 10);
|
||||
buf[2] = 0;
|
||||
} else {
|
||||
buf[0] = (char)('0' + v);
|
||||
buf[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *pci_vendor_name(u16 vendor) {
|
||||
switch (vendor) {
|
||||
case 0x8086: return "Intel";
|
||||
case 0x1234: return "Bochs/QEMU";
|
||||
case 0x1AF4: return "Virtio";
|
||||
case 0x168C: return "Atheros";
|
||||
case 0x10DE: return "NVIDIA";
|
||||
case 0x1002: return "AMD";
|
||||
case 0x10EC: return "Realtek";
|
||||
case 0x14E4: return "Broadcom";
|
||||
case 0x1B36: return "Red Hat";
|
||||
case 0x1022: return "AMD-x86";
|
||||
case 0x106B: return "Apple";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *pci_class_name(u8 class_code) {
|
||||
switch (class_code) {
|
||||
case 0x00: return "Unclassified";
|
||||
case 0x01: return "Mass storage";
|
||||
case 0x02: return "Network";
|
||||
case 0x03: return "Display";
|
||||
case 0x04: return "Multimedia";
|
||||
case 0x05: return "Memory";
|
||||
case 0x06: return "Bridge";
|
||||
case 0x07: return "Comm";
|
||||
case 0x08: return "Sys peripheral";
|
||||
case 0x09: return "Input";
|
||||
case 0x0C: return "Serial bus";
|
||||
case 0x0D: return "Wireless";
|
||||
case 0x10: return "Encryption";
|
||||
case 0x11: return "Signal proc";
|
||||
case 0x40: return "Coprocessor";
|
||||
default: return "Other";
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_pci(void) {
|
||||
int count = 0;
|
||||
term_puts_color("PCI 设备列表:\n", PROMPT_FG);
|
||||
for (u8 bus = 0; bus < 1; bus++) {
|
||||
for (u8 dev = 0; dev < 32; dev++) {
|
||||
u32 vd = pci_config_read(bus, dev, 0, 0x00);
|
||||
if ((vd & 0xFFFFu) == 0xFFFFu) continue;
|
||||
u32 hdr_class = pci_config_read(bus, dev, 0, 0x0C);
|
||||
u8 header_type = (u8)((hdr_class >> 16) & 0xFF);
|
||||
u8 func_count = (u8)((header_type & 0x80) ? 8 : 1);
|
||||
for (u8 func = 0; func < func_count; func++) {
|
||||
u32 vdf = pci_config_read(bus, dev, func, 0x00);
|
||||
u16 vendor = (u16)(vdf & 0xFFFFu);
|
||||
u16 device = (u16)(vdf >> 16);
|
||||
if (vendor == 0xFFFFu) continue;
|
||||
u32 cls = pci_config_read(bus, dev, func, 0x08);
|
||||
u8 rev = (u8)(cls & 0xFF);
|
||||
u8 prog_if = (u8)((cls >> 8) & 0xFF);
|
||||
u8 subclass = (u8)((cls >> 16) & 0xFF);
|
||||
u8 class_code = (u8)((cls >> 24) & 0xFF);
|
||||
|
||||
char line[80];
|
||||
int p = 0;
|
||||
/* "00:00.0 " */
|
||||
u8_to_hex(line + p, bus); p += 2;
|
||||
line[p++] = ':';
|
||||
u8_to_hex(line + p, dev); p += 2;
|
||||
line[p++] = '.';
|
||||
u8_to_hex(line + p, func); p += 2;
|
||||
line[p++] = ' ';
|
||||
/* "VEN:DEV " */
|
||||
u16_to_hex(line + p, vendor); p += 4;
|
||||
line[p++] = ':';
|
||||
u16_to_hex(line + p, device); p += 4;
|
||||
line[p++] = ' ';
|
||||
/* "rev NN " */
|
||||
line[p++] = 'r'; line[p++] = 'e'; line[p++] = 'v';
|
||||
line[p++] = ' ';
|
||||
u8_to_hex(line + p, rev); p += 2;
|
||||
line[p++] = ' ';
|
||||
/* "class CC:SS:PP" */
|
||||
line[p++] = 'c'; line[p++] = 'l'; line[p++] = 'a';
|
||||
line[p++] = 's'; line[p++] = 's'; line[p++] = ' ';
|
||||
u8_to_hex(line + p, class_code); p += 2;
|
||||
line[p++] = ':';
|
||||
u8_to_hex(line + p, subclass); p += 2;
|
||||
line[p++] = ':';
|
||||
u8_to_hex(line + p, prog_if); p += 2;
|
||||
line[p++] = ' ';
|
||||
line[p++] = '[';
|
||||
const char *cn = pci_class_name(class_code);
|
||||
while (*cn) line[p++] = *cn++;
|
||||
line[p++] = ']';
|
||||
const char *vn = pci_vendor_name(vendor);
|
||||
if (*vn) {
|
||||
line[p++] = ' ';
|
||||
while (*vn) line[p++] = *vn++;
|
||||
}
|
||||
line[p] = 0;
|
||||
term_puts(line);
|
||||
term_putc('\n');
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
char tail[32];
|
||||
int q = 0;
|
||||
const char *prefix = "Total: ";
|
||||
while (prefix[q]) { tail[q] = prefix[q]; q++; }
|
||||
u8_to_dec(tail + q, (u8)(count > 255 ? 255 : count));
|
||||
while (tail[q]) q++;
|
||||
const char *suffix = " device(s)\n";
|
||||
int s = 0;
|
||||
while (suffix[s]) { tail[q++] = suffix[s++]; }
|
||||
tail[q] = 0;
|
||||
term_puts_color(tail, DIM_FG);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 网络命令:ping / curl(共享协议栈 net_stack.h)
|
||||
* ============================================================ */
|
||||
|
||||
static u64 g_kernel_api = 0;
|
||||
static const dsk_boot_context *g_boot_ctx = 0;
|
||||
static int g_ns_status = 0; /* 0=未尝试, 1=就绪, <0=初始化失败 */
|
||||
|
||||
static int shell_net_ready(void) {
|
||||
if (g_ns_status == 1) return 1;
|
||||
if (g_ns_status < 0) return 0;
|
||||
int rc = ns_init(g_kernel_api);
|
||||
g_ns_status = (rc == 0) ? 1 : -1;
|
||||
if (rc != 0) {
|
||||
logl("[shell] ns_init failed");
|
||||
term_puts_color("网络初始化失败 (rc=", ERROR_FG);
|
||||
char rcbuf[4];
|
||||
rcbuf[0] = (char)('0' + (-rc % 10));
|
||||
rcbuf[1] = 0;
|
||||
term_puts_color(rcbuf, ERROR_FG);
|
||||
term_puts_color("),无可用网卡或 net API\n", ERROR_FG);
|
||||
return 0;
|
||||
}
|
||||
logl("[shell] ns_init ok");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ping [a.b.c.d] — 缺省网关 10.0.2.2,4 次 echo */
|
||||
static void cmd_ping(const char *args) {
|
||||
u32 ip;
|
||||
if (!args || !*args) {
|
||||
ip = NS_GATEWAY_IP;
|
||||
} else if (ns_parse_ip(args, &ip) != 0) {
|
||||
term_puts_color("用法: ping [a.b.c.d]\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
if (!shell_net_ready()) return;
|
||||
|
||||
char ipstr[24];
|
||||
ns_fmt_ip(ip, ipstr);
|
||||
term_puts_color("PING ", PROMPT_FG);
|
||||
term_puts_color(ipstr, ACCENT_FG);
|
||||
term_puts_color(" 32 data bytes\n", DIM_FG);
|
||||
|
||||
int sent = 0, recv = 0;
|
||||
u32 sum = 0, min = 0xFFFFFFFFu, max = 0;
|
||||
for (u16 seq = 1; seq <= 4; seq++) {
|
||||
u32 rtt = 0; u8 ttl = 0;
|
||||
int rc = ns_ping(ip, seq, 2000, &rtt, &ttl);
|
||||
sent++;
|
||||
if (rc == 0) {
|
||||
recv++;
|
||||
sum += rtt;
|
||||
if (rtt < min) min = rtt;
|
||||
if (rtt > max) max = rtt;
|
||||
term_puts("reply from ");
|
||||
term_puts(ipstr);
|
||||
term_puts(": bytes=32 time=");
|
||||
char nb[12]; ns_u32_dec(nb, rtt);
|
||||
term_puts(nb);
|
||||
term_puts("ms TTL=");
|
||||
ns_u32_dec(nb, ttl);
|
||||
term_puts(nb);
|
||||
term_putc('\n');
|
||||
} else if (rc == -1) {
|
||||
term_puts_color("ARP 解析失败,目标不可达\n", ERROR_FG);
|
||||
break;
|
||||
} else {
|
||||
term_puts_color("request timed out\n", DIM_FG);
|
||||
}
|
||||
}
|
||||
/* 统计行 */
|
||||
char nb[12];
|
||||
ns_u32_dec(nb, (u32)sent);
|
||||
term_puts_color("--- ", DIM_FG);
|
||||
term_puts_color(ipstr, DIM_FG);
|
||||
term_puts_color(" ping statistics ---\n ", DIM_FG);
|
||||
term_puts(nb);
|
||||
term_puts(" transmitted, ");
|
||||
ns_u32_dec(nb, (u32)recv);
|
||||
term_puts(nb);
|
||||
term_puts(" received, ");
|
||||
u32 loss = sent ? (u32)(sent - recv) * 100 / (u32)sent : 100;
|
||||
ns_u32_dec(nb, loss);
|
||||
term_puts(nb);
|
||||
term_puts("% loss");
|
||||
if (recv > 0) {
|
||||
term_puts(", min/avg/max = ");
|
||||
ns_u32_dec(nb, min); term_puts(nb); term_puts("/");
|
||||
ns_u32_dec(nb, sum / (u32)recv); term_puts(nb); term_puts("/");
|
||||
ns_u32_dec(nb, max); term_puts(nb); term_puts(" ms");
|
||||
}
|
||||
term_putc('\n');
|
||||
}
|
||||
|
||||
/* curl http://host[:port][/path] — HTTP/1.0 GET,打印 status + body */
|
||||
static void cmd_curl(const char *args) {
|
||||
if (!args || !*args) {
|
||||
term_puts_color("用法: curl http://host[:port][/path]\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
if (!shell_net_ready()) return;
|
||||
|
||||
const char *p = args;
|
||||
if (p[0]=='h'&&p[1]=='t'&&p[2]=='t'&&p[3]=='p'&&p[4]==':'&&p[5]=='/'&&p[6]=='/') p += 7;
|
||||
|
||||
char host[128]; int hl = 0;
|
||||
while (*p && *p != ':' && *p != '/' && hl < 127) host[hl++] = *p++;
|
||||
host[hl] = 0;
|
||||
if (!hl) { term_puts_color("curl: 缺少主机名\n", ERROR_FG); return; }
|
||||
|
||||
u16 port = 80;
|
||||
if (*p == ':') {
|
||||
p++;
|
||||
u32 pv = 0; int digits = 0;
|
||||
while (*p >= '0' && *p <= '9') { pv = pv * 10 + (u32)(*p - '0'); p++; digits++; }
|
||||
if (digits && pv <= 65535) port = (u16)pv;
|
||||
}
|
||||
char path[128]; int pl = 0;
|
||||
if (*p == '/') {
|
||||
while (*p && *p != ' ' && pl < 127) path[pl++] = *p++;
|
||||
}
|
||||
if (!pl) { path[0] = '/'; pl = 1; }
|
||||
path[pl] = 0;
|
||||
|
||||
/* 解析主机 */
|
||||
u32 ip;
|
||||
term_puts_color("-> 解析 ", DIM_FG);
|
||||
term_puts_color(host, DIM_FG);
|
||||
term_puts_color("...\n", DIM_FG);
|
||||
if (ns_dns_resolve(host, &ip) != 0) {
|
||||
term_puts_color("curl: DNS 解析失败\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
char ipstr[24]; ns_fmt_ip(ip, ipstr);
|
||||
term_puts_color("-> ", DIM_FG);
|
||||
term_puts_color(ipstr, DIM_FG);
|
||||
term_putc('\n');
|
||||
|
||||
/* 连接 */
|
||||
term_puts_color("-> TCP 连接...\n", DIM_FG);
|
||||
if (ns_tcp_connect(ip, port, 2000) != 0) {
|
||||
term_puts_color("curl: TCP 连接失败(超时/RST)\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
term_puts_color("-> 已连接,发送请求\n", DIM_FG);
|
||||
|
||||
/* 构造 HTTP/1.0 请求 */
|
||||
static char req[512];
|
||||
int r = 0;
|
||||
const char *m = "GET "; while (*m) req[r++] = *m++;
|
||||
for (int i = 0; i < pl; i++) req[r++] = path[i];
|
||||
m = " HTTP/1.0\r\nHost: "; while (*m) req[r++] = *m++;
|
||||
for (int i = 0; i < hl; i++) req[r++] = host[i];
|
||||
m = "\r\nConnection: close\r\n\r\n"; while (*m) req[r++] = *m++;
|
||||
req[r] = 0;
|
||||
|
||||
if (ns_tcp_send((const u8 *)req, (u32)r) != 0) {
|
||||
term_puts_color("curl: 发送失败\n", ERROR_FG);
|
||||
ns_tcp_close();
|
||||
return;
|
||||
}
|
||||
|
||||
/* 收至 FIN(数据在协议栈 ns_tcp_rx 中累计) */
|
||||
int n = ns_tcp_recv(0, 0, 5000);
|
||||
ns_tcp_close();
|
||||
if (n < 0) {
|
||||
term_puts_color("curl: 连接被重置\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
if (n == 0) {
|
||||
term_puts_color("curl: 无响应数据(超时)\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 打印状态行 + body(截断提示) */
|
||||
u32 total = ns_tcp_rx_len;
|
||||
u32 show = (u32)n;
|
||||
for (u32 i = 0; i < show; i++) term_putc((char)ns_tcp_rx[i]);
|
||||
if (total > show) {
|
||||
term_puts_color("\n[... 已截断,共 ", DIM_FG);
|
||||
char nb[12]; ns_u32_dec(nb, total);
|
||||
term_puts_color(nb, DIM_FG);
|
||||
term_puts_color(" 字节]\n", DIM_FG);
|
||||
}
|
||||
term_putc('\n');
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* run 命令:从 FAT32 根目录加载并跳转 PIE ELF 工具
|
||||
* ============================================================ */
|
||||
|
||||
#define SH_ELFCLASS64 2
|
||||
#define SH_EM_X86_64 62
|
||||
#define SH_PT_LOAD 1
|
||||
#define SH_PT_DYNAMIC 2
|
||||
#define SH_DT_RELA 7
|
||||
#define SH_DT_RELASZ 8
|
||||
#define SH_DT_RELAENT 9
|
||||
#define SH_R_X86_64_RELATIVE 8
|
||||
|
||||
typedef struct { u8 ident[16]; u16 type,machine; u32 ver; u64 entry,phoff,shoff; u32 flags; u16 ehsize,phentsize,phnum,shentsize,shnum,shstrndx; } sh_elf64_ehdr;
|
||||
typedef struct { u32 type,flags; u64 offset,vaddr,paddr,filesz,memsz,align; } sh_elf64_phdr;
|
||||
typedef struct { i64 tag; u64 val; } sh_elf64_dyn;
|
||||
typedef struct { u64 offset; u64 info; i64 addend; } sh_elf64_rela;
|
||||
|
||||
/* run 加载镜像缓冲(容纳工具 ELF 展开后的 memsz) */
|
||||
static u8 g_run_image[262144];
|
||||
|
||||
static int sh_load_elf(u8 *data, void **entry_out) {
|
||||
const sh_elf64_ehdr *eh = (const sh_elf64_ehdr *)data;
|
||||
if (eh->ident[0] != 0x7F || eh->ident[4] != SH_ELFCLASS64) return -1;
|
||||
if (eh->machine != SH_EM_X86_64) return -2;
|
||||
u64 min_vaddr = ~0ULL, max_vaddr = 0;
|
||||
u32 lc = 0;
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const sh_elf64_phdr *ph = (const sh_elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
||||
if (ph->type != SH_PT_LOAD) continue;
|
||||
if (ph->filesz > ph->memsz) return -3;
|
||||
if (ph->vaddr < min_vaddr) min_vaddr = ph->vaddr;
|
||||
if (ph->vaddr + ph->memsz > max_vaddr) max_vaddr = ph->vaddr + ph->memsz;
|
||||
lc++;
|
||||
}
|
||||
if (!lc || min_vaddr == ~0ULL) return -4;
|
||||
u64 isize = (max_vaddr - min_vaddr + 0xFFF) & ~0xFFFULL;
|
||||
if (isize > sizeof(g_run_image)) return -5;
|
||||
u8 *image = g_run_image;
|
||||
for (u64 i = 0; i < isize; i++) image[i] = 0;
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const sh_elf64_phdr *ph = (const sh_elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
||||
if (ph->type != SH_PT_LOAD) continue;
|
||||
u64 off = ph->vaddr - min_vaddr;
|
||||
for (u64 b = 0; b < ph->filesz; b++) image[off + b] = data[ph->offset + b];
|
||||
}
|
||||
*entry_out = image + (eh->entry - min_vaddr);
|
||||
|
||||
/* R_X86_64_RELATIVE 重定位 */
|
||||
u64 load_bias = (u64)image - min_vaddr;
|
||||
for (u16 i = 0; i < eh->phnum; i++) {
|
||||
const sh_elf64_phdr *ph = (const sh_elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
||||
if (ph->type != SH_PT_DYNAMIC) continue;
|
||||
const sh_elf64_dyn *dyn = (const sh_elf64_dyn *)(image + (ph->vaddr - min_vaddr));
|
||||
u64 rela_off = 0, rela_sz = 0, rela_ent = 24;
|
||||
for (; dyn->tag != 0; dyn++) {
|
||||
if (dyn->tag == SH_DT_RELA) rela_off = dyn->val;
|
||||
else if (dyn->tag == SH_DT_RELASZ) rela_sz = dyn->val;
|
||||
else if (dyn->tag == SH_DT_RELAENT) rela_ent = dyn->val;
|
||||
}
|
||||
if (rela_off && rela_sz) {
|
||||
u64 cnt = rela_sz / rela_ent;
|
||||
for (u64 rr = 0; rr < cnt; rr++) {
|
||||
const sh_elf64_rela *rel = (const sh_elf64_rela *)(image + (rela_off - min_vaddr) + rr * rela_ent);
|
||||
if ((u32)(rel->info & 0xFFFFFFFF) == SH_R_X86_64_RELATIVE) {
|
||||
u64 *slot = (u64 *)(image + (rel->offset - min_vaddr));
|
||||
*slot = load_bias + (u64)rel->addend;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* run NAME.ELF — 加载根目录工具,全屏执行,返回后重绘 shell */
|
||||
static void cmd_run(const char *args) {
|
||||
if (!g_block_read) { term_puts_color("run: 无块设备\n", ERROR_FG); return; }
|
||||
char fn[64];
|
||||
parse_token(args, fn, 64);
|
||||
if (fn[0] == 0) { term_puts_color("用法: run <NAME.ELF>\n", ERROR_FG); return; }
|
||||
char n83[11];
|
||||
if (name_to_83(fn, n83) != 0) { term_puts_color("run: 无效文件名\n", ERROR_FG); return; }
|
||||
u8 *data = 0; u32 size = 0;
|
||||
if (fat32_read_root_file(n83, &data, &size) != 0) {
|
||||
term_puts_color("run: 文件不存在: ", ERROR_FG);
|
||||
term_puts_color(fn, ERROR_FG);
|
||||
term_putc('\n');
|
||||
return;
|
||||
}
|
||||
void *entry = 0;
|
||||
int rc = sh_load_elf(data, &entry);
|
||||
if (rc != 0) {
|
||||
term_puts_color("run: ELF 加载失败(无效格式或过大)\n", ERROR_FG);
|
||||
return;
|
||||
}
|
||||
logl("[shell] run: jumping to tool");
|
||||
void (*fn_entry)(const dsk_boot_context *) = (void (*)(const dsk_boot_context *))entry;
|
||||
fn_entry(g_boot_ctx);
|
||||
logl("[shell] run: tool returned");
|
||||
/* 工具可能改动磁盘/显示状态:失效 FAT 缓存并重绘 */
|
||||
g_disk_loaded = 0;
|
||||
term_redraw_all();
|
||||
}
|
||||
|
||||
static void execute_command(const char *cmd) {
|
||||
while (*cmd == ' ') cmd++;
|
||||
if (*cmd == 0) return;
|
||||
@@ -367,9 +1546,15 @@ static void execute_command(const char *cmd) {
|
||||
else if (str_eq(name, "halt") || str_eq(name, "shutdown")) cmd_halt();
|
||||
else if (str_eq(name, "echo")) cmd_echo(args);
|
||||
else if (str_eq(name, "date") || str_eq(name, "time")) cmd_date();
|
||||
else if (str_eq(name, "ls") || str_eq(name, "dir")) cmd_not_impl("ls");
|
||||
else if (str_eq(name, "pci")) cmd_not_impl("pci");
|
||||
else if (str_eq(name, "cat")) cmd_not_impl("cat");
|
||||
else if (str_eq(name, "ls") || str_eq(name, "dir")) cmd_ls();
|
||||
else if (str_eq(name, "pci")) cmd_pci();
|
||||
else if (str_eq(name, "cat")) cmd_cat(args);
|
||||
else if (str_eq(name, "cp")) cmd_cp(args);
|
||||
else if (str_eq(name, "mv")) cmd_mv(args);
|
||||
else if (str_eq(name, "rm") || str_eq(name, "del")) cmd_rm(args);
|
||||
else if (str_eq(name, "ping")) cmd_ping(args);
|
||||
else if (str_eq(name, "curl")) cmd_curl(args);
|
||||
else if (str_eq(name, "run")) cmd_run(args);
|
||||
else if (str_eq(name, "cd")) cmd_not_impl("cd");
|
||||
else if (str_eq(name, "pwd")) { term_puts("/\n"); }
|
||||
else if (str_eq(name, "whoami")) { term_puts("root\n"); }
|
||||
@@ -497,6 +1682,54 @@ static void kill_line(void) {
|
||||
redraw_input_line();
|
||||
}
|
||||
|
||||
/* 开发者模式:自动测试命令序列(ls/echo>/cat/cp/mv/rm)
|
||||
* 由 DSK 在 firstInit.txt 第二行=1 时触发,reserved[3]=1 */
|
||||
static void run_dev_tests(void) {
|
||||
term_puts_color("=== 开发者模式:自动测试命令 ===\n", PROMPT_FG);
|
||||
term_putc('\n');
|
||||
|
||||
term_puts_color("[1] ls — 列出根目录\n", ACCENT_FG);
|
||||
cmd_ls();
|
||||
term_putc('\n');
|
||||
|
||||
term_puts_color("[2] echo \"Deshab dev test\" > TEST.TXT\n", ACCENT_FG);
|
||||
cmd_echo("Deshab dev test > TEST.TXT");
|
||||
|
||||
term_puts_color("[3] cat TEST.TXT — 读回验证\n", ACCENT_FG);
|
||||
cmd_cat("TEST.TXT");
|
||||
term_putc('\n');
|
||||
|
||||
term_puts_color("[4] cp TEST.TXT COPY.TXT\n", ACCENT_FG);
|
||||
cmd_cp("TEST.TXT COPY.TXT");
|
||||
|
||||
term_puts_color("[5] ls — 确认复制\n", ACCENT_FG);
|
||||
cmd_ls();
|
||||
term_putc('\n');
|
||||
|
||||
term_puts_color("[6] mv COPY.TXT MOVED.TXT\n", ACCENT_FG);
|
||||
cmd_mv("COPY.TXT MOVED.TXT");
|
||||
|
||||
term_puts_color("[7] ls — 确认移动\n", ACCENT_FG);
|
||||
cmd_ls();
|
||||
term_putc('\n');
|
||||
|
||||
term_puts_color("[8] rm TEST.TXT\n", ACCENT_FG);
|
||||
cmd_rm("TEST.TXT");
|
||||
term_puts_color("[9] rm MOVED.TXT — 清理\n", ACCENT_FG);
|
||||
cmd_rm("MOVED.TXT");
|
||||
|
||||
term_puts_color("[10] ls — 确认清理\n", ACCENT_FG);
|
||||
cmd_ls();
|
||||
|
||||
term_puts_color("[11] ping 10.0.2.2 — 网络回归(失败不阻断)\n", ACCENT_FG);
|
||||
cmd_ping("10.0.2.2");
|
||||
|
||||
term_putc('\n');
|
||||
term_puts_color("=== 自动测试完成 ===\n", OK_FG);
|
||||
term_puts_color("按 Esc 返回 DSK,或继续输入命令\n", DIM_FG);
|
||||
term_putc('\n');
|
||||
}
|
||||
|
||||
/* ---- 主入口 ---- */
|
||||
__attribute__((visibility("default")))
|
||||
void dsk_entry(const dsk_boot_context *ctx) {
|
||||
@@ -513,6 +1746,20 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
fb_h = ctx->framebuffer_height;
|
||||
fb_p = ctx->framebuffer_pitch;
|
||||
|
||||
/* 保存 boot 上下文(网络协议栈/run 命令使用) */
|
||||
g_kernel_api = ctx->dkm_kernel_api;
|
||||
g_boot_ctx = ctx;
|
||||
|
||||
/* 获取 block 设备 read/write(从 kernel_api + 0xA8 → block_api → +16/+24) */
|
||||
{
|
||||
u64 api = ctx->dkm_kernel_api;
|
||||
u64 blk = *(u64 *)(api + 0xA8);
|
||||
g_block_read = blk ? (shell_block_read_fn)*(u64 *)(blk + 16) : 0;
|
||||
g_block_write = blk ? (shell_block_write_fn)*(u64 *)(blk + 24) : 0;
|
||||
}
|
||||
if (g_block_read) logl("[shell] block_read ok");
|
||||
if (g_block_write) logl("[shell] block_write ok");
|
||||
|
||||
/* 初始化风格系统渲染上下文 */
|
||||
du_context_init(&g_ctx, fb_a, fb_w, fb_h, fb_p);
|
||||
|
||||
@@ -522,10 +1769,19 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
|
||||
/* 启动 banner — 使用风格令牌 */
|
||||
term_puts_color("=== Deshab OS v0.1.0 ===\n", ACCENT_FG);
|
||||
term_puts_color("欢迎使用 Deshab Shell\n", OK_FG);
|
||||
if (ctx->reserved[3] == 1)
|
||||
term_puts_color("开发者模式 (自动测试命令)\n", OK_FG);
|
||||
else
|
||||
term_puts_color("欢迎使用 Deshab Shell\n", OK_FG);
|
||||
term_puts_color("输入 'help' 查看可用命令\n", DIM_FG);
|
||||
term_putc('\n');
|
||||
|
||||
/* 开发者模式:DSK 设 reserved[3]=1 时自动跑命令测试序列 */
|
||||
if (ctx->reserved[3] == 1) {
|
||||
g_serial_mirror = 1;
|
||||
run_dev_tests();
|
||||
}
|
||||
|
||||
/* 主循环 */
|
||||
int shift = 0;
|
||||
int e0 = 0;
|
||||
@@ -567,21 +1823,27 @@ void dsk_entry(const dsk_boot_context *ctx) {
|
||||
else if (sc == 0x47) cursor_home();
|
||||
else if (sc == 0x4F) cursor_end();
|
||||
else if (sc == 0x53) delete_char_fwd();
|
||||
else if (sc == 0x48) { }
|
||||
else if (sc == 0x50) { }
|
||||
else if (sc == 0x48) { history_prev(); }
|
||||
else if (sc == 0x50) { history_next(); }
|
||||
e0 = 0;
|
||||
continue;
|
||||
}
|
||||
if (sc == 0x1C) {
|
||||
term_clear_cursor();
|
||||
input_buf[input_len] = 0;
|
||||
/* 提交命令前先入历史; 执行后再清空输入 */
|
||||
history_push(input_buf);
|
||||
g_history_view = -1;
|
||||
term_putc('\n');
|
||||
execute_command(input_buf);
|
||||
input_len = 0;
|
||||
input_cursor = 0;
|
||||
input_buf[0] = 0;
|
||||
cmd_done = 1;
|
||||
continue;
|
||||
}
|
||||
if (sc == 0x0E) { delete_char_back(); continue; }
|
||||
if (sc == 0x01) { kill_line(); continue; }
|
||||
if (sc == 0x01) { logl("[shell] esc -> return to DSK"); return; }
|
||||
if (sc == 0x15 && !shift) { kill_line(); continue; }
|
||||
if (sc == 0x17 && !shift) { while (input_cursor > 0) delete_char_back(); continue; }
|
||||
if (sc == 0x0B && !shift) { kill_to_end(); continue; }
|
||||
|
||||
Binary file not shown.
@@ -1,16 +0,0 @@
|
||||
ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(7);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(7);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
}
|
||||
@@ -1,456 +0,0 @@
|
||||
/* Deshab Bash — 全屏终端应用
|
||||
* PS/2 键盘输入,命令行编辑,内置命令。
|
||||
* Esc 键退出返回 DSK。
|
||||
*/
|
||||
|
||||
#include "../../firstInit/ascii_bitmaps.c"
|
||||
#include "../desktop_app.h"
|
||||
|
||||
/* ---- 终端参数 ---- */
|
||||
#define TERM_COLS 120
|
||||
#define TERM_ROWS 40
|
||||
#define TERM_MAX_CHARS (TERM_COLS * TERM_ROWS)
|
||||
#define CHAR_STEP 12
|
||||
#define CHAR_H 18
|
||||
#define PROMPT_STR "deshab# "
|
||||
|
||||
static da_app_context g_ac;
|
||||
|
||||
/* 终端缓冲区 */
|
||||
static u8 term_ch[TERM_MAX_CHARS];
|
||||
static u32 term_fg[TERM_MAX_CHARS];
|
||||
static int term_w = TERM_COLS;
|
||||
static int term_h = TERM_ROWS;
|
||||
static int cur_col = 0;
|
||||
static int cur_row = 0;
|
||||
|
||||
/* 输入缓冲 */
|
||||
static char input_buf[256];
|
||||
static int input_len = 0;
|
||||
static int input_cursor = 0;
|
||||
|
||||
/* 命令历史 */
|
||||
#define HIST_SIZE 16
|
||||
static char history[HIST_SIZE][256];
|
||||
static int hist_count = 0;
|
||||
static int hist_idx = 0;
|
||||
|
||||
/* 坐标 */
|
||||
static int term_x, term_y;
|
||||
static int content_h;
|
||||
|
||||
static void term_init_layout(void) {
|
||||
term_x = 8;
|
||||
term_y = DA_TITLEBAR_H + 4;
|
||||
int avail_w = (int)g_ac.fb_w - 16;
|
||||
int avail_h = (int)g_ac.fb_h - term_y - DA_STATUSBAR_H - 8;
|
||||
term_w = avail_w / CHAR_STEP;
|
||||
term_h = avail_h / CHAR_H;
|
||||
if (term_w < 10) term_w = 10;
|
||||
if (term_h < 5) term_h = 5;
|
||||
if (term_w > TERM_COLS) term_w = TERM_COLS;
|
||||
if (term_h > TERM_ROWS) term_h = TERM_ROWS;
|
||||
content_h = term_h * CHAR_H;
|
||||
}
|
||||
|
||||
static void term_clear(void) {
|
||||
for (int i = 0; i < TERM_MAX_CHARS; i++) {
|
||||
term_ch[i] = ' ';
|
||||
term_fg[i] = DA_TEXT_PRIMARY;
|
||||
}
|
||||
cur_col = 0; cur_row = 0;
|
||||
}
|
||||
|
||||
static void term_scroll(void) {
|
||||
for (int r = 1; r < term_h; r++) {
|
||||
for (int c = 0; c < term_w; c++) {
|
||||
term_ch[(r-1)*TERM_COLS+c] = term_ch[r*TERM_COLS+c];
|
||||
term_fg[(r-1)*TERM_COLS+c] = term_fg[r*TERM_COLS+c];
|
||||
}
|
||||
}
|
||||
for (int c = 0; c < term_w; c++) {
|
||||
term_ch[(term_h-1)*TERM_COLS+c] = ' ';
|
||||
term_fg[(term_h-1)*TERM_COLS+c] = DA_TEXT_PRIMARY;
|
||||
}
|
||||
cur_row = term_h - 1; cur_col = 0;
|
||||
}
|
||||
|
||||
static void term_newline(void) {
|
||||
cur_col = 0; cur_row++;
|
||||
if (cur_row >= term_h) term_scroll();
|
||||
}
|
||||
|
||||
static void term_putc_color(char c, u32 color) {
|
||||
if (c == '\n') { term_newline(); return; }
|
||||
if (c == '\r') { cur_col = 0; return; }
|
||||
if (c == '\t') { int sp = 4 - (cur_col % 4); for (int i = 0; i < sp; i++) term_putc_color(' ', color); return; }
|
||||
if (c < ' ' || c > '~') c = '?';
|
||||
if (cur_col >= term_w) term_newline();
|
||||
int idx = cur_row * TERM_COLS + cur_col;
|
||||
term_ch[idx] = (u8)c; term_fg[idx] = color;
|
||||
cur_col++;
|
||||
}
|
||||
|
||||
static void term_putc(char c) { term_putc_color(c, DA_TEXT_PRIMARY); }
|
||||
static void term_puts_color(const char *s, u32 color) { while (*s) term_putc_color(*s++, color); }
|
||||
static void term_puts(const char *s) { term_puts_color(s, DA_TEXT_PRIMARY); }
|
||||
|
||||
/* ---- 绘制 ---- */
|
||||
static void redraw_all(void) {
|
||||
da_fill_bg(&g_ac, DA_BG_PRIMARY);
|
||||
da_draw_titlebar(&g_ac, "Deshab Bash", (i64)g_ac.fb_w);
|
||||
/* 终端字符 */
|
||||
for (int r = 0; r < term_h; r++) {
|
||||
for (int c = 0; c < term_w; c++) {
|
||||
int idx = r * TERM_COLS + c;
|
||||
if (term_ch[idx] == ' ') continue;
|
||||
da_draw_char(&g_ac, term_ch[idx],
|
||||
term_x + c * CHAR_STEP, term_y + r * CHAR_H,
|
||||
term_fg[idx], DA_BG_PRIMARY);
|
||||
}
|
||||
}
|
||||
/* 光标 */
|
||||
if (cur_col < term_w && cur_row < term_h) {
|
||||
da_fill_rect(&g_ac, term_x + cur_col * CHAR_STEP,
|
||||
term_y + cur_row * CHAR_H + CHAR_H - 3, 11, 2, DA_ACCENT);
|
||||
}
|
||||
/* 状态栏 */
|
||||
char status[64];
|
||||
int p = 0;
|
||||
const char *s1 = "/ root@deshab ";
|
||||
while (*s1) status[p++] = *s1++;
|
||||
u8 hh, mm; da_rtc_time(&hh, &mm);
|
||||
status[p++] = '0' + hh/10; status[p++] = '0' + hh%10;
|
||||
status[p++] = ':'; status[p++] = '0' + mm/10; status[p++] = '0' + mm%10;
|
||||
status[p] = 0;
|
||||
da_draw_statusbar(&g_ac, status, (i64)g_ac.fb_w, (i64)g_ac.fb_h);
|
||||
}
|
||||
|
||||
/* ---- 内置命令 ---- */
|
||||
static int str_eq(const char *a, const char *b) {
|
||||
while (*a && *b) { if (*a != *b) return 0; a++; b++; }
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static void cmd_help(void) {
|
||||
term_puts_color("Deshab Bash - 内置命令:\n", DA_PROMPT_COLOR);
|
||||
term_puts(" help 显示此帮助\n");
|
||||
term_puts(" clear 清屏\n");
|
||||
term_puts(" echo <text> 显示文本\n");
|
||||
term_puts(" version 显示系统版本\n");
|
||||
term_puts(" ver 同 version\n");
|
||||
term_puts(" uname 显示系统名称\n");
|
||||
term_puts(" date 显示当前日期时间\n");
|
||||
term_puts(" about 关于 Deshab\n");
|
||||
term_puts(" reboot 重启系统\n");
|
||||
term_puts(" halt 关机\n");
|
||||
term_puts(" pwd 显示当前目录\n");
|
||||
term_puts(" whoami 显示当前用户\n");
|
||||
term_puts(" id 显示用户ID\n");
|
||||
term_puts(" ls 列出根目录文件\n");
|
||||
term_puts(" cat <file> 显示文件内容\n");
|
||||
}
|
||||
|
||||
static void cmd_version(void) {
|
||||
term_puts_color("Deshab OS v0.1.0\n", DA_SUCCESS);
|
||||
term_puts(" Kernel: DSK (Deshab System Kernel)\n");
|
||||
term_puts(" Architecture: x86_64\n");
|
||||
term_puts(" ABI: DKM v1\n");
|
||||
term_puts(" Bootloader: Limine\n");
|
||||
}
|
||||
|
||||
static void cmd_uname(void) { term_puts("Deshab\n"); }
|
||||
|
||||
static void cmd_about(void) {
|
||||
term_puts_color("=== Deshab OS ===\n", DA_PROMPT_COLOR);
|
||||
term_puts("单地址空间 Ring0 内核实验系统\n");
|
||||
term_puts("架构: UTSM + DSK + DKM\n");
|
||||
term_puts_color("Built with Clang + lld\n", DA_TEXT_DIM);
|
||||
}
|
||||
|
||||
static void cmd_clear(void) { term_clear(); }
|
||||
|
||||
static void cmd_reboot(void) {
|
||||
term_puts_color("Rebooting...\n", DA_PROMPT_COLOR);
|
||||
redraw_all();
|
||||
outb(0x64, 0xFE);
|
||||
for(;;) __asm__("hlt");
|
||||
}
|
||||
|
||||
static void cmd_halt(void) {
|
||||
term_puts_color("System halted.\n", DA_PROMPT_COLOR);
|
||||
redraw_all();
|
||||
for(;;) __asm__("hlt");
|
||||
}
|
||||
|
||||
static void cmd_echo(const char *args) {
|
||||
if (args && *args) term_puts_color(args, DA_TEXT_PRIMARY);
|
||||
term_putc('\n');
|
||||
}
|
||||
|
||||
static void cmd_date(void) {
|
||||
u8 year, month, day, hour, minute, second;
|
||||
outb(0x70, 9); year = inb(0x71);
|
||||
outb(0x70, 8); month = inb(0x71);
|
||||
outb(0x70, 7); day = inb(0x71);
|
||||
outb(0x70, 4); hour = inb(0x71);
|
||||
outb(0x70, 2); minute = inb(0x71);
|
||||
outb(0x70, 0); second = inb(0x71);
|
||||
year = (u8)((year>>4)*10+(year&0xF));
|
||||
month = (u8)((month>>4)*10+(month&0xF));
|
||||
day = (u8)((day>>4)*10+(day&0xF));
|
||||
hour = (u8)((hour>>4)*10+(hour&0xF));
|
||||
minute = (u8)((minute>>4)*10+(minute&0xF));
|
||||
second = (u8)((second>>4)*10+(second&0xF));
|
||||
char buf[32]; int p = 0;
|
||||
buf[p++]='2'; buf[p++]='0'; buf[p++]='0'+year/10; buf[p++]='0'+year%10; buf[p++]='-';
|
||||
buf[p++]='0'+month/10; buf[p++]='0'+month%10; buf[p++]='-';
|
||||
buf[p++]='0'+day/10; buf[p++]='0'+day%10; buf[p++]=' ';
|
||||
buf[p++]='0'+hour/10; buf[p++]='0'+hour%10; buf[p++]=':';
|
||||
buf[p++]='0'+minute/10; buf[p++]='0'+minute%10; buf[p++]=':';
|
||||
buf[p++]='0'+second/10; buf[p++]='0'+second%10; buf[p]=0;
|
||||
term_puts(buf); term_putc('\n');
|
||||
}
|
||||
|
||||
static void cmd_ls(void) {
|
||||
if (!g_ac.block_read) {
|
||||
term_puts_color("ls: 无块设备可用\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
/* 读取 FAT32 根目录 — 简化版:读取 BPB 获取根目录区 */
|
||||
u8 bpb[512];
|
||||
if (g_ac.block_read(0, 0, 1, bpb) != 0) {
|
||||
term_puts_color("ls: 读取 BPB 失败\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
/* 检查 FAT32 签名 */
|
||||
if (bpb[510] != 0x55 || bpb[511] != 0xAA) {
|
||||
term_puts_color("ls: 无有效 FAT32 分区\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
u32 root_cluster = *(u32 *)(bpb + 44);
|
||||
u16 bytes_per_sector = *(u16 *)(bpb + 11);
|
||||
u8 sectors_per_cluster = bpb[13];
|
||||
u32 fat_start = *(u16 *)(bpb + 14);
|
||||
u32 data_start = fat_start + (*(u16 *)(bpb + 22)) * 2;
|
||||
(void)bytes_per_sector;
|
||||
(void)sectors_per_cluster;
|
||||
(void)data_start;
|
||||
|
||||
/* 读取根目录簇 — 简化:只读取第一个簇 */
|
||||
u8 dir_buf[8192];
|
||||
u32 cluster = root_cluster;
|
||||
u32 lba = data_start + (cluster - 2) * sectors_per_cluster;
|
||||
if (g_ac.block_read(0, lba, sectors_per_cluster, dir_buf) != 0) {
|
||||
term_puts_color("ls: 读取根目录失败\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
/* 解析目录项 */
|
||||
int found = 0;
|
||||
for (int i = 0; i < (int)(sectors_per_cluster * 512); i += 32) {
|
||||
u8 first = dir_buf[i];
|
||||
if (first == 0x00) break;
|
||||
if (first == 0xE5) continue;
|
||||
if (dir_buf[i+11] & 0x08) continue; /* 卷标 */
|
||||
if (dir_buf[i+11] & 0x10) {
|
||||
/* 目录 */
|
||||
term_puts_color("[DIR] ", DA_ACCENT);
|
||||
} else {
|
||||
term_puts_color(" ", DA_TEXT_PRIMARY);
|
||||
}
|
||||
/* 文件名(8.3) */
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (dir_buf[i+j] == ' ') break;
|
||||
term_putc((char)dir_buf[i+j]);
|
||||
}
|
||||
if (dir_buf[i+8] != ' ') {
|
||||
term_putc('.');
|
||||
for (int j = 8; j < 11; j++) {
|
||||
if (dir_buf[i+j] == ' ') break;
|
||||
term_putc((char)dir_buf[i+j]);
|
||||
}
|
||||
}
|
||||
term_putc('\n');
|
||||
found++;
|
||||
}
|
||||
if (found == 0) term_puts_color("(empty)\n", DA_TEXT_DIM);
|
||||
}
|
||||
|
||||
static void cmd_cat(const char *args) {
|
||||
if (!args || !*args) {
|
||||
term_puts_color("cat: 需要文件名参数\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
if (!g_ac.block_read) {
|
||||
term_puts_color("cat: 无块设备可用\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
term_puts_color("cat: 文件读取暂未完整实现\n", DA_WARNING);
|
||||
}
|
||||
|
||||
static void execute_command(const char *cmd) {
|
||||
while (*cmd == ' ') cmd++;
|
||||
if (*cmd == 0) return;
|
||||
const char *args = cmd;
|
||||
while (*args && *args != ' ') args++;
|
||||
char name[32];
|
||||
int nlen = (int)(args - cmd);
|
||||
if (nlen >= 32) nlen = 31;
|
||||
for (int i = 0; i < nlen; i++) name[i] = cmd[i];
|
||||
name[nlen] = 0;
|
||||
while (*args == ' ') args++;
|
||||
|
||||
if (str_eq(name,"help")||str_eq(name,"?")) cmd_help();
|
||||
else if (str_eq(name,"version")||str_eq(name,"ver")) cmd_version();
|
||||
else if (str_eq(name,"uname")) cmd_uname();
|
||||
else if (str_eq(name,"about")) cmd_about();
|
||||
else if (str_eq(name,"clear")||str_eq(name,"cls")) cmd_clear();
|
||||
else if (str_eq(name,"reboot")) cmd_reboot();
|
||||
else if (str_eq(name,"halt")||str_eq(name,"shutdown")) cmd_halt();
|
||||
else if (str_eq(name,"echo")) cmd_echo(args);
|
||||
else if (str_eq(name,"date")||str_eq(name,"time")) cmd_date();
|
||||
else if (str_eq(name,"ls")||str_eq(name,"dir")) cmd_ls();
|
||||
else if (str_eq(name,"cat")) cmd_cat(args);
|
||||
else if (str_eq(name,"pwd")) { term_puts("/\n"); }
|
||||
else if (str_eq(name,"whoami")) { term_puts("root\n"); }
|
||||
else if (str_eq(name,"id")) { term_puts("uid=0(root) gid=0(root)\n"); }
|
||||
else {
|
||||
term_puts_color("未知命令: ", DA_ERROR);
|
||||
term_puts_color(name, DA_ERROR);
|
||||
term_putc('\n');
|
||||
term_puts_color("输入 'help' 查看可用命令\n", DA_TEXT_DIM);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_history(const char *cmd) {
|
||||
if (hist_count < HIST_SIZE) {
|
||||
int i;
|
||||
for (i = 0; cmd[i] && i < 255; i++) history[hist_count][i] = cmd[i];
|
||||
history[hist_count][i] = 0;
|
||||
hist_count++;
|
||||
}
|
||||
hist_idx = hist_count;
|
||||
}
|
||||
|
||||
/* ---- 输入行重绘 ---- */
|
||||
static void redraw_input_line(void) {
|
||||
int plen = 0;
|
||||
while (PROMPT_STR[plen]) plen++;
|
||||
i64 y = term_y + (i64)cur_row * CHAR_H;
|
||||
da_fill_rect(&g_ac, term_x, y, (i64)term_w * CHAR_STEP, CHAR_H, DA_BG_PRIMARY);
|
||||
for (int i = 0; i < plen; i++)
|
||||
da_draw_char(&g_ac, PROMPT_STR[i], term_x + i * CHAR_STEP, y, DA_PROMPT_COLOR, DA_BG_PRIMARY);
|
||||
for (int i = 0; i < input_len; i++)
|
||||
da_draw_char(&g_ac, input_buf[i], term_x + (plen + i) * CHAR_STEP, y, DA_TEXT_PRIMARY, DA_BG_PRIMARY);
|
||||
cur_col = plen + input_cursor;
|
||||
/* 光标 */
|
||||
da_fill_rect(&g_ac, term_x + cur_col * CHAR_STEP, y + CHAR_H - 3, 11, 2, DA_ACCENT);
|
||||
}
|
||||
|
||||
/* ---- 主入口 ---- */
|
||||
__attribute__((visibility("default")))
|
||||
void dsk_entry(const da_boot_context *ctx) {
|
||||
__asm__ volatile("cli");
|
||||
da_slog("bash", "boot");
|
||||
|
||||
if (!ctx || ctx->magic != DA_BOOT_MAGIC) {
|
||||
da_slog("bash", "bad context");
|
||||
for(;;) __asm__("hlt");
|
||||
}
|
||||
|
||||
da_init(&g_ac, ctx);
|
||||
term_init_layout();
|
||||
term_clear();
|
||||
|
||||
/* 启动 banner */
|
||||
term_puts_color("=== Deshab Bash v0.1 ===\n", DA_ACCENT);
|
||||
term_puts_color("欢迎使用 Deshab 终端\n", DA_SUCCESS);
|
||||
term_puts_color("输入 'help' 查看可用命令 | Esc 退出\n", DA_TEXT_DIM);
|
||||
term_putc('\n');
|
||||
|
||||
redraw_all();
|
||||
|
||||
int shift = 0, e0 = 0;
|
||||
for (;;) {
|
||||
/* 绘制提示符 */
|
||||
term_puts_color(PROMPT_STR, DA_PROMPT_COLOR);
|
||||
input_len = 0; input_cursor = 0; input_buf[0] = 0;
|
||||
int plen = 0; while (PROMPT_STR[plen]) plen++;
|
||||
cur_col = plen;
|
||||
redraw_all();
|
||||
|
||||
int cmd_done = 0;
|
||||
while (!cmd_done) {
|
||||
u8 st = inb(0x64);
|
||||
if (!(st & 1)) { __asm__("pause"); continue; }
|
||||
u8 data = inb(0x60);
|
||||
if (st & 0x20) continue;
|
||||
u8 sc = data;
|
||||
if (sc == 0xE0) { e0 = 1; continue; }
|
||||
if (sc == 0x2A || sc == 0x36) { shift = 1; continue; }
|
||||
if (sc == 0xAA || sc == 0xB6) { shift = 0; continue; }
|
||||
if (sc & 0x80) { e0 = 0; continue; }
|
||||
|
||||
/* Esc 退出 */
|
||||
if (sc == 0x01 && !e0) {
|
||||
da_slog("bash", "exit");
|
||||
return;
|
||||
}
|
||||
|
||||
if (e0) {
|
||||
if (sc == 0x4B) { if (input_cursor > 0) input_cursor--; }
|
||||
else if (sc == 0x4D) { if (input_cursor < input_len) input_cursor++; }
|
||||
else if (sc == 0x47) { input_cursor = 0; }
|
||||
else if (sc == 0x4F) { input_cursor = input_len; }
|
||||
else if (sc == 0x48) { /* 上箭头 - 历史 */
|
||||
if (hist_idx > 0) {
|
||||
hist_idx--;
|
||||
int i; for (i = 0; history[hist_idx][i] && i < 255; i++) input_buf[i] = history[hist_idx][i];
|
||||
input_len = i; input_cursor = i; input_buf[i] = 0;
|
||||
}
|
||||
}
|
||||
else if (sc == 0x50) { /* 下箭头 - 历史 */
|
||||
if (hist_idx < hist_count - 1) {
|
||||
hist_idx++;
|
||||
int i; for (i = 0; history[hist_idx][i] && i < 255; i++) input_buf[i] = history[hist_idx][i];
|
||||
input_len = i; input_cursor = i; input_buf[i] = 0;
|
||||
} else if (hist_idx < hist_count) {
|
||||
hist_idx = hist_count;
|
||||
input_len = 0; input_cursor = 0; input_buf[0] = 0;
|
||||
}
|
||||
}
|
||||
e0 = 0;
|
||||
redraw_input_line();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sc == 0x1C) { /* Enter */
|
||||
input_buf[input_len] = 0;
|
||||
term_putc('\n');
|
||||
if (input_len > 0) add_history(input_buf);
|
||||
execute_command(input_buf);
|
||||
cmd_done = 1;
|
||||
continue;
|
||||
}
|
||||
if (sc == 0x0E) { /* Backspace */
|
||||
if (input_cursor > 0) {
|
||||
for (int i = input_cursor - 1; i < input_len - 1; i++)
|
||||
input_buf[i] = input_buf[i+1];
|
||||
input_len--; input_cursor--;
|
||||
input_buf[input_len] = 0;
|
||||
}
|
||||
redraw_input_line();
|
||||
continue;
|
||||
}
|
||||
char c = da_scan_to_ascii(sc, shift);
|
||||
if (c && c >= 32 && c <= 126 && input_len < 255) {
|
||||
for (int i = input_len; i > input_cursor; i--)
|
||||
input_buf[i] = input_buf[i-1];
|
||||
input_buf[input_cursor++] = c;
|
||||
input_len++;
|
||||
redraw_input_line();
|
||||
}
|
||||
}
|
||||
redraw_all();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(7);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(7);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(7);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(7);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
+112
-21
@@ -1,11 +1,11 @@
|
||||
/* Deshab curl — 终端风格 HTTP 客户端 stub
|
||||
* 命令行输入 URL,显示 HTTP GET 请求结果。
|
||||
* 当前为 stub,提示需要 TCP/IP 栈支持。
|
||||
/* Deshab curl — 终端风格 HTTP 客户端
|
||||
* 命令行输入 URL,发送 HTTP/1.0 GET 请求并打印响应(net_stack.h 共享协议栈)。
|
||||
* Esc 键退出返回 DSK。
|
||||
*/
|
||||
|
||||
#include "../../firstInit/ascii_bitmaps.c"
|
||||
#include "../desktop_app.h"
|
||||
#include "../net_stack.h"
|
||||
|
||||
/* ---- 终端参数 ---- */
|
||||
#define TERM_COLS 120
|
||||
@@ -125,29 +125,121 @@ static void redraw_all(void) {
|
||||
da_draw_statusbar(&g_ac, status, (i64)g_ac.fb_w, (i64)g_ac.fb_h);
|
||||
}
|
||||
|
||||
/* ---- URL 请求模拟 ---- */
|
||||
/* ---- HTTP GET 实现(net_stack.h) ---- */
|
||||
static int g_ns_status = 0; /* 0=未尝试, 1=就绪, <0=失败 */
|
||||
|
||||
static int curl_net_ready(void) {
|
||||
if (g_ns_status == 1) return 1;
|
||||
if (g_ns_status < 0) return 0;
|
||||
int rc = ns_init((u64)g_ac.kernel_api);
|
||||
g_ns_status = (rc == 0) ? 1 : -1;
|
||||
if (rc != 0) {
|
||||
term_puts_color(" [错误] 网络初始化失败,无可用网卡或 net API\n", DA_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void do_http_get(const char *url) {
|
||||
if (!curl_net_ready()) return;
|
||||
|
||||
const char *p = url;
|
||||
if (p[0]=='h'&&p[1]=='t'&&p[2]=='t'&&p[3]=='p'&&p[4]==':'&&p[5]=='/'&&p[6]=='/') p += 7;
|
||||
|
||||
char host[128]; int hl = 0;
|
||||
while (*p && *p != ':' && *p != '/' && hl < 127) host[hl++] = *p++;
|
||||
host[hl] = 0;
|
||||
if (!hl) { term_puts_color(" [错误] 缺少主机名\n", DA_ERROR); return; }
|
||||
|
||||
u16 port = 80;
|
||||
if (*p == ':') {
|
||||
p++;
|
||||
u32 pv = 0; int digits = 0;
|
||||
while (*p >= '0' && *p <= '9') { pv = pv * 10 + (u32)(*p - '0'); p++; digits++; }
|
||||
if (digits && pv <= 65535) port = (u16)pv;
|
||||
}
|
||||
char path[128]; int pl = 0;
|
||||
if (*p == '/') {
|
||||
while (*p && *p != ' ' && pl < 127) path[pl++] = *p++;
|
||||
}
|
||||
if (!pl) { path[0] = '/'; pl = 1; }
|
||||
path[pl] = 0;
|
||||
|
||||
term_puts_color("GET ", DA_PROMPT_COLOR);
|
||||
term_puts_color(url, DA_ACCENT_LIGHT);
|
||||
term_putc('\n');
|
||||
term_puts_color(" -> 解析主机...\n", DA_TEXT_DIM);
|
||||
term_puts_color(" -> 建立 TCP 连接...\n", DA_TEXT_DIM);
|
||||
|
||||
/* stub: 检查 kernel_api 是否有 net 接口 */
|
||||
if (!g_ac.kernel_api) {
|
||||
term_puts_color(" [错误] 无内核 API\n", DA_ERROR);
|
||||
/* 解析主机 */
|
||||
term_puts_color(" -> 解析 ", DA_TEXT_DIM);
|
||||
term_puts_color(host, DA_TEXT_DIM);
|
||||
term_puts_color("...\n", DA_TEXT_DIM);
|
||||
redraw_all();
|
||||
u32 ip;
|
||||
if (ns_dns_resolve(host, &ip) != 0) {
|
||||
term_puts_color(" [错误] DNS 解析失败\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
/* 尝试读取 net API — 当前为 stub */
|
||||
u64 net_api = *(u64 *)((u64)g_ac.kernel_api + 0xC0);
|
||||
if (!net_api) {
|
||||
term_puts_color(" [错误] 需要 TCP/IP 栈支持\n", DA_ERROR);
|
||||
term_puts_color(" 当前内核未实现网络协议栈。\n", DA_WARNING);
|
||||
term_puts_color(" 请等待后续版本更新。\n", DA_TEXT_DIM);
|
||||
char ipstr[24]; ns_fmt_ip(ip, ipstr);
|
||||
term_puts_color(" -> ", DA_TEXT_DIM);
|
||||
term_puts_color(ipstr, DA_TEXT_DIM);
|
||||
term_putc('\n');
|
||||
|
||||
/* TCP 连接 */
|
||||
term_puts_color(" -> TCP 连接...\n", DA_TEXT_DIM);
|
||||
redraw_all();
|
||||
if (ns_tcp_connect(ip, port, 2000) != 0) {
|
||||
term_puts_color(" [错误] TCP 连接失败(超时/RST)\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
/* 如果有 net API,此处应实现真正的 HTTP GET */
|
||||
term_puts_color(" [stub] 网络功能尚未实现\n", DA_WARNING);
|
||||
|
||||
/* 构造 HTTP/1.0 请求 */
|
||||
static char req[512];
|
||||
int r = 0;
|
||||
const char *m = "GET "; while (*m) req[r++] = *m++;
|
||||
for (int i = 0; i < pl; i++) req[r++] = path[i];
|
||||
m = " HTTP/1.0\r\nHost: "; while (*m) req[r++] = *m++;
|
||||
for (int i = 0; i < hl; i++) req[r++] = host[i];
|
||||
m = "\r\nConnection: close\r\n\r\n"; while (*m) req[r++] = *m++;
|
||||
req[r] = 0;
|
||||
|
||||
term_puts_color(" -> 已连接,发送请求\n", DA_TEXT_DIM);
|
||||
redraw_all();
|
||||
if (ns_tcp_send((const u8 *)req, (u32)r) != 0) {
|
||||
term_puts_color(" [错误] 发送失败\n", DA_ERROR);
|
||||
ns_tcp_close();
|
||||
return;
|
||||
}
|
||||
|
||||
/* 收至 FIN */
|
||||
term_puts_color(" -> 等待响应...\n", DA_TEXT_DIM);
|
||||
redraw_all();
|
||||
int n = ns_tcp_recv(0, 0, 5000);
|
||||
ns_tcp_close();
|
||||
if (n < 0) {
|
||||
term_puts_color(" [错误] 连接被重置\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
if (n == 0) {
|
||||
term_puts_color(" [错误] 无响应数据(超时)\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
term_puts_color(" -> 收到 ", DA_SUCCESS);
|
||||
char nb[12]; ns_u32_dec(nb, (u32)n);
|
||||
term_puts_color(nb, DA_SUCCESS);
|
||||
term_puts_color(" 字节\n\n", DA_SUCCESS);
|
||||
|
||||
/* 打印 status line + body */
|
||||
u32 total = ns_tcp_rx_len;
|
||||
u32 show = (u32)n;
|
||||
for (u32 i = 0; i < show; i++) term_putc((char)ns_tcp_rx[i]);
|
||||
if (total > show) {
|
||||
term_puts_color("\n[... 已截断,共 ", DA_TEXT_DIM);
|
||||
ns_u32_dec(nb, total);
|
||||
term_puts_color(nb, DA_TEXT_DIM);
|
||||
term_puts_color(" 字节]\n", DA_TEXT_DIM);
|
||||
}
|
||||
term_putc('\n');
|
||||
}
|
||||
|
||||
/* ---- 内置命令 ---- */
|
||||
@@ -168,8 +260,8 @@ static void cmd_help(void) {
|
||||
static void cmd_clear(void) { term_clear(); }
|
||||
|
||||
static void cmd_version(void) {
|
||||
term_puts_color("Deshab curl v0.1 (stub)\n", DA_SUCCESS);
|
||||
term_puts_color(" HTTP 客户端功能需要 TCP/IP 栈支持\n", DA_TEXT_DIM);
|
||||
term_puts_color("Deshab curl v1.0\n", DA_SUCCESS);
|
||||
term_puts_color(" HTTP/1.0 GET via net_stack (e1000 + slirp)\n", DA_TEXT_DIM);
|
||||
}
|
||||
|
||||
static void execute_command(const char *cmd) {
|
||||
@@ -231,10 +323,9 @@ void dsk_entry(const da_boot_context *ctx) {
|
||||
term_clear();
|
||||
|
||||
/* 启动 banner */
|
||||
term_puts_color("=== Deshab curl v0.1 (stub) ===\n", DA_ACCENT);
|
||||
term_puts_color("=== Deshab curl v1.0 ===\n", DA_ACCENT);
|
||||
term_puts_color("HTTP 命令行客户端\n", DA_SUCCESS);
|
||||
term_puts_color("输入 URL 发送 GET 请求 | 输入 'help' 查看帮助 | Esc 退出\n", DA_TEXT_DIM);
|
||||
term_puts_color("注意: 当前需要 TCP/IP 栈支持\n", DA_WARNING);
|
||||
term_putc('\n');
|
||||
|
||||
redraw_all();
|
||||
|
||||
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(7);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(7);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(7);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(7);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
@@ -0,0 +1,716 @@
|
||||
/* net_stack.h — Deshab 用户态共享网络协议栈(static inline,无库)
|
||||
*
|
||||
* 前置条件:包含者已定义 u8/u16/u32/u64/i64 基础类型。
|
||||
* 通过 dkm_kernel_api + 0x48 的 net API 收发原始以太帧(轮询模型,无 IRQ)。
|
||||
*
|
||||
* 能力:eth II / ARP(含应答)/ IPv4 / ICMP echo / UDP DNS / TCP 最小 client。
|
||||
* 默认拓扑:QEMU slirp — guest 10.0.2.15 / gw 10.0.2.2 / dns 10.0.2.3。
|
||||
*
|
||||
* 用法:
|
||||
* ns_init(ctx->dkm_kernel_api) — 初始化,选第一个有线 tx/rx ready 设备
|
||||
* ns_ping(ip, seq, timeout, &rtt, &ttl) — 单次 ICMP echo
|
||||
* ns_dns_resolve(host, &ip) — A 记录查询(数字 IP 直接返回)
|
||||
* ns_tcp_connect(ip, port, timeout)
|
||||
* ns_tcp_send(data, len)
|
||||
* ns_tcp_recv(buf, cap, idle_timeout) — 收至 FIN/超时,返回累计长度
|
||||
* ns_tcp_close()
|
||||
*
|
||||
* IP 以 u32 网络序数值表示(NS_IP4(10,0,2,15))。
|
||||
*/
|
||||
|
||||
#ifndef DESHAB_NET_STACK_H
|
||||
#define DESHAB_NET_STACK_H
|
||||
|
||||
/* ---- 默认网络配置(QEMU user-mode slirp) ---- */
|
||||
#define NS_IP4(a,b,c,d) ((u32)((((u32)(a))<<24)|(((u32)(b))<<16)|(((u32)(c))<<8)|((u32)(d))))
|
||||
#define NS_GUEST_IP NS_IP4(10,0,2,15)
|
||||
#define NS_GATEWAY_IP NS_IP4(10,0,2,2)
|
||||
#define NS_DNS_IP NS_IP4(10,0,2,3)
|
||||
#define NS_NETMASK NS_IP4(255,255,255,0)
|
||||
|
||||
#define NS_ETH_ARP 0x0806
|
||||
#define NS_ETH_IPV4 0x0800
|
||||
#define NS_IP_ICMP 1
|
||||
#define NS_IP_TCP 6
|
||||
#define NS_IP_UDP 17
|
||||
|
||||
#define NS_ARP_CACHE_SIZE 8
|
||||
#define NS_TCP_RX_CAP 65536
|
||||
|
||||
/* dkm_net_device_desc.flags 位(与 utsm/net.h 一致) */
|
||||
#define NS_NET_F_TX_READY 0x2
|
||||
#define NS_NET_F_RX_READY 0x4
|
||||
#define NS_NET_F_WIRELESS 0x8
|
||||
|
||||
/* ---- 端口 I/O / TSC(ns_ 前缀避免与包含者冲突) ---- */
|
||||
static inline void ns_outb(u16 p, u8 v) { __asm__ volatile("outb %0,%1"::"a"(v),"Nd"(p)); }
|
||||
static inline u8 ns_inb(u16 p) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(p)); return v; }
|
||||
static inline u64 ns_rdtsc(void) {
|
||||
u32 lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
return ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
/* PIT ch0 ~10ms 校准 TSC(与 shell/dsk 同法) */
|
||||
static u64 ns_tsc_per_ms = 0;
|
||||
static inline void ns_tsc_calibrate(void) {
|
||||
if (ns_tsc_per_ms) return;
|
||||
ns_outb(0x43, 0x30);
|
||||
ns_outb(0x40, 0x7C);
|
||||
ns_outb(0x40, 0x2E);
|
||||
u64 t0 = ns_rdtsc();
|
||||
u16 prev = 0; u64 loops = 0;
|
||||
for (;;) {
|
||||
ns_outb(0x43, 0x00);
|
||||
u16 cur = (u16)ns_inb(0x40) | ((u16)ns_inb(0x40) << 8);
|
||||
if (cur > prev && loops > 10) break;
|
||||
prev = cur; loops++;
|
||||
}
|
||||
ns_tsc_per_ms = (ns_rdtsc() - t0) / 10;
|
||||
if (!ns_tsc_per_ms) ns_tsc_per_ms = 3000; /* 兜底 ~3GHz */
|
||||
}
|
||||
|
||||
static inline int ns_deadline_reached(u64 deadline) {
|
||||
return (i64)(ns_rdtsc() - deadline) >= 0;
|
||||
}
|
||||
|
||||
/* ---- 字节序/校验和 ---- */
|
||||
static inline void ns_w16(u8 *p, u16 v) { p[0] = (u8)(v >> 8); p[1] = (u8)v; }
|
||||
static inline void ns_w32(u8 *p, u32 v) { p[0] = (u8)(v >> 24); p[1] = (u8)(v >> 16); p[2] = (u8)(v >> 8); p[3] = (u8)v; }
|
||||
static inline u16 ns_r16(const u8 *p) { return (u16)(((u16)p[0] << 8) | p[1]); }
|
||||
static inline u32 ns_r32(const u8 *p) { return ((u32)p[0] << 24) | ((u32)p[1] << 16) | ((u32)p[2] << 8) | p[3]; }
|
||||
|
||||
static inline u16 ns_checksum(const void *data, u32 len) {
|
||||
const u8 *p = (const u8 *)data;
|
||||
u32 sum = 0;
|
||||
while (len > 1) { sum += ((u16)p[0] << 8) | p[1]; p += 2; len -= 2; }
|
||||
if (len) sum += ((u16)p[0] << 8);
|
||||
while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
return (u16)~sum;
|
||||
}
|
||||
|
||||
static inline void ns_memcpy(void *d, const void *s, u32 n) {
|
||||
u8 *dd = (u8 *)d; const u8 *ss = (const u8 *)s;
|
||||
while (n--) *dd++ = *ss++;
|
||||
}
|
||||
static inline void ns_memset(void *d, u8 c, u32 n) {
|
||||
u8 *dd = (u8 *)d; while (n--) *dd++ = c;
|
||||
}
|
||||
|
||||
/* ---- 十进制/IP 字符串 ---- */
|
||||
static inline void ns_u32_dec(char *buf, u32 v) {
|
||||
char tmp[12]; int n = 0;
|
||||
if (!v) { buf[0] = '0'; buf[1] = 0; return; }
|
||||
while (v && n < 11) { tmp[n++] = (char)('0' + v % 10); v /= 10; }
|
||||
for (int i = 0; i < n; i++) buf[i] = tmp[n - 1 - i];
|
||||
buf[n] = 0;
|
||||
}
|
||||
|
||||
static inline void ns_fmt_ip(u32 ip, char *out) {
|
||||
int p = 0;
|
||||
for (int i = 3; i >= 0; i--) {
|
||||
char d[4]; ns_u32_dec(d, (ip >> (i * 8)) & 0xFF);
|
||||
for (int j = 0; d[j]; j++) out[p++] = d[j];
|
||||
if (i) out[p++] = '.';
|
||||
}
|
||||
out[p] = 0;
|
||||
}
|
||||
|
||||
/* 解析 "a.b.c.d" → 网络序 u32。返回 0 成功。 */
|
||||
static inline int ns_parse_ip(const char *s, u32 *out) {
|
||||
u32 v = 0;
|
||||
for (int part = 0; part < 4; part++) {
|
||||
u32 n = 0; int digits = 0;
|
||||
while (*s >= '0' && *s <= '9') {
|
||||
n = n * 10 + (u32)(*s - '0');
|
||||
if (n > 255) return -1;
|
||||
s++; digits++;
|
||||
}
|
||||
if (!digits) return -1;
|
||||
v = (v << 8) | n;
|
||||
if (part < 3) {
|
||||
if (*s != '.') return -1;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
if (*s && *s != ' ') return -1;
|
||||
*out = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- net API 绑定 ---- */
|
||||
typedef int (*ns_net_tx_fn)(u32 index, const void *packet, u32 length);
|
||||
typedef int (*ns_net_rx_poll_fn)(u32 index, void *buffer, u32 capacity, u32 *out_length);
|
||||
typedef u32 (*ns_net_count_fn)(void);
|
||||
typedef int (*ns_net_info_fn)(u32 index, void *out);
|
||||
|
||||
static int ns_ready = 0;
|
||||
static u32 ns_dev_index = 0;
|
||||
static u8 ns_mac[6] = {0};
|
||||
static ns_net_tx_fn ns_net_tx = 0;
|
||||
static ns_net_rx_poll_fn ns_net_rx_poll_fn_ptr = 0;
|
||||
static u16 ns_ip_id = 1;
|
||||
|
||||
/* dkm_net_device_info 布局:name ptr @0, mac[6] @8, flags @16(对齐填充后 size 24) */
|
||||
typedef struct __attribute__((packed)) {
|
||||
u64 name;
|
||||
u8 mac[6];
|
||||
u16 pad;
|
||||
u32 flags;
|
||||
} ns_dev_info;
|
||||
|
||||
static inline int ns_init(u64 dkm_kernel_api) {
|
||||
if (ns_ready) return 0;
|
||||
if (!dkm_kernel_api) return -1;
|
||||
u64 net = *(u64 *)(dkm_kernel_api + 0x48);
|
||||
if (!net) return -2;
|
||||
ns_net_count_fn device_count = (ns_net_count_fn)*(u64 *)(net + 0x08);
|
||||
ns_net_info_fn device_info = (ns_net_info_fn)*(u64 *)(net + 0x10);
|
||||
ns_net_tx = (ns_net_tx_fn)*(u64 *)(net + 0x18);
|
||||
ns_net_rx_poll_fn_ptr = (ns_net_rx_poll_fn)*(u64 *)(net + 0x20);
|
||||
if (!device_count || !device_info || !ns_net_tx || !ns_net_rx_poll_fn_ptr) return -3;
|
||||
u32 n = device_count();
|
||||
if (!n) return -4;
|
||||
|
||||
int picked = -1;
|
||||
ns_dev_info info;
|
||||
for (u32 i = 0; i < n && i < 8; i++) {
|
||||
ns_memset(&info, 0, sizeof(info));
|
||||
if (device_info(i, &info) != 0) continue;
|
||||
if (info.flags & NS_NET_F_WIRELESS) continue;
|
||||
if ((info.flags & NS_NET_F_TX_READY) && (info.flags & NS_NET_F_RX_READY)) {
|
||||
picked = (int)i;
|
||||
for (int k = 0; k < 6; k++) ns_mac[k] = info.mac[k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (picked < 0) {
|
||||
ns_memset(&info, 0, sizeof(info));
|
||||
if (device_info(0, &info) != 0) return -5;
|
||||
picked = 0;
|
||||
for (int k = 0; k < 6; k++) ns_mac[k] = info.mac[k];
|
||||
}
|
||||
ns_dev_index = (u32)picked;
|
||||
ns_tsc_calibrate();
|
||||
ns_ready = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---- 帧缓冲 ---- */
|
||||
static u8 ns_txbuf[2048];
|
||||
static u8 ns_rxframe[2048];
|
||||
|
||||
/* 发送以太帧 */
|
||||
static inline int ns_send_eth(const u8 dst_mac[6], u16 ethertype, const u8 *payload, u32 len) {
|
||||
if (len + 14 > sizeof(ns_txbuf)) return -1;
|
||||
for (int i = 0; i < 6; i++) ns_txbuf[i] = dst_mac[i];
|
||||
for (int i = 0; i < 6; i++) ns_txbuf[6 + i] = ns_mac[i];
|
||||
ns_w16(ns_txbuf + 12, ethertype);
|
||||
ns_memcpy(ns_txbuf + 14, payload, len);
|
||||
u32 total = len + 14;
|
||||
if (total < 60) { /* 以太网最小帧 */
|
||||
ns_memset(ns_txbuf + total, 0, 60 - total);
|
||||
total = 60;
|
||||
}
|
||||
return ns_net_tx(ns_dev_index, ns_txbuf, total);
|
||||
}
|
||||
|
||||
/* ---- ARP ---- */
|
||||
typedef struct {
|
||||
u32 ip;
|
||||
u8 mac[6];
|
||||
u8 valid;
|
||||
} ns_arp_entry;
|
||||
|
||||
static ns_arp_entry ns_arp_cache[NS_ARP_CACHE_SIZE];
|
||||
static u8 ns_arp_reply_mac[6];
|
||||
static volatile int ns_arp_reply_valid = 0;
|
||||
|
||||
static inline void ns_arp_cache_put(u32 ip, const u8 mac[6]) {
|
||||
int slot = -1;
|
||||
for (int i = 0; i < NS_ARP_CACHE_SIZE; i++) {
|
||||
if (ns_arp_cache[i].valid && ns_arp_cache[i].ip == ip) { slot = i; break; }
|
||||
}
|
||||
if (slot < 0) {
|
||||
for (int i = 0; i < NS_ARP_CACHE_SIZE; i++) {
|
||||
if (!ns_arp_cache[i].valid) { slot = i; break; }
|
||||
}
|
||||
}
|
||||
if (slot < 0) slot = 0;
|
||||
ns_arp_cache[slot].ip = ip;
|
||||
for (int k = 0; k < 6; k++) ns_arp_cache[slot].mac[k] = mac[k];
|
||||
ns_arp_cache[slot].valid = 1;
|
||||
}
|
||||
|
||||
static inline int ns_arp_cache_get(u32 ip, u8 mac[6]) {
|
||||
for (int i = 0; i < NS_ARP_CACHE_SIZE; i++) {
|
||||
if (ns_arp_cache[i].valid && ns_arp_cache[i].ip == ip) {
|
||||
for (int k = 0; k < 6; k++) mac[k] = ns_arp_cache[i].mac[k];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 构造 ARP 包到 out(42 字节),oper 1=request 2=reply */
|
||||
static inline void ns_arp_build(u8 *out, u16 oper,
|
||||
const u8 sha[6], u32 spa,
|
||||
const u8 tha[6], u32 tpa) {
|
||||
ns_w16(out + 0, 1); /* htype eth */
|
||||
ns_w16(out + 2, NS_ETH_IPV4); /* ptype */
|
||||
out[4] = 6; out[5] = 4;
|
||||
ns_w16(out + 6, oper);
|
||||
for (int i = 0; i < 6; i++) out[8 + i] = sha[i];
|
||||
ns_w32(out + 14, spa);
|
||||
for (int i = 0; i < 6; i++) out[18 + i] = tha[i];
|
||||
ns_w32(out + 24, tpa);
|
||||
}
|
||||
|
||||
/* 处理收到的 ARP 包:应答对我们的请求,记录 reply。 */
|
||||
static inline void ns_arp_handle(const u8 *pkt, u32 len) {
|
||||
if (len < 28) return;
|
||||
u16 oper = ns_r16(pkt + 6);
|
||||
u32 spa = ns_r32(pkt + 14);
|
||||
u32 tpa = ns_r32(pkt + 24);
|
||||
if (oper == 1 && tpa == NS_GUEST_IP) {
|
||||
/* 请求我们的 IP → 回复 */
|
||||
u8 reply[28];
|
||||
ns_arp_build(reply, 2, ns_mac, NS_GUEST_IP, pkt + 8, spa);
|
||||
ns_send_eth(pkt + 8, NS_ETH_ARP, reply, 28);
|
||||
} else if (oper == 2) {
|
||||
ns_arp_cache_put(spa, pkt + 8);
|
||||
for (int k = 0; k < 6; k++) ns_arp_reply_mac[k] = pkt[8 + k];
|
||||
ns_arp_reply_valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 轮询一帧;ARP 内部处理(不返回给调用者)。
|
||||
* 返回 0=收到非 ARP 帧(*out_et 为 ethertype),1=超时。 */
|
||||
static inline int ns_wait_frame(u8 *buf, u32 cap, u32 *out_len, u16 *out_et, u32 timeout_ms) {
|
||||
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * timeout_ms;
|
||||
for (;;) {
|
||||
u32 len = 0;
|
||||
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, buf, cap, &len);
|
||||
if (rc == 0 && len >= 14) {
|
||||
u16 et = ns_r16(buf + 12);
|
||||
if (et == NS_ETH_ARP) {
|
||||
ns_arp_handle(buf + 14, len - 14);
|
||||
/* 继续等待 */
|
||||
} else {
|
||||
*out_len = len;
|
||||
*out_et = et;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (ns_deadline_reached(deadline)) return 1;
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
}
|
||||
|
||||
/* ARP 解析 ip → mac,3 次重传。返回 0 成功。 */
|
||||
static inline int ns_arp_resolve(u32 ip, u8 out_mac[6]) {
|
||||
if (ns_arp_cache_get(ip, out_mac) == 0) return 0;
|
||||
static const u8 bcast[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
|
||||
static const u8 zero_mac[6] = {0,0,0,0,0,0};
|
||||
for (int attempt = 0; attempt < 3; attempt++) {
|
||||
u8 req[28];
|
||||
ns_arp_build(req, 1, ns_mac, NS_GUEST_IP, zero_mac, ip);
|
||||
ns_arp_reply_valid = 0;
|
||||
if (ns_send_eth(bcast, NS_ETH_ARP, req, 28) != 0) continue;
|
||||
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * 1000;
|
||||
while (!ns_deadline_reached(deadline)) {
|
||||
u32 len = 0;
|
||||
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, ns_rxframe, sizeof(ns_rxframe), &len);
|
||||
if (rc == 0 && len >= 14 && ns_r16(ns_rxframe + 12) == NS_ETH_ARP) {
|
||||
ns_arp_handle(ns_rxframe + 14, len - 14);
|
||||
if (ns_arp_reply_valid) {
|
||||
u32 spa = ns_r32(ns_rxframe + 14 + 14);
|
||||
if (spa == ip) {
|
||||
for (int k = 0; k < 6; k++) out_mac[k] = ns_arp_reply_mac[k];
|
||||
return 0;
|
||||
}
|
||||
ns_arp_reply_valid = 0;
|
||||
}
|
||||
}
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 目标 IP 的下一跳 MAC(同子网直连,否则走网关)。返回 0 成功。 */
|
||||
static inline int ns_route_mac(u32 dst_ip, u8 out_mac[6]) {
|
||||
u32 next = dst_ip;
|
||||
if ((dst_ip & NS_NETMASK) != (NS_GUEST_IP & NS_NETMASK)) next = NS_GATEWAY_IP;
|
||||
return ns_arp_resolve(next, out_mac);
|
||||
}
|
||||
|
||||
/* ---- IPv4 发送 ---- */
|
||||
static inline void ns_ipv4_build(u8 *out, u8 proto, u32 src, u32 dst, u32 payload_len) {
|
||||
out[0] = 0x45; /* ver=4 ihl=5 */
|
||||
out[1] = 0; /* tos */
|
||||
ns_w16(out + 2, (u16)(20 + payload_len));
|
||||
ns_w16(out + 4, ns_ip_id++);
|
||||
ns_w16(out + 6, 0x4000); /* DF */
|
||||
out[8] = 64; /* ttl */
|
||||
out[9] = proto;
|
||||
ns_w16(out + 10, 0);
|
||||
ns_w32(out + 12, src);
|
||||
ns_w32(out + 16, dst);
|
||||
ns_w16(out + 10, ns_checksum(out, 20));
|
||||
}
|
||||
|
||||
/* ---- ICMP echo(ping) ----
|
||||
* 返回 0 成功(*out_rtt_ms / *out_ttl 有效),-1 ARP 失败,-2 超时。 */
|
||||
static inline int ns_ping(u32 dst_ip, u16 seq, u32 timeout_ms, u32 *out_rtt_ms, u8 *out_ttl) {
|
||||
u8 dst_mac[6];
|
||||
if (ns_route_mac(dst_ip, dst_mac) != 0) return -1;
|
||||
|
||||
u8 pkt[20 + 8 + 32];
|
||||
ns_ipv4_build(pkt, NS_IP_ICMP, NS_GUEST_IP, dst_ip, 8 + 32);
|
||||
u8 *icmp = pkt + 20;
|
||||
icmp[0] = 8; /* echo request */
|
||||
icmp[1] = 0;
|
||||
ns_w16(icmp + 2, 0);
|
||||
ns_w16(icmp + 4, 0xD5AB); /* identifier */
|
||||
ns_w16(icmp + 6, seq);
|
||||
for (int i = 0; i < 32; i++) icmp[8 + i] = (u8)(0x61 + (i % 26));
|
||||
ns_w16(icmp + 2, ns_checksum(icmp, 8 + 32));
|
||||
|
||||
if (ns_send_eth(dst_mac, NS_ETH_IPV4, pkt, sizeof(pkt)) != 0) return -3;
|
||||
u64 t0 = ns_rdtsc();
|
||||
u64 deadline = t0 + ns_tsc_per_ms * timeout_ms;
|
||||
while (!ns_deadline_reached(deadline)) {
|
||||
u32 len = 0;
|
||||
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, ns_rxframe, sizeof(ns_rxframe), &len);
|
||||
if (rc == 0 && len >= 14) {
|
||||
u16 et = ns_r16(ns_rxframe + 12);
|
||||
if (et == NS_ETH_ARP) {
|
||||
ns_arp_handle(ns_rxframe + 14, len - 14);
|
||||
} else if (et == NS_ETH_IPV4 && len >= 14 + 20 + 8) {
|
||||
const u8 *ip = ns_rxframe + 14;
|
||||
u8 ihl = (u8)((ip[0] & 0x0F) * 4);
|
||||
if (ihl < 20 || len < 14 + ihl + 8) continue;
|
||||
if (ip[9] != NS_IP_ICMP) continue;
|
||||
const u8 *ic = ip + ihl;
|
||||
if (ic[0] == 0 && ns_r16(ic + 4) == 0xD5AB && ns_r16(ic + 6) == seq) {
|
||||
u64 dt = ns_rdtsc() - t0;
|
||||
if (out_rtt_ms) {
|
||||
u32 ms = (u32)(dt / ns_tsc_per_ms);
|
||||
*out_rtt_ms = ms;
|
||||
}
|
||||
if (out_ttl) *out_ttl = ip[8];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* ---- UDP DNS A 查询 ----
|
||||
* host 为数字 IP 时直接解析返回。返回 0 成功。 */
|
||||
static inline int ns_dns_resolve(const char *host, u32 *out_ip) {
|
||||
if (ns_parse_ip(host, out_ip) == 0) return 0;
|
||||
|
||||
u8 dst_mac[6];
|
||||
if (ns_route_mac(NS_DNS_IP, dst_mac) != 0) return -1;
|
||||
|
||||
/* 构造查询:header + qname + qtype/qclass */
|
||||
u8 q[512];
|
||||
u16 txid = (u16)(ns_rdtsc() & 0xFFFF);
|
||||
if (!txid) txid = 0x1234;
|
||||
ns_w16(q + 0, txid);
|
||||
ns_w16(q + 2, 0x0100); /* RD */
|
||||
ns_w16(q + 4, 1); /* qdcount */
|
||||
ns_w16(q + 6, 0); ns_w16(q + 8, 0); ns_w16(q + 10, 0);
|
||||
u32 p = 12;
|
||||
u32 i = 0;
|
||||
while (host[i]) {
|
||||
u32 start = p++;
|
||||
u8 n = 0;
|
||||
while (host[i] && host[i] != '.') {
|
||||
if (n >= 63 || p >= 500) return -2;
|
||||
q[p++] = (u8)host[i++]; n++;
|
||||
}
|
||||
q[start] = n;
|
||||
if (host[i] == '.') i++;
|
||||
}
|
||||
q[p++] = 0;
|
||||
ns_w16(q + p, 1); p += 2; /* A */
|
||||
ns_w16(q + p, 1); p += 2; /* IN */
|
||||
u32 qlen = p;
|
||||
|
||||
u8 pkt[20 + 8 + 512];
|
||||
ns_ipv4_build(pkt, NS_IP_UDP, NS_GUEST_IP, NS_DNS_IP, 8 + qlen);
|
||||
u8 *udp = pkt + 20;
|
||||
ns_w16(udp + 0, 49153);
|
||||
ns_w16(udp + 2, 53);
|
||||
ns_w16(udp + 4, (u16)(8 + qlen));
|
||||
ns_w16(udp + 6, 0); /* 不校验 UDP checksum */
|
||||
ns_memcpy(udp + 8, q, qlen);
|
||||
|
||||
for (int attempt = 0; attempt < 2; attempt++) {
|
||||
if (ns_send_eth(dst_mac, NS_ETH_IPV4, pkt, 20 + 8 + qlen) != 0) continue;
|
||||
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * 3000;
|
||||
while (!ns_deadline_reached(deadline)) {
|
||||
u32 len = 0;
|
||||
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, ns_rxframe, sizeof(ns_rxframe), &len);
|
||||
if (rc == 0 && len >= 14) {
|
||||
u16 et = ns_r16(ns_rxframe + 12);
|
||||
if (et == NS_ETH_ARP) {
|
||||
ns_arp_handle(ns_rxframe + 14, len - 14);
|
||||
} else if (et == NS_ETH_IPV4 && len >= 14 + 20 + 8 + 12) {
|
||||
const u8 *ip = ns_rxframe + 14;
|
||||
u8 ihl = (u8)((ip[0] & 0x0F) * 4);
|
||||
if (ihl < 20 || ip[9] != NS_IP_UDP) continue;
|
||||
const u8 *ru = ip + ihl;
|
||||
if (ns_r16(ru + 2) != 49153) continue;
|
||||
const u8 *d = ru + 8;
|
||||
if (ns_r16(d + 0) != txid) continue;
|
||||
u16 qd = ns_r16(d + 4);
|
||||
u16 an = ns_r16(d + 6);
|
||||
u32 off = 12;
|
||||
/* 跳过问题段 */
|
||||
for (u16 qq = 0; qq < qd; qq++) {
|
||||
while (off < len) {
|
||||
u8 b = d[off];
|
||||
if (b == 0) { off++; break; }
|
||||
if ((b & 0xC0) == 0xC0) { off += 2; break; }
|
||||
off += 1 + b;
|
||||
}
|
||||
off += 4;
|
||||
}
|
||||
/* 遍历应答 RR */
|
||||
for (u16 rr = 0; rr < an; rr++) {
|
||||
while (off < len) { /* 跳过 name */
|
||||
u8 b = d[off];
|
||||
if (b == 0) { off++; break; }
|
||||
if ((b & 0xC0) == 0xC0) { off += 2; break; }
|
||||
off += 1 + b;
|
||||
}
|
||||
if (off + 10 > len) break;
|
||||
u16 rtype = ns_r16(d + off);
|
||||
u16 rdlen = ns_r16(d + off + 8);
|
||||
off += 10;
|
||||
if (rtype == 1 && rdlen == 4 && off + 4 <= len) {
|
||||
*out_ip = ns_r32(d + off);
|
||||
return 0;
|
||||
}
|
||||
off += rdlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
}
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* ---- TCP 最小 client ---- */
|
||||
#define NS_TCP_CLOSED 0
|
||||
#define NS_TCP_SYN_SENT 1
|
||||
#define NS_TCP_ESTAB 2
|
||||
#define NS_TCP_FIN_WAIT 3
|
||||
|
||||
static struct {
|
||||
u32 state;
|
||||
u32 dst_ip;
|
||||
u16 dst_port;
|
||||
u16 src_port;
|
||||
u32 snd_nxt;
|
||||
u32 rcv_nxt;
|
||||
u8 dst_mac[6];
|
||||
} ns_tc = {0, 0, 0, 0, 0, 0, {0}};
|
||||
|
||||
static u8 ns_tcp_rx[NS_TCP_RX_CAP];
|
||||
static u32 ns_tcp_rx_len = 0;
|
||||
static volatile int ns_tcp_got_fin = 0;
|
||||
static volatile int ns_tcp_got_rst = 0;
|
||||
|
||||
#define NS_TCP_FIN 0x01
|
||||
#define NS_TCP_SYN 0x02
|
||||
#define NS_TCP_RST 0x04
|
||||
#define NS_TCP_PSH 0x08
|
||||
#define NS_TCP_ACK 0x10
|
||||
|
||||
/* 构造并发送 TCP 段(data 可为 0)。 */
|
||||
static inline int ns_tcp_emit(u8 flags, const u8 *data, u32 len, u32 seq) {
|
||||
u8 pkt[20 + 20 + 1460];
|
||||
if (len > 1460) return -1;
|
||||
u32 tcp_len = 20 + len;
|
||||
ns_ipv4_build(pkt, NS_IP_TCP, NS_GUEST_IP, ns_tc.dst_ip, tcp_len);
|
||||
u8 *t = pkt + 20;
|
||||
ns_w16(t + 0, ns_tc.src_port);
|
||||
ns_w16(t + 2, ns_tc.dst_port);
|
||||
ns_w32(t + 4, seq);
|
||||
ns_w32(t + 8, (flags & NS_TCP_ACK) ? ns_tc.rcv_nxt : 0);
|
||||
t[12] = (5 << 4); /* data offset */
|
||||
t[13] = flags;
|
||||
ns_w16(t + 14, 64240); /* window */
|
||||
ns_w16(t + 16, 0);
|
||||
ns_w16(t + 18, 0);
|
||||
if (len) ns_memcpy(t + 20, data, len);
|
||||
/* 伪头部校验和 */
|
||||
u8 ph[12];
|
||||
ns_w32(ph + 0, NS_GUEST_IP);
|
||||
ns_w32(ph + 4, ns_tc.dst_ip);
|
||||
ph[8] = 0; ph[9] = NS_IP_TCP;
|
||||
ns_w16(ph + 10, (u16)tcp_len);
|
||||
u32 sum = 0;
|
||||
for (u32 k = 0; k < 12; k += 2) sum += ((u16)ph[k] << 8) | ph[k + 1];
|
||||
for (u32 k = 0; k + 1 < tcp_len; k += 2) sum += ((u16)t[k] << 8) | t[k + 1];
|
||||
if (tcp_len & 1) sum += ((u16)t[tcp_len - 1] << 8);
|
||||
while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
ns_w16(t + 16, (u16)~sum);
|
||||
return ns_send_eth(ns_tc.dst_mac, NS_ETH_IPV4, pkt, 20 + tcp_len);
|
||||
}
|
||||
|
||||
/* 处理收到的 IPv4/TCP 段。返回 1 表示属于本连接并已处理。 */
|
||||
static inline int ns_tcp_process(const u8 *ip, u32 ip_len) {
|
||||
if (ip_len < 20) return 0;
|
||||
u8 ihl = (u8)((ip[0] & 0x0F) * 4);
|
||||
if (ihl < 20 || ip_len < ihl + 20) return 0;
|
||||
if (ip[9] != NS_IP_TCP) return 0;
|
||||
if (ns_r32(ip + 12) != ns_tc.dst_ip) return 0;
|
||||
const u8 *t = ip + ihl;
|
||||
if (ns_r16(t + 0) != ns_tc.dst_port) return 0;
|
||||
if (ns_r16(t + 2) != ns_tc.src_port) return 0;
|
||||
|
||||
u32 seq = ns_r32(t + 4);
|
||||
u32 ack = ns_r32(t + 8);
|
||||
u8 doff = (u8)((t[12] >> 4) * 4);
|
||||
u8 flags = t[13];
|
||||
u16 ip_total = ns_r16(ip + 2);
|
||||
u32 data_len = (u32)ip_total - ihl - doff;
|
||||
const u8 *data = t + doff;
|
||||
|
||||
if (flags & NS_TCP_RST) { ns_tcp_got_rst = 1; ns_tc.state = NS_TCP_CLOSED; return 1; }
|
||||
|
||||
if (ns_tc.state == NS_TCP_SYN_SENT) {
|
||||
if ((flags & (NS_TCP_SYN | NS_TCP_ACK)) == (NS_TCP_SYN | NS_TCP_ACK)) {
|
||||
ns_tc.rcv_nxt = seq + 1;
|
||||
ns_tc.snd_nxt = ack;
|
||||
ns_tc.state = NS_TCP_ESTAB;
|
||||
ns_tcp_emit(NS_TCP_ACK, 0, 0, ns_tc.snd_nxt);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ns_tc.state == NS_TCP_ESTAB || ns_tc.state == NS_TCP_FIN_WAIT) {
|
||||
if (data_len > 0) {
|
||||
if (seq == ns_tc.rcv_nxt) {
|
||||
u32 room = NS_TCP_RX_CAP - ns_tcp_rx_len;
|
||||
u32 take = data_len < room ? data_len : room;
|
||||
ns_memcpy(ns_tcp_rx + ns_tcp_rx_len, data, take);
|
||||
ns_tcp_rx_len += take;
|
||||
ns_tc.rcv_nxt += data_len;
|
||||
ns_tcp_emit(NS_TCP_ACK, 0, 0, ns_tc.snd_nxt);
|
||||
} else {
|
||||
/* 乱序超前或重复段:重 ACK 当前期望序号 */
|
||||
ns_tcp_emit(NS_TCP_ACK, 0, 0, ns_tc.snd_nxt);
|
||||
}
|
||||
}
|
||||
if (flags & NS_TCP_FIN) {
|
||||
if (seq + data_len == ns_tc.rcv_nxt || data_len == 0) {
|
||||
ns_tc.rcv_nxt = seq + data_len + 1;
|
||||
ns_tcp_emit(NS_TCP_ACK, 0, 0, ns_tc.snd_nxt);
|
||||
ns_tcp_got_fin = 1;
|
||||
ns_tc.state = NS_TCP_CLOSED;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 在超时窗口内收帧并喂给 TCP;返回 0=收到本连接段,1=超时。 */
|
||||
static inline int ns_tcp_wait(u32 timeout_ms) {
|
||||
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * timeout_ms;
|
||||
while (!ns_deadline_reached(deadline)) {
|
||||
u32 len = 0;
|
||||
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, ns_rxframe, sizeof(ns_rxframe), &len);
|
||||
if (rc == 0 && len >= 14) {
|
||||
u16 et = ns_r16(ns_rxframe + 12);
|
||||
if (et == NS_ETH_ARP) {
|
||||
ns_arp_handle(ns_rxframe + 14, len - 14);
|
||||
} else if (et == NS_ETH_IPV4) {
|
||||
if (ns_tcp_process(ns_rxframe + 14, len - 14)) return 0;
|
||||
}
|
||||
}
|
||||
__asm__ volatile("pause");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 返回 0 成功(state=ESTAB),-1 ARP 失败,-2 超时/RST。 */
|
||||
static inline int ns_tcp_connect(u32 dst_ip, u16 dst_port, u32 timeout_ms) {
|
||||
if (ns_route_mac(dst_ip, ns_tc.dst_mac) != 0) return -1;
|
||||
ns_tc.dst_ip = dst_ip;
|
||||
ns_tc.dst_port = dst_port;
|
||||
ns_tc.src_port = (u16)(49152 + (ns_rdtsc() & 0x0FFF));
|
||||
u32 iss = (u32)ns_rdtsc();
|
||||
ns_tcp_rx_len = 0;
|
||||
ns_tcp_got_fin = 0;
|
||||
ns_tcp_got_rst = 0;
|
||||
|
||||
for (int attempt = 0; attempt < 3; attempt++) {
|
||||
ns_tc.state = NS_TCP_SYN_SENT;
|
||||
if (ns_tcp_emit(NS_TCP_SYN, 0, 0, iss) != 0) continue;
|
||||
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * timeout_ms;
|
||||
while (!ns_deadline_reached(deadline)) {
|
||||
if (ns_tcp_got_rst) { ns_tc.state = NS_TCP_CLOSED; return -2; }
|
||||
if (ns_tc.state == NS_TCP_ESTAB) return 0;
|
||||
ns_tcp_wait(50);
|
||||
}
|
||||
}
|
||||
ns_tc.state = NS_TCP_CLOSED;
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* 发送数据并等待 ACK(数据段可能在等待期间到达,已入缓冲)。 */
|
||||
static inline int ns_tcp_send(const u8 *data, u32 len) {
|
||||
if (ns_tc.state != NS_TCP_ESTAB) return -1;
|
||||
for (int attempt = 0; attempt < 3; attempt++) {
|
||||
u32 expect = ns_tc.snd_nxt + len;
|
||||
if (ns_tcp_emit((u8)(NS_TCP_PSH | NS_TCP_ACK), data, len, ns_tc.snd_nxt) != 0) return -2;
|
||||
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * 2000;
|
||||
while (!ns_deadline_reached(deadline)) {
|
||||
if (ns_tcp_got_rst) { ns_tc.state = NS_TCP_CLOSED; return -3; }
|
||||
/* 检查 snd_una 是否被 ACK 推进:ns_tcp_process 不记录 una,
|
||||
* 简单起见此处认为发出后收到任何本连接段即推进。
|
||||
* 对 HTTP/1.0 请求-响应模式足够(对端 ACK+数据一起回来)。 */
|
||||
if (ns_tcp_wait(100) == 0) {
|
||||
ns_tc.snd_nxt = expect;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* 收至 FIN 或空闲超时;把累计数据拷到 buf(最多 cap)。返回长度或负值。 */
|
||||
static inline int ns_tcp_recv(u8 *buf, u32 cap, u32 idle_timeout_ms) {
|
||||
u64 idle_deadline = ns_rdtsc() + ns_tsc_per_ms * idle_timeout_ms;
|
||||
for (;;) {
|
||||
if (ns_tcp_got_rst) return -1;
|
||||
if (ns_tcp_got_fin) break;
|
||||
if (ns_deadline_reached(idle_deadline)) break;
|
||||
if (ns_tcp_wait(100) == 0) {
|
||||
idle_deadline = ns_rdtsc() + ns_tsc_per_ms * idle_timeout_ms;
|
||||
}
|
||||
}
|
||||
u32 n = ns_tcp_rx_len < cap ? ns_tcp_rx_len : cap;
|
||||
if (buf && n) ns_memcpy(buf, ns_tcp_rx, n);
|
||||
return (int)n;
|
||||
}
|
||||
|
||||
static inline void ns_tcp_close(void) {
|
||||
if (ns_tc.state == NS_TCP_ESTAB) {
|
||||
ns_tcp_emit((u8)(NS_TCP_FIN | NS_TCP_ACK), 0, 0, ns_tc.snd_nxt);
|
||||
}
|
||||
ns_tc.state = NS_TCP_CLOSED;
|
||||
}
|
||||
|
||||
#endif /* DESHAB_NET_STACK_H */
|
||||
@@ -2,9 +2,10 @@ ENTRY(dsk_entry)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS(7);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(7);
|
||||
text PT_LOAD FLAGS(5);
|
||||
rodata PT_LOAD FLAGS(4);
|
||||
data PT_LOAD FLAGS(6);
|
||||
dynamic PT_DYNAMIC FLAGS(4);
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@@ -12,5 +13,12 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
.text : ALIGN(4K) { *(.text*) } :text
|
||||
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
|
||||
.data : ALIGN(4K) { *(.data*) *(COMMON) *(.bss*) } :data
|
||||
.data : ALIGN(4K) {
|
||||
*(.data*)
|
||||
*(.data.rel.ro*)
|
||||
*(COMMON)
|
||||
*(.bss*)
|
||||
} :data
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
|
||||
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
|
||||
}
|
||||
|
||||
+80
-29
@@ -1,11 +1,11 @@
|
||||
/* Deshab ping — 终端风格 ICMP Echo 工具 stub
|
||||
* 命令行输入 IP 地址,发送 ICMP Echo Request。
|
||||
* 当前为 stub,提示需要 TCP/IP 栈支持。
|
||||
/* Deshab ping — 终端风格 ICMP Echo 工具
|
||||
* 命令行输入 IP 地址,发送 ICMP Echo Request(net_stack.h 共享协议栈)。
|
||||
* Esc 键退出返回 DSK。
|
||||
*/
|
||||
|
||||
#include "../../firstInit/ascii_bitmaps.c"
|
||||
#include "../desktop_app.h"
|
||||
#include "../net_stack.h"
|
||||
|
||||
/* ---- 终端参数 ---- */
|
||||
#define TERM_COLS 120
|
||||
@@ -137,32 +137,84 @@ static int is_valid_ip(const char *s) {
|
||||
return dots == 3;
|
||||
}
|
||||
|
||||
/* ---- Ping 模拟 ---- */
|
||||
static void do_ping(const char *ip) {
|
||||
/* ---- Ping 实现(net_stack.h) ---- */
|
||||
static int g_ns_status = 0; /* 0=未尝试, 1=就绪, <0=失败 */
|
||||
|
||||
static int ping_net_ready(void) {
|
||||
if (g_ns_status == 1) return 1;
|
||||
if (g_ns_status < 0) return 0;
|
||||
int rc = ns_init((u64)g_ac.kernel_api);
|
||||
g_ns_status = (rc == 0) ? 1 : -1;
|
||||
if (rc != 0) {
|
||||
term_puts_color(" [错误] 网络初始化失败,无可用网卡或 net API\n", DA_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void do_ping(const char *ip_str) {
|
||||
u32 ip;
|
||||
if (ns_parse_ip(ip_str, &ip) != 0) {
|
||||
term_puts_color(" [错误] 无法解析 IP\n", DA_ERROR);
|
||||
return;
|
||||
}
|
||||
if (!ping_net_ready()) return;
|
||||
|
||||
char ipstr[24];
|
||||
ns_fmt_ip(ip, ipstr);
|
||||
term_puts_color("PING ", DA_PROMPT_COLOR);
|
||||
term_puts_color(ip, DA_ACCENT_LIGHT);
|
||||
term_puts_color(" 56(84) bytes of data.\n", DA_TEXT_DIM);
|
||||
term_puts_color(ipstr, DA_ACCENT_LIGHT);
|
||||
term_puts_color(" 32 data bytes\n", DA_TEXT_DIM);
|
||||
|
||||
/* stub: 检查 kernel_api 是否有 net 接口 */
|
||||
if (!g_ac.kernel_api) {
|
||||
term_puts_color(" [错误] 无内核 API\n", DA_ERROR);
|
||||
return;
|
||||
int sent = 0, recv = 0;
|
||||
u32 sum = 0, min = 0xFFFFFFFFu, max = 0;
|
||||
for (u16 seq = 1; seq <= 4; seq++) {
|
||||
u32 rtt = 0; u8 ttl = 0;
|
||||
int rc = ns_ping(ip, seq, 2000, &rtt, &ttl);
|
||||
sent++;
|
||||
if (rc == 0) {
|
||||
recv++;
|
||||
sum += rtt;
|
||||
if (rtt < min) min = rtt;
|
||||
if (rtt > max) max = rtt;
|
||||
term_puts("reply from ");
|
||||
term_puts(ipstr);
|
||||
term_puts(": bytes=32 time=");
|
||||
char nb[12]; ns_u32_dec(nb, rtt);
|
||||
term_puts(nb);
|
||||
term_puts("ms TTL=");
|
||||
ns_u32_dec(nb, ttl);
|
||||
term_puts(nb);
|
||||
term_putc('\n');
|
||||
} else if (rc == -1) {
|
||||
term_puts_color("ARP 解析失败,目标不可达\n", DA_ERROR);
|
||||
break;
|
||||
} else {
|
||||
term_puts_color("request timed out\n", DA_TEXT_DIM);
|
||||
}
|
||||
redraw_all();
|
||||
}
|
||||
u64 net_api = *(u64 *)((u64)g_ac.kernel_api + 0xC0);
|
||||
if (!net_api) {
|
||||
term_puts_color(" [错误] 需要 TCP/IP 栈支持\n", DA_ERROR);
|
||||
term_puts_color(" 当前内核未实现 ICMP 协议栈。\n", DA_WARNING);
|
||||
term_puts_color(" 请等待后续版本更新。\n", DA_TEXT_DIM);
|
||||
term_putc('\n');
|
||||
term_puts_color("--- ", DA_TEXT_DIM);
|
||||
term_puts_color(ip, DA_TEXT_DIM);
|
||||
term_puts_color(" ping statistics ---\n", DA_TEXT_DIM);
|
||||
term_puts_color(" 0 packets transmitted, 0 received, 100% packet loss\n", DA_ERROR);
|
||||
return;
|
||||
char nb[12];
|
||||
ns_u32_dec(nb, (u32)sent);
|
||||
term_puts_color("--- ", DA_TEXT_DIM);
|
||||
term_puts_color(ipstr, DA_TEXT_DIM);
|
||||
term_puts_color(" ping statistics ---\n ", DA_TEXT_DIM);
|
||||
term_puts(nb);
|
||||
term_puts(" transmitted, ");
|
||||
ns_u32_dec(nb, (u32)recv);
|
||||
term_puts(nb);
|
||||
term_puts(" received, ");
|
||||
u32 loss = sent ? (u32)(sent - recv) * 100 / (u32)sent : 100;
|
||||
ns_u32_dec(nb, loss);
|
||||
term_puts(nb);
|
||||
term_puts("% loss");
|
||||
if (recv > 0) {
|
||||
term_puts(", min/avg/max = ");
|
||||
ns_u32_dec(nb, min); term_puts(nb); term_puts("/");
|
||||
ns_u32_dec(nb, sum / (u32)recv); term_puts(nb); term_puts("/");
|
||||
ns_u32_dec(nb, max); term_puts(nb); term_puts(" ms");
|
||||
}
|
||||
|
||||
/* 如果有 net API,此处应实现真正的 ICMP Echo */
|
||||
term_puts_color(" [stub] 网络功能尚未实现\n", DA_WARNING);
|
||||
term_putc('\n');
|
||||
}
|
||||
|
||||
/* ---- 内置命令 ---- */
|
||||
@@ -183,8 +235,8 @@ static void cmd_help(void) {
|
||||
static void cmd_clear(void) { term_clear(); }
|
||||
|
||||
static void cmd_version(void) {
|
||||
term_puts_color("Deshab ping v0.1 (stub)\n", DA_SUCCESS);
|
||||
term_puts_color(" ICMP Echo 功能需要 TCP/IP 栈支持\n", DA_TEXT_DIM);
|
||||
term_puts_color("Deshab ping v1.0\n", DA_SUCCESS);
|
||||
term_puts_color(" ICMP Echo via net_stack (e1000 + slirp)\n", DA_TEXT_DIM);
|
||||
}
|
||||
|
||||
static void execute_command(const char *cmd) {
|
||||
@@ -246,10 +298,9 @@ void dsk_entry(const da_boot_context *ctx) {
|
||||
term_clear();
|
||||
|
||||
/* 启动 banner */
|
||||
term_puts_color("=== Deshab ping v0.1 (stub) ===\n", DA_ACCENT);
|
||||
term_puts_color("=== Deshab ping v1.0 ===\n", DA_ACCENT);
|
||||
term_puts_color("ICMP Echo 请求工具\n", DA_SUCCESS);
|
||||
term_puts_color("输入 IP 地址发送 ping | 输入 'help' 查看帮助 | Esc 退出\n", DA_TEXT_DIM);
|
||||
term_puts_color("注意: 当前需要 TCP/IP 栈支持\n", DA_WARNING);
|
||||
term_putc('\n');
|
||||
|
||||
redraw_all();
|
||||
|
||||
Reference in New Issue
Block a user