diff --git a/asm/lumbda b/asm/lumbda index 002d589..8fccc7c 100755 Binary files a/asm/lumbda and b/asm/lumbda differ diff --git a/asm/lumbda-gc b/asm/lumbda-gc index 8bdd070..5214f87 100755 Binary files a/asm/lumbda-gc and b/asm/lumbda-gc differ diff --git a/asm/lumbda-gc.o b/asm/lumbda-gc.o index 94f7516..16533c0 100644 Binary files a/asm/lumbda-gc.o and b/asm/lumbda-gc.o differ diff --git a/asm/lumbda.o b/asm/lumbda.o index 38fc272..0089363 100644 Binary files a/asm/lumbda.o and b/asm/lumbda.o differ diff --git a/asm/lumbda.s b/asm/lumbda.s index 777d306..e873157 100644 --- a/asm/lumbda.s +++ b/asm/lumbda.s @@ -35,6 +35,7 @@ .equ SYS_LISTEN,50 .equ SYS_SETSOCKOPT,54 .equ SYS_EXIT, 60 +.equ SYS_SENDFILE, 40 .equ SYS_CLOCK_GETTIME, 228 .equ CLOCK_REALTIME, 0 @@ -192,15 +193,16 @@ .equ BI_HS_HAS, 105 .equ BI_HS_SIZE, 106 .equ BI_HS_LIST, 107 +.equ BI_TCPSENDFILE, 108 .ifdef GC_NAIVE -.equ BI_GC_COLLECT, 108 -.equ BI_GC_STATS, 109 -.equ BI_WITH_ARENA, 110 -.equ BI_ARENA_STATS, 111 -.equ BI_ARENA_SET_MODE, 112 -.equ BI_COUNT, 113 +.equ BI_GC_COLLECT, 109 +.equ BI_GC_STATS, 110 +.equ BI_WITH_ARENA, 111 +.equ BI_ARENA_STATS, 112 +.equ BI_ARENA_SET_MODE, 113 +.equ BI_COUNT, 114 .else -.equ BI_COUNT, 108 +.equ BI_COUNT, 109 .endif # ============================================================ @@ -312,6 +314,7 @@ bn_tcpconnect: .byte 11; .ascii "tcp-connect" bn_tcprecv: .byte 8; .ascii "tcp-recv" bn_tcpsend: .byte 8; .ascii "tcp-send" bn_tcpclose: .byte 9; .ascii "tcp-close" +bn_tcpsendfile: .byte 12; .ascii "tcp-sendfile" bn_heapsnap: .byte 13; .ascii "heap-snapshot" bn_heaprest: .byte 12; .ascii "heap-restore" bn_curtime: .byte 15; .ascii "current-time-ms" @@ -384,6 +387,7 @@ bi_names: .quad bn_htmake, bn_htp, bn_htset, bn_htref, bn_htrefd, bn_htdel .quad bn_htexists, bn_htsize, bn_htkeys, bn_htvals, bn_htalist .quad bn_hsmake, bn_hsp, bn_hsadd, bn_hshas, bn_hssize, bn_hslist + .quad bn_tcpsendfile .ifdef GC_NAIVE .quad bn_gccollect, bn_gcstats, bn_witharena, bn_arenastats, bn_arenamode .endif @@ -3427,6 +3431,8 @@ eval_list: je bi_hash_set_size cmpq $BI_HS_LIST, %rax je bi_hash_set_to_list + cmpq $BI_TCPSENDFILE, %rax + je bi_tcp_sendfile .ifdef GC_NAIVE cmpq $BI_GC_COLLECT, %rax je bi_gc_collect_user @@ -6996,6 +7002,101 @@ bi_tcp_send: movq $VAL_FALSE, %rax RET_VAL +# bi_tcp_sendfile: (tcp-sendfile socket "path") → int bytes sent or #f +# Zero-copy file-to-socket via the Linux sendfile(2) syscall — the +# kernel streams bytes from the file's page cache directly into +# the socket buffer without ever touching userspace. Opens the +# file, sizes it via lseek, loops sendfile until drained, closes. +bi_tcp_sendfile: + GETARG %rdi # socket + call decode_port + testq %rax, %rax + js .tsf_fail + movq %rax, %rbx # socket fd + + GETARG %rdi # path (tagged string) + andq $-8, %rdi + movq (%rdi), %rcx # string length + leaq 8(%rdi), %rdi # bytes + + # Null-terminate the filename on a 256-byte stack slot. + subq $256, %rsp + movq %rsp, %rsi + pushq %rcx +.tsf_cp: + testq %rcx, %rcx + jz .tsf_cp_done + movb (%rdi), %al + movb %al, (%rsi) + incq %rdi + incq %rsi + decq %rcx + jmp .tsf_cp +.tsf_cp_done: + movb $0, (%rsi) + popq %rcx + + # Open file read-only. + movq $SYS_OPEN, %rax + movq %rsp, %rdi + movq $O_RDONLY, %rsi + xorq %rdx, %rdx + syscall + addq $256, %rsp + testq %rax, %rax + js .tsf_fail + movq %rax, %r12 # file fd + + # Size via lseek(fd, 0, SEEK_END). + movq $SYS_LSEEK, %rax + movq %r12, %rdi + xorq %rsi, %rsi + movq $SEEK_END, %rdx + syscall + testq %rax, %rax + js .tsf_close_fail + movq %rax, %rbp # total size + + # Rewind file position. + movq $SYS_LSEEK, %rax + movq %r12, %rdi + xorq %rsi, %rsi + movq $SEEK_SET, %rdx + syscall + + # Loop: sendfile until %rcx (remaining) is 0. + movq %rbp, %rcx +.tsf_loop: + testq %rcx, %rcx + jz .tsf_ok + movq $SYS_SENDFILE, %rax + movq %rbx, %rdi # out_fd = socket + movq %r12, %rsi # in_fd = file + xorq %rdx, %rdx # offset = NULL — use file's current pos + movq %rcx, %r10 # count = remaining + syscall + testq %rax, %rax + js .tsf_close_fail # kernel error + jz .tsf_ok # EOF before count satisfied + subq %rax, %rcx + jmp .tsf_loop + +.tsf_ok: + movq $SYS_CLOSE, %rax + movq %r12, %rdi + syscall + movq %rbp, %rdi # total bytes sent + call make_int + RET_VAL + +.tsf_close_fail: + movq $SYS_CLOSE, %rax + movq %r12, %rdi + syscall +.tsf_fail: + movq $VAL_FALSE, %rax + RET_VAL + # ============================================================ # list_reverse: %rdi = list -> %rax = reversed list # ============================================================ diff --git a/examples/http-static-server-adaptive.lsp b/examples/http-static-server-adaptive.lsp new file mode 100644 index 0000000..0c4a50a --- /dev/null +++ b/examples/http-static-server-adaptive.lsp @@ -0,0 +1,298 @@ +;;; http-static-server-adaptive.lsp — static server that learns which +;;; paths matter. A hit counter per URL is updated on every request and +;;; periodically flushed to disk (*hits-path*, newline-delimited +;;; "url count" records). At startup, if hit data exists from a prior +;;; run, the top *cache-max* URLs are preloaded; otherwise we fall +;;; back to *seed-paths* (a minimal cold-start set). +;;; +;;; This is the "~95% of the win" version of predictive preloading +;;; for small deployments (<=1000 resources). The DAG-of-hot-paths +;;; variant for larger fleets is future work — see whitepaper §Future. +;;; +;;; Assets above *inline-threshold* bytes are cached as +;;; headers-only + fs-path and streamed via tcp-sendfile, same as +;;; http-static-server-sendfile.lsp. + +(define *port* 8080) +(define *docroot* "www") +(define *hits-path* "www.hits") +(define *cache-max* 100) +(define *max-requests* 1000000) +(define *inline-threshold* 16384) +(define *hits-save-every* 500) + +(define *crlf* "\r\n") +(define *crlf-crlf* "\r\n\r\n") + +;;; Seed paths used on first boot (no hit history yet). Anything +;;; requested afterwards gets learned and promoted across restarts. +(define *seed-paths* + (list "/" + "/404.html")) + +;;; ── helpers ───────────────────────────────────────────────── + +(define SPACE 32) +(define NEWLINE 10) +(define ZERO 48) +(define NINE 57) + +(define (char-at s i) (char->integer (string-ref s i))) + +(define (ends-with? s suffix) + (let ((ns (string-length s)) (nf (string-length suffix))) + (if (< ns nf) #f + (string=? suffix (substring s (- ns nf) ns))))) + +(define (mime-of path) + (cond + ((ends-with? path ".html") "text/html; charset=utf-8") + ((ends-with? path ".css") "text/css; charset=utf-8") + ((ends-with? path ".pdf") "application/pdf") + ((ends-with? path ".txt") "text/plain; charset=utf-8") + ((ends-with? path ".js") "application/javascript") + ((ends-with? path ".svg") "image/svg+xml") + ((ends-with? path ".png") "image/png") + ((ends-with? path ".jpg") "image/jpeg") + ((ends-with? path ".ico") "image/x-icon") + (else "application/octet-stream"))) + +(define (url-to-fs url-path) + (cond + ((string=? url-path "/") (string-append *docroot* "/index.html")) + (else (string-append *docroot* url-path)))) + +(define (inline-response status ctype body) + (string-append + "HTTP/1.0 " status *crlf* + "Content-Type: " ctype *crlf* + "Content-Length: " (number->string (string-length body)) *crlf* + "Connection: close" *crlf-crlf* + body)) + +(define (headers-only status ctype nbytes) + (string-append + "HTTP/1.0 " status *crlf* + "Content-Type: " ctype *crlf* + "Content-Length: " (number->string nbytes) *crlf* + "Connection: close" *crlf-crlf*)) + +;;; ── hit-counter persistence ───────────────────────────────── + +(define *hits* (make-hash-table)) + +(define (bump-hit! path) + (let ((n (hash-table-ref/default *hits* path 0))) + (hash-table-set! *hits* path (+ n 1)))) + +;;; Serialize *hits* to "url count\n" lines and write atomically. +(define (hits-save) + (let loop ((keys (hash-table-keys *hits*)) (acc "")) + (cond + ((null? keys) (write-file *hits-path* acc)) + (else + (let ((k (car keys))) + (loop (cdr keys) + (string-append acc k " " + (number->string + (hash-table-ref/default *hits* k 0)) + "\n"))))))) + +;;; Parse "url count\n" records into a list of (url . count) pairs. +;;; Defensive — skips malformed lines so a corrupt hits file never +;;; takes the server down. +(define (parse-int-token s i len) + (let loop ((j i) (n 0)) + (cond + ((= j len) (cons n j)) + ((and (>= (char-at s j) ZERO) (<= (char-at s j) NINE)) + (loop (+ j 1) (+ (* n 10) (- (char-at s j) ZERO)))) + (else (cons n j))))) + +(define (parse-line s start end) + ;; end is the index of '\n' (or the length). Split on first space. + (let loop ((i start)) + (cond + ((>= i end) #f) + ((= (char-at s i) SPACE) + (let ((pr (parse-int-token s (+ i 1) end))) + (cons (substring s start i) (car pr)))) + (else (loop (+ i 1)))))) + +(define (hits-parse s) + (let ((n (string-length s))) + (let loop ((i 0) (acc '())) + (cond + ((>= i n) (reverse acc)) + (else + (let find-nl ((j i)) + (cond + ((or (= j n) (= (char-at s j) NEWLINE)) + (let ((rec (parse-line s i j))) + (loop (+ j 1) (if rec (cons rec acc) acc)))) + (else (find-nl (+ j 1)))))))))) + +(define (hits-load) + (let ((s (file->string *hits-path*))) + (if s (hits-parse s) '()))) + +;;; Insertion sort by cdr descending. N is cache-max, so O(N²) is fine. +(define (insert-desc x xs) + (cond + ((null? xs) (list x)) + ((>= (cdr x) (cdr (car xs))) (cons x xs)) + (else (cons (car xs) (insert-desc x (cdr xs)))))) + +(define (sort-desc pairs) + (let loop ((in pairs) (out '())) + (cond + ((null? in) out) + (else (loop (cdr in) (insert-desc (car in) out)))))) + +(define (take n xs) + (cond + ((or (= n 0) (null? xs)) '()) + (else (cons (car xs) (take (- n 1) (cdr xs)))))) + +;;; ── cache (headers + either body or fs-path) ──────────────── + +(define *cache-inline* (make-hash-table)) +(define *cache-sendfile* (make-hash-table)) + +(define (cache-count) + (+ (hash-table-size *cache-inline*) + (hash-table-size *cache-sendfile*))) + +(define (cache-add! url-path) + (if (>= (cache-count) *cache-max*) + 'capped + (let ((fs-path (url-to-fs url-path))) + (let ((body (file->string fs-path))) + (cond + ((not body) 'missing) + ((<= (string-length body) *inline-threshold*) + (hash-table-set! *cache-inline* url-path + (inline-response "200 OK" (mime-of fs-path) body)) + 'inline) + (else + (hash-table-set! *cache-sendfile* url-path + (cons (headers-only "200 OK" (mime-of fs-path) + (string-length body)) + fs-path)) + 'sendfile)))))) + +(define (preload-all paths) + (cond + ((null? paths) 'done) + (else (cache-add! (car paths)) (preload-all (cdr paths))))) + +(define (preload-top-n ranked n) + ;; ranked is ((url . count) ...), preload URLs only. + (let loop ((xs ranked) (left n)) + (cond + ((or (null? xs) (= left 0)) 'done) + (else + (cache-add! (car (car xs))) + (loop (cdr xs) (- left 1)))))) + +;;; ── startup: load hits, rank, preload ─────────────────────── + +(define *resp-404* + (let ((body (file->string (string-append *docroot* "/404.html")))) + (if body + (inline-response "404 Not Found" "text/html; charset=utf-8" body) + (inline-response "404 Not Found" "text/plain" "not found\n")))) + +(define *boot-hits* (hits-load)) +(cond + ((null? *boot-hits*) + (display "adaptive: cold start — preloading seed paths") (newline) + (preload-all *seed-paths*)) + (else + (display "adaptive: loaded ") (display (length *boot-hits*)) + (display " hit records, preloading top ") (display *cache-max*) + (newline) + (preload-top-n (sort-desc *boot-hits*) *cache-max*) + ;; Re-seed the in-memory counter from disk so learned ranks + ;; don't reset each boot. + (let loop ((xs *boot-hits*)) + (cond + ((null? xs) 'done) + (else + (hash-table-set! *hits* (car (car xs)) (cdr (car xs))) + (loop (cdr xs))))))) + +;;; ── per-request ───────────────────────────────────────────── + +(define (second-token s) + (let ((len (string-length s))) + (let loop1 ((i 0)) + (cond + ((= i len) "/") + ((= (char-at s i) SPACE) + (let loop2 ((j (+ i 1))) + (cond + ((= j len) (substring s (+ i 1) len)) + ((= (char-at s j) SPACE) (substring s (+ i 1) j)) + (else (loop2 (+ j 1)))))) + (else (loop1 (+ i 1))))))) + +(define (serve client req) + (let ((path (second-token req))) + (bump-hit! path) + (let ((inline (hash-table-ref/default *cache-inline* path #f))) + (if inline + (tcp-send client inline) + (let ((sf (hash-table-ref/default *cache-sendfile* path #f))) + (if sf + (begin + (tcp-send client (car sf)) + (tcp-sendfile client (cdr sf))) + ;; Cold path: try to warm the cache for next hit, + ;; then serve via the new entry. Caps at *cache-max*. + (let ((tag (cache-add! path))) + (cond + ((equal? tag 'inline) + (tcp-send client + (hash-table-ref/default *cache-inline* path *resp-404*))) + ((equal? tag 'sendfile) + (let ((sf2 (hash-table-ref/default *cache-sendfile* path #f))) + (tcp-send client (car sf2)) + (tcp-sendfile client (cdr sf2)))) + (else + (tcp-send client *resp-404*)))))))))) + +;;; ── main loop ─────────────────────────────────────────────── +;;; +;;; This server mutates persistent state on every request +;;; (hit-counter bump, cold-path cache promotion), so the +;;; arena-pattern heap-restore used by the other servers would +;;; corrupt the hits table and cache. We run under lumbda-gc +;;; and rely on mark-sweep to reclaim per-request transients. + +(define server (tcp-listen *port*)) + +(define (server-loop n) + (if (>= n *max-requests*) + (begin + (display "request cap reached, exiting\n") + (hits-save) + (tcp-close server)) + (begin + (let ((client (tcp-accept server))) + (let ((req (tcp-recv client 4096))) + (if (and req (> (string-length req) 0)) + (serve client req) + #f)) + (tcp-close client)) + (if (and (> n 0) (= (remainder n *hits-save-every*) 0)) + (hits-save) + #f) + (server-loop (+ n 1))))) + +(display "lumbda-www adaptive on :") (display *port*) +(display " serving ") (display *docroot*) +(display " (") (display (cache-count)) (display "/") (display *cache-max*) +(display " cached, hits=") (display *hits-path*) (display ")") +(newline) +(server-loop 0) diff --git a/examples/http-static-server-sendfile.lsp b/examples/http-static-server-sendfile.lsp new file mode 100644 index 0000000..47e276e --- /dev/null +++ b/examples/http-static-server-sendfile.lsp @@ -0,0 +1,193 @@ +;;; http-static-server-sendfile.lsp — hybrid in-memory + sendfile(2) +;;; static server for lumbda.com. Small assets (HTML/CSS/txt) are +;;; cached whole as pre-built HTTP responses and flushed in one +;;; tcp-send. Large assets (PDFs, images) cache only the headers; +;;; the body is streamed from disk via sendfile(2), a zero-copy +;;; kernel->socket path that never enters the lumbda heap. +;;; +;;; Why the split: +;;; - For small bodies (<= *inline-threshold*), one tcp-send beats +;;; the syscall split (headers + sendfile). +;;; - For large bodies, kernel-side DMA + no userspace bounce +;;; dominates any string copy we could do in-process. +;;; +;;; Configuration: +;;; *docroot* filesystem root +;;; *preload-paths* URL paths to prepare at startup +;;; *inline-threshold* bytes; <= inline, > sendfile +;;; +;;; Target tier: asm-gc (has tcp-sendfile primitive). On tiers that +;;; lack tcp-sendfile (Python, C, bump-only asm) this file will +;;; error at load — it's a deployment example for asm-gc, not a +;;; portable reference. + +(define *port* 8080) +(define *docroot* "www") +(define *cache-max* 100) +(define *max-requests* 1000000) +(define *inline-threshold* 16384) + +(define *crlf* "\r\n") +(define *crlf-crlf* "\r\n\r\n") + +;;; ── MIME ──────────────────────────────────────────────────── + +(define (ends-with? s suffix) + (let ((ns (string-length s)) (nf (string-length suffix))) + (if (< ns nf) #f + (string=? suffix (substring s (- ns nf) ns))))) + +(define (mime-of path) + (cond + ((ends-with? path ".html") "text/html; charset=utf-8") + ((ends-with? path ".css") "text/css; charset=utf-8") + ((ends-with? path ".pdf") "application/pdf") + ((ends-with? path ".txt") "text/plain; charset=utf-8") + ((ends-with? path ".js") "application/javascript") + ((ends-with? path ".svg") "image/svg+xml") + ((ends-with? path ".png") "image/png") + ((ends-with? path ".jpg") "image/jpeg") + ((ends-with? path ".ico") "image/x-icon") + (else "application/octet-stream"))) + +;;; ── Response builders ─────────────────────────────────────── + +(define (inline-response status ctype body) + (string-append + "HTTP/1.0 " status *crlf* + "Content-Type: " ctype *crlf* + "Content-Length: " (number->string (string-length body)) *crlf* + "Connection: close" *crlf-crlf* + body)) + +(define (headers-only status ctype nbytes) + (string-append + "HTTP/1.0 " status *crlf* + "Content-Type: " ctype *crlf* + "Content-Length: " (number->string nbytes) *crlf* + "Connection: close" *crlf-crlf*)) + +(define (url-to-fs url-path) + (cond + ((string=? url-path "/") (string-append *docroot* "/index.html")) + (else (string-append *docroot* url-path)))) + +;;; ── Cache ─────────────────────────────────────────────────── +;;; +;;; Two tables keyed by URL path: +;;; *cache-inline* url -> full HTTP response (string) +;;; *cache-sendfile* url -> (headers . fs-path) pair +;;; +;;; Per-request handler hits one or the other, never both. + +(define *cache-inline* (make-hash-table)) +(define *cache-sendfile* (make-hash-table)) + +(define (cache-count) + (+ (hash-table-size *cache-inline*) + (hash-table-size *cache-sendfile*))) + +(define (cache-add! url-path) + (if (>= (cache-count) *cache-max*) + (begin + (display "cache-add!: skipped (cap reached): ") + (display url-path) (newline) + 'capped) + (let ((fs-path (url-to-fs url-path))) + (let ((body (file->string fs-path))) + (cond + ((not body) + (display "cache-add!: missing file: ") + (display fs-path) (newline) + 'missing) + ((<= (string-length body) *inline-threshold*) + (hash-table-set! *cache-inline* url-path + (inline-response "200 OK" (mime-of fs-path) body)) + 'inline) + (else + (hash-table-set! *cache-sendfile* url-path + (cons (headers-only "200 OK" (mime-of fs-path) + (string-length body)) + fs-path)) + 'sendfile)))))) + +(define *preload-paths* + (list "/" + "/style.css" + "/whitepaper.pdf" + "/robots.txt" + "/404.html")) + +(define *resp-404* + (let ((body (file->string (string-append *docroot* "/404.html")))) + (if body + (inline-response "404 Not Found" "text/html; charset=utf-8" body) + (inline-response "404 Not Found" "text/plain" "not found\n")))) + +(define (preload-all paths) + (cond + ((null? paths) 'done) + (else + (cache-add! (car paths)) + (preload-all (cdr paths))))) + +(preload-all *preload-paths*) + +;;; ── Request parsing ───────────────────────────────────────── + +(define SPACE 32) +(define (char-at s i) (char->integer (string-ref s i))) + +(define (second-token s) + (let ((len (string-length s))) + (let loop1 ((i 0)) + (cond + ((= i len) "/") + ((= (char-at s i) SPACE) + (let loop2 ((j (+ i 1))) + (cond + ((= j len) (substring s (+ i 1) len)) + ((= (char-at s j) SPACE) (substring s (+ i 1) j)) + (else (loop2 (+ j 1)))))) + (else (loop1 (+ i 1))))))) + +;;; ── Per-request dispatch ──────────────────────────────────── + +(define (serve client req) + (let ((path (second-token req))) + (let ((inline (hash-table-ref/default *cache-inline* path #f))) + (if inline + (tcp-send client inline) + (let ((sf (hash-table-ref/default *cache-sendfile* path #f))) + (if sf + (begin + (tcp-send client (car sf)) + (tcp-sendfile client (cdr sf))) + (tcp-send client *resp-404*))))))) + +;;; ── Main loop ─────────────────────────────────────────────── + +(define server (tcp-listen *port*)) + +(define (server-loop n snap) + (if (>= n *max-requests*) + (begin + (display "request cap reached, exiting\n") + (tcp-close server)) + (begin + (let ((client (tcp-accept server))) + (let ((req (tcp-recv client 4096))) + (if (and req (> (string-length req) 0)) + (serve client req) + #f)) + (tcp-close client)) + (heap-restore snap) + (server-loop (+ n 1) snap)))) + +(display "lumbda-www sendfile on :") (display *port*) +(display " serving ") (display *docroot*) +(display " (") (display (hash-table-size *cache-inline*)) +(display " inline, ") (display (hash-table-size *cache-sendfile*)) +(display " sendfile, cap ") (display *cache-max*) (display ")") +(newline) +(server-loop 0 (heap-snapshot)) diff --git a/tests/bench-www-race.sh b/tests/bench-www-race.sh index e313891..8e80531 100755 --- a/tests/bench-www-race.sh +++ b/tests/bench-www-race.sh @@ -1,8 +1,10 @@ #!/bin/bash -# bench-www-race.sh — asm-gc lumbda-www vs caddy file-server on the -# same lumbda.com docroot. Small-request (index.html) and large- -# request (2.67 MB PDF) workloads, identical concurrency, adjacent -# runs. Reports req/s, MiB/s, and peak RSS for each server. +# bench-www-race.sh — asm-gc lumbda-www (uncached + cached + sendfile) +# vs caddy file-server on the same lumbda.com docroot. Small-request +# (index.html) and large-request (2.56 MiB whitepaper PDF) workloads, +# identical concurrency, adjacent runs. Reports req/s, MiB/s, and +# peak RSS for each server. The PDF size is pulled from the file on +# disk so a whitepaper rebuild does not desync the MiB/s calculation. set -u cd "$(dirname "$0")/.." @@ -11,8 +13,12 @@ LARGE_N=${LARGE_N:-200} CONCURRENCY=${CONCURRENCY:-8} LUMBDA_PORT=${LUMBDA_PORT:-8080} LUMBDA_CACHED_PORT=${LUMBDA_CACHED_PORT:-8082} +LUMBDA_SENDFILE_PORT=${LUMBDA_SENDFILE_PORT:-8083} CADDY_PORT=${CADDY_PORT:-8081} CADDY_BIN=${CADDY_BIN:-/home/fox/git/make_post_sell/caddy} +PDF_PATH="whitepaper/lumbda-whitepaper.pdf" +PDF_BYTES=$(wc -c < "$PDF_PATH") +PDF_MIB=$(python3 -c "print(f'{$PDF_BYTES / (1024*1024):.2f}')") declare -a SPAWNED=() cleanup() { @@ -26,8 +32,8 @@ trap cleanup EXIT INT TERM make -s -C asm all printf "\n═══════════════════════════════════════════════════════\n" -printf "asm-gc lumbda-www (uncached + cached) vs caddy\n" -printf " %s small (/), %s large (/whitepaper.pdf 2.67 MiB)\n" "$SMALL_N" "$LARGE_N" +printf "asm-gc lumbda-www (uncached + cached + sendfile) vs caddy\n" +printf " %s small (/), %s large (/whitepaper.pdf %s MiB)\n" "$SMALL_N" "$LARGE_N" "$PDF_MIB" printf " concurrency %s\n" "$CONCURRENCY" printf "═══════════════════════════════════════════════════════\n" @@ -46,36 +52,48 @@ sed "s|(define \*port\* 8080)|(define *port* $LUMBDA_CACHED_PORT)|" \ LUMBDA_CACHED_PID=$! SPAWNED+=("$LUMBDA_CACHED_PID") -# 3. caddy file-server +# 3. lumbda-www sendfile (small assets inline-cached, big files streamed +# via SYS_SENDFILE — zero-copy kernel->socket). Port patched to avoid +# collisions with the other two lumbda servers. +sed "s|(define \*port\* 8080)|(define *port* $LUMBDA_SENDFILE_PORT)|" \ + examples/http-static-server-sendfile.lsp \ + | ./asm/lumbda-gc >/dev/null 2>&1 & +LUMBDA_SENDFILE_PID=$! +SPAWNED+=("$LUMBDA_SENDFILE_PID") + +# 4. caddy file-server "$CADDY_BIN" file-server --root www --listen ":$CADDY_PORT" >/dev/null 2>&1 & CADDY_PID=$! SPAWNED+=("$CADDY_PID") -# Wait for all three to be ready. +# Wait for all four to be ready. for _ in $(seq 1 40); do a=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$LUMBDA_PORT/" 2>/dev/null || echo 0) b=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$LUMBDA_CACHED_PORT/" 2>/dev/null || echo 0) + d=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$LUMBDA_SENDFILE_PORT/" 2>/dev/null || echo 0) c=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$CADDY_PORT/" 2>/dev/null || echo 0) - [ "$a" = "200" ] && [ "$b" = "200" ] && [ "$c" = "200" ] && break + [ "$a" = "200" ] && [ "$b" = "200" ] && [ "$d" = "200" ] && [ "$c" = "200" ] && break sleep 0.1 done -kill -0 "$LUMBDA_PID" 2>/dev/null || { echo "lumbda-www (uncached) failed to start"; exit 1; } -kill -0 "$LUMBDA_CACHED_PID" 2>/dev/null || { echo "lumbda-www (cached) failed to start"; exit 1; } -kill -0 "$CADDY_PID" 2>/dev/null || { echo "caddy failed to start"; exit 1; } +kill -0 "$LUMBDA_PID" 2>/dev/null || { echo "lumbda-www (uncached) failed to start"; exit 1; } +kill -0 "$LUMBDA_CACHED_PID" 2>/dev/null || { echo "lumbda-www (cached) failed to start"; exit 1; } +kill -0 "$LUMBDA_SENDFILE_PID" 2>/dev/null || { echo "lumbda-www (sendfile) failed to start"; exit 1; } +kill -0 "$CADDY_PID" 2>/dev/null || { echo "caddy failed to start"; exit 1; } # ── Byte-integrity checks ── -curl -s "http://localhost:$LUMBDA_PORT/whitepaper.pdf" -o /tmp/a-lumbda.pdf -curl -s "http://localhost:$LUMBDA_CACHED_PORT/whitepaper.pdf" -o /tmp/a-cached.pdf -curl -s "http://localhost:$CADDY_PORT/whitepaper.pdf" -o /tmp/a-caddy.pdf -for f in /tmp/a-lumbda.pdf /tmp/a-cached.pdf /tmp/a-caddy.pdf; do +curl -s "http://localhost:$LUMBDA_PORT/whitepaper.pdf" -o /tmp/a-lumbda.pdf +curl -s "http://localhost:$LUMBDA_CACHED_PORT/whitepaper.pdf" -o /tmp/a-cached.pdf +curl -s "http://localhost:$LUMBDA_SENDFILE_PORT/whitepaper.pdf" -o /tmp/a-sendfile.pdf +curl -s "http://localhost:$CADDY_PORT/whitepaper.pdf" -o /tmp/a-caddy.pdf +for f in /tmp/a-lumbda.pdf /tmp/a-cached.pdf /tmp/a-sendfile.pdf /tmp/a-caddy.pdf; do label=$(basename "$f" .pdf | sed 's/^a-//') if cmp "$f" whitepaper/lumbda-whitepaper.pdf >/dev/null 2>&1; then - printf " pdf-integrity (%-7s): byte-identical\n" "$label" + printf " pdf-integrity (%-8s): byte-identical\n" "$label" else - printf " pdf-integrity (%-7s): DIFFERS\n" "$label" + printf " pdf-integrity (%-8s): DIFFERS\n" "$label" fi done -rm -f /tmp/a-lumbda.pdf /tmp/a-cached.pdf /tmp/a-caddy.pdf +rm -f /tmp/a-lumbda.pdf /tmp/a-cached.pdf /tmp/a-sendfile.pdf /tmp/a-caddy.pdf # ── benchmark one (pid, port, label, N, path) ── bench_one() { @@ -100,7 +118,7 @@ print(f'{$n / max(t, 1e-6):.0f}') if [ "$path" = "/whitepaper.pdf" ]; then mibs=$(python3 -c " t = float('$t1') - float('$t0') -print(f'{$n * 2669058 / (1024*1024) / max(t, 1e-6):.0f}') +print(f'{$n * $PDF_BYTES / (1024*1024) / max(t, 1e-6):.0f}') ") printf " %-20s %6s req/s %4s MiB/s peak_rss_kb=%s\n" "$label" "$rps" "$mibs" "$peak" else @@ -110,15 +128,17 @@ print(f'{$n * 2669058 / (1024*1024) / max(t, 1e-6):.0f}') echo echo "── small (/) ──" -bench_one "$LUMBDA_PID" "$LUMBDA_PORT" "lumbda-www uncached" "$SMALL_N" "/" -bench_one "$LUMBDA_CACHED_PID" "$LUMBDA_CACHED_PORT" "lumbda-www cached" "$SMALL_N" "/" -bench_one "$CADDY_PID" "$CADDY_PORT" "caddy file-server" "$SMALL_N" "/" +bench_one "$LUMBDA_PID" "$LUMBDA_PORT" "lumbda-www uncached" "$SMALL_N" "/" +bench_one "$LUMBDA_CACHED_PID" "$LUMBDA_CACHED_PORT" "lumbda-www cached" "$SMALL_N" "/" +bench_one "$LUMBDA_SENDFILE_PID" "$LUMBDA_SENDFILE_PORT" "lumbda-www sendfile" "$SMALL_N" "/" +bench_one "$CADDY_PID" "$CADDY_PORT" "caddy file-server" "$SMALL_N" "/" echo -echo "── large (/whitepaper.pdf, 2.67 MiB) ──" -bench_one "$LUMBDA_PID" "$LUMBDA_PORT" "lumbda-www uncached" "$LARGE_N" "/whitepaper.pdf" -bench_one "$LUMBDA_CACHED_PID" "$LUMBDA_CACHED_PORT" "lumbda-www cached" "$LARGE_N" "/whitepaper.pdf" -bench_one "$CADDY_PID" "$CADDY_PORT" "caddy file-server" "$LARGE_N" "/whitepaper.pdf" +echo "── large (/whitepaper.pdf, $PDF_MIB MiB) ──" +bench_one "$LUMBDA_PID" "$LUMBDA_PORT" "lumbda-www uncached" "$LARGE_N" "/whitepaper.pdf" +bench_one "$LUMBDA_CACHED_PID" "$LUMBDA_CACHED_PORT" "lumbda-www cached" "$LARGE_N" "/whitepaper.pdf" +bench_one "$LUMBDA_SENDFILE_PID" "$LUMBDA_SENDFILE_PORT" "lumbda-www sendfile" "$LARGE_N" "/whitepaper.pdf" +bench_one "$CADDY_PID" "$CADDY_PORT" "caddy file-server" "$LARGE_N" "/whitepaper.pdf" echo echo "── binary sizes (stripped) ──" @@ -128,5 +148,5 @@ printf " lumbda-gc %10s bytes\n" "$(du -b /tmp/lumbda-gc-s | cut -f1)" printf " caddy %10s bytes (Go, v2.5.1, already stripped)\n" "$(du -b "$CADDY_BIN" | cut -f1)" rm -f /tmp/lumbda-gc-s -kill -9 "$LUMBDA_PID" "$LUMBDA_CACHED_PID" "$CADDY_PID" 2>/dev/null -wait "$LUMBDA_PID" "$LUMBDA_CACHED_PID" "$CADDY_PID" 2>/dev/null || true +kill -9 "$LUMBDA_PID" "$LUMBDA_CACHED_PID" "$LUMBDA_SENDFILE_PID" "$CADDY_PID" 2>/dev/null +wait "$LUMBDA_PID" "$LUMBDA_CACHED_PID" "$LUMBDA_SENDFILE_PID" "$CADDY_PID" 2>/dev/null || true diff --git a/whitepaper/lumbda-whitepaper.pdf b/whitepaper/lumbda-whitepaper.pdf index 1314234..2b7261d 100644 --- a/whitepaper/lumbda-whitepaper.pdf +++ b/whitepaper/lumbda-whitepaper.pdf @@ -62,9 +62,9 @@ endobj endobj 11 0 obj << -/Annots [ 7 0 R 8 0 R 9 0 R ] /Contents 133 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Annots [ 7 0 R 8 0 R 9 0 R ] /Contents 135 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << -/FormXob.d3ecd28ca03f587d6940049748681018 3 0 R +/FormXob.c9411fecc114c344e33ac82182b38f43 3 0 R >> >> /Rotate 0 /Trans << @@ -74,7 +74,7 @@ endobj endobj 12 0 obj << -/Contents 134 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 136 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -97,7 +97,7 @@ endobj endobj 15 0 obj << -/Contents 135 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 137 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.a2c922509fa3b1785bcd08461c0457b3 13 0 R >> @@ -109,7 +109,7 @@ endobj endobj 16 0 obj << -/Contents 136 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 138 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -119,7 +119,7 @@ endobj endobj 17 0 obj << -/Contents 137 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 139 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -129,7 +129,7 @@ endobj endobj 18 0 obj << -/Contents 138 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 140 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -139,7 +139,7 @@ endobj endobj 19 0 obj << -/Contents 139 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 141 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -149,7 +149,7 @@ endobj endobj 20 0 obj << -/Contents 140 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 142 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -191,7 +191,7 @@ Gb"0;!=8`+$j31%en endobj 25 0 obj << -/Contents 141 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 143 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.6378944cfcd9d967b8dea9d1fdf81282 21 0 R /FormXob.914f0cd152b732307eb1a2bfb0d863fa 23 0 R >> @@ -203,7 +203,7 @@ endobj endobj 26 0 obj << -/Contents 142 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 144 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -229,7 +229,7 @@ Gb"-V$![tprs/%kVg[G]8def./P7Hpb+:.UemqF`fg8QAVF'*,<$Kl#'U!md[DeE%MedO?I4&91M?!Bo endobj 29 0 obj << -/Contents 143 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 145 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.ac4d2a97676ca8c002b2001987b87b9d 28 0 R /FormXob.ddff3fe796cb06f610a0e90e16a0db7d 27 0 R >> @@ -246,7 +246,7 @@ endobj endobj 31 0 obj << -/Contents 144 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 146 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -261,7 +261,7 @@ endobj endobj 33 0 obj << -/Contents 145 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 147 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -271,7 +271,7 @@ endobj endobj 34 0 obj << -/Contents 146 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 148 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -281,7 +281,7 @@ endobj endobj 35 0 obj << -/Contents 147 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 149 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -296,7 +296,7 @@ endobj endobj 37 0 obj << -/Contents 148 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 150 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -306,7 +306,7 @@ endobj endobj 38 0 obj << -/Contents 149 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 151 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -316,7 +316,7 @@ endobj endobj 39 0 obj << -/Contents 150 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 152 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -326,7 +326,7 @@ endobj endobj 40 0 obj << -/Contents 151 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 153 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -336,7 +336,7 @@ endobj endobj 41 0 obj << -/Contents 152 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 154 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -346,7 +346,7 @@ endobj endobj 42 0 obj << -/Contents 153 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 155 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -363,7 +363,7 @@ endobj endobj 44 0 obj << -/Annots [ 43 0 R ] /Contents 154 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Annots [ 43 0 R ] /Contents 156 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -397,7 +397,7 @@ Gb"-VGBahP*ld_dH@X@.673m]5Z!>/OUajVKd+rl%FU.GOCIDSUkBirLgj0l#UggK9*dsQ$&!I6Uj!Oc endobj 48 0 obj << -/Contents 155 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 157 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << /FormXob.02a72be19fedaa76bd1061921e7cc82b 47 0 R /FormXob.baaa2211732baa0f94f6912a5b035550 45 0 R >> @@ -409,7 +409,7 @@ endobj endobj 49 0 obj << -/Contents 156 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 158 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -419,7 +419,7 @@ endobj endobj 50 0 obj << -/Contents 157 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 159 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -437,7 +437,7 @@ Gb",k#?V^BhM4rA',+)6h&$gSeal+> @@ -449,7 +449,7 @@ endobj endobj 53 0 obj << -/Contents 159 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 161 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -459,31 +459,7 @@ endobj endobj 54 0 obj << -/A << -/S /URI /Type /Action /URI (https://undefect.com/moad-cheat-sheet/) ->> /Border [ 0 0 0 ] /Rect [ 505.5536 444.2236 538.0932 456.2236 ] /Subtype /Link /Type /Annot ->> -endobj -55 0 obj -<< -/A << -/S /URI /Type /Action /URI (https://undefect.com/moad-cheat-sheet/) ->> /Border [ 0 0 0 ] /Rect [ 57.02362 432.2236 115.9985 444.2236 ] /Subtype /Link /Type /Annot ->> -endobj -56 0 obj -<< -/Annots [ 54 0 R 55 0 R ] /Contents 160 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << -/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] ->> /Rotate 0 - /Trans << - ->> /Type /Page ->> -endobj -57 0 obj -<< -/Contents 161 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/Contents 162 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -491,23 +467,57 @@ endobj /Type /Page >> endobj -58 0 obj +55 0 obj << /A << -/S /URI /Type /Action /URI (mailto:russell@unturf) ->> /Border [ 0 0 0 ] /Rect [ 134.8436 216.6236 202.0657 228.6236 ] /Subtype /Link /Type /Annot +/S /URI /Type /Action /URI (https://undefect.com/moad-cheat-sheet/) +>> /Border [ 0 0 0 ] /Rect [ 505.5536 533.8236 538.0932 545.8236 ] /Subtype /Link /Type /Annot +>> +endobj +56 0 obj +<< +/A << +/S /URI /Type /Action /URI (https://undefect.com/moad-cheat-sheet/) +>> /Border [ 0 0 0 ] /Rect [ 57.02362 521.8236 115.9985 533.8236 ] /Subtype /Link /Type /Annot +>> +endobj +57 0 obj +<< +/Annots [ 55 0 R 56 0 R ] /Contents 163 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 + /Trans << + +>> /Type /Page +>> +endobj +58 0 obj +<< +/Contents 164 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page >> endobj 59 0 obj << /A << -/S /URI /Type /Action /URI (https://undefect.com/public/stress-on-our-shared-heart/) ->> /Border [ 0 0 0 ] /Rect [ 247.8136 216.6236 385.3838 228.6236 ] /Subtype /Link /Type /Annot +/S /URI /Type /Action /URI (mailto:russell@unturf) +>> /Border [ 0 0 0 ] /Rect [ 134.8436 176.6236 202.0657 188.6236 ] /Subtype /Link /Type /Annot >> endobj 60 0 obj << -/Annots [ 58 0 R 59 0 R ] /Contents 162 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/A << +/S /URI /Type /Action /URI (https://undefect.com/public/stress-on-our-shared-heart/) +>> /Border [ 0 0 0 ] /Rect [ 247.8136 176.6236 385.3838 188.6236 ] /Subtype /Link /Type /Annot +>> +endobj +61 0 obj +<< +/Annots [ 59 0 R 60 0 R ] /Contents 165 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -515,23 +525,23 @@ endobj >> /Type /Page >> endobj -61 0 obj -<< -/A << -/S /URI /Type /Action /URI (https://undefect.com/public/stress-on-our-shared-heart/) ->> /Border [ 0 0 0 ] /Rect [ 293.562 363.0236 417.502 375.0236 ] /Subtype /Link /Type /Annot ->> -endobj 62 0 obj << /A << -/S /URI /Type /Action /URI (mailto:russell@unturf) ->> /Border [ 0 0 0 ] /Rect [ 423.062 363.0236 487.672 375.0236 ] /Subtype /Link /Type /Annot +/S /URI /Type /Action /URI (https://undefect.com/public/stress-on-our-shared-heart/) +>> /Border [ 0 0 0 ] /Rect [ 293.562 321.0236 417.502 333.0236 ] /Subtype /Link /Type /Annot >> endobj 63 0 obj << -/Annots [ 61 0 R 62 0 R ] /Contents 163 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << +/A << +/S /URI /Type /Action /URI (mailto:russell@unturf) +>> /Border [ 0 0 0 ] /Rect [ 423.062 321.0236 487.672 333.0236 ] /Subtype /Link /Type /Annot +>> +endobj +64 0 obj +<< +/Annots [ 62 0 R 63 0 R ] /Contents 166 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << @@ -539,15 +549,15 @@ endobj >> /Type /Page >> endobj -64 0 obj +65 0 obj << -/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 523 /Length 58769 /SMask 65 0 R +/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 523 /Length 58769 /SMask 66 0 R /Subtype /Image /Type /XObject /Width 535 >> stream Gb"-6G?bhRd.iTHHKKV;S9*7;?q-4+'=2>sQuc%9W4VOEt5+"MMd4I@K6]a#T+0$[iX^XpGYnBb\U(!cg3:0pQ,3AlqHU,Y3N0mqXMIRQ%XgD\@B&qcqo4As7>F"n(kU"eZ)VJVG-7+Y@$VHXm=Q?>IJA$]Qs*\aH.Qjo&Os2nAfY8dcJQ4UN#2/jiWjh?+]f;J,Rok6O.7:kHSO;cCI%@h7@_M*Zc\(S@F%HH=1.=X&lK6@q4QZj"4PT!s8W-"*K"fo]c2Ck8,dXgot5)^juTga]Q&l@?W$4/A#5MP9NGQp?gVH]"6b3HhYF5&!h*%!s8XX?O3$ADr8:BCtZ,J[;/um2;gj1CtW&u>cqGK%Vh6)>M$YU'>Aqo)B0V7*Zc@:']eH?GPUgk'.6P"H[C*aGdtAtDr/-Pe##k/?T0pQSND%AH$LDjEoc#dF7<'%qtiU+q@m7pM2;6b*ood`=2hs%q>C'[c'pY)cCC:M:EE/)q:a8i5m-nfi,c5HP8b@cnEnu>[r:0\\T>g?drX6MBhhDu>(!X[$Pmi+FRKQ.?5JFi'VX)6V"eZ;o;q]N7pRPejbdMdLrQL4kX"!t[2rsie\ace)":7PFtFD8pI2(;J$CtlDc\om=(joirJdVWK%0qLLQZ=(M#e>ZBQ&#u^6ZT:'*$lqBNfs519p[5_6iPOE_GCtO#6#LuBmbNX/+$`+e84W_$q>3t+`=W"M5J^#'c[_Mf$IQnT+62A?U8+J.,9oQB6D19MDM-AcqXeJ5^"0Ao5CND#^4#l:CtLFCY$C>T#9_:cn)%?L0+877H2[U4JHH/VrV'YOK3ULLGON7qs8LBl:upq#8;,IiG4p4`"ac[qm-Da>"MP>98k0,RR\-sq6oB4Gd/mXnl9,?g]e:R>Zfb6P:O<-"0M?]T%\T-fXSU'hhj4i$Q!^-TL#JNSV@Oj12514))GmKRl>9%Jd!8X_LLaoSNCoT9G\M3OX!BildlYhS0gt!<2rnHB?m"uRECe*c'gMo+Bl?^%9U/^k>(3cSQ5?3ZY%I*m+Ck#l-lhC^KS5Dgk^cB!0%qt7bA!E:7\\4OUZaS*^+i![;/iD+)1<,aZFV.!!:KcM\i!KHPRD6a*tDirVLg6j<:M,YcrY.J90o!\[f8e9%:M!F%3PC(,)%N\?qNPDL`_@B@!0.))Dp!El!>2=0,L)KA!]_%18b>5d>([]!^3LWDf]iE,`%XbA33(J[r@3j2Q`oC"94`=05Y;WI%EtM2ZA^eZ)&?C_J6rVHgZP-*0r>(Z%ClDr/-p4aT(q\&(8%0j7]'7oujl].eLCQR$O%1NJ@K&e-s1M2TLYHJZN6I8u3USE6bI$QEm?FOfX_Dqk":n[rl6rmD7K9n5u%NIHiU_Cq9.HB[WBpe)^q"Z(<]m@(aV+Sl^G5hDb9:+-NM#`b&S2kZ7I\bGi9mcNrOYmuY&G#5C[hg](m,#FfA]pB-CPeV=EH`H]#c[YWQQ)2Ys"+3fshU\l;n*f_K`NA`9[r,3K>Zmcbg9bQ-)&^OZ?\;^C1M=u]J"aQ&pV(_3Nih1VLBRi^^nj\jOr3.ZXB>#ZfsA+nA_SLV,_X,4W-\.%+A:JKXh$/m^4)7.d+HsDD-,!C5Kp?dYJ,L#k>Za97e-Vs@`'$)+')Dl-a]_U-\>N,Tb$t\>0H[#8Si>+"KR'!%;:J6t(!s]l1H8I`HS:--I'YM,m's]>jXOtFG%iKFCpncWWICm@Pg:MQI;R1t?"-ued.*Z(;?F"*5P$C\_MN8iD/m,?nm*n(Anmmg_oI1EshE?5Z`61ukI!I-?YHKVFkJF>`pmq6P)d:RNuW3#OP,95nih`JPDl7M3_u^V]Pm&.fE"Vb\DrY8Fu;_hj$^,UOjaG^,UH7AiqR*ZZ9':Q]*rA#E(mC:6YuL("qhNZEkp>^gHU&YN'.PNUk42M>[:VY6-5'NUYiY*CICPn9.hoRqtp8+V\DBJ]Y2!WUe%3KM&ed-=JOZ$*C<+\c(5EPDVb0.M\l5Sa6]dV/TUOLT(Jr#h=2%j%fU[Alia.],VH]Y%?=Y"W;6,-2IcJ.p'H0nH'E]9q+&kX&kA[?!%OnFj^Y)!ORA^m\s*\\o[%pG.At&J5V(IX[s&bCppf5%0qc2k=):4+jA%0)'DJar.o5ESeH[06u;=%-,1Z&$fIrCI?_`q"!OigpqJT?;I%K/^3;5IWG>ZmJd(]PJ";@h)^_mr9qE#Z=hKY;(?-(9q'#Qd0:k$\8\-\iPH:,)//4@Y3K&k?>XjYoA.$&,kngNSBdZeC[)B87('=3bKApqmbBhiZF2cr?b`c!=YO=<062Zk72PXC;@FEu"PL20p?\3ajtf?Pc3r`*QA^`VS9dY>R$$)X]i-\1jqhODr+18;t)fj-.nq\$bci=[`.RaYJnN633[StE_7)_(8ep(d"IuRH^[sH5(*-U*(C=cX&mWncVJE<`5KT=H@!HV,?Z(N,8(%(8oEFo5n`f^%*W"u4d9;0aG^$_InB>>N!.LZkPYP_VeFJPauq_6rd7$k3$_,^OsNcZCP@VmXG&m!E&I+8X]oOIe.Y0F%fp:cEokG8-C?5\-:2,oM.(Q8lb\>`*4&Re,0GVfV+Z%#gpqn4qLo:n:6mH!g#o\ScOO+YI&+rP0*a3QVVg=i?r]Bp*^"[DU-o;225jnj?m&r0_*A/q.>pC(i*PF%RlIC1!\(ijG*fZ>63QkFb@dXfmO%o7Uc$b9\[!m`Nf_Be5iW5\@B&qF]Lgq!_aDNao6&+^G&S82"Em2r57,')^[BN`WF;P2fHX&_WLoi%[n*]jjgD5NugHqH1Ro;9Z4uloCAjjl0R-3MgHl,OH:%#%`Ahpi#?>!jR`!U]4)snb$OZP6g9MC[l]+&M8Q^=&ECD$?In:1dRNZL>5q;R\l>Nfh"2'aP>EbsC45q^j>Vb^5=CI4]:GkE(u4onmZ'"q(/#po#4u0V>D7"$qrfFEGIMR5&3+.W7`uM;eGP4*9\ZXLnc@"K8Gq%Y3D(??$s=Wt6COZD;=8I/*3)If9*MD6(WT]Pugr%7\26_;!_6Ha0[[O^aRJCXf96Ea_/'M`/EB$FMeC=P4Zg;&625C^E$fmjWkZV*#smbEptH-Md8/1FdZ0UrjF'Js^_R-qUYR?oR6C,6"l+!=C"0=KC4h]o`GO>mW)s1mGX-Si;Nuj^PKpgWMh4<.UF^ST"Q_\"Ca2Q#OKn[>moB".3ad_5#GOO*lhC)6q"CpC*/>ZeB@nbYbH2d`P6@6R7eL9i8XA/W)?UV54c&@I`'M*P;03,$:V9AN^K&"/D=0E[3A5->lB$;)rG=(&rGAf'F%miu_J]Po'3Nr>/VG6)JF__#4O?uV.gUE5F7UNoZNK0#/%M"6^!i.9.(l0_.pO2i+JQLf[&YP1sc^l`AT";lr2F,?O1T.`-G4+/-Qlpd/p$:3oF660EE'4$no4PVERM#8GNhDLX)ho]:9UWboqA/8Q_hSS9W7LtWM#Er0I>Wi:#RC]d+hDsjk(sa![VXX&@)7FuFKmS>"Yg%c3]oP&eu`0Rp[;IpABBoV6iQoET8F@6k0BMZD;)@KnSkL-WNp*Y#,6I>7ZD`floBLjFE_s'$PtDu"U0HdDRKJscCR0Lf9dU#*gSG7Y7#fGc/7F9dY4tZ,^3VK0cP^qKXeNOPGpbJbREk&>8CcjKHeE=p[6kFkXl1I>NaF&+KE7eFR%@)OO"Z%2:YU#8p3cVk6CII(PBnDT"iQS"[j+&P!&!VMj)PjQ_b2mqj;$=$kBWLF'UWN`T\QrHS8)C;;:C;I[brp/_/#&B*6:(e0P&jW*14*I]G_.Lu_WD@dJ'L9mL";i_HoE;O>_0]0uD!\cXn"QSPiP4m^n/(j]YCk#IrVC6uD.^kNTi%RS,=ddL\8gQne#+9MGjsk?)n";'TVcbqLlL,(77Kbh[937qjXF_M(aN7jB%[/8-gI$`+c'pX&7&,nk99P7@N#=E0DVTL7q!k"RgqS?2:-FBk%I'hgf[qTSYTQUXe#,th3BMt6=`.Tik3e9q#A)2N=gBZfC=OMMZ\+q,j\tQ:3QK1\qtTrF*^*]%P&nRX_#Y>#!s]=k\T8#,46St%q$m=4')=eZI.lopYHP.=[l8][X]r88Fnf(35_4\$+)9+:T*Jh`OZpK_.M7Ip'k,MF^rqbq6IRF*aE-?CgHM"-c"(mb_A,RRUC5+AX^+@CX:S'\jcj@8bE_DraFX1a2Df8G73WnLpNV]JmkK_je!9sjDMR(E(30*Bp_3$Pj<-#D,hR'6UH_\[#ei"ttR7T0.C>*==f=bSZN&_4$i>9,>V`TN0Z+7jeKM)C/Jb)Du8+4(#j#rHQ0+aTdQ9[r:/91b$bB4aZ)#IGN`8Tt=[HI][E0.G1YSLPJ72*Zc@I7uf-+\hpUVd>72E\$Pkf1=1Rk2f:&9@-u[Up[$Q8UQ/(XJ3aR3/-sI^Oc_pq6(n)p4Eti4g9iV%rr)TKE]Y,LOWm4$:jKS;:'gjYW`H7EZ$:p;Ts+mIq1.#:VN`;J4@kdN7#;Q+:>K?5jOaiLb*FX&V:JL@;/=aaTe"$!^\u`e?bcR:pBLp.F.$<"OFp?ed\TTXkKX7%Kl;lH1O/Cs5H?Oe<"il$ZU"q51sXrX<-khV[;=PD[pJfLHaHhZqkE8U_D;`f0h=M/luT0@Z/cV;>7D;%qp.a#ise#,3,ZZYTbK_`J70:.J1^-Que(HEdiqXi:V#&+=Q$,mMMpl^2ZJR,m2cqDHb/Lqf)-BgD]m=hlj@T-:jUU*'U/%7?YdQ`Cps@_iAdo#+ET2Xpdln-n_o!Z%?P#nrK_P.I-3;Zril-h>-;BZXmD6o31#nrpLKFa7'T[1ga^)W5dNP#Fc'gMlo93--`r`5p3a%/Mp$Ao!b?ql)9s(/DWDf_Ta,fPjX/nQQ6:+dVfS'\LQ7cIsW`?+,C")WfbVEbPo^:NS6r;jk[a%`bTGI;lcC[&W<4jeC)8HhS!q/,1@r$NPJ^olOV#GcN=P6R0o\m]Q./8#k09AY4[%ci"&0lE0[Of)a(0DM?srq$77G$\g9P9_m64)Tfs51)hnK&H'e?Fl\H3tRVD]8FH@:0g@%<]i*2(f6tsNRXq+PCIeeEoj<(ZY"t&*Cc)2%I10QLW>f=BDh]*JqJ\!foI4>>3_<.O,q%tkn<")(^CBi'GR?$nV.JlOuEsZW\f,qJ#@J@A?:K0!B%\1?:r%B5!+rU:KCI4&;LNKhaWSDJbj9jk6A[866+=tT0L)?s'E2k%`H<(`5T]DqXb*VB:/=-`N0,5%N;f9X="MAk,P4R\S7QP[gSqAHNNu-!;('R^rV&"d?/90_e_Q?;6UF]Qs*N:4EZ\%'0]$Jp_ups8Mn6Khn:&r!c=ES>NIhLYBEU8`*m_C=TWbingG#&%l;($5I"a`HU\$_7e)fZt\!DYSd-&h(rif!P83CIJ]1^bA.1^",)btOQ"*4.nh9e;,JV'/76,]mlWL@c5a67fsGH,T$H-%F4I`,2rmZ*?bLbSSYhI/:PB,jppN'^M48;-c"G:iV48%Z9'=KjZhQS!?soWbDr/-(E$\,NP!BAeB/1Bl:#3C'_pc/:jU,"gYS%`g-Wr*&Q31S]H'C,TiX!YCS`&F6jit06=gQPe@5KYlY['R_6X^%YS.c)8(gtoFTTbQQhq>)LhnEiD.*EVr=QJauUjJ:3'.-O$Fn=`iEiUQKm-X2$*'$?kMn"9:Ic[@8*&q>>*sMqa/97ZLC!reS2Vdlnn^1`^qk)fNWb*Nu>N*hr2eR"FF\%8\aIYQ,g7sa6[r1a//V?m4Gk#(OFqH@4hnFM;p:._RiBfRA`!-DM8I:ah7Z80-3D1>UHs#egR-NkZS#=4nQR,9?gB'@^A&"YF_0GcI--;ELP@e]Fm9Z)P@Vq,Q$aSa\97*Qqil?lfJ/Q%!WrPpG<9p15h,j&i'EB$VG'SET9d0U`)$U!OR&moV+[kH\SPY]?m$T&Z]QJ&NjuSYnjJ(^KA!0@,tjO8Agb-gp"t9!;)NkA,_Ib&0MdfF-uSCR,Y"of&NMfI?+Y8;Hm]gL(f2H&``fBA.Iu3o>jf&<<(<5qBE@AHVak&hP9pb5O?eYZM&A*]6o+&_\MIN+&J5WAXX$BdOh.'0s!^mDcrJ-%^qdb(K*MqVl,D&tOjM;Ma,_=qVo0cJMNAWVdT4rTh4:tTUcEDP!1jS+jV!nS58+niA0B2:3[edpXEYr4Q7\l4Mh-G1!J7*Jm>)?!8D`IinlM)i4`oma49^V896,QsK;ZJ3q/Ya'4Zkj:[$!]!RPi3nQ4,fa(h+@")"9uBaiTi#>=dW41,4Br9O:mo?\f[Br(>91/C)S^Nuu]EPm"[BmnT8=U.("0f*rb=^q`2C:7aS):H5SgR!hi[nl@>WD,re_4n1qM3+i*bodcX)TgOT;d]?Z^/pe8"Qp,pZ8Z%Ygdu8>Z!s8YmOM!ee2?ZVMqXrMh7^Z8mhnOXo>duJNaOI1f)/B2dm,#Dp8N'A94H+/og"T$@eu`0$jp8YT^Y#AU(RA5AY`k01&/uPr,1F5PpF]^\i9fq!k2s*eeZ&c\(qi9c2"=m3;gW7^JNB@4mHS05an`l3qc_E,bjb/'#r+45&@YN3`CILCP>dkNC*Za'K,U8RTYH^OAh<&6]BIK$=g9bSYWa)Gs*@.Ug[r0S>,mHSG@RMB^0HLM*5_0!lYO`]`R!SGjR5/=Z$WEil&L[sZ1C?eFk09B(_hKUAUh%T1M\[o8p%=#1K<@9)Z,FW#JYE/S14B"@aZrK),=[W:rqneNqBg'P`K4\r$uXA0I25(".H+#E4*Bha2N^k37NmUn\o`e34=8@F4j0[5"9oAXXDD5)k2qE212"lP`[VgmJ9dXFpb,RC9V>O=9#tZoW/Aon5Ms,!'1?iWZ*]#\IOeYqTS418?E?uig9k]<5(#=J2HGakiSt7P$JN"0A#2e_'[#q>hgbP#qeK&ZUrp8kl]=#h4JIgoN!,-'Due)O`ufeu]osX1UIL6)e5TR5iZ>m5VbYJb0nL%_fH=XHmFnD,S`DAOKoI_fEaZW;]6CH!#?@p3H2$a_(3cbhKD*-6#GXeM2ERX@KV(JYhQismF8GNCL!kRY&0;mq>@HH*3dUF3_hJW^b#>35*U:FZ^DcV;++DV$[D.0XN)g=IN@"C6bZYdHHCIO$@p\,V3fT6`Y\7qA.t_M26t$euY9E#sgLqs8K^.aqc!<]kPrmABC!+QE>H(k/"mMQ7A@5J`#]REo`&;PH_R,\@@cjI=($\A)!<3rVQ?4oh1Q"e(n=HDG29_SX0)f<-].QooZbgqS>Gcb^5+(`3P4LLcgd]Y#e$3i`IGWMCN\p>X&L$H&,?[F66hlpqJ:?AN$m7UDmK@/f`Y99+HQ8:6m4i1BkGK4c)"ppl##ks$7\QS.+UbEjed5^GVBqW-r,W\E_&I8b(fh`s*)@`8[)fC**uX&5Vr??/kB6:4*l>rq9TR;'!>c)U\(W"KGIPn4QM_I='"TgX_MAm^,JMI]?BkCf1Y)NZ[``b3VhO_7t5H?CJ:8P&)CZZ_q>0r&OXY/J@q+)p@4WRK/-6N1cC?n>?!rpS/gj8sI/.f&6\30bp(dM@="Qdp%OEbOmP!1.*"Y5;'WCrj3JqfuFC_JS$1]SNKaJP]hDLhE;#h%XGAN_TpUY?G5:6/CD8@-mE!M%N?B8Xum4!DUm!,@cHbMJD[N_iLE-kag`eN9Q+[iG=JCjk/C=Pr8@2RWfG!10D:mIRgr2q,!K_HI+c"lRlV:=W,AU4(?Tk#g,*rRU*EJ*I$G=rNI'eW?V5(%ABC"rji`uA.7Zis8daiKa,V1>'n7`%nrs8f91tVp]"l"t/)*r!rql.rVFu!/[F9X\M56g&9a,_raV)#g5'FrgR`LdHS([/t,@EMBR0I\VH[ADos1s'*MA5o`h.b[ftDb,\T?q[H$S5WFXnX[K%Ejd<)ci!>.#XIV7t]EgWu?k[;$GC@LI_+o^(6e.&X,Hl\#QX3d:#Yi8@Ga[K-m@ROAbG?=E_ki>P=PNrb?gKb]tHR=PtdWggJYCl;<4"<,h2(/S6m2:YLpX\*tSt`.m?XE]LGQ*FQm1Efs,$W:f%]rW'6#K`fDY?k7Ys$]_FL^%n2+aZ&6]6E^A'Ft^E/#i!04*M0[N85uP_1MuOV3S(2Xm''t&JeG$Jn6LK:N\?,(iZi]KXq!X(C'm->!5L-R*#G3p4(i>i2QRl>7\Pq&%WX_$\^ljTL?7DU7;0OY$GIf&j+PK$TIFq,KO+Dr&WRCQqSRZ)YeI8#Tq,ACqK`%5;WV>`j)`gE3H"UiK7K"Jah0k1E7iI;G?Y?m3t[Y'27hb+;!F'cCtjfcGui\_cZJ6CLYgKX(;V/Vs0FmE(^(R=shR]'2b''Ot$mN4afkh39iY6IiNJ,]AdNZI.8gWu?J%nRb,F^lHfJN6I1]b5gLrKK<8Q7UN3*'AJM3%9&qGPi=TX2WESZAL#dDF968)N$'9jNK%5YIQakh^m@ut:8t6$W)3^*'Tc#Rn%\mg%,A'ub8,te/R#MPd[E3L/oKjtS_:;[A#hO7]6bEa`*IF7$4iT+F@/4IgP2,tYgJ0Z@`%FabF3qNV6*3m(P97mEX`.g;m:H_h4ZY'g/#[+]Y-'Dl\NZF,N&Q%#sD1[PL=)`a`aGCQXW/LEDm9:hnj8n'7!\[^KcCI%U'fQ0Q)4j"tB#nK5l0m-U!3$TLiTACSF6WF\O:Z&;B3tP>"/(d=+-_:4%Utf1;LeZ<(FTkLm+Le%"c='I.U9E9I)h0`_^/#H;PZk"G\n#D7heX[IM%[dIs`mT2bm0W@j!QQ28g@Og[T;9V*"8D537SbSD-NK%N9WMWCZ1):B\i,a$`2>r3?bYkr+8\scHZPfes:p41g,ion"Ag#D:+k;g>P[fUe/^!&p#4r^l(P42u.QIWUnj#aD:7[+L*L\0@$As$n$&Xb'^4603hRn-uEp!q?:P1rc"sHPeS%9n_O@WB-G7d]d=hrE^3T=ie'kX,[;'I6KuGZ!0i@M-W'p\(O!8ljI)TsVZpBjQNq&Hh60:#BN0ZUt'4XE4,g]uro]](7iHK!=1(s3So4MCH'!CEW%NZ'$TaJm:_k]2G%LilTP'\9Sd'$e@ndT,$.g9sHE>or?NaJPXVK1e@+B_!#aMl][+'2NF[WIgq`G;I0lB\0DXW=f..pKuu_G%4VEK0L>\DDuFBJKQ6;H\2M3kaUN1jp7sfA!QT4RR#lCfGQl"jTu;&PAJbc04%JN#.(A\?N&fLS%a2Q#o9q)niL[a/3&d*GYg^)!)+I4hW:AOJB=Y-qB\;I0I-cdI%.U??]4MDOfP4%Rro6Pb1HS394HGJkm\bAkYY63tPe#10B($!iN<_hJ^FU8/+JB66IBiE%<9EFHfR6Gf\=LrV=#[_[mE/9C/$47-WVd`;m2Ce-q=0M*]I_d7(ABu,0N9+;]P;@OWB^4S#7Z#a">nd2IWe^B-u)oa!61QhnGYpfL_-"T0SqBZ_-U(mY-+q?]%'i[>e)V`L'qKh_.u1W.or`*,mXn-n`.[3&)XQt^CEmXI`,VC3d:"nC3/=i]mE9W2/:Y9eLn0Q-e*Bo1)La^]6+HC4[&%eLWfa&[VQQTSh+#"n_Y&_NY"P@/;OkZG`fIQh*N0XgR1Xe,U=WX&qYZ/@PofIN\3^8Lu-/mFi:n;NpT8%cWT/(Bh**6;R/jhRk!l=ap)2RA6OP>^"E`)Rc@EK4,4=g-6I'naWn"\NG`\5Lpr<(!dr1F=&oKY=XIUM,P^NBn$'#U^-M%T)+g)CQ!@`92f:0q'#-bBJ:$,WB$['N2BCR?`NMki]QlN+^'f12H-'VVD;$iEH-j]<[;'9]W:4N=GCB,I;6CADKW870\:5%_fL@beNugGX'c5cH&-G6)H`&]6cp4]^*Fe,Gp[dSjpC'W!pJ7DFjiER:]kSlfV`$NUPD^51VCm%T"SZnK-RIY""!-+,F_d!XC?oETRT7d90+.d]!HQj63cmp`Q1O1bRk8C?e>^@'_r2!_g&Og^gdiidIf9,NABC"UlbC_o[FgMK8`9t-)d2"EXTQXUIM8,r'Eb<1M+_IYsX]Z^]4:[A7VKHMlg0j.QTVZU;($KHmtDQ>[AL:IRN0W8Fl]SF1I*a(85p=g4Vu`Y@#%6hM'?JBIRT[*'AIB>]Ie3&$IW3VUQ6jj)"r+brHOX'61[Y!Tb?F=Lr7c>p3G6'uq5mjmQod>7gr.LuNp`SqUYp3QGg(qE:^>`sf2]46[n)p^H9rnjKp'gW$99P<=FE,!S:ViLeWWNXX=U`KIR3V2qJ(+I(5PnV3cuomQ/KfM/(A_)'uY(L^k'WG+m1MOc;U&iC%1riB1Z/MqtKP,:Lr%X=^8Q,Q\EUWV1aMTI/3=V.5+r9OQ>4*(G7*MY>V2h:r9bakA&WP.S5gN%>cM8mLc9fPq#?bS8N_%]XY6SF)k)R&52o$29cb!:-^j_l@bO(h7\0%U%[9s@OR#Fma@qipu1r6gU!-teq($(=gM^b)lecHL5-!h:dq-KNHfRoIX[D7AP0g`I=-DV$9;\?PjdMEQRuEBbEbs0XI(7[+1Sl&o]aiXRb<"<03VUZ"of3+W'OGEaH;,#%KtHMK*<8%AAG@2F1GERM'unc/:;1CL6#bD9MQeiA]FIFG>eBq0kF^`]-V^&J=D$DU]-0DV[A=ZJda'rqPLanNR=S-BsXOTViQZPE'\Fb))bOjh'C3O??0i%OJk&Jt.r@:r@K8_k[75=gLRt$4=)Tn`.[ObV1Thb*=L%HMAIouIS?#2Sg8sD.;D7="CVX/.58?Pi>rQ48WtL\oZ*"7YNg7t=sZN9f_tiA1qIo"Y"Q[2i:Q9_B'Y.hf$Rc?ZZod)EpJ$p@1M;ToV_^g-f<:fWBfBn_`#`Sl$Wu0H<9bJg$-hak)No(ESK-h-RkCl8KP.7NA(NO]=FFgi-oMD0tJ,%WN/I*k?RN'JpYYJ#26J#B=;-VHcDiq$j&F$6fp=nE#Y\Lb:MTND\;as,/BKr>H"SRi8NXGUfjs37I^Hn-;^D.>,g=WNgs,4b[-o;l*$Z;aubbEjmAA.alDWpW:-1n?^P`Z(gmgU;dD(05+4P@WU#-K*314C[Z#=I.W0-jVCA7D0KqspG@`=3J/$'`;p"$[%OYl"a8%Ls:!oijOXhUU)U*L*d&e]6YlrdWJL(^g^4p_N%Lg+m]%F!o*-TjLr>U-L`:U=7sKJ[W(S9i-5&_3!QFtV?KYfn92K'\:>4iHMcM\[nsbA?:]R7tADqj&pi%NRV"m1BFT*6fB*ORu[D8'(i0qtho@8?k-KRPZa'2>m/rNugH_)p1c^*/=U=u5tS2+^KH(&3As3;;n!?i6rk(ucfkS1tbhTnRJ46jJtTF]0DX]OJj;/4nfl\EnYK6b.='P$ZC#cgBJrbuV&MY?o:S2BD()d@s(h]&<1mLPH,T(02CR"(+G-Q_#`0e^gj,3EFDCWDf^VN5geo,CUb0RP`N*[W:GfWHR[_7@4,^S6C#l!:?^>SuBceZ)X>lu9^)'P4_%jGlXMUB%MXfJ-3VX/dc.hFI!j:e,F/*$$'i!e:"7@FCrCH8Q3Hb!*KBn1/4]lV]BWk02hB8?SZQ!=d!rGe:r2(D.o,KrWW*ioB(0f^VQH(`8(lLqBfaH4amUJ,YCOG7j&o\MIY$n)(mH]U!6("iH*+k;rYT0;^os51E0_V(GcO*;mK6+'VC<<8YH?c^m9]Hc)^OO[?0#/\Ha-J1%q5WZ8m+)S$E7Rl>7TT&acsBj"hj`UKJ/h6@,M&RH0sPGjutfPEmk/St^Xp]9%2#DsE2Z8a_'7+XA<9dDFOuF"*(&@kcU==;rC68i?rH/5ZGK]o8J7iB@Zh#8[_5mc;/0/g*>AhGt+S9Rt?'<`[.e"1E%!P.(0<"6(.r3G^3=ONKIug;#D8-m=&mE9brPidW"/E.GCj5G3q.@+:H.:iLi54!=4fo:mqH[BXi<;TT+L%LsgZ!==?oTFY42F,Q!96r#=(NZ:X)Gq4.A$SiQpJAcuB$2X;YA%'O)L]mJmfK)<"2Jh"g0"eKP1US=;0k84"h`QL9*_C5Eo&\k\P5Fd5K3+QfKmao-:6C=bMesd,h7Hao26L<$:7/n`.p'6f^O]S@6VGUBoB&be8E^6e)LV>LJ`K8TYmJ&NJ)@M@LV@WC%8TbqZaE8=''pH%_,IbdO>Zk&,?X=0uij[foX&>dOpb,h.EP$;TN[^hQaaf`MZNPcb[M\=F0cP0:GDD>)6O#mG5Sb_O[VXrd/+6l`ig;#b(0.KGDr3au'#&_e%S?9=TgRghNZC3I0ae"E82N=P`*AajPiib>-s)>"g`[W%Htm"0Ai^*UL5OcGOJjKAE;q"T7m`NOH:%D@floDcuO[7&"oM`gt.45Kdf6F>?:OqqL8;5$&OITF(EFXam=n8)n4RTRo\>68`=*8kcn3l>[]92DQ87Y^KnEm@F%@B(+dD[/g5Z?p,2.@&iX.&l*L'0cqqi]kh!![@1"^dn45\H/;tH&`lH+iiM6RA'(PRm;PiA0*0c8;M\ED.FmG@1A%3ESJHH.kIJY@:B>irrhnQqZL;Ma_;j\lp$t;ifm-H;!(oWXS'3Z#>bhGZRA1,!]G(\e(nr<#VQ%nPP"2#&Y8(&MDffCimI/M,_XBbmeD5)+q\6fs>=PfnR?k+7:c,pi?6'BlRi5k,INjf>mer5/`@/5V;N25[R-Vp=idii_X_9RfH+68.]0!K3GZ3@+"\RB+9R!#G5h28j#HLtk[qLerA<*[AF/G/^U^\u1#<[>6q$+TqpBoCMp(+r!_fU"6uT"=bmRl86H4F6biNBCfoL;&K%@=m;1%";d-5SXA+%O>DbEH#?@@otZiJ=$[d5meiiQA._4\T.iV8.aTCKn&skBlJ#Fr:eU67m^/e:i5pngUD@ng'JE>^cI9AHEp]o*$!2ZGIVYQ#4`PQD)gp5mLU1TrVH3H?Wf^rRlGZ^+F?,BooN_Sl\F8$Lr@6M+:dT!!%CR2/3\Q\:7[h"G)sqmR57@=RcI3Gn3&o:EeY&EqWcT]p3uAZXd_:Q,RUG5"9o(-8Ws@Xi/&*pW"XjQki9^Ec_!GRY@a+SenG.XWhs3A!Y<)0-f`Im&ru9eD7fbpUDK/CH#9"a[Qa-9$$@"R%>G;I,;M]OTuFr5SbtY]Zi$b;3gPq(=f?b`^I\)+iI)\sQu2`Yk`!/d[gNkg/ErJ+I%o&Ro?-UqFS-p$kafe_a$`5]eD99r9Lb4tMe3OTY13HF0l(JI_pANUD=R,(]hY+Z8Nm?.kM'5B!9X+(rok/cNql;59L^jQA6>hoZ9?/R"Am01i3PM^.BlVGNsQjMhTkHM#RYD7S,k8J?Uber4-1*A3rIE9>E7LZe@*nRF0AqB9u2/Z).*.cU%9;#9%]H#r5u-(%[DhdSVH3L[VcEqAEfj=M,T"EpHWo&e1I/ruNB-GFiQ%`PY<;TOqC"8iaf/7D>(-oB+&ib,[N[0K"uZ(0A)$>Mcll/9QU'-J9B,11c>RVNS)t8OPKa[kVpZF[:u,ol(,68G+dAC+aBWhY)2E#D4X?'a#=9h<8O'ens__$$qi/K@?S55gWj9?d7oef'G_!+Em+)3W7pY$F,4+/-ci8#8hCo^Qm\btbQTaTr95n&[4i^ANacO:d@3]VeMqd\qaEcC[e-$pTX?QlP=PZa?fgbFc_Xqni-M6jY+!4^"s'*fB83rceTM_rr_YB4^ot"J]m<[YCE,H]ODjM3JOND/$n"iB`*WPec%<5.n_=&_*b/-s1]6>(k]j86nW_s%h&3:3K;D(/=j=i[Ia_be'\@>?n)(e-?6#s@UGAO"EKD1flCP!OAOXh0Z&Gq0ik!]h?"N!`s0&)0-M%L<'amC:`G3sV;aq`%k*DoHiqDL'$9M>jmcHDP-CRX:gA&h]k\X4'[;NR82j7`*3gUGeoL+L&Y=05X`_QDirV+R_eHcq^,3L1XLp^f'7#iJd\fNSm9mG#*g,N]6\AC$j<0OHId0?Fpjc_&Nc,I>1-0k/',\LN]Q_AG4L*1',."7qo)`ESH-2_qc27787V2HH)X$$qA@UHmc6p$:TBVG<\^BDI\LN?()]lPuVpFmIVT)smnkEo\@R3$s<;7(@=$%`_1YhnC,WK%t1'_C'jF%Y+qk(*e\9qsV:s?ZAkuF>r4@#RLgj]QnRP$5M(!J;GUIRZM/0-cV2c2+frsCW`>6[VXV`P/t+Nhg5"_8_m"%J7>[Db7X\=Jj9WUYs5E(T_i*/Gd18L<2^@bgYOf'f&6#BS2leV$'aLn<1#Vc;fH_rTr@jH(GFDK%tIQ.UqCm<>19[b-W8=%\E&PZ*?@l%#^5M#ddb41JYl/2Ed%Q_ji\GObS1C[(fLhgC>??;$h+1[a4Re?@#2rCn6"ki\h^MZ?+FuE/h.`jVl-H^(4M[6`/p5l\./J36\kuRMM_J;,Zh-RaA:j9NRP_(?.,:IDU*t*.i!0ecCLHcLfl@#GD-A=.%Gr8qiE-qHp>L5",-aZ":<_SQ3@X3W%Bn;^6s]q2N8V4$@.1!21bSpk>O=Vn`.[?Ad;6G@Wa#0n`%NHqDe-9Ue-aab+(J5jsNrrOa_J-DdLf-82a[Wq?#f!Qkqt@;%N/?W;P@(nCM5!%3`JPB\<7SQf_1Gi,8SjWsEofpT2+#sh@GF#%N/X"50lcR40bAdZGgP(VX6JInD%KG3jJEj@R]r`O[a:L!Q>R"4\%S;'Q8l6cg>:h7JFFk26WjkokMU%dPA19Lq\[ndGdme2\^l$#p6ge]lA+l-lPF[kH=7>GmR!Pq#d!h^&-r@"c>dOY^WFK`j]k+ggH`MXWC>>.&+1%L8P.,BqU,!O7'/Fs*2*=Kk']d[$'u4[TE.Uo?,:_;.(R#=.,T^]h,]VhZ?qtBF%-K=%E67A4P^0J6kBeE+GkJ=sfJC^T:G-1#*0GAIX$l4aTGo!>u4)&FnR)njpf5JVCL=^OA`)K(1,M4897a1q*906tB0I3WjTHO.er7%3oG-&Zb#;OJm2i$78rqs=t*^XCJ,k\E+#p>"bmlL$N94^#SK2hs>1OJh3=S7Of0+Q,gXJ,@]p+9LWm*_^+*m>;tDR@iYjFdg9`3G'3Sec0=2q=lEbstVEDnu@p0FIl:tFq7T_b)CQ5*'4=1^U%TKu#3^s5_P6X#,p>pf*"4X2qqXeJ*1PW&<]Ahffm`cKfT0L).-KTV\3aB49KeVE"^d)oNp7T3-\8[";5G`;,.9[MC.4TK!EHE;fX8$ec;I>Keg6i6LYgc%\Yg,K5W9OY[cP1jngKe?j2[54XWimiOfHQi04-p2AO,#aRJni<,KsYNWMqXr!XTiB+XSP57ZA>-PC3ErZ=M(/]WSI@JF>Kp#JSS\Zds!SC$&A_SjC]BQr]lBE\oK"Q?pTaVNp]`R06&ofirBPE";1K?oiYQo3hDtT7rW9$?25_,k<&@-303rL))3BK<<;&=eX7>hWn1;q)J"8!V$dT%<2j$Q6Y&3Sn8l%qMuBBT`PSTYI:^l0-e-qaBsVc7a'eh))ipSh)hNZ:'"m+AQq/hV5.c<\26]pG);Pq,p$l(G7F!F`0HeZ/!/8t.`@Ub.6W6aFb%4aV@?oIO,l9LRl>8S9a?@=ABC"6C?cBU7`_ElR$`\6YN]Qdn3\[/3\TF_f@0*h7u%h&5Bl9uq"ad_,1fpF5[k;W.GgTCK:,J7a>VIn`&UE4Z,HW/u8F(n$1`/P]p2K.F\X#V469-_^Fa&$O0OR/4/mVkA>dS1l_1N!3-Osm0m)&?JC!/O)'C%3\;n@#29!a@Q9X\`fXEleIH,*Fci]m<-(aD',#V(bEXHW*_T$M_STmF\g^QeCq3d)=!.[8j-#2cT?h(RTsSNElETkrDf8.*!<^Vq:]7OXn2_^bBEe#1:.a9N4s:k[?orr%2I?G/0F\Sfei[/aB1Y$QPQoT=JnX`5SZ#B,MFpA[Ap+'B(eU;r<:_g:;+km9qP4*N;:31.Rp#^IZ$3;,afq[dL6*#Uk`Yc8;SK&#a*=P9`TX/9)UPbAB&KR5AWPOVhL^qkX.OVA]lCoFcf3*LPV^k'f@^,qDZi*-:d%YjN5`J^:XSSQi[NC93$d\Vl%o"tO)&9X>";GLZW[Wb3P/C:[NZC4H=X-C0pY\=0[WGYO33mUIFC`K!\SF*Mp2"&8+9]E,4WQ-uEQ/1O5d;*#HM-Q@Fl19cN`E,fmFV:eg%Fm;rC_Lls(h6eTL,;q/lnq&$4h%UkaG3i+5./e3e;/e?c'oBtRL:g8e@KtW'>jMVP%k9GjZ>R=+LS=)a.S_:+h-D1*t`W`1D7-7hbMun('iu1Zb]e/N=8D?kY"^:Niku3cA.PPAP%.ZikIf9-&G;ZLk!`;flN3u[oKf9"fq#0sE8M"]Jdu\D!ZE](m]lE':?5O$!qb['H))LR+<(u4^W)-VKDM"7[paudZEH,tDf=O:1;b.&0?00[6SN=_faL?*Fmb+r0YJ:(2m\;!sNj'3_]Lm2TG=W"C!2F&DN$2%l&Drs<<)=(=DMYA3d%KRISNCoTbUHJf9UIMBo]X]?L(+4cYA`=4h7In"e>ZC$[Va8M_3!Ff@.s\R46KkXDOoKL5hOYa+ZU\=p&ecIKaJPObt_&AdsQ_d.9a*Wfa>0&eOhim9:%7[]WThccihR8TQF/4;M@b&a^&p1ADtCZ69;f+ojULJ)UK_=ZicC@=Yd>X#8-'^7?1rW;56Unl>Fj?SiiFSXmf'Lr;#rj-[Xjk$,"'RPS)_\#BQS\l-b05eG&FhX,9/1!V_"k4WuO9Yd_)#lN188!D`+?]d[hms7kj-'r3V%0$'/"8+l/t5u2K@Ee9JPq<+B[cQAfZWDY:6D8lLm/.rbRgriO'DV_a=h-u:#D^9V(S<^/k/if7$EilIr7o3.[m:iU9UY%nHM-R.UdIYD4F'K;UfkI9GOF5uAcpD^'HR@U=IcI((D1'/ZtUf9[riNN5#%S/'hPW!N>fI@5]T5Wcm91i'A+W3!EJG:PYVXfSD(AdbLHtgfiP@`OX'uH?`mYEOOn-jS4OOX)F"e?qq7#QnA)%ii@2alcOWU,`AB;#/Bj@(W`?*ue"MD59O>G\fkaQY5C[S.^-+ReWk-tAaE1t_77;o],?=lRIfN&[mf*1^]Xe*_!$5[.E!n9Z3r8R;gE=:^K)FQCK80sZJi`r(ku1\h5g=tF_h8[E*Y(!+gb".(M49tRYMRYK"db),5"T,c5pC<-))I""-oku2V+[.E9!W!L')#7?`4PfG=gM4.CY?"i.B3"+f/&_P*(co"8]Xt)BGlM3m`=OCA^EC\Y!0Oh4@W0"6@5@_+BqVbWe8#7o7n."pj4FCm,O\ohdq?XI-aqsN9%UlI!M6:%%Q-e5kTF1O^\[1M35;"0IR[&Gb>>%)`JO6PJu;nO5\1D!eLsea-^_f;OB7QNYYnC.=_3hpopYYJ,Xh$Rars-G'7J91!>_(71,hg=0>fUZN)ZuY?SJ2aLXp),0,]aU[Z8s#SL^J;56T3WSmmEFGO9qEh1[>X4mbZ3-_hJ7fibpjh9.F=VYP0g(#)^MU\R5-K$GBiW8JM->)/_KL1&:r#k0-`>8GjqAt"UGVLs7=Q$+lBG.]*8B@BUp/-4t59;R(t#QiPUFl/?L0CM[7@"DP.Mt;[0@f=3Bm.r`lQ9d"Q]3gc8rg'IP7Ur">V.&:R.g7++lSTgOUBlN519N\cN9V$J)9Ukci!"jBROp>pX32F0"_5PZp/a]g!8U@f*g:!A99fHQT9-LW;C&+O!-lFLhe9GJ-u_moCMQ8E8\OKKaYM8lR(8POIY4e+j[/fWM3Pes"BOYps]o.aY/>o%>8MU2TiXUmuY4](pl>j6+HokB9%h*M+B"3h7Ak429Fc*>Wb/!TR=!Cf3a"^hT$FbRj([!Fju"u%j+\t\5i`[K=kCJbaC83qDql9PoPl>%OmQ5!Ze9J9pJ,K#mgnM?fb%K//^qsE[qCZ8&bNHpsn4!qtK\3W[%ou^>-\XhS"8oe"8gP3oBQI_*nE0KSr^"j`$>omKH.o_OjVs_J,fMhfRUa+.]Oc(^Vl]'*rU7N$iWW/$A@ua31?F6?:nU(Shn/kqt99qVtDWscLsoDJGEj>b*Ai-<2icLg*/k/K'r9d\TTA>*ojm8,Z1X:5#g?I%_6(<2`N\2H-JHfsY`:-od805DGF/5<.#u9=0JLl&2-$6pq<(:j,&jS*<&TXG-Vp?'.]jsjRl86@jm1O%H)6Sg&ZKftW]sXmB'&c,CB]*0T^_[BgK3rI(3a9k"q89\UiVj=::"QWnA9j3K^d5TYj/T$//;Z`)A(F%7lh+i%^m5*S1bsJHs"+13RXhGNur"+'+\,:m5L(;aUN4N!t,\3JqATe]tI]V>T=b)`I<>9VG(-c5QM_S*BJ9Z0k(8p2nN\H)GTP7%Y!Ng$5kd?S5@qMF6DPt;B*QG3ctd*c%9Q[aK6We`lJNIA&jVkha9H!arcGY3ICJ$h9VkQB@!/P\h'BIrr%1SAE8^h2\$feY\ViC0/'LbB?p;Jq)s6,*7iA1T0@]%qA!VfGOOAl#6u>7I!F/>;401NP3c+Y8*D4Kc7Vk2i4snKl6qE:7'@G!,9IHu?!U_B_[#5;]:)cR$[;'rV5p/Y*'JVt<8\cYFs+Pk3,sPEifZ*@NugHo[4E%h;nQ(gc;"s,B?mSM-g2Udg%NCYr9V-q,k)YGZYV@=0A7+6&lZn8otY@#'Dp?gUg$Pt)O(.NChAY9ea$G7+*T,RV(qjW&2YVR)b=dn7]\<%`AkRq-P0&cMc-NZsB*bKH4puDB(g5&NMmYF$ll:1dNq5qg,M2BQN5O72F@VXGn"k05\76j\*;]H_q>Iecc4#PuD,Rn#Mk09q<+ke-->]Yf@1M.&*Z:0Ze`KNH+k)AO*8TQb)5])=L,f@fl0C>->a\,Kh3lSHVC:P_&)FJF6=fu%EpV>RpF2c*`K)H,s1l/h[\3EXflDs>6,;rd`!M`2N`K!O/0^CW?k0066SWu9\DAX`^?Vk;m-a7<<7Q>bgX@=Z)N3ZNcqtKR6ES@u\frJn4@0Cf)/q=pLREfL@U/@a(3Hja+?$0PTQi!b!gU9=qqMgWlJG&U.7>`gFnmp4Qlron>c#`r-'?68Z"263-4sP[$)[m%6+$Zo.WtpQ(e4Z,\an;NM*$]/CY8pdOWj?;2[LeDSV/R+m.r!.uJ,ZED.ZfR;qs?=KslHH(_mbhdo>/7FX8-VcQGe\f<&8t[k8#<(8!O(?;6,C\_UQMM>-;c9Dn+/#nnT-+DfuBKM[FFXAGSl?ChWI3`)_gETHh$`==B.d(FXF,`?No[YZ)Nr:mPM+TVY$fm&GKp@cW>nF^1*F-rJ6Rj;3Ei0T2:-q$1+GO?WEPNi?'Kj#"_N>jh9eJ*E-Yr%\)$cFigSTQS0Ek<43#S+Fc1Kl(#!t=#Haci3C<>_dWO!!iF[kD#%@Uio+'e>"TZ>.pieo-SFb_d,c,hns[_(5(RjN3Sjq$'.#;]ZI]G3sn%)""guhr.Zd>K#T[K_l@QS1Ss4U.(>[-h3Q6]1NKY0"=+'_Mm:uA?[WLS.rl'3C*HB@1e<8nm+KjhPbm05,XB*!lXFiZY6Ln!S!KnEn6GD=^[L1A,0[;qLB(oh7W58(V,Yuhr:og!].[L'&HBFkq=8e,+;i2-&gMGJ]W"i-:,4U<-j>cC%rgsl3A+Hjh>-d1f2(t*SND$fQ3#JuP6@1NDDBab[_Zg9k_:V(T4"gUD)qXeCH*)KZ#.jrbM.I>drtfL4iDPnh^h3HCpTI]A?Q#D07qVPupX?H=!_aWZZ[,i1C1=gFi6qX*%Hk8o%FdQOeicfgQa/20nJI(Z85(d!1Y4=24DmYaQ1"VYAD&YGp'11\H+&o[6q]bO#dc'pZ&<5`qlCMI&>>t?#QD;W'5q(51I&ut0P]t7P/+<]??Z14hsfI]Zg\@K.Q\i(O).rq"`"@4kWcCD`n$Pb-:RJ?[Rn&\l(P-Al^506]6cC>at3fY(\$.+4^:i9aP`30c#:af!d_Y9(@Git/F9a$+YC?=Db'=*q$bb%,We/B7MX,)B6!E`S@?==@SVdLbmXD9`MohCl3@;I"d>Ib*C%*T?<$Pt.n[J7[+\9Vi`o8^0.jb+d9Fm;rJ,(W@"SY"!6!'11qXY%>;_91Ne4)`ugb+CIF"i36[47c,Sm"r@\PPf@6rME#G5YRV%AVs_aP/`n(3H*fh`@nTeGkgd%G$,2U`5KSbrn=2A(NE#/4ZuM(PpoX$Y/&i]:>-n$1ODi%d0`FI,8D_0<&dZ1\Q^GWDr8:O_R&`#gQ5>q"[LnH>.(B1p&XI.WUo,g$ZS4GhRntmLt\t82sZE@-jR:5A,P/R4*P]uc^d.AjN[f,+!2Tm3EeX$ND##?'bJ^JHl4bSOMW3lY$F+f)8t8D+Q=l0U/.CFBiJ7TU2f55V?RWMDJG.B64l`HrXl\"JrM5WR7J2=/o4kr5\0WZblj%7-".7jbr'l$`A4;hR7*EE;]M$s0'--NiV1'r]__VC=H>u2%bfo)Ja/o5LESBMdhO;@Q+llX;F3t@Z)FfU=`*i#e$Z;=:j_!:f0Li6pRRBhKs\bn*dgEqeWlkp[7J9hL"+/4KglQGP3i!1[!!KcCDeLWsHD&[\0:D+gj&qj#X^_M^?I<%N@r)Zi'bLE@dK6"5o9WE]91)c=?hea+uLFGO86B3*T!COMD--Y&&ZiR;b.+9t$3I(%dI+sr?:b+8uP'm9,\X7]_N#AD#04@p0R[;GOeB`go!Q#WX0m@sgHVV%)Hi*O(FRLg]H1+JS'J;!j/iGUG5!C$UI?l%2O?Y36]68#q"(`V!(I7%"coQt+@9/R=9nX"8,;8cYh95;H2Jq.ng86aHb(uR?pue9!VNWC&4X\*4LcNKEJQj8bhnMt]J?5iRGhbB9eiq54A_XY1,@BBhj(%T9Lq%I.4Zi6/b*=JYWa:>SI!0ZkRc#ngGVFCB1-sJ46iic/)*Gp:68KJq(RM^UlS@8@f%(V\%N2[rNffS<6&+AN#N8nf?)W%$rrtXjRPelXCm-o&l;+ZJ>>*BU,mRmn8CQ4C:?_d+"+:n(!B)2V301,C`Rm-L*X1jJLtSS;(IT^97i9V+@,3B:5=%=S*FH27"Wi?'j21?^!_4di#T&DBX:)\a*%d6X1k=ipEqIt.+Sd:^dsZ$_%T4@NL[*$Ig;mFnu4Ec*?ZOEduq[:jhJ;ZS&*\?%D?11I2]2@$!R=7PkP;Vd[+a1ZioGc[%1;H-UPA&\r>QJB&oX)LY/.5tFTH[F4ud=KiZp(6dDBU$/-+L8>[Nu^)K:SPR_otF"F`lW-27G\BKQ*90T(s!:Aa3o#g9bRh[KL-H6:+"TD/J%:DpP^PdB#gOhq.@LSekt8?ip6!m:4dt_\^H+W?WpVO)]S,*k-emH)V+;2Cd>$3=asS,bXlS)@J&NuH%qo[PCkP`b:>qMV-P%7\+?X5tW'mY"7Le4h-kK+QBJ>+feWc\Tq?a:aFC6JNoKhfTe#,uWoQ2W8/:rM,[G9:dI/%['_I9dh5GU)iLbi\hi"h"I1gO0GTLXf0Vur,k2_fe'lI2YllGYg[Ep!)_gDZJ)!bf.0mdAB\.7Jb5BTf.a4:[c.;l7(7\>6%#CO3UmW[c-m.3g2()jH>WLI#J_+UfeO'\'-_CY?")GOOB'3nQ+$Jb&C&)`MXkDr+`YgRtHos8LU#f"Sl4aiVYhYG^12gaIY#hsbqS6CG5OIpVN:aZ2BPH!k#&DI!<1%V\R[m$A\@867kWAbb9D_h[^<^E)W(MTnUY[5;dVGim5[:W8hbFQtM%_7Uf+gNN=0Es[beSc3EU+5W2"sHq%>4DY.E7Dj^N]/'#7hm>c^A6__N@?L*`668f[GNm9jX4sflQrX@7$I)4`VI&SXk2jb*;u0#4Un=rXW:_l-5gTgg&!fqIJ@A]TP$aH]K42FR4r$H0a1J-Vn]>!dFp;rIfiW9:%8*Sig.K&#-Ogl'0O8@7E4<46'?HLr%2s-OGk5p$:5jbKcV<6e>?7o]`,DY(TV5-RU:sM?!ZC%OEtip$UYJk2tg.>.)f.M8891IJ``c23+KlpB&3/0d5!t`A?'gRAYpV[tSW*k/J<,Q`$99cWcCI$s0A+!e]BWbFTuPmDh+.'4iANXK8MNUIWdUX^fD3nWiTI+QsHjg"=r=08@hFq>b)nd)4I5;5dH4_AH,J%n4?C\H?fi$hMgTOnp7]F%'ZY"^erV)3d0CIW+K,R>o3kg%>p(o>d^b$E8&Aj?1"j1b8H9t(j#2P))InE:(+oJ++SK2Ui!$3Q#MJ=hL_O5:rr30kfd\9/<\rLE4@Nso0DZ^4SUf1%1e>ZAH^E3Kf"Jle%p%?;+92nB>(dZjHQ.p5'o]W"Fn)UfeJGq6@hE4+h=h&FEnup?acDl@$%M!)!Wj8pNoB+:+[WglXR?9'[PZ8?E6qp$8NgL2]u@d*N?!?iViuhRk$+(1m'-=0Gr0rqi9MHdii+q!hj+o@p0=T7DFlWI6:BrVEo?[m<@'CFaokPe48>hnG(SQUh[B4C*_4.riF5iII1We%9gB6@U[D0i@k*&2RtonDS0j7)P+VfU^7Vj2WHg3&)R"TgOSFC1SoH'.#[GAJFI"2fI^,,mFbq6cc6X$*d;LVjfm1n*a'?1PuXQjS7'fMgb6]&K=Y2Eo]c%N=-(#"KS.!T_4GBUE^`2LeF'eiRSD+c`LE\aNn$c<[*_S9qq">?+P,$DbVL1"@qj675H%i#eR;T9V"6;+0+s_)P&''0/'6HVb*ai[r1p5p7\1Rj9$hTKBi6ufeZi:gPHRk,$!I2GFpm:-M^c&d_tnod#O'/SAYaOe%Ko^/;t2^Idc'3)Mr^HC'bs/$Gf:h%I<'?`1;YSJM1W<]lRlJSeD&^sGqgK-X!s8p498O/:jlJoi(f-\`7JEi'4*IQ/#m[I%)9O?U7Rfi^'buCObg4VuG)OG_aRS<2X7m\]Q7lUJr6UK4_Cd\L$lbc=R=a#,PatX[o4:<[8(3I3JHH-4r%L;u?M3(N*qRJXg65cCO3S)k4$[QS)QA?N8\kT8B4DQ`.'iY,J9I.krQZV3-+(N(2i2?[VacbQ^>af$p#g2XWd]8TDs^dG0r*fs1e7&-`g"TL"50rVQWcb:e$^G4+ed;,L22$'@NA8V)E=gJj8YnF5pT#jSALO$EV79M?-k7T`dFW)9>RDOllN+OGN;/;/b41A!EigB@aijiWj1jcebtU&hXp!FiG;"#+G4"!0NfqoA<7T8c8"2DRp@$l\'GQ3A;b9Q;2N'l.U5Y%i4ETd`_hJU+o#H_M3=m=.N]`S9geNW_9gQugpqLc]TCMTo"bk=6\c-d;\'f)$Pk;Od),"_9q!mF3GpW/1Fjt+CMW6aqtA^tgE1afJHH/Nm+J^^gU?!hs*a=j\O2)[q;?l9fTZf:%X!a.r;9>TrKQ_i:RNsA[m35%a)Y8CdA'4#(5PGDo&kN&rO3?,jTY4NkKfc5DmD@/G3rHiJ&Yc",*[AA<"V>c:0:V#p[6j+GTt?k4$/@*EBm@I8FP'-'A_[i4F")*DTX/9UJlkNV?>A$<4-Mnf&m,[a?2LC3:LX+=Kll0:8ofFRD3a^`5H%\jlu%*aX<^:p0:S]h7GW-Tj9q7TS3U+'48=mWE`=`CW,2LLDfqKAM,m,W.m=\X.[M5q"aaUBQc4d_\,j,Quac6S7!'M1rJkVoc5_oJ8!9*F6Cj*hVPd-$OFd[J,Mh1d'moKMHcVom+]"1TrYA&]2m,G=0Gr4.&qapqJtJnW[VU5[VXVPQ<"0kJ'H6_'fk`GPEQ@]$7[MT#g506U-\f#(Ddl!&9.-s_6ILjZ74JTdZXQh#baPMP>:;%5Q6ICh*9TGg$\:rW7quKj7(%G_1POR3!$XqF;9PSI5>KZ^o^?CQui3W=gCHm>Gqb?E-6ruY^JfH:]ifT@cS;fZ%15UjE%LrtS]67bq;6slZV"<;n+a0U0XD:sA=]SQ=C-(G/Oo'3CG!:9H/99Y!f%*l&#-o4jQ5LRX]q-cH0X9VD`ALSABjEfWdf"qbEY@;,P'W[LD]OVG3QDg=G-;?3C;-a""b\-)e;2+G1Q=ib6oE)5TGRX'i<19h@peFmBed&"8Yka,WaS9+[a,d-Yh1gpdrC:6"&ag_MJF:s/\)_[fUcV5:"'(De"l3tgmbK)B975r0MXK0(#GWab(DhhhNbg]DTD1:<]Y#49/m.uR/khm$STE40!+6,pZ5Pn#=Pl9IT?.OlphSSd8uICOE>"Si3k7n9t^%r_FK?XM^JIesSL!8aE>k:9o5"9\k32iL@`%NW^(+$g(1?(]j'fO-fWR[fnlHkLVPW)8<[*=<;fV\=pdSM$[Bf;Rh56[40q@'\\60iMn+1=V]Xri/kO\i$kIJ`$T"m?l2B$DM1+5ESI!%m'X^7\:+o%!:@Rb1Os2>Ydr7>i"S`R:SU,9nGTL,q1L4TPI6AAmnaQ04rV[I]mTg?(2="5^N$b%`RGR_;]co$[NO#NH4[&&$_Os2IeF'DuMi1NH-1gm*(V0tLq=tFrSHArrKbbdN2f@CnYJ66UN:c-5U3/M;+15n9B&trM(L>8tO-,fs(l]TQS2kXm/hYM'?GCsfaH7^$Y(D9#pisCJK+8A$ib76jo$3XpP:#6("m?6$Dr7E305o^[_(CY4P*-G0;g%D+?4V%3NfM]S&JPurC/ho,nH>*'N=5Qr#ZVja<<][T!8@&2fe^2o0$Qqn8P)J^&RsF7n(p4_'jFY*6#NPEWo`d@c1=DS9ksG3p2Ns3RH,AJ^_ur94kiY63LoS8I6?\T>7arX2nILP1=77q&74b/t(e*P/c!#-^m0!33'!fKUM;[d4>e9MEZ#++6PU6DmSLj;$)SN@$t,bg"CPMZRE\7RdU0E\,9e@2JcLmp?e>-D;)L>@m`W$?G1YZSN:oZeucE!h+C4/&E+Q_&jmPe8k*/'VG3OL&C5\o)*ir`$O^b#Wg2;cNOkN;kAsMh9he>N`dIC?c'70B1h+q2:#t+oF=.k5,`mmS-W-br;N'8*0'XKoU7\E:*/t5.$EmdL9"q]G>`g"6'Dh);RZYeGT[1@0+XB>rXTP7*OY$JI%)lHH%'(c?/DJnlq#nmS'h6h$b`(s]E\8["lg!.bN[jXMiPa@^I*BKF1\0:Gr7%hN)Z8)q$O0N38C2",*6#.@(OaeeRq'/qA=M]?LJUcOs0IO@'J,oaOs"F!CC?AL(lnL=R'KRfOq:4%Thg?(M&gHO6[=R,A0Ui+\5Vou#;l25Z[&6]lnp]K'['Yf32tCD_#RhY1bhLlVUYMhj.7]M=jh9Z(JuM\H&mG20n%XACjGEGk*:l2AiPUHBfOok$OFl'PVP^6Oq^u6i*4_H@YVeYke&de$)1JX6@2"sng9jT;.RurtNYjL&6%cGIECNEPcna,1iSd'6L0QWS;1M&CLhD"YS.f0qW#[VV@H;\'a$K]N`l]UdqdUqk^<>1!*qLl$sk[r*30'?Zt6K+8k\nG;fn&Ho&ombPL.Q>,*^/T+F9'LC2.[*YHb:nN10)-SfbGWW997q5'dOoG%*?Z4`0dF[!:a%Qa"jlLTnHhZqK?ZuMV&/&*!"mCH4o--iDX]r7?bu2#g?/2.S.H9FL6oU?lU#ssZ+G[pJpD4iS[VS79UP+:'NP9LJ"J%cjIf6iCG6AIC5s_NQbqd]]=rqG.IlohUcsedb0G(?jeR"3s-N[@Ql;5J$_^u4W*0leSFG"8VW)[#f[uS^eg;^j6Ji[hQ1'jP?;oBnrTjWse*Y;T6hsok\@D=PM%e)LbNO&Y&3)X/OP9oI-pVh"jZtRX29s85B^nW'FJ+$=e0md<+Lo:`%Y`l5o.aH.Qu$FXWq@dMaPQBmhLc^kRO#`+=oaiVX:o4-.-*BOs-fZ3jCZY,=g?&5_](+lm2<[I.e[F:P!c2l(mJ6N^13I:Gf:$sBe(+nP?0'VWbc'gN=BWtFPY:<-],2S*1LPm9?BTQ6DBK_.mS=&2dP^tYoc=+#bZSh#7NupS5(IHE*=TPpV((RL:BYQdXj5YHJQ/Tq>K=Bo&WM&UDpbMIJ`^mf^Sb1lgq'4NhiHr3W\!ED\k]id-TZ)?gY1u=0EZKO5.L"+%u6H1G^h_!Hf?If/)S=+:o>*7p/AtC204rD('lXjfG#)@U`e5BSoQU3oLhX8.3T(E;\j9+@f0L@r6(bggO2];aYaH)WNpeUP%N0D2T/]6kCIh%*a]4\T4OU[lb7b8^EtkH)d1Spu\&a#Yd$^_?AYg!,4`ZkCZU#aqKcBaN2Gl2fBa$I!G,:]rnN@PiiSk&e`\@,!c89LT22OO+$cYGC3G_T%^SfdqL3`0,I-25bOAGTgg7rN,WubQXHBmNPb-c=')/n'6@eRr;HBIbiPMC5CWNTndf:D09KTik8Wa5B?d:^\&Ml#9H!P5jfm604%Ua:f1)@r\'g&eHUa^DL$MQFMI\>\)0SfR"#tD3=6ej#7]8%1!4F%1R1/[Om+>ck>Km!f;bjF?d.?[2#TNaMCN7#b;,p"R=L9USs*KV^H@6;J4+7-)saJSA:(]^tID/h"`+o%R=FabaIO@Z?GV=[a'C:CY#Rq?s+jPr:.4?SeF9(*R`.0HSd\B^8>f4RPTA]9[;3;6#g;PcY:4h4R@+q1Bn58PM!mX,ET>&/Nuj:@N^b7!\R?QX#Pu4(hS!uRFs]^M:bm+S9_KDVI=6P.b456#(T]@j#BC^d"hf6T&k@I?5g(cA41fRsc8djDS32'09i,\CD"d8NL]/SB+FqKP!C]FGM\e$1Gjlh_"nIT:`+IuFKt-4M#^R%(I../JkEl([6pMm9l)i)"kg>%Ek4$O9b#bcQ+`"E,lddXl[\3YFrqq%-6%MLgkR9H1fs>=]C8ir>Y@"1A^jB$V9_c-!b4tMe2*-4Q8SDe9_>B$=]Ef:/mbPK*Wr2+ZTAnEG'\1aaF5^juUI#`otG]Yqb,*'Sc&d*Rm0/8*;#j]o+.?R$5d2V8LGI!g=+op*$dc7mHX,a,;HO="[UBmomP-$PitM\fk`=EOE3BtBleg)5lKVbU(rE,fk07t?h\Mi/f-i1Pum^l1&FY4OYJX);%^cHaE]LOV3ufK_C`eui;:>9+ggcm8Y0M%c2@Q00FlnpQ'QGtVje[:mi.3ihUlXLUPU_]RNZ+15Y#kNt[/CV@o#Di%-j8jBAGC#r[a>Pq\om=2G/FC^:nl0N7n0lDLUOY"PQDtHO=HZdR11&k:i2i&:S4rjXn#DuN'`GXLPIB:hnOX_[h_0\^3r*!LbjSMl$s1F[r*3lIhqFET8eg>V19phSqnUV/s'RfZ?ZV2B"#kJPEM(sd)c[8='&IXMpYEkH)1X"@54O5N\3EN8'-;a#8fSEX]r8R$NpHi0H=@1D/1Fb!;qq?&90PJLsj^L67Xd\6TfDMLuK=0>7aXV5:Aj4a\b&!\ehd^jKd;:!%8^HFt?qV(+j,@ANCkYKnY6?aH.!e,GM'4VK>lhY6bXI'iQ8_FR7YB+oA205r17XXJ6?])3?pILCU0HhP0*ZNK&p/(hLs]2b-e(cIn5"Pn"fqW4#TCE%q*V[r:/]s"sPjhVPtfkK^S;E$RG(qMp=W,+B;rZm!"E@/$]Qis5[;fBZDG>9fLCP>&r,qu7oiOUs:K1:m]mB?jX5F%HW\jr8>oNhF!G.?:N(sLA(IX'QBkaQ6_PGD?.8s2ML)f^VRr?#IJ@);5*uNQBjFHgc4H!4+6sIGU3a](p-uLU?q7V)Di"4%%8l*KnZ'WEIqWFR"5a<51?+IbY1@`TJ`;":KCLsMLVn8YeVbekGbG[EH#l)FrpqbPVO<,/&(rP9?Ib%W)4eP_MjG4kQ[feYq]R%P!U%b:r1SV9,7K`\8c#t^VE,n5m[u0D:>AA=qBWTk([(h!!iXs'5>mj$!q%cH$OMlYtLE9GdU*MnmWk*3]\W98,7Yl]mGN=UMbZermtM,`.Jk2r]21Mk\t%hB34s+UDf]Mi'?9Gd2X^m$9Hi3Y&.gO/\E=-T8j@Ddi0V>V&A'L\qfK+C/]/PTEEV54cmB[3,.crNJ0<`\qG?[o>#*scs7DS6#m3.uq19'Xp*K3R(0":lc.>FOWGbI*4>_RQH,#\`mNo&NB.mK:_M+N5q*-V3=&+XK!'23buCeuaj7RcGT`),Xd[Di\+klp2"BL0TCBXK8KQ.OoD<"oseLf<:fWSHtrgVbUc2T7?i#DI$.Nk007S[Xo42S3`1Ncd-OZW);p;8)qUK+mq1[D[[^O>fofP_1Di$@;Xc-`N;dj6q9b2gF>'<'t5f`;,pVM*5Td_/(se0-!e*(O_LI]!8u)>M%f,CKG90Y^4#n"_Ras[Na%i<))Gk5TrfqS^5Q9\4K,?_I.?48RPek?p^U<,?b_W5.KCS@F6CiF)\/SgV.+s1&lHDmrG_(c-t-OmjQ9oB=TtHn*Y]m:f\9PCRD.otRD,t6\'H"18k_;8a*=]sRjE?cYOU7e/E;*oST3p"?'TE,%c%rBq)Kl5g>@7!DNYGtBj5.G`,(IF]*"g;7G_Q?HtT]PQRT7'1BUAFQKp[6jaqXj"k2f:a+qQuTUfB_%lZa-m(pK>&;\P\A--RU:hWWN6GZ+%3?F!@$?RCLfGPF\7=(=p3JHec1X%@K+u%=8VGmS>dT=.aiQit,dc@X125mH8WtQXc^d.Ap_!u8;?fj`kaY1kHou:hs-/h8P(e>ZiJ4pc8Xa;dZ#IS=rZH:#QR3]k04jVShH3B+PjVO,AVoJc>'%H>7]nrKu;3]NkpcA-8e%i+UM[%fRl68-%5qn!KlVLd]Qs,6l>#,&FI":MShTr%))GkiDHoI$-n6^@lgp#N0?1-^?T)`Q5Ul0GR5;@L8Y&;.(6RA=fWeqrFm1Z8KnZ!SD5%tJ6\c/*fSk?@;,pUbfAQrF*fO=Z^E@/TVpNZ3/35i'XK8Mc4_Tib)d-1_aN1#j\&?3QgsU;7q"T+)WD<[1R@=3WO3jA0g"De!MdF&@&[sRsi00`qHdWdB.I6qFpo0N5!G501H.6/[kn*CNJ.`Vd[=Pn`9o-,/EG_W%,M5pJ1^VR=0Gq-[SKe!&oME0!G,)`,=ddPecc&dZ%)e&3]e<%*K=:Z^Mn6<#4UL3^JKCErU.;di2*%O:sO[XeZ4I0(BEq/_kHaMp[7!@pFj^V0B_[l*#or;bK!C]=W(f2^u5H:(clae\acNcXr%.`iUuNgF;ENSc47=pJ"_h_bF[eUADB&X:LIQQA`LSr6P7tWB+MQ791hfqlN.'8aN_u+1VZkd:;s@'s$O8(Oq$HlO2ihZ'%!KBK:#h/Z[).SEjM*uQK$I!!;o(ujNp/$Df212I@?^tSX#K5il)9q8&q/^G:m+.N$1^(.Rccp\E2b+1*eVao]X]lEC.""eGH`84^OuN\*.I2KZ?_M2B'N:+FoMg/9iV[;4B59@HU1SifS^m3+iOi78&3Huf&RANKGKl04%/*F$mbM67Uk;,OjR8VNV%RXY53;7=ojLC\C*dl"eN]I96f,+&Bl7RTWISb_*QFXq?P)DG[@%*Da9J,UFs1^T;4R7[._6UO4\X4%Y1.kCA^h+QAFWMul,"Te[r0Ze>1(_o!]Q0G#hYhS"9&St:sS+K,kBC^P<\['VYS5<^I?Tgghd,n64k"M8([?6X]gE_*Eu-.8iRcF`JYPuiVB\Jo()7`qi7gR"q2=kQXISLEBJL8!%ffA2JgIF%gWM1mKI\OL(oF9lds1Z:'4\-C;kIc:Ra6O[sSSu(Dh;`gmOj=%NRT0<`XrZ-3Zqc:f,NID;/7$BYjMYW@(apj`lIDpOF3>OfIU!6UAP,Tg6UF+UD/I&`jr8.Y[$X+C90c94GO?I,-jU4i`3#%OBM%mWO$@Y+n$?ZQ`a&[/TXDf7n`/0.cg]o2Y@#&9QBikp2Dg1T.h3L;)s.m!"Bi3O*CT2soEU,,lW^f6_6$H7ct&Co@]`gKeZ+=-4uTFAX">kRfXKCi))E6Q*Q,e4H!dME-i!E&>NDoP/6Ti1f9=]<1,;0ri3uhh5iOJNo53?s3GrsXPFeA+X:XqL6\c0=hS":%eubDuBu4KWbB-Ai?X1-^Kq$a84F$Alp$:#O?bCWGR[T*R!LoCVXK9XhbDV46naZ.S\$qtnIX!+!%4A0Sob'&QOZU77H[.5"Uf3jOoR'XcC['Lb9[8'JM@#>d7bWji`ut^3l?:RAj'O)eAOj.Okc4$;sc"_Sa9>I=3+V*OfqB3dpksNZC3e'OY]l$Sb\YOa"-RZLqWuD8/+b6\:Elq%=jQ,C^a,d]Ff8^r&^m\iXQFXW>Vl-G&Ht@tK9bqp4`XQ1!!'mi#A7X&HAHrGFh!28@]"4?hj\2F=NF5CD96,)pdJSCBW`9,fUh\_sou;t1!s/NLoptrWT7/!J['I!S/IDKR#[PUGrr)`SQH#KDdaIU!s.7&GaX@b*UaRcF$k!G1$WscBi-^F[M_DeH]Qiu.bEq,!H%V\&mQ+3dm+=%Els[edi>)Rs;M8I_:/Ok#DKQqe0OY$8&IT'Y`[t"WW2ZaF/hTmj8O8rea2dAcPq,@b*3lr\hQUF@\[f8)KuKo`RquqY;'5E#nqr6ZaNDYg9AI_Rc_$DJ%W5,D+@XYeVDGZp^:q,-E?R(mP/2bnK8*SQ+9QY)ElaeAkjSBK+B&IT*_^9dkKK?H>8e=)eLfg,OA(_md>>8.'.Oj_ZU3iadO@-Odt\#-3dN&&HVfU4gF/tr;-HLqKP-if>WX&c?s[(;/30?,S<@m9_L'?[m[QnSQM1dFh&gprWqKl5e^NE[(s8!!@t1L6T,*+8.'.(P^9%;Fn:A*X;oT\r($2BB*"taG,Th0,"*lE\"Xg!J%!!ZtU2Mm?Q9+m+&.P)$acs6CC"&rhV.i1`70T4q5pRd(iYDg@K>i`b'06XlK*MCa(`=2gg>;>gE88ku^t@;,cAAoGh-.NI_#Q3(hnD7Io0?2'!)Q=%BIK_ESNhTfDJ:$In*eT,(hqBl77p/ZDN01BTj5pd-$gg:i2(MXcBPb=;X#6i@=FuJi510Ue^`3[Pl_R%/\MH2VJY(r\4$FK4J81`+#n3>[knQH]6CG^5>n[k]j%s`5qE_#bdMBC#eagJqXq?e!J!;2WMsUe\1si1Pu0Z`U7rj>:.34OUISn&c2rZR15)i)1Eul"(@L%m95/4G?b_V*RKeiaM_R"uaH.&_:-E7V67E:/2:F?>R(/AS#HOpu@Fr-SDU3\,[Wl\p*U<*`,S"1m.$i.PEH9Mi0qtnEA8p99q.)p=jLGqiMXG=s*p$]0c?\AS#G%IXYa8ildZA]tD"JS=K<>fs>GD.PrmDf<='J?[T]h_0,2$fu1g>qtBEU&C_A"]Qf!.)53atkeFTCfg>LuP:'/cD?'Zu.j6&ZPf)e;X]r<3nH55l^4-$,euW!or(*qn[D7jm$hEke8WcSgF*"[q[@K6p?FOh.3'8+.JN,XiTFKAI9qr\23YhbuR4Jj1V.%8r"U,(>[EB2iQplo@jM>,-?-s9mjN*J;=aHc$HhK#YV?-aC6PnHX`s,UbEA9Bse$j7&3:j;=MMd:u['ZL!T_%?mY?8&]]_tEjo]js7NXGl5G2_gQ<%\onDUl-+Y:17\bGOJ1Gq&?ZCs[`7un^WQBp.+?OmVV:.Ro@m]W:VTX_KK4n4De$FGbTl$daTO<$na8X+j,2n&T]#&_s*SIG.JXR+2WqX]j\d"J:@%L=2nkQ68,(gj&S]SW'ih!.Z,Bk&p(F[3L`>S_9TVm+=$E9j(.`%.6aW5[%?[]KVH>4$2J?1B7DW&KMld3JsFmI>V5I59NIaS=KNBeZ5pYY_\*kW:rE%ps@gOS;fBnDFf*`c^m;K^(AS_"UM:9?>t!u%Kc]W_P'>P.*&X=Di$"o.62nW4L7>C3d%HgGI`5'^&cf@IoTKKnaZ-FSih"6F$"jKpr8:49h\6lFQpZWp#grcD;)cU/-(bJBWb)Jd:h@IFh"9)6"+1F10eoZX`N[Ng(^^6W@,qB6`BEdJYrCd,6_b#kMbA3&e]dsHt`%miPL;&$Q!P]LgKJM"ot2;+X)DW6pH.u(q2=VTM.A>^sLGiF0W9d\]Sq<^9%\:34bkPCAIMN:XO(u@]q((-(R2G[U6duC5_ZRne/:[!!)N0eZ2b#a0e*a4O)!iTegIi]6<::AlVj]^juTQjiAVe(L!3MR57>X&)um>b'oIQ>$?76aq_L^/1iFWXW7BA6:5HPk0KZ\>F47r?TO>.r(Z7=?[bj(7n2tC042H;`dJgjI(6i%>gpR9S2ir!s"mI0(Q-in$efGD]YH\Za7!u:uK?Q)eEk0',)$LN#4k4-9HD;i#KjXp$1(lAa8?e:&rX._Sa8?a*;uZ4Dnk"iT9/iB.X^am`qr9X"<]![K'aKR$=-AK?h+>gBl#mgo$HhO6d7p[\X!dni:X/`1oCn)_?Npoq1!!!X?n`%OKOhQ#+>26]6L1+#HJoThjYq.@L,@eWG%1G\Iikr@SUo1+h2NA9NEreNj.5*?P4?DHdlAAdaDe*Hl14'RcO,o@UEaiNgJ,T%Ak&P4eW[0ukUebrK0P1,lB4p7j"onYLUo("eNq_c$B\_$\+?)6g?G1Z"SHs;nq4sg^.9!+B/Hde:_?A8d-=sj']d_\@3F^dl!!(rLTV*FuGXms4\Xsij.4Jue]!Y_bJ*PN4L-gn?3Prda.+l4[[qN1512(5hffhI3r=8o#(Wp8kaQ4"6M[r:.>\W5*k/hk/`OX"j=!rtS7[Vabg*qe+8f!ojBK]0/).bCh/UFTd7b*&eL*5s[eG<`@ud)`EY\Q/m02'*&#ujQG]Ur:.hgJY/O*Na!E+.P!%&)#Q*u`mC!4S=Ig>K,A:mp+IX8A,lQ,hVR*OZJ7huIY/!!!91jjC`,/R-A/!r:cj"#^@U_19/0]5r$;"t\VE]mfq6`5G&`0o*Q!o&@ZK)jIH-#=\\Y[u$!"+qOVAj2XeKit?p<7uss\p1U$k=2Me+#<=jXKThT5g#86]PT\kZ)Gs+>&ed&g))<*CirXbVoA[^so%=!@pYTuV;@aD^`meX3AC-UGF6?4t_Q=1G!5Z3ek72e4UU_[g?*p7r5"fB,'bs/?_Xls:[;ln=>eG;Yj9C_JPT/JfD;0eL(B=GEE:`3dZ3:LA$cB*)Q?267Z*EID>IL>$s,iG+Tr"Z[j0R&qPJuYe17k)/>*^j^i^@g>n=g?l!9rP+k!lcZEH-!.F\u(D?I%!!)]9NU5>SLjb@lc\K5:/Hfi-(1+[,ff?>@\toYf@&'^:q<4%D/mM0f]qqn(tacneO('jfAoZk09CMgY6LB!bJ5Y.DHZ&!.]:7PK?:R)G)i_hX]dO=k`R(A&])(qpqlR[Ib8G^A-[q>YUnT++O3.bEa`f.=lMfGO3s:^(^VK+:J,Fr!7J=;lA5L$GP7HhZrBkq^=RR5+qUCM8R!$G!^Xg(ZkKUC!h.!C./=8%9QpA4T-X"`@T[W6MJ?i;3-4M@\TaEH,63"YILfp)EGni/XN=rr2oN'Jb.8GX@l:)]SCF&-)\J&Jc-OYQg:<9p4W>\ql.JND+c,B$Ho2I>ZTVS=Kg(X&lLEh&%+tN`Ap[/N;dSEt(g530>kV!!()uf[s;X6'sTLSi$2FE]Ef%Df(["g<,KL0'e=6]U*_-26rTT4Y[KoErdp;a!sdh'#*'B6(Fs9p9f_8mZ*^n!9-aK;EhoA$TP)TBWb,\q\okMO;=jMK>CN+E#B7-Q7oV9sE"65NH%aYgabaB(!!((MA6#L%SZ6EB,TG#Q-RYffT0@k=$@7d6ghji\Vb`p7X2$_1Lm=5?\NsQ8HH!'e!!)(N9hc(#J>aBAh7Imk(.CqtCOceZ2^Ca2Z,^YG"$%K[q9@7ZF-XMQ3[+J[GR[+A:/2dL6QoQ+"QG_#_"h-:1'e3@lQi5Q(#'U4a1-:2':;TV*F/2:_cuOoM/M,/Q4hY$Ieb!gB7Khn=A\\jgXYE=o#O!!(*'daD$'@q2@S\8^C.DFI6`Q^:Y=*E()PkKakh:rYM.5dF6;$(.*IW628K]/JULAQZpQX=VnO:JOZf=0EZNo`kmB+CZVs!0A]h2E"1>EV]0:giCp6il-fd557Af?dPoZ2s&?f!Wq$SE9,*&jS8=E_oKfQ+FDY=D&3:_7t\?ta5PqHJphTo9pLN\WgPG)D07RQ#.[(/-^=Tc+=)dA'2h2)T.?YfNO@!!"-!o()@#pu)I3)3MlSeWQ(.p,T7&I!h/C6tVbHY7uBWeQ6G0O0PQmMMmD)G3qnf3cjFWe]W.)hQ?Y+Rl>7\SiiFOZ=oAPX&8ota;rfF.P`unjfj?ukAio36HVF-bQJ%Oi2S#Qm-O(>X]eSZI/NcEo!5;tY7ggq@))d)3i`0!!!%Ng[r:/)Qk]07\@&OB/JBP1jTHVgI&QrLEgIai!,p`,)1,hrW2M*KKuu&.QS)RlW+seZ:R>eB0E;(uaP41B5Pa@R"8N(_WiE'C6j=n-h07bUr^?!$254g6VW$Lm\>mZPH2mmBMT[h>T'>@uKr[ZC!9bmY,pdWpbX!#a_nuSc(:L/9;h^a:nm^[(1pXKgm+Sj?jP@RrH$Kc6/nA"JR@0J6SZVUdLFPB0mY(@m!!!;Ffs><#A2R;n['XAJR=tK1QS2]XDf5q=C=Geb@ocEfZVqq;?sr9LW>b/1*]@h:I!iR4q>gTCF$`5]%K:QqPE`&FW*hNTWkk?m.:kLqHhM:79Qb_cLgaN/bOI;HY^!i@#pS<'h%-e!!$D=hnFN_G+NY93=;pTE)nU.p#/$5qU[D/J?G\ULa!!$K5Ni()@[k.JE#TVjo@4XBDls$\.m:)<\lIn`J(84rP@?!'k`6$k++8E1f\/<23,)dF$@s/GAAZWu6eSM2C1lX>[.b\Phbe"onYM&]2H']6E_HW?E9:@YCU;8ki%11nQj=e##i]"VqmjCK_W`BR^-t!!#7h?k\EZba2[c=]AA=iHE8%*RjXegUD+!.rE+S"WYJP!kPcTXUY=2TF:Pipi*I0A&aJdG1>s)Rl;=)8%0*;$Obuk)NR",oLQUV#64ac0cVD*euD`nc-;7&m0X4/\_67TIee]'5U.KuD?]S:bC'No!!'TcVE8^7gpj'&f%+j$`c3farVH13Q^3u)a/q1Iq>'3G[+TV4l2ZbpAUbGOJiibN'8B7ao):!!!#["f4B[rV,4Fc#m>l<2@3mp@\))'W];U0-*/<4aCj#!!!#`6YQu#oCMdkbM'@>[5ZLoDsO/gO4M$II^sh"0#(*c!!"-QaN=F+5D]:/j\*<]1uZF-q!mD?.[`dZ?G+?t!s/H&8MbJ+:JoI+`.!'&F':2Xj^%^K=WA6$Pj!!;$:KD'g+8=0Gs#=MBu_'9C0/j,ZE*29t(8hE2S!00OXR84lM6YpBDN!$k*==rP6R"U52%3s!5(Ynl@%[1$,0$?Za1=^11t64.rV\7ku&[B_(WEDm>?dY,'Xd^3)W[R4ZkikZ+l\#1E8W.**lKA;o@59!<<,X"nI&4(J@b3=t5V.*^+hV;IOs#]KgZQLo*n9IeMH-P^d.Up>*?)UC0hh5-=d)!<<,XSVW(-RkhN/7^OO4-@\.b-\XnBFRsE=ihgkU3%e3-r=coUnje`UIM4h&/H%Ym@sgb!"^2^N<]t8XL)90V5;ti@9=GH^ANKZqDBoqf\"iD>A>`=nGN*'AV1[5([p(cMf?MXSNF6-XoJG%@Sp!"0lc2@L&'H4E?hqZrqPLa8qYg3It-##1AlTKDqD-4O/7[8C&pb%Pa%E&3d$=-6)RJKWiE(DGch#H!+LNGr8P\R'h0`:4IebFldi25[$dnmWN)<@\ogY2""ed47rm&,e#faSl)mTQ:?L`5!WW4VMh?Wa11GumL)`DAg=tAGmGX[er^jUN-722I)_GoMn)!Hlj$WV85p.9mJ>\//!!%P#=0GrO9V+@Lm58P%SDi]e!WW4.""cllJq>iX4u'$=n2%S!!!#[b3,CH:,%Wk_#pa14b!q&>LL[U>dU_LaR;f;?!!&\%\``^Cu2g-bXVa8!$DXTR1if5CrnBa:.\$nA]+$>]6ODW!9bO.aDuHIB"0fW1_c9&`s'BG$ig8-pkRp#R$3A**`NiBp?gTj+!)5M"q;Kha2a,3'EA+5j@aN61:!;Tj(W+;`dG%a=V9mH.Okc2#S?BHZY%H3/hRp;nGrUiF9#i-J,8CWKaB&\5Tt+7gc6q"@nc*T$`P"qQ/]mKKKfHpe&!75H8h;+2R4`]V>g+1:chAHS-%+N_BVl-FCDd?LK8^7jC-.f;*'=(mE!!)YFkic[^RV5k->[:W[1ULI$p.\Jng8PXKJ_/q(G9[H$O[aIXZ*K'cr!3H_2!2,B@77FJdfZ7)DXq(sNrUeQ7\X@lb(O!*7?G1Z).o90A9q)n;)_5e.!rr>b34ZT1CgL*jh\r1+^.+aWNYa?Tbg4TOX!%KD!;%(':JYSlChmfZp^(,hq"srL*^*\*o=eh]Rafhd8f;;RKTrQD]=)G&VVHQSZ*CR?ZZB_jVXSF,!!!#s+'D`Lbb=(op$5-D@2dDaDr/,eA]b^HXSr(moBA#F.4?c"IJ``?]=[ss]mCPH=>5!hi30lkWaWf"FmIUqd\KHi%NU#ni[(nCQ1_d)FJ3NT)!69N]'E~>endstream endobj -65 0 obj +66 0 obj << /BitsPerComponent 8 /ColorSpace /DeviceGray /Decode [ 0 1 ] /Filter [ /ASCII85Decode /FlateDecode ] /Height 523 /Length 102 /Subtype /Image /Type /XObject /Width 535 @@ -555,22 +565,12 @@ endobj stream Gb"0;0`_7S!5bE.WFlYNTE"rlzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz%La%hpV[~>endstream endobj -66 0 obj -<< -/Contents 164 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << -/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << -/FormXob.d3ecd28ca03f587d6940049748681018 3 0 R /FormXob.fc331aff86ff817ecac4c4ce4b2ecd3a 64 0 R ->> ->> /Rotate 0 /Trans << - ->> - /Type /Page ->> -endobj 67 0 obj << -/Contents 165 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 132 0 R /Resources << -/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +/Contents 167 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << +/FormXob.c9411fecc114c344e33ac82182b38f43 3 0 R /FormXob.fc331aff86ff817ecac4c4ce4b2ecd3a 65 0 R +>> >> /Rotate 0 /Trans << >> @@ -579,345 +579,360 @@ endobj endobj 68 0 obj << -/Outlines 70 0 R /PageLabels 166 0 R /PageMode /UseNone /Pages 132 0 R /Type /Catalog +/Contents 168 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 134 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page >> endobj 69 0 obj << -/Author () /CreationDate (D:20260419101758-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260419101758-04'00') /Producer (ReportLab PDF Library - \(opensource\)) - /Subject (\(unspecified\)) /Title () /Trapped /False +/Outlines 71 0 R /PageLabels 169 0 R /PageMode /UseNone /Pages 134 0 R /Type /Catalog >> endobj 70 0 obj << -/Count 72 /First 71 0 R /Last 71 0 R /Type /Outlines +/Author () /CreationDate (D:20260419123935-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260419123935-04'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title () /Trapped /False >> endobj 71 0 obj << -/Count 60 /Dest [ 11 0 R /XYZ 57.02362 525.9477 0 ] /First 72 0 R /Last 131 0 R /Parent 70 0 R /Title (Lumbda) +/Count 73 /First 72 0 R /Last 72 0 R /Type /Outlines >> endobj 72 0 obj << -/Dest [ 11 0 R /XYZ 57.02362 346.4013 0 ] /Next 73 0 R /Parent 71 0 R /Title (Abstract) +/Count 61 /Dest [ 11 0 R /XYZ 57.02362 525.9477 0 ] /First 73 0 R /Last 133 0 R /Parent 71 0 R /Title (Lumbda) >> endobj 73 0 obj << -/Dest [ 12 0 R /XYZ 57.02362 255.0236 0 ] /Next 74 0 R /Parent 71 0 R /Prev 72 0 R /Title (1. The Problem: Interpreters That Cannot Feed Back) +/Dest [ 11 0 R /XYZ 57.02362 346.4013 0 ] /Next 74 0 R /Parent 72 0 R /Title (Abstract) >> endobj 74 0 obj << -/Count 2 /Dest [ 15 0 R /XYZ 57.02362 765.0236 0 ] /First 75 0 R /Last 76 0 R /Next 77 0 R /Parent 71 0 R - /Prev 73 0 R /Title (2. Architecture: One File, Two Evaluators) +/Dest [ 12 0 R /XYZ 57.02362 255.0236 0 ] /Next 75 0 R /Parent 72 0 R /Prev 73 0 R /Title (1. The Problem: Interpreters That Cannot Feed Back) >> endobj 75 0 obj << -/Dest [ 15 0 R /XYZ 57.02362 160.245 0 ] /Next 76 0 R /Parent 74 0 R /Title (2.1 Type System) +/Count 2 /Dest [ 15 0 R /XYZ 57.02362 765.0236 0 ] /First 76 0 R /Last 77 0 R /Next 78 0 R /Parent 72 0 R + /Prev 74 0 R /Title (2. Architecture: One File, Two Evaluators) >> endobj 76 0 obj << -/Dest [ 16 0 R /XYZ 57.02362 619.0236 0 ] /Parent 74 0 R /Prev 75 0 R /Title (2.2 The Bytecode) +/Dest [ 15 0 R /XYZ 57.02362 160.245 0 ] /Next 77 0 R /Parent 75 0 R /Title (2.1 Type System) >> endobj 77 0 obj << -/Dest [ 16 0 R /XYZ 57.02362 209.0236 0 ] /Next 78 0 R /Parent 71 0 R /Prev 74 0 R /Title (3. The Explicit Frame Stack) +/Dest [ 16 0 R /XYZ 57.02362 619.0236 0 ] /Parent 75 0 R /Prev 76 0 R /Title (2.2 The Bytecode) >> endobj 78 0 obj << -/Count 3 /Dest [ 17 0 R /XYZ 57.02362 530.6236 0 ] /First 79 0 R /Last 81 0 R /Next 82 0 R /Parent 71 0 R - /Prev 77 0 R /Title (4. Continuations: Feedback as a Data Structure) +/Dest [ 16 0 R /XYZ 57.02362 209.0236 0 ] /Next 79 0 R /Parent 72 0 R /Prev 75 0 R /Title (3. The Explicit Frame Stack) >> endobj 79 0 obj << -/Dest [ 17 0 R /XYZ 57.02362 123.0236 0 ] /Next 80 0 R /Parent 78 0 R /Title (4.1 Generators from Continuations) +/Count 3 /Dest [ 17 0 R /XYZ 57.02362 530.6236 0 ] /First 80 0 R /Last 82 0 R /Next 83 0 R /Parent 72 0 R + /Prev 78 0 R /Title (4. Continuations: Feedback as a Data Structure) >> endobj 80 0 obj << -/Dest [ 18 0 R /XYZ 57.02362 542.6236 0 ] /Next 81 0 R /Parent 78 0 R /Prev 79 0 R /Title (4.2 Why "Feedback Is All You Need") +/Dest [ 17 0 R /XYZ 57.02362 123.0236 0 ] /Next 81 0 R /Parent 79 0 R /Title (4.1 Generators from Continuations) >> endobj 81 0 obj << -/Dest [ 18 0 R /XYZ 57.02362 324.6236 0 ] /Parent 78 0 R /Prev 80 0 R /Title (4.3 Four Scopes of Feedback) +/Dest [ 18 0 R /XYZ 57.02362 542.6236 0 ] /Next 82 0 R /Parent 79 0 R /Prev 80 0 R /Title (4.2 Why "Feedback Is All You Need") >> endobj 82 0 obj << -/Count 3 /Dest [ 19 0 R /XYZ 57.02362 765.0236 0 ] /First 83 0 R /Last 85 0 R /Next 86 0 R /Parent 71 0 R - /Prev 78 0 R /Title (5. Optimizations) +/Dest [ 18 0 R /XYZ 57.02362 324.6236 0 ] /Parent 79 0 R /Prev 81 0 R /Title (4.3 Four Scopes of Feedback) >> endobj 83 0 obj << -/Dest [ 19 0 R /XYZ 57.02362 737.8236 0 ] /Next 84 0 R /Parent 82 0 R /Title (5.1 Peephole Optimizer) +/Count 3 /Dest [ 19 0 R /XYZ 57.02362 765.0236 0 ] /First 84 0 R /Last 86 0 R /Next 87 0 R /Parent 72 0 R + /Prev 79 0 R /Title (5. Optimizations) >> endobj 84 0 obj << -/Dest [ 19 0 R /XYZ 57.02362 591.8236 0 ] /Next 85 0 R /Parent 82 0 R /Prev 83 0 R /Title (5.2 Inline Cache) +/Dest [ 19 0 R /XYZ 57.02362 737.8236 0 ] /Next 85 0 R /Parent 83 0 R /Title (5.1 Peephole Optimizer) >> endobj 85 0 obj << -/Dest [ 19 0 R /XYZ 57.02362 391.8236 0 ] /Parent 82 0 R /Prev 84 0 R /Title (5.3 Constant Folding) +/Dest [ 19 0 R /XYZ 57.02362 591.8236 0 ] /Next 86 0 R /Parent 83 0 R /Prev 84 0 R /Title (5.2 Inline Cache) >> endobj 86 0 obj << -/Count 11 /Dest [ 19 0 R /XYZ 57.02362 231.8236 0 ] /First 87 0 R /Last 92 0 R /Next 98 0 R /Parent 71 0 R - /Prev 82 0 R /Title (6. Benchmarks: Three Evaluators vs CPython) +/Dest [ 19 0 R /XYZ 57.02362 391.8236 0 ] /Parent 83 0 R /Prev 85 0 R /Title (5.3 Constant Folding) >> endobj 87 0 obj << -/Dest [ 20 0 R /XYZ 57.02362 523.0236 0 ] /Next 88 0 R /Parent 86 0 R /Title (6.1 Raw Results) +/Count 11 /Dest [ 19 0 R /XYZ 57.02362 231.8236 0 ] /First 88 0 R /Last 93 0 R /Next 99 0 R /Parent 72 0 R + /Prev 83 0 R /Title (6. Benchmarks: Three Evaluators vs CPython) >> endobj 88 0 obj << -/Dest [ 20 0 R /XYZ 57.02362 257.0236 0 ] /Next 89 0 R /Parent 86 0 R /Prev 87 0 R /Title (6.2 Analysis) +/Dest [ 20 0 R /XYZ 57.02362 523.0236 0 ] /Next 89 0 R /Parent 87 0 R /Title (6.1 Raw Results) >> endobj 89 0 obj << -/Dest [ 25 0 R /XYZ 57.02362 765.0236 0 ] /Next 90 0 R /Parent 86 0 R /Prev 88 0 R /Title (6.3 What the Benchmarks Test) +/Dest [ 20 0 R /XYZ 57.02362 257.0236 0 ] /Next 90 0 R /Parent 87 0 R /Prev 88 0 R /Title (6.2 Analysis) >> endobj 90 0 obj << -/Dest [ 25 0 R /XYZ 57.02362 571.0236 0 ] /Next 91 0 R /Parent 86 0 R /Prev 89 0 R /Title (6.4 Three Implementations Head-to-Head \(i5-8350U\)) +/Dest [ 25 0 R /XYZ 57.02362 765.0236 0 ] /Next 91 0 R /Parent 87 0 R /Prev 89 0 R /Title (6.3 What the Benchmarks Test) >> endobj 91 0 obj << -/Dest [ 26 0 R /XYZ 57.02362 625.0236 0 ] /Next 92 0 R /Parent 86 0 R /Prev 90 0 R /Title (6.5 Native Container Primitives: Moving Hot Loops Into Asm) +/Dest [ 25 0 R /XYZ 57.02362 571.0236 0 ] /Next 92 0 R /Parent 87 0 R /Prev 90 0 R /Title (6.4 Three Implementations Head-to-Head \(i5-8350U\)) >> endobj 92 0 obj << -/Count 5 /Dest [ 26 0 R /XYZ 57.02362 173.0236 0 ] /First 93 0 R /Last 97 0 R /Parent 86 0 R /Prev 91 0 R - /Title (6.6 Memory Management and the Meta-GC) +/Dest [ 26 0 R /XYZ 57.02362 625.0236 0 ] /Next 93 0 R /Parent 87 0 R /Prev 91 0 R /Title (6.5 Native Container Primitives: Moving Hot Loops Into Asm) >> endobj 93 0 obj << -/Dest [ 29 0 R /XYZ 57.02362 435.9366 0 ] /Next 94 0 R /Parent 92 0 R /Title (6.6.1 Meta-GC: Arena Fast Path with Mark-Phase Verifier) +/Count 5 /Dest [ 26 0 R /XYZ 57.02362 173.0236 0 ] /First 94 0 R /Last 98 0 R /Parent 87 0 R /Prev 92 0 R + /Title (6.6 Memory Management and the Meta-GC) >> endobj 94 0 obj << -/Dest [ 31 0 R /XYZ 57.02362 510.2236 0 ] /Next 95 0 R /Parent 92 0 R /Prev 93 0 R /Title (6.6.2 What the Control Group Tells Us) +/Dest [ 29 0 R /XYZ 57.02362 435.9366 0 ] /Next 95 0 R /Parent 93 0 R /Title (6.6.1 Meta-GC: Arena Fast Path with Mark-Phase Verifier) >> endobj 95 0 obj << -/Dest [ 31 0 R /XYZ 57.02362 294.2236 0 ] /Next 96 0 R /Parent 92 0 R /Prev 94 0 R /Title (6.6.3 Collaborative Meta-GC: From Greedy to Adaptive) +/Dest [ 31 0 R /XYZ 57.02362 510.2236 0 ] /Next 96 0 R /Parent 93 0 R /Prev 94 0 R /Title (6.6.2 What the Control Group Tells Us) >> endobj 96 0 obj << -/Dest [ 34 0 R /XYZ 57.02362 717.0236 0 ] /Next 97 0 R /Parent 92 0 R /Prev 95 0 R /Title (6.6.4 Validation: HTTP Server Under Sustained Load) +/Dest [ 31 0 R /XYZ 57.02362 294.2236 0 ] /Next 97 0 R /Parent 93 0 R /Prev 95 0 R /Title (6.6.3 Collaborative Meta-GC: From Greedy to Adaptive) >> endobj 97 0 obj << -/Dest [ 35 0 R /XYZ 57.02362 699.0236 0 ] /Parent 92 0 R /Prev 96 0 R /Title (6.6.5 Precise Block Typing: Killing a Class of Bugs) +/Dest [ 34 0 R /XYZ 57.02362 717.0236 0 ] /Next 98 0 R /Parent 93 0 R /Prev 96 0 R /Title (6.6.4 Validation: HTTP Server Under Sustained Load) >> endobj 98 0 obj << -/Count 8 /Dest [ 35 0 R /XYZ 57.02362 380.6236 0 ] /First 99 0 R /Last 106 0 R /Next 107 0 R /Parent 71 0 R - /Prev 86 0 R /Title (7. Portal: Feedback Across Time) +/Dest [ 35 0 R /XYZ 57.02362 699.0236 0 ] /Parent 93 0 R /Prev 97 0 R /Title (6.6.5 Precise Block Typing: Killing a Class of Bugs) >> endobj 99 0 obj << -/Dest [ 35 0 R /XYZ 57.02362 177.4236 0 ] /Next 100 0 R /Parent 98 0 R /Title (7.1 S-Expression Portal \204 the Portable One) +/Count 8 /Dest [ 35 0 R /XYZ 57.02362 380.6236 0 ] /First 100 0 R /Last 107 0 R /Next 108 0 R /Parent 72 0 R + /Prev 87 0 R /Title (7. Portal: Feedback Across Time) >> endobj 100 0 obj << -/Dest [ 37 0 R /XYZ 57.02362 631.0236 0 ] /Next 101 0 R /Parent 98 0 R /Prev 99 0 R /Title (7.2 Cross-Implementation Exchange Matrix) +/Dest [ 35 0 R /XYZ 57.02362 177.4236 0 ] /Next 101 0 R /Parent 99 0 R /Title (7.1 S-Expression Portal \204 the Portable One) >> endobj 101 0 obj << -/Dest [ 37 0 R /XYZ 57.02362 401.0236 0 ] /Next 102 0 R /Parent 98 0 R /Prev 100 0 R /Title (7.3 JSON Portal \204 Graph-Aware, Continuation-Preserving) +/Dest [ 37 0 R /XYZ 57.02362 631.0236 0 ] /Next 102 0 R /Parent 99 0 R /Prev 100 0 R /Title (7.2 Cross-Implementation Exchange Matrix) >> endobj 102 0 obj << -/Count 1 /Dest [ 37 0 R /XYZ 57.02362 114.2236 0 ] /First 103 0 R /Last 103 0 R /Next 104 0 R /Parent 98 0 R - /Prev 101 0 R /Title (7.4 Binary Heap Dump \204 the Fast One) +/Dest [ 37 0 R /XYZ 57.02362 401.0236 0 ] /Next 103 0 R /Parent 99 0 R /Prev 101 0 R /Title (7.3 JSON Portal \204 Graph-Aware, Continuation-Preserving) >> endobj 103 0 obj << -/Dest [ 38 0 R /XYZ 57.02362 565.0236 0 ] /Parent 102 0 R /Title (7.4.1 The GC Build Uses S-Expressions) +/Count 1 /Dest [ 37 0 R /XYZ 57.02362 114.2236 0 ] /First 104 0 R /Last 104 0 R /Next 105 0 R /Parent 99 0 R + /Prev 102 0 R /Title (7.4 Binary Heap Dump \204 the Fast One) >> endobj 104 0 obj << -/Dest [ 38 0 R /XYZ 57.02362 189.4236 0 ] /Next 105 0 R /Parent 98 0 R /Prev 102 0 R /Title (7.5 Cross-Process Benchmarks) +/Dest [ 38 0 R /XYZ 57.02362 565.0236 0 ] /Parent 103 0 R /Title (7.4.1 The GC Build Uses S-Expressions) >> endobj 105 0 obj << -/Dest [ 39 0 R /XYZ 57.02362 565.0236 0 ] /Next 106 0 R /Parent 98 0 R /Prev 104 0 R /Title (7.6 Mismatch Cases: Graceful Degradation) +/Dest [ 38 0 R /XYZ 57.02362 189.4236 0 ] /Next 106 0 R /Parent 99 0 R /Prev 103 0 R /Title (7.5 Cross-Process Benchmarks) >> endobj 106 0 obj << -/Dest [ 39 0 R /XYZ 57.02362 299.0236 0 ] /Parent 98 0 R /Prev 105 0 R /Title (7.7 Use Case: Distributed Primality Testing) +/Dest [ 39 0 R /XYZ 57.02362 565.0236 0 ] /Next 107 0 R /Parent 99 0 R /Prev 105 0 R /Title (7.6 Mismatch Cases: Graceful Degradation) >> endobj 107 0 obj << -/Count 6 /Dest [ 40 0 R /XYZ 57.02362 765.0236 0 ] /First 108 0 R /Last 113 0 R /Next 114 0 R /Parent 71 0 R - /Prev 98 0 R /Title (8. The EML Universality Proof) +/Dest [ 39 0 R /XYZ 57.02362 299.0236 0 ] /Parent 99 0 R /Prev 106 0 R /Title (7.7 Use Case: Distributed Primality Testing) >> endobj 108 0 obj << -/Dest [ 40 0 R /XYZ 57.02362 687.8236 0 ] /Next 109 0 R /Parent 107 0 R /Title (8.1 The Operator) +/Count 6 /Dest [ 40 0 R /XYZ 57.02362 765.0236 0 ] /First 109 0 R /Last 114 0 R /Next 115 0 R /Parent 72 0 R + /Prev 99 0 R /Title (8. The EML Universality Proof) >> endobj 109 0 obj << -/Dest [ 40 0 R /XYZ 57.02362 611.0236 0 ] /Next 110 0 R /Parent 107 0 R /Prev 108 0 R /Title (8.2 Stage 1: Core Functions \(Depth 1--3\)) +/Dest [ 40 0 R /XYZ 57.02362 687.8236 0 ] /Next 110 0 R /Parent 108 0 R /Title (8.1 The Operator) >> endobj 110 0 obj << -/Dest [ 40 0 R /XYZ 57.02362 491.0236 0 ] /Next 111 0 R /Parent 107 0 R /Prev 109 0 R /Title (8.3 Stage 2: Arithmetic) +/Dest [ 40 0 R /XYZ 57.02362 611.0236 0 ] /Next 111 0 R /Parent 108 0 R /Prev 109 0 R /Title (8.2 Stage 1: Core Functions \(Depth 1--3\)) >> endobj 111 0 obj << -/Dest [ 40 0 R /XYZ 57.02362 376.6236 0 ] /Next 112 0 R /Parent 107 0 R /Prev 110 0 R /Title (8.4 Stage 3: Complex Plane Access) +/Dest [ 40 0 R /XYZ 57.02362 491.0236 0 ] /Next 112 0 R /Parent 108 0 R /Prev 110 0 R /Title (8.3 Stage 2: Arithmetic) >> endobj 112 0 obj << -/Dest [ 40 0 R /XYZ 57.02362 268.6236 0 ] /Next 113 0 R /Parent 107 0 R /Prev 111 0 R /Title (8.5 Stage 4: Trigonometry via Euler) +/Dest [ 40 0 R /XYZ 57.02362 376.6236 0 ] /Next 113 0 R /Parent 108 0 R /Prev 111 0 R /Title (8.4 Stage 3: Complex Plane Access) >> endobj 113 0 obj << -/Dest [ 40 0 R /XYZ 57.02362 172.6236 0 ] /Parent 107 0 R /Prev 112 0 R /Title (8.6 Verification & Friction Analysis) +/Dest [ 40 0 R /XYZ 57.02362 268.6236 0 ] /Next 114 0 R /Parent 108 0 R /Prev 112 0 R /Title (8.5 Stage 4: Trigonometry via Euler) >> endobj 114 0 obj << -/Dest [ 42 0 R /XYZ 57.02362 168.2236 0 ] /Next 115 0 R /Parent 71 0 R /Prev 107 0 R /Title (9. Language Coverage) +/Dest [ 40 0 R /XYZ 57.02362 172.6236 0 ] /Parent 108 0 R /Prev 113 0 R /Title (8.6 Verification & Friction Analysis) >> endobj 115 0 obj << -/Dest [ 44 0 R /XYZ 57.02362 609.0236 0 ] /Next 116 0 R /Parent 71 0 R /Prev 114 0 R /Title (10. Relationship to Companion Papers) +/Dest [ 42 0 R /XYZ 57.02362 168.2236 0 ] /Next 116 0 R /Parent 72 0 R /Prev 108 0 R /Title (9. Language Coverage) >> endobj 116 0 obj << -/Count 6 /Dest [ 44 0 R /XYZ 57.02362 359.8236 0 ] /First 117 0 R /Last 122 0 R /Next 123 0 R /Parent 71 0 R - /Prev 115 0 R /Title (11. Four Implementation Tiers, One Language) +/Dest [ 44 0 R /XYZ 57.02362 609.0236 0 ] /Next 117 0 R /Parent 72 0 R /Prev 115 0 R /Title (10. Relationship to Companion Papers) >> endobj 117 0 obj << -/Dest [ 49 0 R /XYZ 57.02362 277.0236 0 ] /Next 118 0 R /Parent 116 0 R /Title (11.1 Test Coverage) +/Count 7 /Dest [ 44 0 R /XYZ 57.02362 359.8236 0 ] /First 118 0 R /Last 124 0 R /Next 125 0 R /Parent 72 0 R + /Prev 116 0 R /Title (11. Four Implementation Tiers, One Language) >> endobj 118 0 obj << -/Dest [ 50 0 R /XYZ 57.02362 765.0236 0 ] /Next 119 0 R /Parent 116 0 R /Prev 117 0 R /Title (11.2 File I/O Parity) +/Dest [ 49 0 R /XYZ 57.02362 277.0236 0 ] /Next 119 0 R /Parent 117 0 R /Title (11.1 Test Coverage) >> endobj 119 0 obj << -/Dest [ 50 0 R /XYZ 57.02362 457.0236 0 ] /Next 120 0 R /Parent 116 0 R /Prev 118 0 R /Title (11.3 Sockets: One HTTP Server, Three Runtimes) +/Dest [ 50 0 R /XYZ 57.02362 765.0236 0 ] /Next 120 0 R /Parent 117 0 R /Prev 118 0 R /Title (11.2 File I/O Parity) >> endobj 120 0 obj << -/Dest [ 52 0 R /XYZ 57.02362 506.6988 0 ] /Next 121 0 R /Parent 116 0 R /Prev 119 0 R /Title (11.4 S-expressions over Sockets: RPC, REPL, and Chains) +/Dest [ 50 0 R /XYZ 57.02362 457.0236 0 ] /Next 121 0 R /Parent 117 0 R /Prev 119 0 R /Title (11.3 Sockets: One HTTP Server, Three Runtimes) >> endobj 121 0 obj << -/Dest [ 53 0 R /XYZ 57.02362 673.0236 0 ] /Next 122 0 R /Parent 116 0 R /Prev 120 0 R /Title (11.5 Portal over HTTP: State Transfer Between Machines) +/Dest [ 52 0 R /XYZ 57.02362 506.6988 0 ] /Next 122 0 R /Parent 117 0 R /Prev 120 0 R /Title (11.4 S-expressions over Sockets: RPC, REPL, and Chains) >> endobj 122 0 obj << -/Dest [ 53 0 R /XYZ 57.02362 124.6236 0 ] /Parent 116 0 R /Prev 121 0 R /Title (11.6 heap-snapshot: The Arena Escape Hatch) +/Dest [ 53 0 R /XYZ 57.02362 673.0236 0 ] /Next 123 0 R /Parent 117 0 R /Prev 121 0 R /Title (11.5 Portal over HTTP: State Transfer Between Machines) >> endobj 123 0 obj << -/Count 3 /Dest [ 56 0 R /XYZ 57.02362 477.4236 0 ] /First 124 0 R /Last 126 0 R /Next 127 0 R /Parent 71 0 R - /Prev 116 0 R /Title (12. MOAD Audit: Fixing What We Built) +/Dest [ 53 0 R /XYZ 57.02362 124.6236 0 ] /Next 124 0 R /Parent 117 0 R /Prev 122 0 R /Title (11.6 heap-snapshot: The Arena Escape Hatch) >> endobj 124 0 obj << -/Dest [ 56 0 R /XYZ 57.02362 190.2236 0 ] /Next 125 0 R /Parent 123 0 R /Title (12.1 MOAD-0001: The Sedimentary Defect in Our Own Code) +/Dest [ 54 0 R /XYZ 57.02362 481.4236 0 ] /Parent 117 0 R /Prev 123 0 R /Title (11.7 Static File Serving: Cache, Sendfile, and Adaptive Preload) >> endobj 125 0 obj << -/Dest [ 57 0 R /XYZ 57.02362 277.0236 0 ] /Next 126 0 R /Parent 123 0 R /Prev 124 0 R /Title (12.2 MOAD-0002: The Intertangle in Our Own Design) +/Count 3 /Dest [ 57 0 R /XYZ 57.02362 567.0236 0 ] /First 126 0 R /Last 128 0 R /Next 129 0 R /Parent 72 0 R + /Prev 117 0 R /Title (12. MOAD Audit: Fixing What We Built) >> endobj 126 0 obj << -/Dest [ 60 0 R /XYZ 57.02362 715.0236 0 ] /Parent 123 0 R /Prev 125 0 R /Title (12.3 Our Shared Infrastructure) +/Dest [ 57 0 R /XYZ 57.02362 279.8236 0 ] /Next 127 0 R /Parent 125 0 R /Title (12.1 MOAD-0001: The Sedimentary Defect in Our Own Code) >> endobj 127 0 obj << -/Dest [ 60 0 R /XYZ 57.02362 523.0236 0 ] /Next 128 0 R /Parent 71 0 R /Prev 123 0 R /Title (13. Future Work) +/Dest [ 58 0 R /XYZ 57.02362 366.2236 0 ] /Next 128 0 R /Parent 125 0 R /Prev 126 0 R /Title (12.2 MOAD-0002: The Intertangle in Our Own Design) >> endobj 128 0 obj << -/Dest [ 60 0 R /XYZ 57.02362 267.8236 0 ] /Next 129 0 R /Parent 71 0 R /Prev 127 0 R /Title (14. The Defect in the Model) +/Dest [ 61 0 R /XYZ 57.02362 765.0236 0 ] /Parent 125 0 R /Prev 127 0 R /Title (12.3 Our Shared Infrastructure) >> endobj 129 0 obj << -/Dest [ 63 0 R /XYZ 57.02362 297.0236 0 ] /Next 130 0 R /Parent 71 0 R /Prev 128 0 R /Title (Citation) +/Dest [ 61 0 R /XYZ 57.02362 573.0236 0 ] /Next 130 0 R /Parent 72 0 R /Prev 125 0 R /Title (13. Future Work) >> endobj 130 0 obj << -/Dest [ 63 0 R /XYZ 57.02362 215.8236 0 ] /Next 131 0 R /Parent 71 0 R /Prev 129 0 R /Title (References) +/Dest [ 61 0 R /XYZ 57.02362 227.8236 0 ] /Next 131 0 R /Parent 72 0 R /Prev 129 0 R /Title (14. The Defect in the Model) >> endobj 131 0 obj << -/Dest [ 63 0 R /XYZ 57.02362 134.6236 0 ] /Parent 71 0 R /Prev 130 0 R /Title (License) +/Dest [ 64 0 R /XYZ 57.02362 255.0236 0 ] /Next 132 0 R /Parent 72 0 R /Prev 130 0 R /Title (Citation) >> endobj 132 0 obj << -/Count 33 /Kids [ 11 0 R 12 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 25 0 R 26 0 R - 29 0 R 31 0 R 33 0 R 34 0 R 35 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R - 42 0 R 44 0 R 48 0 R 49 0 R 50 0 R 52 0 R 53 0 R 56 0 R 57 0 R 60 0 R - 63 0 R 66 0 R 67 0 R ] /Type /Pages +/Dest [ 64 0 R /XYZ 57.02362 173.8236 0 ] /Next 133 0 R /Parent 72 0 R /Prev 131 0 R /Title (References) >> endobj 133 0 obj << +/Dest [ 64 0 R /XYZ 57.02362 92.62362 0 ] /Parent 72 0 R /Prev 132 0 R /Title (License) +>> +endobj +134 0 obj +<< +/Count 34 /Kids [ 11 0 R 12 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 25 0 R 26 0 R + 29 0 R 31 0 R 33 0 R 34 0 R 35 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R + 42 0 R 44 0 R 48 0 R 49 0 R 50 0 R 52 0 R 53 0 R 54 0 R 57 0 R 58 0 R + 61 0 R 64 0 R 67 0 R 68 0 R ] /Type /Pages +>> +endobj +135 0 obj +<< /Length 5064 >> stream @@ -934,7 +949,7 @@ q 1 0 0 1 142.0762 3 cm q 197.0759 0 0 197.0759 0 0 cm -/FormXob.d3ecd28ca03f587d6940049748681018 Do +/FormXob.c9411fecc114c344e33ac82182b38f43 Do Q Q q @@ -1097,7 +1112,7 @@ Q endstream endobj -134 0 obj +136 0 obj << /Length 8031 >> @@ -1198,7 +1213,7 @@ Q endstream endobj -135 0 obj +137 0 obj << /Length 4740 >> @@ -1361,7 +1376,7 @@ Q endstream endobj -136 0 obj +138 0 obj << /Length 6876 >> @@ -1676,7 +1691,7 @@ Q endstream endobj -137 0 obj +139 0 obj << /Length 8861 >> @@ -2187,7 +2202,7 @@ Q endstream endobj -138 0 obj +140 0 obj << /Length 9194 >> @@ -2629,7 +2644,7 @@ Q endstream endobj -139 0 obj +141 0 obj << /Length 9151 >> @@ -3040,7 +3055,7 @@ Q endstream endobj -140 0 obj +142 0 obj << /Length 12963 >> @@ -3770,7 +3785,7 @@ Q endstream endobj -141 0 obj +143 0 obj << /Length 10062 >> @@ -4237,7 +4252,7 @@ Q endstream endobj -142 0 obj +144 0 obj << /Length 9313 >> @@ -4471,7 +4486,7 @@ Q endstream endobj -143 0 obj +145 0 obj << /Length 8511 >> @@ -4795,7 +4810,7 @@ Q endstream endobj -144 0 obj +146 0 obj << /Length 10897 >> @@ -5165,7 +5180,7 @@ Q endstream endobj -145 0 obj +147 0 obj << /Length 12449 >> @@ -5781,7 +5796,7 @@ Q endstream endobj -146 0 obj +148 0 obj << /Length 10559 >> @@ -6135,7 +6150,7 @@ Q endstream endobj -147 0 obj +149 0 obj << /Length 8970 >> @@ -6475,7 +6490,7 @@ Q endstream endobj -148 0 obj +150 0 obj << /Length 10627 >> @@ -6948,7 +6963,7 @@ Q endstream endobj -149 0 obj +151 0 obj << /Length 7564 >> @@ -7127,7 +7142,7 @@ Q endstream endobj -150 0 obj +152 0 obj << /Length 9535 >> @@ -7588,7 +7603,7 @@ Q endstream endobj -151 0 obj +153 0 obj << /Length 7783 >> @@ -7903,7 +7918,7 @@ Q endstream endobj -152 0 obj +154 0 obj << /Length 10217 >> @@ -8277,7 +8292,7 @@ Q endstream endobj -153 0 obj +155 0 obj << /Length 9888 >> @@ -8565,7 +8580,7 @@ Q endstream endobj -154 0 obj +156 0 obj << /Length 6464 >> @@ -8797,7 +8812,7 @@ Q endstream endobj -155 0 obj +157 0 obj << /Length 1782 >> @@ -8861,7 +8876,7 @@ Q endstream endobj -156 0 obj +158 0 obj << /Length 13402 >> @@ -9372,7 +9387,7 @@ Q endstream endobj -157 0 obj +159 0 obj << /Length 16587 >> @@ -10209,7 +10224,7 @@ Q endstream endobj -158 0 obj +160 0 obj << /Length 10454 >> @@ -10611,7 +10626,7 @@ Q endstream endobj -159 0 obj +161 0 obj << /Length 7406 >> @@ -10825,9 +10840,9 @@ Q endstream endobj -160 0 obj +162 0 obj << -/Length 6621 +/Length 8989 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET @@ -10908,49 +10923,363 @@ BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL .241019 Tw (This is not a general-purpose all Q Q q -1 0 0 1 57.02362 464.2236 cm +1 0 0 1 57.02362 469.4236 cm +q +BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (11.7 Static File Serving: Cache, Sendfile, and Adaptive Preload) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 415.4236 cm +q +BT 1 0 0 1 0 38 Tm .551223 Tw 12 TL /F1 10 Tf 0 0 0 rg (The HTTP demo in \24711.3 served synthesized responses. To host ) Tj /F5 10 Tf (lumbda.com) Tj /F1 10 Tf ( we needed a real static-file) Tj T* 0 Tw .579908 Tw (path \227 something that hands a 2.67 MiB PDF \(this whitepaper\) off the disk without bouncing it through the) Tj T* 0 Tw 1.830596 Tw (Scheme heap. Three variants now ship in ) Tj /F5 10 Tf (examples/) Tj /F1 10 Tf (, each ~100\226200 lines of portable Scheme, each) Tj T* 0 Tw (running on ) Tj /F5 10 Tf (asm/lumbda-gc) Tj /F1 10 Tf ( \(the GC build, 27 KB stripped\).) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 409.4236 cm +Q +q +1 0 0 1 57.02362 409.4236 cm +Q +q +1 0 0 1 57.02362 373.4236 cm +q +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 21 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F5 10 Tf 12 TL 8 0 Td (\177) Tj T* -8 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +BT 1 0 0 1 0 26 Tm .480696 Tw 12 TL /F5 10 Tf 0 0 0 rg (http-static-server.lsp) Tj /F1 10 Tf ( \227 read the file per request via ) Tj /F5 10 Tf (file-) Tj (>) Tj (string) Tj /F1 10 Tf (, build a response, send.) Tj T* 0 Tw .017397 Tw (Baseline. Correct and portable across all four tiers; every 2.67 MiB PDF round-trip allocates 2.67 MiB of) Tj T* 0 Tw (Scheme string.) Tj T* ET +Q +Q +q +Q +Q +Q +q +1 0 0 1 57.02362 367.4236 cm +Q +q +1 0 0 1 57.02362 319.4236 cm +q +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 33 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F5 10 Tf 12 TL 8 0 Td (\177) Tj T* -8 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +BT 1 0 0 1 0 38 Tm .656027 Tw 12 TL /F5 10 Tf 0 0 0 rg (http-static-server-cached.lsp) Tj /F1 10 Tf ( \227 on startup, build a hash-table keyed by URL path to the full) Tj T* 0 Tw 13.27537 Tw (pre-composed HTTP response \(headers + body\). Per-request handler is one) Tj T* 0 Tw 1.391835 Tw /F5 10 Tf (hash-table-ref/default) Tj /F1 10 Tf (. No ) Tj /F5 10 Tf (file-) Tj (>) Tj (string) Tj /F1 10 Tf (, no ) Tj /F5 10 Tf (string-append) Tj /F1 10 Tf (, no MIME lookup in the hot) Tj T* 0 Tw (path.) Tj T* ET +Q +Q +q +Q +Q +Q +q +1 0 0 1 57.02362 313.4236 cm +Q +q +1 0 0 1 57.02362 265.4236 cm +q +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 33 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F5 10 Tf 12 TL 8 0 Td (\177) Tj T* -8 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +BT 1 0 0 1 0 38 Tm 4.499835 Tw 12 TL /F5 10 Tf 0 0 0 rg (http-static-server-sendfile.lsp) Tj /F1 10 Tf ( \227 small assets \() Tj /F6 10 Tf 12 TL (\243) Tj /F1 10 Tf 12 TL ( 16 KB\) stay inline-cached as full) Tj T* 0 Tw 2.337025 Tw (responses; large assets cache only the headers and stream the body via a new ) Tj /F5 10 Tf (tcp-sendfile) Tj /F1 10 Tf T* 0 Tw 1.76218 Tw (primitive that issues the Linux ) Tj /F5 10 Tf (SYS_SENDFILE) Tj /F1 10 Tf ( \(40\) syscall directly. Zero-copy kernel ) Tj /F6 10 Tf 12 TL (\256) Tj /F1 10 Tf 12 TL ( socket, no) Tj T* 0 Tw (userspace bounce.) Tj T* ET +Q +Q +q +Q +Q +Q +q +1 0 0 1 57.02362 247.4236 cm +Q +q +1 0 0 1 57.02362 193.4236 cm +q +BT 1 0 0 1 0 38 Tm 3.259272 Tw 12 TL /F5 10 Tf 0 0 0 rg (tcp-sendfile) Tj /F1 10 Tf ( is a 90-line asm-gc builtin. It opens the path, ) Tj /F5 10 Tf (lseek) Tj /F1 10 Tf ('s to find the size, then loops) Tj T* 0 Tw 1.390522 Tw /F5 10 Tf (sendfile\(2\)) Tj /F1 10 Tf ( until the full body is written, and ) Tj /F5 10 Tf (close\(\)) Tj /F1 10 Tf ('s. The body never enters the Lumbda heap \227) Tj T* 0 Tw .243432 Tw (headers are composed in Scheme and flushed via ) Tj /F5 10 Tf (tcp-send) Tj /F1 10 Tf (, then the kernel DMAs the file directly into the) Tj T* 0 Tw (socket buffer.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 163.4236 cm +q +BT 1 0 0 1 0 14 Tm 4.109816 Tw 12 TL /F3 10 Tf 0 0 0 rg (Four-way race) Tj /F1 10 Tf ( \() Tj /F5 10 Tf (tests/bench-www-race.sh) Tj /F1 10 Tf (, i5-8350U, 1000 small requests, 100 large requests,) Tj T* 0 Tw (concurrency 8, ) Tj /F5 10 Tf (xargs) Tj ( ) Tj (-P) Tj ( ) Tj (8) Tj ( ) Tj (curl) Tj /F1 10 Tf (, adjacent runs\):) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 157.4236 cm +Q +q +1 0 0 1 57.02362 67.42362 cm +q +1 1 1 rg +n 0 90 481.2283 -18 re f* +.878431 .878431 .878431 rg +n 0 72 481.2283 -18 re f* +1 1 1 rg +n 0 54 481.2283 -18 re f* +.878431 .878431 .878431 rg +n 0 36 481.2283 -18 re f* +1 1 1 rg +n 0 18 481.2283 -18 re f* +0 0 0 rg +BT /F3 10 Tf 12 TL ET +q +1 0 0 1 6 75 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 74.68067 0 Td (Server) Tj T* -74.68067 0 Td ET +Q +Q +q +1 0 0 1 198.4913 75 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 18.78283 0 Td (PDF req/s) Tj T* -18.78283 0 Td ET +Q +Q +q +1 0 0 1 294.737 75 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 17.39783 0 Td (PDF MiB/s) Tj T* -17.39783 0 Td ET +Q +Q +q +1 0 0 1 390.9827 75 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL 18.77783 0 Td (Peak RSS) Tj T* -18.77783 0 Td ET +Q +Q +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 57 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (lumbda-www uncached) Tj T* ET +Q +Q +q +1 0 0 1 198.4913 57 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (159) Tj T* ET +Q +Q +q +1 0 0 1 294.737 57 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (404) Tj T* ET +Q +Q +q +1 0 0 1 390.9827 57 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (15.5 MB) Tj T* ET +Q +Q +q +1 0 0 1 6 39 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (lumbda-www cached) Tj T* ET +Q +Q +q +1 0 0 1 198.4913 39 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (237) Tj T* ET +Q +Q +q +1 0 0 1 294.737 39 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (602) Tj T* ET +Q +Q +q +1 0 0 1 390.9827 39 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (7.2 MB) Tj T* ET +Q +Q +q +1 0 0 1 6 21 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (lumbda-www sendfile) Tj T* ET +Q +Q +q +1 0 0 1 198.4913 21 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (474) Tj T* ET +Q +Q +q +1 0 0 1 294.737 21 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (1208) Tj T* ET +Q +Q +q +1 0 0 1 390.9827 21 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (4.2 MB) Tj T* ET +Q +Q +q +1 0 0 1 6 3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (caddy file-server \(Go\)) Tj T* ET +Q +Q +q +1 0 0 1 198.4913 3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (485) Tj T* ET +Q +Q +q +1 0 0 1 294.737 3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (1234) Tj T* ET +Q +Q +q +1 0 0 1 390.9827 3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (37.1 MB) Tj T* ET +Q +Q +q +1 J +1 j +0 0 0 RG +.25 w +n 0 72 m 481.2283 72 l S +n 0 54 m 481.2283 54 l S +n 0 36 m 481.2283 36 l S +n 0 18 m 481.2283 18 l S +n 192.4913 0 m 192.4913 90 l S +n 288.737 0 m 288.737 90 l S +n 384.9827 0 m 384.9827 90 l S +n 0 90 m 481.2283 90 l S +n 0 0 m 481.2283 0 l S +n 0 0 m 0 90 l S +n 481.2283 0 m 481.2283 90 l S +Q +Q +Q +q +1 0 0 1 57.02362 67.42362 cm +Q + +endstream +endobj +163 0 obj +<< +/Length 7203 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET +q +1 0 0 1 57.02362 717.0236 cm +q +BT 1 0 0 1 0 38 Tm -0.070097 Tw 12 TL /F1 10 Tf 0 0 0 rg (All four servers return the PDF byte-identical against the on-disk master. The sendfile path lands within 2% of) Tj T* 0 Tw -0.036403 Tw (Caddy on throughput while holding ) Tj /F3 10 Tf (9\327 less peak RSS) Tj /F1 10 Tf ( in a binary ) Tj /F3 10 Tf (1,400\327 smaller) Tj /F1 10 Tf ( \(27 KB stripped vs 38 MB\).) Tj T* 0 Tw 1.29189 Tw (Small-request throughput \() Tj /F5 10 Tf (GET) Tj ( ) Tj (/) Tj /F1 10 Tf (\) is essentially flat across the three lumbda variants \227 the cached path) Tj T* 0 Tw (already removed per-request work, so sendfile's win is entirely on large bodies.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 627.0236 cm +q +BT 1 0 0 1 0 74 Tm .177835 Tw 12 TL /F3 10 Tf 0 0 0 rg (Adaptive preload: ``http-static-server-adaptive.lsp``.) Tj /F1 10 Tf ( A hit-counter hash-table \(URL ) Tj /F6 10 Tf 12 TL (\256) Tj /F1 10 Tf 12 TL ( integer\) is updated) Tj T* 0 Tw 1.609168 Tw (every request. Every ) Tj /F4 10 Tf (N) Tj /F1 10 Tf ( requests the counter is flushed to ) Tj /F5 10 Tf (www.hits) Tj /F1 10 Tf ( as newline-delimited ) Tj /F5 10 Tf (path) Tj ( ) Tj (count) Tj /F1 10 Tf T* 0 Tw .451079 Tw (records. On startup the file is loaded, sorted descending, and the top ) Tj /F4 10 Tf (cache-max) Tj /F1 10 Tf ( URLs are preloaded \227 so) Tj T* 0 Tw 2.841575 Tw (each boot reflects what the previous run actually served. Cold start falls back to a seed list \() Tj /F5 10 Tf (/) Tj /F1 10 Tf ( and) Tj T* 0 Tw 1.316019 Tw /F5 10 Tf (/404.html) Tj /F1 10 Tf (\). Cold requests beyond the seed set are promoted into the cache on first hit until the cap is) Tj T* 0 Tw 1.39989 Tw (reached. Because this server mutates persistent state \(the counter and the cache\) on every request, the) Tj T* 0 Tw (arena-pattern ) Tj /F5 10 Tf (heap-restore) Tj /F1 10 Tf ( is dropped and the GC build's mark-sweep reclaims transients instead.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 585.0236 cm +q +BT 1 0 0 1 0 26 Tm -0.123981 Tw 12 TL /F1 10 Tf 0 0 0 rg (For small deployments \() Tj /F6 10 Tf 12 TL (\243) Tj /F1 10 Tf 12 TL ( ~1000 resources\) this is ~95% of the win of a full predictive-preload system: the top) Tj T* 0 Tw .681079 Tw (few URLs dominate traffic and get pinned at boot. Anything rarer warms on demand. The remaining 5% \227) Tj T* 0 Tw (predicting which URLs will be needed from ) Tj /F4 10 Tf (co-occurrence) Tj /F1 10 Tf ( rather than raw frequency \227 is \24713 Future Work.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 553.8236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (12. MOAD Audit: Fixing What We Built) Tj T* ET Q Q q -1 0 0 1 57.02362 408.2236 cm +1 0 0 1 57.02362 497.8236 cm q BT 1 0 0 1 0 38 Tm .158726 Tw 12 TL /F1 10 Tf 0 0 0 rg (We scanned all three implementations for the five MOADs. The taxonomy used here is defined in the ) Tj 0 .4 .6 rg (MOAD) Tj T* 0 Tw 3.384835 Tw (Cheat Sheet) Tj 0 0 0 rg ( at undefect.com \227 MOAD-0001 \(sedimentary O\(N\262\) defects\), MOAD-0002 \(intertangle\),) Tj T* 0 Tw .059816 Tw (MOAD-0003 \(context-leak\), MOAD-0004 \(stringly-typed\), MOAD-0005 \(bus-factor\). Every project contains its) Tj T* 0 Tw (own sediment.) Tj T* ET Q Q q -1 0 0 1 57.02362 318.2236 cm +1 0 0 1 57.02362 407.8236 cm q BT 1 0 0 1 0 74 Tm 7.459168 Tw 12 TL /F3 10 Tf 0 0 0 rg (Standard: what the Lean EML proof sets.) Tj /F1 10 Tf ( \2478 documents a formal Lean 4 proof that) Tj T* 0 Tw .542844 Tw /F5 10 Tf (eml\(x,) Tj ( ) Tj (y\)) Tj ( ) Tj (=) Tj ( ) Tj (exp\(x\)) Tj ( ) Tj (-) Tj ( ) Tj (ln\(y\)) Tj /F1 10 Tf ( generates every elementary function \227 and that the proof is 40\327 faster) Tj T* 0 Tw .55131 Tw (than the brute-force numerical verification it replaced. That speedup is the MOAD-0001 story in microcosm:) Tj T* 0 Tw 1.171667 Tw (algebraic understanding beats O\(N\262\) search, at the proof layer just like at every other layer. We take that) Tj T* 0 Tw .048417 Tw (standard as the bar for the implementations too. Every hot path should be fast for a ) Tj /F4 10 Tf (reason) Tj /F1 10 Tf ( \(a hash, a cache,) Tj T* 0 Tw -0.019034 Tw (an O\(1\) invariant\), not because a test didn't happen to hit the slow case. Every behavior should be correct for) Tj T* 0 Tw (a reason, not by coincidence. The audit below is where we hold ourselves to that bar.) Tj T* ET Q Q q -1 0 0 1 57.02362 204.2236 cm +1 0 0 1 57.02362 293.8236 cm q BT 1 0 0 1 0 98 Tm 1.954609 Tw 12 TL /F1 10 Tf 0 0 0 rg (We also ran the unmoad scanner on the full tree at each release. Most recent scan \(2026-04-17, post) Tj T* 0 Tw .255223 Tw (portal-over-HTTP\): 18 HIGH MOAD-0001 candidates in C and 4 MOAD-0003 candidates in Python. All 18 C) Tj T* 0 Tw 1.186796 Tw (candidates inspected individually turn out to be false positives \227 one-shot option parsing, bounded-depth) Tj T* 0 Tw .330596 Tw (ancestor walks, hash bucket chain walks \(already O\(1\) amortized\), or static 6-element tables \(e.g. ) Tj /F5 10 Tf (#\\space) Tj /F1 10 Tf T* 0 Tw 3.004862 Tw (char-literal names\). The 4 Python MOAD-0003 candidates are scanner misfires on a non-ContextVar) Tj T* 0 Tw 6.764835 Tw /F5 10 Tf (Env.set\(\)) Tj /F1 10 Tf ( method. New-work-introduced MOAD-0001: ) Tj /F3 10 Tf (zero) Tj /F1 10 Tf (. The defects fixed in this paper) Tj T* 0 Tw 2.914587 Tw (\() Tj /F5 10 Tf (intern_symbol) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (_define_record_type) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (bi_string_replace) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (_tokenize_lines) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (Env.lookup) Tj /F1 10 Tf T* 0 Tw 1.773223 Tw (shortcut\) were all surfaced by other pressures \227 benchmarks, crashes, portal exchanges \227 not by the) Tj T* 0 Tw (scanner. The scanner remains a second line; the first line is building with understanding.) Tj T* ET Q Q q -1 0 0 1 57.02362 178.2236 cm +1 0 0 1 57.02362 267.8236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (12.1 MOAD-0001: The Sedimentary Defect in Our Own Code) Tj T* ET Q Q q -1 0 0 1 57.02362 136.2236 cm +1 0 0 1 57.02362 225.8236 cm q BT 1 0 0 1 0 26 Tm 1.195596 Tw 12 TL /F1 10 Tf 0 0 0 rg (The assembly interpreter's ) Tj /F5 10 Tf (intern_symbol) Tj /F1 10 Tf ( used a linear scan through all interned symbols \227 O\(N\) per) Tj T* 0 Tw .024897 Tw (lookup, O\(N\262\) over a program's lifetime. For a program defining 34 builtins plus user symbols, every ) Tj /F5 10 Tf (define) Tj /F1 10 Tf (,) Tj T* 0 Tw (every lambda parameter, every variable reference walked the entire table.) Tj T* ET Q Q q -1 0 0 1 57.02362 118.2236 cm +1 0 0 1 57.02362 207.8236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (Before \(linear scan\)) Tj /F1 10 Tf (:) Tj T* ET Q Q q -1 0 0 1 57.02362 68.22362 cm +1 0 0 1 57.02362 109.8236 cm q q 1 0 0 1 0 0 cm @@ -10960,54 +11289,33 @@ q .662745 .662745 .662745 RG .5 w .960784 .960784 .960784 rg -n -6 -6 480.0283 40.8 re B* +n -6 -6 480.0283 88.8 re B* Q q 0 0 0 rg -BT 1 0 0 1 0 20.8 Tm /F5 8 Tf 9.6 TL (.isym_search:) Tj T* ( cmpq %rcx, %r8 # compare lengths) Tj T* ( jne .isym_next) Tj T* ET +BT 1 0 0 1 0 68.8 Tm /F5 8 Tf 9.6 TL (.isym_search:) Tj T* ( cmpq %rcx, %r8 # compare lengths) Tj T* ( jne .isym_next) Tj T* ( rep cmpsb # compare bytes) Tj T* ( je .isym_found) Tj T* (.isym_next:) Tj T* ( addq $24, %rax # next entry) Tj T* ( jmp .isym_search # O\(N\) per intern) Tj T* ET Q Q Q Q Q +q +1 0 0 1 57.02362 89.82362 cm +q +BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (After \(djb2 hash table, 1024 buckets\)) Tj /F1 10 Tf (:) Tj T* ET +Q +Q endstream endobj -161 0 obj +164 0 obj << -/Length 7971 +/Length 7846 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 703.8236 cm -q -q -1 0 0 1 0 0 cm -q -1 0 0 1 6.6 6.6 cm -q -.662745 .662745 .662745 RG -.5 w -.960784 .960784 .960784 rg -n -6 -6 480.0283 60 re B* -Q -q -0 0 0 rg -BT 1 0 0 1 0 40 Tm /F5 8 Tf 9.6 TL ( rep cmpsb # compare bytes) Tj T* ( je .isym_found) Tj T* (.isym_next:) Tj T* ( addq $24, %rax # next entry) Tj T* ( jmp .isym_search # O\(N\) per intern) Tj T* ET -Q -Q -Q -Q -Q -q -1 0 0 1 57.02362 683.8236 cm -q -BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (After \(djb2 hash table, 1024 buckets\)) Tj /F1 10 Tf (:) Tj T* ET -Q -Q -q -1 0 0 1 57.02362 605.0236 cm +1 0 0 1 57.02362 694.2236 cm q q 1 0 0 1 0 0 cm @@ -11027,32 +11335,32 @@ Q Q Q q -1 0 0 1 57.02362 549.0236 cm +1 0 0 1 57.02362 638.2236 cm q BT 1 0 0 1 0 38 Tm .721772 Tw 12 TL /F1 10 Tf 0 0 0 rg (The fix: 99 lines changed, 1024-bucket hash table with chaining. ) Tj /F3 10 Tf (2.9x faster) Tj /F1 10 Tf ( on a 2000-symbol stress test.) Tj T* 0 Tw 2.453719 Tw (On benchmarks with fewer symbols \() Tj /F5 10 Tf (ack) Tj /F1 10 Tf (, ) Tj /F5 10 Tf (fib) Tj /F1 10 Tf (\), the improvement is modest \(15% on ) Tj /F5 10 Tf (sum-to\(50k\)) Tj /F1 10 Tf (\),) Tj T* 0 Tw 1.940417 Tw (because the linear scan was already fast at small N. The fix pays off at scale \227 the same pattern as) Tj T* 0 Tw (MOAD-0001 everywhere: invisible at small inputs, catastrophic at large ones.) Tj T* ET Q Q q -1 0 0 1 57.02362 519.0236 cm +1 0 0 1 57.02362 608.2236 cm q BT 1 0 0 1 0 14 Tm 1.423486 Tw 12 TL /F1 10 Tf 0 0 0 rg (The Python implementation had a similar defect: ) Tj /F5 10 Tf (_define_record_type) Tj /F1 10 Tf ( used ) Tj /F5 10 Tf (list.index\(\)) Tj /F1 10 Tf ( for field) Tj T* 0 Tw (lookup. Replaced with a dict. O\(N\) ) Tj /F6 10 Tf 12 TL (\256) Tj /F1 10 Tf 12 TL ( O\(1\).) Tj T* ET Q Q q -1 0 0 1 57.02362 489.0236 cm +1 0 0 1 57.02362 578.2236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F3 10 Tf 12 TL 1.554556 Tw (Two more MOAD-0001 defects surfaced during the HTTP server work and were fixed in the same) Tj T* 0 Tw (pass:) Tj T* ET Q Q q -1 0 0 1 57.02362 483.0236 cm +1 0 0 1 57.02362 572.2236 cm Q q -1 0 0 1 57.02362 483.0236 cm +1 0 0 1 57.02362 572.2236 cm Q q -1 0 0 1 57.02362 447.0236 cm +1 0 0 1 57.02362 536.2236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11074,10 +11382,10 @@ Q Q Q q -1 0 0 1 57.02362 441.0236 cm +1 0 0 1 57.02362 530.2236 cm Q q -1 0 0 1 57.02362 405.0236 cm +1 0 0 1 57.02362 494.2236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11099,42 +11407,42 @@ Q Q Q q -1 0 0 1 57.02362 387.0236 cm +1 0 0 1 57.02362 476.2236 cm Q q -1 0 0 1 57.02362 309.0236 cm +1 0 0 1 57.02362 398.2236 cm q BT 1 0 0 1 0 62 Tm .226796 Tw 12 TL /F1 10 Tf 0 0 0 rg (A third correctness fix landed after the portal-over-HTTP demo exposed it: ) Tj /F5 10 Tf (lumbda.py) Tj /F1 10 Tf ('s ) Tj /F5 10 Tf (Env.lookup) Tj /F1 10 Tf ( used) Tj T* 0 Tw .794272 Tw (to short-cut from the local frame directly to the global frame before walking intermediate parents. That was) Tj T* 0 Tw .366019 Tw (fast but wrong \227 a let-loop parameter named the same as a global builtin \() Tj /F5 10 Tf (count) Tj /F1 10 Tf (, a SRFI-1 procedure\) got) Tj T* 0 Tw .949897 Tw (shadowed in reverse, the shortcut returned the global builtin instead of walking up to the loop's parameter) Tj T* 0 Tw .453797 Tw (frame. Fix: walk ) Tj /F5 10 Tf (self) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (self.p) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (...) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (global) Tj /F1 10 Tf ( in order, without any shortcut. The inline cache at) Tj T* 0 Tw /F5 10 Tf (OP_LOOKUP) Tj /F1 10 Tf ( was correspondingly tightened to validate the full chain before firing. 980 tests remained green.) Tj T* ET Q Q q -1 0 0 1 57.02362 291.0236 cm +1 0 0 1 57.02362 380.2236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Every release audit surfaces more. Writing new code is writing new sediment, unless the audit runs.) Tj T* ET Q Q q -1 0 0 1 57.02362 265.0236 cm +1 0 0 1 57.02362 354.2236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (12.2 MOAD-0002: The Intertangle in Our Own Design) Tj T* ET Q Q q -1 0 0 1 57.02362 247.0236 cm +1 0 0 1 57.02362 336.2236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (All three implementations share mutable global state between subsystems:) Tj T* ET Q Q q -1 0 0 1 57.02362 241.0236 cm +1 0 0 1 57.02362 330.2236 cm Q q -1 0 0 1 57.02362 241.0236 cm +1 0 0 1 57.02362 330.2236 cm Q q -1 0 0 1 57.02362 193.0236 cm +1 0 0 1 57.02362 282.2236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11156,10 +11464,10 @@ Q Q Q q -1 0 0 1 57.02362 187.0236 cm +1 0 0 1 57.02362 276.2236 cm Q q -1 0 0 1 57.02362 151.0236 cm +1 0 0 1 57.02362 240.2236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11181,10 +11489,10 @@ Q Q Q q -1 0 0 1 57.02362 145.0236 cm +1 0 0 1 57.02362 234.2236 cm Q q -1 0 0 1 57.02362 109.0236 cm +1 0 0 1 57.02362 198.2236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11206,62 +11514,62 @@ Q Q Q q -1 0 0 1 57.02362 91.02362 cm +1 0 0 1 57.02362 180.2236 cm Q - -endstream -endobj -162 0 obj -<< -/Length 7883 ->> -stream -1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 729.0236 cm +1 0 0 1 57.02362 138.2236 cm q BT 1 0 0 1 0 26 Tm .770556 Tw 12 TL /F1 10 Tf 0 0 0 rg (We documented these rather than refactoring them. In each case, the coupling exists for performance \(the) Tj T* 0 Tw .79631 Tw (globals are on hot paths\) or necessity \() Tj /F5 10 Tf (setjmp) Tj /F1 10 Tf ( requires thread-local state\). The documentation makes the) Tj T* 0 Tw (coupling visible so future work can decouple selectively.) Tj T* ET Q Q + +endstream +endobj +165 0 obj +<< +/Length 8288 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 703.0236 cm +1 0 0 1 57.02362 753.0236 cm q BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (12.3 Our Shared Infrastructure) Tj T* ET Q Q q -1 0 0 1 57.02362 649.0236 cm +1 0 0 1 57.02362 699.0236 cm q BT 1 0 0 1 0 38 Tm 1.468917 Tw 12 TL /F1 10 Tf 0 0 0 rg (Every MOAD we fixed in our own code is a MOAD we understand better when we find it in others. The) Tj T* 0 Tw 3.534168 Tw (sedimentary defect in ) Tj /F5 10 Tf (intern_symbol) Tj /F1 10 Tf ( is the same pattern as the sedimentary defect in Lean 4's) Tj T* 0 Tw .17985 Tw /F5 10 Tf (check_duplicated_univ_params) Tj /F1 10 Tf (. The intertangle in our global environment register is the same pattern) Tj T* 0 Tw (as the intertangle in any system that routes state through implicit globals instead of explicit parameters.) Tj T* ET Q Q q -1 0 0 1 57.02362 583.0236 cm +1 0 0 1 57.02362 633.0236 cm q BT 1 0 0 1 0 50 Tm 1.036556 Tw 12 TL /F3 10 Tf 0 0 0 rg (Our infrastructure does not extract rent from workaholics to feed gluttons.) Tj /F1 10 Tf ( A symbol table that does) Tj T* 0 Tw .025176 Tw (O\(N\) work per lookup is a workaholic node \227 it does more work than necessary on every operation, and that) Tj T* 0 Tw .250642 Tw (cost compounds through every downstream consumer. Fixing it reduces stress on our shared computational) Tj T* 0 Tw .385785 Tw (heart. The CPU cycles saved are cycles available for the next lambda, the next continuation, the next portal) Tj T* 0 Tw (resume.) Tj T* ET Q Q q -1 0 0 1 57.02362 541.0236 cm +1 0 0 1 57.02362 591.0236 cm q 0 0 0 rg BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL 3.447739 Tw (This is the permacomputer obligation: infrastructure that renews itself. Code that gets faster as we) Tj T* 0 Tw .462545 Tw (understand it better. A hash table is not an optimization \227 it is the removal of unnecessary suffering from a) Tj T* 0 Tw (system that deserves better.) Tj T* ET Q Q q -1 0 0 1 57.02362 509.8236 cm +1 0 0 1 57.02362 559.8236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (13. Future Work) Tj T* ET Q Q q -1 0 0 1 57.02362 495.8236 cm +1 0 0 1 57.02362 545.8236 cm Q q -1 0 0 1 57.02362 495.8236 cm +1 0 0 1 57.02362 545.8236 cm Q q -1 0 0 1 57.02362 471.8236 cm +1 0 0 1 57.02362 521.8236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11283,10 +11591,10 @@ Q Q Q q -1 0 0 1 57.02362 465.8236 cm +1 0 0 1 57.02362 515.8236 cm Q q -1 0 0 1 57.02362 429.8236 cm +1 0 0 1 57.02362 479.8236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11308,10 +11616,35 @@ Q Q Q q -1 0 0 1 57.02362 423.8236 cm +1 0 0 1 57.02362 473.8236 cm Q q -1 0 0 1 57.02362 399.8236 cm +1 0 0 1 57.02362 389.8236 cm +q +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 69 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F5 10 Tf 12 TL 8 0 Td (\177) Tj T* -8 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +BT 1 0 0 1 0 74 Tm .144862 Tw 12 TL /F3 10 Tf 0 0 0 rg (DAG-of-hot-paths predictive preload) Tj /F1 10 Tf (: \24711.7's adaptive server ranks by raw frequency, which pins the) Tj T* 0 Tw 5.726796 Tw (top URLs but cannot predict ) Tj /F4 10 Tf (which) Tj /F1 10 Tf ( assets co-occur. A navigation DAG \(edge weights =) Tj T* 0 Tw .980491 Tw /F5 10 Tf (P\(next) Tj ( ) Tj (=) Tj ( ) Tj (v) Tj ( ) Tj (|) Tj ( ) Tj (prev) Tj ( ) Tj (=) Tj ( ) Tj (u\)) Tj /F1 10 Tf (\) learned from referrer headers or session logs would let the boot-time) Tj T* 0 Tw 1.329168 Tw (preloader walk forward from seed nodes and warm everything within a predicted session depth. For) Tj T* 0 Tw .488726 Tw (deployments with > 1000 resources where the flat top-N is too narrow and full hot-caching is too wide,) Tj T* 0 Tw 2.366962 Tw (the DAG is the middle path. The frequency-only version in the repo today is designed to be the) Tj T* 0 Tw (single-node degenerate case \227 a DAG with no edges.) Tj T* ET +Q +Q +q +Q +Q +Q +q +1 0 0 1 57.02362 383.8236 cm +Q +q +1 0 0 1 57.02362 359.8236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11333,10 +11666,10 @@ Q Q Q q -1 0 0 1 57.02362 393.8236 cm +1 0 0 1 57.02362 353.8236 cm Q q -1 0 0 1 57.02362 369.8236 cm +1 0 0 1 57.02362 329.8236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11358,10 +11691,10 @@ Q Q Q q -1 0 0 1 57.02362 363.8236 cm +1 0 0 1 57.02362 323.8236 cm Q q -1 0 0 1 57.02362 339.8236 cm +1 0 0 1 57.02362 299.8236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11383,10 +11716,10 @@ Q Q Q q -1 0 0 1 57.02362 333.8236 cm +1 0 0 1 57.02362 293.8236 cm Q q -1 0 0 1 57.02362 321.8236 cm +1 0 0 1 57.02362 281.8236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11408,10 +11741,10 @@ Q Q Q q -1 0 0 1 57.02362 315.8236 cm +1 0 0 1 57.02362 275.8236 cm Q q -1 0 0 1 57.02362 303.8236 cm +1 0 0 1 57.02362 263.8236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11433,70 +11766,76 @@ Q Q Q q -1 0 0 1 57.02362 285.8236 cm +1 0 0 1 57.02362 245.8236 cm Q q -1 0 0 1 57.02362 254.6236 cm +1 0 0 1 57.02362 214.6236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (14. The Defect in the Model) Tj T* ET Q Q q -1 0 0 1 57.02362 234.6236 cm +1 0 0 1 57.02362 194.6236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (This paper is evidence of a problem that extends beyond any single codebase.) Tj T* ET Q Q q -1 0 0 1 57.02362 168.6236 cm +1 0 0 1 57.02362 128.6236 cm q BT 1 0 0 1 0 50 Tm .653022 Tw 12 TL /F1 10 Tf 0 0 0 rg (On April 4, 2026, ) Tj 0 .4 .6 rg (russell@unturf) Tj 0 0 0 rg ( published ) Tj 0 .4 .6 rg ("Stress on Our Shared Heart") Tj 0 0 0 rg ( \227 a systematic analysis of 1,264) Tj T* 0 Tw .998334 Tw (MOAD defects across 60+ ecosystems, 18 programming languages, with 919 patches written. The central) Tj T* 0 Tw 2.218835 Tw (finding: O\(N\262\) sedimentary defects compound across architectural layers, creating invisible performance) Tj T* 0 Tw .27131 Tw (taxation on every downstream consumer. A single bottleneck multiplies against every other bottleneck in the) Tj T* 0 Tw (dependency chain.) Tj T* ET Q Q q -1 0 0 1 57.02362 138.6236 cm +1 0 0 1 57.02362 98.62362 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .222844 Tw (On April 13--14, 2026 \227 nine days later \227 the machine learning agent that built Lumbda wrote MOAD-0001) Tj T* 0 Tw (into fresh code. Twice.) Tj T* ET Q Q q -1 0 0 1 57.02362 72.62362 cm +1 0 0 1 57.02362 68.62362 cm q -BT 1 0 0 1 0 50 Tm 1.989873 Tw 12 TL /F5 10 Tf 0 0 0 rg (intern_symbol) Tj /F1 10 Tf ( in the assembly implementation: a linear scan through all interned symbols. O\(N\) per) Tj T* 0 Tw 1.841147 Tw (lookup. The exact pattern described in "Stress on Our Shared Heart." The exact pattern the agent was) Tj T* 0 Tw 3.328647 Tw (explicitly instructed to avoid. The agent had the full MOAD taxonomy in its context window. It had) Tj T* 0 Tw 2.822739 Tw /F5 10 Tf (BLACKOPS.md) Tj /F1 10 Tf ( defining all five MOADs. It had the undefect.com mission statement. And it still wrote) Tj T* 0 Tw /F5 10 Tf (jmp) Tj ( ) Tj (.isym_search) Tj /F1 10 Tf ( instead of a hash table.) Tj T* ET +BT 1 0 0 1 0 14 Tm 1.989873 Tw 12 TL /F5 10 Tf 0 0 0 rg (intern_symbol) Tj /F1 10 Tf ( in the assembly implementation: a linear scan through all interned symbols. O\(N\) per) Tj T* 0 Tw 1.841147 Tw (lookup. The exact pattern described in "Stress on Our Shared Heart." The exact pattern the agent was) Tj T* 0 Tw ET Q Q endstream endobj -163 0 obj +166 0 obj << -/Length 6415 +/Length 6861 >> stream 1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET q -1 0 0 1 57.02362 741.0236 cm +1 0 0 1 57.02362 729.0236 cm +q +BT 1 0 0 1 0 26 Tm 3.328647 Tw 12 TL /F1 10 Tf 0 0 0 rg (explicitly instructed to avoid. The agent had the full MOAD taxonomy in its context window. It had) Tj T* 0 Tw 2.822739 Tw /F5 10 Tf (BLACKOPS.md) Tj /F1 10 Tf ( defining all five MOADs. It had the undefect.com mission statement. And it still wrote) Tj T* 0 Tw /F5 10 Tf (jmp) Tj ( ) Tj (.isym_search) Tj /F1 10 Tf ( instead of a hash table.) Tj T* ET +Q +Q +q +1 0 0 1 57.02362 699.0236 cm q BT 1 0 0 1 0 14 Tm 1.541835 Tw 12 TL /F5 10 Tf 0 0 0 rg (list.index\(\)) Tj /F1 10 Tf ( in the Python implementation's ) Tj /F5 10 Tf (_define_record_type) Tj /F1 10 Tf (: linear search for field position.) Tj T* 0 Tw (O\(N\) where O\(1\) was trivial. Same defect. Same context. Same failure.) Tj T* ET Q Q q -1 0 0 1 57.02362 723.0236 cm +1 0 0 1 57.02362 681.0236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (The commit history proves it:) Tj T* ET Q Q q -1 0 0 1 57.02362 717.0236 cm +1 0 0 1 57.02362 675.0236 cm Q q -1 0 0 1 57.02362 717.0236 cm +1 0 0 1 57.02362 675.0236 cm Q q -1 0 0 1 57.02362 705.0236 cm +1 0 0 1 57.02362 663.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11518,10 +11857,10 @@ Q Q Q q -1 0 0 1 57.02362 699.0236 cm +1 0 0 1 57.02362 657.0236 cm Q q -1 0 0 1 57.02362 687.0236 cm +1 0 0 1 57.02362 645.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11543,10 +11882,10 @@ Q Q Q q -1 0 0 1 57.02362 681.0236 cm +1 0 0 1 57.02362 639.0236 cm Q q -1 0 0 1 57.02362 669.0236 cm +1 0 0 1 57.02362 627.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11568,52 +11907,52 @@ Q Q Q q -1 0 0 1 57.02362 651.0236 cm +1 0 0 1 57.02362 609.0236 cm Q q -1 0 0 1 57.02362 633.0236 cm +1 0 0 1 57.02362 591.0236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (The defect is in the model, not the programmer.) Tj T* ET Q Q q -1 0 0 1 57.02362 579.0236 cm +1 0 0 1 57.02362 537.0236 cm q BT 1 0 0 1 0 38 Tm 5.336796 Tw 12 TL /F1 10 Tf 0 0 0 rg (Language models learn from training data. The training data contains millions of linear scans,) Tj T* 0 Tw 3.434395 Tw /F5 10 Tf (list.contains) Tj /F1 10 Tf ( calls, ) Tj /F5 10 Tf (std::find) Tj /F1 10 Tf ( inside loops, ) Tj /F5 10 Tf (array.indexOf) Tj /F1 10 Tf ( in hot paths. These patterns are) Tj T* 0 Tw .94631 Tw (statistically dominant. When a model generates code, it reproduces the dominant patterns from its training) Tj T* 0 Tw (distribution \227 including the sedimentary defects.) Tj T* ET Q Q q -1 0 0 1 57.02362 537.0236 cm +1 0 0 1 57.02362 495.0236 cm q 0 0 0 rg BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL .029897 Tw (Cantor formalized set theory in 1874. Hash tables were implemented in 1953. The O\(1\) membership test has) Tj T* 0 Tw .363241 Tw (been known for 152 years and available in every language for 73 years. Yet language models still default to) Tj T* 0 Tw (O\(N\) because O\(N\) is what most code does. The training data is the sediment.) Tj T* ET Q Q q -1 0 0 1 57.02362 495.0236 cm +1 0 0 1 57.02362 453.0236 cm q BT 1 0 0 1 0 26 Tm 2.359862 Tw 12 TL /F3 10 Tf 0 0 0 rg (This means every machine learning agent generating code today is propagating MOAD-0001 by) Tj T* 0 Tw .91789 Tw (default.) Tj /F1 10 Tf ( Not because the solutions are unknown. Not because the agents lack capability. But because the) Tj T* 0 Tw (statistical distribution of training data encodes the defect as the norm.) Tj T* ET Q Q q -1 0 0 1 57.02362 453.0236 cm +1 0 0 1 57.02362 411.0236 cm q BT 1 0 0 1 0 26 Tm .412917 Tw 12 TL /F1 10 Tf 0 0 0 rg (The fix is not to patch individual outputs. The fix is to teach models that ) Tj /F3 10 Tf (O\(1\) is the default) Tj /F1 10 Tf ( for membership) Tj T* 0 Tw 4.550556 Tw (tests, lookups, and deduplication. That ) Tj /F5 10 Tf (set\(\)) Tj /F1 10 Tf ( is not an optimization \227 it is the baseline. That) Tj T* 0 Tw /F5 10 Tf (list.contains) Tj /F1 10 Tf ( inside a loop is a defect, not a pattern.) Tj T* ET Q Q q -1 0 0 1 57.02362 411.0236 cm +1 0 0 1 57.02362 369.0236 cm q 0 0 0 rg BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL 1.790491 Tw (Until that teaching happens at the training level, every agent needs a MOAD audit pass on every code) Tj T* 0 Tw 1.596373 Tw (generation. This paper \227 with its commit history showing the defect introduced and then fixed \227 is the) Tj T* 0 Tw (evidence that the audit is necessary.) Tj T* ET Q Q q -1 0 0 1 57.02362 405.0236 cm +1 0 0 1 57.02362 363.0236 cm Q q -1 0 0 1 57.02362 363.0236 cm +1 0 0 1 57.02362 321.0236 cm q 0 0 0 rg BT /F1 10 Tf 12 TL ET @@ -11636,30 +11975,30 @@ Q Q Q q -1 0 0 1 57.02362 363.0236 cm +1 0 0 1 57.02362 321.0236 cm Q q -1 0 0 1 57.02362 333.0236 cm +1 0 0 1 57.02362 291.0236 cm q 0 0 0 rg BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.253223 Tw (The stress is real. The compound burden is measurable. And the models that generate our infrastructure) Tj T* 0 Tw (carry the defect in their weights.) Tj T* ET Q Q q -1 0 0 1 57.02362 315.0236 cm +1 0 0 1 57.02362 273.0236 cm q 0 0 0 rg BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (This paper is the proof. The commit history is the evidence. The fix starts with awareness.) Tj T* ET Q Q q -1 0 0 1 57.02362 283.8236 cm +1 0 0 1 57.02362 241.8236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (Citation) Tj T* ET Q Q q -1 0 0 1 57.02362 233.8236 cm +1 0 0 1 57.02362 191.8236 cm q q 1 0 0 1 0 0 cm @@ -11680,13 +12019,13 @@ Q Q Q q -1 0 0 1 57.02362 202.6236 cm +1 0 0 1 57.02362 160.6236 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (References) Tj T* ET Q Q q -1 0 0 1 57.02362 152.6236 cm +1 0 0 1 57.02362 110.6236 cm q q 1 0 0 1 0 0 cm @@ -11707,18 +12046,18 @@ Q Q Q q -1 0 0 1 57.02362 121.4236 cm +1 0 0 1 57.02362 79.42362 cm q BT 1 0 0 1 0 2.2 Tm 13.2 TL /F2 11 Tf .133333 .133333 .133333 rg (License) Tj T* ET Q Q q -1 0 0 1 57.02362 105.4236 cm +1 0 0 1 57.02362 63.42362 cm Q endstream endobj -164 0 obj +167 0 obj << /Length 2103 >> @@ -11733,7 +12072,7 @@ q 1 0 0 1 142.0762 3 cm q 197.0759 0 0 197.0759 0 0 cm -/FormXob.d3ecd28ca03f587d6940049748681018 Do +/FormXob.c9411fecc114c344e33ac82182b38f43 Do Q Q q @@ -11795,7 +12134,7 @@ Q endstream endobj -165 0 obj +168 0 obj << /Length 1025 >> @@ -11824,184 +12163,189 @@ Q endstream endobj -166 0 obj -<< -/Nums [ 0 167 0 R 1 168 0 R 2 169 0 R 3 170 0 R 4 171 0 R - 5 172 0 R 6 173 0 R 7 174 0 R 8 175 0 R 9 176 0 R - 10 177 0 R 11 178 0 R 12 179 0 R 13 180 0 R 14 181 0 R - 15 182 0 R 16 183 0 R 17 184 0 R 18 185 0 R 19 186 0 R - 20 187 0 R 21 188 0 R 22 189 0 R 23 190 0 R 24 191 0 R - 25 192 0 R 26 193 0 R 27 194 0 R 28 195 0 R 29 196 0 R - 30 197 0 R 31 198 0 R 32 199 0 R ] ->> -endobj -167 0 obj -<< -/S /D /St 1 ->> -endobj -168 0 obj -<< -/S /D /St 2 ->> -endobj 169 0 obj << -/S /D /St 3 +/Nums [ 0 170 0 R 1 171 0 R 2 172 0 R 3 173 0 R 4 174 0 R + 5 175 0 R 6 176 0 R 7 177 0 R 8 178 0 R 9 179 0 R + 10 180 0 R 11 181 0 R 12 182 0 R 13 183 0 R 14 184 0 R + 15 185 0 R 16 186 0 R 17 187 0 R 18 188 0 R 19 189 0 R + 20 190 0 R 21 191 0 R 22 192 0 R 23 193 0 R 24 194 0 R + 25 195 0 R 26 196 0 R 27 197 0 R 28 198 0 R 29 199 0 R + 30 200 0 R 31 201 0 R 32 202 0 R 33 203 0 R ] >> endobj 170 0 obj << -/S /D /St 4 +/S /D /St 1 >> endobj 171 0 obj << -/S /D /St 5 +/S /D /St 2 >> endobj 172 0 obj << -/S /D /St 6 +/S /D /St 3 >> endobj 173 0 obj << -/S /D /St 7 +/S /D /St 4 >> endobj 174 0 obj << -/S /D /St 8 +/S /D /St 5 >> endobj 175 0 obj << -/S /D /St 9 +/S /D /St 6 >> endobj 176 0 obj << -/S /D /St 10 +/S /D /St 7 >> endobj 177 0 obj << -/S /D /St 11 +/S /D /St 8 >> endobj 178 0 obj << -/S /D /St 12 +/S /D /St 9 >> endobj 179 0 obj << -/S /D /St 13 +/S /D /St 10 >> endobj 180 0 obj << -/S /D /St 14 +/S /D /St 11 >> endobj 181 0 obj << -/S /D /St 15 +/S /D /St 12 >> endobj 182 0 obj << -/S /D /St 16 +/S /D /St 13 >> endobj 183 0 obj << -/S /D /St 17 +/S /D /St 14 >> endobj 184 0 obj << -/S /D /St 18 +/S /D /St 15 >> endobj 185 0 obj << -/S /D /St 19 +/S /D /St 16 >> endobj 186 0 obj << -/S /D /St 20 +/S /D /St 17 >> endobj 187 0 obj << -/S /D /St 21 +/S /D /St 18 >> endobj 188 0 obj << -/S /D /St 22 +/S /D /St 19 >> endobj 189 0 obj << -/S /D /St 23 +/S /D /St 20 >> endobj 190 0 obj << -/S /D /St 24 +/S /D /St 21 >> endobj 191 0 obj << -/S /D /St 25 +/S /D /St 22 >> endobj 192 0 obj << -/S /D /St 26 +/S /D /St 23 >> endobj 193 0 obj << -/S /D /St 27 +/S /D /St 24 >> endobj 194 0 obj << -/S /D /St 28 +/S /D /St 25 >> endobj 195 0 obj << -/S /D /St 29 +/S /D /St 26 >> endobj 196 0 obj << -/S /D /St 30 +/S /D /St 27 >> endobj 197 0 obj << -/S /D /St 31 +/S /D /St 28 >> endobj 198 0 obj << -/S /D /St 32 +/S /D /St 29 >> endobj 199 0 obj << +/S /D /St 30 +>> +endobj +200 0 obj +<< +/S /D /St 31 +>> +endobj +201 0 obj +<< +/S /D /St 32 +>> +endobj +202 0 obj +<< /S /D /St 33 >> endobj +203 0 obj +<< +/S /D /St 34 +>> +endobj xref -0 200 +0 204 0000000000 65535 f 0000000061 00000 n 0000000180 00000 n @@ -12057,161 +12401,165 @@ xref 0002309800 00000 n 0002310072 00000 n 0002310280 00000 n -0002310471 00000 n -0002310662 00000 n -0002310896 00000 n +0002310488 00000 n +0002310679 00000 n +0002310870 00000 n 0002311104 00000 n -0002311278 00000 n +0002311312 00000 n 0002311486 00000 n -0002311720 00000 n -0002311926 00000 n -0002312098 00000 n -0002312332 00000 n -0002371308 00000 n -0002371618 00000 n -0002371938 00000 n +0002311694 00000 n +0002311928 00000 n +0002312134 00000 n +0002312306 00000 n +0002312540 00000 n +0002371516 00000 n +0002371826 00000 n 0002372146 00000 n -0002372254 00000 n -0002372509 00000 n -0002372584 00000 n +0002372354 00000 n +0002372462 00000 n 0002372717 00000 n -0002372827 00000 n -0002372992 00000 n -0002373187 00000 n -0002373303 00000 n -0002373421 00000 n -0002373563 00000 n -0002373763 00000 n -0002373898 00000 n -0002374047 00000 n -0002374176 00000 n -0002374346 00000 n -0002374470 00000 n -0002374601 00000 n -0002374723 00000 n -0002374920 00000 n -0002375037 00000 n -0002375164 00000 n -0002375307 00000 n -0002375473 00000 n -0002375646 00000 n -0002375824 00000 n -0002375981 00000 n -0002376133 00000 n -0002376300 00000 n -0002376465 00000 n -0002376618 00000 n -0002376805 00000 n -0002376953 00000 n -0002377110 00000 n -0002377285 00000 n -0002377482 00000 n -0002377610 00000 n -0002377756 00000 n -0002377914 00000 n -0002378061 00000 n -0002378248 00000 n -0002378369 00000 n -0002378530 00000 n -0002378672 00000 n -0002378824 00000 n -0002378978 00000 n -0002379119 00000 n -0002379257 00000 n -0002379411 00000 n -0002379613 00000 n -0002379736 00000 n -0002379875 00000 n -0002380039 00000 n -0002380212 00000 n -0002380385 00000 n -0002380532 00000 n -0002380727 00000 n -0002380886 00000 n -0002381054 00000 n -0002381189 00000 n -0002381322 00000 n -0002381467 00000 n -0002381593 00000 n -0002381721 00000 n -0002381832 00000 n -0002382128 00000 n -0002387245 00000 n -0002395329 00000 n -0002400122 00000 n -0002407051 00000 n -0002415965 00000 n -0002425212 00000 n -0002434416 00000 n -0002447433 00000 n -0002457549 00000 n -0002466915 00000 n -0002475479 00000 n -0002486430 00000 n -0002498933 00000 n -0002509546 00000 n -0002518569 00000 n -0002529250 00000 n -0002536867 00000 n -0002546455 00000 n -0002554291 00000 n -0002564562 00000 n -0002574503 00000 n -0002581020 00000 n -0002582855 00000 n -0002596311 00000 n -0002612952 00000 n -0002623460 00000 n -0002630919 00000 n -0002637593 00000 n -0002645617 00000 n -0002653553 00000 n -0002660021 00000 n -0002662177 00000 n -0002663255 00000 n -0002663659 00000 n -0002663694 00000 n -0002663729 00000 n -0002663764 00000 n -0002663799 00000 n -0002663834 00000 n -0002663869 00000 n -0002663904 00000 n -0002663939 00000 n -0002663974 00000 n -0002664010 00000 n -0002664046 00000 n -0002664082 00000 n -0002664118 00000 n -0002664154 00000 n -0002664190 00000 n -0002664226 00000 n -0002664262 00000 n -0002664298 00000 n -0002664334 00000 n -0002664370 00000 n -0002664406 00000 n -0002664442 00000 n -0002664478 00000 n -0002664514 00000 n -0002664550 00000 n -0002664586 00000 n -0002664622 00000 n -0002664658 00000 n -0002664694 00000 n -0002664730 00000 n -0002664766 00000 n -0002664802 00000 n +0002372792 00000 n +0002372925 00000 n +0002373035 00000 n +0002373200 00000 n +0002373395 00000 n +0002373511 00000 n +0002373629 00000 n +0002373771 00000 n +0002373971 00000 n +0002374106 00000 n +0002374255 00000 n +0002374384 00000 n +0002374554 00000 n +0002374678 00000 n +0002374809 00000 n +0002374931 00000 n +0002375128 00000 n +0002375245 00000 n +0002375372 00000 n +0002375515 00000 n +0002375681 00000 n +0002375854 00000 n +0002376032 00000 n +0002376189 00000 n +0002376341 00000 n +0002376508 00000 n +0002376673 00000 n +0002376826 00000 n +0002377014 00000 n +0002377163 00000 n +0002377321 00000 n +0002377496 00000 n +0002377693 00000 n +0002377821 00000 n +0002377967 00000 n +0002378125 00000 n +0002378272 00000 n +0002378459 00000 n +0002378580 00000 n +0002378741 00000 n +0002378883 00000 n +0002379035 00000 n +0002379189 00000 n +0002379330 00000 n +0002379468 00000 n +0002379622 00000 n +0002379824 00000 n +0002379947 00000 n +0002380086 00000 n +0002380250 00000 n +0002380423 00000 n +0002380596 00000 n +0002380757 00000 n +0002380925 00000 n +0002381120 00000 n +0002381279 00000 n +0002381447 00000 n +0002381582 00000 n +0002381715 00000 n +0002381860 00000 n +0002381986 00000 n +0002382114 00000 n +0002382225 00000 n +0002382528 00000 n +0002387645 00000 n +0002395729 00000 n +0002400522 00000 n +0002407451 00000 n +0002416365 00000 n +0002425612 00000 n +0002434816 00000 n +0002447833 00000 n +0002457949 00000 n +0002467315 00000 n +0002475879 00000 n +0002486830 00000 n +0002499333 00000 n +0002509946 00000 n +0002518969 00000 n +0002529650 00000 n +0002537267 00000 n +0002546855 00000 n +0002554691 00000 n +0002564962 00000 n +0002574903 00000 n +0002581420 00000 n +0002583255 00000 n +0002596711 00000 n +0002613352 00000 n +0002623860 00000 n +0002631319 00000 n +0002640361 00000 n +0002647617 00000 n +0002655516 00000 n +0002663857 00000 n +0002670771 00000 n +0002672927 00000 n +0002674005 00000 n +0002674420 00000 n +0002674455 00000 n +0002674490 00000 n +0002674525 00000 n +0002674560 00000 n +0002674595 00000 n +0002674630 00000 n +0002674665 00000 n +0002674700 00000 n +0002674735 00000 n +0002674771 00000 n +0002674807 00000 n +0002674843 00000 n +0002674879 00000 n +0002674915 00000 n +0002674951 00000 n +0002674987 00000 n +0002675023 00000 n +0002675059 00000 n +0002675095 00000 n +0002675131 00000 n +0002675167 00000 n +0002675203 00000 n +0002675239 00000 n +0002675275 00000 n +0002675311 00000 n +0002675347 00000 n +0002675383 00000 n +0002675419 00000 n +0002675455 00000 n +0002675491 00000 n +0002675527 00000 n +0002675563 00000 n +0002675599 00000 n trailer << /ID -[<256838ea1d698f91db2ad0c26a223907><256838ea1d698f91db2ad0c26a223907>] +[<1ab8e5e9ff3d8f9eff3db3ad0754f230><1ab8e5e9ff3d8f9eff3db3ad0754f230>] % ReportLab generated PDF document -- digest (opensource) -/Info 69 0 R -/Root 68 0 R -/Size 200 +/Info 70 0 R +/Root 69 0 R +/Size 204 >> startxref -2664838 +2675635 %%EOF diff --git a/whitepaper/lumbda-whitepaper.rst b/whitepaper/lumbda-whitepaper.rst index 4308f63..720045c 100644 --- a/whitepaper/lumbda-whitepaper.rst +++ b/whitepaper/lumbda-whitepaper.rst @@ -1272,6 +1272,37 @@ The snapshot is dangerously precise: anything allocated after the snap and still This is not a general-purpose allocator. It is an escape hatch the programmer uses when they can prove the scope boundary. For general programs on asm, the heap still grows. For the HTTP server pattern, O(1) memory costs two lines of code. +11.7 Static File Serving: Cache, Sendfile, and Adaptive Preload +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The HTTP demo in §11.3 served synthesized responses. To host ``lumbda.com`` we needed a real static-file path — something that hands a 2.67 MiB PDF (this whitepaper) off the disk without bouncing it through the Scheme heap. Three variants now ship in ``examples/``, each ~100–200 lines of portable Scheme, each running on ``asm/lumbda-gc`` (the GC build, 27 KB stripped). + +- ``http-static-server.lsp`` — read the file per request via ``file->string``, build a response, send. Baseline. Correct and portable across all four tiers; every 2.67 MiB PDF round-trip allocates 2.67 MiB of Scheme string. +- ``http-static-server-cached.lsp`` — on startup, build a hash-table keyed by URL path to the full pre-composed HTTP response (headers + body). Per-request handler is one ``hash-table-ref/default``. No ``file->string``, no ``string-append``, no MIME lookup in the hot path. +- ``http-static-server-sendfile.lsp`` — small assets (≤ 16 KB) stay inline-cached as full responses; large assets cache only the headers and stream the body via a new ``tcp-sendfile`` primitive that issues the Linux ``SYS_SENDFILE`` (40) syscall directly. Zero-copy kernel → socket, no userspace bounce. + +``tcp-sendfile`` is a 90-line asm-gc builtin. It opens the path, ``lseek``'s to find the size, then loops ``sendfile(2)`` until the full body is written, and ``close()``'s. The body never enters the Lumbda heap — headers are composed in Scheme and flushed via ``tcp-send``, then the kernel DMAs the file directly into the socket buffer. + +**Four-way race** (``tests/bench-www-race.sh``, i5-8350U, 1000 small requests, 100 large requests, concurrency 8, ``xargs -P 8 curl``, adjacent runs): + +.. table:: + :widths: 28 14 14 14 + + =========================== ============ ============ ============== + Server PDF req/s PDF MiB/s Peak RSS + =========================== ============ ============ ============== + lumbda-www uncached 159 404 15.5 MB + lumbda-www cached 237 602 7.2 MB + **lumbda-www sendfile** **474** **1208** **4.2 MB** + caddy file-server (Go) 485 1234 37.1 MB + =========================== ============ ============ ============== + +All four servers return the PDF byte-identical against the on-disk master. The sendfile path lands within 2% of Caddy on throughput while holding **9× less peak RSS** in a binary **1,400× smaller** (27 KB stripped vs 38 MB). Small-request throughput (``GET /``) is essentially flat across the three lumbda variants — the cached path already removed per-request work, so sendfile's win is entirely on large bodies. + +**Adaptive preload: ``http-static-server-adaptive.lsp``.** A hit-counter hash-table (URL → integer) is updated every request. Every *N* requests the counter is flushed to ``www.hits`` as newline-delimited ``path count`` records. On startup the file is loaded, sorted descending, and the top *cache-max* URLs are preloaded — so each boot reflects what the previous run actually served. Cold start falls back to a seed list (``/`` and ``/404.html``). Cold requests beyond the seed set are promoted into the cache on first hit until the cap is reached. Because this server mutates persistent state (the counter and the cache) on every request, the arena-pattern ``heap-restore`` is dropped and the GC build's mark-sweep reclaims transients instead. + +For small deployments (≤ ~1000 resources) this is ~95% of the win of a full predictive-preload system: the top few URLs dominate traffic and get pinned at boot. Anything rarer warms on demand. The remaining 5% — predicting which URLs will be needed from *co-occurrence* rather than raw frequency — is §13 Future Work. + 12. MOAD Audit: Fixing What We Built -------------------------------------- @@ -1348,6 +1379,7 @@ This is the permacomputer obligation: infrastructure that renews itself. Code th - **WebSocket / bidirectional**: HTTP/1.0 is request-response; a persistent socket loop with framing brings full-duplex feedback. - **Continuation-passing over HTTP**: §11.5 moves *bindings* over HTTP. The next step is moving a live *continuation* — serialize it via ``call/cc`` + JSON portal, transmit, resume on the remote VM. Makes any TCP endpoint a trampoline target. +- **DAG-of-hot-paths predictive preload**: §11.7's adaptive server ranks by raw frequency, which pins the top URLs but cannot predict *which* assets co-occur. A navigation DAG (edge weights = ``P(next = v | prev = u)``) learned from referrer headers or session logs would let the boot-time preloader walk forward from seed nodes and warm everything within a predicted session depth. For deployments with > 1000 resources where the flat top-N is too narrow and full hot-caching is too wide, the DAG is the middle path. The frequency-only version in the repo today is designed to be the single-node degenerate case — a DAG with no edges. - **GPU lambda execution**: Map/reduce on CUDA for data-parallel Scheme (Phase 1), trampolining for recursive lambdas (Phase 2), interaction combinators for massive parallelism (Phase 3) - **Copying GC in asm**: ``heap-snapshot`` is an escape hatch. A mark-and-copy collector would remove the sharp edge for general programs without forcing the programmer to reason about lifetimes. - **Concurrent accept loop (asm)**: Currently single-threaded. A pre-forked worker model or ``SO_REUSEPORT`` pool would multiply throughput without changing the Scheme code.