From a76da1e5daccfb2f953d98c5dcc07147040f5c5a Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 7 Jan 2022 13:06:50 -0600 Subject: [PATCH 001/168] urbit: add stubbed flow for remote scry --- pkg/urbit/vere/io/ames.c | 120 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 1773e02ed..8a1ac15e9 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -20,7 +20,14 @@ /* u3_ames: ames networking. */ typedef struct _u3_ames { // packet network state - u3_auto car_u; // driver + u3_auto car_u; // ames driver + struct { + u3_auto car_u; // fine driver + c3_y pro_y; // fine protocol + + // TODO: hashtable, stats, maybe config? etc. + } fin_s; + u3_auto van_u; // fine driver TODO: review, correct? u3_pier* pir_u; // pier union { // uv udp handle uv_udp_t wax_u; // @@ -55,9 +62,10 @@ } sat_u; // } u3_ames; -/* u3_head: ames packet header +/* u3_head: ames or fine packet header */ typedef struct _u3_head { + c3_o req_o; // is request (fine only) c3_o sim_o; // is ames protocol? c3_y ver_y; // protocol version c3_y sac_y; // sender class @@ -66,6 +74,7 @@ c3_o rel_o; // relayed? } u3_head; +/* TODO: request response bodies for scry */ /* u3_body: ames packet body */ typedef struct _u3_body { @@ -1057,6 +1066,35 @@ _ames_skip(u3_body* bod_u) { } #endif +/* _fine_hear(): hear a (potential) packet, dispatch appropriately + */ +static void _fine_hear(u3_head* hed_u) { + u3_noun* bod_u; + if(hed_u->req_o) { + // lookup in cache + // (unit (unit (unit packet)) + // ~ -> miss + // [~ ~] -> hit, unbound + // [~ ~ ~] -> hit, empty + // [~ ~ ~ *] -> hit, w/ data + if(hit) { + _fine_send(cache_res); + } else { + + u3_pier_peek_last(car_u->pir_u, u3_nul, c3__ax, u3_nul, + // TODO path for scry + sam_u, _fine_pack_scry_cb); + } + } else { + // handle response + // TODO: serialize, validate, enqueue task + // [%fund *] + + } + + +} + /* _ames_hear(): parse a (potential) packet, dispatch appropriately. */ static void @@ -1083,8 +1121,11 @@ _ames_hear(u3_ames* sam_u, // unpack header, ensuring buffer is large enough // + // + c3_o is_ames_o = _ames_sift_head(&hed_u, hun_y); + if ( (4 > len_w) - || (c3n == _ames_sift_head(&hed_u, hun_y)) ) + || (c3n == is_ames_o)) { sam_u->sat_u.hed_d++; if ( 0 == (sam_u->sat_u.hed_d % 100000) ) { @@ -1094,6 +1135,10 @@ _ames_hear(u3_ames* sam_u, c3_free(hun_y); return; + } else if ((4 > len_w) + || (c3n == is_ames_o)) { + // TODO: dispatch fine request + //_fine_hear() } // ensure the protocol version matches ours @@ -1312,6 +1357,71 @@ _ames_ef_turf(u3_ames* sam_u, u3_noun tuf) } } +/* _fine_pack_scry_cb(): receive all packets for datum out of fine + * TODO: implement + */ +static void _fine_pack_scry_cb(void* vod_p u3_noun nun) +{ + u3_ames* sam_u = vod_p; + u3_weak pack = u3r_at(3, nun); + // + // hashtable = (path, packet_num) -> cached_result; + // All cases, except 1st ~: put results in cache for all packets + // ~ -> if second request, ask for notification if 2nd, drop on floor + // [~ ~] -> send packet + // [~ ~ *] -> send packet + // + // TODO: also, maybe evict +} + +/** + * _fine_send() + */ +static void _fine_send() +{ + // TODO: deduplicate with _ames_send(); + // _fine_send_fail() + // _fine_send_cb() +} + +/* fine_io_kick:(): receive effect from arvo + * TODO: + */ +static c3_o _fine_io_kick() +{ + /** + * +task:fine + * $% [%find *] + * [%fund *] + * == + * +gift:fine + * $% [%made *] + * [%find *] + * == + */ + u3_noun hed = u3h(nun); + if(c3__made == hed) { + // TODO: respond to notification of bound data + // put in cache + return c3y; + } else if(c3__find == hed) { + // TODO: emit request packet to host ship + // _fine_io_request(); + } else { + return c3n; + } +} + +static void _fine_send_fail() +{ + // TODO: log some shit +} + +static void _fine_send_cb() +{ + // TODO: anything to do here? +} + /* _ames_prot_scry_cb(): receive protocol version */ static void @@ -1361,6 +1471,8 @@ _ames_io_talk(u3_auto* car_u) u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); } + // TODO: scry the fine protocol out of arvo + // // scry the protocol version out of arvo // @@ -1525,6 +1637,8 @@ u3_ames_io_init(u3_pier* pir_u) sam_u->fig_u.see_o = c3y; sam_u->fig_u.fit_o = c3n; + // TODO: setup hashtable for scry cache + //NOTE some numbers on memory usage for the lane cache // // assuming we store: From 81395eea3f22f121675fda270374e257d62859da Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 10 Jan 2022 09:30:53 -0600 Subject: [PATCH 002/168] urbit: genericise packet handling This commit genericises the packet handling to allow for better code sharing between fine and ames. The ames packets, requests and responses are now stored in tagged union u3_pend which contains members that should be filled out as the packet makes its way to the network --- pkg/urbit/include/c/motes.h | 2 + pkg/urbit/vere/io/ames.c | 540 ++++++++++++++++++++++++++++-------- 2 files changed, 421 insertions(+), 121 deletions(-) diff --git a/pkg/urbit/include/c/motes.h b/pkg/urbit/include/c/motes.h index cda80b557..89880d3bf 100644 --- a/pkg/urbit/include/c/motes.h +++ b/pkg/urbit/include/c/motes.h @@ -388,6 +388,7 @@ # define c3__exit c3_s4('e','x','i','t') # define c3__eyre c3_s4('e','y','r','e') # define c3__f c3_s1('f') +# define c3__fx c3_s2('f', 'x') # define c3__fab c3_s3('f','a','b') # define c3__face c3_s4('f','a','c','e') # define c3__fail c3_s4('f','a','i','l') @@ -701,6 +702,7 @@ # define c3__lunt c3_s4('l','u','n','t') # define c3__mack c3_s4('m','a','c','k') # define c3__mach c3_s4('m','a','c','h') +# define c3__made c3_s4('m','a','d','e') # define c3__main c3_s4('m','a','i','n') # define c3__make c3_s4('m','a','k','e') # define c3__malg c3_s4('m','a','l','g') diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 8a1ac15e9..a62a26605 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -22,12 +22,11 @@ typedef struct _u3_ames { // packet network state u3_auto car_u; // ames driver struct { - u3_auto car_u; // fine driver - c3_y pro_y; // fine protocol - - // TODO: hashtable, stats, maybe config? etc. + u3_auto car_u; // fine driver + c3_y ver_y; // fine protocol + u3p(u3h_root) sac_p; // scry cache hashtable + // TODO: stats, maybe config? etc. } fin_s; - u3_auto van_u; // fine driver TODO: review, correct? u3_pier* pir_u; // pier union { // uv udp handle uv_udp_t wax_u; // @@ -75,6 +74,56 @@ } u3_head; /* TODO: request response bodies for scry */ +/* u3_requ: fine packet request */ + typedef struct _u3_requ { + c3_y sig_y[64]; // requester signature + c3_w lyf_w; // requester life + c3_d her_d[2]; // requester addres + c3_w fra_w; // fragment number + c3_d hos_d[2]; // host address + c3_s len_s; // path length + c3_c* pat_c; // path as ascii + } u3_requ; + + typedef struct _u3_reqp { + u3_ames* sam_u; + u3_head hed_u; + u3_requ req_u; + } u3_reqp; + +/* u3_resp: fine packet response */ + typedef struct _u3_resp { + // request: + c3_w fra_w; // fragment number + c3_d hos_d[2]; // host address + c3_s len_s; // path length + c3_c* pat_c; // path as ascii + // response: + c3_y sig_y[64]; // host signature + c3_w lyf_w; // host life + c3_w num_w; // number of fragments + c3_s siz_s; // datum size + c3_y* dat_y; // datum (0 if null response) + } u3_resp; + + + /* u3_pend: generic ames or fine pending packet */ + typedef struct _u3_pend { + c3_y typ_y; // 0 for ames, 1 for fine request, 2 for fine response + uv_udp_send_t snd_u; // udp send request + c3_d her_d[2]; // recipent mars address + c3_c* dns_c; // galaxy FQDN + c3_y* hun_y; // packet contents + c3_w len_w; // packet contents + u3_lane lan_u; // recipient lane + u3_ames* sam_u; // ames backpointer + union { + u3_resp* res_u; + u3_reqp* req_u; + u3_pact* pac_u; + }; + } u3_pend; + /* u3_body: ames packet body */ typedef struct _u3_body { @@ -125,6 +174,22 @@ _ames_pact_free(u3_pact* pac_u) c3_free(pac_u); } +static void +_ames_pend_free(u3_pend* pen_u) +{ + if(0 == pen_u->typ_y) { // ames packet + _ames_pact_free(pen_u->pac_u); + } else if (1 == pen_u->typ_y) { // fine request + c3_free(pen_u->req_u); + c3_free(pen_u->hun_y); + } else { // fine response + c3_free(pen_u->res_u); + c3_free(pen_u->hun_y); + } + c3_free(pen_u->dns_c); + c3_free(pen_u); +} + /* _ames_panc_free(): remove references, lose refcounts and free struct */ static void @@ -158,6 +223,7 @@ _ames_sift_head(u3_head* hed_u, c3_y buf_y[4]) // first three bits are reserved // + hed_u->req_o = (hed_w >> 2) & 0x1; hed_u->sim_o = (hed_w >> 3) & 0x1; hed_u->ver_y = (hed_w >> 4) & 0x7; hed_u->sac_y = (hed_w >> 7) & 0x3; @@ -228,6 +294,115 @@ _ames_ship_of_chubs(c3_d sip_d[2], c3_y len_y, c3_y* buf_y) memcpy(buf_y, sip_y, c3_min(16, len_y)); } +/* _fine_sift_requ(): parse request body, returning success +*/ +static c3_o +_fine_sift_requ(u3_head* hed_u, + u3_requ* req_u, + c3_w len_w, + c3_y* req_y) +{ + c3_w rem_w = (64 + 4 + hed_u->sac_y + 4 + hed_u->rac_y + 2); + if(rem_w > len_w) { + return c3n; + } + memcpy(req_u->sig_y, req_y, 64); + req_y += 64; + + req_u->lyf_w = ( + (req_y[0] << 0x18) + | (req_y[1] << 0x10) + | (req_y[2] << 0x8) + | (req_y[3] << 0x0)); + req_y += 4; + + _ames_ship_to_chubs(req_u->her_d, hed_u->sac_y, req_y); + req_y += hed_u->sac_y; + + req_u->fra_w = ( + (req_y[0] << 0x18) + | (req_y[1] << 0x10) + | (req_y[2] << 0x8) + | (req_y[3] << 0x0)); + req_y += 4; + + _ames_ship_to_chubs(req_u->hos_d, hed_u->rac_y, req_y); + req_y += hed_u->rac_y; + + + req_u->len_s = c3_min(384, + (req_y[0] << 0x8) + | (req_y[1] << 0x0)); + req_y += 2; + + // TODO: strict inequality? + if(rem_w + req_u->len_s != len_w) { + return c3n; + } + + // TODO: defend maliciusly crafted lengths? + req_u->pat_c = c3_malloc(req_u->len_s + 1); + + memcpy(req_u->pat_c, req_y, req_u->len_s); + req_u->pat_c[req_u->len_s] = '\0'; + // TODO: add null terminator? + return c3y; +} + +/* _fine_sift_resp(): parse response body, returning success +*/ +static c3_o +_fine_sift_resp(u3_head* hed_u, + u3_resp* res_u, + c3_w len_w, + c3_y* res_y) +{ + c3_w rem_w = (64 + 4 + hed_u->sac_y + 4 + hed_u->rac_y + 2); + if(rem_w > len_w) { + return c3n; + } + memcpy(res_u->sig_y, res_y, 64); + res_y += 64; + + res_u->lyf_w = ( + (res_y[0] << 0x18) + | (res_y[1] << 0x10) + | (res_y[2] << 0x8) + | (res_y[3] << 0x0)); + res_y += 4; + + _ames_ship_to_chubs(res_u->hos_d, hed_u->sac_y, res_y); + res_y += hed_u->sac_y; + + res_u->fra_w = ( + (res_y[0] << 0x18) + | (res_y[1] << 0x10) + | (res_y[2] << 0x8) + | (res_y[3] << 0x0)); + res_y += 4; + + _ames_ship_to_chubs(res_u->hos_d, hed_u->rac_y, res_y); + res_y += hed_u->rac_y; + + + res_u->len_s = c3_min(384, + (res_y[0] << 0x8) + | (res_y[1] << 0x0)); + res_y += 2; + + // TODO: strict inequality? + if(rem_w + res_u->len_s != len_w) { + return c3n; + } + + // TODO: defend maliciusly crafted lengths? + res_u->pat_c = c3_malloc(res_u->len_s); + + memcpy(res_u->pat_c, res_y, res_u->len_s); + // TODO: add null terminator? + return c3y; +} + /* _ames_sift_body(): parse packet body. */ static c3_o @@ -282,7 +457,8 @@ _ames_sift_body(u3_head* hed_u, static void _ames_etch_head(u3_head* hed_u, c3_y buf_y[4]) { - c3_w hed_w = ((hed_u->sim_o & 0x1) << 3) + c3_w hed_w = ((hed_u->req_o & 0x1) << 2) + ^ ((hed_u->sim_o & 0x1) << 3) ^ ((hed_u->ver_y & 0x7) << 4) ^ ((hed_u->sac_y & 0x3) << 7) ^ ((hed_u->rac_y & 0x3) << 9) @@ -345,42 +521,45 @@ _ames_etch_pack(u3_head* hed_u, static void _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) { - u3_pact* pac_u = (u3_pact*)req_u; - u3_ames* sam_u = pac_u->sam_u; + //u3_pend* pen_u = (u3_pend*)req_u; + //u3_ames* sam_u = pen_u->sam_u; - if ( sas_i && (c3y == sam_u->fig_u.net_o) ) { + if (sas_i) { u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); - sam_u->fig_u.net_o = c3n; + //sam_u->fig_u.net_o = c3n; } else { - sam_u->fig_u.net_o = c3y; + //sam_u->fig_u.net_o = c3y; } - _ames_pact_free(pac_u); + //_ames_pend_free(pen_u); } +#define _fine_send _ames_send /* _ames_send(): send buffer to address on port. */ static void -_ames_send(u3_pact* pac_u) +_ames_send(u3_pend* pen_u) { - u3_ames* sam_u = pac_u->sam_u; + u3_ames* sam_u = pen_u->sam_u; - if ( !pac_u->hun_y ) { - _ames_pact_free(pac_u); - return; + + // TODO: prevalidation? + /*if ( !pen_u->hun_y ) { + // _ames_pact_free(pac_u); + //return; } - else { + else */ { struct sockaddr_in add_u; memset(&add_u, 0, sizeof(add_u)); add_u.sin_family = AF_INET; - add_u.sin_addr.s_addr = htonl(pac_u->lan_u.pip_w); - add_u.sin_port = htons(pac_u->lan_u.por_s); + add_u.sin_addr.s_addr = htonl(pen_u->lan_u.pip_w); + add_u.sin_port = htons(pen_u->lan_u.por_s); { - uv_buf_t buf_u = uv_buf_init((c3_c*)pac_u->hun_y, pac_u->len_w); - c3_i sas_i = uv_udp_send(&pac_u->snd_u, + uv_buf_t buf_u = uv_buf_init((c3_c*)pen_u->hun_y, pen_u->len_w); + c3_i sas_i = uv_udp_send(&pen_u->snd_u, &sam_u->wax_u, &buf_u, 1, (const struct sockaddr*)&add_u, @@ -392,7 +571,7 @@ _ames_send(u3_pact* pac_u) sam_u->fig_u.net_o = c3n; } - _ames_pact_free(pac_u); + _ames_pend_free(pen_u); } } } @@ -520,53 +699,55 @@ _ames_czar_port(c3_y imp_y) /* _ames_czar_gone(): galaxy address resolution failed. */ static void -_ames_czar_gone(u3_pact* pac_u, time_t now) +_ames_czar_gone(u3_pend* pen_u, time_t now) { - u3_ames* sam_u = pac_u->sam_u; + u3_ames* sam_u = pen_u->sam_u; + c3_d imp_d = pen_u->her_d[0]; - if ( c3y == sam_u->imp_o[pac_u->imp_y] ) { - u3l_log("ames: czar at %s: not found (b)\n", pac_u->dns_c); - sam_u->imp_o[pac_u->imp_y] = c3n; + if ( c3y == sam_u->imp_o[imp_d] ) { + u3l_log("ames: czar at %s: not found (b)\n", pen_u->dns_c); + sam_u->imp_o[imp_d] = c3n; } - if ( (0 == sam_u->imp_w[pac_u->imp_y]) || - (0xffffffff == sam_u->imp_w[pac_u->imp_y]) ) + if ( (0 == sam_u->imp_w[imp_d]) || + (0xffffffff == sam_u->imp_w[imp_d]) ) { - sam_u->imp_w[pac_u->imp_y] = 0xffffffff; + sam_u->imp_w[imp_d] = 0xffffffff; } // keep existing ip for 5 more minutes // - sam_u->imp_t[pac_u->imp_y] = now; + sam_u->imp_t[imp_d] = now; - _ames_pact_free(pac_u); + _ames_pend_free(pen_u); } /* _ames_czar_here(): galaxy address resolution succeeded. */ static void -_ames_czar_here(u3_pact* pac_u, time_t now, struct sockaddr_in* add_u) +_ames_czar_here(u3_pend* pen_u, time_t now, struct sockaddr_in* add_u) { - u3_ames* sam_u = pac_u->sam_u; - c3_w old_w = sam_u->imp_w[pac_u->imp_y]; + u3_ames* sam_u = pen_u->sam_u; + c3_y imp_y = pen_u->her_d[0]; + c3_w old_w = sam_u->imp_w[imp_y]; c3_w pip_w = ntohl(add_u->sin_addr.s_addr); if ( pip_w != old_w ) { u3_noun nam = u3dc("scot", c3__if, u3i_word(pip_w)); c3_c* nam_c = u3r_string(nam); - u3l_log("ames: czar %s: ip %s\n", pac_u->dns_c, nam_c); + u3l_log("ames: czar %s: ip %s\n", pen_u->dns_c, nam_c); c3_free(nam_c); u3z(nam); } - sam_u->imp_w[pac_u->imp_y] = pip_w; - sam_u->imp_t[pac_u->imp_y] = now; - sam_u->imp_o[pac_u->imp_y] = c3y; + sam_u->imp_w[imp_y] = pip_w; + sam_u->imp_t[imp_y] = now; + sam_u->imp_o[imp_y] = c3y; - pac_u->lan_u.pip_w = pip_w; - _ames_send(pac_u); + pen_u->lan_u.pip_w = pip_w; + _ames_send(pen_u); } /* _ames_czar_cb(): galaxy address resolution callback. @@ -577,13 +758,13 @@ _ames_czar_cb(uv_getaddrinfo_t* adr_u, struct addrinfo* aif_u) { { - u3_pact* pac_u = (u3_pact*)adr_u->data; + u3_pend* pen_u = (u3_pend*)adr_u->data; struct addrinfo* rai_u = aif_u; time_t now = time(0); while ( rai_u ) { if ( (AF_INET == rai_u->ai_family) ) { - _ames_czar_here(pac_u, now, (struct sockaddr_in *)rai_u->ai_addr); + _ames_czar_here(pen_u, now, (struct sockaddr_in *)rai_u->ai_addr); break; } else { @@ -592,7 +773,7 @@ _ames_czar_cb(uv_getaddrinfo_t* adr_u, } if ( !rai_u ) { - _ames_czar_gone(pac_u, now); + _ames_czar_gone(pen_u, now); } } @@ -603,22 +784,26 @@ _ames_czar_cb(uv_getaddrinfo_t* adr_u, /* _ames_czar(): galaxy address resolution. */ static void -_ames_czar(u3_pact* pac_u) +_ames_czar(u3_pend* pen_u) { - u3_ames* sam_u = pac_u->sam_u; + u3_ames* sam_u = pen_u->sam_u; - pac_u->lan_u.por_s = _ames_czar_port(pac_u->imp_y); + c3_d imp_d = pen_u->her_d[0]; + + c3_assert( imp_d < 256 ); + + pen_u->lan_u.por_s = _ames_czar_port(imp_d); if ( c3n == u3_Host.ops_u.net ) { - pac_u->lan_u.pip_w = 0x7f000001; - _ames_send(pac_u); + pen_u->lan_u.pip_w = 0x7f000001; + _ames_send(pen_u); return; } // if we don't have a galaxy domain, no-op // if ( !sam_u->dns_c ) { - u3_noun nam = u3dc("scot", 'p', pac_u->imp_y); + u3_noun nam = u3dc("scot", 'p', pen_u->her_d[0]); c3_c* nam_c = u3r_string(nam); u3l_log("ames: no galaxy domain for %s, no-op\r\n", nam_c); @@ -628,8 +813,8 @@ _ames_czar(u3_pact* pac_u) } { - c3_w pip_w = sam_u->imp_w[pac_u->imp_y]; - time_t wen = sam_u->imp_t[pac_u->imp_y]; + c3_w pip_w = sam_u->imp_w[imp_d]; + time_t wen = sam_u->imp_t[imp_d]; time_t now = time(0); // backoff for 5 minutes after failed lookup @@ -638,27 +823,27 @@ _ames_czar(u3_pact* pac_u) || ( (0xffffffff == pip_w) // sentinal ip address && ((now - wen) < 300) ) ) { - _ames_pact_free(pac_u); + _ames_pend_free(pen_u); return; } // cached addresses have a 5 minute TTL // else if ( (0 != pip_w) && ((now - wen) < 300) ) { - pac_u->lan_u.pip_w = pip_w; - _ames_send(pac_u); + pen_u->lan_u.pip_w = pip_w; + _ames_send(pen_u); return; } else { c3_i sas_i; { - u3_noun nam = u3dc("scot", 'p', pac_u->imp_y); + u3_noun nam = u3dc("scot", 'p', imp_d); c3_c* nam_c = u3r_string(nam); // NB: . separator not counted, as [nam_c] includes a ~ that we skip // - pac_u->dns_c = c3_malloc(1 + strlen(nam_c) + strlen(sam_u->dns_c)); - sas_i = snprintf(pac_u->dns_c, 255, "%s.%s", nam_c + 1, sam_u->dns_c); + pen_u->dns_c = c3_malloc(1 + strlen(nam_c) + strlen(sam_u->dns_c)); + sas_i = snprintf(pen_u->dns_c, 255, "%s.%s", nam_c + 1, sam_u->dns_c); c3_free(nam_c); u3z(nam); @@ -666,20 +851,20 @@ _ames_czar(u3_pact* pac_u) if ( 255 <= sas_i ) { u3l_log("ames: czar: galaxy domain %s truncated\n", sam_u->dns_c); - _ames_pact_free(pac_u); + _ames_pend_free(pen_u); return; } { uv_getaddrinfo_t* adr_u = c3_malloc(sizeof(*adr_u)); - adr_u->data = pac_u; + adr_u->data = pen_u; if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u, _ames_czar_cb, - pac_u->dns_c, 0, 0)) ) + pen_u->dns_c, 0, 0)) ) { u3l_log("ames: %s\n", uv_strerror(sas_i)); - _ames_czar_gone(pac_u, now); + _ames_czar_gone(pen_u, now); return; } } @@ -703,6 +888,14 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) pac_u->len_w = u3r_met(3, pac); pac_u->hun_y = c3_malloc(pac_u->len_w); + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + pen_u->typ_y = 0; + pen_u->len_w = pac_u->len_w; + pen_u->hun_y = pac_u->hun_y; + pen_u->sam_u = sam_u; + + + u3r_bytes(0, pac_u->len_w, pac_u->hun_y, pac); u3_noun tag, val; @@ -716,7 +909,7 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) c3_assert( val < 256 ); pac_u->imp_y = val; - _ames_czar(pac_u); + _ames_czar(pen_u); } // non-galaxy lane // @@ -741,8 +934,8 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) // otherwise, mutate destination and send packet // else { - pac_u->lan_u = lan_u; - _ames_send(pac_u); + pen_u->lan_u = lan_u; + _ames_send(pen_u); } } u3z(lan); u3z(pac); @@ -1066,33 +1259,131 @@ _ames_skip(u3_body* bod_u) { } #endif +/* _fine_pack_scry_cb(): receive all packets for datum out of fine + * TODO: implement + */ +static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) +{ + u3_pend* pen_u = vod_p; + u3_weak pack = u3r_at(3, nun); + // + // hashtable = (path, packet_num) -> cached_result; + // All cases, except 1st ~: put results in cache for all packets + // ~ -> if second request, ask for notification if 2nd, drop on floor + // [~ ~] -> send packet + // [~ ~ *] -> send packet + // TODO: cache logic, counting requests, evict? + + u3_weak lan = _ames_lane_from_cache(pen_u->sam_u->lax_p, + u3i_chubs(2, pen_u->her_d)); + if(u3_none == lan) { + // TODO: enqueue packet for later sending, populate lane cache + } else if(u3_nul == lan) { + // TODO: no lane, drop packet + } else { + + + + _fine_send(pen_u); + } +} + + + /* _fine_hear(): hear a (potential) packet, dispatch appropriately */ -static void _fine_hear(u3_head* hed_u) { - u3_noun* bod_u; - if(hed_u->req_o) { +// _fine_hear(sam_u, lan_u, len_w, hun_y) +static void _fine_hear(u3_ames* sam_u, + u3_lane lan_u, + c3_w len_w, + c3_y* hun_y) +{ + u3_head hed_u; + //u3_body bod_u; + c3_o val_o = _ames_sift_head(&hed_u, hun_y); + if(c3y == val_o) { + // invalid, maybe crash? + // + return; + } + // skip past header + len_w -= 4; + hun_y += 4; + + if(hed_u.req_o) { // lookup in cache // (unit (unit (unit packet)) // ~ -> miss // [~ ~] -> hit, unbound // [~ ~ ~] -> hit, empty // [~ ~ ~ *] -> hit, w/ data - if(hit) { - _fine_send(cache_res); - } else { + u3_requ req_u; + + + _fine_sift_requ(&hed_u, &req_u, len_w, hun_y); + + u3_noun pat = u3i_string(req_u.pat_c); + + u3_weak cac = u3h_git(sam_u->fin_s.sac_p, pat); + + if(u3_none == cac) { + // cache miss + // packet scry path + // /packet/requested/path/elements/ + // + // eg: + // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10/20 + // (fragment num is 20) + // + u3_noun pax = u3dc("snoc", + u3do("stab", u3i_string(req_u.pat_c)), + u3i_words(1, &req_u.fra_w)); + u3_reqp* rep_u = c3_malloc(sizeof(*rep_u)); + rep_u->sam_u = sam_u; + memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); + memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); + + u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, + u3nc(u3i_string("packet"), pax), rep_u, _fine_pack_scry_cb); + + } else if(u3_nul == cac) { + // cache hit, unbound + // do nothing, maybe report? + } else { + u3_noun hit = u3t(cac); + + // + u3_resp res; + // _fine_etch_resp(); + + //_fine_send(); + - u3_pier_peek_last(car_u->pir_u, u3_nul, c3__ax, u3_nul, - // TODO path for scry - sam_u, _fine_pack_scry_cb); } } else { - // handle response - // TODO: serialize, validate, enqueue task - // [%fund *] + u3_resp res_u; + _fine_sift_resp(&hed_u, &res_u, len_w, hun_y); + u3_noun pat = u3do("stab", u3i_string(res_u.pat_c)); + + + // + // + u3_noun wir = u3nc(c3__fine, u3_nul); + c3_w num_w = res_u.num_w; + c3_w fra_w = res_u.fra_w; + u3_noun cad = u3nq(c3__fund, + pat, + u3i_words(1, &fra_w), + u3nc(u3i_words(1, &res_u.num_w), + u3i_bytes(res_u.siz_s, res_u.dat_y))); + + + u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, wir, cad); + u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); + + // TODO: moar stats? } - - } /* _ames_hear(): parse a (potential) packet, dispatch appropriately. @@ -1103,6 +1394,7 @@ _ames_hear(u3_ames* sam_u, c3_w len_w, c3_y* hun_y) { + // TODO: move from stack to heap to avoid reparsing u3_head hed_u; u3_body bod_u; @@ -1124,9 +1416,7 @@ _ames_hear(u3_ames* sam_u, // c3_o is_ames_o = _ames_sift_head(&hed_u, hun_y); - if ( (4 > len_w) - || (c3n == is_ames_o)) - { + if (4 > len_w) { sam_u->sat_u.hed_d++; if ( 0 == (sam_u->sat_u.hed_d % 100000) ) { u3l_log("ames: %" PRIu64 " dropped, failed to read header\n", @@ -1135,10 +1425,10 @@ _ames_hear(u3_ames* sam_u, c3_free(hun_y); return; - } else if ((4 > len_w) - || (c3n == is_ames_o)) { + } + else if (c3n == is_ames_o) { // TODO: dispatch fine request - //_fine_hear() + //_fine_hear(sam_u, lan_u, len_w, hun_y) } // ensure the protocol version matches ours @@ -1193,7 +1483,7 @@ _ames_hear(u3_ames* sam_u, // and we are not the recipient, // we might want to forward statelessly // - if ( (c3y == sam_u->fig_u.see_o) + if ( 0 && (c3y == sam_u->fig_u.see_o) && ( (bod_u.rec_d[0] != sam_u->pir_u->who_d[0]) || (bod_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) { @@ -1357,46 +1647,19 @@ _ames_ef_turf(u3_ames* sam_u, u3_noun tuf) } } -/* _fine_pack_scry_cb(): receive all packets for datum out of fine - * TODO: implement - */ -static void _fine_pack_scry_cb(void* vod_p u3_noun nun) -{ - u3_ames* sam_u = vod_p; - u3_weak pack = u3r_at(3, nun); - // - // hashtable = (path, packet_num) -> cached_result; - // All cases, except 1st ~: put results in cache for all packets - // ~ -> if second request, ask for notification if 2nd, drop on floor - // [~ ~] -> send packet - // [~ ~ *] -> send packet - // - // TODO: also, maybe evict -} - -/** - * _fine_send() - */ -static void _fine_send() -{ - // TODO: deduplicate with _ames_send(); - // _fine_send_fail() - // _fine_send_cb() -} /* fine_io_kick:(): receive effect from arvo * TODO: */ -static c3_o _fine_io_kick() -{ +static c3_o _fine_io_kick(u3_noun nun) { /** * +task:fine - * $% [%find *] - * [%fund *] + * $% [%find *] :: request + * [%fund =path frag-num=@ud frag-tot=@ud contents=@] * == * +gift:fine - * $% [%made *] - * [%find *] + * $% [%made *] :: notification + * [%find =lane =path] :: request packet to unix * == */ u3_noun hed = u3h(nun); @@ -1407,6 +1670,7 @@ static c3_o _fine_io_kick() } else if(c3__find == hed) { // TODO: emit request packet to host ship // _fine_io_request(); + return c3y; } else { return c3n; } @@ -1422,7 +1686,7 @@ static void _fine_send_cb() // TODO: anything to do here? } -/* _ames_prot_scry_cb(): receive protocol version +/* _ames_prot_scry_cb(): receive ames protocol version */ static void _ames_prot_scry_cb(void* vod_p, u3_noun nun) @@ -1451,6 +1715,33 @@ _ames_prot_scry_cb(void* vod_p, u3_noun nun) u3z(nun); } +/* _fine_prot_scry_cb(): receive fine protocol version +*/ +static void +_fine_prot_scry_cb(void* vod_p, u3_noun nun) +{ + u3_ames* sam_u = vod_p; + u3_weak ver = u3r_at(7, nun); + + if ( u3_none == ver ) { + // assume protocol version 0 + // + sam_u->fin_s.ver_y = 0; + } + else if ( (c3n == u3a_is_cat(ver)) + || (7 < ver) ) { + u3m_p("fine: strange protocol", nun); + sam_u->fin_s.ver_y = 0; + } + else { + sam_u->fin_s.ver_y = ver; + } + + u3z(nun); +} + + + /* _ames_io_talk(): start receiving ames traffic. */ static void @@ -1473,6 +1764,9 @@ _ames_io_talk(u3_auto* car_u) } // TODO: scry the fine protocol out of arvo // + u3_pier_peek_last(car_u->pir_u, u3_nul, c3__fx, u3_nul, + u3nt(u3i_string("protocol"), u3i_string("version"), u3_nul), + sam_u, _fine_prot_scry_cb); // scry the protocol version out of arvo // @@ -1637,7 +1931,11 @@ u3_ames_io_init(u3_pier* pir_u) sam_u->fig_u.see_o = c3y; sam_u->fig_u.fit_o = c3n; - // TODO: setup hashtable for scry cache + // hashtable for scry cache + // TODO: review size + // 1500 bytes per packet * 100_000 = 150MB + // 50 bytes (average) per path * 100_000 = 5MB + sam_u->fin_s.sac_p = u3h_new_cache(100000); //NOTE some numbers on memory usage for the lane cache // From d5616fd88f9f227c674401f8d177fd9c586b69eb Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 10 Jan 2022 10:56:23 -0600 Subject: [PATCH 003/168] urbit: fix positioning of libuv handler --- pkg/urbit/vere/io/ames.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index a62a26605..18d2c8c61 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -109,8 +109,8 @@ /* u3_pend: generic ames or fine pending packet */ typedef struct _u3_pend { - c3_y typ_y; // 0 for ames, 1 for fine request, 2 for fine response uv_udp_send_t snd_u; // udp send request + c3_y typ_y; // 0 for ames, 1 for fine request, 2 for fine response c3_d her_d[2]; // recipent mars address c3_c* dns_c; // galaxy FQDN c3_y* hun_y; // packet contents @@ -521,15 +521,15 @@ _ames_etch_pack(u3_head* hed_u, static void _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) { - //u3_pend* pen_u = (u3_pend*)req_u; - //u3_ames* sam_u = pen_u->sam_u; + u3_pend* pen_u = (u3_pend*)req_u; + u3_ames* sam_u = pen_u->sam_u; if (sas_i) { u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); - //sam_u->fig_u.net_o = c3n; + sam_u->fig_u.net_o = c3n; } else { - //sam_u->fig_u.net_o = c3y; + sam_u->fig_u.net_o = c3y; } //_ames_pend_free(pen_u); @@ -541,9 +541,9 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) static void _ames_send(u3_pend* pen_u) { + u3l_log("ames: send"); u3_ames* sam_u = pen_u->sam_u; - // TODO: prevalidation? /*if ( !pen_u->hun_y ) { // _ames_pact_free(pac_u); @@ -559,6 +559,7 @@ _ames_send(u3_pend* pen_u) { uv_buf_t buf_u = uv_buf_init((c3_c*)pen_u->hun_y, pen_u->len_w); + c3_i sas_i = uv_udp_send(&pen_u->snd_u, &sam_u->wax_u, &buf_u, 1, @@ -909,6 +910,7 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) c3_assert( val < 256 ); pac_u->imp_y = val; + pen_u->her_d[0] = val; _ames_czar(pen_u); } // non-galaxy lane @@ -1281,9 +1283,6 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) } else if(u3_nul == lan) { // TODO: no lane, drop packet } else { - - - _fine_send(pen_u); } } @@ -1394,6 +1393,8 @@ _ames_hear(u3_ames* sam_u, c3_w len_w, c3_y* hun_y) { + + u3l_log("ames: hear"); // TODO: move from stack to heap to avoid reparsing u3_head hed_u; u3_body bod_u; From 355f05753fa46c1121d4d54e95be8256dd66f5b0 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 14 Jan 2022 00:22:56 +0100 Subject: [PATCH 004/168] fine: remote scry Implements a WIP version of %fine, the remote scry vane. Plenty of work remains to be done here, marked by TODOs and REVIEWs. --- pkg/arvo/sys/arvo.hoon | 2 +- pkg/arvo/sys/lull.hoon | 38 ++++++ pkg/arvo/sys/vane/fine.hoon | 259 ++++++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 pkg/arvo/sys/vane/fine.hoon diff --git a/pkg/arvo/sys/arvo.hoon b/pkg/arvo/sys/arvo.hoon index a0cbfcc2c..2e8660544 100644 --- a/pkg/arvo/sys/arvo.hoon +++ b/pkg/arvo/sys/arvo.hoon @@ -1675,7 +1675,7 @@ %c %clay %d %dill %e %eyre - %f %ford + %f %fine %g %gall %i %iris %j %jael diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 2e457aa4c..379f6f14b 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1627,6 +1627,36 @@ +$ user knot :: username -- ::eyre :: :::: +:::: ++fine :: (1f) remote scry + :: :::: +++ fine ^? + |% + +$ gift :: to arvo: + $% [%tune =path =(cask)] :: found at path + ::TODO add task to clay (& gall?) for declaring notify desire + :: :: to vere: + [%hoot =lane:ames =hoot] :: request packet + [%howl =path =song] :: full response + == :: + :: :: + +$ task :: from arvo: + $% [%keen =path] :: data request + [%yawn =path] :: cancel request + :: :: from unix: + ::TODO add ames task for updating lane + [%purr [from=ship =lane:ames] =purr] :: data packet + [%bide =path] :: await %howl + :: :: generic: + $>(%born vane-task) :: new unix process + $>(%trim vane-task) :: trim state + $>(%vega vane-task) :: report upgrade + == :: + :: :: + +$ hoot @uxhoot :: request packet + +$ purr @uxpurr :: response packet + +$ song (list purr) :: full response + -- ::fine +:: :::: :::: ++gall :: (1g) extensions :: :::: ++ gall ^? @@ -2120,6 +2150,7 @@ [%c task:clay] [%d task:dill] [%e task:eyre] + [%f task:fine] [%g task:gall] [%i task:iris] [%j task:jael] @@ -2141,6 +2172,7 @@ [%clay gift:clay] [%dill gift:dill] [%eyre gift:eyre] + [%fine gift:fine] [%gall gift:gall] [%iris gift:iris] [%jael gift:jael] @@ -2196,5 +2228,11 @@ :: %behn: wakeup :: $>(%wake task:behn) + :: %fine: hear packet + :: + $>(%purr task:fine) + :: %fine: await datum + :: + $>(%bide task:fine) == -- :: diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon new file mode 100644 index 000000000..d746d5d23 --- /dev/null +++ b/pkg/arvo/sys/vane/fine.hoon @@ -0,0 +1,259 @@ +:: %fine, remote scries +!: +:: +=, fine +|= our=ship +=> |% + +$ move [p=duct q=(wite note gift)] + +$ note :: out request $-> + $% $: %b ::TODO to self + $>(%wait task:behn) :: set timer + == == :: + +$ sign + $% [%fine $>(%tune gift)] + [%fine $>(%hoot gift)] + [%fine $>(%howl gift)] + == + :: + +$ fine-state + $: %0 + hear=(jug path duct) :: awaiting existence + want=(jug path duct) :: awaiting response + part=(map path [size=@ud =song]) :: partial responses + ::TODO cache? full=(map path (cask *)) + == + :: + ::TODO types for unpacked packets? + :: + +$ bits [w=@ud d=@] + ++ protocol-version %0 + -- +:: +~% %fine ..part ~ +:: +=| fine-state +=* state - +|= [now=@da eny=@uvJ rof=roof] +=* fine-gate . +=> |% + ++ spit + |= =path + ^- [pat=@t wid=@ud] + =+ pat=(spat path) + =+ wid=(met 3 pat) + ?> (lte wid 384) ::TODO check when we handle %keen, instead of here? + [pat wid] + :: + ++ meet ::NOTE from ames, but bits instead of bytes + |= =ship + ^- [size=@ rank=@ub] + =/ size=@ (met 3 ship) + ?: (lte size 2) [16 %0b0] + ?: (lte size 4) [32 %0b1] + ?: (lte size 8) [64 %0b10] + [128 %0b11] + :: + ++ header + |= [for=ship req=? bod=@ rel=?] + ^- bits + =+ him=(meet our) + =+ her=(meet for) + =+ sum=(end [0 20] (mug bod)) + :- 32 + %+ can 0 + :~ 2^0 :: reserved + 1^req :: request or response + 1^| :: not ames + 3^protocol-version :: protocol version + 2^size.him :: sender address size + 2^size.her :: receiver address size + 20^sum :: checksum + 1^rel :: relayed + == + :: + ++ prelude + |= [for=[=ship =life] =life origin=(unit lane:ames)] + ^- bits + =+ him=(meet our) + =+ her=(meet ship.for) + =/ ore=bits + ?. ?=([~ %| *] origin) 0^0 + (mul 8 (met 3 p.u.origin))^p.u.origin + :- :(add 4 4 size.him size.her w.ore) + %+ can 0 + :~ 4^(mod life 16) :: sender life + 4^(mod life.for 16) :: receiver life + size.him^our :: sender + size.her^ship.for :: receiver + ore + == + :: + ++ request-body + |= [=path num=@ud] + ^- bits + ?> (lth num (bex 32)) + =+ (spit path) + :- :(add 32 16 (mul 8 wid)) + %+ can 0 + :~ 32^num :: fragment number + 16^wid :: path size + (mul 8 wid)^`@`pat :: namespace path + == + :: + ++ packetize-request + |= [=path num=@ud] + ^- hoot + =+ bod=(request-body path num) + (can 0 512^(sign:sign d.bod) bod ~) + :: + ++ packetize-response + |= [=path data=(unit (cask *))] + ^- song + :: prepend request descriptions to each response packet + :: + =; pacs=(list bits) + %- head + %^ spin pacs 1 + |= [pac=bits num=@ud] + ^- [purr _num] + :_ +(num) + ::NOTE we stub out the receiver & origin details, + :: runtime should replace them as appropriate. + =/ pre=bits (prelude [*ship *life] life:sign ~) + =/ req=bits (request-body path num) + =/ bod=bits [:(add w.pre w.req w.pac) (can 0 pre req pac ~)] + =/ hed=bits (header *ship | +.bod |) + (can 0 hed bod ~) + :: prepend a signature and split the data into 1024-byte fragments + :: + =/ frag=(list @) + =/ sig=@ (sign path (fall data ~)) + ?~ data [sig]~ + %+ rip 3^1.024 ::TODO prints "rip: stub" + (cat 3 sig (jam u.data)) ::REVIEW + =/ size=@ud + ?~(data 0 (lent frag)) ::REVIEW + :: sign & packetize the fragments + :: + %+ turn frag + |= dat=@ + =/ wid=@ud (met 3 dat) + :- :(add 512 32 16 (mul 8 wid)) + %+ can 0 + :~ 512^(sign:sign dat) :: signature + 32^size :: number of fragments + 16^wid :: response data size in bytes ::REVIEW + (mul 8 wid)^dat :: response data + == + :: + ++ sign + |^ |= [=path mess=*] + !! + ::TODO compiler bug here? + :: (sign (shax (jam [our life path mess]))) + :: + ++ life ~+ (jael ^life %life /[(scot %p our)]) + ++ ring ~+ (jael ^ring %vein /[(scot %ud life)]) + ++ sign sign:as:(nol:nu:crub:crypto ring) + :: + ++ jael + |* [=mold =desk =path] + !< mold + %- tail %- need %- need + (rof `[our ~ ~] [%jael %$] [our desk da+now] path) + -- + -- +^? +|% +:: +call: handle a +task:fine request +:: +++ call + ~% %fine-call ..part ~ + |= $: hen=duct + dud=(unit goof) + wrapped-task=(hobo task) + == + ^- [(list move) _fine-gate] + :: + =/ =task ((harden task) wrapped-task) + :: + ?^ dud + ~|(%fine-call-dud (mean -.task tang.u.dud)) + :: + =^ moves state + ?- -.task + %keen !! ::TODO emit request packet + %yawn !! + :: + %purr !! + %bide [~ state(hear (~(put ju hear) path.task hen))] + :: + %born [~ state(hear ~)] ::REVIEW assuming this is for runtime use only? + %trim [~ state] ::TODO maybe clear part? + %vega [~ state] + == + [~ fine-gate] +:: +load: migrate an old state to a new fine version +:: +++ load + |= old=fine-state + ^+ fine-gate + fine-gate(state old) +:: +scry: get packets +:: +:: /fx/message/[full-scry-path] song all packets for some scry path +:: +++ scry + ^- roon + |= [lyc=gang car=term bem=beam] + ^- (unit (unit cage)) + ::TODO don't special-case whey scry + :: + ?: &(=(car %$) =(s.bem /whey)) + =/ maz=(list mass) + :~ state+&+state + == + ``mass+!>(maz) + :: only respond for the local identity, %$ desk, current timestamp + :: + ?. ?& =(our p.bem) + =(%$ q.bem) + =([%da now] r.bem) + == + ~ + :: + ?. ?=(%x car) ~ + ?. ?=([%message @ *] s.bem) ~ + :: s.bem is expected to be a scry path of the shape /vc/desk/rev/etc, + :: so we need to give it the right shape + :: + =/ pax=path + [i.t.s.bem (scot %p our) t.t.s.bem] + ?~ nom=(de-omen pax) [~ ~] + :: we only support scrying into clay, and only if the data is fully public + :: + ?. =(%c (end 3 (snag 0 pax))) ~ + =+ pem=(rof lyc (need (de-omen %cp (slag 1 pax)))) + ?~ pem ~ + ?~ u.pem ~ + =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) + ?. =([%black ~ ~] rul.r.per) ~ + :: scry out the data from clay and packetize it as appropriate + :: + =+ res=(rof lyc u.nom) + ?- res + ~ ~ + [~ ~] ``noun+!>((packetize-response pax ~)) + [~ ~ *] ``noun+!>((packetize-response pax `[p q.q]:u.u.res)) + == +:: +++ stay state +++ take + |= [tea=wire hen=duct dud=(unit goof) hin=sign] + ^- [(list move) _fine-gate] + ?^ dud + ~|(%fine-take-dud (mean tang.u.dud)) + :: + ::TODO + [~ fine-gate] +-- From fa9c4016aa9ae5c9190bb3c883263a05243740b2 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 14 Jan 2022 13:50:15 +0100 Subject: [PATCH 005/168] fine: work around compiler bug --- pkg/arvo/sys/vane/fine.hoon | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index d746d5d23..de21f2e4e 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -104,7 +104,7 @@ |= [=path num=@ud] ^- hoot =+ bod=(request-body path num) - (can 0 512^(sign:sign d.bod) bod ~) + (can 0 512^(sign:sign-fine d.bod) bod ~) :: ++ packetize-response |= [=path data=(unit (cask *))] @@ -119,7 +119,7 @@ :_ +(num) ::NOTE we stub out the receiver & origin details, :: runtime should replace them as appropriate. - =/ pre=bits (prelude [*ship *life] life:sign ~) + =/ pre=bits (prelude [*ship *life] life:sign-fine ~) =/ req=bits (request-body path num) =/ bod=bits [:(add w.pre w.req w.pac) (can 0 pre req pac ~)] =/ hed=bits (header *ship | +.bod |) @@ -127,7 +127,7 @@ :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) - =/ sig=@ (sign path (fall data ~)) + =/ sig=@ (sign-fine path (fall data ~)) ?~ data [sig]~ %+ rip 3^1.024 ::TODO prints "rip: stub" (cat 3 sig (jam u.data)) ::REVIEW @@ -140,17 +140,15 @@ =/ wid=@ud (met 3 dat) :- :(add 512 32 16 (mul 8 wid)) %+ can 0 - :~ 512^(sign:sign dat) :: signature - 32^size :: number of fragments - 16^wid :: response data size in bytes ::REVIEW - (mul 8 wid)^dat :: response data + :~ 512^(sign:sign-fine dat) :: signature + 32^size :: number of fragments + 16^wid :: response data size in bytes ::REVIEW + (mul 8 wid)^dat :: response data == :: - ++ sign + ++ sign-fine ::TODO +sign, except compiler bug |^ |= [=path mess=*] - !! - ::TODO compiler bug here? - :: (sign (shax (jam [our life path mess]))) + (sign (shax (jam [our life path mess]))) :: ++ life ~+ (jael ^life %life /[(scot %p our)]) ++ ring ~+ (jael ^ring %vein /[(scot %ud life)]) From d1c97ef7e7d3e70b0daefe4e29127c0ba432fcee Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 13 Jan 2022 12:46:47 -0600 Subject: [PATCH 006/168] urbit: add ames prelude struct --- pkg/urbit/vere/io/ames.c | 218 ++++++++++++++++++++++++--------------- 1 file changed, 137 insertions(+), 81 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 18d2c8c61..4b6101933 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -72,16 +72,24 @@ c3_l mug_l; // truncated mug hash of u3_body c3_o rel_o; // relayed? } u3_head; + +/* u3_prel: ames/fine packet prelude +*/ + typedef struct _u3_prel { + c3_y sic_y; // sender life tick + c3_y ric_y; // receiver life tick + c3_d sen_d[2]; // sender + c3_d rec_d[2]; // receiver + c3_d rog_d; // origin lane (optional) + } u3_prel; /* TODO: request response bodies for scry */ /* u3_requ: fine packet request */ typedef struct _u3_requ { - c3_y sig_y[64]; // requester signature - c3_w lyf_w; // requester life - c3_d her_d[2]; // requester addres - c3_w fra_w; // fragment number - c3_d hos_d[2]; // host address - c3_s len_s; // path length + u3_prel pre_u; + c3_y sig_y[64]; // requester signature + c3_w fra_w; // fragment number + c3_s len_s; // path length c3_c* pat_c; // path as ascii } u3_requ; @@ -117,7 +125,7 @@ c3_w len_w; // packet contents u3_lane lan_u; // recipient lane u3_ames* sam_u; // ames backpointer - union { + union { u3_resp* res_u; u3_reqp* req_u; u3_pact* pac_u; @@ -127,14 +135,10 @@ /* u3_body: ames packet body */ typedef struct _u3_body { - c3_d sen_d[2]; // sender - c3_d rec_d[2]; // receiver - c3_y sic_y; // sender life tick - c3_y ric_y; // receiver life tick - c3_s con_s; // content size - c3_y* con_y; // content - c3_d rog_d; // origin lane (optional) - c3_l mug_l; // checksum + u3_prel pre_u; // prelude + c3_s con_s; // content size + c3_y* con_y; // content + c3_l mug_l; // checksum } u3_body; /* u3_panc: deconstructed incoming packet @@ -294,7 +298,42 @@ _ames_ship_of_chubs(c3_d sip_d[2], c3_y len_y, c3_y* buf_y) memcpy(buf_y, sip_y, c3_min(16, len_y)); } +/* _ames_sift_prelude(): parse prelude, returning length +*/ +static c3_y +_ames_sift_prelude(u3_head* hed_u, + u3_prel* pre_u, + c3_w len_w, + c3_y* pre_y) +{ + c3_y rog_y, sen_y, rec_y, len_y; + + rog_y = ( c3y == hed_u->rel_o )? 6 : 0; + sen_y = 2 << hed_u->sac_y; + rec_y = 2 << hed_u->rac_y; + len_y = rog_y + sen_y + rec_y; + + pre_u->sic_y = pre_y[0] & 0xf; + pre_u->ric_y = pre_y[0] & 0xf0; + + _ames_ship_to_chubs(pre_u->sen_d, sen_y, pre_y + 1); + _ames_ship_to_chubs(pre_u->rec_d, rec_y, pre_y + 1 + sen_y); + + if (rog_y) { + c3_y rag_y[8] = {0}; + memcpy(rag_y, pre_y + 1 + sen_y + rec_y, rog_y); + pre_u->rog_d = _ames_chub_bytes(rag_y); + } + else { + pre_u->rog_d = 0; + } + return len_y; +} + + + /* _fine_sift_requ(): parse request body, returning success + * TODO: bring up to date */ static c3_o _fine_sift_requ(u3_head* hed_u, @@ -309,14 +348,8 @@ _fine_sift_requ(u3_head* hed_u, memcpy(req_u->sig_y, req_y, 64); req_y += 64; - req_u->lyf_w = ( - (req_y[0] << 0x18) - | (req_y[1] << 0x10) - | (req_y[2] << 0x8) - | (req_y[3] << 0x0)); req_y += 4; - _ames_ship_to_chubs(req_u->her_d, hed_u->sac_y, req_y); req_y += hed_u->sac_y; req_u->fra_w = ( @@ -326,8 +359,8 @@ _fine_sift_requ(u3_head* hed_u, | (req_y[3] << 0x0)); req_y += 4; - _ames_ship_to_chubs(req_u->hos_d, hed_u->rac_y, req_y); - req_y += hed_u->rac_y; + //_ames_ship_to_chubs(req_u->hos_d, hed_u->rac_y, req_y); + //req_y += hed_u->rac_y; req_u->len_s = c3_min(384, @@ -411,42 +444,19 @@ _ames_sift_body(u3_head* hed_u, c3_w len_w, c3_y* bod_y) { - c3_y rog_y, sen_y, rec_y; + c3_y rog_y = ( c3y == hed_u->rel_o )? 6 : 0; + c3_y* gob_y = bod_y + rog_y; + c3_s gob_s = len_w - rog_y; - rog_y = ( c3y == hed_u->rel_o )? 6 : 0; + c3_y pre_y = _ames_sift_prelude(hed_u, &bod_u->pre_u, len_w, bod_y); - sen_y = 2 << hed_u->sac_y; - rec_y = 2 << hed_u->rac_y; - - if ( (1 + sen_y + rec_y + rog_y) >= len_w ) { + if (pre_y >= len_w ) { return c3n; } else { - c3_y* gob_y; - c3_s gob_s; - - if ( rog_y) { - c3_y rag_y[8] = {0}; - memcpy(rag_y, bod_y, rog_y); - bod_u->rog_d = _ames_chub_bytes(rag_y); - } - else { - bod_u->rog_d = 0; - } - - gob_y = bod_y + rog_y; - gob_s = len_w - rog_y; - bod_u->mug_l = u3r_mug_bytes(gob_y, gob_s) & 0xfffff; - bod_u->sic_y = gob_y[0] & 0xf; - bod_u->ric_y = (gob_y[0] >> 4) & 0xf; - - _ames_ship_to_chubs(bod_u->sen_d, sen_y, gob_y + 1); - _ames_ship_to_chubs(bod_u->rec_d, rec_y, gob_y + 1 + sen_y); - - bod_u->con_s = gob_s - 1 - sen_y - rec_y; - bod_u->con_y = gob_y + 1 + sen_y + rec_y; + bod_u->con_y = gob_y + 4; return c3y; } @@ -475,6 +485,63 @@ _ames_etch_head(u3_head* hed_u, c3_y buf_y[4]) buf_y[3] = (hed_w >> 24) & 0xff; } +/* _ames_etch_prelude(): serialize packet prelude +*/ +static c3_y +_ames_etch_prelude(u3_head* hed_u, u3_prel* pre_u, c3_y* buf_y) +{ + c3_y rog_y = ( c3y == hed_u->rel_o ) ? 6 : 0; // origin len + c3_y sen_y = 2 << pre_u->sic_y; + c3_y rec_y = 2 << pre_u->ric_y; + c3_y len_y = sen_y + rec_y + rog_y; + + + // copy lives + buf_y[0] = (pre_u->sic_y & 0xf) ^ ((pre_u->ric_y & 0xf) << 4); + + _ames_ship_of_chubs(pre_u->sen_d, sen_y, buf_y + 1); + _ames_ship_of_chubs(pre_u->rec_d, rec_y, buf_y + 1 + sen_y); + + if ( rog_y ) { + c3_y rag_y[8] = {0}; + _ames_bytes_chub(rag_y, pre_u->rog_d); + memcpy(buf_y, rag_y, rog_y); + } + return len_y; +} + +/* _fine_etch_resp(): serialise response packet + */ +static c3_w +_fine_etch_resp(u3_head* hed_u, + u3_resp* res_u, + c3_y** out_y) +{ + c3_assert(0 == hed_u->req_o); + c3_assert(0 == hed_u->sim_o); + + c3_y sen_y = 2 << hed_u->sac_y; // sender len + c3_y rec_y = 2 << hed_u->rac_y; // receiver len + c3_y len_w = 80 + sen_y + rec_y + res_u->siz_s + res_u->len_s; + + c3_y* pac_y = c3_calloc(len_w); + c3_w* pac_w = (c3_w*)pac_y; + + memcpy(pac_w, &res_u->fra_w, 4); + *pac_w = res_u->fra_w; // TODO: check byte order + _ames_ship_of_chubs(res_u->hos_d, sen_y, pac_y + 4); + + *(pac_y + sen_y + 4) = (0xff << 0) & res_u->len_s; + *(pac_y + sen_y + 5) = (0xff << 1) & res_u->len_s; + + memcpy(pac_y + sen_y + 6, res_u->pat_c, res_u->len_s); + + memcpy(pac_y + sen_y + 6 + res_u->len_s, &res_u->sig_y, 64 + 4 + 4 + 2); + + return len_w; +} + + /* _ames_etch_pack(): serialize packet header and body. */ static c3_w @@ -484,33 +551,21 @@ _ames_etch_pack(u3_head* hed_u, { c3_y sen_y = 2 << hed_u->sac_y; // sender len c3_y rec_y = 2 << hed_u->rac_y; // receiver len - c3_y rog_y = ( c3y == hed_u->rel_o )? 6 : 0; // origin len + c3_y rog_y = ( c3y == hed_u->rel_o ) ? 6 : 0; // origin len c3_w bod_w = rog_y + 1 + sen_y + rec_y + bod_u->con_s; // body len c3_w len_w = 4 + bod_w; // packet len c3_y* pac_y = c3_malloc(len_w); // output buf c3_y* bod_y = pac_y + 4; // body cursor - c3_y* gob_y = bod_y + rog_y; // after origin // serialize the head // _ames_etch_head(hed_u, pac_y); - // serialize the origin, if present - // - if ( rog_y ) { - c3_y rag_y[8] = {0}; - _ames_bytes_chub(rag_y, bod_u->rog_d); - memcpy(bod_y, rag_y, rog_y); - } + c3_y pre_y = _ames_etch_prelude(hed_u, &bod_u->pre_u, bod_y + 4); + c3_y* gob_y = bod_y + pre_y; // after origin // serialize the body - // - gob_y[0] = (bod_u->sic_y & 0xf) ^ ((bod_u->ric_y & 0xf) << 4); - - _ames_ship_of_chubs(bod_u->sen_d, sen_y, gob_y + 1); - _ames_ship_of_chubs(bod_u->rec_d, rec_y, gob_y + 1 + sen_y); - - memcpy(gob_y + 1 + sen_y + rec_y, bod_u->con_y, bod_u->con_s); + memcpy(gob_y, bod_u->con_y, bod_u->con_s); *out_y = pac_y; return len_w; @@ -660,11 +715,11 @@ _ames_serialize_packet(u3_panc* pac_u, c3_o dop_o) // if ( c3y == dop_o && c3n == pac_u->hed_u.rel_o - && !( ( 256 > pac_u->bod_u.sen_d[0] ) - && ( 0 == pac_u->bod_u.sen_d[1] ) ) ) + && !( ( 256 > pac_u->bod_u.pre_u.sen_d[0] ) + && ( 0 == pac_u->bod_u.pre_u.sen_d[1] ) ) ) { pac_u->hed_u.rel_o = c3y; - pac_u->bod_u.rog_d = u3_ames_lane_to_chub(pac_u->ore_u); + pac_u->bod_u.pre_u.rog_d = u3_ames_lane_to_chub(pac_u->ore_u); } // serialize the packet @@ -1051,8 +1106,8 @@ _ames_forward(u3_panc* pac_u, u3_noun las) } if ( u3C.wag_w & u3o_verbose ) { - u3_noun sen = u3dc("scot", 'p', u3i_chubs(2, pac_u->bod_u.sen_d)); - u3_noun rec = u3dc("scot", 'p', u3i_chubs(2, pac_u->bod_u.rec_d)); + u3_noun sen = u3dc("scot", 'p', u3i_chubs(2, pac_u->bod_u.pre_u.sen_d)); + u3_noun rec = u3dc("scot", 'p', u3i_chubs(2, pac_u->bod_u.pre_u.rec_d)); c3_c* sen_c = u3r_string(sen); c3_c* rec_c = u3r_string(rec); c3_y* pip_y = (c3_y*)&pac_u->ore_u.pip_w; @@ -1136,7 +1191,7 @@ _ames_lane_scry_cb(void* vod_p, u3_noun nun) // cache the scry result for later use // _ames_lane_into_cache(sam_u->lax_p, - u3i_chubs(2, pac_u->bod_u.rec_d), + u3i_chubs(2, pac_u->bod_u.pre_u.rec_d), u3k(las)); // if there is no lane, drop the packet @@ -1167,15 +1222,15 @@ _ames_try_forward(u3_ames* sam_u, // if the recipient is a galaxy, their lane is always &+~gax // - if ( (256 > bod_u->rec_d[0]) - && (0 == bod_u->rec_d[1]) ) + if ( (256 > bod_u->pre_u.rec_d[0]) + && (0 == bod_u->pre_u.rec_d[1]) ) { - lac = u3nc(c3y, (c3_y)bod_u->rec_d[0]); + lac = u3nc(c3y, (c3_y)bod_u->pre_u.rec_d[0]); } // otherwise, try to get the lane from cache // else { - lac = _ames_lane_from_cache(sam_u->lax_p, u3i_chubs(2, bod_u->rec_d)); + lac = _ames_lane_from_cache(sam_u->lax_p, u3i_chubs(2, bod_u->pre_u.rec_d)); // if we don't know the lane, and the scry queue is full, // just drop the packet @@ -1233,7 +1288,7 @@ _ames_try_forward(u3_ames* sam_u, else { sam_u->sat_u.foq_d++; u3_noun pax = u3nq(u3i_string("peers"), - u3dc("scot", 'p', u3i_chubs(2, bod_u->rec_d)), + u3dc("scot", 'p', u3i_chubs(2, bod_u->pre_u.rec_d)), u3i_string("forward-lane"), u3_nul); u3_pier_peek_last(sam_u->pir_u, u3_nul, c3__ax, @@ -1468,6 +1523,7 @@ _ames_hear(u3_ames* sam_u, // ensure the mug is valid // + u3l_log("bod: %ux, hed: %ux\n", hed_u.mug_l, bod_u.mug_l); if ( bod_u.mug_l != hed_u.mug_l ) { sam_u->sat_u.mut_d++; if ( 0 == (sam_u->sat_u.mut_d % 100000) ) { @@ -1485,8 +1541,8 @@ _ames_hear(u3_ames* sam_u, // we might want to forward statelessly // if ( 0 && (c3y == sam_u->fig_u.see_o) - && ( (bod_u.rec_d[0] != sam_u->pir_u->who_d[0]) - || (bod_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) + && ( (bod_u.pre_u.rec_d[0] != sam_u->pir_u->who_d[0]) + || (bod_u.pre_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) { _ames_try_forward(sam_u, lan_u, &hed_u, &bod_u, hun_y); } From 207dc91c8cf13762b043d290211ed19b839f9559 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 19 Jan 2022 12:35:54 +0100 Subject: [PATCH 007/168] fine: wip, add packet deserializing logic Also stub our some flows, add todos, etc. Bit of a mess, follow-up soon. --- pkg/arvo/sys/vane/fine.hoon | 276 ++++++++++++++++++++++++++++++++---- 1 file changed, 251 insertions(+), 25 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index de21f2e4e..a4adad268 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -1,26 +1,43 @@ :: %fine, remote scries !: :: +::TODO jael does ames-specific behavior for %public-keys gifts(?). +:: should it do something similar for fine? +:: =, fine |= our=ship => |% +$ move [p=duct q=(wite note gift)] +$ note :: out request $-> - $% $: %b ::TODO to self - $>(%wait task:behn) :: set timer - == == :: + $% $: %b + $% $>(%wait task:behn) + $>(%rest task:behn) + == == + $: %j + $% $>(%private-keys task:jael) + $>(%public-keys task:jael) + == == == +$ sign - $% [%fine $>(%tune gift)] - [%fine $>(%hoot gift)] - [%fine $>(%howl gift)] - == + $% $: %behn + $% $>(%wake gift:behn) + == == + $: %fine + $% $>(%tune gift) + $>(%hoot gift) + $>(%howl gift) + == == + $: %jael + $% $>(%private-keys gift:jael) + $>(%public-keys gift:jael) + == == == + :: + ::TODO get pubkeys from jael in the same way ames does :: +$ fine-state $: %0 hear=(jug path duct) :: awaiting existence want=(jug path duct) :: awaiting response - part=(map path [size=@ud =song]) :: partial responses - ::TODO cache? full=(map path (cask *)) + part=(map path [siz=@ud pac=(map @ud @)]) :: partial responses == :: ::TODO types for unpacked packets? @@ -104,7 +121,7 @@ |= [=path num=@ud] ^- hoot =+ bod=(request-body path num) - (can 0 512^(sign:sign-fine d.bod) bod ~) + (can 0 512^(sign:keys d.bod) bod ~) :: ++ packetize-response |= [=path data=(unit (cask *))] @@ -119,7 +136,7 @@ :_ +(num) ::NOTE we stub out the receiver & origin details, :: runtime should replace them as appropriate. - =/ pre=bits (prelude [*ship *life] life:sign-fine ~) + =/ pre=bits (prelude [*ship *life] life:keys ~) =/ req=bits (request-body path num) =/ bod=bits [:(add w.pre w.req w.pac) (can 0 pre req pac ~)] =/ hed=bits (header *ship | +.bod |) @@ -127,7 +144,7 @@ :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) - =/ sig=@ (sign-fine path (fall data ~)) + =/ sig=@ (full:keys path (fall data ~)) ?~ data [sig]~ %+ rip 3^1.024 ::TODO prints "rip: stub" (cat 3 sig (jam u.data)) ::REVIEW @@ -140,18 +157,20 @@ =/ wid=@ud (met 3 dat) :- :(add 512 32 16 (mul 8 wid)) %+ can 0 - :~ 512^(sign:sign-fine dat) :: signature + :~ 512^(sign:keys dat) :: signature 32^size :: number of fragments 16^wid :: response data size in bytes ::REVIEW (mul 8 wid)^dat :: response data == :: - ++ sign-fine ::TODO +sign, except compiler bug - |^ |= [=path mess=*] - (sign (shax (jam [our life path mess]))) + ++ keys + |% + ++ full + |= [=path mess=*] + (sign (shax (jam [our life path mess]))) :: - ++ life ~+ (jael ^life %life /[(scot %p our)]) - ++ ring ~+ (jael ^ring %vein /[(scot %ud life)]) + ++ life ~+ (jael ^life %life /(scot %p our)) + ++ ring ~+ (jael ^ring %vein /(scot %ud life)) ++ sign sign:as:(nol:nu:crub:crypto ring) :: ++ jael @@ -159,7 +178,168 @@ !< mold %- tail %- need %- need (rof `[our ~ ~] [%jael %$] [our desk da+now] path) + :: + ++ lyfe + |= who=ship + (jael (unit ^life) %lyfe /(scot %p our)) + :: + ::TODO don't scry! subscribe & get from state instead + ++ pass + |= [who=ship lyf=^life] + ::TODO but might fail need checks? + :: (jael * %deed ) + !! -- + :: + :: + ::TODO copied from ames + +$ dyad [sndr=ship rcvr=ship] + +$ packet + $: dyad + sndr-tick=@ubC + rcvr-tick=@ubC + origin=(unit @uxaddress) + content=@uxcontent + == + :: + ::TODO copied from ames, only req parsing added + ++ decode-packet + ~/ %decode-packet + |= blob=@ux + ^- [req=? packet] + ~| %decode-packet-fail + :: first 32 (2^5) bits are header; the rest is body + :: + =/ header (end 5 blob) + =/ body (rsh 5 blob) + :: read header; first two bits are reserved + :: + :- req==(0 (cut 0 [2 1] header)) + =/ is-ames (cut 0 [3 1] header) + ?: =(& is-ames) + ~| %fine-but-ames !! + :: + =/ version (cut 0 [4 3] header) + ?. =(protocol-version version) + ~| fine-protocol-version+version !! + :: + =/ sndr-size (decode-ship-size (cut 0 [7 2] header)) + =/ rcvr-size (decode-ship-size (cut 0 [9 2] header)) + =/ checksum (cut 0 [11 20] header) + =/ relayed (cut 0 [31 1] header) + :: origin, if present, is 6 octets long, at the end of the body + :: + =^ origin=(unit @) body + ?: =(| relayed) + [~ body] + =/ len (sub (met 3 body) 6) + [`(end [3 6] body) (rsh [3 6] body)] + :: .checksum does not apply to the origin + :: + ?. =(checksum (end [0 20] (mug body))) + ~| %ames-checksum !! + :: read fixed-length sndr and rcvr life data from body + :: + :: These represent the last four bits of the sender and receiver + :: life fields, to be used for quick dropping of honest packets to + :: or from the wrong life. + :: + =/ sndr-tick (cut 0 [0 4] body) + =/ rcvr-tick (cut 0 [4 4] body) + :: read variable-length .sndr and .rcvr addresses + :: + =/ off 1 + =^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)] + ?. (is-valid-rank sndr sndr-size) + ~| ames-sender-impostor+[sndr sndr-size] !! + :: + =^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)] + ?. (is-valid-rank rcvr rcvr-size) + ~| ames-receiver-impostor+[rcvr rcvr-size] !! + :: read variable-length .content from the rest of .body + :: + =/ content (cut 3 [off (sub (met 3 body) off)] body) + [[sndr rcvr] sndr-tick rcvr-tick origin content] + :: +decode-ship-size: decode a 2-bit ship type specifier into a byte width + :: + :: Type 0: galaxy or star -- 2 bytes + :: Type 1: planet -- 4 bytes + :: Type 2: moon -- 8 bytes + :: Type 3: comet -- 16 bytes + :: + ++ decode-ship-size + ~/ %decode-ship-size + |= rank=@ubC + ^- @ + :: + ?+ rank !! + %0b0 2 + %0b1 4 + %0b10 8 + %0b11 16 + == + :: +is-valid-rank: does .ship match its stated .size? + :: + ++ is-valid-rank + ~/ %is-valid-rank + |= [=ship size=@ubC] + ^- ? + .= size + ?- (clan:title ship) + %czar 2 + %king 2 + %duke 4 + %earl 8 + %pawn 16 + == + :: + +$ twit :: signed request + $: signature=@ + peep + == + :: + +$ peep :: request data + $: =path + num=@ud + == + :: + +$ rawr :: response data + $: sig=@ + siz=@ud + wid=@ud + dat=@ + == + :: + ++ decode-request + |= =hoot + ^- twit + :- sig=(cut 0 [0 512] hoot) + -:(decode-request-info (rsh [0 512] hoot)) + :: + ++ decode-request-info + |= =hoot + ^- [=peep =purr] + =+ num=(cut 0 [0 32] hoot) + =+ len=(cut 0 [32 16] hoot) + =+ pat=(cut 3 [6 len] hoot) + :- [(stab pat) num] + :: if there is data remaining, it's the response + (rsh [3 (add 6 len)] hoot) + :: + ++ decode-response + |= =purr + =; =rawr + ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] + rawr + :* sig=(cut 0 [0 512] purr) + siz=(cut 0 [512 32] purr) + wid=(cut 0 [544 16] purr) + dat=(rsh 0^560 purr) + == + :: + ++ verify-response + |= rawr + !! -- ^? |% @@ -180,15 +360,61 @@ :: =^ moves state ?- -.task - %keen !! ::TODO emit request packet - %yawn !! + %keen + :- ~ ::TODO emit request packet + state(want (~(put ju want) path.task hen)) :: - %purr !! - %bide [~ state(hear (~(put ju hear) path.task hen))] + %yawn + [~ state(want (~(del ju want) path.task hen))] :: - %born [~ state(hear ~)] ::REVIEW assuming this is for runtime use only? - %trim [~ state] ::TODO maybe clear part? - %vega [~ state] + %purr + =/ [req=? =packet] (decode-packet purr.task) + ?: req + =/ =twit (decode-request `@ux`content.packet) + ::TODO verify request signature + ::TODO handle twit + !! + =/ [=peep =purr] (decode-request-info `@ux`content.packet) + =/ =rawr (decode-response purr) + ::TODO validate response signature + ?: =(0 siz.rawr) + ::TODO complete instantly + ::TODO (~(del by part) path.peep) for safety? + !! + !! + :: =/ have=(list @) (~(get ja part) path.peep) + :: ::TODO if we get fancier, we could receive in any order + :: ?> =((lent have) (dec num.peep)) + :: =. have [[wid dat]:rawr have] + :: :: if we have all the parts now, construct the response + :: :: + :: ?> (lte num.peep siz.rawr) + :: ?: =(num.peep siz.rawr) + :: ?. =((lent have) siz.rawr) + :: ::TODO wtf! start over? + :: !! + :: ::TODO need to flop first y/n? + :: !! + :: :: otherwise, store the part, and send out the next request + :: :: + :: =. part (~(put by part) path.peep have) + :: ::TODO emit properly + :: :+ %hoot + :: !! ::TODO get lane, from response or ames? + :: ::TODO needs header, prelude + :: (packetize-request path.peep +(num.peep)) + :: + %bide + [~ state(hear (~(put ju hear) path.task hen))] + :: + %born + [~ state(hear ~)] ::REVIEW assuming this is for runtime use only? + :: + %trim + [~ state] ::TODO maybe clear part? + :: + %vega + [~ state] == [~ fine-gate] :: +load: migrate an old state to a new fine version From dd4eb87f4224769e5c85ee61f00a54430f2bfcf2 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 20 Jan 2022 01:59:43 +0100 Subject: [PATCH 008/168] ames: move packet en/decoding into lull By moving this behavior for packets with ames-style headers into lull, other vanes that want to do protocols in similar style (like the upcoming %fine vane) can reuse the logic here. Note that we parameterize the main en- and decoding functions, so that we may pass in the "is ames" flag and protocol versions as appropriate to the context. --- pkg/arvo/sys/lull.hoon | 167 ++++++++++++++++++++++++++++++++++ pkg/arvo/sys/vane/ames.hoon | 172 +----------------------------------- 2 files changed, 171 insertions(+), 168 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 379f6f14b..f0de981af 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -434,6 +434,9 @@ :: $blob: raw atom to or from unix, representing a packet :: +$ blob @uxblob + :: $protocol-version: 3-bit protocol version + :: + +$ protocol-version ?(%0 %1 %2 %3 %4 %5 %6 %7) :: $error: tagged diagnostic trace :: +$ error [tag=@tas =tang] @@ -702,7 +705,171 @@ num-received=fragment-num fragments=(map fragment-num fragment) == + :: |packets: ames-style packet en- and decoding :: + :: $dyad: pair of sender and receiver ships + :: + +$ dyad [sndr=ship rcvr=ship] + :: $rank: which kind of ship address, by length + :: + :: 0b0: galaxy or star -- 2 bytes + :: 0b1: planet -- 4 bytes + :: 0b10: moon -- 8 bytes + :: 0b11: comet -- 16 bytes + :: + +$ rank ?(%0b0 %0b1 %0b10 %0b11) + :: $packet: noun representation of an ames datagram packet + :: + :: Roundtrips losslessly through atom encoding and decoding. + :: + :: .origin is ~ unless the packet is being forwarded. If present, + :: it's an atom that encodes a route to another ship, such as an IPv4 + :: address. Routes are opaque to Arvo and only have meaning in the + :: interpreter. This enforces that Ames is transport-agnostic. + :: + +$ packet + $: dyad + sndr-tick=@ubC + rcvr-tick=@ubC + origin=(unit @uxaddress) + content=@uxcontent + == + :: +encode-packet: serialize a packet into a bytestream + :: + ++ encode-packet + |= [ames=? =protocol-version] + |= packet + ^- blob + :: + =/ sndr-meta (encode-ship-metadata sndr) + =/ rcvr-meta (encode-ship-metadata rcvr) + :: + =/ body=@ + ;: mix + sndr-tick + (lsh 2 rcvr-tick) + (lsh 3 sndr) + (lsh [3 +(size.sndr-meta)] rcvr) + (lsh [3 +((add size.sndr-meta size.rcvr-meta))] content) + == + =/ checksum (end [0 20] (mug body)) + =? body ?=(^ origin) (mix u.origin (lsh [3 6] body)) + :: + =/ header=@ + %+ can 0 + :~ [3 reserved=0] + [1 is-ames=&] + [3 protocol-version] + [2 rank.sndr-meta] + [2 rank.rcvr-meta] + [20 checksum] + [1 relayed=.?(origin)] + == + (mix header (lsh 5 body)) + :: +decode-packet: deserialize packet from bytestream or crash + :: + ++ decode-packet + |= [ames=? =protocol-version] + |= =blob + ^- packet + ~| %decode-packet-fail + :: first 32 (2^5) bits are header; the rest is body + :: + =/ header (end 5 blob) + =/ body (rsh 5 blob) + :: read header; first three bits are reserved + :: + =/ is-ames (cut 0 [3 1] header) + ?. =(ames is-ames) + ~| ?:(ames %ames-not-ames %fine-not-fine) !! + :: + =/ version (cut 0 [4 3] header) + ?. =(protocol-version version) + ~| ames-protocol-version+version !! + :: + =/ sndr-size (decode-ship-size (cut 0 [7 2] header)) + =/ rcvr-size (decode-ship-size (cut 0 [9 2] header)) + =/ checksum (cut 0 [11 20] header) + =/ relayed (cut 0 [31 1] header) + :: origin, if present, is 6 octets long, at the end of the body + :: + =^ origin=(unit @) body + ?: =(| relayed) + [~ body] + =/ len (sub (met 3 body) 6) + [`(end [3 6] body) (rsh [3 6] body)] + :: .checksum does not apply to the origin + :: + ?. =(checksum (end [0 20] (mug body))) + ~| %ames-checksum !! + :: read fixed-length sndr and rcvr life data from body + :: + :: These represent the last four bits of the sender and receiver + :: life fields, to be used for quick dropping of honest packets to + :: or from the wrong life. + :: + =/ sndr-tick (cut 0 [0 4] body) + =/ rcvr-tick (cut 0 [4 4] body) + :: read variable-length .sndr and .rcvr addresses + :: + =/ off 1 + =^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)] + ?. (is-valid-rank sndr sndr-size) + ~| ames-sender-impostor+[sndr sndr-size] !! + :: + =^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)] + ?. (is-valid-rank rcvr rcvr-size) + ~| ames-receiver-impostor+[rcvr rcvr-size] !! + :: read variable-length .content from the rest of .body + :: + =/ content (cut 3 [off (sub (met 3 body) off)] body) + [[sndr rcvr] sndr-tick rcvr-tick origin content] + :: +decode-ship-size: decode a 2-bit ship type specifier into a byte width + :: + :: Type 0: galaxy or star -- 2 bytes + :: Type 1: planet -- 4 bytes + :: Type 2: moon -- 8 bytes + :: Type 3: comet -- 16 bytes + :: + ++ decode-ship-size + |= rank=@ubC + ^- @ + :: + ?+ rank !! + %0b0 2 + %0b1 4 + %0b10 8 + %0b11 16 + == + :: +encode-ship-metadata: produce size (in bytes) and address rank for .ship + :: + :: 0: galaxy or star + :: 1: planet + :: 2: moon + :: 3: comet + :: + ++ encode-ship-metadata + |= =ship + ^- [size=@ =rank] + :: + =/ size=@ (met 3 ship) + :: + ?: (lte size 2) [2 %0b0] + ?: (lte size 4) [4 %0b1] + ?: (lte size 8) [8 %0b10] + [16 %0b11] + :: +is-valid-rank: does .ship match its stated .size? + :: + ++ is-valid-rank + |= [=ship size=@ubC] + ^- ? + .= size + =/ wid (met 3 ship) + ?: (lte wid 1) 2 + ?: =(2 wid) 2 + ?: (lte wid 4) 4 + ?: (lte wid 8) 8 + ?> (lte wid 16) 16 -- ::ames :: :::: :::: ++behn :: (1b) timekeeping diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 41742600b..baf1b813e 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -88,8 +88,8 @@ :: protocol-version: current version of the ames wire protocol :: !: -=/ protocol-version=?(%0 %1 %2 %3 %4 %5 %6 %7) %0 =, ames +=/ =protocol-version %0 =* point point:jael =* public-keys-result public-keys-result:jael :: veb: verbosity flags @@ -248,110 +248,9 @@ =. private-key (rsh 8 (rsh 3 private-key)) :: `@`(shar:ed:crypto public-key private-key) -:: +encode-packet: serialize a packet into a bytestream :: -++ encode-packet - ~/ %encode-packet - |= packet - ^- blob - :: - =/ sndr-meta (encode-ship-metadata sndr) - =/ rcvr-meta (encode-ship-metadata rcvr) - :: - =/ body=@ - ;: mix - sndr-tick - (lsh 2 rcvr-tick) - (lsh 3 sndr) - (lsh [3 +(size.sndr-meta)] rcvr) - (lsh [3 +((add size.sndr-meta size.rcvr-meta))] content) - == - =/ checksum (end [0 20] (mug body)) - =? body ?=(^ origin) (mix u.origin (lsh [3 6] body)) - :: - =/ header=@ - %+ can 0 - :~ [3 reserved=0] - [1 is-ames=&] - [3 protocol-version] - [2 rank.sndr-meta] - [2 rank.rcvr-meta] - [20 checksum] - [1 relayed=.?(origin)] - == - (mix header (lsh 5 body)) -:: +decode-packet: deserialize packet from bytestream or crash -:: -++ decode-packet - ~/ %decode-packet - |= =blob - ^- packet - ~| %decode-packet-fail - :: first 32 (2^5) bits are header; the rest is body - :: - =/ header (end 5 blob) - =/ body (rsh 5 blob) - :: read header; first three bits are reserved - :: - =/ is-ames (cut 0 [3 1] header) - ?. =(& is-ames) - ~| %ames-not-ames !! - :: - =/ version (cut 0 [4 3] header) - ?. =(protocol-version version) - ~| ames-protocol-version+version !! - :: - =/ sndr-size (decode-ship-size (cut 0 [7 2] header)) - =/ rcvr-size (decode-ship-size (cut 0 [9 2] header)) - =/ checksum (cut 0 [11 20] header) - =/ relayed (cut 0 [31 1] header) - :: origin, if present, is 6 octets long, at the end of the body - :: - =^ origin=(unit @) body - ?: =(| relayed) - [~ body] - =/ len (sub (met 3 body) 6) - [`(end [3 6] body) (rsh [3 6] body)] - :: .checksum does not apply to the origin - :: - ?. =(checksum (end [0 20] (mug body))) - ~| %ames-checksum !! - :: read fixed-length sndr and rcvr life data from body - :: - :: These represent the last four bits of the sender and receiver - :: life fields, to be used for quick dropping of honest packets to - :: or from the wrong life. - :: - =/ sndr-tick (cut 0 [0 4] body) - =/ rcvr-tick (cut 0 [4 4] body) - :: read variable-length .sndr and .rcvr addresses - :: - =/ off 1 - =^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)] - ?. (is-valid-rank sndr sndr-size) - ~| ames-sender-impostor+[sndr sndr-size] !! - :: - =^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)] - ?. (is-valid-rank rcvr rcvr-size) - ~| ames-receiver-impostor+[rcvr rcvr-size] !! - :: read variable-length .content from the rest of .body - :: - =/ content (cut 3 [off (sub (met 3 body) off)] body) - [[sndr rcvr] sndr-tick rcvr-tick origin content] -:: +is-valid-rank: does .ship match its stated .size? -:: -++ is-valid-rank - ~/ %is-valid-rank - |= [=ship size=@ubC] - ^- ? - .= size - ?- (clan:title ship) - %czar 2 - %king 2 - %duke 4 - %earl 8 - %pawn 16 - == +++ encode-packet (^encode-packet & protocol-version) +++ decode-packet (^decode-packet & protocol-version) :: +encode-open-packet: convert $open-packet attestation to $packet :: ++ encode-open-packet @@ -437,54 +336,10 @@ =/ vec ~[sndr.packet rcvr.packet sndr-life rcvr-life] ;; shut-packet %- cue %- need (~(de sivc:aes:crypto (shaz symmetric-key) vec) siv len cyf) -:: +decode-ship-size: decode a 2-bit ship type specifier into a byte width -:: -:: Type 0: galaxy or star -- 2 bytes -:: Type 1: planet -- 4 bytes -:: Type 2: moon -- 8 bytes -:: Type 3: comet -- 16 bytes -:: -++ decode-ship-size - ~/ %decode-ship-size - |= rank=@ubC - ^- @ - :: - ?+ rank !! - %0b0 2 - %0b1 4 - %0b10 8 - %0b11 16 - == -:: +encode-ship-metadata: produce size (in bytes) and address rank for .ship -:: -:: 0: galaxy or star -:: 1: planet -:: 2: moon -:: 3: comet -:: -++ encode-ship-metadata - ~/ %encode-ship-metadata - |= =ship - ^- [size=@ =rank] - :: - =/ size=@ (met 3 ship) - :: - ?: (lte size 2) [2 %0b0] - ?: (lte size 4) [4 %0b1] - ?: (lte size 8) [8 %0b10] - [16 %0b11] +| %atomics :: +$ private-key @uwprivatekey +$ signature @uwsignature -:: $rank: which kind of ship address, by length -:: -:: 0b0: galaxy or star -- 2 bytes -:: 0b1: planet -- 4 bytes -:: 0b10: moon -- 8 bytes -:: 0b11: comet -- 16 bytes -:: -+$ rank ?(%0b0 %0b1 %0b10 %0b11) :: +| %kinetics :: $channel: combined sender and receiver identifying data @@ -505,25 +360,6 @@ =her=public-key her-sponsor=ship == == -:: $dyad: pair of sender and receiver ships -:: -+$ dyad [sndr=ship rcvr=ship] -:: $packet: noun representation of an ames datagram packet -:: -:: Roundtrips losslessly through atom encoding and decoding. -:: -:: .origin is ~ unless the packet is being forwarded. If present, -:: it's an atom that encodes a route to another ship, such as an IPv4 -:: address. Routes are opaque to Arvo and only have meaning in the -:: interpreter. This enforces that Ames is transport-agnostic. -:: -+$ packet - $: dyad - sndr-tick=@ubC - rcvr-tick=@ubC - origin=(unit @uxaddress) - content=@uxcontent - == :: $open-packet: unencrypted packet payload, for comet self-attestation :: :: This data structure gets signed and jammed to form the .contents @@ -1081,7 +917,7 @@ -- :: |per-event: inner event-handling core :: -~% %per-event ..decode-packet ~ +~% %per-event ..trace ~ |% ++ per-event =| moves=(list move) From 2d0a6f160b0099a6f22402826376ca7d3fd67312 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 20 Jan 2022 20:36:38 +0100 Subject: [PATCH 009/168] fine: reuse packet en/decoding logic from ames Also adds some more of the core logic, but still wip. --- pkg/arvo/sys/lull.hoon | 3 +- pkg/arvo/sys/vane/fine.hoon | 354 ++++++++++++++---------------------- 2 files changed, 139 insertions(+), 218 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index f0de981af..1453be0e0 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1799,8 +1799,7 @@ ++ fine ^? |% +$ gift :: to arvo: - $% [%tune =path =(cask)] :: found at path - ::TODO add task to clay (& gall?) for declaring notify desire + $% [%tune =path data=(unit (cask))] :: found at path :: :: to vere: [%hoot =lane:ames =hoot] :: request packet [%howl =path =song] :: full response diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index a4adad268..a1b227281 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -21,11 +21,6 @@ $% $: %behn $% $>(%wake gift:behn) == == - $: %fine - $% $>(%tune gift) - $>(%hoot gift) - $>(%howl gift) - == == $: %jael $% $>(%private-keys gift:jael) $>(%public-keys gift:jael) @@ -35,15 +30,42 @@ :: +$ fine-state $: %0 + urth=duct :: unix duct hear=(jug path duct) :: awaiting existence want=(jug path duct) :: awaiting response - part=(map path [siz=@ud pac=(map @ud @)]) :: partial responses + part=(map path partial) :: partial responses + ::TODO re-send request timers? == :: - ::TODO types for unpacked packets? - :: +$ bits [w=@ud d=@] ++ protocol-version %0 + :: + +$ partial + $: num-fragments=@ud + num-received=@ud + fragments=(map @ud byts) + == + :: + +$ twit :: signed request + $: signature=@ + peep + == + :: + +$ peep :: request data + $: =path + num=@ud + == + :: + +$ rawr :: response packet + $: sig=@ + siz=@ud + byts + == + :: + +$ roar :: response message + $: sig=@ + dat=(cask) + == -- :: ~% %fine ..part ~ @@ -53,6 +75,9 @@ |= [now=@da eny=@uvJ rof=roof] =* fine-gate . => |% + ++ encode-packet (encode-packet:ames | protocol-version) + ++ decode-packet (decode-packet:ames | protocol-version) + :: ++ spit |= =path ^- [pat=@t wid=@ud] @@ -61,50 +86,6 @@ ?> (lte wid 384) ::TODO check when we handle %keen, instead of here? [pat wid] :: - ++ meet ::NOTE from ames, but bits instead of bytes - |= =ship - ^- [size=@ rank=@ub] - =/ size=@ (met 3 ship) - ?: (lte size 2) [16 %0b0] - ?: (lte size 4) [32 %0b1] - ?: (lte size 8) [64 %0b10] - [128 %0b11] - :: - ++ header - |= [for=ship req=? bod=@ rel=?] - ^- bits - =+ him=(meet our) - =+ her=(meet for) - =+ sum=(end [0 20] (mug bod)) - :- 32 - %+ can 0 - :~ 2^0 :: reserved - 1^req :: request or response - 1^| :: not ames - 3^protocol-version :: protocol version - 2^size.him :: sender address size - 2^size.her :: receiver address size - 20^sum :: checksum - 1^rel :: relayed - == - :: - ++ prelude - |= [for=[=ship =life] =life origin=(unit lane:ames)] - ^- bits - =+ him=(meet our) - =+ her=(meet ship.for) - =/ ore=bits - ?. ?=([~ %| *] origin) 0^0 - (mul 8 (met 3 p.u.origin))^p.u.origin - :- :(add 4 4 size.him size.her w.ore) - %+ can 0 - :~ 4^(mod life 16) :: sender life - 4^(mod life.for 16) :: receiver life - size.him^our :: sender - size.her^ship.for :: receiver - ore - == - :: ++ request-body |= [=path num=@ud] ^- bits @@ -117,14 +98,14 @@ (mul 8 wid)^`@`pat :: namespace path == :: - ++ packetize-request + ++ encode-request |= [=path num=@ud] ^- hoot =+ bod=(request-body path num) (can 0 512^(sign:keys d.bod) bod ~) :: - ++ packetize-response - |= [=path data=(unit (cask *))] + ++ encode-response + |= [=path data=(unit (cask))] ^- song :: prepend request descriptions to each response packet :: @@ -134,13 +115,12 @@ |= [pac=bits num=@ud] ^- [purr _num] :_ +(num) + ^- @ux ::NOTE we stub out the receiver & origin details, :: runtime should replace them as appropriate. - =/ pre=bits (prelude [*ship *life] life:keys ~) =/ req=bits (request-body path num) - =/ bod=bits [:(add w.pre w.req w.pac) (can 0 pre req pac ~)] - =/ hed=bits (header *ship | +.bod |) - (can 0 hed bod ~) + =/ con=@ux (can 0 req pac ~) + (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ con) :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) @@ -191,125 +171,6 @@ !! -- :: - :: - ::TODO copied from ames - +$ dyad [sndr=ship rcvr=ship] - +$ packet - $: dyad - sndr-tick=@ubC - rcvr-tick=@ubC - origin=(unit @uxaddress) - content=@uxcontent - == - :: - ::TODO copied from ames, only req parsing added - ++ decode-packet - ~/ %decode-packet - |= blob=@ux - ^- [req=? packet] - ~| %decode-packet-fail - :: first 32 (2^5) bits are header; the rest is body - :: - =/ header (end 5 blob) - =/ body (rsh 5 blob) - :: read header; first two bits are reserved - :: - :- req==(0 (cut 0 [2 1] header)) - =/ is-ames (cut 0 [3 1] header) - ?: =(& is-ames) - ~| %fine-but-ames !! - :: - =/ version (cut 0 [4 3] header) - ?. =(protocol-version version) - ~| fine-protocol-version+version !! - :: - =/ sndr-size (decode-ship-size (cut 0 [7 2] header)) - =/ rcvr-size (decode-ship-size (cut 0 [9 2] header)) - =/ checksum (cut 0 [11 20] header) - =/ relayed (cut 0 [31 1] header) - :: origin, if present, is 6 octets long, at the end of the body - :: - =^ origin=(unit @) body - ?: =(| relayed) - [~ body] - =/ len (sub (met 3 body) 6) - [`(end [3 6] body) (rsh [3 6] body)] - :: .checksum does not apply to the origin - :: - ?. =(checksum (end [0 20] (mug body))) - ~| %ames-checksum !! - :: read fixed-length sndr and rcvr life data from body - :: - :: These represent the last four bits of the sender and receiver - :: life fields, to be used for quick dropping of honest packets to - :: or from the wrong life. - :: - =/ sndr-tick (cut 0 [0 4] body) - =/ rcvr-tick (cut 0 [4 4] body) - :: read variable-length .sndr and .rcvr addresses - :: - =/ off 1 - =^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)] - ?. (is-valid-rank sndr sndr-size) - ~| ames-sender-impostor+[sndr sndr-size] !! - :: - =^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)] - ?. (is-valid-rank rcvr rcvr-size) - ~| ames-receiver-impostor+[rcvr rcvr-size] !! - :: read variable-length .content from the rest of .body - :: - =/ content (cut 3 [off (sub (met 3 body) off)] body) - [[sndr rcvr] sndr-tick rcvr-tick origin content] - :: +decode-ship-size: decode a 2-bit ship type specifier into a byte width - :: - :: Type 0: galaxy or star -- 2 bytes - :: Type 1: planet -- 4 bytes - :: Type 2: moon -- 8 bytes - :: Type 3: comet -- 16 bytes - :: - ++ decode-ship-size - ~/ %decode-ship-size - |= rank=@ubC - ^- @ - :: - ?+ rank !! - %0b0 2 - %0b1 4 - %0b10 8 - %0b11 16 - == - :: +is-valid-rank: does .ship match its stated .size? - :: - ++ is-valid-rank - ~/ %is-valid-rank - |= [=ship size=@ubC] - ^- ? - .= size - ?- (clan:title ship) - %czar 2 - %king 2 - %duke 4 - %earl 8 - %pawn 16 - == - :: - +$ twit :: signed request - $: signature=@ - peep - == - :: - +$ peep :: request data - $: =path - num=@ud - == - :: - +$ rawr :: response data - $: sig=@ - siz=@ud - wid=@ud - dat=@ - == - :: ++ decode-request |= =hoot ^- twit @@ -326,7 +187,7 @@ :: if there is data remaining, it's the response (rsh [3 (add 6 len)] hoot) :: - ++ decode-response + ++ decode-response-packet |= =purr =; =rawr ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] @@ -337,9 +198,81 @@ dat=(rsh 0^560 purr) == :: - ++ verify-response + ++ verify-response-packet |= rawr !! + :: + ++ decode-response-msg + |= partial ::TODO maybe take @ instead + ^- roar + =/ mess=@ + %+ can 3 + %+ turn (gulf 1 num-fragments) + ~(got by fragments) + :- sig=(cut 0 [0 512] mess) + ~| [%fine %response-not-cask] + ;;((cask) (cue (rsh 0^512 mess))) + :: + ++ process-response + |= [=path data=(unit (cask))] + ^- (quip move _state) + :- %+ turn ~(tap in (~(get ju want) path)) + (late [%give %tune path data]) + =. want (~(del by want) path) + =. part (~(del by part) path) + state + :: + ++ handle-request + |= =twit + ^- (list move) + ::TODO collect scry response + ::TODO sane y/n? other task? + [duct %give %fine %howl !!]~ + :: + ++ handle-response + |= [[from=ship =lane:ames] =peep =rawr] + ^- (quip move _state) + ?: =(0 siz.rawr) + ?> =(0 dat.rawr) + (process-response path.peep ~) + ?. (~(has by part) path.peep) + :: we did not initiate this request, or it's been cancelled + :: + !! + =/ partial (~(got by part) path.peep) + =. partial + ?: (~(has by fragments.partial) num.peep) + ~& [%fine %duplicate-response peep] ::TODO disable + ::TODO what if non-equal? + partial + =, partial + :+ ~| [%fine %response-size-changed have=num-fragments new=siz.rawr] + ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) + num-fragments + +(num-received) + (~(put by fragments) num.peep [wid dat]:rawr) + :: + ?: =(num-fragments num-received):partial + :: we have all the parts now, construct the full response + :: + =/ =roar (decode-response-msg partial) + ::TODO check signature + (process-response path.peep `dat.roar) + :: otherwise, store the part, and send out the next request + :: + =. part (~(put by part) path.peep partial) + =/ next-num=@ud + =/ next=@ud +(num.peep) + :: we should receive responses in order, but in case we don't... + :: + |- + ?. (~(has by fragments.partial) next) next + $(next +((mod next num-fragments.partial))) + :: + =/ =lane:ames !! ::TODO + =/ =hoot (encode-request path.peep next-num) + ::REVIEW no %f tag? + [[urth %give %hoot lane hoot]~ state] -- ^? |% @@ -361,54 +294,43 @@ =^ moves state ?- -.task %keen - :- ~ ::TODO emit request packet - state(want (~(put ju want) path.task hen)) + ^- (quip move _state) + =. want (~(put ju want) path.task hen) + ?: (~(has by part) path.task) + :: request is already ongoing + :: + [~ state] + :: kick off the request + :: + =. part (~(put by part) path.task *partial) + =/ =lane:ames !! ::TODO just scry out of ames, or what? + =/ =hoot (encode-request path.task 1) + ::TODO how to make sure this ends up in the runtime? default duct?? + [[urth %give %hoot lane hoot]~ state] :: %yawn [~ state(want (~(del ju want) path.task hen))] :: %purr - =/ [req=? =packet] (decode-packet purr.task) + ^- (quip move _state) + =/ =packet:ames (decode-packet `@ux`purr.task) + =/ req=? =(& (cut 0 [2 1] purr.task)) ?: req =/ =twit (decode-request `@ux`content.packet) ::TODO verify request signature - ::TODO handle twit - !! + [(handle-request twit) state] =/ [=peep =purr] (decode-request-info `@ux`content.packet) - =/ =rawr (decode-response purr) + =/ =rawr (decode-response-packet purr) ::TODO validate response signature - ?: =(0 siz.rawr) - ::TODO complete instantly - ::TODO (~(del by part) path.peep) for safety? - !! - !! - :: =/ have=(list @) (~(get ja part) path.peep) - :: ::TODO if we get fancier, we could receive in any order - :: ?> =((lent have) (dec num.peep)) - :: =. have [[wid dat]:rawr have] - :: :: if we have all the parts now, construct the response - :: :: - :: ?> (lte num.peep siz.rawr) - :: ?: =(num.peep siz.rawr) - :: ?. =((lent have) siz.rawr) - :: ::TODO wtf! start over? - :: !! - :: ::TODO need to flop first y/n? - :: !! - :: :: otherwise, store the part, and send out the next request - :: :: - :: =. part (~(put by part) path.peep have) - :: ::TODO emit properly - :: :+ %hoot - :: !! ::TODO get lane, from response or ames? - :: ::TODO needs header, prelude - :: (packetize-request path.peep +(num.peep)) + (handle-response [from lane]:task peep rawr) :: %bide [~ state(hear (~(put ju hear) path.task hen))] :: %born - [~ state(hear ~)] ::REVIEW assuming this is for runtime use only? + ^- (quip move _state) + ::REVIEW assuming hear is for runtime use only? + [~ state(hear ~, urth hen)] :: %trim [~ state] ::TODO maybe clear part? @@ -448,7 +370,7 @@ :: ?. ?=(%x car) ~ ?. ?=([%message @ *] s.bem) ~ - :: s.bem is expected to be a scry path of the shape /vc/desk/rev/etc, + :: t.s.bem is expected to be a scry path of the shape /vc/desk/rev/etc, :: so we need to give it the right shape :: =/ pax=path @@ -467,8 +389,8 @@ =+ res=(rof lyc u.nom) ?- res ~ ~ - [~ ~] ``noun+!>((packetize-response pax ~)) - [~ ~ *] ``noun+!>((packetize-response pax `[p q.q]:u.u.res)) + [~ ~] ``noun+!>((encode-response pax ~)) + [~ ~ *] ``noun+!>((encode-response pax `[p q.q]:u.u.res)) == :: ++ stay state From 92aa604be022234228d25c5bb497c088d2079ce1 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 21 Jan 2022 14:59:54 +0100 Subject: [PATCH 010/168] fine: factor out the fetching of scry results And use it to implement task-ways request handling, which we'll probably remove in favor of peek-ways handling. --- pkg/arvo/sys/vane/fine.hoon | 53 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index a1b227281..bfbb83cf2 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -223,11 +223,13 @@ state :: ++ handle-request - |= =twit + |= [=duct =twit] ^- (list move) - ::TODO collect scry response - ::TODO sane y/n? other task? - [duct %give %fine %howl !!]~ + =/ =song + %+ encode-response path.twit + (get-scry-result *gang path.twit) + ::TODO different task, pick the right packet + [duct %give %howl path.twit song]~ :: ++ handle-response |= [[from=ship =lane:ames] =peep =rawr] @@ -273,6 +275,28 @@ =/ =hoot (encode-request path.peep next-num) ::REVIEW no %f tag? [[urth %give %hoot lane hoot]~ state] + :: + ++ get-scry-result + |= [=gang =path] + ^- (unit (cask)) + ?~ nom=(de-omen path) ~ + ?> =(our p.bem.u.nom) + :: we only support scrying into clay, + :: and only if the data is fully public. + :: + ?. =(%c (end 3 (snag 0 path))) ~ + =+ pem=(rof gang (need (de-omen %cp (slag 1 path)))) + ?> ?=(^ pem) + ?> ?=(^ u.pem) + =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) + ?> =([%black ~ ~] rul.r.per) + =+ res=(rof gang u.nom) + ~! res + ?- res + ~ !! ::REVIEW crashing in the blocking case is fine.. right? + [~ ~] ~ + [~ ~ *] `[p q.q]:u.u.res + == -- ^? |% @@ -316,9 +340,10 @@ =/ =packet:ames (decode-packet `@ux`purr.task) =/ req=? =(& (cut 0 [2 1] purr.task)) ?: req + ::TODO crash instead, scry/peek should be used for this =/ =twit (decode-request `@ux`content.packet) ::TODO verify request signature - [(handle-request twit) state] + [(handle-request hen twit) state] =/ [=peep =purr] (decode-request-info `@ux`content.packet) =/ =rawr (decode-response-packet purr) ::TODO validate response signature @@ -375,23 +400,7 @@ :: =/ pax=path [i.t.s.bem (scot %p our) t.t.s.bem] - ?~ nom=(de-omen pax) [~ ~] - :: we only support scrying into clay, and only if the data is fully public - :: - ?. =(%c (end 3 (snag 0 pax))) ~ - =+ pem=(rof lyc (need (de-omen %cp (slag 1 pax)))) - ?~ pem ~ - ?~ u.pem ~ - =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) - ?. =([%black ~ ~] rul.r.per) ~ - :: scry out the data from clay and packetize it as appropriate - :: - =+ res=(rof lyc u.nom) - ?- res - ~ ~ - [~ ~] ``noun+!>((encode-response pax ~)) - [~ ~ *] ``noun+!>((encode-response pax `[p q.q]:u.u.res)) - == + ``noun+!>((encode-response pax (get-scry-result lyc pax))) :: ++ stay state ++ take From b606dea97055ecd2cb6a872bcf290654207d0676 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 24 Jan 2022 21:01:09 +0100 Subject: [PATCH 011/168] fine: work on bytes instead of bits --- pkg/arvo/sys/vane/fine.hoon | 63 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index bfbb83cf2..124739e7e 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -88,59 +88,58 @@ :: ++ request-body |= [=path num=@ud] - ^- bits + ^- byts ?> (lth num (bex 32)) =+ (spit path) - :- :(add 32 16 (mul 8 wid)) - %+ can 0 - :~ 32^num :: fragment number - 16^wid :: path size - (mul 8 wid)^`@`pat :: namespace path + :- :(add 32 16 wid) + %+ can 3 + :~ 4^num :: fragment number + 2^wid :: path size + wid^`@`pat :: namespace path == :: ++ encode-request |= [=path num=@ud] ^- hoot =+ bod=(request-body path num) - (can 0 512^(sign:keys d.bod) bod ~) + (can 3 64^(sign:keys d.bod) bod ~) :: ++ encode-response |= [=path data=(unit (cask))] ^- song :: prepend request descriptions to each response packet :: - =; pacs=(list bits) + =; pacs=(list byts) %- head %^ spin pacs 1 - |= [pac=bits num=@ud] + |= [pac=byts num=@ud] ^- [purr _num] :_ +(num) ^- @ux ::NOTE we stub out the receiver & origin details, :: runtime should replace them as appropriate. - =/ req=bits (request-body path num) - =/ con=@ux (can 0 req pac ~) + =/ req=byts (request-body path num) + =/ con=@ux (can 3 req pac ~) (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ con) :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) =/ sig=@ (full:keys path (fall data ~)) ?~ data [sig]~ - %+ rip 3^1.024 ::TODO prints "rip: stub" - (cat 3 sig (jam u.data)) ::REVIEW - =/ size=@ud - ?~(data 0 (lent frag)) ::REVIEW + %+ rip 13 ::NOTE 1024 bytes + (cat 3 sig (jam u.data)) ::TODO should include life :: sign & packetize the fragments :: %+ turn frag |= dat=@ + ^- byts =/ wid=@ud (met 3 dat) - :- :(add 512 32 16 (mul 8 wid)) - %+ can 0 - :~ 512^(sign:keys dat) :: signature - 32^size :: number of fragments - 16^wid :: response data size in bytes ::REVIEW - (mul 8 wid)^dat :: response data + :- :(add 64 4 2 wid) + %+ can 3 + :~ 64^(sign:keys dat) :: signature ::TODO +pack:keys + 4^(lent frag) :: number of fragments + 2^wid :: response data fragment size in bytes + wid^dat :: response data fragment == :: ++ keys @@ -174,14 +173,14 @@ ++ decode-request |= =hoot ^- twit - :- sig=(cut 0 [0 512] hoot) - -:(decode-request-info (rsh [0 512] hoot)) + :- sig=(cut 3 [0 64] hoot) + -:(decode-request-info (rsh 3^64 hoot)) :: ++ decode-request-info |= =hoot ^- [=peep =purr] - =+ num=(cut 0 [0 32] hoot) - =+ len=(cut 0 [32 16] hoot) + =+ num=(cut 3 [0 4] hoot) + =+ len=(cut 3 [4 2] hoot) =+ pat=(cut 3 [6 len] hoot) :- [(stab pat) num] :: if there is data remaining, it's the response @@ -192,10 +191,10 @@ =; =rawr ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] rawr - :* sig=(cut 0 [0 512] purr) - siz=(cut 0 [512 32] purr) - wid=(cut 0 [544 16] purr) - dat=(rsh 0^560 purr) + :* sig=(cut 3 [0 64] purr) + siz=(cut 3 [64 4] purr) + wid=(cut 3 [68 2] purr) + dat=(rsh 3^70 purr) == :: ++ verify-response-packet @@ -206,12 +205,12 @@ |= partial ::TODO maybe take @ instead ^- roar =/ mess=@ - %+ can 3 + %+ can 3 ::TODO just (rep 13 -) %+ turn (gulf 1 num-fragments) ~(got by fragments) - :- sig=(cut 0 [0 512] mess) + :- sig=(cut 3 [0 64] mess) ~| [%fine %response-not-cask] - ;;((cask) (cue (rsh 0^512 mess))) + ;;((cask) (cue (rsh 3^64 mess))) :: ++ process-response |= [=path data=(unit (cask))] From 2279764effa258f2fb1c169096fc9eac64bb55e1 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 24 Jan 2022 21:01:46 +0100 Subject: [PATCH 012/168] fine: include header & prelude with %hoot --- pkg/arvo/sys/vane/fine.hoon | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index 124739e7e..1849fd90c 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -100,9 +100,10 @@ :: ++ encode-request |= [=path num=@ud] - ^- hoot + ^- hoot ^- @ =+ bod=(request-body path num) - (can 3 64^(sign:keys d.bod) bod ~) + =+ con=(can 3 64^(sign:keys dat.bod) bod ~) + (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ con) :: ++ encode-response |= [=path data=(unit (cask))] From 176aa3a45e3d4f101a0059f0b16857b996995852 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 24 Jan 2022 21:38:55 +0100 Subject: [PATCH 013/168] lull: stop hardcoding ames bit in +encode-packet --- pkg/arvo/sys/lull.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 1453be0e0..7fc2f6115 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -758,7 +758,7 @@ =/ header=@ %+ can 0 :~ [3 reserved=0] - [1 is-ames=&] + [1 is-ames=ames] [3 protocol-version] [2 rank.sndr-meta] [2 rank.rcvr-meta] From 03b73b85bf671bd29a474f815a301dad334b4c09 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 24 Jan 2022 23:06:06 +0100 Subject: [PATCH 014/168] fine: set and handle the response bit correctly --- pkg/arvo/sys/vane/fine.hoon | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index 1849fd90c..63898675b 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -102,8 +102,9 @@ |= [=path num=@ud] ^- hoot ^- @ =+ bod=(request-body path num) - =+ con=(can 3 64^(sign:keys dat.bod) bod ~) - (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ con) + =+ syn=(can 3 64^(sign:keys dat.bod) bod ~) + %+ con 0b100 ::NOTE request bit + (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ syn) :: ++ encode-response |= [=path data=(unit (cask))] @@ -338,8 +339,8 @@ %purr ^- (quip move _state) =/ =packet:ames (decode-packet `@ux`purr.task) - =/ req=? =(& (cut 0 [2 1] purr.task)) - ?: req + =/ resp=? =(& (cut 0 [2 1] purr.task)) + ?. resp ::TODO crash instead, scry/peek should be used for this =/ =twit (decode-request `@ux`content.packet) ::TODO verify request signature From ff53ae5e66d7b7139e817a008e2aba2209b9e025 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 24 Jan 2022 23:26:02 +0100 Subject: [PATCH 015/168] fine: supply lane where needed Still somewhat wip, this might not be the lane behavior we want for real. --- pkg/arvo/sys/vane/fine.hoon | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index 63898675b..3d49b76cb 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -172,6 +172,18 @@ !! -- :: + ++ get-lane + |= =ship + ^- lane:ames + =; lanes + ::TODO should we send to all lanes? + ?^ lanes i.lanes + ~&(%fine-lane-stub &+~zod) ::TODO + .^ (list lane:ames) + %ax (scot %p our) %$ (scot %da now) + /peers/(scot %p ship)/forward-lane + == + :: ++ decode-request |= =hoot ^- twit @@ -272,9 +284,11 @@ ?. (~(has by fragments.partial) next) next $(next +((mod next num-fragments.partial))) :: - =/ =lane:ames !! ::TODO =/ =hoot (encode-request path.peep next-num) - ::REVIEW no %f tag? + ::TODO ask amsden, should we shotgun? we can tweak this + :: for now (mvp) though, stay 1-to-1 + ::TODO update lane in ames state + ::TODO is reusing the lane fine? [[urth %give %hoot lane hoot]~ state] :: ++ get-scry-result @@ -320,6 +334,9 @@ ?- -.task %keen ^- (quip move _state) + =/ omen + ~| [%fine %invalid-namespace-path path.task] + (need (de-omen path.task)) =. want (~(put ju want) path.task hen) ?: (~(has by part) path.task) :: request is already ongoing @@ -328,9 +345,8 @@ :: kick off the request :: =. part (~(put by part) path.task *partial) - =/ =lane:ames !! ::TODO just scry out of ames, or what? + =/ =lane:ames (get-lane p.bem.omen) =/ =hoot (encode-request path.task 1) - ::TODO how to make sure this ends up in the runtime? default duct?? [[urth %give %hoot lane hoot]~ state] :: %yawn From 793c31d7f993f6cd5e486d4d61eed652e388f7ef Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 24 Jan 2022 23:51:22 +0100 Subject: [PATCH 016/168] fine: properly sign individual packets --- pkg/arvo/sys/vane/fine.hoon | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index 3d49b76cb..7acde2c09 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -111,18 +111,16 @@ ^- song :: prepend request descriptions to each response packet :: - =; pacs=(list byts) + =; pacs=(list @ux) %- head %^ spin pacs 1 - |= [pac=byts num=@ud] + |= [pac=@ux num=@ud] ^- [purr _num] :_ +(num) ^- @ux ::NOTE we stub out the receiver & origin details, :: runtime should replace them as appropriate. - =/ req=byts (request-body path num) - =/ con=@ux (can 3 req pac ~) - (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ con) + (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ pac) :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) @@ -132,17 +130,23 @@ (cat 3 sig (jam u.data)) ::TODO should include life :: sign & packetize the fragments :: - %+ turn frag - |= dat=@ - ^- byts - =/ wid=@ud (met 3 dat) - :- :(add 64 4 2 wid) - %+ can 3 - :~ 64^(sign:keys dat) :: signature ::TODO +pack:keys - 4^(lent frag) :: number of fragments - 2^wid :: response data fragment size in bytes - wid^dat :: response data fragment - == + %- head + %^ spin frag 1 + |= [dat=@ num=@ud] + :_ +(num) + ^- @ux + =/ req=byts (request-body path num) + =/ bod=byts + =/ wid=@ud (met 3 dat) + :- :(add 4 2 wid) + %+ can 3 + :~ 4^(lent frag) :: number of fragments + 2^wid :: response data fragment size in bytes + wid^dat :: response data fragment + == + =/ sig=byts + 64^(sign:keys (can 3 req bod ~)) + (can 3 req sig bod ~) :: ++ keys |% From af8fd67472e98bdde543b965362c1e930c49db50 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 25 Jan 2022 21:25:17 +0100 Subject: [PATCH 017/168] fine: scry using the roof, not .^ --- pkg/arvo/sys/vane/fine.hoon | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index 7acde2c09..926c04b6f 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -183,10 +183,10 @@ ::TODO should we send to all lanes? ?^ lanes i.lanes ~&(%fine-lane-stub &+~zod) ::TODO - .^ (list lane:ames) - %ax (scot %p our) %$ (scot %da now) - /peers/(scot %p ship)/forward-lane - == + !< (list lane:ames) + =< q %- need %- need + =/ =path /peers/(scot %p ship)/forward-lane + (rof `[our ~ ~] [%ames %x] [our %$ da+now] path) :: ++ decode-request |= =hoot From d4a0f1d9016ed2d78f9f3d1772cd79599bbd378c Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 26 Jan 2022 20:03:03 +0100 Subject: [PATCH 018/168] fine: correctly calculate request body size This had missed getting updated for byte-logic. --- pkg/arvo/sys/vane/fine.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon index 926c04b6f..6eda3ba26 100644 --- a/pkg/arvo/sys/vane/fine.hoon +++ b/pkg/arvo/sys/vane/fine.hoon @@ -91,7 +91,7 @@ ^- byts ?> (lth num (bex 32)) =+ (spit path) - :- :(add 32 16 wid) + :- :(add 4 2 wid) %+ can 3 :~ 4^num :: fragment number 2^wid :: path size From c808657e2a7d50b23b7945c324c31feccbd1b654 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 21 Jan 2022 11:44:21 -0600 Subject: [PATCH 019/168] wip --- .husky/post-checkout | 3 + .husky/post-commit | 3 + .husky/post-merge | 3 + .husky/pre-push | 3 + Makefile | 4 +- nix/overlays/m1.nix | 28 ++++++ pkg/urbit/configure | 5 + pkg/urbit/include/c/motes.h | 2 + pkg/urbit/tests/ames_tests.c | 76 +++++++++++++++ pkg/urbit/vere/io/ames.c | 176 +++++++++++++++++++---------------- shell.nix | 2 +- test | 2 + 12 files changed, 226 insertions(+), 81 deletions(-) create mode 100755 .husky/post-checkout create mode 100755 .husky/post-commit create mode 100755 .husky/post-merge create mode 100755 .husky/pre-push create mode 100644 nix/overlays/m1.nix create mode 100644 test diff --git a/.husky/post-checkout b/.husky/post-checkout new file mode 100755 index 000000000..cab40f264 --- /dev/null +++ b/.husky/post-checkout @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-checkout.\n"; exit 2; } +git lfs post-checkout "$@" diff --git a/.husky/post-commit b/.husky/post-commit new file mode 100755 index 000000000..9443f4161 --- /dev/null +++ b/.husky/post-commit @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-commit.\n"; exit 2; } +git lfs post-commit "$@" diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100755 index 000000000..828b70891 --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-merge.\n"; exit 2; } +git lfs post-merge "$@" diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 000000000..81a9cc639 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/pre-push.\n"; exit 2; } +git lfs pre-push "$@" diff --git a/Makefile b/Makefile index a06eac1c8..3b4795e96 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ .PHONY: build build-all install cross release test pills ropsten-pills clean build: - nix-build -A urbit -A herb --no-out-link + nix-build -A urbit --no-out-link install: - nix-env -f . -iA urbit -iA herb + nix-env -f . -iA urbit release: sh/release diff --git a/nix/overlays/m1.nix b/nix/overlays/m1.nix new file mode 100644 index 000000000..857cb7504 --- /dev/null +++ b/nix/overlays/m1.nix @@ -0,0 +1,28 @@ +final: prev: + +let + + isMusl = prev.stdenv.hostPlatform.isMusl; + + optionalList = xs: if xs == null then [ ] else xs; + + overrideStdenv = pkg: pkg.override { stdenv = prev.gcc9Stdenv; }; + +in prev.lib.optionalAttrs isMusl { + libsigsegv = prev.libsigsegv.overrideAttrs (attrs: { + preConfigure = (attrs.preConfigure or "") + '' + sed -i 's/^CFG_FAULT=$/CFG_FAULT=fault-linux-i386.h/' configure + ''; + }); + + secp256k1 = prev.secp256k1.overrideAttrs (attrs: { + nativeBuildInputs = (attrs.nativeBuildInputs or [ ]) + ++ [ prev.buildPackages.stdenv.cc ]; + }); + + rhash = overrideStdenv prev.rhash; + + numactl = overrideStdenv prev.numactl; + + lmdb = overrideStdenv prev.lmdb; +} diff --git a/pkg/urbit/configure b/pkg/urbit/configure index ab5b3a3df..b7efcc19e 100755 --- a/pkg/urbit/configure +++ b/pkg/urbit/configure @@ -97,6 +97,11 @@ case $(tr A-Z a-z <<< $cpu) in defmacro U3_OS_ENDIAN_little 1 defmacro U3_CPU_aarch64 1 ;; + arm64) + defmacro U3_OS_ENDIAN_little 1 + defmacro U3_CPU_aarch64 1 + ;; + *) echo "Unknown or unsupported CPU: '$cpu'" >&2 exit 1 diff --git a/pkg/urbit/include/c/motes.h b/pkg/urbit/include/c/motes.h index 89880d3bf..b5a3a50ab 100644 --- a/pkg/urbit/include/c/motes.h +++ b/pkg/urbit/include/c/motes.h @@ -548,6 +548,7 @@ # define c3__homp c3_s4('h','o','m','p') # define c3__hook c3_s4('h','o','o','k') # define c3__hoon c3_s4('h','o','o','n') +# define c3__hoot c3_s4('h','o','o','t') # define c3__hop c3_s3('h','o','p') # define c3__hosc c3_s4('h','o','s','c') # define c3__hose c3_s4('h','o','s','e') @@ -914,6 +915,7 @@ # define c3__punk c3_s4('p','u','n','k') # define c3__punt c3_s4('p','u','n','t') # define c3__pure c3_s4('p','u','r','e') +# define c3__purr c3_s4('p','u','r','r') # define c3__push c3_s4('p','u','s','h') # define c3__put c3_s3('p','u','t') # define c3__quac c3_s4('q','u','a','c') diff --git a/pkg/urbit/tests/ames_tests.c b/pkg/urbit/tests/ames_tests.c index 69ed7b9b9..392fdf5fd 100644 --- a/pkg/urbit/tests/ames_tests.c +++ b/pkg/urbit/tests/ames_tests.c @@ -1,6 +1,37 @@ #include "all.h" #include "vere/vere.h" +// ripped TODO: reemove +/*u3_head: ames or fine packet header +*/ + typedef struct _u3_head { + c3_o req_o; // is request (fine only) + c3_o sim_o; // is ames protocol? + c3_y ver_y; // protocol version + c3_y sac_y; // sender class + c3_y rac_y; // receiver class + c3_l mug_l; // truncated mug hash of u3_body + c3_o rel_o; // relayed? + } u3_head; + +/* u3_prel: ames/fine packet prelude +*/ + typedef struct _u3_prel { + c3_y sic_y; // sender life tick + c3_y ric_y; // receiver life tick + c3_d sen_d[2]; // sender + c3_d rec_d[2]; // receiver + c3_d rog_d; // origin lane (optional) + } u3_prel; + + typedef struct _u3_body { + u3_prel pre_u; // prelude + c3_s con_s; // content size + c3_y* con_y; // content + c3_l mug_l; // checksum + } u3_body; + + /* _setup(): prepare for tests. */ static void @@ -30,6 +61,51 @@ _test_ames(void) } } +static void +_test_sift_etch() +{ + u3_head* hed_u = c3_calloc(sizeof(*hed_u)); + u3_body* bod_u = c3_calloc(sizeof(*bod_u)); + + hed_u->sim_o = c3y; + hed_u->ver_y = 1; + hed_u->sac_y = 4; + hed_u->rac_y = 4; + hed_u->rel_o = c3n; + + bod_u->pre_u.sen_d[0] = 0; + bod_u->pre_u.sen_d[1] = 0; + bod_u->pre_u.rec_d[0] = 182; + bod_u->pre_u.rec_d[1] = 0; + + c3_y* str = (c3_y*)"test"; + + bod_u->con_y = str; + bod_u->con_s = 5; + + c3_y** out_y; + + c3_w pac_w = _ames_etch_pack(hed_u, bod_u, out_y); + + u3_head* nhed_u = c3_calloc(sizeof(*nhed_u)); + u3_body* nbod_u = c3_calloc(sizeof(*nbod_u)); + _ames_sift_head(nhed_u, *out_y); + *out_y += 4; + c3_y_ames_sift_body(nbod_u, *out_y); + + if( 0 != memcmp(hed_u, nhed_u, sizeof(*hed_u))) { + fprintf(stderr, "ames: header serialisation mismatch(a)\r\n"); + exit(1); + } + if( 0 != memcmp(bod_u, nbod_u, sizeof(*bod_u))) { + fprintf(stderr, "ames: body serialisation fail(a)\r\n"); + exit(1); + } else { + fprintf(stderr, "ames: pass (a)\r\n"); + exit(1); + } + +} /* main(): run all test cases. */ int diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 4b6101933..5385c4b8e 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -78,8 +78,8 @@ typedef struct _u3_prel { c3_y sic_y; // sender life tick c3_y ric_y; // receiver life tick - c3_d sen_d[2]; // sender - c3_d rec_d[2]; // receiver + c3_d sen_d[2]; // sender/requester + c3_d rec_d[2]; // receiver/responder c3_d rog_d; // origin lane (optional) } u3_prel; @@ -101,17 +101,16 @@ /* u3_resp: fine packet response */ typedef struct _u3_resp { + u3_prel pre_u; // request: - c3_w fra_w; // fragment number - c3_d hos_d[2]; // host address - c3_s len_s; // path length - c3_c* pat_c; // path as ascii + c3_w fra_w; // fragment number + c3_s len_s; // path length + c3_c* pat_c; // path as ascii // response: - c3_y sig_y[64]; // host signature - c3_w lyf_w; // host life - c3_w num_w; // number of fragments - c3_s siz_s; // datum size - c3_y* dat_y; // datum (0 if null response) + c3_y sig_y[64]; // host signature + c3_w num_w; // number of fragments + c3_s siz_s; // datum size + c3_y* dat_y; // datum (0 if null response) } u3_resp; @@ -341,17 +340,17 @@ _fine_sift_requ(u3_head* hed_u, c3_w len_w, c3_y* req_y) { - c3_w rem_w = (64 + 4 + hed_u->sac_y + 4 + hed_u->rac_y + 2); + c3_y pre_y = _ames_sift_prelude(hed_u, &req_u->pre_u, len_w, req_y); + + req_y += pre_y; + + c3_w rem_w = (64 + 4 + 2 + pre_y); if(rem_w > len_w) { return c3n; } memcpy(req_u->sig_y, req_y, 64); req_y += 64; - req_y += 4; - - req_y += hed_u->sac_y; - req_u->fra_w = ( (req_y[0] << 0x18) | (req_y[1] << 0x10) @@ -359,9 +358,6 @@ _fine_sift_requ(u3_head* hed_u, | (req_y[3] << 0x0)); req_y += 4; - //_ames_ship_to_chubs(req_u->hos_d, hed_u->rac_y, req_y); - //req_y += hed_u->rac_y; - req_u->len_s = c3_min(384, (req_y[0] << 0x8) @@ -374,11 +370,10 @@ _fine_sift_requ(u3_head* hed_u, } // TODO: defend maliciusly crafted lengths? - req_u->pat_c = c3_malloc(req_u->len_s + 1); + req_u->pat_c = c3_calloc(req_u->len_s + 1); memcpy(req_u->pat_c, req_y, req_u->len_s); req_u->pat_c[req_u->len_s] = '\0'; - // TODO: add null terminator? return c3y; } @@ -394,19 +389,12 @@ _fine_sift_resp(u3_head* hed_u, if(rem_w > len_w) { return c3n; } + c3_y pre_y = _ames_sift_prelude(hed_u, &res_u->pre_u, len_w, res_y); + res_y += pre_y; + memcpy(res_u->sig_y, res_y, 64); res_y += 64; - res_u->lyf_w = ( - (res_y[0] << 0x18) - | (res_y[1] << 0x10) - | (res_y[2] << 0x8) - | (res_y[3] << 0x0)); - res_y += 4; - - _ames_ship_to_chubs(res_u->hos_d, hed_u->sac_y, res_y); - res_y += hed_u->sac_y; - res_u->fra_w = ( (res_y[0] << 0x18) | (res_y[1] << 0x10) @@ -414,9 +402,6 @@ _fine_sift_resp(u3_head* hed_u, | (res_y[3] << 0x0)); res_y += 4; - _ames_ship_to_chubs(res_u->hos_d, hed_u->rac_y, res_y); - res_y += hed_u->rac_y; - res_u->len_s = c3_min(384, (res_y[0] << 0x8) @@ -529,7 +514,6 @@ _fine_etch_resp(u3_head* hed_u, memcpy(pac_w, &res_u->fra_w, 4); *pac_w = res_u->fra_w; // TODO: check byte order - _ames_ship_of_chubs(res_u->hos_d, sen_y, pac_y + 4); *(pac_y + sen_y + 4) = (0xff << 0) & res_u->len_s; *(pac_y + sen_y + 5) = (0xff << 1) & res_u->len_s; @@ -1354,12 +1338,8 @@ static void _fine_hear(u3_ames* sam_u, { u3_head hed_u; //u3_body bod_u; - c3_o val_o = _ames_sift_head(&hed_u, hun_y); - if(c3y == val_o) { - // invalid, maybe crash? - // - return; - } + c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); + // skip past header len_w -= 4; hun_y += 4; @@ -1383,36 +1363,60 @@ static void _fine_hear(u3_ames* sam_u, if(u3_none == cac) { // cache miss // packet scry path - // /packet/requested/path/elements/ + // /packet/requested/path/elements // // eg: - // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10/20 - // (fragment num is 20) + // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10 // - u3_noun pax = u3dc("snoc", - u3do("stab", u3i_string(req_u.pat_c)), - u3i_words(1, &req_u.fra_w)); + u3_noun pax = u3nc(u3i_string("packet"), + u3do("stab", u3i_string(req_u.pat_c))); + + u3_reqp* rep_u = c3_malloc(sizeof(*rep_u)); rep_u->sam_u = sam_u; memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, - u3nc(u3i_string("packet"), pax), rep_u, _fine_pack_scry_cb); + pax, rep_u, _fine_pack_scry_cb); } else if(u3_nul == cac) { // cache hit, unbound // do nothing, maybe report? } else { - u3_noun hit = u3t(cac); - + // shape + // + u3_noun fra = u3dc("snag", u3i_word(req_u.fra_w), u3t(cac)); // - u3_resp res; - // _fine_etch_resp(); + + c3_w fra_w = u3r_met(3, fra); + c3_y* fra_y = c3_calloc(fra_w); + + u3r_bytes(0, fra_w, fra_y, fra); - //_fine_send(); + u3_resp* res_u = c3_calloc(sizeof(*res_u)); + c3_assert(c3y == _fine_sift_resp(&hed_u, res_u, fra_w, fra_y)); + + memcpy(&res_u->pre_u, &req_u.pre_u, sizeof(u3_prel)); + c3_y* res_y; + c3_w res_w = _fine_etch_resp(&hed_u, res_u, &res_y); + + // TODO: where free? maybe stack allocate instead? + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + pen_u->typ_y = 2; + pen_u->res_u = res_u; + pen_u->len_w = res_w; + pen_u->hun_y = res_y; + pen_u->her_d[0] = res_u->pre_u.sen_d[0]; + pen_u->her_d[1] = res_u->pre_u.sen_d[1]; + pen_u->lan_u = lan_u; + pen_u->sam_u = sam_u; + + _fine_send(pen_u); + + return; } } else { u3_resp res_u; @@ -1426,20 +1430,44 @@ static void _fine_hear(u3_ames* sam_u, u3_noun wir = u3nc(c3__fine, u3_nul); c3_w num_w = res_u.num_w; c3_w fra_w = res_u.fra_w; - u3_noun cad = u3nq(c3__fund, - pat, - u3i_words(1, &fra_w), - u3nc(u3i_words(1, &res_u.num_w), - u3i_bytes(res_u.siz_s, res_u.dat_y))); - + u3_noun cad = u3nc(c3__purr, u3i_bytes(len_w, hun_y)); u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, wir, cad); u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); - - // TODO: moar stats? } } +static void +_fine_request(u3_ames* sam_u, + u3_lane lan_u, + u3_noun req) +{ + u3l_log("fine: request\n"); + + u3_pend pen_u; + u3_head hed_u; + u3_requ req_u; + + + c3_w req_w = u3r_met(3, req); + c3_y* req_y = c3_calloc(req_w); + u3r_bytes(0, req_w, req_y, req); + + _ames_sift_head(&hed_u, req_y); + req_y += 4; + req_w -= 4; + + _fine_sift_requ(&hed_u, &req_u, req_w, req_y); + + + pen_u.typ_y = 1; + pen_u.her_d[0] = req_u.pre_u.rec_d[0]; + pen_u.her_d[1] = req_u.pre_u.rec_d[1]; + + pen_u.lan_u = lan_u; + pen_u.sam_u = sam_u; +} + /* _ames_hear(): parse a (potential) packet, dispatch appropriately. */ static void @@ -1484,7 +1512,7 @@ _ames_hear(u3_ames* sam_u, } else if (c3n == is_ames_o) { // TODO: dispatch fine request - //_fine_hear(sam_u, lan_u, len_w, hun_y) + _fine_hear(sam_u, *lan_u, len_w, hun_y); } // ensure the protocol version matches ours @@ -1708,25 +1736,17 @@ _ames_ef_turf(u3_ames* sam_u, u3_noun tuf) /* fine_io_kick:(): receive effect from arvo * TODO: */ -static c3_o _fine_io_kick(u3_noun nun) { - /** - * +task:fine - * $% [%find *] :: request - * [%fund =path frag-num=@ud frag-tot=@ud contents=@] - * == - * +gift:fine - * $% [%made *] :: notification - * [%find =lane =path] :: request packet to unix - * == - */ +static c3_o _fine_io_kick(u3_auto* car_u, u3_noun wir, u3_noun nun) { + u3_ames* sam_u = (u3_ames*)car_u; u3_noun hed = u3h(nun); - if(c3__made == hed) { + if(c3__hoot == hed) { // TODO: respond to notification of bound data - // put in cache return c3y; - } else if(c3__find == hed) { - // TODO: emit request packet to host ship - // _fine_io_request(); + } else if(c3__howl == hed) { + u3_noun lan, hot; + u3x_cell(u3t(nun), &lan, &hot); + u3_lane lan_u = u3_ames_decode_lane(lan); + _fine_request(sam_u, lan_u, hot); return c3y; } else { return c3n; diff --git a/shell.nix b/shell.nix index b1858df93..c6d03692a 100644 --- a/shell.nix +++ b/shell.nix @@ -22,7 +22,7 @@ let # # Typically the inputs listed here also have a shell.nix in their respective # source directory you can use directly. - inputsFrom = with pkgsLocal; [ ent herb urbit urcrypt ]; + inputsFrom = with pkgsLocal; [ ent urbit urcrypt ]; # Collect the named attribute from all dependencies listed in inputsFrom. mergeFrom = name: pkgs.lib.concatLists (pkgs.lib.catAttrs name inputsFrom); diff --git a/test b/test new file mode 100644 index 000000000..ff0e118fd --- /dev/null +++ b/test @@ -0,0 +1,2 @@ +~[46.318 46.574 46.830 47.086 47.342 47.598 47.854 48.110 48.366 48.622 48.878 49.134 49.390 49.646 49.902 50.158 50.414] + From 90cdc2de6aebd5b8c313ad84034c4264f7f94289 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 26 Jan 2022 18:01:48 -0600 Subject: [PATCH 020/168] wip --- nix/pkgs/2 | 2101 +++++++++++++++++++++++++++++++++ pkg/urbit/include/vere/vere.h | 2 +- pkg/urbit/vere/auto.c | 5 +- pkg/urbit/vere/io/ames.c | 340 ++++-- 4 files changed, 2377 insertions(+), 71 deletions(-) create mode 100644 nix/pkgs/2 diff --git a/nix/pkgs/2 b/nix/pkgs/2 new file mode 100644 index 000000000..f479e9c01 --- /dev/null +++ b/nix/pkgs/2 @@ -0,0 +1,2101 @@ +/* vere/ames.c +** +*/ +#include "all.h" +#include "vere/vere.h" +#include "ur/serial.h" + +/* u3_pact: outbound ames packet. +*/ + typedef struct _u3_pact { + uv_udp_send_t snd_u; // udp send request + u3_lane lan_u; // destination lane + c3_w len_w; // length in bytes + c3_y* hun_y; // packet buffer + c3_y imp_y; // galaxy number (optional) + c3_c* dns_c; // galaxy fqdn (optional) + struct _u3_ames* sam_u; // ames backpointer + } u3_pact; + +/* u3_fine: fine networking +*/ + typedef struct _u3_fine { + u3_auto car_u; // fine driver + c3_y ver_y; // fine protocol + u3p(u3h_root) sac_p; // scry cache hashtable + struct _u3_ames* sam_u; // ames backpointer + } u3_fine; + +/* u3_ames: ames networking. +*/ + typedef struct _u3_ames { // packet network state + u3_auto car_u; // ames driver + u3_fine fin_s; // fine networking + u3_pier* pir_u; // pier + union { // uv udp handle + uv_udp_t wax_u; // + uv_handle_t had_u; // + }; // + c3_l sev_l; // instance number + ur_cue_test_t* tes_u; // cue-test handle + u3_cue_xeno* sil_u; // cue handle + c3_c* dns_c; // domain XX multiple/fallback + c3_y ver_y; // protocol version + u3p(u3h_root) lax_p; // lane scry cache + struct _u3_panc* pac_u; // packets pending forwards + c3_w imp_w[256]; // imperial IPs + time_t imp_t[256]; // imperial IP timestamps + c3_o imp_o[256]; // imperial print status + struct { // config: + c3_o net_o; // can send + c3_o see_o; // can scry + c3_o fit_o; // filtering active + } fig_u; // + struct { // stats: + c3_d dop_d; // drop count + c3_d fal_d; // crash count + c3_d saw_d; // successive scry failures + c3_d hed_d; // failed to read header + c3_d vet_d; // version mismatches filtered + c3_d mut_d; // invalid mugs filtered + c3_d bod_d; // failed to read body + c3_d foq_d; // forward queue size + c3_d fow_d; // forwarded count + c3_d fod_d; // forwards dropped count + } sat_u; // + } u3_ames; + +/* u3_head: ames or fine packet header +*/ + typedef struct _u3_head { + c3_o req_o; // is request (fine only) + c3_o sim_o; // is ames protocol? + c3_y ver_y; // protocol version + c3_y sac_y; // sender class + c3_y rac_y; // receiver class + c3_l mug_l; // truncated mug hash of u3_body + c3_o rel_o; // relayed? + } u3_head; + +/* u3_prel: ames/fine packet prelude +*/ + typedef struct _u3_prel { + c3_y sic_y; // sender life tick + c3_y ric_y; // receiver life tick + c3_d sen_d[2]; // sender/requester + c3_d rec_d[2]; // receiver/responder + c3_d rog_d; // origin lane (optional) + } u3_prel; + +/* TODO: request response bodies for scry */ +/* u3_requ: fine packet request */ + typedef struct _u3_requ { + u3_prel pre_u; + c3_y sig_y[64]; // requester signature + c3_w fra_w; // fragment number + c3_s len_s; // path length + c3_c* pat_c; // path as ascii + } u3_requ; + + typedef struct _u3_reqp { + u3_ames* sam_u; + u3_head hed_u; + u3_requ req_u; + } u3_reqp; + +/* u3_resp: fine packet response */ + typedef struct _u3_resp { + u3_prel pre_u; + // request: + c3_w fra_w; // fragment number + c3_s len_s; // path length + c3_c* pat_c; // path as ascii + // response: + c3_y sig_y[64]; // host signature + c3_w num_w; // number of fragments + c3_s siz_s; // datum size + c3_y* dat_y; // datum (0 if null response) + } u3_resp; + + + /* u3_pend: generic ames or fine pending packet */ + typedef struct _u3_pend { + uv_udp_send_t snd_u; // udp send request + c3_y typ_y; // 0 for ames, 1 for fine request, 2 for fine response + c3_d her_d[2]; // recipent mars address + c3_c* dns_c; // galaxy FQDN + c3_y* hun_y; // packet contents + c3_w len_w; // packet contents + u3_lane lan_u; // recipient lane + u3_ames* sam_u; // ames backpointer + union { + u3_resp* res_u; + u3_reqp* req_u; + u3_pact* pac_u; + }; + } u3_pend; + +/* u3_body: ames packet body +*/ + typedef struct _u3_body { + u3_prel pre_u; // prelude + c3_s con_s; // content size + c3_y* con_y; // content + c3_l mug_l; // checksum + } u3_body; + +/* u3_panc: deconstructed incoming packet +*/ + typedef struct _u3_panc { + u3_ames* sam_u; // ames backpointer + struct _u3_panc* pre_u; // previous packet + struct _u3_panc* nex_u; // next packet + u3_lane ore_u; // origin lane + u3_head hed_u; // header + u3_body bod_u; // body + void* ptr_v; // buffer (to free) + } u3_panc; + +/* _ames_alloc(): libuv buffer allocator. +*/ +static void +_ames_alloc(uv_handle_t* had_u, + size_t len_i, + uv_buf_t* buf + ) +{ + // we allocate 2K, which gives us plenty of space + // for a single ames packet (max size 1060 bytes) + // + void* ptr_v = c3_malloc(2048); + *buf = uv_buf_init(ptr_v, 2048); +} + +/* _ames_pact_free(): free packet struct. +*/ +static void +_ames_pact_free(u3_pact* pac_u) +{ + c3_free(pac_u->hun_y); + c3_free(pac_u->dns_c); + c3_free(pac_u); +} + +static void +_ames_pend_free(u3_pend* pen_u) +{ + if(0 == pen_u->typ_y) { // ames packet + _ames_pact_free(pen_u->pac_u); + } else if (1 == pen_u->typ_y) { // fine request + c3_free(pen_u->req_u); + c3_free(pen_u->hun_y); + } else { // fine response + c3_free(pen_u->res_u); + c3_free(pen_u->hun_y); + } + c3_free(pen_u->dns_c); + c3_free(pen_u); +} + +/* _ames_panc_free(): remove references, lose refcounts and free struct +*/ +static void +_ames_panc_free(u3_panc* pac_u) +{ + if ( 0 != pac_u->nex_u ) { + pac_u->nex_u->pre_u = pac_u->pre_u; + } + + if ( 0 != pac_u->pre_u ) { + pac_u->pre_u->nex_u = pac_u->nex_u; + } + else { + c3_assert(pac_u == pac_u->sam_u->pac_u); + pac_u->sam_u->pac_u = pac_u->nex_u; + } + + c3_free(pac_u->ptr_v); + c3_free(pac_u); +} + +/* _ames_sift_head(): parse packet header. +*/ +static c3_o +_ames_sift_head(u3_head* hed_u, c3_y buf_y[4]) +{ + c3_w hed_w = buf_y[0] + | (buf_y[1] << 8) + | (buf_y[2] << 16) + | (buf_y[3] << 24); + + // first three bits are reserved + // + hed_u->req_o = (hed_w >> 2) & 0x1; + hed_u->sim_o = (hed_w >> 3) & 0x1; + hed_u->ver_y = (hed_w >> 4) & 0x7; + hed_u->sac_y = (hed_w >> 7) & 0x3; + hed_u->rac_y = (hed_w >> 9) & 0x3; + hed_u->mug_l = (hed_w >> 11) & 0xfffff; // 20 bits + hed_u->rel_o = (hed_w >> 31) & 0x1; + + // reject packets that don't even claim to be ames packets + // + return hed_u->sim_o; +} + + +/* _ames_chub_bytes(): c3_y[8] to c3_d +** XX factor out, deduplicate with other conversions +*/ +static inline c3_d +_ames_chub_bytes(c3_y byt_y[8]) +{ + return (c3_d)byt_y[0] + | (c3_d)byt_y[1] << 8 + | (c3_d)byt_y[2] << 16 + | (c3_d)byt_y[3] << 24 + | (c3_d)byt_y[4] << 32 + | (c3_d)byt_y[5] << 40 + | (c3_d)byt_y[6] << 48 + | (c3_d)byt_y[7] << 56; +} + +/* _ames_ship_to_chubs(): pack [len_y] bytes into c3_d[2] +*/ +static inline void +_ames_ship_to_chubs(c3_d sip_d[2], c3_y len_y, c3_y* buf_y) +{ + c3_y sip_y[16] = {0}; + memcpy(sip_y, buf_y, c3_min(16, len_y)); + + sip_d[0] = _ames_chub_bytes(sip_y); + sip_d[1] = _ames_chub_bytes(sip_y + 8); +} + +/* _ames_chub_bytes(): c3_d to c3_y[8] +** XX factor out, deduplicate with other conversions +*/ +static inline void +_ames_bytes_chub(c3_y byt_y[8], c3_d num_d) +{ + byt_y[0] = num_d & 0xff; + byt_y[1] = (num_d >> 8) & 0xff; + byt_y[2] = (num_d >> 16) & 0xff; + byt_y[3] = (num_d >> 24) & 0xff; + byt_y[4] = (num_d >> 32) & 0xff; + byt_y[5] = (num_d >> 40) & 0xff; + byt_y[6] = (num_d >> 48) & 0xff; + byt_y[7] = (num_d >> 56) & 0xff; +} + +/* _ames_ship_of_chubs(): unpack c3_d[2] into [len_y] bytes. +*/ +static inline void +_ames_ship_of_chubs(c3_d sip_d[2], c3_y len_y, c3_y* buf_y) +{ + c3_y sip_y[16] = {0}; + + _ames_bytes_chub(sip_y, sip_d[0]); + _ames_bytes_chub(sip_y + 8, sip_d[1]); + + memcpy(buf_y, sip_y, c3_min(16, len_y)); +} + +/* _ames_sift_prelude(): parse prelude, returning length +*/ +static c3_y +_ames_sift_prelude(u3_head* hed_u, + u3_prel* pre_u, + c3_w len_w, + c3_y* pre_y) +{ + c3_y rog_y, sen_y, rec_y, len_y; + + rog_y = ( c3y == hed_u->rel_o )? 6 : 0; + sen_y = 2 << hed_u->sac_y; + rec_y = 2 << hed_u->rac_y; + len_y = rog_y + sen_y + rec_y; + + pre_u->sic_y = pre_y[0] & 0xf; + pre_u->ric_y = pre_y[0] & 0xf0; + + _ames_ship_to_chubs(pre_u->sen_d, sen_y, pre_y + 1); + _ames_ship_to_chubs(pre_u->rec_d, rec_y, pre_y + 1 + sen_y); + + if (rog_y) { + c3_y rag_y[8] = {0}; + memcpy(rag_y, pre_y + 1 + sen_y + rec_y, rog_y); + pre_u->rog_d = _ames_chub_bytes(rag_y); + } + else { + pre_u->rog_d = 0; + } + return len_y; +} + + + +/* _fine_sift_requ(): parse request body, returning success + * TODO: bring up to date +*/ +static c3_o +_fine_sift_requ(u3_head* hed_u, + u3_requ* req_u, + c3_w len_w, + c3_y* req_y) +{ + c3_y pre_y = _ames_sift_prelude(hed_u, &req_u->pre_u, len_w, req_y); + + req_y += pre_y; + + c3_w rem_w = (64 + 4 + 2 + pre_y); + if(rem_w > len_w) { + return c3n; + } + memcpy(req_u->sig_y, req_y, 64); + req_y += 64; + + req_u->fra_w = ( + (req_y[0] << 0x18) + | (req_y[1] << 0x10) + | (req_y[2] << 0x8) + | (req_y[3] << 0x0)); + req_y += 4; + + + req_u->len_s = c3_min(384, + (req_y[0] << 0x8) + | (req_y[1] << 0x0)); + req_y += 2; + + // TODO: strict inequality? + if(rem_w + req_u->len_s != len_w) { + return c3n; + } + + // TODO: defend maliciusly crafted lengths? + req_u->pat_c = c3_calloc(req_u->len_s + 1); + + memcpy(req_u->pat_c, req_y, req_u->len_s); + req_u->pat_c[req_u->len_s] = '\0'; + return c3y; +} + +/* _fine_sift_resp(): parse response body, returning success +*/ +static c3_o +_fine_sift_resp(u3_head* hed_u, + u3_resp* res_u, + c3_w len_w, + c3_y* res_y) +{ + c3_w rem_w = (64 + 4 + hed_u->sac_y + 4 + hed_u->rac_y + 2); + if(rem_w > len_w) { + return c3n; + } + c3_y pre_y = _ames_sift_prelude(hed_u, &res_u->pre_u, len_w, res_y); + res_y += pre_y; + + memcpy(res_u->sig_y, res_y, 64); + res_y += 64; + + res_u->fra_w = ( + (res_y[0] << 0x18) + | (res_y[1] << 0x10) + | (res_y[2] << 0x8) + | (res_y[3] << 0x0)); + res_y += 4; + + + res_u->len_s = c3_min(384, + (res_y[0] << 0x8) + | (res_y[1] << 0x0)); + res_y += 2; + + // TODO: strict inequality? + if(rem_w + res_u->len_s != len_w) { + return c3n; + } + + // TODO: defend maliciusly crafted lengths? + res_u->pat_c = c3_malloc(res_u->len_s); + + memcpy(res_u->pat_c, res_y, res_u->len_s); + // TODO: add null terminator? + return c3y; +} + +/* _ames_sift_body(): parse packet body. +*/ +static c3_o +_ames_sift_body(u3_head* hed_u, + u3_body* bod_u, + c3_w len_w, + c3_y* bod_y) +{ + c3_y rog_y = ( c3y == hed_u->rel_o )? 6 : 0; + c3_y* gob_y = bod_y + rog_y; + c3_s gob_s = len_w - rog_y; + + c3_y pre_y = _ames_sift_prelude(hed_u, &bod_u->pre_u, len_w, bod_y); + + if (pre_y >= len_w ) { + return c3n; + } + else { + bod_u->mug_l = u3r_mug_bytes(gob_y, gob_s) & 0xfffff; + + bod_u->con_y = gob_y + 4; + + return c3y; + } +} + +/* _ames_etch_head(): serialize packet header. +*/ +static void +_ames_etch_head(u3_head* hed_u, c3_y buf_y[4]) +{ + c3_w hed_w = ((hed_u->req_o & 0x1) << 2) + ^ ((hed_u->sim_o & 0x1) << 3) + ^ ((hed_u->ver_y & 0x7) << 4) + ^ ((hed_u->sac_y & 0x3) << 7) + ^ ((hed_u->rac_y & 0x3) << 9) + ^ ((hed_u->mug_l & 0xfffff) << 11) + ^ ((hed_u->rel_o & 0x1) << 31); + + // only version 0 currently recognized + // + c3_assert( 0 == hed_u->ver_y ); // XX remove after testing + + buf_y[0] = hed_w & 0xff; + buf_y[1] = (hed_w >> 8) & 0xff; + buf_y[2] = (hed_w >> 16) & 0xff; + buf_y[3] = (hed_w >> 24) & 0xff; +} + +/* _ames_etch_prelude(): serialize packet prelude +*/ +static c3_y +_ames_etch_prelude(u3_head* hed_u, u3_prel* pre_u, c3_y* buf_y) +{ + c3_y rog_y = ( c3y == hed_u->rel_o ) ? 6 : 0; // origin len + c3_y sen_y = 2 << pre_u->sic_y; + c3_y rec_y = 2 << pre_u->ric_y; + c3_y len_y = sen_y + rec_y + rog_y; + + + // copy lives + buf_y[0] = (pre_u->sic_y & 0xf) ^ ((pre_u->ric_y & 0xf) << 4); + + _ames_ship_of_chubs(pre_u->sen_d, sen_y, buf_y + 1); + _ames_ship_of_chubs(pre_u->rec_d, rec_y, buf_y + 1 + sen_y); + + if ( rog_y ) { + c3_y rag_y[8] = {0}; + _ames_bytes_chub(rag_y, pre_u->rog_d); + memcpy(buf_y, rag_y, rog_y); + } + return len_y; +} + +/* _fine_etch_resp(): serialise response packet + */ +static c3_w +_fine_etch_resp(u3_head* hed_u, + u3_resp* res_u, + c3_y** out_y) +{ + c3_assert(0 == hed_u->req_o); + c3_assert(0 == hed_u->sim_o); + + c3_y sen_y = 2 << hed_u->sac_y; // sender len + c3_y rec_y = 2 << hed_u->rac_y; // receiver len + c3_y len_w = 80 + sen_y + rec_y + res_u->siz_s + res_u->len_s; + + c3_y* pac_y = c3_calloc(len_w); + c3_w* pac_w = (c3_w*)pac_y; + + memcpy(pac_w, &res_u->fra_w, 4); + *pac_w = res_u->fra_w; // TODO: check byte order + + *(pac_y + sen_y + 4) = (0xff << 0) & res_u->len_s; + *(pac_y + sen_y + 5) = (0xff << 1) & res_u->len_s; + + memcpy(pac_y + sen_y + 6, res_u->pat_c, res_u->len_s); + + memcpy(pac_y + sen_y + 6 + res_u->len_s, &res_u->sig_y, 64 + 4 + 4 + 2); + + return len_w; +} + + +/* _ames_etch_pack(): serialize packet header and body. +*/ +static c3_w +_ames_etch_pack(u3_head* hed_u, + u3_body* bod_u, + c3_y** out_y) +{ + c3_y sen_y = 2 << hed_u->sac_y; // sender len + c3_y rec_y = 2 << hed_u->rac_y; // receiver len + c3_y rog_y = ( c3y == hed_u->rel_o ) ? 6 : 0; // origin len + c3_w bod_w = rog_y + 1 + sen_y + rec_y + bod_u->con_s; // body len + c3_w len_w = 4 + bod_w; // packet len + c3_y* pac_y = c3_malloc(len_w); // output buf + c3_y* bod_y = pac_y + 4; // body cursor + + // serialize the head + // + _ames_etch_head(hed_u, pac_y); + + c3_y pre_y = _ames_etch_prelude(hed_u, &bod_u->pre_u, bod_y + 4); + c3_y* gob_y = bod_y + pre_y; // after origin + + // serialize the body + memcpy(gob_y, bod_u->con_y, bod_u->con_s); + + *out_y = pac_y; + return len_w; +} + +/* _ames_send_cb(): send callback. +*/ +static void +_ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) +{ + u3_pend* pen_u = (u3_pend*)req_u; + u3_ames* sam_u = pen_u->sam_u; + + if (sas_i) { + u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); + sam_u->fig_u.net_o = c3n; + } + else { + sam_u->fig_u.net_o = c3y; + } + + //_ames_pend_free(pen_u); +} + +#define _fine_send _ames_send +/* _ames_send(): send buffer to address on port. +*/ +static void +_ames_send(u3_pend* pen_u) +{ + u3l_log("ames: send"); + u3_ames* sam_u = pen_u->sam_u; + + // TODO: prevalidation? + /*if ( !pen_u->hun_y ) { + // _ames_pact_free(pac_u); + //return; + } + else */ { + struct sockaddr_in add_u; + + memset(&add_u, 0, sizeof(add_u)); + add_u.sin_family = AF_INET; + add_u.sin_addr.s_addr = htonl(pen_u->lan_u.pip_w); + add_u.sin_port = htons(pen_u->lan_u.por_s); + + { + uv_buf_t buf_u = uv_buf_init((c3_c*)pen_u->hun_y, pen_u->len_w); + + c3_i sas_i = uv_udp_send(&pen_u->snd_u, + &sam_u->wax_u, + &buf_u, 1, + (const struct sockaddr*)&add_u, + _ames_send_cb); + + if ( sas_i ) { + if ( c3y == sam_u->fig_u.net_o ) { + u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); + sam_u->fig_u.net_o = c3n; + } + + _ames_pend_free(pen_u); + } + } + } +} + +/* u3_ames_decode_lane(): deserialize noun to lane; 0.0.0.0:0 if invalid +*/ +u3_lane +u3_ames_decode_lane(u3_atom lan) { + u3_lane lan_u; + c3_d lan_d; + + if ( c3n == u3r_safe_chub(lan, &lan_d) || (lan_d >> 48) != 0 ) { + return (u3_lane){0, 0}; + } + + u3z(lan); + + lan_u.pip_w = (c3_w)lan_d; + lan_u.por_s = (c3_s)(lan_d >> 32); + return lan_u; +} + +/* u3_ames_lane_to_chub(): serialize lane to double-word +*/ +c3_d +u3_ames_lane_to_chub(u3_lane lan) { + return ((c3_d)lan.por_s << 32) ^ (c3_d)lan.pip_w; +} + +/* u3_ames_encode_lane(): serialize lane to noun +*/ +u3_atom +u3_ames_encode_lane(u3_lane lan) { + return u3i_chub(u3_ames_lane_to_chub(lan)); +} + +/* _ames_lane_into_cache(): put las for who into cache, including timestamp +*/ +static void +_ames_lane_into_cache(u3p(u3h_root) lax_p, u3_noun who, u3_noun las) { + struct timeval tim_tv; + gettimeofday(&tim_tv, 0); + u3_noun now = u3_time_in_tv(&tim_tv); + u3_noun val = u3nc(las, now); + u3h_put(lax_p, who, val); + u3z(who); +} + +/* _ames_lane_from_cache(): retrieve lane for who from cache, if any & fresh +*/ +static u3_weak +_ames_lane_from_cache(u3p(u3h_root) lax_p, u3_noun who) { + u3_weak lac = u3h_git(lax_p, who); + + if ( u3_none != lac ) { + struct timeval tim_tv; + gettimeofday(&tim_tv, 0); + u3_noun now = u3_time_in_tv(&tim_tv); + u3_noun den = u3t(lac); + + // consider entries older than 2 minutes stale, ignore them + // + if ( 120000 > u3_time_gap_ms(u3k(den), now) ) { + lac = u3k(u3h(lac)); + } else { + lac = u3_none; + } + } + + u3z(who); + return lac; +} + +/* _ames_serialize_packet(): u3_panc to atom, updating the origin lane if dop_o +** (retains pac_u) +*/ +static u3_noun +_ames_serialize_packet(u3_panc* pac_u, c3_o dop_o) +{ + // update the body's lane, if: + // - we're supposed to (dop_o) + // - it hasn't already been updated (rel_o) + // - sender is not a galaxy + // + if ( c3y == dop_o + && c3n == pac_u->hed_u.rel_o + && !( ( 256 > pac_u->bod_u.pre_u.sen_d[0] ) + && ( 0 == pac_u->bod_u.pre_u.sen_d[1] ) ) ) + { + pac_u->hed_u.rel_o = c3y; + pac_u->bod_u.pre_u.rog_d = u3_ames_lane_to_chub(pac_u->ore_u); + } + + // serialize the packet + // + // XX serialize on stack? + // + { + u3_noun pac; + c3_y* pac_y; + c3_w len_w = _ames_etch_pack(&pac_u->hed_u, + &pac_u->bod_u, + &pac_y); + pac = u3i_bytes(len_w, pac_y); + c3_free(pac_y); + + return pac; + } +} + +/* _ames_czar_port(): udp port for galaxy. +*/ +static c3_s +_ames_czar_port(c3_y imp_y) +{ + if ( c3n == u3_Host.ops_u.net ) { + return 31337 + imp_y; + } + else { + return 13337 + imp_y; + } +} + +/* _ames_czar_gone(): galaxy address resolution failed. +*/ +static void +_ames_czar_gone(u3_pend* pen_u, time_t now) +{ + u3_ames* sam_u = pen_u->sam_u; + c3_d imp_d = pen_u->her_d[0]; + + if ( c3y == sam_u->imp_o[imp_d] ) { + u3l_log("ames: czar at %s: not found (b)\n", pen_u->dns_c); + sam_u->imp_o[imp_d] = c3n; + } + + if ( (0 == sam_u->imp_w[imp_d]) || + (0xffffffff == sam_u->imp_w[imp_d]) ) + { + sam_u->imp_w[imp_d] = 0xffffffff; + } + + // keep existing ip for 5 more minutes + // + sam_u->imp_t[imp_d] = now; + + _ames_pend_free(pen_u); +} + +/* _ames_czar_here(): galaxy address resolution succeeded. +*/ +static void +_ames_czar_here(u3_pend* pen_u, time_t now, struct sockaddr_in* add_u) +{ + u3_ames* sam_u = pen_u->sam_u; + c3_y imp_y = pen_u->her_d[0]; + c3_w old_w = sam_u->imp_w[imp_y]; + c3_w pip_w = ntohl(add_u->sin_addr.s_addr); + + if ( pip_w != old_w ) { + u3_noun nam = u3dc("scot", c3__if, u3i_word(pip_w)); + c3_c* nam_c = u3r_string(nam); + + u3l_log("ames: czar %s: ip %s\n", pen_u->dns_c, nam_c); + + c3_free(nam_c); + u3z(nam); + } + + sam_u->imp_w[imp_y] = pip_w; + sam_u->imp_t[imp_y] = now; + sam_u->imp_o[imp_y] = c3y; + + pen_u->lan_u.pip_w = pip_w; + _ames_send(pen_u); +} + +/* _ames_czar_cb(): galaxy address resolution callback. +*/ +static void +_ames_czar_cb(uv_getaddrinfo_t* adr_u, + c3_i sas_i, + struct addrinfo* aif_u) +{ + { + u3_pend* pen_u = (u3_pend*)adr_u->data; + struct addrinfo* rai_u = aif_u; + time_t now = time(0); + + while ( rai_u ) { + if ( (AF_INET == rai_u->ai_family) ) { + _ames_czar_here(pen_u, now, (struct sockaddr_in *)rai_u->ai_addr); + break; + } + else { + rai_u = rai_u->ai_next; + } + } + + if ( !rai_u ) { + _ames_czar_gone(pen_u, now); + } + } + + c3_free(adr_u); + uv_freeaddrinfo(aif_u); +} + +/* _ames_czar(): galaxy address resolution. +*/ +static void +_ames_czar(u3_pend* pen_u) +{ + u3_ames* sam_u = pen_u->sam_u; + + c3_d imp_d = pen_u->her_d[0]; + + c3_assert( imp_d < 256 ); + + pen_u->lan_u.por_s = _ames_czar_port(imp_d); + + if ( c3n == u3_Host.ops_u.net ) { + pen_u->lan_u.pip_w = 0x7f000001; + _ames_send(pen_u); + return; + } + + // if we don't have a galaxy domain, no-op + // + if ( !sam_u->dns_c ) { + u3_noun nam = u3dc("scot", 'p', pen_u->her_d[0]); + c3_c* nam_c = u3r_string(nam); + u3l_log("ames: no galaxy domain for %s, no-op\r\n", nam_c); + + c3_free(nam_c); + u3z(nam); + return; + } + + { + c3_w pip_w = sam_u->imp_w[imp_d]; + time_t wen = sam_u->imp_t[imp_d]; + time_t now = time(0); + + // backoff for 5 minutes after failed lookup + // + if ( ( now < wen ) // time shenanigans! + || ( (0xffffffff == pip_w) // sentinal ip address + && ((now - wen) < 300) ) ) + { + _ames_pend_free(pen_u); + return; + } + // cached addresses have a 5 minute TTL + // + else if ( (0 != pip_w) && ((now - wen) < 300) ) { + pen_u->lan_u.pip_w = pip_w; + _ames_send(pen_u); + return; + } + else { + c3_i sas_i; + + { + u3_noun nam = u3dc("scot", 'p', imp_d); + c3_c* nam_c = u3r_string(nam); + + // NB: . separator not counted, as [nam_c] includes a ~ that we skip + // + pen_u->dns_c = c3_malloc(1 + strlen(nam_c) + strlen(sam_u->dns_c)); + sas_i = snprintf(pen_u->dns_c, 255, "%s.%s", nam_c + 1, sam_u->dns_c); + + c3_free(nam_c); + u3z(nam); + } + + if ( 255 <= sas_i ) { + u3l_log("ames: czar: galaxy domain %s truncated\n", sam_u->dns_c); + _ames_pend_free(pen_u); + return; + } + + { + uv_getaddrinfo_t* adr_u = c3_malloc(sizeof(*adr_u)); + adr_u->data = pen_u; + + if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u, + _ames_czar_cb, + pen_u->dns_c, 0, 0)) ) + { + u3l_log("ames: %s\n", uv_strerror(sas_i)); + _ames_czar_gone(pen_u, now); + return; + } + } + } + } +} + +/* _ames_ef_send(): send packet to network (v4). +*/ +static void +_ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) +{ + if ( c3n == sam_u->car_u.liv_o ) { + u3l_log("ames: not yet live, dropping outbound\r\n"); + u3z(lan); u3z(pac); + return; + } + + u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); + pac_u->sam_u = sam_u; + pac_u->len_w = u3r_met(3, pac); + pac_u->hun_y = c3_malloc(pac_u->len_w); + + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + pen_u->typ_y = 0; + pen_u->len_w = pac_u->len_w; + pen_u->hun_y = pac_u->hun_y; + pen_u->sam_u = sam_u; + + + + u3r_bytes(0, pac_u->len_w, pac_u->hun_y, pac); + + u3_noun tag, val; + u3x_cell(lan, &tag, &val); + c3_assert( (c3y == tag) || (c3n == tag) ); + + // galaxy lane; do DNS lookup and send packet + // + if ( c3y == tag ) { + c3_assert( c3y == u3a_is_cat(val) ); + c3_assert( val < 256 ); + + pac_u->imp_y = val; + pen_u->her_d[0] = val; + _ames_czar(pen_u); + } + // non-galaxy lane + // + else { + u3_lane lan_u = u3_ames_decode_lane(u3k(val)); + // convert incoming localhost to outgoing localhost + // + lan_u.pip_w = ( 0 == lan_u.pip_w )? 0x7f000001 : lan_u.pip_w; + // if in local-only mode, don't send remote packets + // + if ( (c3n == u3_Host.ops_u.net) && (0x7f000001 != lan_u.pip_w) ) { + _ames_pact_free(pac_u); + } + // if the lane is uninterpretable, silently drop the packet + // + else if ( 0 == lan_u.por_s ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("ames: inscrutable lane\n"); + } + _ames_pact_free(pac_u); + } + // otherwise, mutate destination and send packet + // + else { + pen_u->lan_u = lan_u; + _ames_send(pen_u); + } + } + u3z(lan); u3z(pac); +} + +/* _ames_cap_queue(): cap ovum queue at 1k, dropping oldest packets. +*/ +static void +_ames_cap_queue(u3_ames* sam_u) +{ + u3_ovum* egg_u = sam_u->car_u.ext_u; + + while ( egg_u && (1000 < sam_u->car_u.dep_w) ) { + u3_ovum* nex_u = egg_u->nex_u; + + if ( c3__hear == u3h(egg_u->cad) ) { + u3_auto_drop(&sam_u->car_u, egg_u); + sam_u->sat_u.dop_d++; + + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("ames: packet dropped (%" PRIu64 " total)\n", sam_u->sat_u.dop_d); + } + } + + egg_u = nex_u; + } + + if ( (sam_u->sat_u.dop_d && (0 == (sam_u->sat_u.dop_d % 1000))) + && !(u3C.wag_w & u3o_verbose) ) + { + u3l_log("ames: packet dropped (%" PRIu64 " total)\n", sam_u->sat_u.dop_d); + } +} + +/* _ames_punt_goof(): print %bail error report(s). +*/ +static void +_ames_punt_goof(u3_noun lud) +{ + if ( 2 == u3qb_lent(lud) ) { + u3_pier_punt_goof("hear", u3k(u3h(lud))); + u3_pier_punt_goof("crud", u3k(u3h(u3t(lud)))); + } + else { + u3_noun dul = lud; + c3_w len_w = 1; + + while ( u3_nul != dul ) { + u3l_log("ames: bail %u\r\n", len_w++); + u3_pier_punt_goof("ames", u3k(u3h(dul))); + dul = u3t(dul); + } + } + + u3z(lud); +} + +/* _ames_hear_bail(): handle packet failure. +*/ +static void +_ames_hear_bail(u3_ovum* egg_u, u3_noun lud) +{ + u3_ames* sam_u = (u3_ames*)egg_u->car_u; + sam_u->sat_u.fal_d++; + + if ( (u3C.wag_w & u3o_verbose) + || (0 == (sam_u->sat_u.fal_d % 1000)) ) + { + _ames_punt_goof(lud); + u3l_log("ames: packet failed (%" PRIu64 " total)\n\n", sam_u->sat_u.fal_d); + } + else { + u3z(lud); + + if ( 0 == (sam_u->sat_u.fal_d % 1000) ) { + u3l_log("ames: packet failed (%" PRIu64 " total)\n\n", sam_u->sat_u.fal_d); + } + } + + u3_ovum_free(egg_u); +} + +/* _ames_put_packet(): add packet to queue, drop old packets on pressure +*/ +static void +_ames_put_packet(u3_ames* sam_u, + u3_noun msg, + u3_lane lan_u) +{ + u3_noun wir = u3nc(c3__ames, u3_nul); + u3_noun cad = u3nt(c3__hear, u3nc(c3n, u3_ames_encode_lane(lan_u)), msg); + + u3_auto_peer( + u3_auto_plan(&sam_u->car_u, + u3_ovum_init(0, c3__a, wir, cad)), + 0, 0, _ames_hear_bail); + + _ames_cap_queue(sam_u); +} + +/* _ames_forward(): forward pac_u onto the (list lane) las, then free pac_u +*/ +static void +_ames_forward(u3_panc* pac_u, u3_noun las) +{ + u3_ames* sam_u = pac_u->sam_u; + + sam_u->sat_u.fow_d++; + if ( 0 == (sam_u->sat_u.fow_d % 1000000) ) { + u3l_log("ames: forwarded %" PRIu64 " total\n", sam_u->sat_u.fow_d); + } + + if ( u3C.wag_w & u3o_verbose ) { + u3_noun sen = u3dc("scot", 'p', u3i_chubs(2, pac_u->bod_u.pre_u.sen_d)); + u3_noun rec = u3dc("scot", 'p', u3i_chubs(2, pac_u->bod_u.pre_u.rec_d)); + c3_c* sen_c = u3r_string(sen); + c3_c* rec_c = u3r_string(rec); + c3_y* pip_y = (c3_y*)&pac_u->ore_u.pip_w; + + u3l_log("ames: forwarding for %s to %s from %d.%d.%d.%d:%d\n", + sen_c, rec_c, + pip_y[0], pip_y[1], pip_y[2], pip_y[3], + pac_u->ore_u.por_s); + + c3_free(sen_c); c3_free(rec_c); + u3z(sen); u3z(rec); + } + + { + u3_noun pac = _ames_serialize_packet(pac_u, c3y); + u3_noun tag, dat, lan, t = las; + + while ( u3_nul != t ) { + u3x_cell(t, &lan, &t); + + // validate lane and skip self if galaxy + // + if ( c3n == u3r_cell(lan, &tag, &dat) ) { + u3l_log("ames: bogus lane\n"); + u3m_p("lan", lan); + } + else { + c3_o sen_o = c3y; + c3_d who_d[2]; + + if ( c3y == tag ) { + u3r_chubs(0, 2, who_d, dat); + + if ( (who_d[0] == sam_u->pir_u->who_d[0]) + && (who_d[1] == sam_u->pir_u->who_d[1]) ) + { + sen_o = c3n; + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("ames: forward skipping self\n"); + } + } + } + + if ( c3y == sen_o ) { + _ames_ef_send(sam_u, u3k(lan), u3k(pac)); + } + } + } + + u3z(pac); + } + + _ames_panc_free(pac_u); + u3z(las); +} + +/* _ames_lane_scry_cb(): learn lane to forward packet on +*/ +static void +_ames_lane_scry_cb(void* vod_p, u3_noun nun) +{ + u3_panc* pac_u = vod_p; + u3_ames* sam_u = pac_u->sam_u; + u3_weak las = u3r_at(7, nun); + + sam_u->sat_u.foq_d--; + + // if scry fails, remember we can't scry, and just inject the packet + // + if ( u3_none == las ) { + if ( 5 < ++sam_u->sat_u.saw_d ) { + u3l_log("ames: giving up scry\n"); + sam_u->fig_u.see_o = c3n; + } + _ames_put_packet(sam_u, _ames_serialize_packet(pac_u, c3n), pac_u->ore_u); + _ames_panc_free(pac_u); + } + else { + sam_u->sat_u.saw_d = 0; + + // cache the scry result for later use + // + _ames_lane_into_cache(sam_u->lax_p, + u3i_chubs(2, pac_u->bod_u.pre_u.rec_d), + u3k(las)); + + // if there is no lane, drop the packet + // + if ( u3_nul == las ) { + _ames_panc_free(pac_u); + } + // if there is a lane, forward the packet on it + // + else { + _ames_forward(pac_u, u3k(las)); + } + } + + u3z(nun); +} + +/* _ames_try_forward(): try to forward a packet for another ship. +*/ +static void +_ames_try_forward(u3_ames* sam_u, + u3_lane* lan_u, + u3_head* hed_u, + u3_body* bod_u, + c3_y* hun_y) +{ + u3_weak lac; + + // if the recipient is a galaxy, their lane is always &+~gax + // + if ( (256 > bod_u->pre_u.rec_d[0]) + && (0 == bod_u->pre_u.rec_d[1]) ) + { + lac = u3nc(c3y, (c3_y)bod_u->pre_u.rec_d[0]); + } + // otherwise, try to get the lane from cache + // + else { + lac = _ames_lane_from_cache(sam_u->lax_p, u3i_chubs(2, bod_u->pre_u.rec_d)); + + // if we don't know the lane, and the scry queue is full, + // just drop the packet + // + //TODO drop oldest item in forward queue in favor of this one. + // ames.c doesn't/shouldn't know about the shape of scry events, + // so can't pluck these out of the event queue like it does in + // _ames_cap_queue. as such, blocked on u3_lord_peek_cancel or w/e. + // + if ( (u3_none == lac) && (1000 < sam_u->sat_u.foq_d) ) { + sam_u->sat_u.fod_d++; + if ( 0 == (sam_u->sat_u.fod_d % 10000) ) { + u3l_log("ames: dropped %" PRIu64 " forwards total\n", + sam_u->sat_u.fod_d); + } + + c3_free(hun_y); + return; + } + // if we know there's no lane, drop the packet + // + else if ( u3_nul == lac ) { + c3_free(hun_y); + return; + } + } + + // proceed with forwarding + // + { + // store the packet details for later processing + // + // XX allocates unnecessarily when we know the lane + // + u3_panc* pac_u = c3_calloc(sizeof(*pac_u)); + pac_u->sam_u = sam_u; + pac_u->hed_u = *hed_u; + pac_u->bod_u = *bod_u; + pac_u->ore_u = *lan_u; + pac_u->ptr_v = hun_y; + + if ( 0 != sam_u->pac_u ) { + pac_u->nex_u = sam_u->pac_u; + sam_u->pac_u->pre_u = pac_u; + } + sam_u->pac_u = pac_u; + + // if we already know the lane, just forward + // + if ( u3_none != lac ) { + _ames_forward(pac_u, lac); + } + // otherwise, there's space in the scry queue; scry the lane out of ames + // + else { + sam_u->sat_u.foq_d++; + u3_noun pax = u3nq(u3i_string("peers"), + u3dc("scot", 'p', u3i_chubs(2, bod_u->pre_u.rec_d)), + u3i_string("forward-lane"), + u3_nul); + u3_pier_peek_last(sam_u->pir_u, u3_nul, c3__ax, + u3_nul, pax, pac_u, _ames_lane_scry_cb); + } + } +} + +#undef AMES_SKIP +#ifdef AMES_SKIP +/* _ames_skip(): decide whether to skip this packet, for rescue +*/ +static c3_o +_ames_skip(u3_body* bod_u) { + if ( bod_u->sen_d[1] == 0 && + ( bod_u->sen_d[0] == 0x743a17a6 + || bod_u->sen_d[0] == 0xea99acb6 + || bod_u->sen_d[0] == 0x10100 + ) ) { + return c3n; + } + else { + return c3y; + } +} +#endif + +/* _fine_pack_scry_cb(): receive all packets for datum out of fine + * TODO: implement + */ +static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) +{ + u3_pend* pen_u = vod_p; + u3_weak pack = u3r_at(3, nun); + // + // hashtable = (path, packet_num) -> cached_result; + // All cases, except 1st ~: put results in cache for all packets + // ~ -> if second request, ask for notification if 2nd, drop on floor + // [~ ~] -> send packet + // [~ ~ *] -> send packet + // TODO: cache logic, counting requests, evict? + + u3_weak lan = _ames_lane_from_cache(pen_u->sam_u->lax_p, + u3i_chubs(2, pen_u->her_d)); + if(u3_none == lan) { + // TODO: enqueue packet for later sending, populate lane cache + } else if(u3_nul == lan) { + // TODO: no lane, drop packet + } else { + _fine_send(pen_u); + } +} + + + +/* _fine_hear(): hear a (potential) packet, dispatch appropriately + */ +// _fine_hear(sam_u, lan_u, len_w, hun_y) +static void _fine_hear(u3_ames* sam_u, + u3_lane lan_u, + c3_w len_w, + c3_y* hun_y) +{ + u3_head hed_u; + //u3_body bod_u; + c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); + + // skip past header + len_w -= 4; + hun_y += 4; + + if(hed_u.req_o) { + // lookup in cache + // (unit (unit (unit packet)) + // ~ -> miss + // [~ ~] -> hit, unbound + // [~ ~ ~] -> hit, empty + // [~ ~ ~ *] -> hit, w/ data + u3_requ req_u; + + + _fine_sift_requ(&hed_u, &req_u, len_w, hun_y); + + u3_noun pat = u3i_string(req_u.pat_c); + + u3_weak cac = u3h_git(sam_u->fin_s.sac_p, pat); + + if(u3_none == cac) { + // cache miss + // packet scry path + // /packet/requested/path/elements + // + // eg: + // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10 + // + u3_noun pax = u3nc(u3i_string("packet"), + u3do("stab", u3i_string(req_u.pat_c))); + + + u3_reqp* rep_u = c3_malloc(sizeof(*rep_u)); + rep_u->sam_u = sam_u; + memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); + memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); + + u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, + pax, rep_u, _fine_pack_scry_cb); + + } else if(u3_nul == cac) { + // cache hit, unbound + // do nothing, maybe report? + } else { + // shape + // + u3_noun fra = u3dc("snag", u3i_word(req_u.fra_w), u3t(cac)); + // + + c3_w fra_w = u3r_met(3, fra); + c3_y* fra_y = c3_calloc(fra_w); + + u3r_bytes(0, fra_w, fra_y, fra); + + u3_resp* res_u = c3_calloc(sizeof(*res_u)); + + c3_assert(c3y == _fine_sift_resp(&hed_u, res_u, fra_w, fra_y)); + + memcpy(&res_u->pre_u, &req_u.pre_u, sizeof(u3_prel)); + + c3_y* res_y; + c3_w res_w = _fine_etch_resp(&hed_u, res_u, &res_y); + + // TODO: where free? maybe stack allocate instead? + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + pen_u->typ_y = 2; + pen_u->res_u = res_u; + pen_u->len_w = res_w; + pen_u->hun_y = res_y; + pen_u->her_d[0] = res_u->pre_u.sen_d[0]; + pen_u->her_d[1] = res_u->pre_u.sen_d[1]; + pen_u->lan_u = lan_u; + pen_u->sam_u = sam_u; + + _fine_send(pen_u); + + return; + } + } else { + u3_resp res_u; + + _fine_sift_resp(&hed_u, &res_u, len_w, hun_y); + u3_noun pat = u3do("stab", u3i_string(res_u.pat_c)); + + + // + // + u3_noun wir = u3nc(c3__fine, u3_nul); + c3_w num_w = res_u.num_w; + c3_w fra_w = res_u.fra_w; + u3_noun cad = u3nc(c3__purr, u3i_bytes(len_w, hun_y)); + + u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, wir, cad); + u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); + } +} + +static void +_fine_request(u3_ames* sam_u, + u3_lane lan_u, + u3_noun req) +{ + u3l_log("fine: request\n"); + + u3_pend pen_u; + u3_head hed_u; + u3_requ req_u; + + + c3_w req_w = u3r_met(3, req); + c3_y* req_y = c3_calloc(req_w); + u3r_bytes(0, req_w, req_y, req); + + _ames_sift_head(&hed_u, req_y); + req_y += 4; + req_w -= 4; + + _fine_sift_requ(&hed_u, &req_u, req_w, req_y); + + + pen_u.typ_y = 1; + pen_u.her_d[0] = req_u.pre_u.rec_d[0]; + pen_u.her_d[1] = req_u.pre_u.rec_d[1]; + + pen_u.lan_u = lan_u; + pen_u.sam_u = sam_u; +} + +/* _ames_hear(): parse a (potential) packet, dispatch appropriately. +*/ +static void +_ames_hear(u3_ames* sam_u, + u3_lane* lan_u, + c3_w len_w, + c3_y* hun_y) +{ + + u3l_log("ames: hear"); + // TODO: move from stack to heap to avoid reparsing + u3_head hed_u; + u3_body bod_u; + + // XX packet filtering needs to revised for two protocol-change scenarios + // + // - packets using old protocol versions from our sponsees + // these must be let through, and this is a transitive condition; + // they must also be forwarded where appropriate + // they can be validated, as we know their semantics + // + // - packets using newer protocol versions + // these should probably be let through, or at least + // trigger printfs suggesting upgrade. + // they cannot be filtered, as we do not know their semantics + // + + // unpack header, ensuring buffer is large enough + // + // + c3_o is_ames_o = _ames_sift_head(&hed_u, hun_y); + + if (4 > len_w) { + sam_u->sat_u.hed_d++; + if ( 0 == (sam_u->sat_u.hed_d % 100000) ) { + u3l_log("ames: %" PRIu64 " dropped, failed to read header\n", + sam_u->sat_u.hed_d); + } + + c3_free(hun_y); + return; + } + else if (c3n == is_ames_o) { + // TODO: dispatch fine request + _fine_hear(sam_u, *lan_u, len_w, hun_y); + } + + // ensure the protocol version matches ours + // + // XX rethink use of [fit_o] here and elsewhere + // + if ( (c3y == sam_u->fig_u.fit_o) + && (sam_u->ver_y != hed_u.ver_y) ) + { + sam_u->sat_u.vet_d++; + if ( 0 == (sam_u->sat_u.vet_d % 100000) ) { + u3l_log("ames: %" PRIu64 " dropped for version mismatch\n", + sam_u->sat_u.vet_d); + } + + c3_free(hun_y); + return; + } + + { + c3_w bod_w = len_w - 4; + c3_y* bod_y = hun_y + 4; + + // unpack and validate the body + // + if ( (c3n == _ames_sift_body(&hed_u, &bod_u, bod_w, bod_y)) ) { + sam_u->sat_u.bod_d++; + if ( 0 == (sam_u->sat_u.bod_d % 100) ) { + u3l_log("ames: %" PRIu64 " dropped, failed to read body\n", + sam_u->sat_u.bod_d); + } + + c3_free(hun_y); + return; + } + + // ensure the mug is valid + // + u3l_log("bod: %ux, hed: %ux\n", hed_u.mug_l, bod_u.mug_l); + if ( bod_u.mug_l != hed_u.mug_l ) { + sam_u->sat_u.mut_d++; + if ( 0 == (sam_u->sat_u.mut_d % 100000) ) { + u3l_log("ames: %" PRIu64 " dropped for invalid mug\n", + sam_u->sat_u.mut_d); + } + + c3_free(hun_y); + return; + } + } + + // if we can scry, + // and we are not the recipient, + // we might want to forward statelessly + // + if ( 0 && (c3y == sam_u->fig_u.see_o) + && ( (bod_u.pre_u.rec_d[0] != sam_u->pir_u->who_d[0]) + || (bod_u.pre_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) + { + _ames_try_forward(sam_u, lan_u, &hed_u, &bod_u, hun_y); + } + // otherwise, inject the packet as an event + // + else { + u3_noun msg = u3i_bytes(len_w, hun_y); + c3_free(hun_y); +#ifdef AMES_SKIP + if (_ames_skip(&bod_u) == c3y ) { + u3z(msg); + } + else { +#endif + _ames_put_packet(sam_u, msg, *lan_u); +#ifdef AMES_SKIP + } +#endif + } +} + +/* _ames_recv_cb(): udp message receive callback. +*/ +static void +_ames_recv_cb(uv_udp_t* wax_u, + ssize_t nrd_i, + const uv_buf_t * buf_u, + const struct sockaddr* adr_u, + unsigned flg_i) +{ + if ( 0 > nrd_i ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("ames: recv: fail: %s\n", uv_strerror(nrd_i)); + } + c3_free(buf_u->base); + } + else if ( 0 == nrd_i ) { + c3_free(buf_u->base); + } + else if ( flg_i & UV_UDP_PARTIAL ) { + if ( u3C.wag_w & u3o_verbose ) { + u3l_log("ames: recv: fail: message truncated\n"); + } + c3_free(buf_u->base); + } + else { + u3_ames* sam_u = wax_u->data; + struct sockaddr_in* add_u = (struct sockaddr_in*)adr_u; + u3_lane lan_u; + + lan_u.por_s = ntohs(add_u->sin_port); + lan_u.pip_w = ntohl(add_u->sin_addr.s_addr); + + // NB: [nrd_i] will never exceed max length from _ames_alloc() + // + _ames_hear(sam_u, &lan_u, (c3_w)nrd_i, (c3_y*)buf_u->base); + } +} + +/* _ames_io_start(): initialize ames I/O. +*/ +static void +_ames_io_start(u3_ames* sam_u) +{ + c3_s por_s = sam_u->pir_u->por_s; + u3_noun who = u3i_chubs(2, sam_u->pir_u->who_d); + u3_noun rac = u3do("clan:title", u3k(who)); + c3_i ret_i; + + if ( c3__czar == rac ) { + c3_y num_y = (c3_y)sam_u->pir_u->who_d[0]; + c3_s zar_s = _ames_czar_port(num_y); + + if ( 0 == por_s ) { + por_s = zar_s; + } + else if ( por_s != zar_s ) { + u3l_log("ames: czar: overriding port %d with -p %d\n", zar_s, por_s); + u3l_log("ames: czar: WARNING: %d required for discoverability\n", zar_s); + } + } + + // Bind and stuff. + { + struct sockaddr_in add_u; + c3_i add_i = sizeof(add_u); + + memset(&add_u, 0, sizeof(add_u)); + add_u.sin_family = AF_INET; + add_u.sin_addr.s_addr = _(u3_Host.ops_u.net) ? + htonl(INADDR_ANY) : + htonl(INADDR_LOOPBACK); + add_u.sin_port = htons(por_s); + + if ( (ret_i = uv_udp_bind(&sam_u->wax_u, + (const struct sockaddr*)&add_u, 0)) != 0 ) + { + u3l_log("ames: bind: %s\n", uv_strerror(ret_i)); + + if ( (c3__czar == rac) && + (UV_EADDRINUSE == ret_i) ) + { + u3l_log(" ...perhaps you've got two copies of vere running?\n"); + } + + // XX revise + // + u3_pier_bail(u3_king_stub()); + } + + uv_udp_getsockname(&sam_u->wax_u, (struct sockaddr *)&add_u, &add_i); + c3_assert(add_u.sin_port); + + sam_u->pir_u->por_s = ntohs(add_u.sin_port); + } + + if ( c3y == u3_Host.ops_u.net ) { + u3l_log("ames: live on %d\n", sam_u->pir_u->por_s); + } + else { + u3l_log("ames: live on %d (localhost only)\n", sam_u->pir_u->por_s); + } + + uv_udp_recv_start(&sam_u->wax_u, _ames_alloc, _ames_recv_cb); + + sam_u->car_u.liv_o = c3y; + u3z(rac); + u3z(who); +} + +/* _ames_ef_turf(): initialize ames I/O on domain(s). +*/ +static void +_ames_ef_turf(u3_ames* sam_u, u3_noun tuf) +{ + if ( u3_nul != tuf ) { + // XX save all for fallback, not just first + // + u3_noun hot = u3k(u3h(tuf)); + c3_w len_w = u3_mcut_host(0, 0, u3k(hot)); + + sam_u->dns_c = c3_malloc(1 + len_w); + u3_mcut_host(sam_u->dns_c, 0, hot); + sam_u->dns_c[len_w] = 0; + + // XX invalidate sam_u->imp_w &c ? + // + + u3z(tuf); + } + else if ( (c3n == sam_u->pir_u->fak_o) && (0 == sam_u->dns_c) ) { + u3l_log("ames: turf: no domains\n"); + } + + // XX is this ever necessary? + // + if ( c3n == sam_u->car_u.liv_o ) { + _ames_io_start(sam_u); + } +} + + +/* fine_io_kick:(): receive effect from arvo + * TODO: + */ +static c3_o _fine_io_kick(u3_auto* car_u, u3_noun wir, u3_noun nun) { + u3_ames* sam_u = (u3_ames*)car_u; + u3_noun hed = u3h(nun); + if(c3__hoot == hed) { + // TODO: respond to notification of bound data + return c3y; + } else if(c3__howl == hed) { + u3_noun lan, hot; + u3x_cell(u3t(nun), &lan, &hot); + u3_lane lan_u = u3_ames_decode_lane(lan); + _fine_request(sam_u, lan_u, hot); + return c3y; + } else { + return c3n; + } +} + +static void _fine_send_fail() +{ + // TODO: log some shit +} + +static void _fine_send_cb() +{ + // TODO: anything to do here? +} + +/* _ames_prot_scry_cb(): receive ames protocol version +*/ +static void +_ames_prot_scry_cb(void* vod_p, u3_noun nun) +{ + u3_ames* sam_u = vod_p; + u3_weak ver = u3r_at(7, nun); + + if ( u3_none == ver ) { + // assume protocol version 0 + // + sam_u->ver_y = 0; + } + else if ( (c3n == u3a_is_cat(ver)) + || (7 < ver) ) { + u3m_p("ames: strange protocol", nun); + sam_u->ver_y = 0; + } + else { + sam_u->ver_y = ver; + } + + // XX revise: filtering should probably be disabled if + // we get a protocol version above the latest one we know + // + sam_u->fig_u.fit_o = c3y; + u3z(nun); +} + +/* _fine_prot_scry_cb(): receive fine protocol version +*/ +static void +_fine_prot_scry_cb(void* vod_p, u3_noun nun) +{ + u3_ames* sam_u = vod_p; + u3_weak ver = u3r_at(7, nun); + + if ( u3_none == ver ) { + // assume protocol version 0 + // + sam_u->fin_s.ver_y = 0; + } + else if ( (c3n == u3a_is_cat(ver)) + || (7 < ver) ) { + u3m_p("fine: strange protocol", nun); + sam_u->fin_s.ver_y = 0; + } + else { + sam_u->fin_s.ver_y = ver; + } + + u3z(nun); +} + +/* _fine_io_talk(): start receiving ames traffic. +*/ +static void _fine_io_talk(u3_auto* car_u) +{ + // do nothing +} + + + +/* _ames_io_talk(): start receiving ames traffic. +*/ +static void +_ames_io_talk(u3_auto* car_u) +{ + u3_ames* sam_u = (u3_ames*)car_u; + _ames_io_start(sam_u); + + // send born event + // + { + // XX remove [sev_l] + // + u3_noun wir = u3nt(c3__newt, + u3dc("scot", c3__uv, sam_u->sev_l), + u3_nul); + u3_noun cad = u3nc(c3__born, u3_nul); + + u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); + } + // TODO: scry the fine protocol out of arvo + // + u3_pier_peek_last(car_u->pir_u, u3_nul, c3__fx, u3_nul, + u3nt(u3i_string("protocol"), u3i_string("version"), u3_nul), + sam_u, _fine_prot_scry_cb); + + // scry the protocol version out of arvo + // + // XX this should be re-triggered periodically, + // or, better yet, %ames should emit a %turf + // (or some other reconfig) effect when it is reset. + // + u3_pier_peek_last(car_u->pir_u, u3_nul, c3__ax, u3_nul, + u3nt(u3i_string("protocol"), u3i_string("version"), u3_nul), + sam_u, _ames_prot_scry_cb); +} + +/* _ames_kick_newt(): apply packet network outputs. +*/ +static c3_o +_ames_kick_newt(u3_ames* sam_u, u3_noun tag, u3_noun dat) +{ + c3_o ret_o; + + switch ( tag ) { + default: { + ret_o = c3n; + } break; + + case c3__send: { + u3_noun lan = u3k(u3h(dat)); + u3_noun pac = u3k(u3t(dat)); + _ames_ef_send(sam_u, lan, pac); + ret_o = c3y; + } break; + + case c3__turf: { + _ames_ef_turf(sam_u, u3k(dat)); + ret_o = c3y; + } break; + } + + u3z(tag); u3z(dat); + return ret_o; +} + +/* _ames_io_kick(): apply effects +*/ +static c3_o +_ames_io_kick(u3_auto* car_u, u3_noun wir, u3_noun cad) +{ + u3_ames* sam_u = (u3_ames*)car_u; + + u3_noun tag, dat, i_wir; + c3_o ret_o; + + if ( (c3n == u3r_cell(wir, &i_wir, 0)) + || (c3n == u3r_cell(cad, &tag, &dat)) ) + { + ret_o = c3n; + } + else { + switch ( i_wir ) { + default: { + ret_o = c3n; + } break; + + // XX should also be c3__ames + // + case c3__newt: { + ret_o = _ames_kick_newt(sam_u, u3k(tag), u3k(dat)); + } break; + + // XX obsolete + // + // used to also handle %west and %woot for tcp proxy setup + // + case c3__ames: { + ret_o = _( c3__init == tag); + } break; + + // this can return through dill due to our fscked up boot sequence + // + // XX s/b obsolete, verify + // + case c3__term: { + if ( c3__send != tag ) { + ret_o = c3n; + } + else { + u3l_log("kick: strange send\r\n"); + ret_o = _ames_kick_newt(sam_u, u3k(tag), u3k(dat)); + } + } break; + } + } + + u3z(wir); u3z(cad); + return ret_o; +} + +/* _ames_exit_cb(): dispose resources aftr close. +*/ +static void +_ames_exit_cb(uv_handle_t* had_u) +{ + u3_ames* sam_u = had_u->data; + + u3_panc* pac_u = sam_u->pac_u; + while (0 != pac_u) { + u3_panc* nex_u = pac_u->nex_u; + _ames_panc_free(pac_u); + pac_u = nex_u; + } + + u3h_free(sam_u->lax_p); + + u3s_cue_xeno_done(sam_u->sil_u); + ur_cue_test_done(sam_u->tes_u); + + c3_free(sam_u); +} + +/* _fine_io_exit(): terminate fine I/O. +*/ +static void +_fine_io_exit(u3_auto* car_u) +{ + // cleanup handled in _ames_io_exit +} + +/* _ames_io_exit(): terminate ames I/O. +*/ +static void +_ames_io_exit(u3_auto* car_u) +{ + u3_ames* sam_u = (u3_ames*)car_u; + uv_close(&sam_u->had_u, _ames_exit_cb); +} + +/* _fine_io_info(): print status info. +*/ +static void +_fine_io_info(u3_auto* car_u) +{ + +} + + +/* _ames_io_info(): print status info. +*/ +static void +_ames_io_info(u3_auto* car_u) +{ + u3_ames* sam_u = (u3_ames*)car_u; + +# define FLAG(a) ( (c3y == a) ? "&" : "|" ) + + u3l_log(" config:\n"); + u3l_log(" filtering: %s\n", FLAG(sam_u->fig_u.fit_o)); + u3l_log(" can send: %s\n", FLAG(sam_u->fig_u.net_o)); + u3l_log(" can scry: %s\n", FLAG(sam_u->fig_u.see_o)); + u3l_log(" counters:\n"); + u3l_log(" dropped: %" PRIu64 "\n", sam_u->sat_u.dop_d); + u3l_log(" forwards dropped: %" PRIu64 "\n", sam_u->sat_u.fod_d); + u3l_log(" forwards pending: %" PRIu64 "\n", sam_u->sat_u.foq_d); + u3l_log(" forwarded: %" PRIu64 "\n", sam_u->sat_u.fow_d); + u3l_log(" filtered (hed): %" PRIu64 "\n", sam_u->sat_u.hed_d); + u3l_log(" filtered (ver): %" PRIu64 "\n", sam_u->sat_u.vet_d); + u3l_log(" filtered (mug): %" PRIu64 "\n", sam_u->sat_u.mut_d); + u3l_log(" filtered (bod): %" PRIu64 "\n", sam_u->sat_u.bod_d); + u3l_log(" crashed: %" PRIu64 "\n", sam_u->sat_u.fal_d); + u3l_log(" cached lanes: %u\n", u3h_wyt(sam_u->lax_p)); +} + +/* u3_ames_io_init(): initialize ames I/O. +*/ +u3_auto* +u3_ames_io_init(u3_pier* pir_u) +{ + u3_ames* sam_u = c3_calloc(sizeof(*sam_u)); + sam_u->pir_u = pir_u; + sam_u->fig_u.net_o = c3y; + sam_u->fig_u.see_o = c3y; + sam_u->fig_u.fit_o = c3n; + + // hashtable for scry cache + // TODO: review size + // 1500 bytes per packet * 100_000 = 150MB + // 50 bytes (average) per path * 100_000 = 5MB + sam_u->fin_s.sac_p = u3h_new_cache(100000); + + //NOTE some numbers on memory usage for the lane cache + // + // assuming we store: + // a (list lane) with 1 item, 1+8 + 1 + (6*2) = 22 words + // and a @da as timestamp, 8 words + // consed together, 6 words + // with worst-case (128-bit) @p keys, 8 words + // and an additional cell for the k-v pair, 6 words + // that makes for a per-entry memory use of 50 words => 200 bytes + // + // the 500k entries below would take about 100mb (in the worst case, but + // not accounting for hashtable overhead). + // we could afford more, but 500k entries is more than we'll likely use + // in the near future. + // + sam_u->lax_p = u3h_new_cache(500000); + + c3_assert( !uv_udp_init(u3L, &sam_u->wax_u) ); + sam_u->wax_u.data = sam_u; + + sam_u->sil_u = u3s_cue_xeno_init(); + sam_u->tes_u = ur_cue_test_init(); + + // Disable networking for fake ships + // + if ( c3y == sam_u->pir_u->fak_o ) { + u3_Host.ops_u.net = c3n; + } + + u3_auto* car_u = &sam_u->car_u; + car_u->nam_m = c3__ames; + car_u->liv_o = c3n; + car_u->io.talk_f = _ames_io_talk; + car_u->io.info_f = _ames_io_info; + car_u->io.kick_f = _ames_io_kick; + car_u->io.exit_f = _ames_io_exit; + + u3_auto* far_u = sam_u->fin_u.car_u; + far_u->nam_m = c3__fine; + far_u->liv_o = c3n; + far_u->io.talk_f = _fine_io_talk; + far_u->io.info_f = _fine_io_info; + far_u->io.kick_f = _fine_io_kick; + far_u->io.exit_f = _fine_io_exit; + + { + u3_noun now; + struct timeval tim_u; + gettimeofday(&tim_u, 0); + + now = u3_time_in_tv(&tim_u); + sam_u->sev_l = u3r_mug(now); + u3z(now); + } + + return car_u; +} diff --git a/pkg/urbit/include/vere/vere.h b/pkg/urbit/include/vere/vere.h index 64eea8eac..a457b045b 100644 --- a/pkg/urbit/include/vere/vere.h +++ b/pkg/urbit/include/vere/vere.h @@ -1136,7 +1136,7 @@ /* u3_ames_io_init(): initialize ames I/O. */ u3_auto* - u3_ames_io_init(u3_pier* pir_u); + u3_ames_io_init(u3_pier* pir_u, u3_auto** far_u); /* u3_ames_decode_lane(): destructure lane from noun */ diff --git a/pkg/urbit/vere/auto.c b/pkg/urbit/vere/auto.c index 5a56d22bc..0a6890113 100644 --- a/pkg/urbit/vere/auto.c +++ b/pkg/urbit/vere/auto.c @@ -405,10 +405,13 @@ u3_auto* u3_auto_init(u3_pier* pir_u) { u3_auto* car_u = 0; + u3_auto* fin_u = 0; car_u = _auto_link(u3_hind_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_behn_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_ames_io_init(pir_u), pir_u, car_u); + car_u = _auto_link(u3_ames_io_init(pir_u, &fin_u), pir_u, car_u); + // TODO: hacky, review + car_u = _auto_link(fin_u, pir_u, car_u); car_u = _auto_link(u3_http_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_cttp_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_unix_io_init(pir_u), pir_u, car_u); diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 5385c4b8e..7c76ee579 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -17,16 +17,20 @@ struct _u3_ames* sam_u; // ames backpointer } u3_pact; +/* u3_fine: fine networking +*/ + typedef struct _u3_fine { + u3_auto car_u; // fine driver + c3_y ver_y; // fine protocol + u3p(u3h_root) sac_p; // scry cache hashtable + struct _u3_ames* sam_u; // ames backpointer + } u3_fine; + /* u3_ames: ames networking. */ typedef struct _u3_ames { // packet network state u3_auto car_u; // ames driver - struct { - u3_auto car_u; // fine driver - c3_y ver_y; // fine protocol - u3p(u3h_root) sac_p; // scry cache hashtable - // TODO: stats, maybe config? etc. - } fin_s; + u3_fine fin_s; // fine networking u3_pier* pir_u; // pier union { // uv udp handle uv_udp_t wax_u; // @@ -94,7 +98,6 @@ } u3_requ; typedef struct _u3_reqp { - u3_ames* sam_u; u3_head hed_u; u3_requ req_u; } u3_reqp; @@ -123,6 +126,7 @@ c3_y* hun_y; // packet contents c3_w len_w; // packet contents u3_lane lan_u; // recipient lane + c3_w fra_w; // fragment number u3_ames* sam_u; // ames backpointer union { u3_resp* res_u; @@ -214,6 +218,40 @@ _ames_panc_free(u3_panc* pac_u) c3_free(pac_u); } +static void _log_prel(u3_prel* pre_u) +{ + u3l_log("-- PRELUDE --\n"); + u3l_log("sender life: %u\n", pre_u->sic_y); + u3l_log("receiver life: %u\n", pre_u->ric_y); + u3l_log("sender: %" PRIu64 "\n", pre_u->sen_d[0]); + u3l_log("receiver: %" PRIu64" \n", pre_u->rec_d[0]); + u3l_log("\n"); +} + +static void _log_requ(u3_requ* req_u) +{ + _log_prel(&req_u->pre_u); + u3l_log("--- REQUEST ---\n"); + u3l_log("strlen: %u\n", req_u->len_s); + u3l_log("path: %s\n", req_u->pat_c); + u3l_log("frag: %u\n", req_u->fra_w); + u3l_log("\n"); + return; +} + +static void +_log_bytes(c3_y* byt_y, c3_w len_w) +{ + int i; + u3l_log("-- BYTES (%u) --\n", len_w); + for(i = 0; i < len_w; i++) { + u3l_log("%x\n", byt_y[i]); + } + u3l_log("\n"); +} + + + /* _ames_sift_head(): parse packet header. */ static c3_o @@ -310,7 +348,7 @@ _ames_sift_prelude(u3_head* hed_u, rog_y = ( c3y == hed_u->rel_o )? 6 : 0; sen_y = 2 << hed_u->sac_y; rec_y = 2 << hed_u->rac_y; - len_y = rog_y + sen_y + rec_y; + len_y = rog_y + sen_y + rec_y + 1; pre_u->sic_y = pre_y[0] & 0xf; pre_u->ric_y = pre_y[0] & 0xf0; @@ -342,35 +380,44 @@ _fine_sift_requ(u3_head* hed_u, { c3_y pre_y = _ames_sift_prelude(hed_u, &req_u->pre_u, len_w, req_y); + //u3l_log("prelude size: %u\n", pre_y); + req_y += pre_y; c3_w rem_w = (64 + 4 + 2 + pre_y); if(rem_w > len_w) { + u3l_log("not big enough\n"); return c3n; } memcpy(req_u->sig_y, req_y, 64); req_y += 64; + //_log_bytes(req_y, 4); + req_u->fra_w = ( - (req_y[0] << 0x18) - | (req_y[1] << 0x10) - | (req_y[2] << 0x8) - | (req_y[3] << 0x0)); + (req_y[0] << 0x0) + | (req_y[1] << 0x8) + | (req_y[2] << 0x10) + | (req_y[3] << 0x18)); req_y += 4; req_u->len_s = c3_min(384, - (req_y[0] << 0x8) - | (req_y[1] << 0x0)); + (req_y[0] << 0x0) + | (req_y[1] << 0x8)); req_y += 2; + //_log_bytes(req_y, req_u->len_s); + // TODO: strict inequality? - if(rem_w + req_u->len_s != len_w) { + /*if(rem_w + req_u->len_s != len_w) { + u3l_log("bad format\n"); return c3n; - } + }*/ // TODO: defend maliciusly crafted lengths? req_u->pat_c = c3_calloc(req_u->len_s + 1); + u3l_log("byt: %x\n", *req_y); memcpy(req_u->pat_c, req_y, req_u->len_s); req_u->pat_c[req_u->len_s] = '\0'; @@ -387,36 +434,57 @@ _fine_sift_resp(u3_head* hed_u, { c3_w rem_w = (64 + 4 + hed_u->sac_y + 4 + hed_u->rac_y + 2); if(rem_w > len_w) { + u3l_log("bad size %u", len_w); return c3n; } + c3_y pre_y = _ames_sift_prelude(hed_u, &res_u->pre_u, len_w, res_y); res_y += pre_y; - memcpy(res_u->sig_y, res_y, 64); - res_y += 64; res_u->fra_w = ( - (res_y[0] << 0x18) - | (res_y[1] << 0x10) - | (res_y[2] << 0x8) - | (res_y[3] << 0x0)); + (res_y[0] << 0x0) + | (res_y[1] << 0x8) + | (res_y[2] << 0x10) + | (res_y[3] << 0x18)); res_y += 4; res_u->len_s = c3_min(384, - (res_y[0] << 0x8) - | (res_y[1] << 0x0)); + (res_y[0] << 0x0) + | (res_y[1] << 0x8)); res_y += 2; + res_u->pat_c = c3_calloc(res_u->len_s + 1); + memcpy(res_u->pat_c, res_y, res_u->len_s); + + memcpy(res_u->sig_y, res_y, 64); + res_y += 64; + + res_u->num_w = ( + (res_y[0] << 0x0) + | (res_y[1] << 0x8) + | (res_y[2] << 0x10) + | (res_y[3] << 0x18)); + res_y += 4; + + res_u->siz_s = c3_min(384, + (res_y[0] << 0x0) + | (res_y[1] << 0x8)); + res_y += 2; + + u3l_log("dat siz: %u", res_u->siz_s); + + res_u->dat_y = c3_calloc(res_u->siz_s); + memcpy(&res_u->dat_y, res_y, res_u->siz_s); + + // TODO: strict inequality? - if(rem_w + res_u->len_s != len_w) { + /*if(rem_w + res_u->len_s != len_w) { return c3n; - } + }*/ // TODO: defend maliciusly crafted lengths? - res_u->pat_c = c3_malloc(res_u->len_s); - - memcpy(res_u->pat_c, res_y, res_u->len_s); // TODO: add null terminator? return c3y; } @@ -562,6 +630,7 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) { u3_pend* pen_u = (u3_pend*)req_u; u3_ames* sam_u = pen_u->sam_u; + u3l_log("ames: send \n"); if (sas_i) { u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); @@ -580,7 +649,7 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) static void _ames_send(u3_pend* pen_u) { - u3l_log("ames: send"); + u3l_log("ames: send\n"); u3_ames* sam_u = pen_u->sam_u; // TODO: prevalidation? @@ -611,7 +680,7 @@ _ames_send(u3_pend* pen_u) sam_u->fig_u.net_o = c3n; } - _ames_pend_free(pen_u); + //_ames_pend_free(pen_u); } } } @@ -646,6 +715,8 @@ u3_ames_lane_to_chub(u3_lane lan) { */ u3_atom u3_ames_encode_lane(u3_lane lan) { + // [%| p=@] + // [%& p=@pC] return u3i_chub(u3_ames_lane_to_chub(lan)); } @@ -787,7 +858,6 @@ _ames_czar_here(u3_pend* pen_u, time_t now, struct sockaddr_in* add_u) sam_u->imp_o[imp_y] = c3y; pen_u->lan_u.pip_w = pip_w; - _ames_send(pen_u); } /* _ames_czar_cb(): galaxy address resolution callback. @@ -1305,8 +1375,30 @@ _ames_skip(u3_body* bod_u) { */ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) { + + u3l_log("in scry cb\n"); u3_pend* pen_u = vod_p; - u3_weak pack = u3r_at(3, nun); + u3_weak pac = u3r_at(7, nun); + if(pac == u3_none) { + u3l_log("no result, bailing\n"); + return; + } + //u3m_p("pac:", pac); + u3_noun num = u3i_word(pen_u->fra_w - 1); + u3m_p("frag num", num); + + u3_noun fra = u3dc("snag", num, pac); + u3l_log("found fragment\n"); + + pen_u->len_w = u3r_met(3, fra); + pen_u->hun_y = c3_calloc(pen_u->len_w); + + u3r_bytes(0, pen_u->len_w, pen_u->hun_y, fra); + + + _fine_send(pen_u); + + // // hashtable = (path, packet_num) -> cached_result; // All cases, except 1st ~: put results in cache for all packets @@ -1315,7 +1407,7 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) // [~ ~ *] -> send packet // TODO: cache logic, counting requests, evict? - u3_weak lan = _ames_lane_from_cache(pen_u->sam_u->lax_p, + /*u3_weak lan = _ames_lane_from_cache(pen_u->sam_u->lax_p, u3i_chubs(2, pen_u->her_d)); if(u3_none == lan) { // TODO: enqueue packet for later sending, populate lane cache @@ -1324,13 +1416,13 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) } else { _fine_send(pen_u); } + */ } /* _fine_hear(): hear a (potential) packet, dispatch appropriately */ -// _fine_hear(sam_u, lan_u, len_w, hun_y) static void _fine_hear(u3_ames* sam_u, u3_lane lan_u, c3_w len_w, @@ -1340,11 +1432,10 @@ static void _fine_hear(u3_ames* sam_u, //u3_body bod_u; c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); - // skip past header - len_w -= 4; - hun_y += 4; - - if(hed_u.req_o) { + + u3l_log("fine: request %u == %u \n", hed_u.req_o, c3y); + if(c3n == hed_u.req_o) { + u3l_log("fine: request\n"); // lookup in cache // (unit (unit (unit packet)) // ~ -> miss @@ -1353,12 +1444,22 @@ static void _fine_hear(u3_ames* sam_u, // [~ ~ ~ *] -> hit, w/ data u3_requ req_u; + // skip past header + len_w -= 4; + hun_y += 4; - _fine_sift_requ(&hed_u, &req_u, len_w, hun_y); + + c3_assert( c3y == _fine_sift_requ(&hed_u, &req_u, len_w, hun_y)); + + //_log_requ(&req_u); + + u3l_log("checking cache: %s\n", req_u.pat_c); u3_noun pat = u3i_string(req_u.pat_c); - u3_weak cac = u3h_git(sam_u->fin_s.sac_p, pat); + u3_weak cac = u3_none; // u3h_git(sam_u->fin_s.sac_p, pat); + + u3l_log("checked cache\n"); if(u3_none == cac) { // cache miss @@ -1368,22 +1469,36 @@ static void _fine_hear(u3_ames* sam_u, // eg: // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10 // - u3_noun pax = u3nc(u3i_string("packet"), - u3do("stab", u3i_string(req_u.pat_c))); + u3l_log("constructing path\n"); + u3_noun pax = u3nc(u3i_string("message"), + u3do("stab", pat)); + u3l_log("constructed path\n"); + + u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + + pen_u->sam_u = sam_u; + pen_u->typ_y = 2; + pen_u->req_u = rep_u; - u3_reqp* rep_u = c3_malloc(sizeof(*rep_u)); - rep_u->sam_u = sam_u; memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); + memcpy(&pen_u->lan_u, &lan_u, sizeof(u3_lane)); + u3l_log("frag num %u\n", req_u.fra_w); + pen_u->fra_w = req_u.fra_w; + + u3l_log("scrying...\n"); u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, - pax, rep_u, _fine_pack_scry_cb); + pax, pen_u, _fine_pack_scry_cb); + } else if(u3_nul == cac) { // cache hit, unbound // do nothing, maybe report? } else { + u3l_log("cache hit\n"); // shape // u3_noun fra = u3dc("snag", u3i_word(req_u.fra_w), u3t(cac)); @@ -1419,24 +1534,50 @@ static void _fine_hear(u3_ames* sam_u, return; } } else { + u3l_log("fine: response\n"); u3_resp res_u; - _fine_sift_resp(&hed_u, &res_u, len_w, hun_y); - u3_noun pat = u3do("stab", u3i_string(res_u.pat_c)); - - + u3l_log("fine: parsing\n"); + // TODO: return + //_fine_sift_resp(&hed_u, &res_u, len_w, hun_y); + //u3l_log("pat: %s\n\n\n", res_u.pat_c); + //u3_noun pat = u3do("stab", u3i_string(res_u.pat_c)); + //u3m_p("pat", pat); // // u3_noun wir = u3nc(c3__fine, u3_nul); + u3l_log("made wire"); c3_w num_w = res_u.num_w; c3_w fra_w = res_u.fra_w; - u3_noun cad = u3nc(c3__purr, u3i_bytes(len_w, hun_y)); + u3l_log("making card"); + u3_noun cad = u3nt(c3__purr, + u3nt(0, c3n, u3_ames_encode_lane(lan_u)), + u3i_bytes(len_w, hun_y)); + u3l_log("making ovum"); u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, wir, cad); + u3l_log("made ovum"); u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); + u3l_log("sent ovum"); } } + + +static void _log_head(u3_head* hed_u) +{ + u3l_log("-- HEAADER --\n"); + u3l_log("is request: %u\n", hed_u->req_o); + u3l_log("is ames: %u\n", hed_u->sim_o); + u3l_log("protocol ames: %u\n", hed_u->ver_y); + u3l_log("sender class: %u\n", hed_u->sac_y); + u3l_log("recevr class: %u\n", hed_u->rac_y); + u3l_log("\n"); +} + + + + static void _fine_request(u3_ames* sam_u, u3_lane lan_u, @@ -1444,28 +1585,35 @@ _fine_request(u3_ames* sam_u, { u3l_log("fine: request\n"); - u3_pend pen_u; - u3_head hed_u; - u3_requ req_u; - + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + u3_head* hed_u = c3_calloc(sizeof(*hed_u)); + u3_requ* req_u = c3_calloc(sizeof(*req_u)); c3_w req_w = u3r_met(3, req); c3_y* req_y = c3_calloc(req_w); u3r_bytes(0, req_w, req_y, req); + //_log_bytes(req_y, 4); + pen_u->hun_y = req_y; + pen_u->len_w = req_w; - _ames_sift_head(&hed_u, req_y); + _ames_sift_head(hed_u, req_y); req_y += 4; req_w -= 4; - _fine_sift_requ(&hed_u, &req_u, req_w, req_y); + _log_head(hed_u); + _fine_sift_requ(hed_u, req_u, req_w, req_y); - pen_u.typ_y = 1; - pen_u.her_d[0] = req_u.pre_u.rec_d[0]; - pen_u.her_d[1] = req_u.pre_u.rec_d[1]; + _log_prel(&req_u->pre_u); - pen_u.lan_u = lan_u; - pen_u.sam_u = sam_u; + pen_u->typ_y = 1; + pen_u->her_d[0] = req_u->pre_u.rec_d[0]; + pen_u->her_d[1] = req_u->pre_u.rec_d[1]; + pen_u->lan_u.pip_w = lan_u.pip_w; + pen_u->lan_u.por_s = lan_u.por_s; + + pen_u->sam_u = sam_u; + _ames_czar(pen_u); } /* _ames_hear(): parse a (potential) packet, dispatch appropriately. @@ -1477,7 +1625,7 @@ _ames_hear(u3_ames* sam_u, c3_y* hun_y) { - u3l_log("ames: hear"); + u3l_log("ames: hear\n"); // TODO: move from stack to heap to avoid reparsing u3_head hed_u; u3_body bod_u; @@ -1512,7 +1660,9 @@ _ames_hear(u3_ames* sam_u, } else if (c3n == is_ames_o) { // TODO: dispatch fine request + u3l_log("fine: hear\n"); _fine_hear(sam_u, *lan_u, len_w, hun_y); + return; } // ensure the protocol version matches ours @@ -1734,15 +1884,18 @@ _ames_ef_turf(u3_ames* sam_u, u3_noun tuf) /* fine_io_kick:(): receive effect from arvo - * TODO: */ static c3_o _fine_io_kick(u3_auto* car_u, u3_noun wir, u3_noun nun) { - u3_ames* sam_u = (u3_ames*)car_u; + u3l_log("fine: received effect\n"); + u3_fine* fin_u = (u3_fine*)car_u; + u3_ames* sam_u = fin_u->sam_u; u3_noun hed = u3h(nun); - if(c3__hoot == hed) { + //u3m_p("head: ", hed); + + if(c3__howl == hed) { // TODO: respond to notification of bound data return c3y; - } else if(c3__howl == hed) { + } else if(c3__hoot == hed) { u3_noun lan, hot; u3x_cell(u3t(nun), &lan, &hot); u3_lane lan_u = u3_ames_decode_lane(lan); @@ -1817,6 +1970,13 @@ _fine_prot_scry_cb(void* vod_p, u3_noun nun) u3z(nun); } +/* _fine_io_talk(): start receiving ames traffic. +*/ +static void _fine_io_talk(u3_auto* car_u) +{ + // do nothing +} + /* _ames_io_talk(): start receiving ames traffic. @@ -1839,6 +1999,18 @@ _ames_io_talk(u3_auto* car_u) u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); } + // send fine born + { + u3_noun wir = u3nt(c3__newt, + u3dc("scot", c3__uv, sam_u->sev_l), + u3_nul); + u3_noun cad = u3nc(c3__born, u3_nul); + + u3_auto_plan(&sam_u->fin_s.car_u, u3_ovum_init(0, c3__f, wir, cad)); + + } + + // TODO: scry the fine protocol out of arvo // u3_pier_peek_last(car_u->pir_u, u3_nul, c3__fx, u3_nul, @@ -1962,6 +2134,14 @@ _ames_exit_cb(uv_handle_t* had_u) c3_free(sam_u); } +/* _fine_io_exit(): terminate fine I/O. +*/ +static void +_fine_io_exit(u3_auto* car_u) +{ + // cleanup handled in _ames_io_exit +} + /* _ames_io_exit(): terminate ames I/O. */ static void @@ -1971,6 +2151,15 @@ _ames_io_exit(u3_auto* car_u) uv_close(&sam_u->had_u, _ames_exit_cb); } +/* _fine_io_info(): print status info. +*/ +static void +_fine_io_info(u3_auto* car_u) +{ + +} + + /* _ames_io_info(): print status info. */ static void @@ -2000,7 +2189,7 @@ _ames_io_info(u3_auto* car_u) /* u3_ames_io_init(): initialize ames I/O. */ u3_auto* -u3_ames_io_init(u3_pier* pir_u) +u3_ames_io_init(u3_pier* pir_u, u3_auto** far_u) { u3_ames* sam_u = c3_calloc(sizeof(*sam_u)); sam_u->pir_u = pir_u; @@ -2051,6 +2240,19 @@ u3_ames_io_init(u3_pier* pir_u) car_u->io.kick_f = _ames_io_kick; car_u->io.exit_f = _ames_io_exit; + u3_auto* fur_u = &sam_u->fin_s.car_u; + fur_u->nam_m = c3__fine; + fur_u->liv_o = c3y; + fur_u->io.talk_f = _fine_io_talk; + fur_u->io.info_f = _fine_io_info; + fur_u->io.kick_f = _fine_io_kick; + fur_u->io.exit_f = _fine_io_exit; + u3l_log("fur: %p\n", fur_u); + *far_u = fur_u; + u3l_log("far: %p\n", *far_u); + + sam_u->fin_s.sam_u = sam_u; + { u3_noun now; struct timeval tim_u; From f0aa946f576e8fca420e994528bc90d59ce005ed Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 26 Jan 2022 21:55:08 -0600 Subject: [PATCH 021/168] ames: remove logging --- pkg/urbit/vere/io/ames.c | 47 ++++------------------------------------ 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 7c76ee579..f4f5f945b 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -380,8 +380,6 @@ _fine_sift_requ(u3_head* hed_u, { c3_y pre_y = _ames_sift_prelude(hed_u, &req_u->pre_u, len_w, req_y); - //u3l_log("prelude size: %u\n", pre_y); - req_y += pre_y; c3_w rem_w = (64 + 4 + 2 + pre_y); @@ -417,7 +415,6 @@ _fine_sift_requ(u3_head* hed_u, // TODO: defend maliciusly crafted lengths? req_u->pat_c = c3_calloc(req_u->len_s + 1); - u3l_log("byt: %x\n", *req_y); memcpy(req_u->pat_c, req_y, req_u->len_s); req_u->pat_c[req_u->len_s] = '\0'; @@ -473,7 +470,6 @@ _fine_sift_resp(u3_head* hed_u, | (res_y[1] << 0x8)); res_y += 2; - u3l_log("dat siz: %u", res_u->siz_s); res_u->dat_y = c3_calloc(res_u->siz_s); memcpy(&res_u->dat_y, res_y, res_u->siz_s); @@ -630,7 +626,6 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) { u3_pend* pen_u = (u3_pend*)req_u; u3_ames* sam_u = pen_u->sam_u; - u3l_log("ames: send \n"); if (sas_i) { u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); @@ -649,7 +644,6 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) static void _ames_send(u3_pend* pen_u) { - u3l_log("ames: send\n"); u3_ames* sam_u = pen_u->sam_u; // TODO: prevalidation? @@ -1376,19 +1370,15 @@ _ames_skip(u3_body* bod_u) { static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) { - u3l_log("in scry cb\n"); u3_pend* pen_u = vod_p; u3_weak pac = u3r_at(7, nun); if(pac == u3_none) { u3l_log("no result, bailing\n"); return; } - //u3m_p("pac:", pac); u3_noun num = u3i_word(pen_u->fra_w - 1); - u3m_p("frag num", num); u3_noun fra = u3dc("snag", num, pac); - u3l_log("found fragment\n"); pen_u->len_w = u3r_met(3, fra); pen_u->hun_y = c3_calloc(pen_u->len_w); @@ -1433,9 +1423,7 @@ static void _fine_hear(u3_ames* sam_u, c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); - u3l_log("fine: request %u == %u \n", hed_u.req_o, c3y); if(c3n == hed_u.req_o) { - u3l_log("fine: request\n"); // lookup in cache // (unit (unit (unit packet)) // ~ -> miss @@ -1454,12 +1442,11 @@ static void _fine_hear(u3_ames* sam_u, //_log_requ(&req_u); - u3l_log("checking cache: %s\n", req_u.pat_c); u3_noun pat = u3i_string(req_u.pat_c); + // TODO: revive u3_weak cac = u3_none; // u3h_git(sam_u->fin_s.sac_p, pat); - u3l_log("checked cache\n"); if(u3_none == cac) { // cache miss @@ -1469,11 +1456,9 @@ static void _fine_hear(u3_ames* sam_u, // eg: // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10 // - u3l_log("constructing path\n"); u3_noun pax = u3nc(u3i_string("message"), u3do("stab", pat)); - u3l_log("constructed path\n"); u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); @@ -1486,10 +1471,8 @@ static void _fine_hear(u3_ames* sam_u, memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); memcpy(&pen_u->lan_u, &lan_u, sizeof(u3_lane)); - u3l_log("frag num %u\n", req_u.fra_w); pen_u->fra_w = req_u.fra_w; - u3l_log("scrying...\n"); u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, pax, pen_u, _fine_pack_scry_cb); @@ -1498,7 +1481,6 @@ static void _fine_hear(u3_ames* sam_u, // cache hit, unbound // do nothing, maybe report? } else { - u3l_log("cache hit\n"); // shape // u3_noun fra = u3dc("snag", u3i_word(req_u.fra_w), u3t(cac)); @@ -1534,31 +1516,20 @@ static void _fine_hear(u3_ames* sam_u, return; } } else { - u3l_log("fine: response\n"); u3_resp res_u; - u3l_log("fine: parsing\n"); - // TODO: return - //_fine_sift_resp(&hed_u, &res_u, len_w, hun_y); - //u3l_log("pat: %s\n\n\n", res_u.pat_c); - //u3_noun pat = u3do("stab", u3i_string(res_u.pat_c)); - //u3m_p("pat", pat); - // - // + // TODO: check mug + u3_noun wir = u3nc(c3__fine, u3_nul); - u3l_log("made wire"); c3_w num_w = res_u.num_w; c3_w fra_w = res_u.fra_w; - u3l_log("making card"); + u3_noun cad = u3nt(c3__purr, u3nt(0, c3n, u3_ames_encode_lane(lan_u)), u3i_bytes(len_w, hun_y)); - u3l_log("making ovum"); u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, wir, cad); - u3l_log("made ovum"); u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); - u3l_log("sent ovum"); } } @@ -1600,12 +1571,8 @@ _fine_request(u3_ames* sam_u, req_y += 4; req_w -= 4; - _log_head(hed_u); - _fine_sift_requ(hed_u, req_u, req_w, req_y); - _log_prel(&req_u->pre_u); - pen_u->typ_y = 1; pen_u->her_d[0] = req_u->pre_u.rec_d[0]; pen_u->her_d[1] = req_u->pre_u.rec_d[1]; @@ -1625,7 +1592,6 @@ _ames_hear(u3_ames* sam_u, c3_y* hun_y) { - u3l_log("ames: hear\n"); // TODO: move from stack to heap to avoid reparsing u3_head hed_u; u3_body bod_u; @@ -1660,7 +1626,6 @@ _ames_hear(u3_ames* sam_u, } else if (c3n == is_ames_o) { // TODO: dispatch fine request - u3l_log("fine: hear\n"); _fine_hear(sam_u, *lan_u, len_w, hun_y); return; } @@ -1701,7 +1666,6 @@ _ames_hear(u3_ames* sam_u, // ensure the mug is valid // - u3l_log("bod: %ux, hed: %ux\n", hed_u.mug_l, bod_u.mug_l); if ( bod_u.mug_l != hed_u.mug_l ) { sam_u->sat_u.mut_d++; if ( 0 == (sam_u->sat_u.mut_d % 100000) ) { @@ -1886,7 +1850,6 @@ _ames_ef_turf(u3_ames* sam_u, u3_noun tuf) /* fine_io_kick:(): receive effect from arvo */ static c3_o _fine_io_kick(u3_auto* car_u, u3_noun wir, u3_noun nun) { - u3l_log("fine: received effect\n"); u3_fine* fin_u = (u3_fine*)car_u; u3_ames* sam_u = fin_u->sam_u; u3_noun hed = u3h(nun); @@ -2247,9 +2210,7 @@ u3_ames_io_init(u3_pier* pir_u, u3_auto** far_u) fur_u->io.info_f = _fine_io_info; fur_u->io.kick_f = _fine_io_kick; fur_u->io.exit_f = _fine_io_exit; - u3l_log("fur: %p\n", fur_u); *far_u = fur_u; - u3l_log("far: %p\n", *far_u); sam_u->fin_s.sam_u = sam_u; From c816d4378486eba4cf934087367ec3373d8430e0 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 26 Jan 2022 22:00:54 -0600 Subject: [PATCH 022/168] fine: remove unnecessary from in %purr --- pkg/urbit/vere/io/ames.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index f4f5f945b..61fd9715a 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -1525,7 +1525,7 @@ static void _fine_hear(u3_ames* sam_u, c3_w fra_w = res_u.fra_w; u3_noun cad = u3nt(c3__purr, - u3nt(0, c3n, u3_ames_encode_lane(lan_u)), + u3nc(c3n, u3_ames_encode_lane(lan_u)), u3i_bytes(len_w, hun_y)); u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, wir, cad); From 2f78cf7e0130dc908bd5077f0d89d5b4d309a1fd Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 26 Jan 2022 22:21:40 -0600 Subject: [PATCH 023/168] ames: #freepackets --- pkg/urbit/vere/io/ames.c | 221 ++++++++++++++++++++++----------------- 1 file changed, 123 insertions(+), 98 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 61fd9715a..8309643dd 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -184,15 +184,16 @@ _ames_pact_free(u3_pact* pac_u) static void _ames_pend_free(u3_pend* pen_u) { - if(0 == pen_u->typ_y) { // ames packet + if ( 0 == pen_u->typ_y ) { // ames packet _ames_pact_free(pen_u->pac_u); - } else if (1 == pen_u->typ_y) { // fine request + } else if ( 1 == pen_u->typ_y ) { // fine request c3_free(pen_u->req_u); c3_free(pen_u->hun_y); } else { // fine response c3_free(pen_u->res_u); c3_free(pen_u->hun_y); } + c3_free(pen_u->dns_c); c3_free(pen_u); } @@ -635,7 +636,7 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) sam_u->fig_u.net_o = c3y; } - //_ames_pend_free(pen_u); + _ames_pend_free(pen_u); } #define _fine_send _ames_send @@ -674,7 +675,7 @@ _ames_send(u3_pend* pen_u) sam_u->fig_u.net_o = c3n; } - //_ames_pend_free(pen_u); + _ames_pend_free(pen_u); } } } @@ -1410,6 +1411,118 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) } +static void _fine_hear_response(u3_ames* sam_u, + u3_lane lan_u, + c3_w len_w, + c3_y* hun_y) +{ + +} + + +static void _fine_hear_request(u3_ames* sam_u, + u3_lane lan_u, + c3_w len_w, + c3_y* hun_y) +{ + u3_head hed_u; + c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); + // lookup in cache + // (unit (unit (unit packet)) + // ~ -> miss + // [~ ~] -> hit, unbound + // [~ ~ ~] -> hit, empty + // [~ ~ ~ *] -> hit, w/ data + u3_requ req_u; + + // skip past header + len_w -= 4; + hun_y += 4; + + c3_assert( c3y == _fine_sift_requ(&hed_u, &req_u, len_w, hun_y)); + + u3_noun pat = u3i_string(req_u.pat_c); + + // TODO: revive + u3_weak cac = u3_none; // u3h_git(sam_u->fin_s.sac_p, pat); + + + if ( u3_none == cac ) { + // cache miss + // packet scry path + // /packet/requested/path/elements + // + // eg: + // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10 + // + u3_noun pax = u3nc(u3i_string("message"), + u3do("stab", u3k(pat))); + + + u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + + pen_u->sam_u = sam_u; + pen_u->typ_y = 2; + pen_u->req_u = rep_u; + + memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); + memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); + + memcpy(&pen_u->lan_u, &lan_u, sizeof(u3_lane)); + pen_u->fra_w = req_u.fra_w; + + u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, + pax, pen_u, _fine_pack_scry_cb); + + + } else if(u3_nul == cac) { + // cache hit, unbound + // do nothing, maybe report? + } else { + // shape + // + c3_w fra_w; + c3_y* fra_y; + + { + u3_noun fra = u3dc("snag", u3i_word(req_u.fra_w), u3t(cac)); + + fra_w = u3r_met(3, fra); + fra_y = c3_calloc(fra_w); + + u3r_bytes(0, fra_w, fra_y, fra); + + u3z(fra); + } + + u3_resp* res_u = c3_calloc(sizeof(*res_u)); + + c3_assert(c3y == _fine_sift_resp(&hed_u, res_u, fra_w, fra_y)); + + memcpy(&res_u->pre_u, &req_u.pre_u, sizeof(u3_prel)); + + c3_y* res_y; + c3_w res_w = _fine_etch_resp(&hed_u, res_u, &res_y); + + // TODO: where free? maybe stack allocate instead? + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + pen_u->typ_y = 2; + pen_u->res_u = res_u; + pen_u->len_w = res_w; + pen_u->hun_y = res_y; + pen_u->her_d[0] = res_u->pre_u.sen_d[0]; + pen_u->her_d[1] = res_u->pre_u.sen_d[1]; + pen_u->lan_u = lan_u; + pen_u->sam_u = sam_u; + + _fine_send(pen_u); + } + + u3z(pat); +} + + /* _fine_hear(): hear a (potential) packet, dispatch appropriately */ @@ -1419,102 +1532,11 @@ static void _fine_hear(u3_ames* sam_u, c3_y* hun_y) { u3_head hed_u; - //u3_body bod_u; c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); if(c3n == hed_u.req_o) { - // lookup in cache - // (unit (unit (unit packet)) - // ~ -> miss - // [~ ~] -> hit, unbound - // [~ ~ ~] -> hit, empty - // [~ ~ ~ *] -> hit, w/ data - u3_requ req_u; - - // skip past header - len_w -= 4; - hun_y += 4; - - - - c3_assert( c3y == _fine_sift_requ(&hed_u, &req_u, len_w, hun_y)); - - //_log_requ(&req_u); - - u3_noun pat = u3i_string(req_u.pat_c); - - // TODO: revive - u3_weak cac = u3_none; // u3h_git(sam_u->fin_s.sac_p, pat); - - - if(u3_none == cac) { - // cache miss - // packet scry path - // /packet/requested/path/elements - // - // eg: - // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10 - // - u3_noun pax = u3nc(u3i_string("message"), - u3do("stab", pat)); - - - u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); - u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); - - pen_u->sam_u = sam_u; - pen_u->typ_y = 2; - pen_u->req_u = rep_u; - - memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); - memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); - - memcpy(&pen_u->lan_u, &lan_u, sizeof(u3_lane)); - pen_u->fra_w = req_u.fra_w; - - u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, - pax, pen_u, _fine_pack_scry_cb); - - - } else if(u3_nul == cac) { - // cache hit, unbound - // do nothing, maybe report? - } else { - // shape - // - u3_noun fra = u3dc("snag", u3i_word(req_u.fra_w), u3t(cac)); - // - - c3_w fra_w = u3r_met(3, fra); - c3_y* fra_y = c3_calloc(fra_w); - - u3r_bytes(0, fra_w, fra_y, fra); - - u3_resp* res_u = c3_calloc(sizeof(*res_u)); - - c3_assert(c3y == _fine_sift_resp(&hed_u, res_u, fra_w, fra_y)); - - memcpy(&res_u->pre_u, &req_u.pre_u, sizeof(u3_prel)); - - c3_y* res_y; - c3_w res_w = _fine_etch_resp(&hed_u, res_u, &res_y); - - // TODO: where free? maybe stack allocate instead? - u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); - pen_u->typ_y = 2; - pen_u->res_u = res_u; - pen_u->len_w = res_w; - pen_u->hun_y = res_y; - pen_u->her_d[0] = res_u->pre_u.sen_d[0]; - pen_u->her_d[1] = res_u->pre_u.sen_d[1]; - pen_u->lan_u = lan_u; - pen_u->sam_u = sam_u; - - _fine_send(pen_u); - - return; - } + _fine_hear_request(sam_u, lan_u, len_w, hun_y); } else { u3_resp res_u; @@ -1528,8 +1550,11 @@ static void _fine_hear(u3_ames* sam_u, u3nc(c3n, u3_ames_encode_lane(lan_u)), u3i_bytes(len_w, hun_y)); - u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, wir, cad); + u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, u3k(wir), u3k(cad)); u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); + + u3z(cad); + u3z(wir); } } @@ -1554,7 +1579,6 @@ _fine_request(u3_ames* sam_u, u3_lane lan_u, u3_noun req) { - u3l_log("fine: request\n"); u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); u3_head* hed_u = c3_calloc(sizeof(*hed_u)); @@ -1580,6 +1604,7 @@ _fine_request(u3_ames* sam_u, pen_u->lan_u.por_s = lan_u.por_s; pen_u->sam_u = sam_u; + // TODO: revive for non-galaxy case _ames_czar(pen_u); } From 3a6b2352d0d6f7ef8919674dac3b495d56e4bc12 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 26 Jan 2022 22:35:37 -0600 Subject: [PATCH 024/168] ames: better protect against malicious packets --- pkg/urbit/vere/io/ames.c | 66 ++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 8309643dd..6346bfb7f 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -87,7 +87,6 @@ c3_d rog_d; // origin lane (optional) } u3_prel; -/* TODO: request response bodies for scry */ /* u3_requ: fine packet request */ typedef struct _u3_requ { u3_prel pre_u; @@ -371,7 +370,6 @@ _ames_sift_prelude(u3_head* hed_u, /* _fine_sift_requ(): parse request body, returning success - * TODO: bring up to date */ static c3_o _fine_sift_requ(u3_head* hed_u, @@ -384,7 +382,7 @@ _fine_sift_requ(u3_head* hed_u, req_y += pre_y; c3_w rem_w = (64 + 4 + 2 + pre_y); - if(rem_w > len_w) { + if ( rem_w > len_w ) { u3l_log("not big enough\n"); return c3n; } @@ -400,21 +398,17 @@ _fine_sift_requ(u3_head* hed_u, | (req_y[3] << 0x18)); req_y += 4; - req_u->len_s = c3_min(384, (req_y[0] << 0x0) | (req_y[1] << 0x8)); req_y += 2; - //_log_bytes(req_y, req_u->len_s); - - // TODO: strict inequality? - /*if(rem_w + req_u->len_s != len_w) { - u3l_log("bad format\n"); + c3_w exp_w = rem_w + req_u->len_s; + if ( exp_w != len_w ) { + u3l_log("expected len: %u, actual %u\n", exp_w, len_w); return c3n; - }*/ + } - // TODO: defend maliciusly crafted lengths? req_u->pat_c = c3_calloc(req_u->len_s + 1); memcpy(req_u->pat_c, req_y, req_u->len_s); @@ -1416,7 +1410,21 @@ static void _fine_hear_response(u3_ames* sam_u, c3_w len_w, c3_y* hun_y) { + u3_resp res_u; + u3_noun wir = u3nc(c3__fine, u3_nul); + c3_w num_w = res_u.num_w; + c3_w fra_w = res_u.fra_w; + + u3_noun cad = u3nt(c3__purr, + u3nc(c3n, u3_ames_encode_lane(lan_u)), + u3i_bytes(len_w, hun_y)); + + u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, u3k(wir), u3k(cad)); + u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); + + u3z(cad); + u3z(wir); } @@ -1427,6 +1435,8 @@ static void _fine_hear_request(u3_ames* sam_u, { u3_head hed_u; c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); + // TODO: check mug + // lookup in cache // (unit (unit (unit packet)) // ~ -> miss @@ -1534,27 +1544,10 @@ static void _fine_hear(u3_ames* sam_u, u3_head hed_u; c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); - if(c3n == hed_u.req_o) { _fine_hear_request(sam_u, lan_u, len_w, hun_y); } else { - u3_resp res_u; - - // TODO: check mug - - u3_noun wir = u3nc(c3__fine, u3_nul); - c3_w num_w = res_u.num_w; - c3_w fra_w = res_u.fra_w; - - u3_noun cad = u3nt(c3__purr, - u3nc(c3n, u3_ames_encode_lane(lan_u)), - u3i_bytes(len_w, hun_y)); - - u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, u3k(wir), u3k(cad)); - u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); - - u3z(cad); - u3z(wir); + _fine_hear_response(sam_u, lan_u, len_w, hun_y); } } @@ -1650,7 +1643,6 @@ _ames_hear(u3_ames* sam_u, return; } else if (c3n == is_ames_o) { - // TODO: dispatch fine request _fine_hear(sam_u, *lan_u, len_w, hun_y); return; } @@ -1894,16 +1886,6 @@ static c3_o _fine_io_kick(u3_auto* car_u, u3_noun wir, u3_noun nun) { } } -static void _fine_send_fail() -{ - // TODO: log some shit -} - -static void _fine_send_cb() -{ - // TODO: anything to do here? -} - /* _ames_prot_scry_cb(): receive ames protocol version */ static void @@ -1999,8 +1981,6 @@ _ames_io_talk(u3_auto* car_u) } - // TODO: scry the fine protocol out of arvo - // u3_pier_peek_last(car_u->pir_u, u3_nul, c3__fx, u3_nul, u3nt(u3i_string("protocol"), u3i_string("version"), u3_nul), sam_u, _fine_prot_scry_cb); @@ -2186,7 +2166,7 @@ u3_ames_io_init(u3_pier* pir_u, u3_auto** far_u) sam_u->fig_u.fit_o = c3n; // hashtable for scry cache - // TODO: review size + // // 1500 bytes per packet * 100_000 = 150MB // 50 bytes (average) per path * 100_000 = 5MB sam_u->fin_s.sac_p = u3h_new_cache(100000); From 00b7d2c4d4d6c7ea962145cb26edbca3e4933dc3 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 26 Jan 2022 22:53:31 -0600 Subject: [PATCH 025/168] ames: improve error handling --- pkg/urbit/vere/io/ames.c | 47 +++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 6346bfb7f..7fa90108d 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -1459,16 +1459,9 @@ static void _fine_hear_request(u3_ames* sam_u, if ( u3_none == cac ) { // cache miss - // packet scry path - // /packet/requested/path/elements - // - // eg: - // /packet/gx/~zod/graph-store/5/graphs/~zod/test/message/10 - // u3_noun pax = u3nc(u3i_string("message"), u3do("stab", u3k(pat))); - u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); @@ -1485,7 +1478,6 @@ static void _fine_hear_request(u3_ames* sam_u, u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, pax, pen_u, _fine_pack_scry_cb); - } else if(u3_nul == cac) { // cache hit, unbound // do nothing, maybe report? @@ -1508,25 +1500,26 @@ static void _fine_hear_request(u3_ames* sam_u, u3_resp* res_u = c3_calloc(sizeof(*res_u)); - c3_assert(c3y == _fine_sift_resp(&hed_u, res_u, fra_w, fra_y)); - - memcpy(&res_u->pre_u, &req_u.pre_u, sizeof(u3_prel)); + if ( c3n == _fine_sift_resp(&hed_u, res_u, fra_w, fra_y) ) { + c3_free(res_u); + } else { + memcpy(&res_u->pre_u, &req_u.pre_u, sizeof(u3_prel)); - c3_y* res_y; - c3_w res_w = _fine_etch_resp(&hed_u, res_u, &res_y); + c3_y* res_y; + c3_w res_w = _fine_etch_resp(&hed_u, res_u, &res_y); - // TODO: where free? maybe stack allocate instead? - u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); - pen_u->typ_y = 2; - pen_u->res_u = res_u; - pen_u->len_w = res_w; - pen_u->hun_y = res_y; - pen_u->her_d[0] = res_u->pre_u.sen_d[0]; - pen_u->her_d[1] = res_u->pre_u.sen_d[1]; - pen_u->lan_u = lan_u; - pen_u->sam_u = sam_u; + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + pen_u->typ_y = 2; + pen_u->res_u = res_u; + pen_u->len_w = res_w; + pen_u->hun_y = res_y; + pen_u->her_d[0] = res_u->pre_u.sen_d[0]; + pen_u->her_d[1] = res_u->pre_u.sen_d[1]; + pen_u->lan_u = lan_u; + pen_u->sam_u = sam_u; - _fine_send(pen_u); + _fine_send(pen_u); + } } u3z(pat); @@ -1542,9 +1535,9 @@ static void _fine_hear(u3_ames* sam_u, c3_y* hun_y) { u3_head hed_u; - c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); - - if(c3n == hed_u.req_o) { + if ( c3y == _ames_sift_head(&hed_u, hun_y) ) { + c3_free(hun_y); + } else if ( c3n == hed_u.req_o ) { _fine_hear_request(sam_u, lan_u, len_w, hun_y); } else { _fine_hear_response(sam_u, lan_u, len_w, hun_y); From 4c045a9c4ff0d2408204eea6b7e5febfcea5b4ef Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 27 Jan 2022 14:32:49 +0100 Subject: [PATCH 026/168] ames, fine: minimal compilable unification --- pkg/arvo/sys/arvo.hoon | 1 - pkg/arvo/sys/lull.hoon | 227 ++------------ pkg/arvo/sys/vane/ames.hoon | 600 ++++++++++++++++++++++++++++++++++-- pkg/arvo/sys/vane/fine.hoon | 435 -------------------------- 4 files changed, 602 insertions(+), 661 deletions(-) delete mode 100644 pkg/arvo/sys/vane/fine.hoon diff --git a/pkg/arvo/sys/arvo.hoon b/pkg/arvo/sys/arvo.hoon index acae58895..eb5839853 100644 --- a/pkg/arvo/sys/arvo.hoon +++ b/pkg/arvo/sys/arvo.hoon @@ -1674,7 +1674,6 @@ %c %clay %d %dill %e %eyre - %f %fine %g %gall %i %iris %j %jael diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 7fc2f6115..5f1519e0f 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -353,6 +353,12 @@ :: %jilt: stop tracking peer's responsiveness :: %plea: request to send message :: + :: Remote Scry Tasks + :: + :: %keen: data request from arvo + :: %yawn: cancel request from arvo + :: %bide: unix awaiting datum creation (%howl) + :: :: System and Lifecycle Tasks :: :: %born: process restart notification @@ -367,6 +373,10 @@ [%heed =ship] [%jilt =ship] $>(%plea vane-task) + :: + [%keen =path] + [%yawn =path] + [%bide =path] :: $>(%born vane-task) $>(%init vane-task) @@ -386,6 +396,10 @@ :: %lost: notify vane that we crashed on %boon :: %send: packet to unix :: + :: Remote Scry Gifts + :: %tune: found data for arvo + :: %howl: full response packets + :: :: System and Lifecycle Gifts :: :: %turf: domain report, relayed from jael @@ -396,6 +410,9 @@ [%done error=(unit error)] [%lost ~] [%send =lane =blob] + :: + [%tune =path data=(unit (cask))] + [%howl =path =song] :: [%turf turfs=(list turf)] == @@ -434,9 +451,6 @@ :: $blob: raw atom to or from unix, representing a packet :: +$ blob @uxblob - :: $protocol-version: 3-bit protocol version - :: - +$ protocol-version ?(%0 %1 %2 %3 %4 %5 %6 %7) :: $error: tagged diagnostic trace :: +$ error [tag=@tas =tang] @@ -464,6 +478,10 @@ +$ public-key @uwpublickey +$ symmetric-key @uwsymmetrickey :: + +$ hoot @uxhoot :: request packet + +$ purr @uxpurr :: response packet + +$ song (list purr) :: full response + :: :: +| %kinetics :: $ack: positive ack, nack packet, or nack trace :: @@ -705,171 +723,6 @@ num-received=fragment-num fragments=(map fragment-num fragment) == - :: |packets: ames-style packet en- and decoding - :: - :: $dyad: pair of sender and receiver ships - :: - +$ dyad [sndr=ship rcvr=ship] - :: $rank: which kind of ship address, by length - :: - :: 0b0: galaxy or star -- 2 bytes - :: 0b1: planet -- 4 bytes - :: 0b10: moon -- 8 bytes - :: 0b11: comet -- 16 bytes - :: - +$ rank ?(%0b0 %0b1 %0b10 %0b11) - :: $packet: noun representation of an ames datagram packet - :: - :: Roundtrips losslessly through atom encoding and decoding. - :: - :: .origin is ~ unless the packet is being forwarded. If present, - :: it's an atom that encodes a route to another ship, such as an IPv4 - :: address. Routes are opaque to Arvo and only have meaning in the - :: interpreter. This enforces that Ames is transport-agnostic. - :: - +$ packet - $: dyad - sndr-tick=@ubC - rcvr-tick=@ubC - origin=(unit @uxaddress) - content=@uxcontent - == - :: +encode-packet: serialize a packet into a bytestream - :: - ++ encode-packet - |= [ames=? =protocol-version] - |= packet - ^- blob - :: - =/ sndr-meta (encode-ship-metadata sndr) - =/ rcvr-meta (encode-ship-metadata rcvr) - :: - =/ body=@ - ;: mix - sndr-tick - (lsh 2 rcvr-tick) - (lsh 3 sndr) - (lsh [3 +(size.sndr-meta)] rcvr) - (lsh [3 +((add size.sndr-meta size.rcvr-meta))] content) - == - =/ checksum (end [0 20] (mug body)) - =? body ?=(^ origin) (mix u.origin (lsh [3 6] body)) - :: - =/ header=@ - %+ can 0 - :~ [3 reserved=0] - [1 is-ames=ames] - [3 protocol-version] - [2 rank.sndr-meta] - [2 rank.rcvr-meta] - [20 checksum] - [1 relayed=.?(origin)] - == - (mix header (lsh 5 body)) - :: +decode-packet: deserialize packet from bytestream or crash - :: - ++ decode-packet - |= [ames=? =protocol-version] - |= =blob - ^- packet - ~| %decode-packet-fail - :: first 32 (2^5) bits are header; the rest is body - :: - =/ header (end 5 blob) - =/ body (rsh 5 blob) - :: read header; first three bits are reserved - :: - =/ is-ames (cut 0 [3 1] header) - ?. =(ames is-ames) - ~| ?:(ames %ames-not-ames %fine-not-fine) !! - :: - =/ version (cut 0 [4 3] header) - ?. =(protocol-version version) - ~| ames-protocol-version+version !! - :: - =/ sndr-size (decode-ship-size (cut 0 [7 2] header)) - =/ rcvr-size (decode-ship-size (cut 0 [9 2] header)) - =/ checksum (cut 0 [11 20] header) - =/ relayed (cut 0 [31 1] header) - :: origin, if present, is 6 octets long, at the end of the body - :: - =^ origin=(unit @) body - ?: =(| relayed) - [~ body] - =/ len (sub (met 3 body) 6) - [`(end [3 6] body) (rsh [3 6] body)] - :: .checksum does not apply to the origin - :: - ?. =(checksum (end [0 20] (mug body))) - ~| %ames-checksum !! - :: read fixed-length sndr and rcvr life data from body - :: - :: These represent the last four bits of the sender and receiver - :: life fields, to be used for quick dropping of honest packets to - :: or from the wrong life. - :: - =/ sndr-tick (cut 0 [0 4] body) - =/ rcvr-tick (cut 0 [4 4] body) - :: read variable-length .sndr and .rcvr addresses - :: - =/ off 1 - =^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)] - ?. (is-valid-rank sndr sndr-size) - ~| ames-sender-impostor+[sndr sndr-size] !! - :: - =^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)] - ?. (is-valid-rank rcvr rcvr-size) - ~| ames-receiver-impostor+[rcvr rcvr-size] !! - :: read variable-length .content from the rest of .body - :: - =/ content (cut 3 [off (sub (met 3 body) off)] body) - [[sndr rcvr] sndr-tick rcvr-tick origin content] - :: +decode-ship-size: decode a 2-bit ship type specifier into a byte width - :: - :: Type 0: galaxy or star -- 2 bytes - :: Type 1: planet -- 4 bytes - :: Type 2: moon -- 8 bytes - :: Type 3: comet -- 16 bytes - :: - ++ decode-ship-size - |= rank=@ubC - ^- @ - :: - ?+ rank !! - %0b0 2 - %0b1 4 - %0b10 8 - %0b11 16 - == - :: +encode-ship-metadata: produce size (in bytes) and address rank for .ship - :: - :: 0: galaxy or star - :: 1: planet - :: 2: moon - :: 3: comet - :: - ++ encode-ship-metadata - |= =ship - ^- [size=@ =rank] - :: - =/ size=@ (met 3 ship) - :: - ?: (lte size 2) [2 %0b0] - ?: (lte size 4) [4 %0b1] - ?: (lte size 8) [8 %0b10] - [16 %0b11] - :: +is-valid-rank: does .ship match its stated .size? - :: - ++ is-valid-rank - |= [=ship size=@ubC] - ^- ? - .= size - =/ wid (met 3 ship) - ?: (lte wid 1) 2 - ?: =(2 wid) 2 - ?: (lte wid 4) 4 - ?: (lte wid 8) 8 - ?> (lte wid 16) 16 -- ::ames :: :::: :::: ++behn :: (1b) timekeeping @@ -1794,35 +1647,6 @@ +$ user knot :: username -- ::eyre :: :::: -:::: ++fine :: (1f) remote scry - :: :::: -++ fine ^? - |% - +$ gift :: to arvo: - $% [%tune =path data=(unit (cask))] :: found at path - :: :: to vere: - [%hoot =lane:ames =hoot] :: request packet - [%howl =path =song] :: full response - == :: - :: :: - +$ task :: from arvo: - $% [%keen =path] :: data request - [%yawn =path] :: cancel request - :: :: from unix: - ::TODO add ames task for updating lane - [%purr [from=ship =lane:ames] =purr] :: data packet - [%bide =path] :: await %howl - :: :: generic: - $>(%born vane-task) :: new unix process - $>(%trim vane-task) :: trim state - $>(%vega vane-task) :: report upgrade - == :: - :: :: - +$ hoot @uxhoot :: request packet - +$ purr @uxpurr :: response packet - +$ song (list purr) :: full response - -- ::fine -:: :::: :::: ++gall :: (1g) extensions :: :::: ++ gall ^? @@ -2316,7 +2140,6 @@ [%c task:clay] [%d task:dill] [%e task:eyre] - [%f task:fine] [%g task:gall] [%i task:iris] [%j task:jael] @@ -2338,7 +2161,6 @@ [%clay gift:clay] [%dill gift:dill] [%eyre gift:eyre] - [%fine gift:fine] [%gall gift:gall] [%iris gift:iris] [%jael gift:jael] @@ -2394,11 +2216,8 @@ :: %behn: wakeup :: $>(%wake task:behn) - :: %fine: hear packet + :: %ames: await namespace datum :: - $>(%purr task:fine) - :: %fine: await datum - :: - $>(%bide task:fine) + $>(%bide task:ames) == -- :: diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index baf1b813e..ade806d30 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -85,11 +85,16 @@ :: :: Debug output can be adjusted using %sift and %spew $task's. :: +::TODO fine +:: - receiving packets: +on-hear (1st) -> +on-hear-packet -> %fine +:: - sending packets: +on-plea -> +make-peer-core (make a function kind of like +on-memo) -> call +on-pump-send kind of like how +run-message-pump does +:: (assuming as event, scry just stateless) +:: :: protocol-version: current version of the ames wire protocol :: !: +=/ protocol-version=?(%0 %1 %2 %3 %4 %5 %6 %7) %0 =, ames -=/ =protocol-version %0 =* point point:jael =* public-keys-result public-keys-result:jael :: veb: verbosity flags @@ -248,9 +253,105 @@ =. private-key (rsh 8 (rsh 3 private-key)) :: `@`(shar:ed:crypto public-key private-key) +:: +encode-packet: serialize a packet into a bytestream :: -++ encode-packet (^encode-packet & protocol-version) -++ decode-packet (^decode-packet & protocol-version) +++ encode-packet + |= [ames=? packet] + ^- blob + :: + =/ sndr-meta (encode-ship-metadata sndr) + =/ rcvr-meta (encode-ship-metadata rcvr) + :: + =/ body=@ + ;: mix + sndr-tick + (lsh 2 rcvr-tick) + (lsh 3 sndr) + (lsh [3 +(size.sndr-meta)] rcvr) + (lsh [3 +((add size.sndr-meta size.rcvr-meta))] content) + == + =/ checksum (end [0 20] (mug body)) + =? body ?=(^ origin) (mix u.origin (lsh [3 6] body)) + :: + =/ header=@ + %+ can 0 + :~ [3 reserved=0] + [1 is-ames=ames] + [3 protocol-version] + [2 rank.sndr-meta] + [2 rank.rcvr-meta] + [20 checksum] + [1 relayed=.?(origin)] + == + (mix header (lsh 5 body)) +:: +decode-packet: deserialize packet from bytestream or crash +:: +++ decode-packet + |= =blob + ^- [ames=? =packet] + ~| %decode-packet-fail + :: first 32 (2^5) bits are header; the rest is body + :: + =/ header (end 5 blob) + =/ body (rsh 5 blob) + :: read header; first three bits are reserved + :: + =/ is-ames (cut 0 [3 1] header) + :- =(& is-ames) + :: + =/ version (cut 0 [4 3] header) + ?. =(protocol-version version) + ~| ames-protocol-version+version !! + :: + =/ sndr-size (decode-ship-size (cut 0 [7 2] header)) + =/ rcvr-size (decode-ship-size (cut 0 [9 2] header)) + =/ checksum (cut 0 [11 20] header) + =/ relayed (cut 0 [31 1] header) + :: origin, if present, is 6 octets long, at the end of the body + :: + =^ origin=(unit @) body + ?: =(| relayed) + [~ body] + =/ len (sub (met 3 body) 6) + [`(end [3 6] body) (rsh [3 6] body)] + :: .checksum does not apply to the origin + :: + ?. =(checksum (end [0 20] (mug body))) + ~| %ames-checksum !! + :: read fixed-length sndr and rcvr life data from body + :: + :: These represent the last four bits of the sender and receiver + :: life fields, to be used for quick dropping of honest packets to + :: or from the wrong life. + :: + =/ sndr-tick (cut 0 [0 4] body) + =/ rcvr-tick (cut 0 [4 4] body) + :: read variable-length .sndr and .rcvr addresses + :: + =/ off 1 + =^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)] + ?. (is-valid-rank sndr sndr-size) + ~| ames-sender-impostor+[sndr sndr-size] !! + :: + =^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)] + ?. (is-valid-rank rcvr rcvr-size) + ~| ames-receiver-impostor+[rcvr rcvr-size] !! + :: read variable-length .content from the rest of .body + :: + =/ content (cut 3 [off (sub (met 3 body) off)] body) + [[sndr rcvr] sndr-tick rcvr-tick origin content] +:: +is-valid-rank: does .ship match its stated .size? +:: +++ is-valid-rank + |= [=ship size=@ubC] + ^- ? + .= size + =/ wid (met 3 ship) + ?: (lte wid 1) 2 + ?: =(2 wid) 2 + ?: (lte wid 4) 4 + ?: (lte wid 8) 8 + ?> (lte wid 16) 16 :: +encode-open-packet: convert $open-packet attestation to $packet :: ++ encode-open-packet @@ -336,10 +437,52 @@ =/ vec ~[sndr.packet rcvr.packet sndr-life rcvr-life] ;; shut-packet %- cue %- need (~(de sivc:aes:crypto (shaz symmetric-key) vec) siv len cyf) +:: +decode-ship-size: decode a 2-bit ship type specifier into a byte width +:: +:: Type 0: galaxy or star -- 2 bytes +:: Type 1: planet -- 4 bytes +:: Type 2: moon -- 8 bytes +:: Type 3: comet -- 16 bytes +:: +++ decode-ship-size + |= rank=@ubC + ^- @ + :: + ?+ rank !! + %0b0 2 + %0b1 4 + %0b10 8 + %0b11 16 + == +:: +encode-ship-metadata: produce size (in bytes) and address rank for .ship +:: +:: 0: galaxy or star +:: 1: planet +:: 2: moon +:: 3: comet +:: +++ encode-ship-metadata + |= =ship + ^- [size=@ =rank] + :: + =/ size=@ (met 3 ship) + :: + ?: (lte size 2) [2 %0b0] + ?: (lte size 4) [4 %0b1] + ?: (lte size 8) [8 %0b10] + [16 %0b11] +| %atomics :: +$ private-key @uwprivatekey +$ signature @uwsignature +:: $rank: which kind of ship address, by length +:: +:: 0b0: galaxy or star -- 2 bytes +:: 0b1: planet -- 4 bytes +:: 0b10: moon -- 8 bytes +:: 0b11: comet -- 16 bytes +:: ++$ rank ?(%0b0 %0b1 %0b10 %0b11) :: +| %kinetics :: $channel: combined sender and receiver identifying data @@ -360,6 +503,25 @@ =her=public-key her-sponsor=ship == == +:: $dyad: pair of sender and receiver ships +:: ++$ dyad [sndr=ship rcvr=ship] +:: $packet: noun representation of an ames datagram packet +:: +:: Roundtrips losslessly through atom encoding and decoding. +:: +:: .origin is ~ unless the packet is being forwarded. If present, +:: it's an atom that encodes a route to another ship, such as an IPv4 +:: address. Routes are opaque to Arvo and only have meaning in the +:: interpreter. This enforces that Ames is transport-agnostic. +:: ++$ packet + $: dyad + sndr-tick=@ubC + rcvr-tick=@ubC + origin=(unit @uxaddress) + content=@uxcontent + == :: $open-packet: unencrypted packet payload, for comet self-attestation :: :: This data structure gets signed and jammed to form the .contents @@ -417,6 +579,33 @@ =life crypto-core=acru:ames =bug + =fine-state + == ++$ ames-state-5 + $: peers=(map ship ship-state) + =unix=duct + =life + crypto-core=acru:ames + =bug + == +:: $fine-state: remote scry subsystem state +:: +:: hear: awaiting existence +:: want: awaiting response +:: part: partial responses +:: ++$ fine-state + $: hear=(jug path duct) + want=(jug path duct) + part=(map path partial-fine) + ::TODO re-send request timers? + == +:: $partial-fine: partial remote scry response +:: ++$ partial-fine + $: num-fragments=@ud + num-received=@ud + fragments=(map @ud byts) ::TODO not byts, always 1024 bytes, just @ == :: $bug: debug printing configuration :: @@ -665,17 +854,24 @@ :: lifecycle arms; mostly pass-throughs to the contained adult ames :: ++ scry scry:adult-core - ++ stay [%5 %larva queued-events ames-state.adult-gate] + ++ stay [%6 %larva queued-events ames-state.adult-gate] ++ load |= $= old $% $: %4 $% $: %larva events=(qeu queued-event) - state=_ames-state.adult-gate + state=ames-state-5 == - [%adult state=_ames-state.adult-gate] + [%adult state=ames-state-5] == == $: %5 + $% $: %larva + events=(qeu queued-event) + state=ames-state-5 + == + [%adult state=ames-state-5] + == == + $: %6 $% $: %larva events=(qeu queued-event) state=_ames-state.adult-gate @@ -699,6 +895,14 @@ =. queued-events events.old =. adult-gate (load:adult-core %5 state.old) larval-gate + :: + [%6 %adult *] (load:adult-core %6 state.old) + :: + [%6 %larva *] + ~> %slog.1^leaf/"ames: larva: load" + =. queued-events events.old + =. adult-gate (load:adult-core %6 state.old) + larval-gate == -- :: adult ames, after metamorphosis from larva @@ -719,15 +923,24 @@ =/ event-core (per-event [now eny rof] duct ames-state) :: =^ moves ames-state - =< abet :: handle error notifications :: ?^ dud + =< abet ?+ -.task (on-crud:event-core -.task tang.u.dud) %hear (on-hear:event-core lane.task blob.task dud) == :: + ?: ?=(?(%keen %yawn %bide) -.task) + =/ fine-core (fine now rof duct ames-state) + ?- -.task + %keen (on-keen:fine-core +.task) + %yawn (on-yawn:fine-core +.task) + %bide (on-bide:fine-core +.task) + == + :: + =< abet ?- -.task %born on-born:event-core %hear (on-hear:event-core [lane blob ~]:task) @@ -770,24 +983,31 @@ [moves ames-gate] :: +stay: extract state before reload :: -++ stay [%5 %adult ames-state] +++ stay [%6 %adult ames-state] :: +load: load in old state after reload :: ++ load - |= $= old-state - $% [%4 ^ames-state] - [%5 ^ames-state] - == |^ + |= $= old-state + $% [%4 ames-state-5] + [%5 ames-state-5] + [%6 ^ames-state] + == ^+ ames-gate =? old-state ?=(%4 -.old-state) %5^(state-4-to-5 +.old-state) + =? old-state ?=(%5 -.old-state) %6^(state-5-to-6 +.old-state) :: - ?> ?=(%5 -.old-state) + ?> ?=(%6 -.old-state) ames-gate(ames-state +.old-state) :: + ++ state-5-to-6 + |= old=ames-state-5 + ^- ^ames-state + old(bug [bug.old *fine-state]) + :: ++ state-4-to-5 - |= =^ames-state - ^- ^^ames-state + |= ames-state=ames-state-5 + ^- ames-state-5 =. peers.ames-state %- ~(run by peers.ames-state) |= =ship-state @@ -838,6 +1058,7 @@ :: /ax/peers/[ship]/forward-lane (list lane) :: /ax/bones/[ship] [snd=(set bone) rcv=(set bone)] :: /ax/snd-bones/[ship]/[bone] vase + :: /ax/fine/message/[path/...] song :: ?. ?=(%x ren) ~ ?+ tyl ~ @@ -913,11 +1134,21 @@ =/ res u.mps ``noun+!>(!>(res)) + :: + [%fine %message @ *] + :: t.t.tyl is expected to be a scry path of the shape /vc/desk/rev/etc, + :: so we need to give it the right shape + :: + =/ pax=path + [i.t.t.tyl (scot %p our) t.t.t.tyl] + =/ fin + (fine now rof *duct ames-state) + ``noun+!>((encode-response:fin pax (get-scry-result:fin lyc pax))) == -- :: |per-event: inner event-handling core :: -~% %per-event ..trace ~ +~% %per-event ..decode-packet ~ |% ++ per-event =| moves=(list move) @@ -1076,7 +1307,18 @@ :: ++ on-hear |= [l=lane b=blob d=(unit goof)] - (on-hear-packet l (decode-packet b) d) + =/ [ames=? =packet] + (decode-packet b) + ?: ames + (on-hear-packet l packet d) + :: + =^ moz ames-state + %- on-hear-response:(fine now rof duct ames-state) + ~| [%fine %request-events-forbidden] + ?> response==(& (cut 0 [2 1] b)) + [l packet d] + =. moves (weld (flop moz) moves) + ..on-hear :: +on-hear-packet: handle mildly processed packet receipt :: ++ on-hear-packet @@ -1119,7 +1361,7 @@ ~| ames-lane-size+p.lane !! `p.lane :: - =/ =blob (encode-packet packet) + =/ =blob (encode-packet & packet) (send-blob & rcvr.packet blob) :: +on-hear-open: handle receipt of plaintext comet self-attestation :: @@ -1542,7 +1784,7 @@ :: +on-trim: handle request to free memory :: ++ on-vega event-core - ++ on-trim event-core + ++ on-trim event-core ::TODO trim fine parts on high prio :: +enqueue-alien-todo: helper to enqueue a pending request :: :: Also requests key and life from Jael on first request. @@ -1645,7 +1887,7 @@ ++ attestation-packet |= [her=ship =her=life] ^- blob - %- encode-packet + %+ encode-packet & %- encode-open-packet :_ crypto-core.ames-state :* ^= public-key pub:ex:crypto-core.ames-state @@ -1917,7 +2159,7 @@ :: =. event-core %^ send-blob | her.channel - %- encode-packet + %+ encode-packet & %: encode-shut-packet shut-packet(bone (mix 1 bone.shut-packet)) symmetric-key.channel @@ -2981,4 +3223,320 @@ :: message-sink -- +:: +++ fine + |= [now=@da rof=roof =duct =ames-state] + =* state fine-state.ames-state + =< |% + ++ on-keen + |= =path + ^- (quip move _ames-state) + =/ omen + ~| [%fine %invalid-namespace-path path] + (need (de-omen path)) + =. want.state (~(put ju want.state) path duct) + ?: (~(has by part.state) path) + :: request is already ongoing + :: + [~ ames-state] + :: kick off the request + :: + =. part.state (~(put by part.state) path *partial-fine) + :_ ames-state + =/ =lane:ames (get-lane p.bem.omen) + =/ =hoot (encode-request path 1) + [unix-duct.ames-state %give %send lane `@ux`hoot]~ + :: + ++ on-yawn + |= =path + ^- (quip move _ames-state) + =. want.state (~(del ju want.state) path duct) + [~ ames-state] + :: + ++ on-bide + |= =path + ^- (quip move _ames-state) + =. hear.state (~(put ju hear.state) path duct) + [~ ames-state] + :: + ++ on-hear-response + |= [=lane =packet dud=(unit goof)] + ^- (quip move _ames-state) + ?^ dud + ::TODO handle + ~& [%fine %done-goofed u.dud] + [~ ames-state] + =/ [=peep =purr] (decode-request-info `@ux`content.packet) + =/ =rawr (decode-response-packet purr) + ::TODO validate response signature + (handle-response [sndr.packet lane] peep rawr) + -- + |% + +$ twit :: signed request + $: signature=@ + peep + == + :: + +$ peep :: request data + $: =path + num=@ud + == + :: + +$ rawr :: response packet ::TODO meow + $: sig=@ + siz=@ud + byts + == + :: + +$ roar :: response message + $: sig=@ + dat=(cask) + == + :: + ++ spit + |= =path + ^- [pat=@t wid=@ud] + =+ pat=(spat path) + =+ wid=(met 3 pat) + ?> (lte wid 384) ::TODO check when we handle %keen, in addition to here + [pat wid] + :: + ++ request-body + |= [=path num=@ud] + ::TODO need to ensure valid namespace path without ship + ^- byts + ?> (lth num (bex 32)) + =+ (spit path) + :- :(add 32 16 wid) + %+ can 3 + :~ 4^num :: fragment number + 2^wid :: path size + wid^`@`pat :: namespace path + == + :: + ++ encode-request + |= [=path num=@ud] + ^- hoot ^- @ + =+ bod=(request-body path num) + =+ syn=(can 3 64^(sign:keys dat.bod) bod ~) + %+ con 0b100 ::NOTE request bit + (encode-packet | [our ~zod] (mod life:keys 16) 0b0 ~ syn) + :: + ++ encode-response ::TODO unit tests + |= [=path data=(unit (cask))] + ^- song + :: prepend request descriptions to each response packet + :: + =; pacs=(list @ux) + %- head + %^ spin pacs 1 + |= [pac=@ux num=@ud] + ^- [purr _num] + :_ +(num) + ^- @ux + ::NOTE we stub out the receiver & origin details, + :: runtime should replace them as appropriate. + ::TODO should have scry endpoint that produces gate that does + :: that packet transformation + (encode-packet | [our ~zod] (mod life:keys 16) 0b0 ~ pac) + :: prepend a signature and split the data into 1024-byte fragments + :: + =/ frag=(list @) + ::TODO should also sign the request path + =/ sig=@ (full:keys path (fall data ~)) + ?~ data [sig]~ + %+ rip 13 ::NOTE 1024 bytes + (cat 3 sig (jam u.data)) ::TODO should include life + :: sign & packetize the fragments + :: + %- head + %^ spin frag 1 + |= [dat=@ num=@ud] + :_ +(num) + ^- @ux + =/ req=byts (request-body path num) + =/ bod=byts + =/ wid=@ud (met 3 dat) + :- :(add 4 2 wid) + %+ can 3 + :~ 4^(lent frag) :: number of fragments + 2^wid :: response data fragment size in bytes + wid^dat :: response data fragment + == + =/ sig=byts + 64^(sign:keys (can 3 req bod ~)) + (can 3 req sig bod ~) + :: + ++ keys + |% + ++ full + |= [=path mess=*] + (sign (shax (jam [our life path mess]))) + :: + ++ life ~+ (jael ^life %life /(scot %p our)) + ++ ring ~+ (jael ^ring %vein /(scot %ud life)) + ++ sign sign:as:(nol:nu:crub:crypto ring) + :: + ++ jael + |* [=mold =desk =path] + !< mold + %- tail %- need %- need + (rof `[our ~ ~] [%jael %$] [our desk da+now] path) + :: + ++ lyfe + |= who=ship + (jael (unit ^life) %lyfe /(scot %p our)) + :: + ::TODO don't scry! subscribe & get from state instead + ::TODO literally copy the ames code lol + ::TODO the fact that we share pki and lane data with ames is... suspect + :: also the en/decoding etc + ++ pass + |= [who=ship lyf=^life] + ::TODO but might fail need checks? + :: (jael * %deed ) + !! + -- + :: + ++ get-lane + |= =ship + ^- lane:ames + =; lanes + ::TODO should we send to all lanes? + ?^ lanes i.lanes + ~&(%fine-lane-stub &+~zod) ::TODO + !< (list lane:ames) + =< q %- need %- need + =/ =path /peers/(scot %p ship)/forward-lane + ::TODO get from state + (rof `[our ~ ~] [%ames %x] [our %$ da+now] path) + :: + ++ decode-request + |= =hoot + ^- twit + :- sig=(cut 3 [0 64] hoot) + -:(decode-request-info (rsh 3^64 hoot)) + :: + ++ decode-request-info + |= =hoot + ^- [=peep =purr] + =+ num=(cut 3 [0 4] hoot) + =+ len=(cut 3 [4 2] hoot) + =+ pat=(cut 3 [6 len] hoot) + :- [(stab pat) num] + :: if there is data remaining, it's the response + (rsh [3 (add 6 len)] hoot) + :: + ++ decode-response-packet + |= =purr + =; =rawr + ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] + rawr + :* sig=(cut 3 [0 64] purr) + siz=(cut 3 [64 4] purr) + wid=(cut 3 [68 2] purr) + dat=(rsh 3^70 purr) + == + :: + ++ verify-response-packet + |= rawr + !! + :: + ++ decode-response-msg + |= partial-fine ::TODO maybe take @ instead + ^- roar + =/ mess=@ + %+ can 3 ::TODO just (rep 13 -) + %+ turn (gulf 1 num-fragments) + ~(got by fragments) + :- sig=(cut 3 [0 64] mess) + ~| [%fine %response-not-cask] + ;;((cask) (cue (rsh 3^64 mess))) + :: + ++ process-response + |= [=path data=(unit (cask))] + ^- (quip move _ames-state) + :- %+ turn ~(tap in (~(get ju want.state) path)) + (late [%give %tune path data]) + =. want.state (~(del by want.state) path) + =. part.state (~(del by part.state) path) + ames-state + :: + ++ handle-request + |= =twit + ^- (list move) + =/ =song + %+ encode-response path.twit + (get-scry-result *gang path.twit) + ::TODO different task, pick the right packet + [duct %give %howl path.twit song]~ + :: + ++ handle-response + |= [[from=ship =lane:ames] =peep =rawr] + ^- (quip move _ames-state) + ?: =(0 siz.rawr) + ?> =(~ dat.rawr) + (process-response path.peep ~) + ?. (~(has by part.state) path.peep) + :: we did not initiate this request, or it's been cancelled + :: + !! + =/ partial=partial-fine + (~(got by part.state) path.peep) + =. partial + ?: (~(has by fragments.partial) num.peep) + partial + =, partial + :+ ~| [%fine %response-size-changed have=num-fragments new=siz.rawr] + ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) + num-fragments + +(num-received) + (~(put by fragments) num.peep [wid dat]:rawr) + :: + ?: =(num-fragments num-received):partial + :: we have all the parts now, construct the full response + :: + =/ =roar (decode-response-msg partial) + ::TODO check signature + (process-response path.peep `dat.roar) + :: otherwise, store the part, and send out the next request + :: + =. part.state (~(put by part.state) path.peep partial) + =/ next-num=@ud + =/ next=@ud +(num.peep) + :: we should receive responses in order, but in case we don't... + :: + |- + ?. (~(has by fragments.partial) next) next + $(next +((mod next num-fragments.partial))) + :: + =/ =hoot (encode-request path.peep next-num) + ::TODO ask amsden, should we shotgun? we can tweak this + :: for now (mvp) though, stay 1-to-1 + ::TODO update lane in ames state + ::TODO is reusing the lane fine? + :_ ames-state + [unix-duct.ames-state %give %send lane `@ux`hoot]~ + :: + ++ get-scry-result + |= [=gang =path] + ^- (unit (cask)) + ?~ nom=(de-omen path) ~ + ?> =(our p.bem.u.nom) + :: we only support scrying into clay, + :: and only if the data is fully public. + :: + ?. =(%c (end 3 (snag 0 path))) ~ + =+ pem=(rof gang (need (de-omen %cp (slag 1 path)))) + ?> ?=(^ pem) + ?> ?=(^ u.pem) + =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) + ?> =([%black ~ ~] rul.r.per) + =+ res=(rof gang u.nom) + ?- res + ~ !! ::TODO lets just not do the task case + [~ ~] ~ + [~ ~ *] `[p q.q]:u.u.res + == + -- -- diff --git a/pkg/arvo/sys/vane/fine.hoon b/pkg/arvo/sys/vane/fine.hoon deleted file mode 100644 index 6eda3ba26..000000000 --- a/pkg/arvo/sys/vane/fine.hoon +++ /dev/null @@ -1,435 +0,0 @@ -:: %fine, remote scries -!: -:: -::TODO jael does ames-specific behavior for %public-keys gifts(?). -:: should it do something similar for fine? -:: -=, fine -|= our=ship -=> |% - +$ move [p=duct q=(wite note gift)] - +$ note :: out request $-> - $% $: %b - $% $>(%wait task:behn) - $>(%rest task:behn) - == == - $: %j - $% $>(%private-keys task:jael) - $>(%public-keys task:jael) - == == == - +$ sign - $% $: %behn - $% $>(%wake gift:behn) - == == - $: %jael - $% $>(%private-keys gift:jael) - $>(%public-keys gift:jael) - == == == - :: - ::TODO get pubkeys from jael in the same way ames does - :: - +$ fine-state - $: %0 - urth=duct :: unix duct - hear=(jug path duct) :: awaiting existence - want=(jug path duct) :: awaiting response - part=(map path partial) :: partial responses - ::TODO re-send request timers? - == - :: - +$ bits [w=@ud d=@] - ++ protocol-version %0 - :: - +$ partial - $: num-fragments=@ud - num-received=@ud - fragments=(map @ud byts) - == - :: - +$ twit :: signed request - $: signature=@ - peep - == - :: - +$ peep :: request data - $: =path - num=@ud - == - :: - +$ rawr :: response packet - $: sig=@ - siz=@ud - byts - == - :: - +$ roar :: response message - $: sig=@ - dat=(cask) - == - -- -:: -~% %fine ..part ~ -:: -=| fine-state -=* state - -|= [now=@da eny=@uvJ rof=roof] -=* fine-gate . -=> |% - ++ encode-packet (encode-packet:ames | protocol-version) - ++ decode-packet (decode-packet:ames | protocol-version) - :: - ++ spit - |= =path - ^- [pat=@t wid=@ud] - =+ pat=(spat path) - =+ wid=(met 3 pat) - ?> (lte wid 384) ::TODO check when we handle %keen, instead of here? - [pat wid] - :: - ++ request-body - |= [=path num=@ud] - ^- byts - ?> (lth num (bex 32)) - =+ (spit path) - :- :(add 4 2 wid) - %+ can 3 - :~ 4^num :: fragment number - 2^wid :: path size - wid^`@`pat :: namespace path - == - :: - ++ encode-request - |= [=path num=@ud] - ^- hoot ^- @ - =+ bod=(request-body path num) - =+ syn=(can 3 64^(sign:keys dat.bod) bod ~) - %+ con 0b100 ::NOTE request bit - (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ syn) - :: - ++ encode-response - |= [=path data=(unit (cask))] - ^- song - :: prepend request descriptions to each response packet - :: - =; pacs=(list @ux) - %- head - %^ spin pacs 1 - |= [pac=@ux num=@ud] - ^- [purr _num] - :_ +(num) - ^- @ux - ::NOTE we stub out the receiver & origin details, - :: runtime should replace them as appropriate. - (encode-packet [our ~zod] (mod life:keys 16) 0b0 ~ pac) - :: prepend a signature and split the data into 1024-byte fragments - :: - =/ frag=(list @) - =/ sig=@ (full:keys path (fall data ~)) - ?~ data [sig]~ - %+ rip 13 ::NOTE 1024 bytes - (cat 3 sig (jam u.data)) ::TODO should include life - :: sign & packetize the fragments - :: - %- head - %^ spin frag 1 - |= [dat=@ num=@ud] - :_ +(num) - ^- @ux - =/ req=byts (request-body path num) - =/ bod=byts - =/ wid=@ud (met 3 dat) - :- :(add 4 2 wid) - %+ can 3 - :~ 4^(lent frag) :: number of fragments - 2^wid :: response data fragment size in bytes - wid^dat :: response data fragment - == - =/ sig=byts - 64^(sign:keys (can 3 req bod ~)) - (can 3 req sig bod ~) - :: - ++ keys - |% - ++ full - |= [=path mess=*] - (sign (shax (jam [our life path mess]))) - :: - ++ life ~+ (jael ^life %life /(scot %p our)) - ++ ring ~+ (jael ^ring %vein /(scot %ud life)) - ++ sign sign:as:(nol:nu:crub:crypto ring) - :: - ++ jael - |* [=mold =desk =path] - !< mold - %- tail %- need %- need - (rof `[our ~ ~] [%jael %$] [our desk da+now] path) - :: - ++ lyfe - |= who=ship - (jael (unit ^life) %lyfe /(scot %p our)) - :: - ::TODO don't scry! subscribe & get from state instead - ++ pass - |= [who=ship lyf=^life] - ::TODO but might fail need checks? - :: (jael * %deed ) - !! - -- - :: - ++ get-lane - |= =ship - ^- lane:ames - =; lanes - ::TODO should we send to all lanes? - ?^ lanes i.lanes - ~&(%fine-lane-stub &+~zod) ::TODO - !< (list lane:ames) - =< q %- need %- need - =/ =path /peers/(scot %p ship)/forward-lane - (rof `[our ~ ~] [%ames %x] [our %$ da+now] path) - :: - ++ decode-request - |= =hoot - ^- twit - :- sig=(cut 3 [0 64] hoot) - -:(decode-request-info (rsh 3^64 hoot)) - :: - ++ decode-request-info - |= =hoot - ^- [=peep =purr] - =+ num=(cut 3 [0 4] hoot) - =+ len=(cut 3 [4 2] hoot) - =+ pat=(cut 3 [6 len] hoot) - :- [(stab pat) num] - :: if there is data remaining, it's the response - (rsh [3 (add 6 len)] hoot) - :: - ++ decode-response-packet - |= =purr - =; =rawr - ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] - rawr - :* sig=(cut 3 [0 64] purr) - siz=(cut 3 [64 4] purr) - wid=(cut 3 [68 2] purr) - dat=(rsh 3^70 purr) - == - :: - ++ verify-response-packet - |= rawr - !! - :: - ++ decode-response-msg - |= partial ::TODO maybe take @ instead - ^- roar - =/ mess=@ - %+ can 3 ::TODO just (rep 13 -) - %+ turn (gulf 1 num-fragments) - ~(got by fragments) - :- sig=(cut 3 [0 64] mess) - ~| [%fine %response-not-cask] - ;;((cask) (cue (rsh 3^64 mess))) - :: - ++ process-response - |= [=path data=(unit (cask))] - ^- (quip move _state) - :- %+ turn ~(tap in (~(get ju want) path)) - (late [%give %tune path data]) - =. want (~(del by want) path) - =. part (~(del by part) path) - state - :: - ++ handle-request - |= [=duct =twit] - ^- (list move) - =/ =song - %+ encode-response path.twit - (get-scry-result *gang path.twit) - ::TODO different task, pick the right packet - [duct %give %howl path.twit song]~ - :: - ++ handle-response - |= [[from=ship =lane:ames] =peep =rawr] - ^- (quip move _state) - ?: =(0 siz.rawr) - ?> =(0 dat.rawr) - (process-response path.peep ~) - ?. (~(has by part) path.peep) - :: we did not initiate this request, or it's been cancelled - :: - !! - =/ partial (~(got by part) path.peep) - =. partial - ?: (~(has by fragments.partial) num.peep) - ~& [%fine %duplicate-response peep] ::TODO disable - ::TODO what if non-equal? - partial - =, partial - :+ ~| [%fine %response-size-changed have=num-fragments new=siz.rawr] - ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) - num-fragments - +(num-received) - (~(put by fragments) num.peep [wid dat]:rawr) - :: - ?: =(num-fragments num-received):partial - :: we have all the parts now, construct the full response - :: - =/ =roar (decode-response-msg partial) - ::TODO check signature - (process-response path.peep `dat.roar) - :: otherwise, store the part, and send out the next request - :: - =. part (~(put by part) path.peep partial) - =/ next-num=@ud - =/ next=@ud +(num.peep) - :: we should receive responses in order, but in case we don't... - :: - |- - ?. (~(has by fragments.partial) next) next - $(next +((mod next num-fragments.partial))) - :: - =/ =hoot (encode-request path.peep next-num) - ::TODO ask amsden, should we shotgun? we can tweak this - :: for now (mvp) though, stay 1-to-1 - ::TODO update lane in ames state - ::TODO is reusing the lane fine? - [[urth %give %hoot lane hoot]~ state] - :: - ++ get-scry-result - |= [=gang =path] - ^- (unit (cask)) - ?~ nom=(de-omen path) ~ - ?> =(our p.bem.u.nom) - :: we only support scrying into clay, - :: and only if the data is fully public. - :: - ?. =(%c (end 3 (snag 0 path))) ~ - =+ pem=(rof gang (need (de-omen %cp (slag 1 path)))) - ?> ?=(^ pem) - ?> ?=(^ u.pem) - =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) - ?> =([%black ~ ~] rul.r.per) - =+ res=(rof gang u.nom) - ~! res - ?- res - ~ !! ::REVIEW crashing in the blocking case is fine.. right? - [~ ~] ~ - [~ ~ *] `[p q.q]:u.u.res - == - -- -^? -|% -:: +call: handle a +task:fine request -:: -++ call - ~% %fine-call ..part ~ - |= $: hen=duct - dud=(unit goof) - wrapped-task=(hobo task) - == - ^- [(list move) _fine-gate] - :: - =/ =task ((harden task) wrapped-task) - :: - ?^ dud - ~|(%fine-call-dud (mean -.task tang.u.dud)) - :: - =^ moves state - ?- -.task - %keen - ^- (quip move _state) - =/ omen - ~| [%fine %invalid-namespace-path path.task] - (need (de-omen path.task)) - =. want (~(put ju want) path.task hen) - ?: (~(has by part) path.task) - :: request is already ongoing - :: - [~ state] - :: kick off the request - :: - =. part (~(put by part) path.task *partial) - =/ =lane:ames (get-lane p.bem.omen) - =/ =hoot (encode-request path.task 1) - [[urth %give %hoot lane hoot]~ state] - :: - %yawn - [~ state(want (~(del ju want) path.task hen))] - :: - %purr - ^- (quip move _state) - =/ =packet:ames (decode-packet `@ux`purr.task) - =/ resp=? =(& (cut 0 [2 1] purr.task)) - ?. resp - ::TODO crash instead, scry/peek should be used for this - =/ =twit (decode-request `@ux`content.packet) - ::TODO verify request signature - [(handle-request hen twit) state] - =/ [=peep =purr] (decode-request-info `@ux`content.packet) - =/ =rawr (decode-response-packet purr) - ::TODO validate response signature - (handle-response [from lane]:task peep rawr) - :: - %bide - [~ state(hear (~(put ju hear) path.task hen))] - :: - %born - ^- (quip move _state) - ::REVIEW assuming hear is for runtime use only? - [~ state(hear ~, urth hen)] - :: - %trim - [~ state] ::TODO maybe clear part? - :: - %vega - [~ state] - == - [~ fine-gate] -:: +load: migrate an old state to a new fine version -:: -++ load - |= old=fine-state - ^+ fine-gate - fine-gate(state old) -:: +scry: get packets -:: -:: /fx/message/[full-scry-path] song all packets for some scry path -:: -++ scry - ^- roon - |= [lyc=gang car=term bem=beam] - ^- (unit (unit cage)) - ::TODO don't special-case whey scry - :: - ?: &(=(car %$) =(s.bem /whey)) - =/ maz=(list mass) - :~ state+&+state - == - ``mass+!>(maz) - :: only respond for the local identity, %$ desk, current timestamp - :: - ?. ?& =(our p.bem) - =(%$ q.bem) - =([%da now] r.bem) - == - ~ - :: - ?. ?=(%x car) ~ - ?. ?=([%message @ *] s.bem) ~ - :: t.s.bem is expected to be a scry path of the shape /vc/desk/rev/etc, - :: so we need to give it the right shape - :: - =/ pax=path - [i.t.s.bem (scot %p our) t.t.s.bem] - ``noun+!>((encode-response pax (get-scry-result lyc pax))) -:: -++ stay state -++ take - |= [tea=wire hen=duct dud=(unit goof) hin=sign] - ^- [(list move) _fine-gate] - ?^ dud - ~|(%fine-take-dud (mean tang.u.dud)) - :: - ::TODO - [~ fine-gate] --- From 64ab395fd0fd2eac0b0b50024337a0e4d8e2fa30 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 27 Jan 2022 14:57:15 -0600 Subject: [PATCH 027/168] ames: cache scry packets --- pkg/urbit/vere/io/ames.c | 117 ++++++++++++++------------------------- 1 file changed, 43 insertions(+), 74 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 7fa90108d..b4ab3aa75 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -630,7 +630,7 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) sam_u->fig_u.net_o = c3y; } - _ames_pend_free(pen_u); + //_ames_pend_free(pen_u); } #define _fine_send _ames_send @@ -669,7 +669,7 @@ _ames_send(u3_pend* pen_u) sam_u->fig_u.net_o = c3n; } - _ames_pend_free(pen_u); + //_ames_pend_free(pen_u); } } } @@ -1359,18 +1359,8 @@ _ames_skip(u3_body* bod_u) { } #endif -/* _fine_pack_scry_cb(): receive all packets for datum out of fine - * TODO: implement - */ -static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) +static void _fine_got_pack(u3_pend* pen_u, u3_noun pac) { - - u3_pend* pen_u = vod_p; - u3_weak pac = u3r_at(7, nun); - if(pac == u3_none) { - u3l_log("no result, bailing\n"); - return; - } u3_noun num = u3i_word(pen_u->fra_w - 1); u3_noun fra = u3dc("snag", num, pac); @@ -1404,6 +1394,32 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) */ } +/* _fine_pack_scry_cb(): receive all packets for datum out of fine + * TODO: implement + */ +static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) +{ + u3l_log("got scry result\n"); + + u3_pend* pen_u = vod_p; + u3_ames* sam_u = pen_u->sam_u; + u3_weak pac = u3r_at(7, nun); + if(pac == u3_none) { + u3l_log("no result, bailing\n"); + return; + } + c3_assert( 1 == pen_u->typ_y); + u3_noun pax = u3i_string(pen_u->req_u->req_u.pat_c); + u3l_log("path: %s\n", pen_u->req_u->req_u.pat_c); + u3l_log("made pax\n"); + + u3h_put(sam_u->fin_s.sac_p, u3k(pax), u3k(pac)); + u3l_log("got scry result\n"); + + _fine_got_pack(pen_u, u3k(pac)); +} + + static void _fine_hear_response(u3_ames* sam_u, u3_lane lan_u, @@ -1437,12 +1453,6 @@ static void _fine_hear_request(u3_ames* sam_u, c3_assert ( c3n == _ames_sift_head(&hed_u, hun_y)); // TODO: check mug - // lookup in cache - // (unit (unit (unit packet)) - // ~ -> miss - // [~ ~] -> hit, unbound - // [~ ~ ~] -> hit, empty - // [~ ~ ~ *] -> hit, w/ data u3_requ req_u; // skip past header @@ -1454,72 +1464,31 @@ static void _fine_hear_request(u3_ames* sam_u, u3_noun pat = u3i_string(req_u.pat_c); // TODO: revive - u3_weak cac = u3_none; // u3h_git(sam_u->fin_s.sac_p, pat); + u3_weak cac = u3h_git(sam_u->fin_s.sac_p, pat); + u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + + pen_u->sam_u = sam_u; + pen_u->typ_y = 1; + pen_u->req_u = rep_u; + + memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); + memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); + + memcpy(&pen_u->lan_u, &lan_u, sizeof(u3_lane)); + pen_u->fra_w = req_u.fra_w; if ( u3_none == cac ) { // cache miss u3_noun pax = u3nc(u3i_string("message"), u3do("stab", u3k(pat))); - u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); - u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); - - pen_u->sam_u = sam_u; - pen_u->typ_y = 2; - pen_u->req_u = rep_u; - - memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); - memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); - - memcpy(&pen_u->lan_u, &lan_u, sizeof(u3_lane)); - pen_u->fra_w = req_u.fra_w; - u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, pax, pen_u, _fine_pack_scry_cb); - } else if(u3_nul == cac) { - // cache hit, unbound - // do nothing, maybe report? } else { - // shape - // - c3_w fra_w; - c3_y* fra_y; - - { - u3_noun fra = u3dc("snag", u3i_word(req_u.fra_w), u3t(cac)); - - fra_w = u3r_met(3, fra); - fra_y = c3_calloc(fra_w); - - u3r_bytes(0, fra_w, fra_y, fra); - - u3z(fra); - } - - u3_resp* res_u = c3_calloc(sizeof(*res_u)); - - if ( c3n == _fine_sift_resp(&hed_u, res_u, fra_w, fra_y) ) { - c3_free(res_u); - } else { - memcpy(&res_u->pre_u, &req_u.pre_u, sizeof(u3_prel)); - - c3_y* res_y; - c3_w res_w = _fine_etch_resp(&hed_u, res_u, &res_y); - - u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); - pen_u->typ_y = 2; - pen_u->res_u = res_u; - pen_u->len_w = res_w; - pen_u->hun_y = res_y; - pen_u->her_d[0] = res_u->pre_u.sen_d[0]; - pen_u->her_d[1] = res_u->pre_u.sen_d[1]; - pen_u->lan_u = lan_u; - pen_u->sam_u = sam_u; - - _fine_send(pen_u); - } + _fine_got_pack(pen_u, u3k(cac)); } u3z(pat); From d5040e7eae93acd2612c8cfdc2a64f9ba116daeb Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 27 Jan 2022 15:36:40 -0600 Subject: [PATCH 028/168] fine: correctly decode lane for the non-galaxy case --- pkg/urbit/vere/io/ames.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index b4ab3aa75..382ce0df8 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -1531,7 +1531,7 @@ static void _log_head(u3_head* hed_u) static void _fine_request(u3_ames* sam_u, - u3_lane lan_u, + u3_noun lan, u3_noun req) { @@ -1555,12 +1555,25 @@ _fine_request(u3_ames* sam_u, pen_u->typ_y = 1; pen_u->her_d[0] = req_u->pre_u.rec_d[0]; pen_u->her_d[1] = req_u->pre_u.rec_d[1]; - pen_u->lan_u.pip_w = lan_u.pip_w; - pen_u->lan_u.por_s = lan_u.por_s; - pen_u->sam_u = sam_u; - // TODO: revive for non-galaxy case - _ames_czar(pen_u); + + { + u3_noun tag, val; + u3x_cell(lan, &tag, &val); + u3m_p("tag", tag); + u3m_p("val", val); + if(tag == 0) { + _ames_czar(pen_u); + } else { + u3_lane lan_u = u3_ames_decode_lane(val); + pen_u->lan_u.pip_w = lan_u.pip_w; + u3l_log("IP: %u", lan_u.pip_w); + u3l_log("port: %u", lan_u.por_s); + pen_u->lan_u.por_s = lan_u.por_s; + + _ames_send(pen_u); + } + } } /* _ames_hear(): parse a (potential) packet, dispatch appropriately. @@ -1840,8 +1853,7 @@ static c3_o _fine_io_kick(u3_auto* car_u, u3_noun wir, u3_noun nun) { } else if(c3__hoot == hed) { u3_noun lan, hot; u3x_cell(u3t(nun), &lan, &hot); - u3_lane lan_u = u3_ames_decode_lane(lan); - _fine_request(sam_u, lan_u, hot); + _fine_request(sam_u, lan, hot); return c3y; } else { return c3n; From 769d10fdd4ab76702b028c1febec31feeef25645 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 28 Jan 2022 14:30:59 +0100 Subject: [PATCH 029/168] fine: use keys from ames state instead of jael --- pkg/arvo/sys/vane/ames.hoon | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index ade806d30..cd9107092 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -3373,29 +3373,27 @@ |= [=path mess=*] (sign (shax (jam [our life path mess]))) :: - ++ life ~+ (jael ^life %life /(scot %p our)) - ++ ring ~+ (jael ^ring %vein /(scot %ud life)) - ++ sign sign:as:(nol:nu:crub:crypto ring) - :: - ++ jael - |* [=mold =desk =path] - !< mold - %- tail %- need %- need - (rof `[our ~ ~] [%jael %$] [our desk da+now] path) + ++ life life.ames-state + ++ sign sign:as:crypto-core.ames-state :: + ::TODO for the unknown case, should use the alien-agenda ++ lyfe |= who=ship - (jael (unit ^life) %lyfe /(scot %p our)) + ^- ^life + ~| [%fine %unknown-peer who] + =/ ship-state (~(got by peers.ames-state) who) + ?> ?=([%known *] ship-state) + life.ship-state :: - ::TODO don't scry! subscribe & get from state instead - ::TODO literally copy the ames code lol - ::TODO the fact that we share pki and lane data with ames is... suspect - :: also the en/decoding etc + ::TODO for the unknown case, should use the alien-agenda ++ pass |= [who=ship lyf=^life] - ::TODO but might fail need checks? - :: (jael * %deed ) - !! + ~| [%fine %unknown-peer who lyf] + =/ ship-state (~(got by peers.ames-state) who) + ?> ?=([%known *] ship-state) + ~| [%fine %life-mismatch who lyf] + ?> =(lyf life.ship-state) + public-key.ship-state -- :: ++ get-lane From 10e617d4abe0ce285e05161d3e2d9208378791e8 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 28 Jan 2022 14:09:42 -0600 Subject: [PATCH 030/168] fine: prevent null ptr deref in _ames_pend_free --- pkg/urbit/vere/io/ames.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 382ce0df8..249aad54d 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -184,16 +184,18 @@ static void _ames_pend_free(u3_pend* pen_u) { if ( 0 == pen_u->typ_y ) { // ames packet - _ames_pact_free(pen_u->pac_u); + if( pen_u->pac_u ) { + _ames_pact_free(pen_u->pac_u); + } } else if ( 1 == pen_u->typ_y ) { // fine request c3_free(pen_u->req_u); - c3_free(pen_u->hun_y); } else { // fine response c3_free(pen_u->res_u); - c3_free(pen_u->hun_y); } c3_free(pen_u->dns_c); + c3_free(pen_u->hun_y); + c3_free(pen_u); } @@ -597,7 +599,7 @@ _ames_etch_pack(u3_head* hed_u, c3_y rog_y = ( c3y == hed_u->rel_o ) ? 6 : 0; // origin len c3_w bod_w = rog_y + 1 + sen_y + rec_y + bod_u->con_s; // body len c3_w len_w = 4 + bod_w; // packet len - c3_y* pac_y = c3_malloc(len_w); // output buf + c3_y* pac_y = c3_calloc(len_w); // output buf c3_y* bod_y = pac_y + 4; // body cursor // serialize the head @@ -630,7 +632,7 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) sam_u->fig_u.net_o = c3y; } - //_ames_pend_free(pen_u); + _ames_pend_free(pen_u); } #define _fine_send _ames_send @@ -669,7 +671,7 @@ _ames_send(u3_pend* pen_u) sam_u->fig_u.net_o = c3n; } - //_ames_pend_free(pen_u); + _ames_pend_free(pen_u); } } } @@ -1560,17 +1562,12 @@ _fine_request(u3_ames* sam_u, { u3_noun tag, val; u3x_cell(lan, &tag, &val); - u3m_p("tag", tag); - u3m_p("val", val); if(tag == 0) { _ames_czar(pen_u); } else { u3_lane lan_u = u3_ames_decode_lane(val); pen_u->lan_u.pip_w = lan_u.pip_w; - u3l_log("IP: %u", lan_u.pip_w); - u3l_log("port: %u", lan_u.por_s); pen_u->lan_u.por_s = lan_u.por_s; - _ames_send(pen_u); } } From 3ec30d3e5755ac803aa26b465e284e7dbf9ae260 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 28 Jan 2022 15:18:14 -0600 Subject: [PATCH 031/168] ames: revamp scry cache Update scry cache to be a map of [path num] -> fragment --- pkg/urbit/vere/io/ames.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 249aad54d..da7699d28 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -1361,12 +1361,8 @@ _ames_skip(u3_body* bod_u) { } #endif -static void _fine_got_pack(u3_pend* pen_u, u3_noun pac) +static void _fine_got_pack(u3_pend* pen_u, u3_noun fra) { - u3_noun num = u3i_word(pen_u->fra_w - 1); - - u3_noun fra = u3dc("snag", num, pac); - pen_u->len_w = u3r_met(3, fra); pen_u->hun_y = c3_calloc(pen_u->len_w); @@ -1411,14 +1407,24 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) return; } c3_assert( 1 == pen_u->typ_y); + u3_weak fra = u3_none; u3_noun pax = u3i_string(pen_u->req_u->req_u.pat_c); - u3l_log("path: %s\n", pen_u->req_u->req_u.pat_c); - u3l_log("made pax\n"); - - u3h_put(sam_u->fin_s.sac_p, u3k(pax), u3k(pac)); - u3l_log("got scry result\n"); - - _fine_got_pack(pen_u, u3k(pac)); + u3l_log("made string\n"); + c3_w cur_w = 1; + u3_noun lis = u3k(pac); + while(pac != u3_nul) { + u3h_put(sam_u->fin_s.sac_p, u3nc(u3k(pax), u3i_word(cur_w)), u3h(pac)); + if ( pen_u->fra_w == cur_w ) { + fra = u3k(u3h(pac)); + } + cur_w++; + pac = u3t(pac); + } + if ( fra == u3_none ) { + u3l_log("fragment number out of range\n"); + } else { + _fine_got_pack(pen_u, fra); + } } @@ -1464,9 +1470,10 @@ static void _fine_hear_request(u3_ames* sam_u, c3_assert( c3y == _fine_sift_requ(&hed_u, &req_u, len_w, hun_y)); u3_noun pat = u3i_string(req_u.pat_c); + u3_noun key = u3nc(u3k(pat), u3i_word(req_u.fra_w)); // TODO: revive - u3_weak cac = u3h_git(sam_u->fin_s.sac_p, pat); + u3_weak cac = u3h_git(sam_u->fin_s.sac_p, key); u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); From 709dd75d7438e88b64c73d6442c05f4ea65e4617 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 28 Jan 2022 23:09:50 +0100 Subject: [PATCH 032/168] fine: track pending requests for unknown peers --- pkg/arvo/sys/lull.hoon | 1 + pkg/arvo/sys/vane/ames.hoon | 65 ++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 5f1519e0f..27e5016c6 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -511,6 +511,7 @@ $: messages=(list [=duct =plea]) packets=(set =blob) heeds=(set duct) + keens=(set path) == :: $peer-state: state for a peer with known life and keys :: diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index cd9107092..0222d5f1e 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -582,12 +582,21 @@ =fine-state == +$ ames-state-5 - $: peers=(map ship ship-state) + $: peers=(map ship ship-state-5) =unix=duct =life crypto-core=acru:ames =bug == ++$ ship-state-5 + $% [%alien alien-agenda-5] + [%known peer-state] + == ++$ alien-agenda-5 + $: messages=(list [=duct =plea]) + packets=(set =blob) + heeds=(set duct) + == :: $fine-state: remote scry subsystem state :: :: hear: awaiting existence @@ -1003,14 +1012,23 @@ ++ state-5-to-6 |= old=ames-state-5 ^- ^ames-state - old(bug [bug.old *fine-state]) + %= old + peers (~(run by peers.old) ship-state-5-to-6) + bug [bug.old *fine-state] + == + :: + ++ ship-state-5-to-6 + |= old=ship-state-5 + ^- ship-state + ?. ?=(%alien -.old) old + old(heeds [heeds.old ~]) :: ++ state-4-to-5 |= ames-state=ames-state-5 ^- ames-state-5 =. peers.ames-state %- ~(run by peers.ames-state) - |= =ship-state + |= ship-state=ship-state-5 ?. ?=(%known -.ship-state) ship-state =. snd.ship-state @@ -1728,6 +1746,16 @@ %+ roll ~(tap in packets.todos) |= [=blob core=_event-core] (send-blob:core | ship blob) + :: apply remote scry requests + :: + =^ moz=(list move) ames-state + %+ roll ~(tap in keens.todos) + |= [=path moz=(list move) =_ames-state] + =^ mos ames-state + %. [ship path 1] + send-request:(fine now rof original-duct ames-state) + [(weld moz mos) ames-state] + =. moves (weld (flop moz) moves) :: event-core(duct original-duct) -- @@ -3234,18 +3262,25 @@ =/ omen ~| [%fine %invalid-namespace-path path] (need (de-omen path)) + =* ship p.bem.omen =. want.state (~(put ju want.state) path duct) ?: (~(has by part.state) path) :: request is already ongoing :: [~ ames-state] - :: kick off the request - :: =. part.state (~(put by part.state) path *partial-fine) - :_ ames-state - =/ =lane:ames (get-lane p.bem.omen) - =/ =hoot (encode-request path 1) - [unix-duct.ames-state %give %send lane `@ux`hoot]~ + :: if we don't know the target yet, store the request for later + :: + =/ peer (~(get by peers.ames-state) ship) + ?. ?=([~ %known *] peer) + ::TODO full enqueue-alien-todo + =. peers.ames-state + %+ ~(put by peers.ames-state) ship + ?~ peer [%alien %*(. *alien-agenda keens [path ~ ~])] + ?> ?=(%alien -.u.peer) + u.peer(keens (~(put in keens.u.peer) path)) + [~ ames-state] + (send-request p.bem.omen path 1) :: ++ on-yawn |= =path @@ -3451,6 +3486,18 @@ ~| [%fine %response-not-cask] ;;((cask) (cue (rsh 3^64 mess))) :: + ++ send-request + |= [=ship =path num=@ud] + ^- (quip move _ames-state) + :_ ames-state + :: make sure we exclude the ship from the path proper, + :: since it already gets included in the request header + :: + =. path (oust [1 1] path) + =/ =lane:ames (get-lane ship) + =/ =hoot (encode-request ship path 1) + [unix-duct.ames-state %give %send lane `@ux`hoot]~ + :: ++ process-response |= [=path data=(unit (cask))] ^- (quip move _ames-state) From fb72b7df7d0b504d424ee59fab133aa02ae2af98 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 28 Jan 2022 23:10:50 +0100 Subject: [PATCH 033/168] fine: set receiver life in request packet --- pkg/arvo/sys/vane/ames.hoon | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 0222d5f1e..9d9869fa4 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -3338,7 +3338,7 @@ :: ++ request-body |= [=path num=@ud] - ::TODO need to ensure valid namespace path without ship + ::NOTE path is expected to be a namespace path without the ship ^- byts ?> (lth num (bex 32)) =+ (spit path) @@ -3350,12 +3350,14 @@ == :: ++ encode-request - |= [=path num=@ud] + |= [=ship =path num=@ud] + ::NOTE path is expected to be a namespace path without the ship ^- hoot ^- @ =+ bod=(request-body path num) =+ syn=(can 3 64^(sign:keys dat.bod) bod ~) %+ con 0b100 ::NOTE request bit - (encode-packet | [our ~zod] (mod life:keys 16) 0b0 ~ syn) + %+ encode-packet | + [[our ship] (mod life:keys 16) (mod (lyfe:keys ship) 16) ~ syn] :: ++ encode-response ::TODO unit tests |= [=path data=(unit (cask))] @@ -3555,7 +3557,7 @@ ?. (~(has by fragments.partial) next) next $(next +((mod next num-fragments.partial))) :: - =/ =hoot (encode-request path.peep next-num) + =/ =hoot (encode-request from path.peep next-num) ::TODO ask amsden, should we shotgun? we can tweak this :: for now (mvp) though, stay 1-to-1 ::TODO update lane in ames state From b42dc477c5fe341f3bbb45c8626fe78d9b804dd6 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 28 Jan 2022 23:54:01 +0100 Subject: [PATCH 034/168] fine: move into per-event core This is an obviously more ergonomic factoring. --- pkg/arvo/sys/vane/ames.hoon | 700 +++++++++++++++++------------------- 1 file changed, 336 insertions(+), 364 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 9d9869fa4..28ec050c2 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -932,24 +932,15 @@ =/ event-core (per-event [now eny rof] duct ames-state) :: =^ moves ames-state + =< abet :: handle error notifications :: ?^ dud - =< abet ?+ -.task (on-crud:event-core -.task tang.u.dud) %hear (on-hear:event-core lane.task blob.task dud) == :: - ?: ?=(?(%keen %yawn %bide) -.task) - =/ fine-core (fine now rof duct ames-state) - ?- -.task - %keen (on-keen:fine-core +.task) - %yawn (on-yawn:fine-core +.task) - %bide (on-bide:fine-core +.task) - == - :: - =< abet ?- -.task %born on-born:event-core %hear (on-hear:event-core [lane blob ~]:task) @@ -962,6 +953,10 @@ %trim on-trim:event-core %vega on-vega:event-core %plea (on-plea:event-core [ship plea]:task) + :: + %keen (on-keen:fine:event-core +.task) + %yawn (on-yawn:fine:event-core +.task) + %bide (on-bide:fine:event-core +.task) == :: [moves ames-gate] @@ -1154,14 +1149,30 @@ ``noun+!>(!>(res)) :: [%fine %message @ *] + ::TODO separate endpoint for the full message (instead of packet list) :: t.t.tyl is expected to be a scry path of the shape /vc/desk/rev/etc, :: so we need to give it the right shape :: - =/ pax=path + =/ =path [i.t.t.tyl (scot %p our) t.t.t.tyl] - =/ fin - (fine now rof *duct ames-state) - ``noun+!>((encode-response:fin pax (get-scry-result:fin lyc pax))) + ?~ nom=(de-omen path) ~ + :: we only support scrying into clay, + :: and only if the data is fully public. + :: + ?. =(%c (end 3 (snag 0 path))) ~ + =+ pem=(rof lyc (need (de-omen %cp (slag 1 path)))) + ?> ?=(^ pem) + ?> ?=(^ u.pem) + =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) + ?> =([%black ~ ~] rul.r.per) + =+ res=(rof lyc u.nom) + ::TODO suggests we need to factor differently + =+ ven=(per-event [now 0v0 rof] *duct ames-state) + ?- res + ~ ~ + [~ ~] ``noun+!>((encode-response:fine:ven path ~)) + [~ ~ *] ``noun+!>((encode-response:fine:ven path `[p q.q]:u.u.res)) + == == -- :: |per-event: inner event-handling core @@ -1178,6 +1189,7 @@ ++ event-core . ++ abet [(flop moves) ames-state] ++ emit |=(=move event-core(moves [move moves])) + ++ emil |=(mos=(list move) event-core(moves (weld (flop mos) moves))) ++ channel-state [life crypto-core bug]:ames-state ++ trace |= [verb=? =ship print=(trap tape)] @@ -1325,18 +1337,14 @@ :: ++ on-hear |= [l=lane b=blob d=(unit goof)] + ^+ event-core =/ [ames=? =packet] (decode-packet b) ?: ames (on-hear-packet l packet d) - :: - =^ moz ames-state - %- on-hear-response:(fine now rof duct ames-state) - ~| [%fine %request-events-forbidden] - ?> response==(& (cut 0 [2 1] b)) - [l packet d] - =. moves (weld (flop moz) moves) - ..on-hear + ?. response==(& (cut 0 [2 1] b)) + ~|([%fine %request-events-forbidden] !!) + (on-hear-response:fine l packet d) :: +on-hear-packet: handle mildly processed packet receipt :: ++ on-hear-packet @@ -1748,14 +1756,10 @@ (send-blob:core | ship blob) :: apply remote scry requests :: - =^ moz=(list move) ames-state + =. event-core %+ roll ~(tap in keens.todos) - |= [=path moz=(list move) =_ames-state] - =^ mos ames-state - %. [ship path 1] - send-request:(fine now rof original-duct ames-state) - [(weld moz mos) ames-state] - =. moves (weld (flop moz) moves) + |= [=path core=_event-core] + (send-request:fine:core ship path 1) :: event-core(duct original-duct) -- @@ -2411,6 +2415,309 @@ (run-message-pump nack-trace-bone %memo message-blob) -- -- + :: + ++ fine + =* state fine-state.ames-state + =< |% + ++ on-keen + |= =path + ^+ event-core + =/ omen + ~| [%fine %invalid-namespace-path path] + (need (de-omen path)) + =* ship p.bem.omen + =. want.state (~(put ju want.state) path duct) + ?: (~(has by part.state) path) + :: request is already ongoing + :: + event-core + =. part.state (~(put by part.state) path *partial-fine) + :: if we don't know the target yet, store the request for later + :: + =/ peer (~(get by peers.ames-state) ship) + ?: ?=([~ %known *] peer) + (send-request p.bem.omen path 1) + %+ enqueue-alien-todo ship + |= todos=alien-agenda + todos(keens (~(put in keens.todos) path)) + :: + ++ on-yawn + |= =path + ^+ event-core + =. want.state (~(del ju want.state) path duct) + event-core + :: + ++ on-bide + |= =path + ^+ event-core + =. hear.state (~(put ju hear.state) path duct) + event-core + :: + ++ on-hear-response + |= [=lane =packet dud=(unit goof)] + ^+ event-core + ?^ dud + ::TODO handle + ~& [%fine %done-goofed u.dud] + event-core + =/ [=peep =purr] (decode-request-info `@ux`content.packet) + =/ =rawr (decode-response-packet purr) + ::TODO validate we are the right life? at laest for request case + ::TODO validate response signature + (handle-response [sndr.packet lane] peep rawr) + -- + |% + +$ twit :: signed request + $: signature=@ + peep + == + :: + +$ peep :: request data + $: =path + num=@ud + == + :: + +$ rawr :: response packet ::TODO meow + $: sig=@ + siz=@ud + byts + == + :: + +$ roar :: response message + $: sig=@ + dat=(cask) + == + :: + ++ spit + |= =path + ^- [pat=@t wid=@ud] + =+ pat=(spat path) + =+ wid=(met 3 pat) + ?> (lte wid 384) ::TODO check when we handle %keen, in addition to here + [pat wid] + :: + ++ request-body + |= [=path num=@ud] + ::NOTE path is expected to be a namespace path without the ship + ^- byts + ?> (lth num (bex 32)) + =+ (spit path) + :- :(add 32 16 wid) + %+ can 3 + :~ 4^num :: fragment number + 2^wid :: path size + wid^`@`pat :: namespace path + == + :: + ++ encode-request + |= [=ship =path num=@ud] + ::NOTE path is expected to be a namespace path without the ship + ^- hoot ^- @ + =+ bod=(request-body path num) + =+ syn=(can 3 64^(sign:keys dat.bod) bod ~) + %+ con 0b100 ::NOTE request bit + %+ encode-packet | + [[our ship] (mod life:keys 16) (mod (lyfe:keys ship) 16) ~ syn] + :: + ++ encode-response ::TODO unit tests + |= [=path data=(unit (cask))] + ^- song + :: prepend request descriptions to each response packet + :: + =; pacs=(list @ux) + %- head + %^ spin pacs 1 + |= [pac=@ux num=@ud] + ^- [purr _num] + :_ +(num) + ^- @ux + ::NOTE we stub out the receiver & origin details, + :: runtime should replace them as appropriate. + ::TODO should have scry endpoint that produces gate that does + :: that packet transformation, just to set a spec + (encode-packet | [our ~zod] (mod life:keys 16) 0b0 ~ pac) + :: prepend a signature and split the data into 1024-byte fragments + :: + =/ frag=(list @) + ::TODO should also sign the request path + =/ sig=@ (full:keys path (fall data ~)) + ?~ data [sig]~ + %+ rip 13 ::NOTE 1024 bytes + (cat 3 sig (jam u.data)) ::TODO should include life + :: sign & packetize the fragments + :: + %- head + %^ spin frag 1 + |= [dat=@ num=@ud] + :_ +(num) + ^- @ux + =/ req=byts (request-body path num) + =/ bod=byts + =/ wid=@ud (met 3 dat) + :- :(add 4 2 wid) + %+ can 3 + :~ 4^(lent frag) :: number of fragments + 2^wid :: response data fragment size in bytes + wid^dat :: response data fragment + == + =/ sig=byts + 64^(sign:keys (can 3 req bod ~)) + (can 3 req sig bod ~) + :: + ++ keys + |% + ++ full + |= [=path mess=*] + (sign (shax (jam [our life path mess]))) + :: + ++ life life.ames-state + ++ sign sign:as:crypto-core.ames-state + :: + ::TODO for the unknown case, should use the alien-agenda + ++ lyfe + |= who=ship + ^- ^life + ~| [%fine %unknown-peer who] + =/ ship-state (~(got by peers.ames-state) who) + ?> ?=([%known *] ship-state) + life.ship-state + :: + ::TODO for the unknown case, should use the alien-agenda + ++ pass + |= [who=ship lyf=^life] + ~| [%fine %unknown-peer who lyf] + =/ ship-state (~(got by peers.ames-state) who) + ?> ?=([%known *] ship-state) + ~| [%fine %life-mismatch who lyf] + ?> =(lyf life.ship-state) + public-key.ship-state + -- + :: + ++ get-lane + |= =ship + ^- lane:ames + =; lanes + ::TODO should we send to all lanes? + ?^ lanes i.lanes + ~&(%fine-lane-stub &+~zod) ::TODO + !< (list lane:ames) + =< q %- need %- need + =/ =path /peers/(scot %p ship)/forward-lane + ::TODO get from state + (rof `[our ~ ~] [%ames %x] [our %$ da+now] path) + :: + ++ decode-request + |= =hoot + ^- twit + :- sig=(cut 3 [0 64] hoot) + -:(decode-request-info (rsh 3^64 hoot)) + :: + ++ decode-request-info + |= =hoot + ^- [=peep =purr] + =+ num=(cut 3 [0 4] hoot) + =+ len=(cut 3 [4 2] hoot) + =+ pat=(cut 3 [6 len] hoot) + :- [(stab pat) num] + :: if there is data remaining, it's the response + (rsh [3 (add 6 len)] hoot) + :: + ++ decode-response-packet + |= =purr + =; =rawr + ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] + rawr + :* sig=(cut 3 [0 64] purr) + siz=(cut 3 [64 4] purr) + wid=(cut 3 [68 2] purr) + dat=(rsh 3^70 purr) + == + :: + ++ verify-response-packet + |= rawr + !! + :: + ++ decode-response-msg + |= partial-fine ::TODO maybe take @ instead + ^- roar + =/ mess=@ + %+ can 3 ::TODO just (rep 13 -) + %+ turn (gulf 1 num-fragments) + ~(got by fragments) + :- sig=(cut 3 [0 64] mess) + ~| [%fine %response-not-cask] + ;;((cask) (cue (rsh 3^64 mess))) + :: + ++ send-request + |= [=ship =path num=@ud] + ^+ event-core + :: make sure we exclude the ship from the path proper, + :: since it already gets included in the request header + :: + =. path (oust [1 1] path) + =/ =lane:ames (get-lane ship) + =/ =hoot (encode-request ship path 1) + %- emit + [unix-duct.ames-state %give %send lane `@ux`hoot] + :: + ++ process-response + |= [=path data=(unit (cask))] + ^+ event-core + =. event-core + %- emil + %+ turn ~(tap in (~(get ju want.state) path)) + (late [%give %tune path data]) + =. want.state (~(del by want.state) path) + =. part.state (~(del by part.state) path) + event-core + :: + ++ handle-response + |= [[from=ship =lane:ames] =peep =rawr] + ^+ event-core + ?: =(0 siz.rawr) + ?> =(~ dat.rawr) + (process-response path.peep ~) + ?. (~(has by part.state) path.peep) + :: we did not initiate this request, or it's been cancelled + :: + !! + =/ partial=partial-fine + (~(got by part.state) path.peep) + =. partial + ?: (~(has by fragments.partial) num.peep) + partial + =, partial + :+ ~| [%fine %response-size-changed have=num-fragments new=siz.rawr] + ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) + num-fragments + +(num-received) + (~(put by fragments) num.peep [wid dat]:rawr) + :: + ?: =(num-fragments num-received):partial + :: we have all the parts now, construct the full response + :: + =/ =roar (decode-response-msg partial) + ::TODO check signature + (process-response path.peep `dat.roar) + :: otherwise, store the part, and send out the next request + :: + =. part.state (~(put by part.state) path.peep partial) + =/ next-num=@ud + =/ next=@ud +(num.peep) + :: we should receive responses in order, but in case we don't... + :: + |- + ?. (~(has by fragments.partial) next) next + $(next +((mod next num-fragments.partial))) + :: + =/ =hoot (encode-request from path.peep next-num) + ::TODO ask amsden, should we shotgun? we can tweak this + :: for now (mvp) though, stay 1-to-1 + ::TODO update lane in ames state + ::TODO is reusing the lane fine? + %- emit + [unix-duct.ames-state %give %send lane `@ux`hoot] + -- -- :: +make-message-pump: constructor for |message-pump :: @@ -3251,339 +3558,4 @@ :: message-sink -- -:: -++ fine - |= [now=@da rof=roof =duct =ames-state] - =* state fine-state.ames-state - =< |% - ++ on-keen - |= =path - ^- (quip move _ames-state) - =/ omen - ~| [%fine %invalid-namespace-path path] - (need (de-omen path)) - =* ship p.bem.omen - =. want.state (~(put ju want.state) path duct) - ?: (~(has by part.state) path) - :: request is already ongoing - :: - [~ ames-state] - =. part.state (~(put by part.state) path *partial-fine) - :: if we don't know the target yet, store the request for later - :: - =/ peer (~(get by peers.ames-state) ship) - ?. ?=([~ %known *] peer) - ::TODO full enqueue-alien-todo - =. peers.ames-state - %+ ~(put by peers.ames-state) ship - ?~ peer [%alien %*(. *alien-agenda keens [path ~ ~])] - ?> ?=(%alien -.u.peer) - u.peer(keens (~(put in keens.u.peer) path)) - [~ ames-state] - (send-request p.bem.omen path 1) - :: - ++ on-yawn - |= =path - ^- (quip move _ames-state) - =. want.state (~(del ju want.state) path duct) - [~ ames-state] - :: - ++ on-bide - |= =path - ^- (quip move _ames-state) - =. hear.state (~(put ju hear.state) path duct) - [~ ames-state] - :: - ++ on-hear-response - |= [=lane =packet dud=(unit goof)] - ^- (quip move _ames-state) - ?^ dud - ::TODO handle - ~& [%fine %done-goofed u.dud] - [~ ames-state] - =/ [=peep =purr] (decode-request-info `@ux`content.packet) - =/ =rawr (decode-response-packet purr) - ::TODO validate response signature - (handle-response [sndr.packet lane] peep rawr) - -- - |% - +$ twit :: signed request - $: signature=@ - peep - == - :: - +$ peep :: request data - $: =path - num=@ud - == - :: - +$ rawr :: response packet ::TODO meow - $: sig=@ - siz=@ud - byts - == - :: - +$ roar :: response message - $: sig=@ - dat=(cask) - == - :: - ++ spit - |= =path - ^- [pat=@t wid=@ud] - =+ pat=(spat path) - =+ wid=(met 3 pat) - ?> (lte wid 384) ::TODO check when we handle %keen, in addition to here - [pat wid] - :: - ++ request-body - |= [=path num=@ud] - ::NOTE path is expected to be a namespace path without the ship - ^- byts - ?> (lth num (bex 32)) - =+ (spit path) - :- :(add 32 16 wid) - %+ can 3 - :~ 4^num :: fragment number - 2^wid :: path size - wid^`@`pat :: namespace path - == - :: - ++ encode-request - |= [=ship =path num=@ud] - ::NOTE path is expected to be a namespace path without the ship - ^- hoot ^- @ - =+ bod=(request-body path num) - =+ syn=(can 3 64^(sign:keys dat.bod) bod ~) - %+ con 0b100 ::NOTE request bit - %+ encode-packet | - [[our ship] (mod life:keys 16) (mod (lyfe:keys ship) 16) ~ syn] - :: - ++ encode-response ::TODO unit tests - |= [=path data=(unit (cask))] - ^- song - :: prepend request descriptions to each response packet - :: - =; pacs=(list @ux) - %- head - %^ spin pacs 1 - |= [pac=@ux num=@ud] - ^- [purr _num] - :_ +(num) - ^- @ux - ::NOTE we stub out the receiver & origin details, - :: runtime should replace them as appropriate. - ::TODO should have scry endpoint that produces gate that does - :: that packet transformation - (encode-packet | [our ~zod] (mod life:keys 16) 0b0 ~ pac) - :: prepend a signature and split the data into 1024-byte fragments - :: - =/ frag=(list @) - ::TODO should also sign the request path - =/ sig=@ (full:keys path (fall data ~)) - ?~ data [sig]~ - %+ rip 13 ::NOTE 1024 bytes - (cat 3 sig (jam u.data)) ::TODO should include life - :: sign & packetize the fragments - :: - %- head - %^ spin frag 1 - |= [dat=@ num=@ud] - :_ +(num) - ^- @ux - =/ req=byts (request-body path num) - =/ bod=byts - =/ wid=@ud (met 3 dat) - :- :(add 4 2 wid) - %+ can 3 - :~ 4^(lent frag) :: number of fragments - 2^wid :: response data fragment size in bytes - wid^dat :: response data fragment - == - =/ sig=byts - 64^(sign:keys (can 3 req bod ~)) - (can 3 req sig bod ~) - :: - ++ keys - |% - ++ full - |= [=path mess=*] - (sign (shax (jam [our life path mess]))) - :: - ++ life life.ames-state - ++ sign sign:as:crypto-core.ames-state - :: - ::TODO for the unknown case, should use the alien-agenda - ++ lyfe - |= who=ship - ^- ^life - ~| [%fine %unknown-peer who] - =/ ship-state (~(got by peers.ames-state) who) - ?> ?=([%known *] ship-state) - life.ship-state - :: - ::TODO for the unknown case, should use the alien-agenda - ++ pass - |= [who=ship lyf=^life] - ~| [%fine %unknown-peer who lyf] - =/ ship-state (~(got by peers.ames-state) who) - ?> ?=([%known *] ship-state) - ~| [%fine %life-mismatch who lyf] - ?> =(lyf life.ship-state) - public-key.ship-state - -- - :: - ++ get-lane - |= =ship - ^- lane:ames - =; lanes - ::TODO should we send to all lanes? - ?^ lanes i.lanes - ~&(%fine-lane-stub &+~zod) ::TODO - !< (list lane:ames) - =< q %- need %- need - =/ =path /peers/(scot %p ship)/forward-lane - ::TODO get from state - (rof `[our ~ ~] [%ames %x] [our %$ da+now] path) - :: - ++ decode-request - |= =hoot - ^- twit - :- sig=(cut 3 [0 64] hoot) - -:(decode-request-info (rsh 3^64 hoot)) - :: - ++ decode-request-info - |= =hoot - ^- [=peep =purr] - =+ num=(cut 3 [0 4] hoot) - =+ len=(cut 3 [4 2] hoot) - =+ pat=(cut 3 [6 len] hoot) - :- [(stab pat) num] - :: if there is data remaining, it's the response - (rsh [3 (add 6 len)] hoot) - :: - ++ decode-response-packet - |= =purr - =; =rawr - ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] - rawr - :* sig=(cut 3 [0 64] purr) - siz=(cut 3 [64 4] purr) - wid=(cut 3 [68 2] purr) - dat=(rsh 3^70 purr) - == - :: - ++ verify-response-packet - |= rawr - !! - :: - ++ decode-response-msg - |= partial-fine ::TODO maybe take @ instead - ^- roar - =/ mess=@ - %+ can 3 ::TODO just (rep 13 -) - %+ turn (gulf 1 num-fragments) - ~(got by fragments) - :- sig=(cut 3 [0 64] mess) - ~| [%fine %response-not-cask] - ;;((cask) (cue (rsh 3^64 mess))) - :: - ++ send-request - |= [=ship =path num=@ud] - ^- (quip move _ames-state) - :_ ames-state - :: make sure we exclude the ship from the path proper, - :: since it already gets included in the request header - :: - =. path (oust [1 1] path) - =/ =lane:ames (get-lane ship) - =/ =hoot (encode-request ship path 1) - [unix-duct.ames-state %give %send lane `@ux`hoot]~ - :: - ++ process-response - |= [=path data=(unit (cask))] - ^- (quip move _ames-state) - :- %+ turn ~(tap in (~(get ju want.state) path)) - (late [%give %tune path data]) - =. want.state (~(del by want.state) path) - =. part.state (~(del by part.state) path) - ames-state - :: - ++ handle-request - |= =twit - ^- (list move) - =/ =song - %+ encode-response path.twit - (get-scry-result *gang path.twit) - ::TODO different task, pick the right packet - [duct %give %howl path.twit song]~ - :: - ++ handle-response - |= [[from=ship =lane:ames] =peep =rawr] - ^- (quip move _ames-state) - ?: =(0 siz.rawr) - ?> =(~ dat.rawr) - (process-response path.peep ~) - ?. (~(has by part.state) path.peep) - :: we did not initiate this request, or it's been cancelled - :: - !! - =/ partial=partial-fine - (~(got by part.state) path.peep) - =. partial - ?: (~(has by fragments.partial) num.peep) - partial - =, partial - :+ ~| [%fine %response-size-changed have=num-fragments new=siz.rawr] - ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) - num-fragments - +(num-received) - (~(put by fragments) num.peep [wid dat]:rawr) - :: - ?: =(num-fragments num-received):partial - :: we have all the parts now, construct the full response - :: - =/ =roar (decode-response-msg partial) - ::TODO check signature - (process-response path.peep `dat.roar) - :: otherwise, store the part, and send out the next request - :: - =. part.state (~(put by part.state) path.peep partial) - =/ next-num=@ud - =/ next=@ud +(num.peep) - :: we should receive responses in order, but in case we don't... - :: - |- - ?. (~(has by fragments.partial) next) next - $(next +((mod next num-fragments.partial))) - :: - =/ =hoot (encode-request from path.peep next-num) - ::TODO ask amsden, should we shotgun? we can tweak this - :: for now (mvp) though, stay 1-to-1 - ::TODO update lane in ames state - ::TODO is reusing the lane fine? - :_ ames-state - [unix-duct.ames-state %give %send lane `@ux`hoot]~ - :: - ++ get-scry-result - |= [=gang =path] - ^- (unit (cask)) - ?~ nom=(de-omen path) ~ - ?> =(our p.bem.u.nom) - :: we only support scrying into clay, - :: and only if the data is fully public. - :: - ?. =(%c (end 3 (snag 0 path))) ~ - =+ pem=(rof gang (need (de-omen %cp (slag 1 path)))) - ?> ?=(^ pem) - ?> ?=(^ u.pem) - =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) - ?> =([%black ~ ~] rul.r.per) - =+ res=(rof gang u.nom) - ?- res - ~ !! ::TODO lets just not do the task case - [~ ~] ~ - [~ ~ *] `[p q.q]:u.u.res - == - -- -- From 4bea69bc7d790adc0de05b6b9949c2f46ccd5646 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 1 Feb 2022 11:42:07 +0100 Subject: [PATCH 035/168] fine: verify life & signatures of packets & msgs In addition to doing signing & verification consistently with each other, we now handle the "no data" case sanely. Still uses the wrong keys though. --- pkg/arvo/sys/vane/ames.hoon | 77 ++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 28ec050c2..a5f5bc844 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2460,11 +2460,17 @@ ::TODO handle ~& [%fine %done-goofed u.dud] event-core + ::NOTE we only send requests to ships we know, + :: so we should only get responses from ships we know. + :: below we assume sndr.packet is a known peer. + =* from sndr.packet + =/ peer (~(got by peers.ames-state) from) + ?> ?=(%known -.peer) + ?> =(sndr-tick.packet (mod life.peer 16)) + :: =/ [=peep =purr] (decode-request-info `@ux`content.packet) =/ =rawr (decode-response-packet purr) - ::TODO validate we are the right life? at laest for request case - ::TODO validate response signature - (handle-response [sndr.packet lane] peep rawr) + (handle-response [from life.peer lane] peep rawr) -- |% +$ twit :: signed request @@ -2485,7 +2491,7 @@ :: +$ roar :: response message $: sig=@ - dat=(cask) + dat=$@(~ (cask)) == :: ++ spit @@ -2516,8 +2522,9 @@ =+ bod=(request-body path num) =+ syn=(can 3 64^(sign:keys dat.bod) bod ~) %+ con 0b100 ::NOTE request bit - %+ encode-packet | - [[our ship] (mod life:keys 16) (mod (lyfe:keys ship) 16) ~ syn] + %^ encode-packet | + [our ship] + [(mod life.ames-state 16) (mod (lyfe:keys ship) 16) ~ syn] :: ++ encode-response ::TODO unit tests |= [=path data=(unit (cask))] @@ -2533,13 +2540,10 @@ ^- @ux ::NOTE we stub out the receiver & origin details, :: runtime should replace them as appropriate. - ::TODO should have scry endpoint that produces gate that does - :: that packet transformation, just to set a spec - (encode-packet | [our ~zod] (mod life:keys 16) 0b0 ~ pac) + (encode-packet | [our ~zod] (mod life.ames-state 16) 0b0 ~ pac) :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) - ::TODO should also sign the request path =/ sig=@ (full:keys path (fall data ~)) ?~ data [sig]~ %+ rip 13 ::NOTE 1024 bytes @@ -2566,31 +2570,46 @@ :: ++ keys |% + ++ mess + |=([@p life path $@(~ (cask))] (jam +<)) + :: ++ full - |= [=path mess=*] - (sign (shax (jam [our life path mess]))) + |= [=path data=$@(~ (cask))] + (sign (mess our life.ames-state path data)) :: - ++ life life.ames-state - ++ sign sign:as:crypto-core.ames-state + ++ sign + |= msg=@ + %+ sign:ed:crypto msg + ::TODO get just the sgn key! + sec:ex:crypto-core.ames-state :: - ::TODO for the unknown case, should use the alien-agenda ++ lyfe |= who=ship - ^- ^life + ^- life ~| [%fine %unknown-peer who] =/ ship-state (~(got by peers.ames-state) who) ?> ?=([%known *] ship-state) life.ship-state :: - ::TODO for the unknown case, should use the alien-agenda ++ pass - |= [who=ship lyf=^life] + |= [who=ship lyf=life] ~| [%fine %unknown-peer who lyf] =/ ship-state (~(got by peers.ames-state) who) ?> ?=([%known *] ship-state) ~| [%fine %life-mismatch who lyf] ?> =(lyf life.ship-state) public-key.ship-state + :: + ++ veri + |= [who=ship lyf=life sig=@ dat=@] + %^ veri:ed:crypto sig + dat + ::TODO get jsut the sign key! + pub:ex:(com:nu:crub:crypto (pass:keys who lyf)) + :: + ++ meri + |= [who=ship lyf=life pax=path sig=@ dat=$@(~ (cask))] + (veri who lyf sig (mess who lyf pax dat)) -- :: ++ get-lane @@ -2633,10 +2652,6 @@ dat=(rsh 3^70 purr) == :: - ++ verify-response-packet - |= rawr - !! - :: ++ decode-response-msg |= partial-fine ::TODO maybe take @ instead ^- roar @@ -2645,8 +2660,10 @@ %+ turn (gulf 1 num-fragments) ~(got by fragments) :- sig=(cut 3 [0 64] mess) + =+ dat=(rsh 3^64 mess) + ?~ dat ~ ~| [%fine %response-not-cask] - ;;((cask) (cue (rsh 3^64 mess))) + ;;((cask) (cue dat)) :: ++ send-request |= [=ship =path num=@ud] @@ -2661,22 +2678,20 @@ [unix-duct.ames-state %give %send lane `@ux`hoot] :: ++ process-response - |= [=path data=(unit (cask))] + |= [[from=ship =life] =path sig=@ data=$@(~ (cask))] ^+ event-core + ?> (meri:keys from life path sig data) =. event-core %- emil %+ turn ~(tap in (~(get ju want.state) path)) - (late [%give %tune path data]) + (late [%give %tune path ?@(data data `data)]) =. want.state (~(del by want.state) path) =. part.state (~(del by part.state) path) event-core :: ++ handle-response - |= [[from=ship =lane:ames] =peep =rawr] + |= [[from=ship =life =lane:ames] =peep =rawr] ^+ event-core - ?: =(0 siz.rawr) - ?> =(~ dat.rawr) - (process-response path.peep ~) ?. (~(has by part.state) path.peep) :: we did not initiate this request, or it's been cancelled :: @@ -2691,14 +2706,14 @@ ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) num-fragments +(num-received) + ?> (veri:keys from life [sig dat]:rawr) (~(put by fragments) num.peep [wid dat]:rawr) :: ?: =(num-fragments num-received):partial :: we have all the parts now, construct the full response :: =/ =roar (decode-response-msg partial) - ::TODO check signature - (process-response path.peep `dat.roar) + (process-response [from life] path.peep [sig dat]:roar) :: otherwise, store the part, and send out the next request :: =. part.state (~(put by part.state) path.peep partial) From c72c187eddd0290ffef13b04f0441ba1f71191cd Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 1 Feb 2022 12:02:47 +0100 Subject: [PATCH 036/168] fine: use $@(~ (cask)) consistently It's what ends up in the packet, probably better than passing units and converting them all over. --- pkg/arvo/sys/vane/ames.hoon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index a5f5bc844..0c2e8440f 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -1171,7 +1171,7 @@ ?- res ~ ~ [~ ~] ``noun+!>((encode-response:fine:ven path ~)) - [~ ~ *] ``noun+!>((encode-response:fine:ven path `[p q.q]:u.u.res)) + [~ ~ *] ``noun+!>((encode-response:fine:ven path [p q.q]:u.u.res)) == == -- @@ -2527,7 +2527,7 @@ [(mod life.ames-state 16) (mod (lyfe:keys ship) 16) ~ syn] :: ++ encode-response ::TODO unit tests - |= [=path data=(unit (cask))] + |= [=path data=$@(~ (cask))] ^- song :: prepend request descriptions to each response packet :: From 1e924cfa404b3bcd8260043e8e5b040bd9c9c7bd Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 31 Jan 2022 17:34:32 -0600 Subject: [PATCH 037/168] urbit: move fine runtime into ames --- pkg/urbit/include/vere/vere.h | 2 +- pkg/urbit/vere/auto.c | 5 +- pkg/urbit/vere/io/ames.c | 94 ++++++++++------------------------- 3 files changed, 27 insertions(+), 74 deletions(-) diff --git a/pkg/urbit/include/vere/vere.h b/pkg/urbit/include/vere/vere.h index a457b045b..64eea8eac 100644 --- a/pkg/urbit/include/vere/vere.h +++ b/pkg/urbit/include/vere/vere.h @@ -1136,7 +1136,7 @@ /* u3_ames_io_init(): initialize ames I/O. */ u3_auto* - u3_ames_io_init(u3_pier* pir_u, u3_auto** far_u); + u3_ames_io_init(u3_pier* pir_u); /* u3_ames_decode_lane(): destructure lane from noun */ diff --git a/pkg/urbit/vere/auto.c b/pkg/urbit/vere/auto.c index 0a6890113..5a56d22bc 100644 --- a/pkg/urbit/vere/auto.c +++ b/pkg/urbit/vere/auto.c @@ -405,13 +405,10 @@ u3_auto* u3_auto_init(u3_pier* pir_u) { u3_auto* car_u = 0; - u3_auto* fin_u = 0; car_u = _auto_link(u3_hind_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_behn_io_init(pir_u), pir_u, car_u); - car_u = _auto_link(u3_ames_io_init(pir_u, &fin_u), pir_u, car_u); - // TODO: hacky, review - car_u = _auto_link(fin_u, pir_u, car_u); + car_u = _auto_link(u3_ames_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_http_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_cttp_io_init(pir_u), pir_u, car_u); car_u = _auto_link(u3_unix_io_init(pir_u), pir_u, car_u); diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index da7699d28..beb49fded 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -20,7 +20,6 @@ /* u3_fine: fine networking */ typedef struct _u3_fine { - u3_auto car_u; // fine driver c3_y ver_y; // fine protocol u3p(u3h_root) sac_p; // scry cache hashtable struct _u3_ames* sam_u; // ames backpointer @@ -989,16 +988,20 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) pac_u->len_w = u3r_met(3, pac); pac_u->hun_y = c3_malloc(pac_u->len_w); + u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); - pen_u->typ_y = 0; pen_u->len_w = pac_u->len_w; pen_u->hun_y = pac_u->hun_y; pen_u->sam_u = sam_u; - - u3r_bytes(0, pac_u->len_w, pac_u->hun_y, pac); + u3_head hed_u; + _ames_sift_head(&hed_u, pac_u->hun_y); + pen_u->typ_y = + hed_u.sim_o == c3y ? 0 : + hed_u.req_o == c3y ? 1 : 2; + u3_noun tag, val; u3x_cell(lan, &tag, &val); c3_assert( (c3y == tag) || (c3n == tag) ); @@ -1177,7 +1180,6 @@ _ames_forward(u3_panc* pac_u, u3_noun las) // if ( c3n == u3r_cell(lan, &tag, &dat) ) { u3l_log("ames: bogus lane\n"); - u3m_p("lan", lan); } else { c3_o sen_o = c3y; @@ -1440,12 +1442,12 @@ static void _fine_hear_response(u3_ames* sam_u, c3_w num_w = res_u.num_w; c3_w fra_w = res_u.fra_w; - u3_noun cad = u3nt(c3__purr, + u3_noun cad = u3nt(c3__hear, u3nc(c3n, u3_ames_encode_lane(lan_u)), u3i_bytes(len_w, hun_y)); - u3_ovum* ovo_u = u3_ovum_init(0, c3__fine, u3k(wir), u3k(cad)); - u3_auto_plan(&sam_u->fin_s.car_u, ovo_u); + u3_ovum* ovo_u = u3_ovum_init(0, c3__ames, u3k(wir), u3k(cad)); + u3_auto_plan(&sam_u->car_u, ovo_u); u3z(cad); u3z(wir); @@ -1490,10 +1492,11 @@ static void _fine_hear_request(u3_ames* sam_u, if ( u3_none == cac ) { // cache miss - u3_noun pax = u3nc(u3i_string("message"), + u3_noun pax = u3nt(u3i_string("fine"), + u3i_string("message"), u3do("stab", u3k(pat))); - u3_pier_peek_last(sam_u->fin_s.car_u.pir_u, u3_nul, c3__fx, u3_nul, + u3_pier_peek_last(sam_u->car_u.pir_u, u3_nul, c3__ax, u3_nul, pax, pen_u, _fine_pack_scry_cb); } else { @@ -1843,27 +1846,6 @@ _ames_ef_turf(u3_ames* sam_u, u3_noun tuf) } -/* fine_io_kick:(): receive effect from arvo - */ -static c3_o _fine_io_kick(u3_auto* car_u, u3_noun wir, u3_noun nun) { - u3_fine* fin_u = (u3_fine*)car_u; - u3_ames* sam_u = fin_u->sam_u; - u3_noun hed = u3h(nun); - //u3m_p("head: ", hed); - - if(c3__howl == hed) { - // TODO: respond to notification of bound data - return c3y; - } else if(c3__hoot == hed) { - u3_noun lan, hot; - u3x_cell(u3t(nun), &lan, &hot); - _fine_request(sam_u, lan, hot); - return c3y; - } else { - return c3n; - } -} - /* _ames_prot_scry_cb(): receive ames protocol version */ static void @@ -1918,15 +1900,6 @@ _fine_prot_scry_cb(void* vod_p, u3_noun nun) u3z(nun); } -/* _fine_io_talk(): start receiving ames traffic. -*/ -static void _fine_io_talk(u3_auto* car_u) -{ - // do nothing -} - - - /* _ames_io_talk(): start receiving ames traffic. */ static void @@ -1947,17 +1920,6 @@ _ames_io_talk(u3_auto* car_u) u3_auto_plan(car_u, u3_ovum_init(0, c3__a, wir, cad)); } - // send fine born - { - u3_noun wir = u3nt(c3__newt, - u3dc("scot", c3__uv, sam_u->sev_l), - u3_nul); - u3_noun cad = u3nc(c3__born, u3_nul); - - u3_auto_plan(&sam_u->fin_s.car_u, u3_ovum_init(0, c3__f, wir, cad)); - - } - u3_pier_peek_last(car_u->pir_u, u3_nul, c3__fx, u3_nul, u3nt(u3i_string("protocol"), u3i_string("version"), u3_nul), @@ -1997,6 +1959,17 @@ _ames_kick_newt(u3_ames* sam_u, u3_noun tag, u3_noun dat) _ames_ef_turf(sam_u, u3k(dat)); ret_o = c3y; } break; + + case c3__howl: { + ret_o = c3y; + } break; + + case c3__hoot: { + u3_noun lan = u3k(u3h(dat)); + u3_noun pac = u3k(u3t(dat)); + _fine_request(sam_u, lan, pac); + ret_o = c3y; + } break; } u3z(tag); u3z(dat); @@ -2080,14 +2053,6 @@ _ames_exit_cb(uv_handle_t* had_u) c3_free(sam_u); } -/* _fine_io_exit(): terminate fine I/O. -*/ -static void -_fine_io_exit(u3_auto* car_u) -{ - // cleanup handled in _ames_io_exit -} - /* _ames_io_exit(): terminate ames I/O. */ static void @@ -2135,7 +2100,7 @@ _ames_io_info(u3_auto* car_u) /* u3_ames_io_init(): initialize ames I/O. */ u3_auto* -u3_ames_io_init(u3_pier* pir_u, u3_auto** far_u) +u3_ames_io_init(u3_pier* pir_u) { u3_ames* sam_u = c3_calloc(sizeof(*sam_u)); sam_u->pir_u = pir_u; @@ -2186,15 +2151,6 @@ u3_ames_io_init(u3_pier* pir_u, u3_auto** far_u) car_u->io.kick_f = _ames_io_kick; car_u->io.exit_f = _ames_io_exit; - u3_auto* fur_u = &sam_u->fin_s.car_u; - fur_u->nam_m = c3__fine; - fur_u->liv_o = c3y; - fur_u->io.talk_f = _fine_io_talk; - fur_u->io.info_f = _fine_io_info; - fur_u->io.kick_f = _fine_io_kick; - fur_u->io.exit_f = _fine_io_exit; - *far_u = fur_u; - sam_u->fin_s.sam_u = sam_u; { From 225aefb4ff3872c29ff51c6a30dedc38c294988e Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Feb 2022 12:40:47 -0600 Subject: [PATCH 038/168] ames: unify disparate packet types --- pkg/urbit/vere/io/ames.c | 344 ++++++++++++++++----------------------- 1 file changed, 143 insertions(+), 201 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index beb49fded..202304d57 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -5,17 +5,7 @@ #include "vere/vere.h" #include "ur/serial.h" -/* u3_pact: outbound ames packet. -*/ - typedef struct _u3_pact { - uv_udp_send_t snd_u; // udp send request - u3_lane lan_u; // destination lane - c3_w len_w; // length in bytes - c3_y* hun_y; // packet buffer - c3_y imp_y; // galaxy number (optional) - c3_c* dns_c; // galaxy fqdn (optional) - struct _u3_ames* sam_u; // ames backpointer - } u3_pact; + /* u3_fine: fine networking */ @@ -95,11 +85,6 @@ c3_c* pat_c; // path as ascii } u3_requ; - typedef struct _u3_reqp { - u3_head hed_u; - u3_requ req_u; - } u3_reqp; - /* u3_resp: fine packet response */ typedef struct _u3_resp { u3_prel pre_u; @@ -115,23 +100,7 @@ } u3_resp; - /* u3_pend: generic ames or fine pending packet */ - typedef struct _u3_pend { - uv_udp_send_t snd_u; // udp send request - c3_y typ_y; // 0 for ames, 1 for fine request, 2 for fine response - c3_d her_d[2]; // recipent mars address - c3_c* dns_c; // galaxy FQDN - c3_y* hun_y; // packet contents - c3_w len_w; // packet contents - u3_lane lan_u; // recipient lane - c3_w fra_w; // fragment number - u3_ames* sam_u; // ames backpointer - union { - u3_resp* res_u; - u3_reqp* req_u; - u3_pact* pac_u; - }; - } u3_pend; + /* u3_body: ames packet body */ @@ -142,6 +111,25 @@ c3_l mug_l; // checksum } u3_body; +/* u3_pact: outbound ames packet. +*/ + typedef struct _u3_pact { + uv_udp_send_t snd_u; // udp send request + u3_lane lan_u; // destination lane + c3_w len_w; // length in bytes + c3_y* hun_y; // packet buffer + u3_head hed_u; // head of packet + c3_y imp_y; // galaxy number (optional) + c3_c* dns_c; // galaxy fqdn (optional) + struct _u3_ames* sam_u; // ames backpointer + c3_y typ_y; + union { + u3_resp res_u; + u3_requ req_u; + u3_body bod_u; + }; + } u3_pact; + /* u3_panc: deconstructed incoming packet */ typedef struct _u3_panc { @@ -169,33 +157,21 @@ _ames_alloc(uv_handle_t* had_u, *buf = uv_buf_init(ptr_v, 2048); } -/* _ames_pact_free(): free packet struct. -*/ static void -_ames_pact_free(u3_pact* pac_u) +_ames_pact_free(u3_pact* pac_u) { - c3_free(pac_u->hun_y); - c3_free(pac_u->dns_c); - c3_free(pac_u); -} - -static void -_ames_pend_free(u3_pend* pen_u) -{ - if ( 0 == pen_u->typ_y ) { // ames packet - if( pen_u->pac_u ) { - _ames_pact_free(pen_u->pac_u); - } - } else if ( 1 == pen_u->typ_y ) { // fine request - c3_free(pen_u->req_u); + if ( 0 == pac_u->typ_y ) { // ames packet + } else if ( 1 == pac_u->typ_y ) { // fine request + c3_free(pac_u->req_u.pat_c); } else { // fine response - c3_free(pen_u->res_u); + c3_free(pac_u->res_u.pat_c); + c3_free(pac_u->res_u.dat_y); } - c3_free(pen_u->dns_c); - c3_free(pen_u->hun_y); + c3_free(pac_u->dns_c); + c3_free(pac_u->hun_y); - c3_free(pen_u); + c3_free(pac_u); } /* _ames_panc_free(): remove references, lose refcounts and free struct @@ -390,8 +366,6 @@ _fine_sift_requ(u3_head* hed_u, memcpy(req_u->sig_y, req_y, 64); req_y += 64; - //_log_bytes(req_y, 4); - req_u->fra_w = ( (req_y[0] << 0x0) | (req_y[1] << 0x8) @@ -471,13 +445,10 @@ _fine_sift_resp(u3_head* hed_u, memcpy(&res_u->dat_y, res_y, res_u->siz_s); - // TODO: strict inequality? - /*if(rem_w + res_u->len_s != len_w) { + if(rem_w + res_u->len_s != len_w) { return c3n; - }*/ + } - // TODO: defend maliciusly crafted lengths? - // TODO: add null terminator? return c3y; } @@ -573,7 +544,7 @@ _fine_etch_resp(u3_head* hed_u, c3_w* pac_w = (c3_w*)pac_y; memcpy(pac_w, &res_u->fra_w, 4); - *pac_w = res_u->fra_w; // TODO: check byte order + *pac_w = res_u->fra_w; *(pac_y + sen_y + 4) = (0xff << 0) & res_u->len_s; *(pac_y + sen_y + 5) = (0xff << 1) & res_u->len_s; @@ -620,8 +591,8 @@ _ames_etch_pack(u3_head* hed_u, static void _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) { - u3_pend* pen_u = (u3_pend*)req_u; - u3_ames* sam_u = pen_u->sam_u; + u3_pact* pac_u = (u3_pact*)req_u; + u3_ames* sam_u = pac_u->sam_u; if (sas_i) { u3l_log("ames: send fail: %s\n", uv_strerror(sas_i)); @@ -631,34 +602,33 @@ _ames_send_cb(uv_udp_send_t* req_u, c3_i sas_i) sam_u->fig_u.net_o = c3y; } - _ames_pend_free(pen_u); + _ames_pact_free(pac_u); } #define _fine_send _ames_send /* _ames_send(): send buffer to address on port. */ static void -_ames_send(u3_pend* pen_u) +_ames_send(u3_pact* pac_u) { - u3_ames* sam_u = pen_u->sam_u; + u3_ames* sam_u = pac_u->sam_u; - // TODO: prevalidation? - /*if ( !pen_u->hun_y ) { - // _ames_pact_free(pac_u); - //return; + if ( !pac_u->hun_y ) { + _ames_pact_free(pac_u); + return; } - else */ { + else { struct sockaddr_in add_u; memset(&add_u, 0, sizeof(add_u)); add_u.sin_family = AF_INET; - add_u.sin_addr.s_addr = htonl(pen_u->lan_u.pip_w); - add_u.sin_port = htons(pen_u->lan_u.por_s); + add_u.sin_addr.s_addr = htonl(pac_u->lan_u.pip_w); + add_u.sin_port = htons(pac_u->lan_u.por_s); { - uv_buf_t buf_u = uv_buf_init((c3_c*)pen_u->hun_y, pen_u->len_w); + uv_buf_t buf_u = uv_buf_init((c3_c*)pac_u->hun_y, pac_u->len_w); - c3_i sas_i = uv_udp_send(&pen_u->snd_u, + c3_i sas_i = uv_udp_send(&pac_u->snd_u, &sam_u->wax_u, &buf_u, 1, (const struct sockaddr*)&add_u, @@ -670,7 +640,7 @@ _ames_send(u3_pend* pen_u) sam_u->fig_u.net_o = c3n; } - _ames_pend_free(pen_u); + _ames_pact_free(pac_u); } } } @@ -800,36 +770,36 @@ _ames_czar_port(c3_y imp_y) /* _ames_czar_gone(): galaxy address resolution failed. */ static void -_ames_czar_gone(u3_pend* pen_u, time_t now) +_ames_czar_gone(u3_pact* pac_u, time_t now) { - u3_ames* sam_u = pen_u->sam_u; - c3_d imp_d = pen_u->her_d[0]; + u3_ames* sam_u = pac_u->sam_u; + c3_d imp_y = pac_u->imp_y; - if ( c3y == sam_u->imp_o[imp_d] ) { - u3l_log("ames: czar at %s: not found (b)\n", pen_u->dns_c); - sam_u->imp_o[imp_d] = c3n; + if ( c3y == sam_u->imp_o[imp_y] ) { + u3l_log("ames: czar at %s: not found (b)\n", pac_u->dns_c); + sam_u->imp_o[imp_y] = c3n; } - if ( (0 == sam_u->imp_w[imp_d]) || - (0xffffffff == sam_u->imp_w[imp_d]) ) + if ( (0 == sam_u->imp_w[imp_y]) || + (0xffffffff == sam_u->imp_w[imp_y]) ) { - sam_u->imp_w[imp_d] = 0xffffffff; + sam_u->imp_w[imp_y] = 0xffffffff; } // keep existing ip for 5 more minutes // - sam_u->imp_t[imp_d] = now; + sam_u->imp_t[imp_y] = now; - _ames_pend_free(pen_u); + _ames_pact_free(pac_u); } /* _ames_czar_here(): galaxy address resolution succeeded. */ static void -_ames_czar_here(u3_pend* pen_u, time_t now, struct sockaddr_in* add_u) +_ames_czar_here(u3_pact* pac_u, time_t now, struct sockaddr_in* add_u) { - u3_ames* sam_u = pen_u->sam_u; - c3_y imp_y = pen_u->her_d[0]; + u3_ames* sam_u = pac_u->sam_u; + c3_y imp_y = pac_u->imp_y; c3_w old_w = sam_u->imp_w[imp_y]; c3_w pip_w = ntohl(add_u->sin_addr.s_addr); @@ -837,7 +807,7 @@ _ames_czar_here(u3_pend* pen_u, time_t now, struct sockaddr_in* add_u) u3_noun nam = u3dc("scot", c3__if, u3i_word(pip_w)); c3_c* nam_c = u3r_string(nam); - u3l_log("ames: czar %s: ip %s\n", pen_u->dns_c, nam_c); + u3l_log("ames: czar %s: ip %s\n", pac_u->dns_c, nam_c); c3_free(nam_c); u3z(nam); @@ -847,7 +817,7 @@ _ames_czar_here(u3_pend* pen_u, time_t now, struct sockaddr_in* add_u) sam_u->imp_t[imp_y] = now; sam_u->imp_o[imp_y] = c3y; - pen_u->lan_u.pip_w = pip_w; + pac_u->lan_u.pip_w = pip_w; } /* _ames_czar_cb(): galaxy address resolution callback. @@ -858,13 +828,13 @@ _ames_czar_cb(uv_getaddrinfo_t* adr_u, struct addrinfo* aif_u) { { - u3_pend* pen_u = (u3_pend*)adr_u->data; + u3_pact* pac_u = (u3_pact*)adr_u->data; struct addrinfo* rai_u = aif_u; time_t now = time(0); while ( rai_u ) { if ( (AF_INET == rai_u->ai_family) ) { - _ames_czar_here(pen_u, now, (struct sockaddr_in *)rai_u->ai_addr); + _ames_czar_here(pac_u, now, (struct sockaddr_in *)rai_u->ai_addr); break; } else { @@ -873,7 +843,7 @@ _ames_czar_cb(uv_getaddrinfo_t* adr_u, } if ( !rai_u ) { - _ames_czar_gone(pen_u, now); + _ames_czar_gone(pac_u, now); } } @@ -884,26 +854,24 @@ _ames_czar_cb(uv_getaddrinfo_t* adr_u, /* _ames_czar(): galaxy address resolution. */ static void -_ames_czar(u3_pend* pen_u) +_ames_czar(u3_pact* pac_u) { - u3_ames* sam_u = pen_u->sam_u; + u3_ames* sam_u = pac_u->sam_u; - c3_d imp_d = pen_u->her_d[0]; + c3_y imp_y = pac_u->imp_y; - c3_assert( imp_d < 256 ); - - pen_u->lan_u.por_s = _ames_czar_port(imp_d); + pac_u->lan_u.por_s = _ames_czar_port(imp_y); if ( c3n == u3_Host.ops_u.net ) { - pen_u->lan_u.pip_w = 0x7f000001; - _ames_send(pen_u); + pac_u->lan_u.pip_w = 0x7f000001; + _ames_send(pac_u); return; } // if we don't have a galaxy domain, no-op // if ( !sam_u->dns_c ) { - u3_noun nam = u3dc("scot", 'p', pen_u->her_d[0]); + u3_noun nam = u3dc("scot", 'p', pac_u->imp_y); c3_c* nam_c = u3r_string(nam); u3l_log("ames: no galaxy domain for %s, no-op\r\n", nam_c); @@ -913,8 +881,8 @@ _ames_czar(u3_pend* pen_u) } { - c3_w pip_w = sam_u->imp_w[imp_d]; - time_t wen = sam_u->imp_t[imp_d]; + c3_w pip_w = sam_u->imp_w[imp_y]; + time_t wen = sam_u->imp_t[imp_y]; time_t now = time(0); // backoff for 5 minutes after failed lookup @@ -923,27 +891,27 @@ _ames_czar(u3_pend* pen_u) || ( (0xffffffff == pip_w) // sentinal ip address && ((now - wen) < 300) ) ) { - _ames_pend_free(pen_u); + _ames_pact_free(pac_u); return; } // cached addresses have a 5 minute TTL // else if ( (0 != pip_w) && ((now - wen) < 300) ) { - pen_u->lan_u.pip_w = pip_w; - _ames_send(pen_u); + pac_u->lan_u.pip_w = pip_w; + _ames_send(pac_u); return; } else { c3_i sas_i; { - u3_noun nam = u3dc("scot", 'p', imp_d); + u3_noun nam = u3dc("scot", 'p', imp_y); c3_c* nam_c = u3r_string(nam); // NB: . separator not counted, as [nam_c] includes a ~ that we skip // - pen_u->dns_c = c3_malloc(1 + strlen(nam_c) + strlen(sam_u->dns_c)); - sas_i = snprintf(pen_u->dns_c, 255, "%s.%s", nam_c + 1, sam_u->dns_c); + pac_u->dns_c = c3_malloc(1 + strlen(nam_c) + strlen(sam_u->dns_c)); + sas_i = snprintf(pac_u->dns_c, 255, "%s.%s", nam_c + 1, sam_u->dns_c); c3_free(nam_c); u3z(nam); @@ -951,20 +919,20 @@ _ames_czar(u3_pend* pen_u) if ( 255 <= sas_i ) { u3l_log("ames: czar: galaxy domain %s truncated\n", sam_u->dns_c); - _ames_pend_free(pen_u); + _ames_pact_free(pac_u); return; } { uv_getaddrinfo_t* adr_u = c3_malloc(sizeof(*adr_u)); - adr_u->data = pen_u; + adr_u->data = pac_u; if ( 0 != (sas_i = uv_getaddrinfo(u3L, adr_u, _ames_czar_cb, - pen_u->dns_c, 0, 0)) ) + pac_u->dns_c, 0, 0)) ) { u3l_log("ames: %s\n", uv_strerror(sas_i)); - _ames_czar_gone(pen_u, now); + _ames_czar_gone(pac_u, now); return; } } @@ -988,17 +956,11 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) pac_u->len_w = u3r_met(3, pac); pac_u->hun_y = c3_malloc(pac_u->len_w); - - u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); - pen_u->len_w = pac_u->len_w; - pen_u->hun_y = pac_u->hun_y; - pen_u->sam_u = sam_u; - u3r_bytes(0, pac_u->len_w, pac_u->hun_y, pac); u3_head hed_u; _ames_sift_head(&hed_u, pac_u->hun_y); - pen_u->typ_y = + pac_u->typ_y = hed_u.sim_o == c3y ? 0 : hed_u.req_o == c3y ? 1 : 2; @@ -1013,8 +975,7 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) c3_assert( val < 256 ); pac_u->imp_y = val; - pen_u->her_d[0] = val; - _ames_czar(pen_u); + _ames_czar(pac_u); } // non-galaxy lane // @@ -1039,8 +1000,8 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) // otherwise, mutate destination and send packet // else { - pen_u->lan_u = lan_u; - _ames_send(pen_u); + pac_u->lan_u = lan_u; + _ames_send(pac_u); } } u3z(lan); u3z(pac); @@ -1363,74 +1324,58 @@ _ames_skip(u3_body* bod_u) { } #endif -static void _fine_got_pack(u3_pend* pen_u, u3_noun fra) +static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) { - pen_u->len_w = u3r_met(3, fra); - pen_u->hun_y = c3_calloc(pen_u->len_w); + pac_u->len_w = u3r_met(3, fra); + pac_u->hun_y = c3_calloc(pac_u->len_w); - u3r_bytes(0, pen_u->len_w, pen_u->hun_y, fra); + u3r_bytes(0, pac_u->len_w, pac_u->hun_y, fra); - _fine_send(pen_u); - - - // - // hashtable = (path, packet_num) -> cached_result; - // All cases, except 1st ~: put results in cache for all packets - // ~ -> if second request, ask for notification if 2nd, drop on floor - // [~ ~] -> send packet - // [~ ~ *] -> send packet - // TODO: cache logic, counting requests, evict? - - /*u3_weak lan = _ames_lane_from_cache(pen_u->sam_u->lax_p, - u3i_chubs(2, pen_u->her_d)); - if(u3_none == lan) { - // TODO: enqueue packet for later sending, populate lane cache - } else if(u3_nul == lan) { - // TODO: no lane, drop packet - } else { - _fine_send(pen_u); - } - */ + _fine_send(pac_u); + u3z(fra); } /* _fine_pack_scry_cb(): receive all packets for datum out of fine - * TODO: implement */ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) { u3l_log("got scry result\n"); - u3_pend* pen_u = vod_p; - u3_ames* sam_u = pen_u->sam_u; - u3_weak pac = u3r_at(7, nun); - if(pac == u3_none) { + u3_pact* pac_u = vod_p; + u3_ames* sam_u = pac_u->sam_u; + u3_weak pas = u3r_at(7, nun); + if(pas == u3_none) { u3l_log("no result, bailing\n"); + _ames_pact_free(pac_u); + u3z(nun); return; } - c3_assert( 1 == pen_u->typ_y); + c3_assert( 1 == pac_u->typ_y); u3_weak fra = u3_none; - u3_noun pax = u3i_string(pen_u->req_u->req_u.pat_c); - u3l_log("made string\n"); + u3_noun pax = u3i_string(pac_u->req_u.pat_c); c3_w cur_w = 1; - u3_noun lis = u3k(pac); - while(pac != u3_nul) { - u3h_put(sam_u->fin_s.sac_p, u3nc(u3k(pax), u3i_word(cur_w)), u3h(pac)); - if ( pen_u->fra_w == cur_w ) { - fra = u3k(u3h(pac)); + u3k(pas); + while(pas != u3_nul) { + u3_noun key = u3nc(u3k(pax), u3i_word(cur_w)); + u3h_put(sam_u->fin_s.sac_p, key, u3h(pas)); + if ( pac_u->req_u.fra_w == cur_w ) { + fra = u3k(u3h(pas)); } cur_w++; - pac = u3t(pac); + pas = u3t(pas); + u3z(key); } if ( fra == u3_none ) { u3l_log("fragment number out of range\n"); } else { - _fine_got_pack(pen_u, fra); + _fine_got_pack(pac_u, fra); } + u3z(pas); + u3z(nun); } - static void _fine_hear_response(u3_ames* sam_u, u3_lane lan_u, c3_w len_w, @@ -1474,21 +1419,17 @@ static void _fine_hear_request(u3_ames* sam_u, u3_noun pat = u3i_string(req_u.pat_c); u3_noun key = u3nc(u3k(pat), u3i_word(req_u.fra_w)); - // TODO: revive u3_weak cac = u3h_git(sam_u->fin_s.sac_p, key); - u3_reqp* rep_u = c3_calloc(sizeof(*rep_u)); - u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); - pen_u->sam_u = sam_u; - pen_u->typ_y = 1; - pen_u->req_u = rep_u; + pac_u->sam_u = sam_u; + pac_u->typ_y = 1; - memcpy(&rep_u->hed_u, &hed_u, sizeof(u3_head)); - memcpy(&rep_u->req_u, &req_u, sizeof(u3_requ)); + memcpy(&pac_u->hed_u, &hed_u, sizeof(u3_head)); + memcpy(&pac_u->req_u, &req_u, sizeof(u3_requ)); - memcpy(&pen_u->lan_u, &lan_u, sizeof(u3_lane)); - pen_u->fra_w = req_u.fra_w; + memcpy(&pac_u->lan_u, &lan_u, sizeof(u3_lane)); if ( u3_none == cac ) { // cache miss @@ -1497,10 +1438,10 @@ static void _fine_hear_request(u3_ames* sam_u, u3do("stab", u3k(pat))); u3_pier_peek_last(sam_u->car_u.pir_u, u3_nul, c3__ax, u3_nul, - pax, pen_u, _fine_pack_scry_cb); + pax, pac_u, _fine_pack_scry_cb); } else { - _fine_got_pack(pen_u, u3k(cac)); + _fine_got_pack(pac_u, u3k(cac)); } u3z(pat); @@ -1547,7 +1488,7 @@ _fine_request(u3_ames* sam_u, u3_noun req) { - u3_pend* pen_u = c3_calloc(sizeof(*pen_u)); + u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); u3_head* hed_u = c3_calloc(sizeof(*hed_u)); u3_requ* req_u = c3_calloc(sizeof(*req_u)); @@ -1555,8 +1496,8 @@ _fine_request(u3_ames* sam_u, c3_y* req_y = c3_calloc(req_w); u3r_bytes(0, req_w, req_y, req); //_log_bytes(req_y, 4); - pen_u->hun_y = req_y; - pen_u->len_w = req_w; + pac_u->hun_y = req_y; + pac_u->len_w = req_w; _ames_sift_head(hed_u, req_y); req_y += 4; @@ -1564,21 +1505,20 @@ _fine_request(u3_ames* sam_u, _fine_sift_requ(hed_u, req_u, req_w, req_y); - pen_u->typ_y = 1; - pen_u->her_d[0] = req_u->pre_u.rec_d[0]; - pen_u->her_d[1] = req_u->pre_u.rec_d[1]; - pen_u->sam_u = sam_u; + pac_u->typ_y = 1; + pac_u->sam_u = sam_u; { u3_noun tag, val; u3x_cell(lan, &tag, &val); if(tag == 0) { - _ames_czar(pen_u); + pac_u->imp_y = req_u->pre_u.rec_d[0]; + _ames_czar(pac_u); } else { u3_lane lan_u = u3_ames_decode_lane(val); - pen_u->lan_u.pip_w = lan_u.pip_w; - pen_u->lan_u.por_s = lan_u.por_s; - _ames_send(pen_u); + pac_u->lan_u.pip_w = lan_u.pip_w; + pac_u->lan_u.por_s = lan_u.por_s; + _ames_send(pac_u); } } } @@ -1593,8 +1533,7 @@ _ames_hear(u3_ames* sam_u, { // TODO: move from stack to heap to avoid reparsing - u3_head hed_u; - u3_body bod_u; + u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); // XX packet filtering needs to revised for two protocol-change scenarios // @@ -1612,7 +1551,7 @@ _ames_hear(u3_ames* sam_u, // unpack header, ensuring buffer is large enough // // - c3_o is_ames_o = _ames_sift_head(&hed_u, hun_y); + c3_o is_ames_o = _ames_sift_head(&pac_u->hed_u, hun_y); if (4 > len_w) { sam_u->sat_u.hed_d++; @@ -1634,7 +1573,7 @@ _ames_hear(u3_ames* sam_u, // XX rethink use of [fit_o] here and elsewhere // if ( (c3y == sam_u->fig_u.fit_o) - && (sam_u->ver_y != hed_u.ver_y) ) + && (sam_u->ver_y != pac_u->hed_u.ver_y) ) { sam_u->sat_u.vet_d++; if ( 0 == (sam_u->sat_u.vet_d % 100000) ) { @@ -1643,6 +1582,7 @@ _ames_hear(u3_ames* sam_u, } c3_free(hun_y); + _ames_pact_free(pac_u); return; } @@ -1652,7 +1592,7 @@ _ames_hear(u3_ames* sam_u, // unpack and validate the body // - if ( (c3n == _ames_sift_body(&hed_u, &bod_u, bod_w, bod_y)) ) { + if ( (c3n == _ames_sift_body(&pac_u->hed_u, &pac_u->bod_u, bod_w, bod_y)) ) { sam_u->sat_u.bod_d++; if ( 0 == (sam_u->sat_u.bod_d % 100) ) { u3l_log("ames: %" PRIu64 " dropped, failed to read body\n", @@ -1660,12 +1600,13 @@ _ames_hear(u3_ames* sam_u, } c3_free(hun_y); + _ames_pact_free(pac_u); return; } // ensure the mug is valid // - if ( bod_u.mug_l != hed_u.mug_l ) { + if ( pac_u->bod_u.mug_l != pac_u->hed_u.mug_l ) { sam_u->sat_u.mut_d++; if ( 0 == (sam_u->sat_u.mut_d % 100000) ) { u3l_log("ames: %" PRIu64 " dropped for invalid mug\n", @@ -1673,6 +1614,7 @@ _ames_hear(u3_ames* sam_u, } c3_free(hun_y); + _ames_pact_free(pac_u); return; } } @@ -1682,10 +1624,10 @@ _ames_hear(u3_ames* sam_u, // we might want to forward statelessly // if ( 0 && (c3y == sam_u->fig_u.see_o) - && ( (bod_u.pre_u.rec_d[0] != sam_u->pir_u->who_d[0]) - || (bod_u.pre_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) + && ( (pac_u->bod_u.pre_u.rec_d[0] != sam_u->pir_u->who_d[0]) + || (pac_u->bod_u.pre_u.rec_d[1] != sam_u->pir_u->who_d[1]) ) ) { - _ames_try_forward(sam_u, lan_u, &hed_u, &bod_u, hun_y); + _ames_try_forward(sam_u, lan_u, &pac_u->hed_u, &pac_u->bod_u, hun_y); } // otherwise, inject the packet as an event // From 7205625abf745e06770afcf8f6dba08f322f81a8 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Feb 2022 05:42:13 -0600 Subject: [PATCH 039/168] wip --- .husky/post-checkout | 3 + .husky/post-commit | 3 + .husky/post-merge | 3 + .husky/pre-push | 3 + pkg/arvo/gen/hood/keen.hoon | 8 + pkg/arvo/sys/vane/ames.hoon | 126 ++++- pkg/arvo/tests/sys/vane/ames.hoon | 67 ++- pkg/npm/api/tmp/contacts/index.d.ts | 2 + pkg/npm/api/tmp/contacts/index.js | 3 + pkg/npm/api/tmp/contacts/index.js.map | 1 + pkg/npm/api/tmp/contacts/lib.d.ts | 26 + pkg/npm/api/tmp/contacts/lib.js | 64 +++ pkg/npm/api/tmp/contacts/lib.js.map | 1 + pkg/npm/api/tmp/contacts/types.d.ts | 61 +++ pkg/npm/api/tmp/contacts/types.js | 2 + pkg/npm/api/tmp/contacts/types.js.map | 1 + pkg/npm/api/tmp/docket/index.d.ts | 2 + pkg/npm/api/tmp/docket/index.js | 3 + pkg/npm/api/tmp/docket/index.js.map | 1 + pkg/npm/api/tmp/docket/lib.d.ts | 15 + pkg/npm/api/tmp/docket/lib.js | 54 ++ pkg/npm/api/tmp/docket/lib.js.map | 1 + pkg/npm/api/tmp/docket/types.d.ts | 106 ++++ pkg/npm/api/tmp/docket/types.js | 2 + pkg/npm/api/tmp/docket/types.js.map | 1 + pkg/npm/api/tmp/graph/index.d.ts | 2 + pkg/npm/api/tmp/graph/index.js | 3 + pkg/npm/api/tmp/graph/index.js.map | 1 + pkg/npm/api/tmp/graph/lib.d.ts | 148 ++++++ pkg/npm/api/tmp/graph/lib.js | 380 +++++++++++++ pkg/npm/api/tmp/graph/lib.js.map | 1 + pkg/npm/api/tmp/graph/types.d.ts | 76 +++ pkg/npm/api/tmp/graph/types.js | 2 + pkg/npm/api/tmp/graph/types.js.map | 1 + pkg/npm/api/tmp/groups/index.d.ts | 2 + pkg/npm/api/tmp/groups/index.js | 3 + pkg/npm/api/tmp/groups/index.js.map | 1 + pkg/npm/api/tmp/groups/lib.d.ts | 40 ++ pkg/npm/api/tmp/groups/lib.js | 139 +++++ pkg/npm/api/tmp/groups/lib.js.map | 1 + pkg/npm/api/tmp/groups/types.d.ts | 2 + pkg/npm/api/tmp/groups/types.js | 3 + pkg/npm/api/tmp/groups/types.js.map | 1 + pkg/npm/api/tmp/groups/update.d.ts | 133 +++++ pkg/npm/api/tmp/groups/update.js | 2 + pkg/npm/api/tmp/groups/update.js.map | 1 + pkg/npm/api/tmp/groups/view.d.ts | 24 + pkg/npm/api/tmp/groups/view.js | 2 + pkg/npm/api/tmp/groups/view.js.map | 1 + pkg/npm/api/tmp/hark/index.d.ts | 2 + pkg/npm/api/tmp/hark/index.js | 3 + pkg/npm/api/tmp/hark/index.js.map | 1 + pkg/npm/api/tmp/hark/lib.d.ts | 46 ++ pkg/npm/api/tmp/hark/lib.js | 100 ++++ pkg/npm/api/tmp/hark/lib.js.map | 1 + pkg/npm/api/tmp/hark/types.d.ts | 55 ++ pkg/npm/api/tmp/hark/types.js | 2 + pkg/npm/api/tmp/hark/types.js.map | 1 + pkg/npm/api/tmp/hood/index.d.ts | 2 + pkg/npm/api/tmp/hood/index.js | 3 + pkg/npm/api/tmp/hood/index.js.map | 1 + pkg/npm/api/tmp/hood/lib.d.ts | 34 ++ pkg/npm/api/tmp/hood/lib.js | 97 ++++ pkg/npm/api/tmp/hood/lib.js.map | 1 + pkg/npm/api/tmp/hood/types.d.ts | 145 +++++ pkg/npm/api/tmp/hood/types.js | 2 + pkg/npm/api/tmp/hood/types.js.map | 1 + pkg/npm/api/tmp/index.d.ts | 22 + pkg/npm/api/tmp/index.js | 25 + pkg/npm/api/tmp/index.js.map | 1 + pkg/npm/api/tmp/invite/index.d.ts | 2 + pkg/npm/api/tmp/invite/index.js | 3 + pkg/npm/api/tmp/invite/index.js.map | 1 + pkg/npm/api/tmp/invite/lib.d.ts | 5 + pkg/npm/api/tmp/invite/lib.js | 18 + pkg/npm/api/tmp/invite/lib.js.map | 1 + pkg/npm/api/tmp/invite/types.d.ts | 54 ++ pkg/npm/api/tmp/invite/types.js | 2 + pkg/npm/api/tmp/invite/types.js.map | 1 + .../api/tmp/lib/BigIntArrayOrderedMap.d.ts | 24 + pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js | 131 +++++ .../api/tmp/lib/BigIntArrayOrderedMap.js.map | 1 + pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts | 20 + pkg/npm/api/tmp/lib/BigIntOrderedMap.js | 102 ++++ pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map | 1 + pkg/npm/api/tmp/lib/index.d.ts | 2 + pkg/npm/api/tmp/lib/index.js | 3 + pkg/npm/api/tmp/lib/index.js.map | 1 + pkg/npm/api/tmp/lib/lib.d.ts | 33 ++ pkg/npm/api/tmp/lib/lib.js | 207 ++++++++ pkg/npm/api/tmp/lib/lib.js.map | 1 + pkg/npm/api/tmp/lib/types.d.ts | 42 ++ pkg/npm/api/tmp/lib/types.js | 5 + pkg/npm/api/tmp/lib/types.js.map | 1 + pkg/npm/api/tmp/metadata/index.d.ts | 2 + pkg/npm/api/tmp/metadata/index.js | 3 + pkg/npm/api/tmp/metadata/index.js.map | 1 + pkg/npm/api/tmp/metadata/lib.d.ts | 15 + pkg/npm/api/tmp/metadata/lib.js | 69 +++ pkg/npm/api/tmp/metadata/lib.js.map | 1 + pkg/npm/api/tmp/metadata/types.d.ts | 76 +++ pkg/npm/api/tmp/metadata/types.js | 2 + pkg/npm/api/tmp/metadata/types.js.map | 1 + pkg/npm/api/tmp/s3/index.d.ts | 2 + pkg/npm/api/tmp/s3/index.js | 3 + pkg/npm/api/tmp/s3/index.js.map | 1 + pkg/npm/api/tmp/s3/lib.d.ts | 8 + pkg/npm/api/tmp/s3/lib.js | 24 + pkg/npm/api/tmp/s3/lib.js.map | 1 + pkg/npm/api/tmp/s3/types.d.ts | 41 ++ pkg/npm/api/tmp/s3/types.js | 2 + pkg/npm/api/tmp/s3/types.js.map | 1 + pkg/npm/api/tmp/settings/index.d.ts | 2 + pkg/npm/api/tmp/settings/index.js | 3 + pkg/npm/api/tmp/settings/index.js.map | 1 + pkg/npm/api/tmp/settings/lib.d.ts | 21 + pkg/npm/api/tmp/settings/lib.js | 51 ++ pkg/npm/api/tmp/settings/lib.js.map | 1 + pkg/npm/api/tmp/settings/types.d.ts | 52 ++ pkg/npm/api/tmp/settings/types.js | 2 + pkg/npm/api/tmp/settings/types.js.map | 1 + pkg/npm/http-api/tmp/Urbit.d.ts | 183 +++++++ pkg/npm/http-api/tmp/Urbit.js | 497 ++++++++++++++++++ pkg/npm/http-api/tmp/Urbit.js.map | 1 + pkg/npm/http-api/tmp/index.d.ts | 3 + pkg/npm/http-api/tmp/index.js | 4 + pkg/npm/http-api/tmp/index.js.map | 1 + pkg/npm/http-api/tmp/types.d.ts | 180 +++++++ pkg/npm/http-api/tmp/types.js | 5 + pkg/npm/http-api/tmp/types.js.map | 1 + pkg/npm/http-api/tmp/utils.d.ts | 16 + pkg/npm/http-api/tmp/utils.js | 51 ++ pkg/npm/http-api/tmp/utils.js.map | 1 + 133 files changed, 4037 insertions(+), 27 deletions(-) create mode 100755 .husky/post-checkout create mode 100755 .husky/post-commit create mode 100755 .husky/post-merge create mode 100755 .husky/pre-push create mode 100644 pkg/arvo/gen/hood/keen.hoon create mode 100644 pkg/npm/api/tmp/contacts/index.d.ts create mode 100644 pkg/npm/api/tmp/contacts/index.js create mode 100644 pkg/npm/api/tmp/contacts/index.js.map create mode 100644 pkg/npm/api/tmp/contacts/lib.d.ts create mode 100644 pkg/npm/api/tmp/contacts/lib.js create mode 100644 pkg/npm/api/tmp/contacts/lib.js.map create mode 100644 pkg/npm/api/tmp/contacts/types.d.ts create mode 100644 pkg/npm/api/tmp/contacts/types.js create mode 100644 pkg/npm/api/tmp/contacts/types.js.map create mode 100644 pkg/npm/api/tmp/docket/index.d.ts create mode 100644 pkg/npm/api/tmp/docket/index.js create mode 100644 pkg/npm/api/tmp/docket/index.js.map create mode 100644 pkg/npm/api/tmp/docket/lib.d.ts create mode 100644 pkg/npm/api/tmp/docket/lib.js create mode 100644 pkg/npm/api/tmp/docket/lib.js.map create mode 100644 pkg/npm/api/tmp/docket/types.d.ts create mode 100644 pkg/npm/api/tmp/docket/types.js create mode 100644 pkg/npm/api/tmp/docket/types.js.map create mode 100644 pkg/npm/api/tmp/graph/index.d.ts create mode 100644 pkg/npm/api/tmp/graph/index.js create mode 100644 pkg/npm/api/tmp/graph/index.js.map create mode 100644 pkg/npm/api/tmp/graph/lib.d.ts create mode 100644 pkg/npm/api/tmp/graph/lib.js create mode 100644 pkg/npm/api/tmp/graph/lib.js.map create mode 100644 pkg/npm/api/tmp/graph/types.d.ts create mode 100644 pkg/npm/api/tmp/graph/types.js create mode 100644 pkg/npm/api/tmp/graph/types.js.map create mode 100644 pkg/npm/api/tmp/groups/index.d.ts create mode 100644 pkg/npm/api/tmp/groups/index.js create mode 100644 pkg/npm/api/tmp/groups/index.js.map create mode 100644 pkg/npm/api/tmp/groups/lib.d.ts create mode 100644 pkg/npm/api/tmp/groups/lib.js create mode 100644 pkg/npm/api/tmp/groups/lib.js.map create mode 100644 pkg/npm/api/tmp/groups/types.d.ts create mode 100644 pkg/npm/api/tmp/groups/types.js create mode 100644 pkg/npm/api/tmp/groups/types.js.map create mode 100644 pkg/npm/api/tmp/groups/update.d.ts create mode 100644 pkg/npm/api/tmp/groups/update.js create mode 100644 pkg/npm/api/tmp/groups/update.js.map create mode 100644 pkg/npm/api/tmp/groups/view.d.ts create mode 100644 pkg/npm/api/tmp/groups/view.js create mode 100644 pkg/npm/api/tmp/groups/view.js.map create mode 100644 pkg/npm/api/tmp/hark/index.d.ts create mode 100644 pkg/npm/api/tmp/hark/index.js create mode 100644 pkg/npm/api/tmp/hark/index.js.map create mode 100644 pkg/npm/api/tmp/hark/lib.d.ts create mode 100644 pkg/npm/api/tmp/hark/lib.js create mode 100644 pkg/npm/api/tmp/hark/lib.js.map create mode 100644 pkg/npm/api/tmp/hark/types.d.ts create mode 100644 pkg/npm/api/tmp/hark/types.js create mode 100644 pkg/npm/api/tmp/hark/types.js.map create mode 100644 pkg/npm/api/tmp/hood/index.d.ts create mode 100644 pkg/npm/api/tmp/hood/index.js create mode 100644 pkg/npm/api/tmp/hood/index.js.map create mode 100644 pkg/npm/api/tmp/hood/lib.d.ts create mode 100644 pkg/npm/api/tmp/hood/lib.js create mode 100644 pkg/npm/api/tmp/hood/lib.js.map create mode 100644 pkg/npm/api/tmp/hood/types.d.ts create mode 100644 pkg/npm/api/tmp/hood/types.js create mode 100644 pkg/npm/api/tmp/hood/types.js.map create mode 100644 pkg/npm/api/tmp/index.d.ts create mode 100644 pkg/npm/api/tmp/index.js create mode 100644 pkg/npm/api/tmp/index.js.map create mode 100644 pkg/npm/api/tmp/invite/index.d.ts create mode 100644 pkg/npm/api/tmp/invite/index.js create mode 100644 pkg/npm/api/tmp/invite/index.js.map create mode 100644 pkg/npm/api/tmp/invite/lib.d.ts create mode 100644 pkg/npm/api/tmp/invite/lib.js create mode 100644 pkg/npm/api/tmp/invite/lib.js.map create mode 100644 pkg/npm/api/tmp/invite/types.d.ts create mode 100644 pkg/npm/api/tmp/invite/types.js create mode 100644 pkg/npm/api/tmp/invite/types.js.map create mode 100644 pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.d.ts create mode 100644 pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js create mode 100644 pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js.map create mode 100644 pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts create mode 100644 pkg/npm/api/tmp/lib/BigIntOrderedMap.js create mode 100644 pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map create mode 100644 pkg/npm/api/tmp/lib/index.d.ts create mode 100644 pkg/npm/api/tmp/lib/index.js create mode 100644 pkg/npm/api/tmp/lib/index.js.map create mode 100644 pkg/npm/api/tmp/lib/lib.d.ts create mode 100644 pkg/npm/api/tmp/lib/lib.js create mode 100644 pkg/npm/api/tmp/lib/lib.js.map create mode 100644 pkg/npm/api/tmp/lib/types.d.ts create mode 100644 pkg/npm/api/tmp/lib/types.js create mode 100644 pkg/npm/api/tmp/lib/types.js.map create mode 100644 pkg/npm/api/tmp/metadata/index.d.ts create mode 100644 pkg/npm/api/tmp/metadata/index.js create mode 100644 pkg/npm/api/tmp/metadata/index.js.map create mode 100644 pkg/npm/api/tmp/metadata/lib.d.ts create mode 100644 pkg/npm/api/tmp/metadata/lib.js create mode 100644 pkg/npm/api/tmp/metadata/lib.js.map create mode 100644 pkg/npm/api/tmp/metadata/types.d.ts create mode 100644 pkg/npm/api/tmp/metadata/types.js create mode 100644 pkg/npm/api/tmp/metadata/types.js.map create mode 100644 pkg/npm/api/tmp/s3/index.d.ts create mode 100644 pkg/npm/api/tmp/s3/index.js create mode 100644 pkg/npm/api/tmp/s3/index.js.map create mode 100644 pkg/npm/api/tmp/s3/lib.d.ts create mode 100644 pkg/npm/api/tmp/s3/lib.js create mode 100644 pkg/npm/api/tmp/s3/lib.js.map create mode 100644 pkg/npm/api/tmp/s3/types.d.ts create mode 100644 pkg/npm/api/tmp/s3/types.js create mode 100644 pkg/npm/api/tmp/s3/types.js.map create mode 100644 pkg/npm/api/tmp/settings/index.d.ts create mode 100644 pkg/npm/api/tmp/settings/index.js create mode 100644 pkg/npm/api/tmp/settings/index.js.map create mode 100644 pkg/npm/api/tmp/settings/lib.d.ts create mode 100644 pkg/npm/api/tmp/settings/lib.js create mode 100644 pkg/npm/api/tmp/settings/lib.js.map create mode 100644 pkg/npm/api/tmp/settings/types.d.ts create mode 100644 pkg/npm/api/tmp/settings/types.js create mode 100644 pkg/npm/api/tmp/settings/types.js.map create mode 100644 pkg/npm/http-api/tmp/Urbit.d.ts create mode 100644 pkg/npm/http-api/tmp/Urbit.js create mode 100644 pkg/npm/http-api/tmp/Urbit.js.map create mode 100644 pkg/npm/http-api/tmp/index.d.ts create mode 100644 pkg/npm/http-api/tmp/index.js create mode 100644 pkg/npm/http-api/tmp/index.js.map create mode 100644 pkg/npm/http-api/tmp/types.d.ts create mode 100644 pkg/npm/http-api/tmp/types.js create mode 100644 pkg/npm/http-api/tmp/types.js.map create mode 100644 pkg/npm/http-api/tmp/utils.d.ts create mode 100644 pkg/npm/http-api/tmp/utils.js create mode 100644 pkg/npm/http-api/tmp/utils.js.map diff --git a/.husky/post-checkout b/.husky/post-checkout new file mode 100755 index 000000000..cab40f264 --- /dev/null +++ b/.husky/post-checkout @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-checkout.\n"; exit 2; } +git lfs post-checkout "$@" diff --git a/.husky/post-commit b/.husky/post-commit new file mode 100755 index 000000000..9443f4161 --- /dev/null +++ b/.husky/post-commit @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-commit.\n"; exit 2; } +git lfs post-commit "$@" diff --git a/.husky/post-merge b/.husky/post-merge new file mode 100755 index 000000000..828b70891 --- /dev/null +++ b/.husky/post-merge @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-merge.\n"; exit 2; } +git lfs post-merge "$@" diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 000000000..81a9cc639 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,3 @@ +#!/bin/sh +command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/pre-push.\n"; exit 2; } +git lfs pre-push "$@" diff --git a/pkg/arvo/gen/hood/keen.hoon b/pkg/arvo/gen/hood/keen.hoon new file mode 100644 index 000000000..f57225d13 --- /dev/null +++ b/pkg/arvo/gen/hood/keen.hoon @@ -0,0 +1,8 @@ +:- %say +|= [^ [=ship pax=$@(~ [=path ~])] ~] +=/ =path + ?~ pax /cz/(scot %p ship)/kids/1/sys + ?> ?=([@ *] path.pax) + =, pax + [i.path (scot %p ship) t.path] +[%helm-pass %a %keen path] diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 0c2e8440f..16b573617 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -284,6 +284,53 @@ [1 relayed=.?(origin)] == (mix header (lsh 5 body)) +:: +++ decode-request + |= =hoot + ^- twit + :- sig=(cut 3 [0 64] hoot) + -:(decode-request-info (rsh 3^64 hoot)) +:: +++ decode-request-info + |= =hoot + ^- [=peep =purr] + =+ num=(cut 3 [0 4] hoot) + =+ len=(cut 3 [4 2] hoot) + =+ pat=(cut 3 [6 len] hoot) + :- [(stab pat) num] + :: if there is data remaining, it's the response + (rsh [3 (add 6 len)] hoot) +:: +++ decode-response-packet + |= =purr + =; =rawr + ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] + rawr + :* sig=(cut 3 [0 64] purr) + siz=(cut 3 [64 4] purr) + wid=(cut 3 [68 2] purr) + dat=(rsh 3^70 purr) + == +:: +++ verify-response-packet + |= rawr + !! +:: +++ decode-response-msg + |= partial-fine ::TODO maybe take @ instead + ^- roar + =/ mess=@ + %+ rep 13 + %+ turn (gulf 1 num-fragments) + |= num=@ud + =/ frag=byts (~(got by fragments) num) + dat.frag + =+ sig=(end 3^64 mess) + :- sig + ~| [%fine %response-not-cask] + ;;((cask) (cue (rsh 3^64 mess))) +:: + :: +decode-packet: deserialize packet from bytestream or crash :: ++ decode-packet @@ -483,6 +530,7 @@ :: 0b11: comet -- 16 bytes :: +$ rank ?(%0b0 %0b1 %0b10 %0b11) ++$ byuts [wid=@ud dat=@ux] :: +| %kinetics :: $channel: combined sender and receiver identifying data @@ -609,6 +657,26 @@ part=(map path partial-fine) ::TODO re-send request timers? == ++$ twit :: signed request + $: signature=@ + peep + == +:: ++$ peep :: request data + $: =path + num=@ud + == +:: ++$ rawr :: response packet ::TODO meow + $: sig=@ + siz=@ud + byts + == +:: ++$ roar :: response message + $: sig=@ + dat=(cask) + == :: $partial-fine: partial remote scry response :: +$ partial-fine @@ -1155,16 +1223,18 @@ :: =/ =path [i.t.t.tyl (scot %p our) t.t.t.tyl] + =* pax t.t.tyl ?~ nom=(de-omen path) ~ :: we only support scrying into clay, :: and only if the data is fully public. :: - ?. =(%c (end 3 (snag 0 path))) ~ - =+ pem=(rof lyc (need (de-omen %cp (slag 1 path)))) - ?> ?=(^ pem) - ?> ?=(^ u.pem) - =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) - ?> =([%black ~ ~] rul.r.per) + :: ?. =(%c (end 3 (snag 0 path))) ~ + :: =/ perm-omen (need (de-omen %cp (slag 1 path))) + :: =+ pem=(rof lyc perm-omen) + :: ?> ?=(^ pem) + :: ?> ?=(^ u.pem) + :: =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) + :: ?> =([%black ~ ~] rul.r.per) =+ res=(rof lyc u.nom) ::TODO suggests we need to factor differently =+ ven=(per-event [now 0v0 rof] *duct ames-state) @@ -2458,7 +2528,8 @@ ^+ event-core ?^ dud ::TODO handle - ~& [%fine %done-goofed u.dud] + ~& [%fine %done-goofed mote.u.dud] + %- (slog tang.u.dud) event-core ::NOTE we only send requests to ships we know, :: so we should only get responses from ships we know. @@ -2473,6 +2544,7 @@ (handle-response [from life.peer lane] peep rawr) -- |% +<<<<<<< HEAD +$ twit :: signed request $: signature=@ peep @@ -2508,7 +2580,7 @@ ^- byts ?> (lth num (bex 32)) =+ (spit path) - :- :(add 32 16 wid) + :- :(add 4 2 wid) %+ can 3 :~ 4^num :: fragment number 2^wid :: path size @@ -2544,7 +2616,12 @@ :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) +<<<<<<< HEAD =/ sig=@ (full:keys path (fall data ~)) +======= + ::TODO should also sign the request path + =/ sig=@ ::(full:keys path (fall data ~)) + (fil 5 16 0xdead.beef) ?~ data [sig]~ %+ rip 13 ::NOTE 1024 bytes (cat 3 sig (jam u.data)) ::TODO should include life @@ -2565,7 +2642,8 @@ wid^dat :: response data fragment == =/ sig=byts - 64^(sign:keys (can 3 req bod ~)) + 64^(fil 5 16 0xcafe.face) + :: 64^(fil (sign:keys (can 3 req bod ~)) (can 3 req sig bod ~) :: ++ keys @@ -2611,18 +2689,16 @@ |= [who=ship lyf=life pax=path sig=@ dat=$@(~ (cask))] (veri who lyf sig (mess who lyf pax dat)) -- - :: + :: TODO: should not crash, + :: improve routing? ++ get-lane |= =ship ^- lane:ames - =; lanes - ::TODO should we send to all lanes? - ?^ lanes i.lanes - ~&(%fine-lane-stub &+~zod) ::TODO - !< (list lane:ames) - =< q %- need %- need - =/ =path /peers/(scot %p ship)/forward-lane + =/ =peer-state + (got-peer-state ship) + lane:(need route.peer-state) ::TODO get from state +<<<<<<< HEAD (rof `[our ~ ~] [%ames %x] [our %$ da+now] path) :: ++ decode-request @@ -2681,6 +2757,7 @@ |= [[from=ship =life] =path sig=@ data=$@(~ (cask))] ^+ event-core ?> (meri:keys from life path sig data) + ~& got-response/path =. event-core %- emil %+ turn ~(tap in (~(get ju want.state) path)) @@ -2692,19 +2769,24 @@ ++ handle-response |= [[from=ship =life =lane:ames] =peep =rawr] ^+ event-core - ?. (~(has by part.state) path.peep) + ?> ?=([@ *] path.peep) + =/ =path [i.path.peep (scot %p from) t.path.peep] + ?: =(0 siz.rawr) + ?> =(~ dat.rawr) + (process-response path.peep ~) + ?. (~(has by part.state) path) :: we did not initiate this request, or it's been cancelled :: !! =/ partial=partial-fine - (~(got by part.state) path.peep) + (~(got by part.state) path) =. partial ?: (~(has by fragments.partial) num.peep) partial =, partial :+ ~| [%fine %response-size-changed have=num-fragments new=siz.rawr] ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) - num-fragments + siz.rawr +(num-received) ?> (veri:keys from life [sig dat]:rawr) (~(put by fragments) num.peep [wid dat]:rawr) @@ -2713,10 +2795,10 @@ :: we have all the parts now, construct the full response :: =/ =roar (decode-response-msg partial) - (process-response [from life] path.peep [sig dat]:roar) + (process-response [from life] path [sig dat]:roar) :: otherwise, store the part, and send out the next request :: - =. part.state (~(put by part.state) path.peep partial) + =. part.state (~(put by part.state) path partial) =/ next-num=@ud =/ next=@ud +(num.peep) :: we should receive responses in order, but in case we don't... diff --git a/pkg/arvo/tests/sys/vane/ames.hoon b/pkg/arvo/tests/sys/vane/ames.hoon index 16638ddc1..9352340f1 100644 --- a/pkg/arvo/tests/sys/vane/ames.hoon +++ b/pkg/arvo/tests/sys/vane/ames.hoon @@ -89,6 +89,11 @@ %+ snag index (skim moves is-move-send) :: +++ scry + |= [vane=_nec car=term bem=beam] + =/ vane-core (vane) + (scry:vane-core ~ car bem) +:: ++ call |= [vane=_nec =duct =task:ames] ^- [moves=(list move:ames) _nec] @@ -118,7 +123,7 @@ content=0xdead.beef == :: - =/ encoded (encode-packet:ames packet) + =/ encoded (encode-packet:ames & packet) =/ decoded (decode-packet:ames encoded) :: %+ expect-eq @@ -135,7 +140,7 @@ content=0xdead.beef == :: - =/ encoded (encode-packet:ames packet) + =/ encoded (encode-packet:ames & packet) =/ decoded (decode-packet:ames encoded) :: %+ expect-eq @@ -191,7 +196,7 @@ rcvr-life=3 == :: - =/ =blob:ames (encode-packet:ames packet) + =/ =blob:ames (encode-packet:ames & packet) =^ moves1 bud (call bud ~[//unix] %hear lane-foo blob) =^ moves2 bud =/ =point:ames @@ -236,7 +241,7 @@ =/ packet ~! ames (encode-open-packet:ames open-packet crypto-core.ames-state.comet) - =/ blob (encode-packet:ames packet) + =/ blob (encode-packet:ames & packet) :: =^ moves0 bud (call bud ~[//unix] %hear lane-foo blob) :: @@ -255,7 +260,7 @@ sndr-life=1 rcvr-life=3 == - =/ blob (encode-packet:ames packet) + =/ blob (encode-packet:ames & packet) =^ moves1 bud (call bud ~[//unix] %hear lane-foo blob) :: ;: weld @@ -330,4 +335,56 @@ %+ expect-eq !> [~[/g/talk] %give %done `error] !> (snag 1 `(list move:ames)`moves5) +:: +++ test-fine-request + ^- tang + =/ want=path /cz/~bud/kids/1/sys + =/ net=path /cz/kids/1/sys + =^ moves1 nec (call nec ~[/g/talk] %keen want) + =/ req=hoot:ames + %+ snag 0 + %+ murn ;;((list move:ames) moves1) + |= =move:ames + ^- (unit hoot:ames) + ?. ?=(%give -.card.move) ~ + ?. ?=(%send -.p.card.move) ~ + `;;(@uxhoot blob.p.card.move) + =/ [is-ames=? =packet:ames] (decode-packet:ames `@ux`req) + ?> ?=(%| is-ames) + =/ twit + (decode-request:ames `@ux`content.packet) + ~& twit + (expect-eq !>(1) !>(1)) +:: +++ test-fine-response + ^- tang + =/ want=path /cz/~bud/kids/1/sys + =/ net=path /cz/kids/1/sys + =/ =beam [[~bud %$ da+now:bud] (welp /fine/message net)] + =/ [=mark =vase] (need (need (scry bud %x beam))) + =+ !<(=song:ames vase) + =/ partial + %- ~(gas by *(map @ud byts)) + ^- (list [@ud byts]) + %- head + %^ spin song 1 + |= [blob=@ux num=@ud] + ^- [[_num byts] _num] + :_ +(num) + =/ [is-ames=? =packet:ames] (decode-packet:ames `@ux`blob) + ?> ?=(%| is-ames) + =/ [=peep:ames =purr:ames] (decode-request-info:ames `@ux`content.packet) + =/ rawr (decode-response-packet:ames `@ux`purr) + ~& rawr-sig/`@ux`sig.rawr + ~& rawr-siz/`@ux`siz.rawr + ~& rawr-wid/`@ux`wid.rawr + ~& rawr-dat/`@ux`dat.rawr + :- num + [wid dat]:rawr + =/ num-frag=@ud ~(wyt by partial) + =/ =roar:ames + (decode-response-msg:ames num-frag num-frag partial) + ~& roar + ~! . + (expect-eq !>(1) !>(1)) -- diff --git a/pkg/npm/api/tmp/contacts/index.d.ts b/pkg/npm/api/tmp/contacts/index.d.ts new file mode 100644 index 000000000..4a272fce5 --- /dev/null +++ b/pkg/npm/api/tmp/contacts/index.d.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; diff --git a/pkg/npm/api/tmp/contacts/index.js b/pkg/npm/api/tmp/contacts/index.js new file mode 100644 index 000000000..5c8443c9d --- /dev/null +++ b/pkg/npm/api/tmp/contacts/index.js @@ -0,0 +1,3 @@ +export * from './types'; +export * from './lib'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/index.js.map b/pkg/npm/api/tmp/contacts/index.js.map new file mode 100644 index 000000000..e8bec26c5 --- /dev/null +++ b/pkg/npm/api/tmp/contacts/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../contacts/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/lib.d.ts b/pkg/npm/api/tmp/contacts/lib.d.ts new file mode 100644 index 000000000..b81a69eae --- /dev/null +++ b/pkg/npm/api/tmp/contacts/lib.d.ts @@ -0,0 +1,26 @@ +import { Patp, Poke, Scry } from '../lib'; +import { Contact, ContactUpdateAdd, ContactUpdateEdit, ContactUpdateRemove, ContactEditField, ContactShare, ContactUpdate, ContactUpdateAllowShips, ContactUpdateAllowGroup, ContactUpdateSetPublic } from './types'; +export declare const CONTACT_UPDATE_VERSION = 0; +declare const storeAction: (data: T, version?: number) => Poke; +export { storeAction as contactStoreAction }; +export declare const addContact: (ship: Patp, contact: Contact) => Poke; +export declare const removeContact: (ship: Patp) => Poke; +export declare const share: (recipient: Patp, version?: number) => Poke; +export declare const editContact: (ship: Patp, editField: ContactEditField) => Poke; +export declare const allowShips: (ships: Patp[]) => Poke; +export declare const allowGroup: (ship: string, name: string) => Poke; +export declare const setPublic: (setPublic: any) => Poke; +export declare const retrieve: (ship: string) => { + app: string; + mark: string; + json: { + add: { + resource: { + ship: string; + name: string; + }; + ship: string; + }; + }; +}; +export declare const fetchIsAllowed: (entity: string, name: string, ship: string, personal: boolean) => Scry; diff --git a/pkg/npm/api/tmp/contacts/lib.js b/pkg/npm/api/tmp/contacts/lib.js new file mode 100644 index 000000000..e2177339f --- /dev/null +++ b/pkg/npm/api/tmp/contacts/lib.js @@ -0,0 +1,64 @@ +export const CONTACT_UPDATE_VERSION = 0; +const storeAction = (data, version = CONTACT_UPDATE_VERSION) => ({ + app: 'contact-store', + mark: `contact-update-${version}`, + json: data +}); +export { storeAction as contactStoreAction }; +export const addContact = (ship, contact) => { + contact['last-updated'] = Date.now(); + return storeAction({ + add: { ship, contact } + }); +}; +export const removeContact = (ship) => storeAction({ + remove: { ship } +}); +export const share = (recipient, version = CONTACT_UPDATE_VERSION) => ({ + app: 'contact-push-hook', + mark: 'contact-share', + json: { share: recipient } +}); +export const editContact = (ship, editField) => storeAction({ + edit: { + ship, + 'edit-field': editField, + timestamp: Date.now() + } +}); +export const allowShips = (ships) => storeAction({ + allow: { + ships + } +}); +export const allowGroup = (ship, name) => storeAction({ + allow: { + group: { ship, name } + } +}); +export const setPublic = (setPublic) => { + return storeAction({ + 'set-public': setPublic + }); +}; +export const retrieve = (ship) => { + const resource = { ship, name: '' }; + return { + app: 'contact-pull-hook', + mark: 'pull-hook-action', + json: { + add: { + resource, + ship + } + } + }; +}; +export const fetchIsAllowed = (entity, name, ship, personal) => { + const isPersonal = personal ? 'true' : 'false'; + return { + app: 'contact-store', + path: `/is-allowed/${entity}/${name}/${ship}/${isPersonal}` + }; +}; +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/lib.js.map b/pkg/npm/api/tmp/contacts/lib.js.map new file mode 100644 index 000000000..5c0b9b03e --- /dev/null +++ b/pkg/npm/api/tmp/contacts/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../contacts/lib.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC,MAAM,WAAW,GAAG,CAA0B,IAAO,EAAE,UAAkB,sBAAsB,EAAW,EAAE,CAAC,CAAC;IAC5G,GAAG,EAAE,eAAe;IACpB,IAAI,EAAE,kBAAkB,OAAO,EAAE;IACjC,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAAE,CAAC;AAE7C,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAU,EAAE,OAAgB,EAA0B,EAAE;IACjF,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAErC,OAAO,WAAW,CAAC;QACjB,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;KACvB,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAU,EAA6B,EAAE,CACrE,WAAW,CAAC;IACV,MAAM,EAAE,EAAE,IAAI,EAAE;CACjB,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,SAAe,EAAE,UAAkB,sBAAsB,EAAsB,EAAE,CAAC,CAAC;IACvG,GAAG,EAAE,mBAAmB;IACxB,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;CAC3B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAU,EACV,SAA2B,EACF,EAAE,CAC3B,WAAW,CAAC;IACV,IAAI,EAAE;QACJ,IAAI;QACJ,YAAY,EAAE,SAAS;QACvB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB;CACF,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,KAAa,EACkB,EAAE,CAAC,WAAW,CAAC;IAC9C,KAAK,EAAE;QACL,KAAK;KACN;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAY,EACZ,IAAY,EACmB,EAAE,CAAC,WAAW,CAAC;IAC9C,KAAK,EAAE;QACL,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;KACtB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,SAAc,EACgB,EAAE;IAChC,OAAO,WAAW,CAAC;QACjB,YAAY,EAAE,SAAS;KACxB,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,EAAE;IACF,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACpC,OAAO;QACL,GAAG,EAAE,mBAAmB;QACxB,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE;YACJ,GAAG,EAAE;gBACH,QAAQ;gBACR,IAAI;aACL;SACF;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAAc,EACd,IAAY,EACZ,IAAY,EACZ,QAAiB,EACX,EAAE;IACR,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/C,OAAO;QACL,GAAG,EAAE,eAAe;QACpB,IAAI,EAAE,eAAe,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,UAAU,EAAE;KAC5D,CAAC;AACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/types.d.ts b/pkg/npm/api/tmp/contacts/types.d.ts new file mode 100644 index 000000000..d002ebebf --- /dev/null +++ b/pkg/npm/api/tmp/contacts/types.d.ts @@ -0,0 +1,61 @@ +import { Path, Patp } from '../lib'; +import { Resource } from '../groups'; +export declare type ContactUpdate = ContactUpdateAdd | ContactUpdateRemove | ContactUpdateEdit | ContactUpdateInitial | ContactUpdateAllowGroup | ContactUpdateAllowShips | ContactUpdateSetPublic; +export interface ContactUpdateAdd { + add: { + ship: Patp; + contact: Contact; + }; +} +export interface ContactUpdateRemove { + remove: { + ship: Patp; + }; +} +export interface ContactUpdateEdit { + edit: { + ship: Patp; + 'edit-field': ContactEditField; + timestamp: number; + }; +} +export interface ContactUpdateAllowShips { + allow: { + ships: Patp[]; + }; +} +export interface ContactUpdateAllowGroup { + allow: { + group: Resource; + }; +} +export interface ContactUpdateSetPublic { + 'set-public': boolean; +} +export interface ContactShare { + share: Patp; +} +export interface ContactUpdateInitial { + initial: Rolodex; +} +export declare type Rolodex = { + [p in Patp]: Contact; +}; +export declare type Contacts = Rolodex; +export interface Contact { + nickname: string; + bio: string; + status: string; + color: string; + avatar: string | null; + cover: string | null; + groups: Path[]; + 'last-updated': number; +} +declare type ContactKeys = keyof Contact; +export declare type ContactEditFieldPrim = Exclude; +export declare type ContactEditField = Partial> & { + 'add-group'?: Resource; + 'remove-group'?: Resource; +}; +export {}; diff --git a/pkg/npm/api/tmp/contacts/types.js b/pkg/npm/api/tmp/contacts/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/contacts/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/types.js.map b/pkg/npm/api/tmp/contacts/types.js.map new file mode 100644 index 000000000..b27fd52b3 --- /dev/null +++ b/pkg/npm/api/tmp/contacts/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../contacts/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/index.d.ts b/pkg/npm/api/tmp/docket/index.d.ts new file mode 100644 index 000000000..e06143cf1 --- /dev/null +++ b/pkg/npm/api/tmp/docket/index.d.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/pkg/npm/api/tmp/docket/index.js b/pkg/npm/api/tmp/docket/index.js new file mode 100644 index 000000000..872ee0de4 --- /dev/null +++ b/pkg/npm/api/tmp/docket/index.js @@ -0,0 +1,3 @@ +export * from './lib'; +export * from './types'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/index.js.map b/pkg/npm/api/tmp/docket/index.js.map new file mode 100644 index 000000000..ee11f934d --- /dev/null +++ b/pkg/npm/api/tmp/docket/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../docket/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/lib.d.ts b/pkg/npm/api/tmp/docket/lib.d.ts new file mode 100644 index 000000000..540c66f53 --- /dev/null +++ b/pkg/npm/api/tmp/docket/lib.d.ts @@ -0,0 +1,15 @@ +import { Poke, Scry } from '../lib'; +import { Chad } from './types'; +export declare function chadIsRunning(chad: Chad): boolean; +export declare const scryCharges: Scry; +export declare const scryDockets: Scry; +export declare const scryTreaties: Scry; +export declare const scryDefaultAlly: Scry; +export declare const scryAllies: Scry; +export declare const scryAllyTreaties: (ship: string) => Scry; +/** + * Uninstall a desk, and remove docket + */ +export declare function docketUninstall(desk: string): Poke; +export declare function docketInstall(ship: string, desk: string): Poke; +export declare function allyShip(ship: string): Poke; diff --git a/pkg/npm/api/tmp/docket/lib.js b/pkg/npm/api/tmp/docket/lib.js new file mode 100644 index 000000000..a974be13a --- /dev/null +++ b/pkg/npm/api/tmp/docket/lib.js @@ -0,0 +1,54 @@ +export function chadIsRunning(chad) { + return 'glob' in chad || 'site' in chad; +} +export const scryCharges = { + app: 'docket', + path: '/charges' +}; +export const scryDockets = { + app: 'docket', + path: '/dockets' +}; +export const scryTreaties = { + app: 'treaty', + path: '/treaties' +}; +export const scryDefaultAlly = { + app: 'treaty', + path: '/default-ally' +}; +export const scryAllies = { + app: 'treaty', + path: '/allies' +}; +export const scryAllyTreaties = (ship) => ({ + app: 'treaty', + path: `/treaties/${ship}` +}); +/** + * Uninstall a desk, and remove docket + */ +export function docketUninstall(desk) { + return { + app: 'docket', + mark: 'docket-uninstall', + json: desk + }; +} +export function docketInstall(ship, desk) { + return { + app: 'docket', + mark: 'docket-install', + json: `${ship}/${desk}` + }; +} +export function allyShip(ship) { + return { + app: 'treaty', + mark: 'ally-update-0', + json: { + add: ship + } + }; +} +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/lib.js.map b/pkg/npm/api/tmp/docket/lib.js.map new file mode 100644 index 000000000..7d7d1407c --- /dev/null +++ b/pkg/npm/api/tmp/docket/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../docket/lib.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,aAAa,CAAC,IAAU;IACtC,OAAO,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAS;IAC/B,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAS;IAC/B,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,WAAW;CAClB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,eAAe;CACtB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAS;IAC9B,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAQ,EAAE,CAAC,CAAC;IACvD,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,aAAa,IAAI,EAAE;CAC1B,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO;QACL,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE,IAAI;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAY;IACtD,OAAO;QACL,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,gBAAgB;QACtB,IAAI,EAAE,GAAG,IAAI,IAAI,IAAI,EAAE;KACxB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO;QACL,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,eAAe;QACrB,IAAI,EAAE;YACJ,GAAG,EAAE,IAAI;SACV;KACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/types.d.ts b/pkg/npm/api/tmp/docket/types.d.ts new file mode 100644 index 000000000..594b0f310 --- /dev/null +++ b/pkg/npm/api/tmp/docket/types.d.ts @@ -0,0 +1,106 @@ +import { Cass } from '../hood'; +export declare type DeskStatus = 'active' | 'suspended'; +export declare type DocketHref = DocketHrefSite | DocketHrefGlob; +export interface DocketHrefGlob { + glob: { + base: string; + }; +} +export interface DocketHrefSite { + site: string; +} +export interface Docket { + title: string; + info?: string; + color: string; + href: DocketHref; + website: string; + license: string; + version: string; + image?: string; +} +export interface Charge extends Docket { + chad: Chad; +} +export declare type Chad = HungChad | GlobChad | SiteChad | InstallChad | SuspendChad; +export interface HungChad { + hung: string; +} +export interface GlobChad { + glob: null; +} +export interface SiteChad { + site: null; +} +export interface InstallChad { + install: null; +} +export interface SuspendChad { + suspend: null; +} +export interface Treaty extends Docket { + ship: string; + desk: string; + cass: Cass; + hash: string; +} +export interface Charges { + [desk: string]: Charge; +} +export interface Treaties { + [ref: string]: Treaty; +} +export declare type Charter = string[]; +export interface Allies { + [ship: string]: Charter; +} +export interface Provider { + shipName: string; + nickname?: string; + status?: string; +} +export declare type ChargeUpdate = ChargeUpdateInitial | ChargeUpdateAdd | ChargeUpdateDel; +export interface ChargeUpdateInitial { + initial: { + [desk: string]: Charge; + }; +} +export interface ChargeUpdateAdd { + 'add-charge': { + desk: string; + charge: Charge; + }; +} +export interface ChargeUpdateDel { + 'del-charge': string; +} +export declare type AllyUpdate = AllyUpdateIni | AllyUpdateAdd | AllyUpdateDel | AllyUpdateNew; +export interface AllyUpdateIni { + ini: { + [ship: string]: string[]; + }; +} +export interface AllyUpdateAdd { + add: string; +} +export interface AllyUpdateDel { + del: string; +} +export interface AllyUpdateNew { + new: { + ship: string; + alliance: string[]; + }; +} +export declare type TreatyUpdate = TreatyUpdateIni | TreatyUpdateAdd | TreatyUpdateDel; +export interface TreatyUpdateIni { + ini: { + [foreignDesk: string]: Treaty; + }; +} +export interface TreatyUpdateAdd { + add: Treaty; +} +export interface TreatyUpdateDel { + del: string; +} diff --git a/pkg/npm/api/tmp/docket/types.js b/pkg/npm/api/tmp/docket/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/docket/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/types.js.map b/pkg/npm/api/tmp/docket/types.js.map new file mode 100644 index 000000000..0dffe4f69 --- /dev/null +++ b/pkg/npm/api/tmp/docket/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../docket/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/index.d.ts b/pkg/npm/api/tmp/graph/index.d.ts new file mode 100644 index 000000000..e06143cf1 --- /dev/null +++ b/pkg/npm/api/tmp/graph/index.d.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/pkg/npm/api/tmp/graph/index.js b/pkg/npm/api/tmp/graph/index.js new file mode 100644 index 000000000..872ee0de4 --- /dev/null +++ b/pkg/npm/api/tmp/graph/index.js @@ -0,0 +1,3 @@ +export * from './lib'; +export * from './types'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/index.js.map b/pkg/npm/api/tmp/graph/index.js.map new file mode 100644 index 000000000..5db9fcbe9 --- /dev/null +++ b/pkg/npm/api/tmp/graph/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../graph/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/lib.d.ts b/pkg/npm/api/tmp/graph/lib.d.ts new file mode 100644 index 000000000..1d8e9c69a --- /dev/null +++ b/pkg/npm/api/tmp/graph/lib.d.ts @@ -0,0 +1,148 @@ +import { GroupPolicy, Resource } from '../groups'; +import { Scry } from '../lib'; +import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types'; +import { Content, GraphNodePoke, Post } from './types'; +export declare const GRAPH_UPDATE_VERSION = 3; +export declare const createBlankNodeWithChildPost: (ship: PatpNoSig, parentIndex: string, childIndex: string, contents: Content[]) => GraphNodePoke; +export declare const markPending: (nodes: any) => any; +export declare const createPost: (ship: PatpNoSig, contents: Content[], parentIndex?: string, childIndex?: string) => Post; +declare const storeAction: (data: T, version?: number) => Poke; +export { storeAction as graphStoreAction }; +declare const viewAction: (threadName: string, action: T) => Thread; +export { viewAction as graphViewAction }; +declare const hookAction: (data: T, version?: number) => Poke; +export { hookAction as graphHookAction }; +export declare const createManagedGraph: (ship: PatpNoSig, name: string, title: string, description: string, group: Path, mod: string) => Thread; +export declare const createUnmanagedGraph: (ship: PatpNoSig, name: string, title: string, description: string, policy: Enc, mod: string) => Thread; +export declare const joinGraph: (ship: Patp, name: string) => Thread; +export declare const deleteGraph: (ship: PatpNoSig, name: string) => Thread; +export declare const leaveGraph: (ship: Patp, name: string) => Thread; +export declare const groupifyGraph: (ship: Patp, name: string, toPath?: string) => Thread; +export declare const evalCord: (cord: string) => Thread; +export declare const addGraph: (ship: Patp, name: string, graph: any, mark: any) => Poke; +export declare const addNodes: (ship: Patp, name: string, nodes: Object) => Thread; +export declare const addPost: (ship: Patp, name: string, post: Post) => Thread; +export declare const addNode: (ship: Patp, name: string, node: GraphNodePoke) => Thread; +export declare const createGroupFeed: (group: Resource, vip?: any) => Thread; +export declare const disableGroupFeed: (group: Resource) => Thread; +/** + * Set dm-hook to screen new DMs or not + * + */ +export declare const setScreen: (screen: boolean) => Poke; +/** + * Accept a pending DM request + * + * @param ship the ship to accept + */ +export declare const acceptDm: (ship: string) => Poke<{ + accept: string; +}>; +/** + * Decline a pending DM request + * + * @param ship the ship to accept + */ +export declare const declineDm: (ship: string) => Poke<{ + decline: string; +}>; +/** + * Remove posts from a set of indices + * + */ +export declare const removePosts: (ship: Patp, name: string, indices: string[]) => Poke; +/** + * Remove a DM message from our inbox + * + * @remarks + * This does not remove the message from the recipients inbox + */ +export declare const removeDmMessage: (our: Patp, index: string) => Poke; +/** + * Send a DM to a ship + * + * @param our sender + * @param ship recipient + * @param contents contents of message + */ +export declare const addDmMessage: (our: PatpNoSig, ship: Patp, contents: Content[]) => Poke; +/** + * Fetch newest (larger keys) nodes in a graph under some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export declare const getNewest: (ship: string, name: string, count: number, index?: string) => Scry; +/** + * Fetch nodes in a graph that are older (key is smaller) and direct + * siblings of some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export declare const getOlderSiblings: (ship: string, name: string, count: number, index: string) => Scry; +/** + * Fetch nodes in a graph that are younger (key is larger) and direct + * siblings of some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export declare const getYoungerSiblings: (ship: string, name: string, count: number, index: string) => Scry; +/** + * Fetch all nodes in a graph under some index, without loading children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + */ +export declare const getShallowChildren: (ship: string, name: string, index?: string) => { + app: string; + path: string; +}; +/** + * Fetch newest nodes in a graph as a flat map, including children, + * optionally starting at a specified key + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param start key to start at + * + */ +export declare const getDeepOlderThan: (ship: string, name: string, count: number, start?: string) => { + app: string; + path: string; +}; +/** + * Fetch a flat map of a nodes ancestors and firstborn children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + * + */ +export declare const getFirstborn: (ship: string, name: string, index: string) => Scry; +/** + * Fetch a single node, and all it's children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + * + */ +export declare const getNode: (ship: string, name: string, index: string) => Scry; +/** + * Fetch entire graph + * + * @param ship ship of graph + * @param name name of graph + * + */ +export declare const getGraph: (ship: string, name: string) => Scry; diff --git a/pkg/npm/api/tmp/graph/lib.js b/pkg/npm/api/tmp/graph/lib.js new file mode 100644 index 000000000..af182a9db --- /dev/null +++ b/pkg/npm/api/tmp/graph/lib.js @@ -0,0 +1,380 @@ +import { makeResource, resourceFromPath } from '../groups'; +import { decToUd, deSig, unixToDa } from '../lib'; +import { patp2dec } from 'urbit-ob'; +export const GRAPH_UPDATE_VERSION = 3; +export const createBlankNodeWithChildPost = (ship, parentIndex = '', childIndex = '', contents) => { + const date = unixToDa(Date.now()).toString(); + const nodeIndex = parentIndex + '/' + date; + const childGraph = {}; + childGraph[childIndex] = { + post: { + author: `~${ship}`, + index: nodeIndex + '/' + childIndex, + 'time-sent': Date.now(), + contents, + hash: null, + signatures: [] + }, + children: null + }; + return { + post: { + author: `~${ship}`, + index: nodeIndex, + 'time-sent': Date.now(), + contents: [], + hash: null, + signatures: [] + }, + children: childGraph + }; +}; +export const markPending = (nodes) => { + Object.keys(nodes).forEach((key) => { + nodes[key].post.author = deSig(nodes[key].post.author); + nodes[key].post.pending = true; + if (nodes[key].children) { + nodes[key].children = markPending(nodes[key].children); + } + }); + return nodes; +}; +export const createPost = (ship, contents, parentIndex = '', childIndex = 'DATE_PLACEHOLDER') => { + if (childIndex === 'DATE_PLACEHOLDER') { + childIndex = unixToDa(Date.now()).toString(); + } + return { + author: `~${ship}`, + index: parentIndex + '/' + childIndex, + 'time-sent': Date.now(), + contents, + hash: null, + signatures: [] + }; +}; +function moduleToMark(mod) { + if (mod === 'link') { + return 'graph-validator-link'; + } + if (mod === 'publish') { + return 'graph-validator-publish'; + } + if (mod === 'chat') { + return 'graph-validator-chat'; + } + return undefined; +} +const storeAction = (data, version = GRAPH_UPDATE_VERSION) => ({ + app: 'graph-store', + mark: `graph-update-${version}`, + json: data +}); +export { storeAction as graphStoreAction }; +const viewAction = (threadName, action) => ({ + inputMark: 'graph-view-action', + outputMark: 'json', + threadName, + body: action +}); +export { viewAction as graphViewAction }; +const hookAction = (data, version = GRAPH_UPDATE_VERSION) => ({ + app: 'graph-push-hook', + mark: `graph-update-${version}`, + json: data +}); +const dmAction = (data) => ({ + app: 'dm-hook', + mark: 'dm-hook-action', + json: data +}); +export { hookAction as graphHookAction }; +export const createManagedGraph = (ship, name, title, description, group, mod) => { + const associated = { group: resourceFromPath(group) }; + const resource = makeResource(`~${ship}`, name); + return viewAction('graph-create', { + create: { + resource, + title, + description, + associated, + module: mod, + mark: moduleToMark(mod) + } + }); +}; +export const createUnmanagedGraph = (ship, name, title, description, policy, mod) => viewAction('graph-create', { + create: { + resource: makeResource(`~${ship}`, name), + title, + description, + associated: { policy }, + module: mod, + mark: moduleToMark(mod) + } +}); +export const joinGraph = (ship, name) => viewAction('graph-join', { + join: { + resource: makeResource(ship, name), + ship + } +}); +export const deleteGraph = (ship, name) => viewAction('graph-delete', { + 'delete': { + resource: makeResource(`~${ship}`, name) + } +}); +export const leaveGraph = (ship, name) => viewAction('graph-leave', { + 'leave': { + resource: makeResource(ship, name) + } +}); +export const groupifyGraph = (ship, name, toPath) => { + const resource = makeResource(ship, name); + const to = toPath && resourceFromPath(toPath); + return viewAction('graph-groupify', { + groupify: { + resource, + to + } + }); +}; +export const evalCord = (cord) => { + return ({ + inputMark: 'graph-view-action', + outputMark: 'tang', + threadName: 'graph-eval', + body: { + eval: cord + } + }); +}; +export const addGraph = (ship, name, graph, mark) => { + return storeAction({ + 'add-graph': { + resource: { ship, name }, + graph, + mark + } + }); +}; +export const addNodes = (ship, name, nodes) => ({ + inputMark: `graph-update-${GRAPH_UPDATE_VERSION}`, + outputMark: 'graph-view-action', + threadName: 'graph-add-nodes', + body: { + 'add-nodes': { + resource: { ship, name }, + nodes + } + } +}); +export const addPost = (ship, name, post) => { + const nodes = {}; + nodes[post.index] = { + post, + children: null + }; + return addNodes(ship, name, nodes); +}; +export const addNode = (ship, name, node) => { + const nodes = {}; + nodes[node.post.index] = node; + return addNodes(ship, name, nodes); +}; +export const createGroupFeed = (group, vip = '') => ({ + inputMark: 'graph-view-action', + outputMark: 'resource', + threadName: 'graph-create-group-feed', + body: { + 'create-group-feed': { + resource: group, + vip + } + } +}); +export const disableGroupFeed = (group) => ({ + inputMark: 'graph-view-action', + outputMark: 'json', + threadName: 'graph-disable-group-feed', + body: { + 'disable-group-feed': { + resource: group + } + } +}); +/** + * Set dm-hook to screen new DMs or not + * + */ +export const setScreen = (screen) => dmAction({ screen }); +/** + * Accept a pending DM request + * + * @param ship the ship to accept + */ +export const acceptDm = (ship) => dmAction({ + accept: ship +}); +/** + * Decline a pending DM request + * + * @param ship the ship to accept + */ +export const declineDm = (ship) => dmAction({ + decline: ship +}); +/** + * Remove posts from a set of indices + * + */ +export const removePosts = (ship, name, indices) => hookAction({ + 'remove-posts': { + resource: { ship, name }, + indices + } +}); +/** + * Remove a DM message from our inbox + * + * @remarks + * This does not remove the message from the recipients inbox + */ +export const removeDmMessage = (our, index) => ({ + app: 'graph-store', + mark: `graph-update-${GRAPH_UPDATE_VERSION}`, + json: { + 'remove-posts': { + resource: { ship: our, name: 'dm-inbox' }, + indices: [index] + } + } +}); +/** + * Send a DM to a ship + * + * @param our sender + * @param ship recipient + * @param contents contents of message + */ +export const addDmMessage = (our, ship, contents) => { + const post = createPost(our, contents, `/${patp2dec(ship)}`); + const node = { + post, + children: null + }; + return { + app: 'dm-hook', + mark: `graph-update-${GRAPH_UPDATE_VERSION}`, + json: { + 'add-nodes': { + resource: { ship: `~${our}`, name: 'dm-inbox' }, + nodes: { + [post.index]: node + } + } + } + }; +}; +const encodeIndex = (idx) => idx.split('/').map(decToUd).join('/'); +/** + * Fetch newest (larger keys) nodes in a graph under some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export const getNewest = (ship, name, count, index = '') => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/siblings` + + `/newest/lone/${count}${encodeIndex(index)}` +}); +/** + * Fetch nodes in a graph that are older (key is smaller) and direct + * siblings of some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export const getOlderSiblings = (ship, name, count, index) => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/siblings/older/lone/${count}${encodeIndex(index)}` +}); +/** + * Fetch nodes in a graph that are younger (key is larger) and direct + * siblings of some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export const getYoungerSiblings = (ship, name, count, index) => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/siblings/newer/lone/${count}${encodeIndex(index)}` +}); +/** + * Fetch all nodes in a graph under some index, without loading children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + */ +export const getShallowChildren = (ship, name, index = '') => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/children/lone/~/~${encodeIndex(index)}` +}); +/** + * Fetch newest nodes in a graph as a flat map, including children, + * optionally starting at a specified key + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param start key to start at + * + */ +export const getDeepOlderThan = (ship, name, count, start = '') => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/siblings` + + `/${start.length > 0 ? 'older' : 'newest'}` + + `/kith/${count}${encodeIndex(start)}` +}); +/** + * Fetch a flat map of a nodes ancestors and firstborn children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + * + */ +export const getFirstborn = (ship, name, index) => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/firstborn${encodeIndex(index)}` +}); +/** + * Fetch a single node, and all it's children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + * + */ +export const getNode = (ship, name, index) => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/index/kith${encodeIndex(index)}` +}); +/** + * Fetch entire graph + * + * @param ship ship of graph + * @param name name of graph + * + */ +export const getGraph = (ship, name) => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}` +}); +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/lib.js.map b/pkg/npm/api/tmp/graph/lib.js.map new file mode 100644 index 000000000..e62f9fff2 --- /dev/null +++ b/pkg/npm/api/tmp/graph/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../graph/lib.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAY,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAQ,MAAM,QAAQ,CAAC;AAGxD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAEtC,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAC1C,IAAe,EACf,WAAW,GAAG,EAAE,EAChB,UAAU,GAAG,EAAE,EACf,QAAmB,EACJ,EAAE;IACjB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC7C,MAAM,SAAS,GAAG,WAAW,GAAG,GAAG,GAAG,IAAI,CAAC;IAE3C,MAAM,UAAU,GAAsB,EAAE,CAAC;IACzC,UAAU,CAAC,UAAU,CAAC,GAAG;QACvB,IAAI,EAAE;YACJ,MAAM,EAAE,IAAI,IAAI,EAAE;YAClB,KAAK,EAAE,SAAS,GAAG,GAAG,GAAG,UAAU;YACnC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;YACvB,QAAQ;YACR,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,EAAE;SACf;QACD,QAAQ,EAAE,IAAI;KACf,CAAC;IAEF,OAAO;QACL,IAAI,EAAE;YACJ,MAAM,EAAE,IAAI,IAAI,EAAE;YAClB,KAAK,EAAE,SAAS;YAChB,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;YACvB,QAAQ,EAAE,EAAE;YACZ,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,EAAE;SACf;QACD,QAAQ,EAAE,UAAU;KACrB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAU,EAAO,EAAE;IAC7C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QACjC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAC/B,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;YACvB,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;SACxD;IACH,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAe,EACf,QAAmB,EACnB,WAAW,GAAG,EAAE,EAChB,UAAU,GAAG,kBAAkB,EACzB,EAAE;IACR,IAAI,UAAU,KAAK,kBAAkB,EAAE;QACrC,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;KAC9C;IACD,OAAO;QACL,MAAM,EAAE,IAAI,IAAI,EAAE;QAClB,KAAK,EAAE,WAAW,GAAG,GAAG,GAAG,UAAU;QACrC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;QACvB,QAAQ;QACR,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE;KACf,CAAC;AACJ,CAAC,CAAC;AAEF,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAG,GAAG,KAAK,MAAM,EAAE;QACjB,OAAO,sBAAsB,CAAC;KAC/B;IACD,IAAG,GAAG,KAAK,SAAS,EAAE;QACpB,OAAO,yBAAyB,CAAC;KAClC;IACD,IAAG,GAAG,KAAK,MAAM,EAAE;QACjB,OAAO,sBAAsB,CAAC;KAC/B;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,WAAW,GAAG,CAAI,IAAO,EAAE,UAAkB,oBAAoB,EAAW,EAAE,CAAC,CAAC;IACpF,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,gBAAgB,OAAO,EAAE;IAC/B,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,OAAO,EAAE,WAAW,IAAI,gBAAgB,EAAE,CAAC;AAE3C,MAAM,UAAU,GAAG,CAAI,UAAkB,EAAE,MAAS,EAAa,EAAE,CAAC,CAAC;IACnE,SAAS,EAAE,mBAAmB;IAC9B,UAAU,EAAE,MAAM;IAClB,UAAU;IACV,IAAI,EAAE,MAAM;CACb,CAAC,CAAC;AAEH,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,CAAC;AAEzC,MAAM,UAAU,GAAG,CAAI,IAAO,EAAE,UAAkB,oBAAoB,EAAW,EAAE,CAAC,CAAC;IACnF,GAAG,EAAE,iBAAiB;IACtB,IAAI,EAAE,gBAAgB,OAAO,EAAE;IAC/B,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,CAAI,IAAO,EAAW,EAAE,CAAC,CAAC;IACzC,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,OAAO,EAAE,UAAU,IAAI,eAAe,EAAE,CAAC;AAEzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,IAAe,EACf,IAAY,EACZ,KAAa,EACb,WAAmB,EACnB,KAAW,EACX,GAAW,EACE,EAAE;IACf,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;IACtD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IAEhD,OAAO,UAAU,CAAC,cAAc,EAAE;QAChC,MAAM,EAAE;YACN,QAAQ;YACR,KAAK;YACL,WAAW;YACX,UAAU;YACV,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC;SACxB;KACF,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,IAAe,EACf,IAAY,EACZ,KAAa,EACb,WAAmB,EACnB,MAAwB,EACxB,GAAW,EACE,EAAE,CAAC,UAAU,CAAC,cAAc,EAAE;IAC3C,MAAM,EAAE;QACN,QAAQ,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC;QACxC,KAAK;QACL,WAAW;QACX,UAAU,EAAE,EAAE,MAAM,EAAE;QACtB,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC;KACxB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAU,EACV,IAAY,EACC,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE;IACzC,IAAI,EAAE;QACJ,QAAQ,EAAE,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC;QAClC,IAAI;KACL;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAe,EACf,IAAY,EACC,EAAE,CAAC,UAAU,CAAC,cAAc,EAAE;IAC3C,QAAQ,EAAE;QACR,QAAQ,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC;KACzC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAU,EACV,IAAY,EACC,EAAE,CAAC,UAAU,CAAC,aAAa,EAAE;IAC1C,OAAO,EAAE;QACP,QAAQ,EAAE,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC;KACnC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,IAAU,EACV,IAAY,EACZ,MAAe,EACF,EAAE;IACf,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAE9C,OAAO,UAAU,CAAC,gBAAgB,EAAE;QAClC,QAAQ,EAAE;YACR,QAAQ;YACR,EAAE;SACH;KACF,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACC,EAAE;IACf,OAAO,CAAC;QACN,SAAS,EAAE,mBAAmB;QAC9B,UAAU,EAAE,MAAM;QAClB,UAAU,EAAE,YAAY;QACxB,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI;SACX;KACF,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAU,EACV,IAAY,EACZ,KAAU,EACV,IAAS,EACE,EAAE;IACb,OAAO,WAAW,CAAC;QACjB,WAAW,EAAE;YACX,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;YACxB,KAAK;YACL,IAAI;SACL;KACF,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAU,EACV,IAAY,EACZ,KAAa,EACA,EAAE,CAAC,CAAC;IACjB,SAAS,EAAE,gBAAgB,oBAAoB,EAAE;IACjD,UAAU,EAAE,mBAAmB;IAC/B,UAAU,EAAE,iBAAiB;IAC7B,IAAI,EAAE;QACJ,WAAW,EAAE;YACX,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;YACxB,KAAK;SACN;KACF;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,IAAU,EACV,IAAY,EACZ,IAAU,EACG,EAAE;IACf,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG;QAClB,IAAI;QACJ,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,OAAO,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,IAAU,EACV,IAAY,EACZ,IAAmB,EACN,EAAE;IACf,MAAM,KAAK,GAAkC,EAAE,CAAC;IAChD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IAE9B,OAAO,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,KAAe,EACf,MAAW,EAAE,EACA,EAAE,CAAC,CAAC;IACjB,SAAS,EAAE,mBAAmB;IAC9B,UAAU,EAAE,UAAU;IACtB,UAAU,EAAE,yBAAyB;IACrC,IAAI,EAAE;QACJ,mBAAmB,EAAE;YACnB,QAAQ,EAAE,KAAK;YACf,GAAG;SACJ;KACF;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,KAAe,EACF,EAAE,CAAC,CAAC;IACjB,SAAS,EAAE,mBAAmB;IAC9B,UAAU,EAAE,MAAM;IAClB,UAAU,EAAE,0BAA0B;IACtC,IAAI,EAAE;QACJ,oBAAoB,EAAE;YACpB,QAAQ,EAAE,KAAK;SAChB;KACF;CACF,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAe,EAAa,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AAE9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,QAAQ,CAAC;IACjD,MAAM,EAAE,IAAI;CACb,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,QAAQ,CAAC;IAClD,OAAO,EAAE,IAAI;CACd,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAU,EACV,IAAY,EACZ,OAAiB,EACN,EAAE,CAAC,UAAU,CAAC;IACzB,cAAc,EAAE;QACd,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;QACxB,OAAO;KACR;CACF,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,GAAS,EACT,KAAa,EACF,EAAE,CAAC,CAAC;IACf,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,gBAAgB,oBAAoB,EAAE;IAC5C,IAAI,EAAE;QACJ,cAAc,EAAE;YACd,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE;YACzC,OAAO,EAAE,CAAC,KAAK,CAAC;SACjB;KACF;CACF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAc,EAAE,IAAU,EAAE,QAAmB,EAAa,EAAE;IACzF,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAc;QACtB,IAAI;QACJ,QAAQ,EAAE,IAAI;KACf,CAAC;IACF,OAAO;QACL,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,gBAAgB,oBAAoB,EAAE;QAC5C,IAAI,EAAE;YACJ,WAAW,EAAE;gBACX,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;gBAC/C,KAAK,EAAE;oBACL,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI;iBACnB;aACF;SACF;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE3E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAY,EACZ,IAAY,EACZ,KAAa,EACb,KAAK,GAAG,EAAE,EACJ,EAAE,CAAC,CAAC;IACV,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,UAAU,IAAI,IAAI,IAAI,gBAAgB;QACtC,gBAAgB,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE;CACnD,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,IAAY,EACZ,IAAY,EACZ,KAAa,EACb,KAAa,EACP,EAAE,CAAC,CAAC;IACV,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,UAAU,IAAI,IAAI,IAAI,6BAA6B,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE;CACtF,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,IAAY,EACZ,IAAY,EACZ,KAAa,EACb,KAAa,EACP,EAAE,CAAC,CAAC;IACV,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,UAAU,IAAI,IAAI,IAAI,6BAA6B,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE;CACtF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAE,IAAY,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7E,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,UAAU,IAAI,IAAI,IAAI,0BAA0B,WAAW,CAAC,KAAK,CAAC,EAAE;CAC3E,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,IAAY,EACZ,IAAY,EACZ,KAAa,EACb,KAAK,GAAG,EAAE,EACV,EAAE,CAAC,CAAC;IACJ,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,UAAU,IAAI,IAAI,IAAI,gBAAgB;QACtC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;QAC3C,SAAS,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE;CAC5C,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,IAAY,EACZ,IAAY,EACZ,KAAa,EACP,EAAE,CAAC,CAAC;IACV,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,UAAU,IAAI,IAAI,IAAI,kBAAkB,WAAW,CAAC,KAAK,CAAC,EAAE;CACnE,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,IAAY,EACZ,IAAY,EACZ,KAAa,EACP,EAAE,CAAC,CAAC;IACV,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,UAAU,IAAI,IAAI,IAAI,mBAAmB,WAAW,CAAC,KAAK,CAAC,EAAE;CACpE,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,IAAY,EACN,EAAE,CAAC,CAAC;IACV,GAAG,EAAE,aAAa;IAClB,IAAI,EAAE,UAAU,IAAI,IAAI,IAAI,EAAE;CAC/B,CAAC,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/types.d.ts b/pkg/npm/api/tmp/graph/types.d.ts new file mode 100644 index 000000000..2c18e0103 --- /dev/null +++ b/pkg/npm/api/tmp/graph/types.d.ts @@ -0,0 +1,76 @@ +import { Patp } from '../lib'; +import { BigIntOrderedMap } from '../lib/BigIntOrderedMap'; +import { BigIntArrayOrderedMap } from '../lib/BigIntArrayOrderedMap'; +export interface TextContent { + text: string; +} +export interface UrlContent { + url: string; +} +export interface CodeContent { + code: { + expression: string; + output: string[] | undefined; + }; +} +export interface ReferenceContent { + reference: AppReference | GraphReference | GroupReference; +} +export interface GraphReference { + graph: { + graph: string; + group: string; + index: string; + }; +} +export interface GroupReference { + group: string; +} +export interface AppReference { + app: { + ship: string; + desk: string; + path: string; + }; +} +export interface MentionContent { + mention: string; +} +export declare type Content = TextContent | UrlContent | CodeContent | ReferenceContent | MentionContent; +export interface Post { + author: Patp; + contents: Content[]; + hash: string | null; + index: string; + pending?: boolean; + signatures: string[]; + 'time-sent': number; +} +export interface GraphNodePoke { + post: Post; + children: GraphChildrenPoke | null; +} +export interface GraphChildrenPoke { + [k: string]: GraphNodePoke; +} +export interface GraphNode { + children: Graph | null; + post: Post; +} +export interface FlatGraphNode { + children: null; + post: Post; +} +export declare type Graph = BigIntOrderedMap; +export declare type Graphs = { + [rid: string]: Graph; +}; +export declare type FlatGraph = BigIntArrayOrderedMap; +export declare type FlatGraphs = { + [rid: string]: FlatGraph; +}; +export declare type ThreadGraphs = { + [rid: string]: { + [index: string]: FlatGraph; + }; +}; diff --git a/pkg/npm/api/tmp/graph/types.js b/pkg/npm/api/tmp/graph/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/graph/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/types.js.map b/pkg/npm/api/tmp/graph/types.js.map new file mode 100644 index 000000000..7a3e71902 --- /dev/null +++ b/pkg/npm/api/tmp/graph/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../graph/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/index.d.ts b/pkg/npm/api/tmp/groups/index.d.ts new file mode 100644 index 000000000..4a272fce5 --- /dev/null +++ b/pkg/npm/api/tmp/groups/index.d.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; diff --git a/pkg/npm/api/tmp/groups/index.js b/pkg/npm/api/tmp/groups/index.js new file mode 100644 index 000000000..5c8443c9d --- /dev/null +++ b/pkg/npm/api/tmp/groups/index.js @@ -0,0 +1,3 @@ +export * from './types'; +export * from './lib'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/index.js.map b/pkg/npm/api/tmp/groups/index.js.map new file mode 100644 index 000000000..387cd9ddb --- /dev/null +++ b/pkg/npm/api/tmp/groups/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../groups/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/lib.d.ts b/pkg/npm/api/tmp/groups/lib.d.ts new file mode 100644 index 000000000..a75a837a8 --- /dev/null +++ b/pkg/npm/api/tmp/groups/lib.d.ts @@ -0,0 +1,40 @@ +import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types'; +import { Group, GroupPolicy, GroupPolicyDiff, GroupUpdateAddMembers, GroupUpdateAddTag, GroupUpdateChangePolicy, GroupUpdateRemoveGroup, GroupUpdateRemoveMembers, GroupUpdateRemoveTag, Resource, RoleTags, Tag } from './types'; +import { GroupUpdate } from './update'; +export declare const GROUP_UPDATE_VERSION = 0; +export declare const proxyAction: (data: T, version?: number) => Poke; +declare const storeAction: (data: T, version?: number) => Poke; +export { storeAction as groupStoreAction }; +declare const viewAction: (data: T) => Poke; +export { viewAction as groupViewAction }; +export declare const viewThread: (thread: string, action: T) => Thread; +export declare const removeMembers: (resource: Resource, ships: PatpNoSig[]) => Poke; +export declare const addTag: (resource: Resource, tag: Tag, ships: Patp[]) => Poke; +export declare const removeTag: (tag: Tag, resource: Resource, ships: PatpNoSig[]) => Poke; +export declare const addMembers: (resource: Resource, ships: PatpNoSig[]) => Poke; +export declare const removeGroup: (resource: Resource) => Poke; +export declare const changePolicy: (resource: Resource, diff: Enc) => Poke>; +export declare const makeResource: (ship: string, name: string) => { + ship: string; + name: string; +}; +export declare const join: (ship: string, name: string, app: "groups" | "graph", autojoin: boolean, share: boolean) => Poke; +export declare const createGroup: (name: string, policy: Enc, title: string, description: string) => Thread; +export declare const deleteGroup: (ship: string, name: string) => Thread; +export declare const leaveGroup: (ship: string, name: string) => Thread; +export declare const invite: (ship: string, name: string, ships: Patp[], description: string) => Thread; +export declare const abortJoin: (resource: string) => Poke; +export declare const roleTags: string[]; +export declare const groupBunts: { + group: () => Group; + policy: () => GroupPolicy; +}; +export declare const joinError: readonly ["no-perms", "strange", "abort"]; +export declare const joinResult: readonly ["done", "no-perms", "strange", "abort"]; +export declare const joinLoad: readonly ["start", "added", "metadata"]; +export declare const joinProgress: readonly ["start", "added", "metadata", "done", "no-perms", "strange", "abort"]; +export declare const roleForShip: (group: Group, ship: PatpNoSig) => RoleTags | undefined; +export declare const resourceFromPath: (path: Path) => Resource; +export declare const isWriter: (group: Group, resource: string, ship: string) => boolean; +export declare const isHost: (resource: string, ship: string) => boolean; +export declare const isChannelAdmin: (group: Group, resource: string, ship: string) => boolean; diff --git a/pkg/npm/api/tmp/groups/lib.js b/pkg/npm/api/tmp/groups/lib.js new file mode 100644 index 000000000..e2d572986 --- /dev/null +++ b/pkg/npm/api/tmp/groups/lib.js @@ -0,0 +1,139 @@ +export const GROUP_UPDATE_VERSION = 0; +export const proxyAction = (data, version = GROUP_UPDATE_VERSION) => ({ + app: 'group-push-hook', + mark: `group-update-${version}`, + json: data +}); +const storeAction = (data, version = GROUP_UPDATE_VERSION) => ({ + app: 'group-store', + mark: `group-update-${version}`, + json: data +}); +export { storeAction as groupStoreAction }; +const viewAction = (data) => ({ + app: 'group-view', + mark: 'group-view-action', + json: data +}); +export { viewAction as groupViewAction }; +export const viewThread = (thread, action) => ({ + inputMark: 'group-view-action', + outputMark: 'json', + threadName: thread, + body: action +}); +export const removeMembers = (resource, ships) => proxyAction({ + removeMembers: { + resource, + ships + } +}); +export const addTag = (resource, tag, ships) => proxyAction({ + addTag: { + resource, + tag, + ships + } +}); +export const removeTag = (tag, resource, ships) => proxyAction({ + removeTag: { + tag, + resource, + ships + } +}); +export const addMembers = (resource, ships) => proxyAction({ + addMembers: { + resource, + ships + } +}); +export const removeGroup = (resource) => storeAction({ + removeGroup: { + resource + } +}); +export const changePolicy = (resource, diff) => proxyAction({ + changePolicy: { + resource, + diff + } +}); +export const makeResource = (ship, name) => { + return { ship, name }; +}; +export const join = (ship, name, app, autojoin, share) => viewAction({ + join: { + resource: makeResource(ship, name), + ship, + shareContact: share || false, + app, + autojoin + } +}); +export const createGroup = (name, policy, title, description) => viewThread('group-create', { + create: { + name, + policy, + title, + description + } +}); +export const deleteGroup = (ship, name) => viewThread('group-delete', { + remove: makeResource(ship, name) +}); +export const leaveGroup = (ship, name) => viewThread('group-leave', { + leave: makeResource(ship, name) +}); +export const invite = (ship, name, ships, description) => viewThread('group-invite', { + invite: { + resource: makeResource(ship, name), + ships, + description + } +}); +export const abortJoin = (resource) => viewAction({ + abort: resource +}); +export const roleTags = ['janitor', 'moderator', 'admin']; +// TODO make this type better? +export const groupBunts = { + group: () => ({ members: new Set(), tags: { role: {} }, hidden: false, policy: groupBunts.policy() }), + policy: () => ({ open: { banned: new Set(), banRanks: new Set() } }) +}; +export const joinError = ['no-perms', 'strange', 'abort']; +export const joinResult = ['done', ...joinError]; +export const joinLoad = ['start', 'added', 'metadata']; +export const joinProgress = [...joinLoad, ...joinResult]; +export const roleForShip = (group, ship) => { + return roleTags.reduce((currRole, role) => { + const roleShips = group?.tags?.role?.[role]; + return roleShips && roleShips.has(ship) ? role : currRole; + }, undefined); +}; +export const resourceFromPath = (path) => { + const [, , ship, name] = path.split('/'); + return { ship, name }; +}; +export const isWriter = (group, resource, ship) => { + const graph = group.tags?.graph; + const writers = graph && graph[resource]?.writers; + const admins = group?.tags?.role?.admin ?? new Set(); + if (typeof writers === 'undefined') { + return true; + } + else { + return writers.has(ship) || admins.has(ship); + } +}; +export const isHost = (resource, ship) => { + const [, , host] = resource.split('/'); + return ship === host; +}; +export const isChannelAdmin = (group, resource, ship) => { + const role = roleForShip(group, ship.slice(1)); + return (isHost(resource, ship) || + role === 'admin' || + role === 'moderator'); +}; +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/lib.js.map b/pkg/npm/api/tmp/groups/lib.js.map new file mode 100644 index 000000000..6c2d70922 --- /dev/null +++ b/pkg/npm/api/tmp/groups/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../groups/lib.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/types.d.ts b/pkg/npm/api/tmp/groups/types.d.ts new file mode 100644 index 000000000..b838383f1 --- /dev/null +++ b/pkg/npm/api/tmp/groups/types.d.ts @@ -0,0 +1,2 @@ +export * from './update'; +export * from './view'; diff --git a/pkg/npm/api/tmp/groups/types.js b/pkg/npm/api/tmp/groups/types.js new file mode 100644 index 000000000..fe3fba155 --- /dev/null +++ b/pkg/npm/api/tmp/groups/types.js @@ -0,0 +1,3 @@ +export * from './update'; +export * from './view'; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/types.js.map b/pkg/npm/api/tmp/groups/types.js.map new file mode 100644 index 000000000..e7f9f68e8 --- /dev/null +++ b/pkg/npm/api/tmp/groups/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../groups/types.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/update.d.ts b/pkg/npm/api/tmp/groups/update.d.ts new file mode 100644 index 000000000..a8e74a551 --- /dev/null +++ b/pkg/npm/api/tmp/groups/update.d.ts @@ -0,0 +1,133 @@ +import { PatpNoSig, Path, ShipRank, Enc } from '../lib'; +import { roleTags } from './index'; +export declare type RoleTags = typeof roleTags[number]; +interface RoleTag { + tag: 'admin' | 'moderator' | 'janitor'; +} +interface AppTag { + app: string; + resource: string; + tag: string; +} +export declare type Tag = AppTag | RoleTag; +export interface InvitePolicy { + invite: { + pending: Set; + }; +} +export interface OpenPolicy { + open: { + banned: Set; + banRanks: Set; + }; +} +export interface Resource { + name: string; + ship: PatpNoSig; +} +export declare type OpenPolicyDiff = AllowRanksDiff | BanRanksDiff | AllowShipsDiff | BanShipsDiff; +export interface AllowRanksDiff { + allowRanks: ShipRank[]; +} +export interface BanRanksDiff { + banRanks: ShipRank[]; +} +export interface AllowShipsDiff { + allowShips: PatpNoSig[]; +} +export interface BanShipsDiff { + banShips: PatpNoSig[]; +} +export declare type InvitePolicyDiff = AddInvitesDiff | RemoveInvitesDiff; +export interface AddInvitesDiff { + addInvites: PatpNoSig[]; +} +export interface RemoveInvitesDiff { + removeInvites: PatpNoSig[]; +} +export interface ReplacePolicyDiff { + replace: GroupPolicy; +} +export declare type GroupPolicyDiff = { + open: OpenPolicyDiff; +} | { + invite: InvitePolicyDiff; +} | ReplacePolicyDiff; +export declare type GroupPolicy = OpenPolicy | InvitePolicy; +export interface TaggedShips { + [tag: string]: Set; +} +export interface Tags { + role: TaggedShips; + [app: string]: TaggedShips; +} +export interface Group { + members: Set; + tags: Tags; + policy: GroupPolicy; + hidden: boolean; +} +export declare type Groups = { + [p in Path]: Group; +}; +export interface GroupUpdateInitial { + initial: Enc; +} +export interface GroupUpdateAddGroup { + addGroup: { + resource: Resource; + policy: Enc; + hidden: boolean; + }; +} +export interface GroupUpdateAddMembers { + addMembers: { + ships: PatpNoSig[]; + resource: Resource; + }; +} +export interface GroupUpdateRemoveMembers { + removeMembers: { + ships: PatpNoSig[]; + resource: Resource; + }; +} +export interface GroupUpdateAddTag { + addTag: { + tag: Tag; + resource: Resource; + ships: PatpNoSig[]; + }; +} +export interface GroupUpdateRemoveTag { + removeTag: { + tag: Tag; + resource: Resource; + ships: PatpNoSig[]; + }; +} +export interface GroupUpdateChangePolicy { + changePolicy: { + resource: Resource; + diff: GroupPolicyDiff; + }; +} +export interface GroupUpdateRemoveGroup { + removeGroup: { + resource: Resource; + }; +} +export interface GroupUpdateExpose { + expose: { + resource: Resource; + }; +} +export interface GroupUpdateInitialGroup { + initialGroup: { + resource: Resource; + group: Enc; + }; +} +export declare type GroupUpdate = GroupUpdateInitial | GroupUpdateAddGroup | GroupUpdateAddMembers | GroupUpdateRemoveMembers | GroupUpdateAddTag | GroupUpdateRemoveTag | GroupUpdateChangePolicy | GroupUpdateRemoveGroup | GroupUpdateExpose | GroupUpdateInitialGroup; +export declare type GroupAction = Omit; +export {}; diff --git a/pkg/npm/api/tmp/groups/update.js b/pkg/npm/api/tmp/groups/update.js new file mode 100644 index 000000000..3a8140041 --- /dev/null +++ b/pkg/npm/api/tmp/groups/update.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=update.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/update.js.map b/pkg/npm/api/tmp/groups/update.js.map new file mode 100644 index 000000000..67c69672f --- /dev/null +++ b/pkg/npm/api/tmp/groups/update.js.map @@ -0,0 +1 @@ +{"version":3,"file":"update.js","sourceRoot":"","sources":["../../groups/update.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/view.d.ts b/pkg/npm/api/tmp/groups/view.d.ts new file mode 100644 index 000000000..9e8010ef7 --- /dev/null +++ b/pkg/npm/api/tmp/groups/view.d.ts @@ -0,0 +1,24 @@ +import { joinError, joinProgress, joinResult } from "."; +import { Patp } from "../lib"; +export declare type JoinError = typeof joinError[number]; +export declare type JoinResult = typeof joinResult[number]; +export declare type JoinProgress = typeof joinProgress[number]; +export interface JoinRequest { + /** + * Whether to display the join request or not + */ + hidden: boolean; + /** + * Timestamp of when the request started + */ + started: number; + ship: Patp; + progress: JoinProgress; + shareContact: boolean; + autojoin: boolean; + app: 'graph' | 'groups'; + invite: string[]; +} +export interface JoinRequests { + [rid: string]: JoinRequest; +} diff --git a/pkg/npm/api/tmp/groups/view.js b/pkg/npm/api/tmp/groups/view.js new file mode 100644 index 000000000..d8198797a --- /dev/null +++ b/pkg/npm/api/tmp/groups/view.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=view.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/view.js.map b/pkg/npm/api/tmp/groups/view.js.map new file mode 100644 index 000000000..000c52048 --- /dev/null +++ b/pkg/npm/api/tmp/groups/view.js.map @@ -0,0 +1 @@ +{"version":3,"file":"view.js","sourceRoot":"","sources":["../../groups/view.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/index.d.ts b/pkg/npm/api/tmp/hark/index.d.ts new file mode 100644 index 000000000..4a272fce5 --- /dev/null +++ b/pkg/npm/api/tmp/hark/index.d.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; diff --git a/pkg/npm/api/tmp/hark/index.js b/pkg/npm/api/tmp/hark/index.js new file mode 100644 index 000000000..5c8443c9d --- /dev/null +++ b/pkg/npm/api/tmp/hark/index.js @@ -0,0 +1,3 @@ +export * from './types'; +export * from './lib'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/index.js.map b/pkg/npm/api/tmp/hark/index.js.map new file mode 100644 index 000000000..8624fd26f --- /dev/null +++ b/pkg/npm/api/tmp/hark/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../hark/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/lib.d.ts b/pkg/npm/api/tmp/hark/lib.d.ts new file mode 100644 index 000000000..3b75f25f2 --- /dev/null +++ b/pkg/npm/api/tmp/hark/lib.d.ts @@ -0,0 +1,46 @@ +import { BigInteger } from 'big-integer'; +import { Poke } from '../lib/types'; +import { HarkBin, HarkBinId, HarkLid, HarkPlace } from './types'; +export declare const harkAction: (data: T) => Poke; +declare const graphHookAction: (data: T) => Poke; +export { graphHookAction as harkGraphHookAction }; +declare const groupHookAction: (data: T) => Poke; +export { groupHookAction as harkGroupHookAction }; +export declare const actOnNotification: (frond: string, intTime: BigInteger, bin: HarkBin) => Poke; +export declare const setMentions: (mentions: boolean) => Poke; +export declare const setWatchOnSelf: (watchSelf: boolean) => Poke; +export declare const setDoNotDisturb: (dnd: boolean) => Poke; +export declare const archive: (bin: HarkBin, lid: HarkLid) => Poke; +export declare const opened: Poke<{ + opened: any; +}>; +export declare const markCountAsRead: (place: HarkPlace) => Poke; +export declare const markEachAsRead: (place: HarkPlace, path: string) => Poke; +export declare const seen: () => Poke<{ + seen: any; +}>; +export declare const readAll: Poke<{ + 'read-all': any; +}>; +export declare const archiveAll: Poke<{ + 'archive-all': any; +}>; +export declare const ignoreGroup: (group: string) => Poke; +export declare const ignoreGraph: (graph: string, index: string) => Poke; +export declare const listenGroup: (group: string) => Poke; +export declare const listenGraph: (graph: string, index: string) => Poke; +/** + * Read all graphs belonging to a particular group + */ +export declare const readGroup: (group: string) => Poke<{ + 'read-group': string; +}>; +/** + * Read all unreads in a graph + */ +export declare const readGraph: (graph: string) => Poke<{ + 'read-graph': string; +}>; +export declare function harkBinToId(bin: HarkBin): HarkBinId; +export declare function harkBinEq(a: HarkBin, b: HarkBin): boolean; +export declare function harkLidToId(lid: HarkLid): string; diff --git a/pkg/npm/api/tmp/hark/lib.js b/pkg/npm/api/tmp/hark/lib.js new file mode 100644 index 000000000..7ea20b407 --- /dev/null +++ b/pkg/npm/api/tmp/hark/lib.js @@ -0,0 +1,100 @@ +import { decToUd } from '../lib'; +export const harkAction = (data) => ({ + app: 'hark-store', + mark: 'hark-action', + json: data +}); +const graphHookAction = (data) => ({ + app: 'hark-graph-hook', + mark: 'hark-graph-hook-action', + json: data +}); +export { graphHookAction as harkGraphHookAction }; +const groupHookAction = (data) => ({ + app: 'hark-group-hook', + mark: 'hark-group-hook-action', + json: data +}); +export { groupHookAction as harkGroupHookAction }; +export const actOnNotification = (frond, intTime, bin) => harkAction({ + [frond]: { + time: decToUd(intTime.toString()), + bin + } +}); +export const setMentions = (mentions) => graphHookAction({ + 'set-mentions': mentions +}); +export const setWatchOnSelf = (watchSelf) => graphHookAction({ + 'set-watch-on-self': watchSelf +}); +export const setDoNotDisturb = (dnd) => harkAction({ + 'set-dnd': dnd +}); +export const archive = (bin, lid) => harkAction({ + archive: { + lid, + bin + } +}); +export const opened = harkAction({ + opened: null +}); +export const markCountAsRead = (place) => harkAction({ + 'read-count': place +}); +export const markEachAsRead = (place, path) => harkAction({ + 'read-each': { + place, + path + } +}); +export const seen = () => harkAction({ seen: null }); +export const readAll = harkAction({ 'read-all': null }); +export const archiveAll = harkAction({ 'archive-all': null }); +export const ignoreGroup = (group) => groupHookAction({ + ignore: group +}); +export const ignoreGraph = (graph, index) => graphHookAction({ + ignore: { + graph, + index + } +}); +export const listenGroup = (group) => groupHookAction({ + listen: group +}); +export const listenGraph = (graph, index) => graphHookAction({ + listen: { + graph, + index + } +}); +/** + * Read all graphs belonging to a particular group + */ +export const readGroup = (group) => harkAction({ + 'read-group': group +}); +/** + * Read all unreads in a graph + */ +export const readGraph = (graph) => harkAction({ + 'read-graph': graph +}); +export function harkBinToId(bin) { + const { place, path } = bin; + return `${place.desk}${place.path}${path}`; +} +export function harkBinEq(a, b) { + return (a.place.path === b.place.path && + a.place.desk === b.place.desk && + a.path === b.path); +} +export function harkLidToId(lid) { + if ('time' in lid) { + return `archive-${lid.time}`; + } + return Object.keys(lid)[0]; +} +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/lib.js.map b/pkg/npm/api/tmp/hark/lib.js.map new file mode 100644 index 000000000..8915f9d06 --- /dev/null +++ b/pkg/npm/api/tmp/hark/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../hark/lib.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/types.d.ts b/pkg/npm/api/tmp/hark/types.d.ts new file mode 100644 index 000000000..475a0a62a --- /dev/null +++ b/pkg/npm/api/tmp/hark/types.d.ts @@ -0,0 +1,55 @@ +export interface HarkStats { + count: number; + each: string[]; + last: number; +} +export interface Timebox { + [binId: string]: Notification; +} +export declare type HarkContent = { + ship: string; +} | { + text: string; +}; +export interface HarkBody { + title: HarkContent[]; + time: string; + content: HarkContent[]; + link: string; + binned: string; +} +export interface HarkPlace { + desk: string; + path: string; +} +export interface HarkBin { + path: string; + place: HarkPlace; +} +export declare type HarkLid = { + unseen: null; +} | { + seen: null; +} | { + time: string; +}; +export declare type HarkBinId = string; +export interface Notification { + bin: HarkBin; + time: number; + body: HarkBody[]; +} +export interface NotificationGraphConfig { + watchOnSelf: boolean; + mentions: boolean; + watching: WatchedIndex[]; +} +export interface Unreads { + [path: string]: HarkStats; +} +interface WatchedIndex { + graph: string; + index: string; +} +export declare type GroupNotificationsConfig = string[]; +export {}; diff --git a/pkg/npm/api/tmp/hark/types.js b/pkg/npm/api/tmp/hark/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/hark/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/types.js.map b/pkg/npm/api/tmp/hark/types.js.map new file mode 100644 index 000000000..cc26b3540 --- /dev/null +++ b/pkg/npm/api/tmp/hark/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../hark/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/index.d.ts b/pkg/npm/api/tmp/hood/index.d.ts new file mode 100644 index 000000000..e06143cf1 --- /dev/null +++ b/pkg/npm/api/tmp/hood/index.d.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/pkg/npm/api/tmp/hood/index.js b/pkg/npm/api/tmp/hood/index.js new file mode 100644 index 000000000..872ee0de4 --- /dev/null +++ b/pkg/npm/api/tmp/hood/index.js @@ -0,0 +1,3 @@ +export * from './lib'; +export * from './types'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/index.js.map b/pkg/npm/api/tmp/hood/index.js.map new file mode 100644 index 000000000..deed8c74e --- /dev/null +++ b/pkg/npm/api/tmp/hood/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../hood/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/lib.d.ts b/pkg/npm/api/tmp/hood/lib.d.ts new file mode 100644 index 000000000..3886ad812 --- /dev/null +++ b/pkg/npm/api/tmp/hood/lib.d.ts @@ -0,0 +1,34 @@ +import { Poke, Scry } from '../lib'; +import { Vats, Vat } from './types'; +export declare const getVats: Scry; +/** + * Install a foreign desk + */ +export declare function kilnInstall(ship: string, desk: string, local?: string): Poke; +/** + * Uninstall a desk + */ +export declare function kilnUninstall(desk: string): Poke; +export declare function kilnSuspend(desk: string): Poke; +export declare function kilnRevive(desk: string): Poke; +export declare function kilnBump(force?: boolean, except?: string[]): { + app: string; + mark: string; + json: { + force: boolean; + except: string[]; + }; +}; +export declare function kilnPause(desk: string): { + app: string; + mark: string; + json: string; +}; +export declare function kilnResume(desk: string): { + app: string; + mark: string; + json: string; +}; +export declare const scryLag: Scry; +export declare function getBlockers(vats: Vats): string[]; +export declare function getVatPublisher(vat: Vat): string | undefined; diff --git a/pkg/npm/api/tmp/hood/lib.js b/pkg/npm/api/tmp/hood/lib.js new file mode 100644 index 000000000..885f9395b --- /dev/null +++ b/pkg/npm/api/tmp/hood/lib.js @@ -0,0 +1,97 @@ +export const getVats = { + app: 'hood', + path: '/kiln/vats' +}; +/** + * Install a foreign desk + */ +export function kilnInstall(ship, desk, local) { + return { + app: 'hood', + mark: 'kiln-install', + json: { + ship, + desk, + local: local || desk + } + }; +} +/** + * Uninstall a desk + */ +export function kilnUninstall(desk) { + return { + app: 'hood', + mark: 'kiln-uninstall', + json: desk + }; +} +export function kilnSuspend(desk) { + return { + app: 'hood', + mark: 'kiln-suspend', + json: desk + }; +} +export function kilnRevive(desk) { + return { + app: 'hood', + mark: 'kiln-revive', + json: desk + }; +} +export function kilnBump(force = false, except = []) { + return { + app: 'hood', + mark: 'kiln-bump', + json: { + force, + except + } + }; +} +export function kilnPause(desk) { + return { + app: 'hood', + mark: 'kiln-pause', + json: desk + }; +} +export function kilnResume(desk) { + return { + app: 'hood', + mark: 'kiln-resume', + json: desk + }; +} +export const scryLag = ({ app: 'hood', path: '/kiln/lag' }); +export function getBlockers(vats) { + const blockers = []; + const base = vats?.base; + if (!base) { + return blockers; + } + const blockedOn = base.arak.rail?.next?.[0]?.weft?.kelvin; + if (!blockedOn) { + return blockers; + } + Object.entries(vats) + .filter(([desk]) => desk !== 'base') + .forEach(([desk, vat]) => { + // assuming only %zuse + const woofs = vat.arak.rail?.next || []; + const kelvins = woofs.map(n => n.weft.kelvin); + if (!(kelvins.includes(blockedOn))) { + blockers.push(desk); + } + }); + return blockers; +} +export function getVatPublisher(vat) { + if (vat.arak.rail) { + const { rail } = vat.arak; + return (rail?.publisher || rail?.ship || undefined); + } + return undefined; +} +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/lib.js.map b/pkg/npm/api/tmp/hood/lib.js.map new file mode 100644 index 000000000..79f13c95f --- /dev/null +++ b/pkg/npm/api/tmp/hood/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../hood/lib.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/types.d.ts b/pkg/npm/api/tmp/hood/types.d.ts new file mode 100644 index 000000000..92ff9ed7c --- /dev/null +++ b/pkg/npm/api/tmp/hood/types.d.ts @@ -0,0 +1,145 @@ +/** + * A pending commit, awaiting a future kelvin version + */ +interface Woof { + aeon: number; + weft: Weft; +} +interface Rein { + /** + * Agents not in manifest that should be running + */ + add: string[]; + /** + * Agents in manifest that should not be running + */ + sub: string[]; +} +export interface Rail { + /** + * Original publisher of desk, if available + */ + publisher: string | null; + /** + * Ship of foreign vat + */ + ship: string; + /** + * Desk of foreign vat + */ + desk: string; + /** + * Aeon (version number) that we currently have synced + */ + aeon: number; + next: Woof[]; + paused: boolean; +} +/** + * A tracker of a foreign {@link Vat} + * + */ +export interface Arak { + rein: Rein; + rail: Rail | null; +} +/** + * A component's kelvin version + */ +export interface Weft { + /** + * Name of the component + * + * @remarks + * Usually %zuse, %hoon, or %lull + */ + name: string; + /** + * Kelvin version + * + */ + kelvin: number; +} +export interface KilnDiffBlock { + block: { + desk: string; + arak: Arak; + weft: Weft; + blockers: string[]; + }; +} +export interface KilnDiffReset { + reset: { + desk: string; + arak: Arak; + }; +} +export interface KilnDiffMerge { + merge: { + desk: string; + arak: Arak; + }; +} +export interface KilnDiffMergeSunk { + 'merge-sunk': { + desk: string; + arak: Arak; + tang: string; + }; +} +export interface KilnDiffMergeFail { + 'merge-fail': { + desk: string; + arak: Arak; + tang: string; + }; +} +export declare type KilnDiff = KilnDiffBlock | KilnDiffReset | KilnDiffMerge | KilnDiffMergeSunk | KilnDiffMergeFail; +/** + * Cases for revision + * + */ +export interface Cass { + /** + * Revision number + */ + ud: number; + /** + * Timestamp of revision, as stringifed `@da` + * + * @remarks + * If \@da is outside valid positive unix timestamp, value will be zero + */ + da: string; +} +/** + * A local desk installation + */ +export interface Vat { + /** + * Desk that this Vat describes + */ + desk: string; + /** + * Hash of the desk, rendered as `@uv` + * + * @remarks + * Equivalent to + * ```hoon + * .^(@uv %cz /=desk=) + * ``` + */ + hash: string; + /** + * Current revision + */ + cass: Cass; + /** + * Foreign sync + */ + arak: Arak; +} +export interface Vats { + [desk: string]: Vat; +} +export {}; diff --git a/pkg/npm/api/tmp/hood/types.js b/pkg/npm/api/tmp/hood/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/hood/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/types.js.map b/pkg/npm/api/tmp/hood/types.js.map new file mode 100644 index 000000000..bbc8fe4cb --- /dev/null +++ b/pkg/npm/api/tmp/hood/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../hood/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/index.d.ts b/pkg/npm/api/tmp/index.d.ts new file mode 100644 index 000000000..b0576ccfe --- /dev/null +++ b/pkg/npm/api/tmp/index.d.ts @@ -0,0 +1,22 @@ +export * from './contacts'; +export * as contacts from './contacts'; +export * from './graph'; +export * as graph from './graph'; +export * from './groups'; +export * as groups from './groups'; +export * from './hark'; +export * as hark from './hark'; +export * from './invite'; +export * from './metadata'; +export * as metadata from './metadata'; +export * from './settings'; +export * as settings from './settings'; +export * from './s3'; +export * as s3 from './s3'; +export * from './lib'; +export * from './lib/BigIntOrderedMap'; +export * from './lib/BigIntArrayOrderedMap'; +export * as hood from './hood'; +export * from './hood'; +export * as docket from './docket'; +export * from './docket'; diff --git a/pkg/npm/api/tmp/index.js b/pkg/npm/api/tmp/index.js new file mode 100644 index 000000000..75b48a634 --- /dev/null +++ b/pkg/npm/api/tmp/index.js @@ -0,0 +1,25 @@ +export * from './contacts'; +export * as contacts from './contacts'; +export * from './graph'; +export * as graph from './graph'; +export * from './groups'; +export * as groups from './groups'; +export * from './hark'; +export * as hark from './hark'; +export * from './invite'; +// this conflicts with /groups/lib invite +// export * as invite from './invite'; +export * from './metadata'; +export * as metadata from './metadata'; +export * from './settings'; +export * as settings from './settings'; +export * from './s3'; +export * as s3 from './s3'; +export * from './lib'; +export * from './lib/BigIntOrderedMap'; +export * from './lib/BigIntArrayOrderedMap'; +export * as hood from './hood'; +export * from './hood'; +export * as docket from './docket'; +export * from './docket'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/index.js.map b/pkg/npm/api/tmp/index.js.map new file mode 100644 index 000000000..91d106aaf --- /dev/null +++ b/pkg/npm/api/tmp/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,cAAc,SAAS,CAAC;AACxB,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,cAAc,QAAQ,CAAC;AACvB,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,yCAAyC;AACzC,sCAAsC;AACtC,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,cAAc,MAAM,CAAC;AACrB,OAAO,KAAK,EAAE,MAAM,MAAM,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,cAAc,UAAU,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/index.d.ts b/pkg/npm/api/tmp/invite/index.d.ts new file mode 100644 index 000000000..4a272fce5 --- /dev/null +++ b/pkg/npm/api/tmp/invite/index.d.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; diff --git a/pkg/npm/api/tmp/invite/index.js b/pkg/npm/api/tmp/invite/index.js new file mode 100644 index 000000000..5c8443c9d --- /dev/null +++ b/pkg/npm/api/tmp/invite/index.js @@ -0,0 +1,3 @@ +export * from './types'; +export * from './lib'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/index.js.map b/pkg/npm/api/tmp/invite/index.js.map new file mode 100644 index 000000000..ebd16bd59 --- /dev/null +++ b/pkg/npm/api/tmp/invite/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../invite/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/lib.d.ts b/pkg/npm/api/tmp/invite/lib.d.ts new file mode 100644 index 000000000..e8c18e884 --- /dev/null +++ b/pkg/npm/api/tmp/invite/lib.d.ts @@ -0,0 +1,5 @@ +import { Poke, Serial } from "../lib"; +import { InviteUpdate, InviteUpdateAccept, InviteUpdateDecline } from "./types"; +export declare const inviteAction: (data: T) => Poke; +export declare const accept: (app: string, uid: Serial) => Poke; +export declare const decline: (app: string, uid: Serial) => Poke; diff --git a/pkg/npm/api/tmp/invite/lib.js b/pkg/npm/api/tmp/invite/lib.js new file mode 100644 index 000000000..db7195c3c --- /dev/null +++ b/pkg/npm/api/tmp/invite/lib.js @@ -0,0 +1,18 @@ +export const inviteAction = (data) => ({ + app: 'invite-store', + mark: 'invite-action', + json: data +}); +export const accept = (app, uid) => inviteAction({ + accept: { + term: app, + uid + } +}); +export const decline = (app, uid) => inviteAction({ + decline: { + term: app, + uid + } +}); +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/lib.js.map b/pkg/npm/api/tmp/invite/lib.js.map new file mode 100644 index 000000000..8cfb7eaa2 --- /dev/null +++ b/pkg/npm/api/tmp/invite/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../invite/lib.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAyB,IAAO,EAAW,EAAE,CAAC,CAAC;IACzE,GAAG,EAAE,cAAc;IACnB,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,GAAW,EACX,GAAW,EACe,EAAE,CAAC,YAAY,CAAC;IAC1C,MAAM,EAAE;QACN,IAAI,EAAE,GAAG;QACT,GAAG;KACJ;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,GAAW,EACX,GAAW,EACgB,EAAE,CAAC,YAAY,CAAC;IAC3C,OAAO,EAAE;QACP,IAAI,EAAE,GAAG;QACT,GAAG;KACJ;CACF,CAAC,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/types.d.ts b/pkg/npm/api/tmp/invite/types.d.ts new file mode 100644 index 000000000..d9418ba8f --- /dev/null +++ b/pkg/npm/api/tmp/invite/types.d.ts @@ -0,0 +1,54 @@ +import { Serial, PatpNoSig, Path } from '../lib'; +import { Resource } from "../groups"; +export declare type InviteUpdate = InviteUpdateInitial | InviteUpdateCreate | InviteUpdateDelete | InviteUpdateInvite | InviteUpdateAccept | InviteUpdateAccepted | InviteUpdateDecline; +export interface InviteUpdateAccept { + accept: { + term: string; + uid: Serial; + }; +} +export interface InviteUpdateInitial { + initial: Invites; +} +export interface InviteUpdateCreate { + create: { + term: string; + }; +} +export interface InviteUpdateDelete { + delete: { + term: string; + }; +} +export interface InviteUpdateInvite { + invite: { + term: string; + uid: Serial; + invite: Invite; + }; +} +export interface InviteUpdateAccepted { + accepted: { + term: string; + uid: Serial; + }; +} +export interface InviteUpdateDecline { + decline: { + term: string; + uid: Serial; + }; +} +export declare type Invites = { + [p in Path]: AppInvites; +}; +export declare type AppInvites = { + [s in Serial]: Invite; +}; +export interface Invite { + app: string; + recipient: PatpNoSig; + resource: Resource; + ship: PatpNoSig; + text: string; +} diff --git a/pkg/npm/api/tmp/invite/types.js b/pkg/npm/api/tmp/invite/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/invite/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/types.js.map b/pkg/npm/api/tmp/invite/types.js.map new file mode 100644 index 000000000..e163d5eee --- /dev/null +++ b/pkg/npm/api/tmp/invite/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../invite/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.d.ts b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.d.ts new file mode 100644 index 000000000..4dd317c53 --- /dev/null +++ b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.d.ts @@ -0,0 +1,24 @@ +import { immerable } from 'immer'; +import bigInt, { BigInteger } from 'big-integer'; +export declare function stringToArr(str: string): bigInt.BigInteger[]; +export declare function arrToString(arr: BigInteger[]): string; +export declare function sortBigIntArr(a: BigInteger[], b: BigInteger[]): number; +export declare class BigIntArrayOrderedMap implements Iterable<[BigInteger[], V]> { + root: Record; + cachedIter: [BigInteger[], V][] | null; + [immerable]: boolean; + reversed: boolean; + constructor(items?: [BigInteger[], V][], reversed?: boolean); + get size(): number; + get(key: BigInteger[]): V; + gas(items: [BigInteger[], V][]): this; + set(key: BigInteger[], value: V): this; + clear(): this; + has(key: BigInteger[]): boolean; + delete(key: BigInteger[]): this; + [Symbol.iterator](): IterableIterator<[BigInteger[], V]>; + peekLargest(): [bigInt.BigInteger[], V]; + peekSmallest(): [bigInt.BigInteger[], V]; + keys(): bigInt.BigInteger[][]; + generateCachedIter(): [bigInt.BigInteger[], V][]; +} diff --git a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js new file mode 100644 index 000000000..04e568ef3 --- /dev/null +++ b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js @@ -0,0 +1,131 @@ +import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; +import bigInt from 'big-integer'; +setAutoFreeze(false); +enablePatches(); +export function stringToArr(str) { + return str.split('/').slice(1).map((ind) => { + return bigInt(ind); + }); +} +export function arrToString(arr) { + let string = ''; + arr.forEach((key) => { + string = string + `/${key.toString()}`; + }); + return string; +} +function sorted(a, b, reversed = false) { + const getSort = sortBigIntArr(a, b); + if (reversed) { + return getSort * -1; + } + else { + return getSort; + } +} +export function sortBigIntArr(a, b) { + const aLen = a.length; + const bLen = b.length; + const aCop = a.slice(0); + const bCop = b.slice(0); + aCop.reverse(); + bCop.reverse(); + let i = 0; + while (i < aLen && i < bLen) { + if (aCop[i].lt(bCop[i])) { + return 1; + } + else if (aCop[i].gt(bCop[i])) { + return -1; + } + else { + i++; + } + } + return bLen - aLen; +} +export class BigIntArrayOrderedMap { + root = {}; + cachedIter = null; + [immerable] = true; + reversed = false; + constructor(items = [], reversed = false) { + items.forEach(([key, val]) => { + this.set(key, val); + }); + this.reversed = reversed; + } + get size() { + return Object.keys(this.root).length; + } + get(key) { + return this.root[arrToString(key)] ?? null; + } + gas(items) { + return produce(this, (draft) => { + items.forEach(([key, value]) => { + draft.root[arrToString(key)] = castDraft(value); + }); + draft.generateCachedIter(); + }, (patches) => { + // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); + }); + } + set(key, value) { + return produce(this, (draft) => { + draft.root[arrToString(key)] = castDraft(value); + draft.cachedIter = null; + }); + } + clear() { + return produce(this, (draft) => { + draft.cachedIter = []; + draft.root = {}; + }); + } + has(key) { + return arrToString(key) in this.root; + } + delete(key) { + const result = produce(this, (draft) => { + delete draft.root[arrToString(key)]; + draft.cachedIter = null; + }); + return result; + } + [Symbol.iterator]() { + let idx = 0; + const result = this.generateCachedIter(); + return { + [Symbol.iterator]: this[Symbol.iterator], + next: () => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + } + }; + } + peekLargest() { + const sorted = Array.from(this); + return sorted[0]; + } + peekSmallest() { + const sorted = Array.from(this); + return sorted[sorted.length - 1]; + } + keys() { + return Array.from(this).map(([k, v]) => k); + } + generateCachedIter() { + if (this.cachedIter) { + return [...this.cachedIter]; + } + const result = Object.keys(this.root).map((key) => { + return [stringToArr(key), this.root[key]]; + }).sort(([a], [b]) => sorted(a, b, this.reversed)); + this.cachedIter = result; + return [...result]; + } +} +//# sourceMappingURL=BigIntArrayOrderedMap.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js.map b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js.map new file mode 100644 index 000000000..81db34c03 --- /dev/null +++ b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"BigIntArrayOrderedMap.js","sourceRoot":"","sources":["../../lib/BigIntArrayOrderedMap.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts b/pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts new file mode 100644 index 000000000..bcbcbb0e7 --- /dev/null +++ b/pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts @@ -0,0 +1,20 @@ +import { immerable } from 'immer'; +import bigInt, { BigInteger } from 'big-integer'; +export declare class BigIntOrderedMap implements Iterable<[BigInteger, V]> { + root: Record; + cachedIter: [BigInteger, V][] | null; + [immerable]: boolean; + constructor(items?: [BigInteger, V][]); + get size(): number; + get(key: BigInteger): V; + gas(items: [BigInteger, V][]): this; + set(key: BigInteger, value: V): this; + clear(): this; + has(key: BigInteger): boolean; + delete(key: BigInteger): this; + [Symbol.iterator](): IterableIterator<[BigInteger, V]>; + peekLargest(): [bigInt.BigInteger, V]; + peekSmallest(): [bigInt.BigInteger, V]; + keys(): bigInt.BigInteger[]; + generateCachedIter(): [bigInt.BigInteger, V][]; +} diff --git a/pkg/npm/api/tmp/lib/BigIntOrderedMap.js b/pkg/npm/api/tmp/lib/BigIntOrderedMap.js new file mode 100644 index 000000000..ee37d9aef --- /dev/null +++ b/pkg/npm/api/tmp/lib/BigIntOrderedMap.js @@ -0,0 +1,102 @@ +import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; +import bigInt from 'big-integer'; +setAutoFreeze(false); +enablePatches(); +function sortBigInt(a, b) { + if (a.lt(b)) { + return 1; + } + else if (a.eq(b)) { + return 0; + } + else { + return -1; + } +} +export class BigIntOrderedMap { + root = {}; + cachedIter = null; + [immerable] = true; + constructor(items = []) { + items.forEach(([key, val]) => { + this.set(key, val); + }); + } + get size() { + if (this.cachedIter) { + return this.cachedIter.length; + } + return this.generateCachedIter().length; + } + get(key) { + return this.root[key.toString()] ?? null; + } + gas(items) { + return produce(this, (draft) => { + items.forEach(([key, value]) => { + draft.root[key.toString()] = castDraft(value); + }); + draft.cachedIter = null; + }, (patches) => { + // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); + }); + } + set(key, value) { + return produce(this, (draft) => { + draft.root[key.toString()] = castDraft(value); + draft.cachedIter = null; + }); + } + clear() { + return produce(this, (draft) => { + draft.cachedIter = []; + draft.root = {}; + }); + } + has(key) { + return key.toString() in this.root; + } + delete(key) { + const result = produce(this, (draft) => { + delete draft.root[key.toString()]; + draft.cachedIter = null; + }); + return result; + } + [Symbol.iterator]() { + let idx = 0; + const result = this.generateCachedIter(); + return { + [Symbol.iterator]: this[Symbol.iterator], + next: () => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + } + }; + } + peekLargest() { + const sorted = Array.from(this); + return sorted[0]; + } + peekSmallest() { + const sorted = Array.from(this); + return sorted[sorted.length - 1]; + } + keys() { + return Array.from(this).map(([k, v]) => k); + } + generateCachedIter() { + if (this.cachedIter) { + return [...this.cachedIter]; + } + const result = Object.keys(this.root).map((key) => { + const num = bigInt(key); + return [num, this.root[key]]; + }).sort(([a], [b]) => sortBigInt(a, b)); + this.cachedIter = result; + return [...result]; + } +} +//# sourceMappingURL=BigIntOrderedMap.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map b/pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map new file mode 100644 index 000000000..f907f6444 --- /dev/null +++ b/pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"BigIntOrderedMap.js","sourceRoot":"","sources":["../../lib/BigIntOrderedMap.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/index.d.ts b/pkg/npm/api/tmp/lib/index.d.ts new file mode 100644 index 000000000..e06143cf1 --- /dev/null +++ b/pkg/npm/api/tmp/lib/index.d.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/pkg/npm/api/tmp/lib/index.js b/pkg/npm/api/tmp/lib/index.js new file mode 100644 index 000000000..872ee0de4 --- /dev/null +++ b/pkg/npm/api/tmp/lib/index.js @@ -0,0 +1,3 @@ +export * from './lib'; +export * from './types'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/index.js.map b/pkg/npm/api/tmp/lib/index.js.map new file mode 100644 index 000000000..f4062559b --- /dev/null +++ b/pkg/npm/api/tmp/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/lib.d.ts b/pkg/npm/api/tmp/lib/lib.d.ts new file mode 100644 index 000000000..2600d247a --- /dev/null +++ b/pkg/npm/api/tmp/lib/lib.d.ts @@ -0,0 +1,33 @@ +import { BigInteger } from "big-integer"; +import { Resource } from "../groups/types"; +import { Post, GraphNode } from "../graph/types"; +/** + * Given a bigint representing an urbit date, returns a unix timestamp. + * + * @param {BigInteger} da The urbit date + * + * @return {number} The unix timestamp + */ +export declare function daToUnix(da: BigInteger): number; +/** + * Given a unix timestamp, returns a bigint representing an urbit date + * + * @param {number} unix The unix timestamp + * + * @return {BigInteger} The urbit date + */ +export declare function unixToDa(unix: number): BigInteger; +export declare function makePatDa(patda: string): BigInteger; +export declare function udToDec(ud: string): string; +export declare function decToUd(str: string): string; +export declare function resourceAsPath(resource: Resource): string; +export declare function uuid(): string; +export declare function daToDate(st: string): Date; +export declare function dateToDa(d: Date, mil?: boolean): string; +export declare function deSig(ship: string): string | null; +export declare function cite(ship: string): string; +export declare function uxToHex(ux: string): string; +export declare const hexToUx: (hex: string) => string; +export declare function stringToTa(str: string): string; +export declare const buntPost: () => Post; +export declare function makeNodeMap(posts: Post[]): Record; diff --git a/pkg/npm/api/tmp/lib/lib.js b/pkg/npm/api/tmp/lib/lib.js new file mode 100644 index 000000000..6b52d21c0 --- /dev/null +++ b/pkg/npm/api/tmp/lib/lib.js @@ -0,0 +1,207 @@ +import bigInt from "big-integer"; +const DA_UNIX_EPOCH = bigInt("170141184475152167957503069145530368000"); // `@ud` ~1970.1.1 +const DA_SECOND = bigInt("18446744073709551616"); // `@ud` ~s1 +function chunk(arr, size) { + let chunk = []; + let newArray = [chunk]; + for (let i = 0; i < arr.length; i++) { + if (chunk.length < size) { + chunk.push(arr[i]); + } + else { + chunk = [arr[i]]; + newArray.push(chunk); + } + } + return newArray; +} +function dropWhile(arr, pred) { + const newArray = arr.slice(); + for (const item of arr) { + if (pred(item)) { + newArray.shift(); + } + else { + return newArray; + } + } + return newArray; +} +/** + * Given a bigint representing an urbit date, returns a unix timestamp. + * + * @param {BigInteger} da The urbit date + * + * @return {number} The unix timestamp + */ +export function daToUnix(da) { + // ported from +time:enjs:format in hoon.hoon + const offset = DA_SECOND.divide(bigInt(2000)); + const epochAdjusted = offset.add(da.subtract(DA_UNIX_EPOCH)); + return Math.round(epochAdjusted.multiply(bigInt(1000)).divide(DA_SECOND).toJSNumber()); +} +/** + * Given a unix timestamp, returns a bigint representing an urbit date + * + * @param {number} unix The unix timestamp + * + * @return {BigInteger} The urbit date + */ +export function unixToDa(unix) { + const timeSinceEpoch = bigInt(unix).multiply(DA_SECOND).divide(bigInt(1000)); + return DA_UNIX_EPOCH.add(timeSinceEpoch); +} +export function makePatDa(patda) { + return bigInt(udToDec(patda)); +} +export function udToDec(ud) { + return ud.replace(/\./g, ""); +} +export function decToUd(str) { + const transform = chunk(str.split('').reverse(), 3) + .map(group => group.reverse().join('')) + .reverse() + .join('.'); + return transform.replace(/^[0\.]+/g, ''); +} +export function resourceAsPath(resource) { + const { name, ship } = resource; + return `/ship/~${ship}/${name}`; +} +export function uuid() { + let str = "0v"; + str += Math.ceil(Math.random() * 8) + "."; + for (let i = 0; i < 5; i++) { + let _str = Math.ceil(Math.random() * 10000000).toString(32); + _str = ("00000" + _str).substr(-5, 5); + str += _str + "."; + } + return str.slice(0, -1); +} +/* + Goes from: + ~2018.7.17..23.15.09..5be5 // urbit @da + To: + (javascript Date object) +*/ +export function daToDate(st) { + const dub = function (n) { + return parseInt(n) < 10 ? "0" + parseInt(n) : n.toString(); + }; + const da = st.split(".."); + const bigEnd = da[0].split("."); + const lilEnd = da[1].split("."); + const ds = `${bigEnd[0].slice(1)}-${dub(bigEnd[1])}-${dub(bigEnd[2])}T${dub(lilEnd[0])}:${dub(lilEnd[1])}:${dub(lilEnd[2])}Z`; + return new Date(ds); +} +/* + Goes from: + (javascript Date object) + To: + ~2018.7.17..23.15.09..5be5 // urbit @da +*/ +export function dateToDa(d, mil = false) { + const fil = function (n) { + return n >= 10 ? n : "0" + n; + }; + return (`~${d.getUTCFullYear()}.` + + `${d.getUTCMonth() + 1}.` + + `${fil(d.getUTCDate())}..` + + `${fil(d.getUTCHours())}.` + + `${fil(d.getUTCMinutes())}.` + + `${fil(d.getUTCSeconds())}` + + `${mil ? "..0000" : ""}`); +} +export function deSig(ship) { + if (!ship) { + return null; + } + return ship.replace("~", ""); +} +// trim patps to match dojo, chat-cli +export function cite(ship) { + let patp = ship, shortened = ''; + if (patp === null || patp === '') { + return null; + } + if (patp.startsWith('~')) { + patp = patp.substr(1); + } + // comet + if (patp.length === 56) { + shortened = '~' + patp.slice(0, 6) + '_' + patp.slice(50, 56); + return shortened; + } + // moon + if (patp.length === 27) { + shortened = '~' + patp.slice(14, 20) + '^' + patp.slice(21, 27); + return shortened; + } + return `~${patp}`; +} +export function uxToHex(ux) { + if (ux.length > 2 && ux.substr(0, 2) === '0x') { + const value = ux.substr(2).replace('.', '').padStart(6, '0'); + return value; + } + const value = ux.replace('.', '').padStart(6, '0'); + return value; +} +export const hexToUx = (hex) => { + const nonZeroChars = dropWhile(hex.split(''), y => y === '0'); + const ux = chunk(nonZeroChars.reverse(), 4).map(x => { + return x.reverse().join(''); + }).reverse().join('.') || '0'; + return `0x${ux}`; +}; +// encode the string into @ta-safe format, using logic from +wood. +// for example, 'some Chars!' becomes '~.some.~43.hars~21.' +// +export function stringToTa(str) { + let out = ""; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + let add = ""; + switch (char) { + case " ": + add = "."; + break; + case ".": + add = "~."; + break; + case "~": + add = "~~"; + break; + default: + const charCode = str.charCodeAt(i); + if ((charCode >= 97 && charCode <= 122) || // a-z + (charCode >= 48 && charCode <= 57) || // 0-9 + char === "-") { + add = char; + } + else { + // TODO behavior for unicode doesn't match +wood's, + // but we can probably get away with that for now. + add = "~" + charCode.toString(16) + "."; + } + } + out = out + add; + } + return "~." + out; +} +export const buntPost = () => ({ + author: '', + contents: [], + hash: null, + index: '', + signatures: [], + 'time-sent': 0 +}); +export function makeNodeMap(posts) { + const nodes = {}; + posts.forEach((p) => { + nodes[String(p.index)] = { children: null, post: p }; + }); + return nodes; +} +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/lib.js.map b/pkg/npm/api/tmp/lib/lib.js.map new file mode 100644 index 000000000..8d263d786 --- /dev/null +++ b/pkg/npm/api/tmp/lib/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../lib/lib.ts"],"names":[],"mappings":"AAAA,OAAO,MAAsB,MAAM,aAAa,CAAC;AAKjD,MAAM,aAAa,GAAG,MAAM,CAAC,yCAAyC,CAAC,CAAC,CAAC,kBAAkB;AAE3F,MAAM,SAAS,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,YAAY;AAE9D,SAAS,KAAK,CAAI,GAAQ,EAAE,IAAY;IACtC,IAAI,KAAK,GAAQ,EAAE,CAAC;IACpB,IAAI,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC;IAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAC,CAAC,GAAG,GAAG,CAAC,MAAM,EAAC,CAAC,EAAE,EAAE;QACjC,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE;YACvB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;SACnB;aAAM;YACL,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YAChB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;SACrB;KACF;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,SAAS,CAAI,GAAQ,EAAE,IAAuB;IACrD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE;QACtB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE;YACd,QAAQ,CAAC,KAAK,EAAE,CAAC;SAClB;aAAM;YACL,OAAO,QAAQ,CAAC;SACjB;KACF;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAc;IACrC,6CAA6C;IAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;IAE7D,OAAO,IAAI,CAAC,KAAK,CACf,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CACpE,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,cAAc,GAAI,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,OAAO,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAC3C,CAAC;AAGD,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,EAAU;IAChC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;SAChD,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SACtC,OAAO,EAAE;SACT,IAAI,CAAC,GAAG,CAAC,CAAA;IACZ,OAAO,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAkB;IAC/C,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;IAChC,OAAO,UAAU,IAAI,IAAI,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5D,IAAI,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtC,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC;KACnB;IAED,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;EAKE;AACF,MAAM,UAAU,QAAQ,CAAC,EAAU;IACjC,MAAM,GAAG,GAAG,UAAU,CAAS;QAC7B,OAAO,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC7D,CAAC,CAAC;IACF,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,EAAE,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CACzE,MAAM,CAAC,CAAC,CAAC,CACV,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;AACtB,CAAC;AAED;;;;;EAKE;AAEF,MAAM,UAAU,QAAQ,CAAC,CAAO,EAAE,MAAe,KAAK;IACpD,MAAM,GAAG,GAAG,UAAU,CAAS;QAC7B,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/B,CAAC,CAAC;IACF,OAAO,CACL,IAAI,CAAC,CAAC,cAAc,EAAE,GAAG;QACzB,GAAG,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,GAAG;QACzB,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,IAAI;QAC1B,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG;QAC1B,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,GAAG;QAC5B,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,EAAE;QAC3B,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CACzB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAY;IAChC,IAAI,CAAC,IAAI,EAAE;QACT,OAAO,IAAI,CAAC;KACb;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,IAAI,IAAI,GAAG,IAAI,EACb,SAAS,GAAG,EAAE,CAAC;IACjB,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,EAAE;QAChC,OAAO,IAAI,CAAC;KACb;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;QACxB,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;KACvB;IACD,QAAQ;IACR,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE;QACtB,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9D,OAAO,SAAS,CAAC;KAClB;IACD,OAAO;IACP,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE;QACtB,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAChE,OAAO,SAAS,CAAC;KAClB;IACD,OAAO,IAAI,IAAI,EAAE,CAAC;AACpB,CAAC;AAGD,MAAM,UAAU,OAAO,CAAC,EAAU;IAChC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;QAC7C,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC;KACd;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACnD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAW,EAAU,EAAE;IAC7C,MAAM,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;IAC9D,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QAClD,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;IAE9B,OAAO,KAAK,EAAE,EAAE,CAAC;AACnB,CAAC,CAAC;AAGF,kEAAkE;AAClE,2DAA2D;AAC3D,EAAE;AACF,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,QAAQ,IAAI,EAAE;YACZ,KAAK,GAAG;gBACN,GAAG,GAAG,GAAG,CAAC;gBACV,MAAM;YACR,KAAK,GAAG;gBACN,GAAG,GAAG,IAAI,CAAC;gBACX,MAAM;YACR,KAAK,GAAG;gBACN,GAAG,GAAG,IAAI,CAAC;gBACX,MAAM;YACR;gBACE,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBACnC,IACE,CAAC,QAAQ,IAAI,EAAE,IAAI,QAAQ,IAAI,GAAG,CAAC,IAAI,MAAM;oBAC7C,CAAC,QAAQ,IAAI,EAAE,IAAI,QAAQ,IAAI,EAAE,CAAC,IAAI,MAAM;oBAC5C,IAAI,KAAK,GAAG,EACZ;oBACA,GAAG,GAAG,IAAI,CAAC;iBACZ;qBAAM;oBACL,mDAAmD;oBACnD,sDAAsD;oBACtD,GAAG,GAAG,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;iBACzC;SACJ;QACD,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;KACjB;IACD,OAAO,IAAI,GAAG,GAAG,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAS,EAAE,CAAC,CAAC;IACnC,MAAM,EAAE,EAAE;IACV,QAAQ,EAAE,EAAE;IACZ,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,EAAE;IACT,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,KAAK,CAAC,OAAO,CAAC,CAAC,CAAO,EAAE,EAAE;QACxB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACvD,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/types.d.ts b/pkg/npm/api/tmp/lib/types.d.ts new file mode 100644 index 000000000..f35993cc3 --- /dev/null +++ b/pkg/npm/api/tmp/lib/types.d.ts @@ -0,0 +1,42 @@ +/** + * Martian embassy + */ +import { BigIntOrderedMap } from "./BigIntOrderedMap"; +export declare type Path = string; +export declare type Patp = string; +export declare type PatpNoSig = string; +export declare type Serial = string; +export declare type Jug = Map>; +export declare type AppName = 'chat' | 'link' | 'contacts' | 'publish' | 'graph' | 'groups'; +export declare type ShipRank = 'czar' | 'king' | 'duke' | 'earl' | 'pawn'; +export declare type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete'; +export declare type SetElement = S extends Set<(infer T)> ? T : never; +export declare type MapKey = M extends Map<(infer K), any> ? K : never; +export declare type MapValue = M extends Map ? V : never; +/** + * Turns sets into arrays and maps into objects so we can send them over the wire + */ +export declare type Enc = S extends Set ? Enc>[] : S extends Map ? { + [s: string]: Enc>; +} : S extends object ? { + [K in keyof S]: Enc; +} : S extends BigIntOrderedMap ? { + [index: string]: T; +} : S; +export declare type Mark = string; +export interface Poke { + ship?: string; + app: string; + mark: Mark; + json: Action; +} +export interface Scry { + app: string; + path: string; +} +export interface Thread { + inputMark: string; + outputMark: string; + threadName: string; + body: Action; +} diff --git a/pkg/npm/api/tmp/lib/types.js b/pkg/npm/api/tmp/lib/types.js new file mode 100644 index 000000000..b5d0954fb --- /dev/null +++ b/pkg/npm/api/tmp/lib/types.js @@ -0,0 +1,5 @@ +/** + * Martian embassy + */ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/types.js.map b/pkg/npm/api/tmp/lib/types.js.map new file mode 100644 index 000000000..212a6e318 --- /dev/null +++ b/pkg/npm/api/tmp/lib/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"AAAA;;GAEG"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/index.d.ts b/pkg/npm/api/tmp/metadata/index.d.ts new file mode 100644 index 000000000..4a272fce5 --- /dev/null +++ b/pkg/npm/api/tmp/metadata/index.d.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; diff --git a/pkg/npm/api/tmp/metadata/index.js b/pkg/npm/api/tmp/metadata/index.js new file mode 100644 index 000000000..5c8443c9d --- /dev/null +++ b/pkg/npm/api/tmp/metadata/index.js @@ -0,0 +1,3 @@ +export * from './types'; +export * from './lib'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/index.js.map b/pkg/npm/api/tmp/metadata/index.js.map new file mode 100644 index 000000000..7be78af17 --- /dev/null +++ b/pkg/npm/api/tmp/metadata/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../metadata/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/lib.d.ts b/pkg/npm/api/tmp/metadata/lib.d.ts new file mode 100644 index 000000000..221a2d820 --- /dev/null +++ b/pkg/npm/api/tmp/metadata/lib.d.ts @@ -0,0 +1,15 @@ +import { Path, Poke, PatpNoSig } from '../lib'; +import { MdAppName, Association, Metadata, MetadataUpdate, MetadataUpdateAdd, MetadataUpdateRemove, MetadataEditField, MetadataUpdateEdit } from './types'; +export declare const METADATA_UPDATE_VERSION = 2; +export declare const metadataAction: (data: T, version?: number) => Poke; +export declare const add: (ship: PatpNoSig, appName: MdAppName, resource: Path, group: Path, title: string, description: string, dateCreated: string, color: string, moduleName: string) => Poke; +export { add as metadataAdd }; +export declare const remove: (appName: MdAppName, resource: string, group: string) => Poke; +export { remove as metadataRemove }; +export declare const edit: (association: Association, edit: MetadataEditField) => Poke; +export { edit as metadataEdit }; +/** + * @deprecated use {@link edit} instead + */ +export declare const update: (association: Association, newMetadata: Partial) => Poke; +export { update as metadataUpdate }; diff --git a/pkg/npm/api/tmp/metadata/lib.js b/pkg/npm/api/tmp/metadata/lib.js new file mode 100644 index 000000000..c6fed6976 --- /dev/null +++ b/pkg/npm/api/tmp/metadata/lib.js @@ -0,0 +1,69 @@ +import { uxToHex } from '../lib'; +export const METADATA_UPDATE_VERSION = 2; +export const metadataAction = (data, version = METADATA_UPDATE_VERSION) => ({ + app: 'metadata-push-hook', + mark: `metadata-update-${version}`, + json: data +}); +export const add = (ship, appName, resource, group, title, description, dateCreated, color, moduleName) => metadataAction({ + add: { + group, + resource: { + resource, + 'app-name': appName + }, + metadata: { + title, + description, + color, + 'date-created': dateCreated, + creator: `~${ship}`, + config: { graph: moduleName }, + picture: '', + hidden: false, + preview: false, + vip: '' + } + } +}); +export { add as metadataAdd }; +export const remove = (appName, resource, group) => metadataAction({ + remove: { + group, + resource: { + resource, + 'app-name': appName + } + } +}); +export { remove as metadataRemove }; +export const edit = (association, edit) => metadataAction({ + edit: { + group: association.group, + resource: { + resource: association.resource, + 'app-name': association['app-name'] + }, + edit + } +}); +export { edit as metadataEdit }; +/** + * @deprecated use {@link edit} instead + */ +export const update = (association, newMetadata) => { + const metadata = { ...association.metadata, ...newMetadata }; + metadata.color = uxToHex(metadata.color); + return metadataAction({ + add: { + group: association.group, + resource: { + resource: association.resource, + 'app-name': association['app-name'] + }, + metadata + } + }); +}; +export { update as metadataUpdate }; +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/lib.js.map b/pkg/npm/api/tmp/metadata/lib.js.map new file mode 100644 index 000000000..933172f52 --- /dev/null +++ b/pkg/npm/api/tmp/metadata/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../metadata/lib.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,OAAO,EAAa,MAAM,QAAQ,CAAC;AAGxD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAG,CAA2B,IAAO,EAAE,UAAkB,uBAAuB,EAAW,EAAE,CAAC,CAAC;IACxH,GAAG,EAAE,oBAAoB;IACzB,IAAI,EAAE,mBAAmB,OAAO,EAAE;IAClC,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,GAAG,GAAG,CACjB,IAAe,EACf,OAAkB,EAClB,QAAc,EACd,KAAW,EACX,KAAa,EACb,WAAmB,EACnB,WAAmB,EACnB,KAAa,EACb,UAAkB,EACO,EAAE,CAAC,cAAc,CAAC;IAC3C,GAAG,EAAE;QACH,KAAK;QACL,QAAQ,EAAE;YACR,QAAQ;YACR,UAAU,EAAE,OAAO;SACpB;QACD,QAAQ,EAAE;YACR,KAAK;YACL,WAAW;YACX,KAAK;YACL,cAAc,EAAE,WAAW;YAC3B,OAAO,EAAE,IAAI,IAAI,EAAE;YACnB,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE;YAC7B,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,KAAK;YACd,GAAG,EAAE,EAAE;SACR;KACF;CACF,CAAC,CAAC;AAEH,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC;AAE9B,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,OAAkB,EAClB,QAAgB,EAChB,KAAa,EACe,EAAE,CAAC,cAAc,CAAuB;IACpE,MAAM,EAAE;QACN,KAAK;QACL,QAAQ,EAAE;YACR,QAAQ;YACR,UAAU,EAAE,OAAO;SACpB;KACF;CACF,CAAC,CAAC;AAEH,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAC;AAEpC,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,WAAwB,EACxB,IAAuB,EACG,EAAE,CAAC,cAAc,CAAqB;IAChE,IAAI,EAAE;QACJ,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,QAAQ,EAAE;YACR,QAAQ,EAAE,WAAW,CAAC,QAAQ;YAC9B,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC;SACpC;QACD,IAAI;KACL;CACF,CAAC,CAAC;AAEH,OAAO,EAAE,IAAI,IAAI,YAAY,EAAE,CAAC;AAEhC;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,WAAwB,EACxB,WAA8B,EACL,EAAE;IAC3B,MAAM,QAAQ,GAAG,EAAE,GAAG,WAAW,CAAC,QAAQ,EAAE,GAAG,WAAW,EAAE,CAAC;IAC3D,QAAQ,CAAC,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,cAAc,CAAoB;QACvC,GAAG,EAAE;YACH,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,QAAQ,EAAE;gBACR,QAAQ,EAAE,WAAW,CAAC,QAAQ;gBAC9B,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC;aACpC;YACD,QAAQ;SACT;KACF,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/types.d.ts b/pkg/npm/api/tmp/metadata/types.d.ts new file mode 100644 index 000000000..7459689b8 --- /dev/null +++ b/pkg/npm/api/tmp/metadata/types.d.ts @@ -0,0 +1,76 @@ +import { Path, Patp } from '../lib'; +export declare type MdAppName = 'groups' | 'graph'; +export declare type MetadataUpdate = MetadataUpdateInitial | MetadataUpdateAdd | MetadataUpdateUpdate | MetadataUpdateRemove | MetadataUpdateEdit; +export interface MetadataUpdateInitial { + associations: ResourceAssociations; +} +export declare type ResourceAssociations = { + [p in Path]: Association; +}; +export declare type MetadataUpdateAdd = { + add: AssociationPoke; +}; +export declare type MetadataUpdateUpdate = { + update: AssociationPoke; +}; +export interface MetadataUpdateEdit { + edit: { + resource: MdResource; + group: string; + edit: MetadataEditField; + }; +} +export declare type MetadataEditField = Partial>; +export declare type MetadataUpdateRemove = { + remove: { + resource: MdResource; + group: string; + }; +}; +export interface MdResource { + resource: string; + 'app-name': MdAppName; +} +export interface MetadataUpdatePreview { + group: string; + channels: Associations; + 'channel-count': number; + members: number; + metadata: Metadata; +} +export declare type Associations = { + groups: AppAssociations; + graph: AppAssociations; +}; +export declare type AppAssociations = { + [p in Path]: Association; +}; +export declare type Association = MdResource & { + group: Path; + metadata: Metadata; +}; +export interface AssociationPoke { + group: Path; + resource: MdResource; + metadata: Metadata; +} +export interface Metadata { + color: string; + creator: Patp; + 'date-created': string; + description: string; + title: string; + config: C; + hidden: boolean; + picture: string; + preview: boolean; + vip: PermVariation; +} +export declare type MetadataConfig = GroupConfig | GraphConfig; +export interface GraphConfig { + graph: string; +} +export interface GroupConfig { + group: undefined | {} | MdResource; +} +export declare type PermVariation = '' | ' ' | 'reader-comments' | 'member-metadata' | 'host-feed' | 'admin-feed'; diff --git a/pkg/npm/api/tmp/metadata/types.js b/pkg/npm/api/tmp/metadata/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/metadata/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/types.js.map b/pkg/npm/api/tmp/metadata/types.js.map new file mode 100644 index 000000000..8a55fbd72 --- /dev/null +++ b/pkg/npm/api/tmp/metadata/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../metadata/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/index.d.ts b/pkg/npm/api/tmp/s3/index.d.ts new file mode 100644 index 000000000..e06143cf1 --- /dev/null +++ b/pkg/npm/api/tmp/s3/index.d.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/pkg/npm/api/tmp/s3/index.js b/pkg/npm/api/tmp/s3/index.js new file mode 100644 index 000000000..872ee0de4 --- /dev/null +++ b/pkg/npm/api/tmp/s3/index.js @@ -0,0 +1,3 @@ +export * from './lib'; +export * from './types'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/index.js.map b/pkg/npm/api/tmp/s3/index.js.map new file mode 100644 index 000000000..c694f0ff7 --- /dev/null +++ b/pkg/npm/api/tmp/s3/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../s3/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/lib.d.ts b/pkg/npm/api/tmp/s3/lib.d.ts new file mode 100644 index 000000000..edbfa465b --- /dev/null +++ b/pkg/npm/api/tmp/s3/lib.d.ts @@ -0,0 +1,8 @@ +import { Poke } from '../lib/types'; +import { S3UpdateAccessKeyId, S3UpdateAddBucket, S3UpdateCurrentBucket, S3UpdateEndpoint, S3UpdateRemoveBucket, S3UpdateSecretAccessKey } from './types'; +export declare const setCurrentBucket: (bucket: string) => Poke; +export declare const addBucket: (bucket: string) => Poke; +export declare const removeBucket: (bucket: string) => Poke; +export declare const setEndpoint: (endpoint: string) => Poke; +export declare const setAccessKeyId: (accessKeyId: string) => Poke; +export declare const setSecretAccessKey: (secretAccessKey: string) => Poke; diff --git a/pkg/npm/api/tmp/s3/lib.js b/pkg/npm/api/tmp/s3/lib.js new file mode 100644 index 000000000..4f363769d --- /dev/null +++ b/pkg/npm/api/tmp/s3/lib.js @@ -0,0 +1,24 @@ +const s3Action = (data) => ({ + app: 's3-store', + mark: 's3-action', + json: data +}); +export const setCurrentBucket = (bucket) => s3Action({ + 'set-current-bucket': bucket +}); +export const addBucket = (bucket) => s3Action({ + 'add-bucket': bucket +}); +export const removeBucket = (bucket) => s3Action({ + 'remove-bucket': bucket +}); +export const setEndpoint = (endpoint) => s3Action({ + 'set-endpoint': endpoint +}); +export const setAccessKeyId = (accessKeyId) => s3Action({ + 'set-access-key-id': accessKeyId +}); +export const setSecretAccessKey = (secretAccessKey) => s3Action({ + 'set-secret-access-key': secretAccessKey +}); +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/lib.js.map b/pkg/npm/api/tmp/s3/lib.js.map new file mode 100644 index 000000000..769f49c50 --- /dev/null +++ b/pkg/npm/api/tmp/s3/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../s3/lib.ts"],"names":[],"mappings":"AAGA,MAAM,QAAQ,GAAG,CACf,IAAS,EACA,EAAE,CAAC,CAAC;IACb,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,MAAc,EACe,EAAE,CAAC,QAAQ,CAAC;IACzC,oBAAoB,EAAE,MAAM;CAC7B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,MAAc,EACW,EAAE,CAAC,QAAQ,CAAC;IACrC,YAAY,EAAE,MAAM;CACrB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,MAAc,EACc,EAAE,CAAC,QAAQ,CAAC;IACxC,eAAe,EAAE,MAAM;CACxB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,QAAgB,EACQ,EAAE,CAAC,QAAQ,CAAC;IACpC,cAAc,EAAE,QAAQ;CACzB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,WAAmB,EACQ,EAAE,CAAC,QAAQ,CAAC;IACvC,mBAAmB,EAAE,WAAW;CACjC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,eAAuB,EACQ,EAAE,CAAC,QAAQ,CAAC;IAC3C,uBAAuB,EAAE,eAAe;CACzC,CAAC,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/types.d.ts b/pkg/npm/api/tmp/s3/types.d.ts new file mode 100644 index 000000000..924749718 --- /dev/null +++ b/pkg/npm/api/tmp/s3/types.d.ts @@ -0,0 +1,41 @@ +export interface S3Credentials { + endpoint: string; + accessKeyId: string; + secretAccessKey: string; +} +export interface S3Configuration { + buckets: Set; + currentBucket: string; +} +export interface S3State { + configuration: S3Configuration; + credentials: S3Credentials | null; +} +export interface S3UpdateCredentials { + credentials: S3Credentials; +} +export interface S3UpdateConfiguration { + configuration: { + buckets: string[]; + currentBucket: string; + }; +} +export interface S3UpdateCurrentBucket { + setCurrentBucket: string; +} +export interface S3UpdateAddBucket { + addBucket: string; +} +export interface S3UpdateRemoveBucket { + removeBucket: string; +} +export interface S3UpdateEndpoint { + setEndpoint: string; +} +export interface S3UpdateAccessKeyId { + setAccessKeyId: string; +} +export interface S3UpdateSecretAccessKey { + setSecretAccessKey: string; +} +export declare type S3Update = S3UpdateCredentials | S3UpdateConfiguration | S3UpdateCurrentBucket | S3UpdateAddBucket | S3UpdateRemoveBucket | S3UpdateEndpoint | S3UpdateAccessKeyId | S3UpdateSecretAccessKey; diff --git a/pkg/npm/api/tmp/s3/types.js b/pkg/npm/api/tmp/s3/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/s3/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/types.js.map b/pkg/npm/api/tmp/s3/types.js.map new file mode 100644 index 000000000..651890e84 --- /dev/null +++ b/pkg/npm/api/tmp/s3/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../s3/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/index.d.ts b/pkg/npm/api/tmp/settings/index.d.ts new file mode 100644 index 000000000..4a272fce5 --- /dev/null +++ b/pkg/npm/api/tmp/settings/index.d.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; diff --git a/pkg/npm/api/tmp/settings/index.js b/pkg/npm/api/tmp/settings/index.js new file mode 100644 index 000000000..5c8443c9d --- /dev/null +++ b/pkg/npm/api/tmp/settings/index.js @@ -0,0 +1,3 @@ +export * from './types'; +export * from './lib'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/index.js.map b/pkg/npm/api/tmp/settings/index.js.map new file mode 100644 index 000000000..06b65a2d7 --- /dev/null +++ b/pkg/npm/api/tmp/settings/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../settings/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/lib.d.ts b/pkg/npm/api/tmp/settings/lib.d.ts new file mode 100644 index 000000000..8e2da9a75 --- /dev/null +++ b/pkg/npm/api/tmp/settings/lib.d.ts @@ -0,0 +1,21 @@ +import { Poke, Scry } from '../lib'; +import { PutBucket, Key, Bucket, DelBucket, Value, PutEntry, DelEntry, SettingsUpdate } from './types'; +export declare const action: (data: T) => Poke; +export declare const putBucket: (desk: string, key: Key, bucket: Bucket) => Poke; +export declare const delBucket: (desk: string, key: Key) => Poke; +export declare const putEntry: (desk: string, bucket: Key, key: Key, value: Value) => Poke; +export declare const delEntry: (desk: string, bucket: Key, key: Key) => Poke; +export declare const getAll: Scry; +export declare const getBucket: (desk: string, bucket: string) => { + app: string; + path: string; +}; +export declare const getEntry: (desk: string, bucket: string, entry: string) => { + app: string; + path: string; +}; +export declare const getDeskSettings: (desk: string) => { + app: string; + path: string; +}; +export * from './types'; diff --git a/pkg/npm/api/tmp/settings/lib.js b/pkg/npm/api/tmp/settings/lib.js new file mode 100644 index 000000000..c863ef963 --- /dev/null +++ b/pkg/npm/api/tmp/settings/lib.js @@ -0,0 +1,51 @@ +export const action = (data) => ({ + app: 'settings-store', + mark: 'settings-event', + json: data +}); +export const putBucket = (desk, key, bucket) => action({ + 'put-bucket': { + desk, + 'bucket-key': key, + 'bucket': bucket + } +}); +export const delBucket = (desk, key) => action({ + 'del-bucket': { + desk, + 'bucket-key': key + } +}); +export const putEntry = (desk, bucket, key, value) => action({ + 'put-entry': { + desk, + 'bucket-key': bucket, + 'entry-key': key, + value: value + } +}); +export const delEntry = (desk, bucket, key) => action({ + 'del-entry': { + desk, + 'bucket-key': bucket, + 'entry-key': key + } +}); +export const getAll = { + app: 'settings-store', + path: '/all' +}; +export const getBucket = (desk, bucket) => ({ + app: 'settings-store', + path: `/bucket/${bucket}` +}); +export const getEntry = (desk, bucket, entry) => ({ + app: 'settings-store', + path: `/entry/${desk}/${bucket}/${entry}` +}); +export const getDeskSettings = (desk) => ({ + app: 'settings-store', + path: `/desk/${desk}` +}); +export * from './types'; +//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/lib.js.map b/pkg/npm/api/tmp/settings/lib.js.map new file mode 100644 index 000000000..7c6f13886 --- /dev/null +++ b/pkg/npm/api/tmp/settings/lib.js.map @@ -0,0 +1 @@ +{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../settings/lib.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,MAAM,GAAG,CAA2B,IAAO,EAAW,EAAE,CAAC,CAAC;IACrE,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAY,EACZ,GAAQ,EACR,MAAc,EACG,EAAE,CAAC,MAAM,CAAC;IAC3B,YAAY,EAAE;QACZ,IAAI;QACJ,YAAY,EAAE,GAAG;QACjB,QAAQ,EAAE,MAAM;KACjB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAY,EACZ,GAAQ,EACS,EAAE,CAAC,MAAM,CAAC;IAC3B,YAAY,EAAE;QACZ,IAAI;QACJ,YAAY,EAAE,GAAG;KAClB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,MAAW,EACX,GAAQ,EACR,KAAY,EACI,EAAE,CAAC,MAAM,CAAC;IAC1B,WAAW,EAAE;QACX,IAAI;QACJ,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,GAAG;QAChB,KAAK,EAAE,KAAK;KACb;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,MAAW,EACX,GAAQ,EACQ,EAAE,CAAC,MAAM,CAAC;IAC1B,WAAW,EAAE;QACX,IAAI;QACJ,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,GAAG;KACjB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAS;IAC1B,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE,CAAC,CAAC;IAC1D,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,WAAW,MAAM,EAAE;CAC1B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC;IACxE,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,UAAU,IAAI,IAAI,MAAM,IAAI,KAAK,EAAE;CAC1C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;IAChD,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,SAAS,IAAI,EAAE;CACtB,CAAC,CAAC;AAEH,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/types.d.ts b/pkg/npm/api/tmp/settings/types.d.ts new file mode 100644 index 000000000..9e58650d1 --- /dev/null +++ b/pkg/npm/api/tmp/settings/types.d.ts @@ -0,0 +1,52 @@ +export declare type Key = string; +export declare type Value = string | string[] | boolean | number; +export declare type Bucket = { + [key: string]: Value; +}; +export declare type DeskSettings = { + [bucket: string]: Bucket; +}; +export declare type Settings = { + [desk: string]: Settings; +}; +export interface PutBucket { + 'put-bucket': { + desk: string; + 'bucket-key': Key; + 'bucket': Bucket; + }; +} +export interface DelBucket { + 'del-bucket': { + desk: string; + 'bucket-key': Key; + }; +} +export interface PutEntry { + 'put-entry': { + 'bucket-key': Key; + 'entry-key': Key; + 'value'?: Value; + }; +} +export interface DelEntry { + 'del-entry': { + desk: string; + 'bucket-key': Key; + 'entry-key': Key; + }; +} +export interface AllData { + 'all': Settings; +} +export interface DeskData { + desk: DeskSettings; +} +export interface BucketData { + 'bucket': Bucket; +} +export interface EntryData { + 'entry': Value; +} +export declare type SettingsUpdate = PutBucket | DelBucket | PutEntry | DelEntry; +export declare type SettingsData = AllData | BucketData | EntryData | DeskData; diff --git a/pkg/npm/api/tmp/settings/types.js b/pkg/npm/api/tmp/settings/types.js new file mode 100644 index 000000000..718fd38ae --- /dev/null +++ b/pkg/npm/api/tmp/settings/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/types.js.map b/pkg/npm/api/tmp/settings/types.js.map new file mode 100644 index 000000000..e768750c4 --- /dev/null +++ b/pkg/npm/api/tmp/settings/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../../settings/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/Urbit.d.ts b/pkg/npm/http-api/tmp/Urbit.d.ts new file mode 100644 index 000000000..9b4570b1c --- /dev/null +++ b/pkg/npm/http-api/tmp/Urbit.d.ts @@ -0,0 +1,183 @@ +import { Scry, Thread, AuthenticationInterface, PokeInterface, SubscriptionRequestInterface } from './types'; +/** + * A class for interacting with an urbit ship, given its URL and code + */ +export declare class Urbit { + url: string; + code?: string; + desk?: string; + /** + * UID will be used for the channel: The current unix time plus a random hex string + */ + private uid; + /** + * Last Event ID is an auto-updated index of which events have been sent over this channel + */ + private lastEventId; + private lastAcknowledgedEventId; + /** + * SSE Client is null for now; we don't want to start polling until it the channel exists + */ + private sseClientInitialized; + /** + * Cookie gets set when we log in. + */ + cookie?: string | undefined; + /** + * A registry of requestId to successFunc/failureFunc + * + * These functions are registered during a +poke and are executed + * in the onServerEvent()/onServerError() callbacks. Only one of + * the functions will be called, and the outstanding poke will be + * removed after calling the success or failure function. + */ + private outstandingPokes; + /** + * A registry of requestId to subscription functions. + * + * These functions are registered during a +subscribe and are + * executed in the onServerEvent()/onServerError() callbacks. The + * event function will be called whenever a new piece of data on this + * subscription is available, which may be 0, 1, or many times. The + * disconnect function may be called exactly once. + */ + private outstandingSubscriptions; + /** + * Our abort controller, used to close the connection + */ + private abort; + /** + * Ship can be set, in which case we can do some magic stuff like send chats + */ + ship?: string | null; + /** + * If verbose, logs output eagerly. + */ + verbose?: boolean; + /** + * number of consecutive errors in connecting to the eventsource + */ + private errorCount; + onError?: (error: any) => void; + onRetry?: () => void; + onOpen?: () => void; + /** This is basic interpolation to get the channel URL of an instantiated Urbit connection. */ + private get channelUrl(); + private get fetchOptions(); + /** + * Constructs a new Urbit connection. + * + * @param url The URL (with protocol and port) of the ship to be accessed. If + * the airlock is running in a webpage served by the ship, this should just + * be the empty string. + * @param code The access code for the ship at that address + */ + constructor(url: string, code?: string, desk?: string); + /** + * All-in-one hook-me-up. + * + * Given a ship, url, and code, this returns an airlock connection + * that is ready to go. It `|hi`s itself to create the channel, + * then opens the channel via EventSource. + * + */ + static authenticate({ ship, url, code, verbose, }: AuthenticationInterface): Promise; + /** + * Connects to the Urbit ship. Nothing can be done until this is called. + * That's why we roll it into this.authenticate + */ + connect(): Promise; + /** + * Initializes the SSE pipe for the appropriate channel. + */ + eventSource(): Promise; + /** + * Reset airlock, abandoning current subscriptions and wiping state + * + */ + reset(): void; + /** + * Autoincrements the next event ID for the appropriate channel. + */ + private getEventId; + /** + * Acknowledges an event. + * + * @param eventId The event to acknowledge. + */ + private ack; + private sendJSONtoChannel; + /** + * Creates a subscription, waits for a fact and then unsubscribes + * + * @param app Name of gall agent to subscribe to + * @param path Path to subscribe to + * @param timeout Optional timeout before ending subscription + * + * @returns The first fact on the subcription + */ + subscribeOnce(app: string, path: string, timeout?: number): Promise; + /** + * Pokes a ship with data. + * + * @param app The app to poke + * @param mark The mark of the data being sent + * @param json The data to send + */ + poke(params: PokeInterface): Promise; + /** + * Subscribes to a path on an app on a ship. + * + * + * @param app The app to subsribe to + * @param path The path to which to subscribe + * @param handlers Handlers to deal with various events of the subscription + */ + subscribe(params: SubscriptionRequestInterface): Promise; + /** + * Unsubscribes to a given subscription. + * + * @param subscription + */ + unsubscribe(subscription: number): Promise; + /** + * Deletes the connection to a channel. + */ + delete(): void; + /** + * Scry into an gall agent at a path + * + * @typeParam T - Type of the scry result + * + * @remarks + * + * Equivalent to + * ```hoon + * .^(T %gx /(scot %p our)/[app]/(scot %da now)/[path]/json) + * ``` + * The returned cage must have a conversion to JSON for the scry to succeed + * + * @param params The scry request + * @returns The scry result + */ + scry(params: Scry): Promise; + /** + * Run a thread + * + * + * @param inputMark The mark of the data being sent + * @param outputMark The mark of the data being returned + * @param threadName The thread to run + * @param body The data to send to the thread + * @returns The return value of the thread + */ + thread(params: Thread): Promise; + /** + * Utility function to connect to a ship that has its *.arvo.network domain configured. + * + * @param name Name of the ship e.g. zod + * @param code Code to log in + */ + static onArvoNetwork(ship: string, code: string): Promise; +} +export default Urbit; diff --git a/pkg/npm/http-api/tmp/Urbit.js b/pkg/npm/http-api/tmp/Urbit.js new file mode 100644 index 000000000..4f38123cc --- /dev/null +++ b/pkg/npm/http-api/tmp/Urbit.js @@ -0,0 +1,497 @@ +import { isBrowser, isNode } from 'browser-or-node'; +import { fetchEventSource, } from '@microsoft/fetch-event-source'; +import { hexString } from './utils'; +/** + * A class for interacting with an urbit ship, given its URL and code + */ +export class Urbit { + /** + * Constructs a new Urbit connection. + * + * @param url The URL (with protocol and port) of the ship to be accessed. If + * the airlock is running in a webpage served by the ship, this should just + * be the empty string. + * @param code The access code for the ship at that address + */ + constructor(url, code, desk) { + this.url = url; + this.code = code; + this.desk = desk; + /** + * UID will be used for the channel: The current unix time plus a random hex string + */ + this.uid = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`; + /** + * Last Event ID is an auto-updated index of which events have been sent over this channel + */ + this.lastEventId = 0; + this.lastAcknowledgedEventId = 0; + /** + * SSE Client is null for now; we don't want to start polling until it the channel exists + */ + this.sseClientInitialized = false; + /** + * A registry of requestId to successFunc/failureFunc + * + * These functions are registered during a +poke and are executed + * in the onServerEvent()/onServerError() callbacks. Only one of + * the functions will be called, and the outstanding poke will be + * removed after calling the success or failure function. + */ + this.outstandingPokes = new Map(); + /** + * A registry of requestId to subscription functions. + * + * These functions are registered during a +subscribe and are + * executed in the onServerEvent()/onServerError() callbacks. The + * event function will be called whenever a new piece of data on this + * subscription is available, which may be 0, 1, or many times. The + * disconnect function may be called exactly once. + */ + this.outstandingSubscriptions = new Map(); + /** + * Our abort controller, used to close the connection + */ + this.abort = new AbortController(); + /** + * number of consecutive errors in connecting to the eventsource + */ + this.errorCount = 0; + this.onError = null; + this.onRetry = null; + this.onOpen = null; + if (isBrowser) { + window.addEventListener('beforeunload', this.delete); + } + return this; + } + /** This is basic interpolation to get the channel URL of an instantiated Urbit connection. */ + get channelUrl() { + return `${this.url}/~/channel/${this.uid}`; + } + get fetchOptions() { + const headers = { + 'Content-Type': 'application/json', + }; + if (!isBrowser) { + headers.Cookie = this.cookie; + } + return { + credentials: 'include', + accept: '*', + headers, + signal: this.abort.signal, + }; + } + /** + * All-in-one hook-me-up. + * + * Given a ship, url, and code, this returns an airlock connection + * that is ready to go. It `|hi`s itself to create the channel, + * then opens the channel via EventSource. + * + */ + static async authenticate({ ship, url, code, verbose = false, }) { + const airlock = new Urbit(`http://${url}`, code); + airlock.verbose = verbose; + airlock.ship = ship; + await airlock.connect(); + await airlock.poke({ + app: 'hood', + mark: 'helm-hi', + json: 'opening airlock', + }); + await airlock.eventSource(); + return airlock; + } + /** + * Connects to the Urbit ship. Nothing can be done until this is called. + * That's why we roll it into this.authenticate + */ + async connect() { + if (this.verbose) { + console.log(`password=${this.code} `, isBrowser + ? 'Connecting in browser context at ' + `${this.url}/~/login` + : 'Connecting from node context'); + } + return fetch(`${this.url}/~/login`, { + method: 'post', + body: `password=${this.code}`, + credentials: 'include', + }).then((response) => { + if (this.verbose) { + console.log('Received authentication response', response); + } + const cookie = response.headers.get('set-cookie'); + if (!this.ship) { + this.ship = new RegExp(/urbauth-~([\w-]+)/).exec(cookie)[1]; + } + if (!isBrowser) { + this.cookie = cookie; + } + }); + } + /** + * Initializes the SSE pipe for the appropriate channel. + */ + async eventSource() { + if (this.sseClientInitialized) { + return Promise.resolve(); + } + if (this.lastEventId === 0) { + // Can't receive events until the channel is open, + // so poke and open then + await this.poke({ + app: 'hood', + mark: 'helm-hi', + json: 'Opening API channel', + }); + return; + } + this.sseClientInitialized = true; + return new Promise((resolve, reject) => { + const sseOptions = { + headers: {}, + }; + if (isBrowser) { + sseOptions.withCredentials = true; + } + else if (isNode) { + sseOptions.headers.Cookie = this.cookie; + } + fetchEventSource(this.channelUrl, { + ...this.fetchOptions, + openWhenHidden: true, + onopen: async (response) => { + if (this.verbose) { + console.log('Opened eventsource', response); + } + if (response.ok) { + this.errorCount = 0; + this.onOpen && this.onOpen(); + resolve(); + return; // everything's good + } + else { + const err = new Error('failed to open eventsource'); + reject(err); + } + }, + onmessage: (event) => { + if (this.verbose) { + console.log('Received SSE: ', event); + } + if (!event.id) + return; + this.lastEventId = parseInt(event.id, 10); + if (this.lastEventId - this.lastAcknowledgedEventId > 20) { + this.ack(this.lastEventId); + } + if (event.data && JSON.parse(event.data)) { + const data = JSON.parse(event.data); + if (data.response === 'poke' && + this.outstandingPokes.has(data.id)) { + const funcs = this.outstandingPokes.get(data.id); + if (data.hasOwnProperty('ok')) { + funcs.onSuccess(); + } + else if (data.hasOwnProperty('err')) { + console.error(data.err); + funcs.onError(data.err); + } + else { + console.error('Invalid poke response', data); + } + this.outstandingPokes.delete(data.id); + } + else if (data.response === 'subscribe' && + this.outstandingSubscriptions.has(data.id)) { + const funcs = this.outstandingSubscriptions.get(data.id); + if (data.hasOwnProperty('err')) { + console.error(data.err); + funcs.err(data.err, data.id); + this.outstandingSubscriptions.delete(data.id); + } + } + else if (data.response === 'diff' && + this.outstandingSubscriptions.has(data.id)) { + const funcs = this.outstandingSubscriptions.get(data.id); + try { + funcs.event(data.json); + } + catch (e) { + console.error('Failed to call subscription event callback', e); + } + } + else if (data.response === 'quit' && + this.outstandingSubscriptions.has(data.id)) { + const funcs = this.outstandingSubscriptions.get(data.id); + funcs.quit(data); + this.outstandingSubscriptions.delete(data.id); + } + else { + console.log([...this.outstandingSubscriptions.keys()]); + console.log('Unrecognized response', data); + } + } + }, + onerror: (error) => { + console.warn(error); + if (this.errorCount++ < 4) { + this.onRetry && this.onRetry(); + return Math.pow(2, this.errorCount - 1) * 750; + } + this.onError && this.onError(error); + throw error; + }, + onclose: () => { + console.log('e'); + throw new Error('Ship unexpectedly closed the connection'); + }, + }); + }); + } + /** + * Reset airlock, abandoning current subscriptions and wiping state + * + */ + reset() { + this.delete(); + this.abort.abort(); + this.abort = new AbortController(); + this.uid = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`; + this.lastEventId = 0; + this.lastAcknowledgedEventId = 0; + this.outstandingSubscriptions = new Map(); + this.outstandingPokes = new Map(); + this.sseClientInitialized = false; + } + /** + * Autoincrements the next event ID for the appropriate channel. + */ + getEventId() { + this.lastEventId = Number(this.lastEventId) + 1; + return this.lastEventId; + } + /** + * Acknowledges an event. + * + * @param eventId The event to acknowledge. + */ + async ack(eventId) { + this.lastAcknowledgedEventId = eventId; + const message = { + action: 'ack', + 'event-id': eventId, + }; + await this.sendJSONtoChannel(message); + return eventId; + } + async sendJSONtoChannel(...json) { + const response = await fetch(this.channelUrl, { + ...this.fetchOptions, + method: 'PUT', + body: JSON.stringify(json), + }); + if (!response.ok) { + throw new Error('Failed to PUT channel'); + } + if (!this.sseClientInitialized) { + await this.eventSource(); + } + } + /** + * Creates a subscription, waits for a fact and then unsubscribes + * + * @param app Name of gall agent to subscribe to + * @param path Path to subscribe to + * @param timeout Optional timeout before ending subscription + * + * @returns The first fact on the subcription + */ + async subscribeOnce(app, path, timeout) { + return new Promise(async (resolve, reject) => { + let done = false; + let id = null; + const quit = () => { + if (!done) { + reject('quit'); + } + }; + const event = (e) => { + if (!done) { + resolve(e); + this.unsubscribe(id); + } + }; + const request = { app, path, event, err: reject, quit }; + id = await this.subscribe(request); + if (timeout) { + setTimeout(() => { + if (!done) { + done = true; + reject('timeout'); + this.unsubscribe(id); + } + }, timeout); + } + }); + } + /** + * Pokes a ship with data. + * + * @param app The app to poke + * @param mark The mark of the data being sent + * @param json The data to send + */ + async poke(params) { + const { app, mark, json, ship, onSuccess, onError } = { + onSuccess: () => { }, + onError: () => { }, + ship: this.ship, + ...params, + }; + const message = { + id: this.getEventId(), + action: 'poke', + ship, + app, + mark, + json, + }; + const [send, result] = await Promise.all([ + this.sendJSONtoChannel(message), + new Promise((resolve, reject) => { + this.outstandingPokes.set(message.id, { + onSuccess: () => { + onSuccess(); + resolve(message.id); + }, + onError: (event) => { + onError(event); + reject(event.err); + }, + }); + }), + ]); + return result; + } + /** + * Subscribes to a path on an app on a ship. + * + * + * @param app The app to subsribe to + * @param path The path to which to subscribe + * @param handlers Handlers to deal with various events of the subscription + */ + async subscribe(params) { + const { app, path, ship, err, event, quit } = { + err: () => { }, + event: () => { }, + quit: () => { }, + ship: this.ship, + ...params, + }; + const message = { + id: this.getEventId(), + action: 'subscribe', + ship, + app, + path, + }; + this.outstandingSubscriptions.set(message.id, { + app, + path, + err, + event, + quit, + }); + await this.sendJSONtoChannel(message); + return message.id; + } + /** + * Unsubscribes to a given subscription. + * + * @param subscription + */ + async unsubscribe(subscription) { + return this.sendJSONtoChannel({ + id: this.getEventId(), + action: 'unsubscribe', + subscription, + }).then(() => { + this.outstandingSubscriptions.delete(subscription); + }); + } + /** + * Deletes the connection to a channel. + */ + delete() { + if (isBrowser) { + navigator.sendBeacon(this.channelUrl, JSON.stringify([ + { + action: 'delete', + }, + ])); + } + else { + // TODO + // this.sendMessage('delete'); + } + } + /** + * Scry into an gall agent at a path + * + * @typeParam T - Type of the scry result + * + * @remarks + * + * Equivalent to + * ```hoon + * .^(T %gx /(scot %p our)/[app]/(scot %da now)/[path]/json) + * ``` + * The returned cage must have a conversion to JSON for the scry to succeed + * + * @param params The scry request + * @returns The scry result + */ + async scry(params) { + const { app, path } = params; + const response = await fetch(`${this.url}/~/scry/${app}${path}.json`, this.fetchOptions); + return await response.json(); + } + /** + * Run a thread + * + * + * @param inputMark The mark of the data being sent + * @param outputMark The mark of the data being returned + * @param threadName The thread to run + * @param body The data to send to the thread + * @returns The return value of the thread + */ + async thread(params) { + const { inputMark, outputMark, threadName, body, desk = this.desk, } = params; + if (!desk) { + throw new Error('Must supply desk to run thread from'); + } + const res = await fetch(`${this.url}/spider/${desk}/${inputMark}/${threadName}/${outputMark}.json`, { + ...this.fetchOptions, + method: 'POST', + body: JSON.stringify(body), + }); + return res.json(); + } + /** + * Utility function to connect to a ship that has its *.arvo.network domain configured. + * + * @param name Name of the ship e.g. zod + * @param code Code to log in + */ + static async onArvoNetwork(ship, code) { + const url = `https://${ship}.arvo.network`; + return await Urbit.authenticate({ ship, url, code }); + } +} +export default Urbit; +//# sourceMappingURL=Urbit.js.map \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/Urbit.js.map b/pkg/npm/http-api/tmp/Urbit.js.map new file mode 100644 index 000000000..2ef2ed00d --- /dev/null +++ b/pkg/npm/http-api/tmp/Urbit.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Urbit.js","sourceRoot":"","sources":["../src/Urbit.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/index.d.ts b/pkg/npm/http-api/tmp/index.d.ts new file mode 100644 index 000000000..5c39dfc41 --- /dev/null +++ b/pkg/npm/http-api/tmp/index.d.ts @@ -0,0 +1,3 @@ +export * from './types'; +import { Urbit } from './Urbit'; +export { Urbit as default, Urbit }; diff --git a/pkg/npm/http-api/tmp/index.js b/pkg/npm/http-api/tmp/index.js new file mode 100644 index 000000000..46ce972d6 --- /dev/null +++ b/pkg/npm/http-api/tmp/index.js @@ -0,0 +1,4 @@ +export * from './types'; +import { Urbit } from './Urbit'; +export { Urbit as default, Urbit }; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/index.js.map b/pkg/npm/http-api/tmp/index.js.map new file mode 100644 index 000000000..011e99d58 --- /dev/null +++ b/pkg/npm/http-api/tmp/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC"} \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/types.d.ts b/pkg/npm/http-api/tmp/types.d.ts new file mode 100644 index 000000000..361d94378 --- /dev/null +++ b/pkg/npm/http-api/tmp/types.d.ts @@ -0,0 +1,180 @@ +/** + * An urbit style path, rendered as a Javascript string + * @example + * `"/updates"` + */ +export declare type Path = string; +/** + * @p including leading sig, rendered as a string + * + * @example + * ```typescript + * "~sampel-palnet" + * ``` + * + */ +export declare type Patp = string; +/** + * @p not including leading sig, rendered as a string + * + * @example + * ```typescript + * "sampel-palnet" + * ``` + * + */ +export declare type PatpNoSig = string; +/** + * The name of a clay mark, as a string + * + * @example + * ```typescript + * "graph-update" + * ``` + */ +export declare type Mark = string; +/** + * The name of a gall agent, as a string + * + * @example + * + * ```typescript + * "graph-store" + * ``` + */ +export declare type GallAgent = string; +/** + * Description of an outgoing poke + * + * @typeParam Action - Typescript type of the data being poked + */ +export interface Poke { + /** + * Ship to poke. If left empty, the api lib will populate it with the ship that it is connected to. + * + * @remarks + * + * This should always be the ship that you are connected to + * + */ + ship?: PatpNoSig; + /** + */ + app: GallAgent; + /** + * Mark of the cage to be poked + * + */ + mark: Mark; + /** + * Vase of the cage of to be poked, as JSON + */ + json: Action; +} +/** + * Description of a scry request + */ +export interface Scry { + /** {@inheritDoc GallAgent} */ + app: GallAgent; + /** {@inheritDoc Path} */ + path: Path; +} +/** + * Description of a thread request + * + * @typeParam Action - Typescript type of the data being poked + */ +export interface Thread { + /** + * The mark of the input vase + */ + inputMark: Mark; + /** + * The mark of the output vase + */ + outputMark: Mark; + /** + * Name of the thread + * + * @example + * ```typescript + * "graph-add-nodes" + * ``` + */ + threadName: string; + /** + * Desk of thread + */ + desk?: string; + /** + * Data of the input vase + */ + body: Action; +} +export declare type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete'; +export interface PokeHandlers { + onSuccess?: () => void; + onError?: (e: any) => void; +} +export declare type PokeInterface = PokeHandlers & Poke; +export interface AuthenticationInterface { + ship: string; + url: string; + code: string; + verbose?: boolean; +} +/** + * Subscription event handlers + * + */ +export interface SubscriptionInterface { + /** + * Handle negative %watch-ack + */ + err?(error: any, id: string): void; + /** + * Handle %fact + */ + event?(data: any): void; + /** + * Handle %kick + */ + quit?(data: any): void; +} +export declare type OnceSubscriptionErr = 'quit' | 'nack' | 'timeout'; +export interface SubscriptionRequestInterface extends SubscriptionInterface { + /** + * The app to subscribe to + * @example + * `"graph-store"` + */ + app: GallAgent; + /** + * The path to which to subscribe + * @example + * `"/keys"` + */ + path: Path; +} +export interface headers { + 'Content-Type': string; + Cookie?: string; +} +export interface CustomEventHandler { + (data: any, response: string): void; +} +export interface SSEOptions { + headers?: { + Cookie?: string; + }; + withCredentials?: boolean; +} +export interface Message extends Record { + action: Action; + id?: number; +} +export declare class ResumableError extends Error { +} +export declare class FatalError extends Error { +} diff --git a/pkg/npm/http-api/tmp/types.js b/pkg/npm/http-api/tmp/types.js new file mode 100644 index 000000000..3d3a607cf --- /dev/null +++ b/pkg/npm/http-api/tmp/types.js @@ -0,0 +1,5 @@ +export class ResumableError extends Error { +} +export class FatalError extends Error { +} +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/types.js.map b/pkg/npm/http-api/tmp/types.js.map new file mode 100644 index 000000000..1c908503f --- /dev/null +++ b/pkg/npm/http-api/tmp/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAmMA,MAAM,OAAO,cAAe,SAAQ,KAAK;CAAG;AAE5C,MAAM,OAAO,UAAW,SAAQ,KAAK;CAAG"} \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/utils.d.ts b/pkg/npm/http-api/tmp/utils.d.ts new file mode 100644 index 000000000..75bdaf067 --- /dev/null +++ b/pkg/npm/http-api/tmp/utils.d.ts @@ -0,0 +1,16 @@ +export declare function camelize(str: string): string; +export declare function uncamelize(str: string, separator?: string): string; +/** + * Returns a hex string of given length. + * + * Poached from StackOverflow. + * + * @param len Length of hex string to return. + */ +export declare function hexString(len: number): string; +/** + * Generates a random UID. + * + * Copied from https://github.com/urbit/urbit/blob/137e4428f617c13f28ed31e520eff98d251ed3e9/pkg/interface/src/lib/util.js#L3 + */ +export declare function uid(): string; diff --git a/pkg/npm/http-api/tmp/utils.js b/pkg/npm/http-api/tmp/utils.js new file mode 100644 index 000000000..4a99da707 --- /dev/null +++ b/pkg/npm/http-api/tmp/utils.js @@ -0,0 +1,51 @@ +export function camelize(str) { + return str + .replace(/\s(.)/g, function ($1) { + return $1.toUpperCase(); + }) + .replace(/\s/g, '') + .replace(/^(.)/, function ($1) { + return $1.toLowerCase(); + }); +} +export function uncamelize(str, separator = '-') { + // Replace all capital letters by separator followed by lowercase one + var str = str.replace(/[A-Z]/g, function (letter) { + return separator + letter.toLowerCase(); + }); + return str.replace(new RegExp('^' + separator), ''); +} +/** + * Returns a hex string of given length. + * + * Poached from StackOverflow. + * + * @param len Length of hex string to return. + */ +export function hexString(len) { + const maxlen = 8; + const min = Math.pow(16, Math.min(len, maxlen) - 1); + const max = Math.pow(16, Math.min(len, maxlen)) - 1; + const n = Math.floor(Math.random() * (max - min + 1)) + min; + let r = n.toString(16); + while (r.length < len) { + r = r + hexString(len - maxlen); + } + return r; +} +/** + * Generates a random UID. + * + * Copied from https://github.com/urbit/urbit/blob/137e4428f617c13f28ed31e520eff98d251ed3e9/pkg/interface/src/lib/util.js#L3 + */ +export function uid() { + let str = '0v'; + str += Math.ceil(Math.random() * 8) + '.'; + for (let i = 0; i < 5; i++) { + let _str = Math.ceil(Math.random() * 10000000).toString(32); + _str = ('00000' + _str).substr(-5, 5); + str += _str + '.'; + } + return str.slice(0, -1); +} +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/utils.js.map b/pkg/npm/http-api/tmp/utils.js.map new file mode 100644 index 000000000..a5238c348 --- /dev/null +++ b/pkg/npm/http-api/tmp/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,GAAG;SACP,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAU;QACrC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC;SACD,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;SAClB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAU;QACnC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,SAAS,GAAG,GAAG;IACrD,qEAAqE;IACrE,IAAI,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,MAAc;QACtD,OAAO,SAAS,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IAC1C,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,GAAG,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,MAAM,GAAG,CAAC,CAAC;IACjB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IAC5D,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvB,OAAO,CAAC,CAAC,MAAM,GAAG,GAAG,EAAE;QACrB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;KACjC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,GAAG;IACjB,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5D,IAAI,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtC,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC;KACnB;IACD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC"} \ No newline at end of file From 1eaad36d4d0efcd488dc582d8879e96d6ceabac3 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Feb 2022 20:30:11 -0600 Subject: [PATCH 040/168] ames: working notifications --- pkg/arvo/sys/vane/ames.hoon | 74 +++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 16b573617..b295863be 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -724,6 +724,9 @@ $% [%wait date=@da] [%rest date=@da] == == + $: %c + $% $>(%warp task:clay) + == == $: %d $% [%flog flog:dill] == == @@ -742,6 +745,9 @@ $% $: %behn $% $>(%wake gift:behn) == == + $: ?(%behn %clay) + $% [%writ p=riot:clay] + == == $: %jael $% [%private-keys =life vein=(map life ring)] [%public-keys =public-keys-result] @@ -1044,6 +1050,8 @@ ?- sign [@ %done *] (on-take-done:event-core wire error.sign) [@ %boon *] (on-take-boon:event-core wire payload.sign) + :: + [?(%clay %behn) %writ *] (on-take-clay-bide:fine:event-core wire p.sign) :: [%behn %wake *] (on-take-wake:event-core wire error.sign) :: @@ -1241,7 +1249,7 @@ ?- res ~ ~ [~ ~] ``noun+!>((encode-response:fine:ven path ~)) - [~ ~ *] ``noun+!>((encode-response:fine:ven path [p q.q]:u.u.res)) + [~ ~ *] ``noun+!>((encode-response:fine:ven path `[p q.q]:u.u.res)) == == -- @@ -2521,7 +2529,43 @@ |= =path ^+ event-core =. hear.state (~(put ju hear.state) path duct) - event-core + :: TODO: other vanes? + (bide-clay path) + :: + ++ bide-clay + |= =path + ^+ event-core + ?> ?=([@ @ *] path) + =/ =wire + (welp /fine/bide path) + =/ =ship (slav %p i.t.path) + =/ [vis=view bem=beam] + (need (de-omen path)) + =+ ;; =care:clay + ?^ vis car.vis + (rsh 3^1 vis) + =/ =rave:clay + [%sing care r.bem s.bem] + (emit duct %pass wire %c %warp p.bem q.bem `rave) + :: + ++ on-take-clay-bide + |= [=wire =riot:clay] + ?> ?=([%fine %bide @ *] wire) + =/ pax=path t.t.wire + ?> ?=([@ @ *] pax) + =/ pan=path [i t.t]:pax + =/ cas=(unit (cask)) + ?~ riot ~ + `[p q.q]:r.u.riot + ~& resolved-bide/pax + =/ wanted (~(get ju want.state) pax) + =. want.state (~(del by want.state) pax) + =/ =song + (encode-response pan cas) + %- emil + %+ turn [unix-duct.ames-state ~(tap in wanted)] + |= d=^duct + [d %give %howl pax song] :: ++ on-hear-response |= [=lane =packet dud=(unit goof)] @@ -2544,7 +2588,6 @@ (handle-response [from life.peer lane] peep rawr) -- |% -<<<<<<< HEAD +$ twit :: signed request $: signature=@ peep @@ -2599,7 +2642,7 @@ [(mod life.ames-state 16) (mod (lyfe:keys ship) 16) ~ syn] :: ++ encode-response ::TODO unit tests - |= [=path data=$@(~ (cask))] + |= [=path data=(unit (cask))] ^- song :: prepend request descriptions to each response packet :: @@ -2616,9 +2659,6 @@ :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) -<<<<<<< HEAD - =/ sig=@ (full:keys path (fall data ~)) -======= ::TODO should also sign the request path =/ sig=@ ::(full:keys path (fall data ~)) (fil 5 16 0xdead.beef) @@ -2657,9 +2697,10 @@ :: ++ sign |= msg=@ - %+ sign:ed:crypto msg + (fil 5 16 0xdead.beef) + :: %+ sign:ed:crypto msg ::TODO get just the sgn key! - sec:ex:crypto-core.ames-state + :: sec:ex:crypto-core.ames-state :: ++ lyfe |= who=ship @@ -2680,10 +2721,12 @@ :: ++ veri |= [who=ship lyf=life sig=@ dat=@] - %^ veri:ed:crypto sig - dat + & + + ::%^ veri:ed:crypto sig + :: dat ::TODO get jsut the sign key! - pub:ex:(com:nu:crub:crypto (pass:keys who lyf)) + :: pub:ex:(com:nu:crub:crypto (pass:keys who lyf)) :: ++ meri |= [who=ship lyf=life pax=path sig=@ dat=$@(~ (cask))] @@ -2697,9 +2740,6 @@ =/ =peer-state (got-peer-state ship) lane:(need route.peer-state) - ::TODO get from state -<<<<<<< HEAD - (rof `[our ~ ~] [%ames %x] [our %$ da+now] path) :: ++ decode-request |= =hoot @@ -2771,9 +2811,11 @@ ^+ event-core ?> ?=([@ *] path.peep) =/ =path [i.path.peep (scot %p from) t.path.peep] + ~& path + ~& ~(key by part.state) ?: =(0 siz.rawr) ?> =(~ dat.rawr) - (process-response path.peep ~) + (process-response [from life] path sig.rawr ~) ?. (~(has by part.state) path) :: we did not initiate this request, or it's been cancelled :: From f31bf964ceb53a10fc5d9d12c46a7d67c6b7cf50 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Feb 2022 20:30:50 -0600 Subject: [PATCH 041/168] urbit: working notifications support --- pkg/urbit/include/c/motes.h | 1 + pkg/urbit/vere/io/ames.c | 107 +++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/pkg/urbit/include/c/motes.h b/pkg/urbit/include/c/motes.h index b5a3a50ab..fbb0a8d39 100644 --- a/pkg/urbit/include/c/motes.h +++ b/pkg/urbit/include/c/motes.h @@ -72,6 +72,7 @@ # define c3__ber c3_s3('b','e','r') # define c3__bias c3_s4('b','i','a','s') # define c3__bic c3_s3('b','i','c') +# define c3__bide c3_s4('b','i','d', 'e') # define c3__bind c3_s4('b','i','n','d') # define c3__bink c3_s4('b','i','n','k') # define c3__bird c3_s4('b','i','r','d') diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 202304d57..2563fa6c9 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -12,6 +12,7 @@ typedef struct _u3_fine { c3_y ver_y; // fine protocol u3p(u3h_root) sac_p; // scry cache hashtable + u3p(u3h_root) bid_p; // pending notifications struct _u3_ames* sam_u; // ames backpointer } u3_fine; @@ -130,6 +131,8 @@ }; } u3_pact; +static void _fine_got_pack(u3_pact*, u3_noun); + /* u3_panc: deconstructed incoming packet */ typedef struct _u3_panc { @@ -940,6 +943,58 @@ _ames_czar(u3_pact* pac_u) } } +/* _fine_ef_howl(): broadcast notification of newly bound data + */ +static void +_fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) { + u3l_log("howling\n"); + u3_noun pas = lis; + + // TODO; refactor, + u3_weak fra = u3_none; + c3_w cur_w = 1; + u3k(pas); + u3l_log("howling a\n"); + while(pas != u3_nul) { + u3l_log("howling in list\n"); + u3_noun key = u3nc(u3k(pax), u3i_word(cur_w)); + u3h_put(sam_u->fin_s.sac_p, key, u3k(u3h(pas))); + pas = u3t(pas); + u3z(key); + } + u3l_log("howling after list\n"); + u3m_p("pax", pax); + u3_weak who = u3h_get(sam_u->fin_s.bid_p, pax); + if ( who == u3_none ) { + u3l_log("no listeners\n"); + } else { + + u3_noun her = who; + while ( her != u3_nul ) { + //u3m_p("her", her); + + /*u3_weak lac = _ames_lane_from_cache(sam_u->lax_p, u3h(her)); + if ( lac == u3_none ) { + u3l_log("no lane\n"); + u3m_p("for", u3h(her)); + her = u3t(her); + continue; + }*/ + u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); + pac_u->sam_u = sam_u; + c3_d her_d[2]; + u3r_chubs(0, 2, her_d, u3k(u3h(her))); + u3l_log(" %"PRIu64", %" PRIu64 "\n", her_d[0], her_d[1]); + + // TODO: fix for non-galaxy case + pac_u->imp_y = her_d[0]; + + _fine_got_pack(pac_u, u3h(lis)); + her = u3t(her); + } + } +} + /* _ames_ef_send(): send packet to network (v4). */ static void @@ -1326,16 +1381,52 @@ _ames_skip(u3_body* bod_u) { static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) { + u3l_log("got pack\n"); pac_u->len_w = u3r_met(3, fra); pac_u->hun_y = c3_calloc(pac_u->len_w); + u3m_p("fra", fra); u3r_bytes(0, pac_u->len_w, pac_u->hun_y, fra); + u3l_log("preczar\n"); - _fine_send(pac_u); + _ames_czar(pac_u); //_fine_send(pac_u); + u3l_log("postczar\n"); u3z(fra); } +static void _fine_bide(u3_pact* pac_u, u3_noun pax) +{ + u3_ames* sam_u = pac_u->sam_u; + u3_weak lis = u3h_get(sam_u->fin_s.bid_p, pax); + + if ( u3_none == lis ) { + lis = u3_nul; + } + u3_noun her = u3i_chubs(2, pac_u->req_u.pre_u.sen_d); + u3_noun new = u3nc(her, lis); + // TODO: linear search bad + + u3l_log("put in hashtable\n"); + u3m_p("hashtable", new); + u3_noun car, res; + u3x_cell(pax, &car, &res); + u3_noun our = u3dc("scot", 'p', u3i_chubs(2, sam_u->car_u.pir_u->who_d)); + + u3_noun pat = u3nt(car, our, res); + u3h_put(sam_u->fin_s.bid_p, pat, new); + u3m_p("pat", pat); + + u3_noun cad = u3nc(c3__bide, pat); + u3_noun wir = u3nc(c3__fine, u3_nul); + u3_ovum* ovo_u = u3_ovum_init(0, c3__ames, u3k(wir), u3k(cad)); + u3_auto_plan(&sam_u->car_u, ovo_u); + + u3z(wir); + u3z(cad); +} + + /* _fine_pack_scry_cb(): receive all packets for datum out of fine */ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) @@ -1345,15 +1436,18 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) u3_pact* pac_u = vod_p; u3_ames* sam_u = pac_u->sam_u; u3_weak pas = u3r_at(7, nun); + u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); if(pas == u3_none) { + // TODO: send %bide u3l_log("no result, bailing\n"); + _fine_bide(pac_u, u3k(pax)); _ames_pact_free(pac_u); + u3z(pax); u3z(nun); return; } - c3_assert( 1 == pac_u->typ_y); + c3_assert( 1 == pac_u->typ_y ); u3_weak fra = u3_none; - u3_noun pax = u3i_string(pac_u->req_u.pat_c); c3_w cur_w = 1; u3k(pas); while(pas != u3_nul) { @@ -1903,6 +1997,10 @@ _ames_kick_newt(u3_ames* sam_u, u3_noun tag, u3_noun dat) } break; case c3__howl: { + u3_noun pat = u3k(u3h(dat)); + u3_noun lis = u3k(u3t(dat)); + u3l_log("fine: howl\n"); + _fine_ef_howl(sam_u, pat, lis); ret_o = c3y; } break; @@ -2056,6 +2154,9 @@ u3_ames_io_init(u3_pier* pir_u) // 50 bytes (average) per path * 100_000 = 5MB sam_u->fin_s.sac_p = u3h_new_cache(100000); + // hashtable for notificatiosn + sam_u->fin_s.bid_p = u3h_new_cache(100000); + //NOTE some numbers on memory usage for the lane cache // // assuming we store: From 86bafc98389a4a3996e87db987bac4c6702278a8 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Feb 2022 20:47:55 -0600 Subject: [PATCH 042/168] urbit: unify path format --- pkg/urbit/vere/io/ames.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 2563fa6c9..2488e9592 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -1399,7 +1399,6 @@ static void _fine_bide(u3_pact* pac_u, u3_noun pax) { u3_ames* sam_u = pac_u->sam_u; u3_weak lis = u3h_get(sam_u->fin_s.bid_p, pax); - if ( u3_none == lis ) { lis = u3_nul; } @@ -1409,15 +1408,11 @@ static void _fine_bide(u3_pact* pac_u, u3_noun pax) u3l_log("put in hashtable\n"); u3m_p("hashtable", new); - u3_noun car, res; - u3x_cell(pax, &car, &res); - u3_noun our = u3dc("scot", 'p', u3i_chubs(2, sam_u->car_u.pir_u->who_d)); - u3_noun pat = u3nt(car, our, res); - u3h_put(sam_u->fin_s.bid_p, pat, new); - u3m_p("pat", pat); + u3h_put(sam_u->fin_s.bid_p, pax, new); + u3m_p("pax", pax); - u3_noun cad = u3nc(c3__bide, pat); + u3_noun cad = u3nc(c3__bide, pax); u3_noun wir = u3nc(c3__fine, u3_nul); u3_ovum* ovo_u = u3_ovum_init(0, c3__ames, u3k(wir), u3k(cad)); u3_auto_plan(&sam_u->car_u, ovo_u); @@ -1437,6 +1432,7 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) u3_ames* sam_u = pac_u->sam_u; u3_weak pas = u3r_at(7, nun); u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); + u3m_p("pax", pax); if(pas == u3_none) { // TODO: send %bide u3l_log("no result, bailing\n"); From 6ee2e1626f07d9659f6ff3a6c48d07c7329cd2b6 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Feb 2022 20:48:04 -0600 Subject: [PATCH 043/168] ames: unify path format --- pkg/arvo/sys/vane/ames.hoon | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index b295863be..ea4d27141 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -1229,9 +1229,7 @@ :: t.t.tyl is expected to be a scry path of the shape /vc/desk/rev/etc, :: so we need to give it the right shape :: - =/ =path - [i.t.t.tyl (scot %p our) t.t.t.tyl] - =* pax t.t.tyl + =* path t.t.tyl ?~ nom=(de-omen path) ~ :: we only support scrying into clay, :: and only if the data is fully public. @@ -2500,6 +2498,7 @@ ++ on-keen |= =path ^+ event-core + ~& path =/ omen ~| [%fine %invalid-namespace-path path] (need (de-omen path)) @@ -2534,6 +2533,7 @@ :: ++ bide-clay |= =path + ~& bide-clay/path ^+ event-core ?> ?=([@ @ *] path) =/ =wire @@ -2552,8 +2552,6 @@ |= [=wire =riot:clay] ?> ?=([%fine %bide @ *] wire) =/ pax=path t.t.wire - ?> ?=([@ @ *] pax) - =/ pan=path [i t.t]:pax =/ cas=(unit (cask)) ?~ riot ~ `[p q.q]:r.u.riot @@ -2561,7 +2559,7 @@ =/ wanted (~(get ju want.state) pax) =. want.state (~(del by want.state) pax) =/ =song - (encode-response pan cas) + (encode-response pax cas) %- emil %+ turn [unix-duct.ames-state ~(tap in wanted)] |= d=^duct @@ -2584,6 +2582,7 @@ ?> =(sndr-tick.packet (mod life.peer 16)) :: =/ [=peep =purr] (decode-request-info `@ux`content.packet) + ~& path.peep =/ =rawr (decode-response-packet purr) (handle-response [from life.peer lane] peep rawr) -- @@ -2632,6 +2631,7 @@ :: ++ encode-request |= [=ship =path num=@ud] + ~& enc-req/path ::NOTE path is expected to be a namespace path without the ship ^- hoot ^- @ =+ bod=(request-body path num) @@ -2643,6 +2643,7 @@ :: ++ encode-response ::TODO unit tests |= [=path data=(unit (cask))] + ~& enc-res/path ^- song :: prepend request descriptions to each response packet :: @@ -2784,10 +2785,6 @@ ++ send-request |= [=ship =path num=@ud] ^+ event-core - :: make sure we exclude the ship from the path proper, - :: since it already gets included in the request header - :: - =. path (oust [1 1] path) =/ =lane:ames (get-lane ship) =/ =hoot (encode-request ship path 1) %- emit @@ -2809,19 +2806,16 @@ ++ handle-response |= [[from=ship =life =lane:ames] =peep =rawr] ^+ event-core - ?> ?=([@ *] path.peep) - =/ =path [i.path.peep (scot %p from) t.path.peep] - ~& path ~& ~(key by part.state) ?: =(0 siz.rawr) ?> =(~ dat.rawr) - (process-response [from life] path sig.rawr ~) - ?. (~(has by part.state) path) + (process-response [from life] path.peep sig.rawr ~) + ?. (~(has by part.state) path.peep) :: we did not initiate this request, or it's been cancelled :: !! =/ partial=partial-fine - (~(got by part.state) path) + (~(got by part.state) path.peep) =. partial ?: (~(has by fragments.partial) num.peep) partial @@ -2837,10 +2831,10 @@ :: we have all the parts now, construct the full response :: =/ =roar (decode-response-msg partial) - (process-response [from life] path [sig dat]:roar) + (process-response [from life] path.peep [sig dat]:roar) :: otherwise, store the part, and send out the next request :: - =. part.state (~(put by part.state) path partial) + =. part.state (~(put by part.state) path.peep partial) =/ next-num=@ud =/ next=@ud +(num.peep) :: we should receive responses in order, but in case we don't... From 7bf6356d737303d24d0474043c6142e0c95b65e4 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Feb 2022 20:49:31 -0600 Subject: [PATCH 044/168] urbit: remove unnecessary logs --- pkg/urbit/vere/io/ames.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 2488e9592..869fc966f 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -947,23 +947,18 @@ _ames_czar(u3_pact* pac_u) */ static void _fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) { - u3l_log("howling\n"); u3_noun pas = lis; // TODO; refactor, u3_weak fra = u3_none; c3_w cur_w = 1; u3k(pas); - u3l_log("howling a\n"); while(pas != u3_nul) { - u3l_log("howling in list\n"); u3_noun key = u3nc(u3k(pax), u3i_word(cur_w)); u3h_put(sam_u->fin_s.sac_p, key, u3k(u3h(pas))); pas = u3t(pas); u3z(key); } - u3l_log("howling after list\n"); - u3m_p("pax", pax); u3_weak who = u3h_get(sam_u->fin_s.bid_p, pax); if ( who == u3_none ) { u3l_log("no listeners\n"); @@ -971,6 +966,7 @@ _fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) { u3_noun her = who; while ( her != u3_nul ) { + // TODO: prime cache maybe??? //u3m_p("her", her); /*u3_weak lac = _ames_lane_from_cache(sam_u->lax_p, u3h(her)); @@ -984,7 +980,6 @@ _fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) { pac_u->sam_u = sam_u; c3_d her_d[2]; u3r_chubs(0, 2, her_d, u3k(u3h(her))); - u3l_log(" %"PRIu64", %" PRIu64 "\n", her_d[0], her_d[1]); // TODO: fix for non-galaxy case pac_u->imp_y = her_d[0]; @@ -1381,17 +1376,14 @@ _ames_skip(u3_body* bod_u) { static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) { - u3l_log("got pack\n"); pac_u->len_w = u3r_met(3, fra); pac_u->hun_y = c3_calloc(pac_u->len_w); - u3m_p("fra", fra); u3r_bytes(0, pac_u->len_w, pac_u->hun_y, fra); - u3l_log("preczar\n"); _ames_czar(pac_u); //_fine_send(pac_u); - u3l_log("postczar\n"); + u3z(fra); } @@ -1431,11 +1423,9 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) u3_pact* pac_u = vod_p; u3_ames* sam_u = pac_u->sam_u; u3_weak pas = u3r_at(7, nun); - u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); - u3m_p("pax", pax); + u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); u3m_p("pax", pax); if(pas == u3_none) { // TODO: send %bide - u3l_log("no result, bailing\n"); _fine_bide(pac_u, u3k(pax)); _ames_pact_free(pac_u); u3z(pax); From 9dad96332b5656f6c210296a015700b57b40f5f4 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 1 Feb 2022 20:50:02 -0600 Subject: [PATCH 045/168] ames: remove logging --- pkg/arvo/sys/vane/ames.hoon | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index ea4d27141..62d958f8a 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2498,7 +2498,6 @@ ++ on-keen |= =path ^+ event-core - ~& path =/ omen ~| [%fine %invalid-namespace-path path] (need (de-omen path)) @@ -2533,7 +2532,6 @@ :: ++ bide-clay |= =path - ~& bide-clay/path ^+ event-core ?> ?=([@ @ *] path) =/ =wire @@ -2555,7 +2553,6 @@ =/ cas=(unit (cask)) ?~ riot ~ `[p q.q]:r.u.riot - ~& resolved-bide/pax =/ wanted (~(get ju want.state) pax) =. want.state (~(del by want.state) pax) =/ =song @@ -2582,7 +2579,6 @@ ?> =(sndr-tick.packet (mod life.peer 16)) :: =/ [=peep =purr] (decode-request-info `@ux`content.packet) - ~& path.peep =/ =rawr (decode-response-packet purr) (handle-response [from life.peer lane] peep rawr) -- @@ -2631,7 +2627,6 @@ :: ++ encode-request |= [=ship =path num=@ud] - ~& enc-req/path ::NOTE path is expected to be a namespace path without the ship ^- hoot ^- @ =+ bod=(request-body path num) @@ -2643,7 +2638,6 @@ :: ++ encode-response ::TODO unit tests |= [=path data=(unit (cask))] - ~& enc-res/path ^- song :: prepend request descriptions to each response packet :: @@ -2794,7 +2788,6 @@ |= [[from=ship =life] =path sig=@ data=$@(~ (cask))] ^+ event-core ?> (meri:keys from life path sig data) - ~& got-response/path =. event-core %- emil %+ turn ~(tap in (~(get ju want.state) path)) @@ -2806,7 +2799,6 @@ ++ handle-response |= [[from=ship =life =lane:ames] =peep =rawr] ^+ event-core - ~& ~(key by part.state) ?: =(0 siz.rawr) ?> =(~ dat.rawr) (process-response [from life] path.peep sig.rawr ~) From 1302c5fa0bbace00c44b6ff361c53209f2cf8077 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 2 Feb 2022 19:54:17 +0100 Subject: [PATCH 046/168] fine: fix broken +full:keys callsite Straggler from last commit about data type consistency. --- pkg/arvo/sys/vane/ames.hoon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 0c2e8440f..6f9e30592 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2544,10 +2544,10 @@ :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) - =/ sig=@ (full:keys path (fall data ~)) + =/ sig=@ (full:keys path data) ?~ data [sig]~ %+ rip 13 ::NOTE 1024 bytes - (cat 3 sig (jam u.data)) ::TODO should include life + (cat 3 sig (jam data)) ::TODO should include life :: sign & packetize the fragments :: %- head From 83e315cccdb6a4be2f335e678681a82c50cefaa1 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 2 Feb 2022 20:10:30 +0100 Subject: [PATCH 047/168] lull: add arms to ex:acru for separate keys We may want _just_ the encryption key, or _just_ the signing key. --- pkg/arvo/sys/lull.hoon | 2 ++ pkg/arvo/sys/vane/ames.hoon | 16 +++++++++++----- pkg/arvo/sys/zuse.hoon | 8 ++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 27e5016c6..6498b22f0 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -434,7 +434,9 @@ |% ++ fig *@uvH :: fingerprint ++ pac *@uvG :: default passcode ++ pub *pass :: public key + ++ par *[cry=@ sgn=@] :: shared pair ++ sec *ring :: private key + ++ raw *[cry=@ sgn=@] :: secret pair -- ::ex :: ++ nu ^? :: reconstructors |% ++ pit |~([a=@ b=@] ^?(..nu)) :: from [width seed] diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 6f9e30592..b911dc8ad 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -581,11 +581,12 @@ =bug =fine-state == +:: +$ ames-state-5 $: peers=(map ship ship-state-5) =unix=duct =life - crypto-core=acru:ames + crypto-core=* =bug == +$ ship-state-5 @@ -1010,6 +1011,13 @@ %= old peers (~(run by peers.old) ship-state-5-to-6) bug [bug.old *fine-state] + :: + crypto-core + %- nol:nu:crub:crypto + ~| [%ames %strange-pk-reload life.old] + ;; private-key + =< q.q %- need %- need + (rof ~ %j [our %vein da+now] /(scot %ud life.old)) == :: ++ ship-state-5-to-6 @@ -2580,8 +2588,7 @@ ++ sign |= msg=@ %+ sign:ed:crypto msg - ::TODO get just the sgn key! - sec:ex:crypto-core.ames-state + sgn:raw:ex:crypto-core.ames-state :: ++ lyfe |= who=ship @@ -2604,8 +2611,7 @@ |= [who=ship lyf=life sig=@ dat=@] %^ veri:ed:crypto sig dat - ::TODO get jsut the sign key! - pub:ex:(com:nu:crub:crypto (pass:keys who lyf)) + sgn:par:ex:(com:nu:crub:crypto (pass:keys who lyf)) :: ++ meri |= [who=ship lyf=life pax=path sig=@ dat=$@(~ (cask))] diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index 4481d43e8..7b822922d 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -1516,11 +1516,19 @@ ++ pub :: public key ^- pass (cat 3 'b' (cat 8 sgn.^pub cry.^pub)) + :: :: ++par:ex:crub:crypto + ++ par :: shared pair + ^pub :: :: ++sec:ex:crub:crypto ++ sec :: private key ^- ring ?~ sek ~| %pubkey-only !! (cat 3 'B' (cat 8 sgn.u.sek cry.u.sek)) + :: :: ++raw:ex:crub:crypto + ++ raw :: secret pair + ^- [cry=@ sgn=@] + ~| %pubkey-only + (need sek) -- ::ex :: :: ++nu:crub:crypto ++ nu :: From a71cf68170640c9692a92e01148f5af3b9e2e92a Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 2 Feb 2022 14:50:12 -0600 Subject: [PATCH 048/168] urbit: refactor caching --- pkg/urbit/vere/io/ames.c | 68 +++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 869fc966f..e1c6f84b5 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -862,6 +862,7 @@ _ames_czar(u3_pact* pac_u) u3_ames* sam_u = pac_u->sam_u; c3_y imp_y = pac_u->imp_y; + u3l_log("ames: send to %u\n", imp_y); pac_u->lan_u.por_s = _ames_czar_port(imp_y); @@ -943,22 +944,35 @@ _ames_czar(u3_pact* pac_u) } } +/* _fine_put_cache(): put list of packets into cache + */ +static void +_fine_put_cache(u3_ames* sam_u, u3_noun pax, u3_noun lis) +{ + u3_noun beg = lis; + + c3_w cur_w = 1; + while ( lis != u3_nul ) { + u3_noun key = u3nc(u3k(pax), u3i_word(cur_w)); + u3h_put(sam_u->fin_s.sac_p, key, u3k(u3h(lis))); + + lis = u3t(lis); + cur_w++; + u3z(key); + } + u3l_log("put %u packets at\n", cur_w); + u3m_p("path", pax); +} + /* _fine_ef_howl(): broadcast notification of newly bound data */ static void -_fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) { +_fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) +{ u3_noun pas = lis; - // TODO; refactor, - u3_weak fra = u3_none; - c3_w cur_w = 1; - u3k(pas); - while(pas != u3_nul) { - u3_noun key = u3nc(u3k(pax), u3i_word(cur_w)); - u3h_put(sam_u->fin_s.sac_p, key, u3k(u3h(pas))); - pas = u3t(pas); - u3z(key); - } + _fine_put_cache(sam_u, pax, pas); + u3_weak who = u3h_get(sam_u->fin_s.bid_p, pax); if ( who == u3_none ) { u3l_log("no listeners\n"); @@ -1391,18 +1405,15 @@ static void _fine_bide(u3_pact* pac_u, u3_noun pax) { u3_ames* sam_u = pac_u->sam_u; u3_weak lis = u3h_get(sam_u->fin_s.bid_p, pax); + if ( u3_none == lis ) { lis = u3_nul; } + u3_noun her = u3i_chubs(2, pac_u->req_u.pre_u.sen_d); u3_noun new = u3nc(her, lis); - // TODO: linear search bad - - u3l_log("put in hashtable\n"); - u3m_p("hashtable", new); u3h_put(sam_u->fin_s.bid_p, pax, new); - u3m_p("pax", pax); u3_noun cad = u3nc(c3__bide, pax); u3_noun wir = u3nc(c3__fine, u3_nul); @@ -1418,12 +1429,12 @@ static void _fine_bide(u3_pact* pac_u, u3_noun pax) */ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) { - u3l_log("got scry result\n"); u3_pact* pac_u = vod_p; u3_ames* sam_u = pac_u->sam_u; u3_weak pas = u3r_at(7, nun); - u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); u3m_p("pax", pax); + u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); + if(pas == u3_none) { // TODO: send %bide _fine_bide(pac_u, u3k(pax)); @@ -1434,23 +1445,25 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) } c3_assert( 1 == pac_u->typ_y ); u3_weak fra = u3_none; + _fine_put_cache(sam_u, pax, pas); + c3_w cur_w = 1; - u3k(pas); - while(pas != u3_nul) { - u3_noun key = u3nc(u3k(pax), u3i_word(cur_w)); - u3h_put(sam_u->fin_s.sac_p, key, u3h(pas)); + + // find requested fragment + while ( pas != u3_nul ) { if ( pac_u->req_u.fra_w == cur_w ) { fra = u3k(u3h(pas)); } cur_w++; pas = u3t(pas); - u3z(key); } + if ( fra == u3_none ) { u3l_log("fragment number out of range\n"); } else { _fine_got_pack(pac_u, fra); } + u3z(pas); u3z(nun); } @@ -1496,7 +1509,7 @@ static void _fine_hear_request(u3_ames* sam_u, c3_assert( c3y == _fine_sift_requ(&hed_u, &req_u, len_w, hun_y)); - u3_noun pat = u3i_string(req_u.pat_c); + u3_noun pat = u3do("stab", u3i_string(req_u.pat_c)); u3_noun key = u3nc(u3k(pat), u3i_word(req_u.fra_w)); u3_weak cac = u3h_git(sam_u->fin_s.sac_p, key); @@ -1511,11 +1524,16 @@ static void _fine_hear_request(u3_ames* sam_u, memcpy(&pac_u->lan_u, &lan_u, sizeof(u3_lane)); + if ( pac_u->req_u.pre_u.sen_d[0] < 256 + && pac_u->req_u.pre_u.sen_d[1] == 0 ) { + pac_u->imp_y = pac_u->req_u.pre_u.sen_d[0]; + } + if ( u3_none == cac ) { // cache miss u3_noun pax = u3nt(u3i_string("fine"), u3i_string("message"), - u3do("stab", u3k(pat))); + u3k(pat)); u3_pier_peek_last(sam_u->car_u.pir_u, u3_nul, c3__ax, u3_nul, pax, pac_u, _fine_pack_scry_cb); From 5776226a6c3fb960ed40492c7c47e51c0bb17ed1 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 2 Feb 2022 21:52:48 +0100 Subject: [PATCH 049/168] lull: add acru arms for simply signing & authing Instead of exporting keys so that caller can do this themselves, we expose arms for signing and authenticating that produce and operate on just the signature, without mangling it into the message. --- pkg/arvo/sys/lull.hoon | 4 ++-- pkg/arvo/sys/vane/ames.hoon | 10 ++++------ pkg/arvo/sys/zuse.hoon | 22 ++++++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 6498b22f0..febec18e0 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -424,7 +424,9 @@ ++ as ^? :: asym ops |% ++ seal |~([a=pass b=@] *@) :: encrypt to a ++ sign |~(a=@ *@) :: certify as us + ++ sigh |~(a=@ *@) :: certification only ++ sure |~(a=@ *(unit @)) :: authenticate from us + ++ safe |~([a=@ b=@] *?) :: authentication only ++ tear |~([a=pass b=@] *(unit @)) :: accept from a -- ::as :: ++ de |~([a=@ b=@] *(unit @)) :: symmetric de, soft @@ -434,9 +436,7 @@ |% ++ fig *@uvH :: fingerprint ++ pac *@uvG :: default passcode ++ pub *pass :: public key - ++ par *[cry=@ sgn=@] :: shared pair ++ sec *ring :: private key - ++ raw *[cry=@ sgn=@] :: secret pair -- ::ex :: ++ nu ^? :: reconstructors |% ++ pit |~([a=@ b=@] ^?(..nu)) :: from [width seed] diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index b911dc8ad..813bdd90c 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2586,9 +2586,7 @@ (sign (mess our life.ames-state path data)) :: ++ sign - |= msg=@ - %+ sign:ed:crypto msg - sgn:raw:ex:crypto-core.ames-state + sigh:as:crypto-core.ames-state :: ++ lyfe |= who=ship @@ -2609,9 +2607,9 @@ :: ++ veri |= [who=ship lyf=life sig=@ dat=@] - %^ veri:ed:crypto sig - dat - sgn:par:ex:(com:nu:crub:crypto (pass:keys who lyf)) + ^- ? + =/ =^pass (pass who lyf) + (safe:as:(com:nu:crub:crypto pass) sig dat) :: ++ meri |= [who=ship lyf=life pax=path sig=@ dat=$@(~ (cask))] diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index 7b822922d..38cc98d1d 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -1448,17 +1448,27 @@ |% :: :: ++sign:as:crub: ++ sign :: + |= msg=@ + ^- @ux + (jam [(sigh msg) msg]) + :: :: ++sigh:as:crub: + ++ sigh :: |= msg=@ ^- @ux ?~ sek ~| %pubkey-only !! - (jam [(sign:ed msg sgn.u.sek) msg]) + (sign:ed msg sgn.u.sek) :: :: ++sure:as:crub: ++ sure :: |= txt=@ ^- (unit @ux) =+ ;;([sig=@ msg=@] (cue txt)) - ?. (veri:ed sig msg sgn.pub) ~ + ?. (safe sig msg) ~ (some msg) + :: :: ++safe:as:crub: + ++ safe + |= [sig=@ msg=@] + ^- ? + (veri:ed sig msg sgn.pub) :: :: ++seal:as:crub: ++ seal :: |= [bpk=pass msg=@] @@ -1516,19 +1526,11 @@ ++ pub :: public key ^- pass (cat 3 'b' (cat 8 sgn.^pub cry.^pub)) - :: :: ++par:ex:crub:crypto - ++ par :: shared pair - ^pub :: :: ++sec:ex:crub:crypto ++ sec :: private key ^- ring ?~ sek ~| %pubkey-only !! (cat 3 'B' (cat 8 sgn.u.sek cry.u.sek)) - :: :: ++raw:ex:crub:crypto - ++ raw :: secret pair - ^- [cry=@ sgn=@] - ~| %pubkey-only - (need sek) -- ::ex :: :: ++nu:crub:crypto ++ nu :: From 39959942d28d673868c5a939ae22e7e68a047b0a Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 2 Feb 2022 22:16:16 +0100 Subject: [PATCH 050/168] ames: use +safe:as:crub instead of +veri:ed +safe now exists to wrap that, so we should use it instead of deriving the relevant key and calling +veri:ed directly. --- pkg/arvo/sys/vane/ames.hoon | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 813bdd90c..440ef9c02 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -383,15 +383,13 @@ :: only a star can sponsor a comet :: ?> =(%king (clan:title (^sein:title sndr.packet))) + =/ crub (com:nu:crub:crypto public-key.open-packet) :: comet public-key must hash to its @p address :: - ?> =(sndr.packet fig:ex:(com:nu:crub:crypto public-key.open-packet)) + ?> =(sndr.packet fig:ex:crub) :: verify signature :: - :: Logic duplicates +com:nu:crub:crypto and +sure:as:crub:crypto. - :: - =/ key (end 8 (rsh 3 public-key.open-packet)) - ?> (veri:ed:crypto signature signed key) + ?> (safe:as:crub signature signed) open-packet :: +encode-shut-packet: encrypt and packetize a $shut-packet :: From cb706ee8ae2024c192cd6bef741f2f91743383f3 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 3 Feb 2022 00:45:16 +0100 Subject: [PATCH 051/168] dbug: update for ames' new alien-agenda --- pkg/arvo/app/dbug.hoon | 1 + pkg/interface/dbug/src/js/views/ames.js | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/pkg/arvo/app/dbug.hoon b/pkg/arvo/app/dbug.hoon index b5c4da98c..d42e08aca 100644 --- a/pkg/arvo/app/dbug.hoon +++ b/pkg/arvo/app/dbug.hoon @@ -524,6 +524,7 @@ :~ 'messages'^(numb (lent messages)) 'packets'^(numb ~(wyt in packets)) 'heeds'^(set-array heeds from-duct) + 'keens'^(set-array keens path) == :: :: json for known peer is structured to closely match the peer-state type. diff --git a/pkg/interface/dbug/src/js/views/ames.js b/pkg/interface/dbug/src/js/views/ames.js index c656d1360..24d54fff6 100644 --- a/pkg/interface/dbug/src/js/views/ames.js +++ b/pkg/interface/dbug/src/js/views/ames.js @@ -35,6 +35,16 @@ export class Ames extends Component { api.getPeer(who); } + renderPaths(paths) { + const items = paths.map(path => { + return { + key: path, + jsx: path + } + }); + return ; + } + renderDucts(ducts) { const items = ducts.map(duct => { return { @@ -213,6 +223,7 @@ export class Ames extends Component { Pending messages: {peer.alien.messages} Pending packets: {peer.alien.packets} Heeds: {this.renderDucts(peer.alien.heeds)} + Keens: {this.renderPaths(peer.alien.keens)} ); } else if (peer.known) { const p = peer.known; From a8574df4010e7612792445e8e4e440519fefa1b9 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 3 Feb 2022 13:49:38 +0100 Subject: [PATCH 052/168] ames: retrieve pk from old crypto core on load Since we cannot scry the key out of jael during load, and the alternative is defering this logic through the larval core in some way, we simply include the type for the old acru interface, letting us reuse the old core to initialize the new one. --- pkg/arvo/sys/vane/ames.hoon | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 440ef9c02..967065d32 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -584,7 +584,7 @@ $: peers=(map ship ship-state-5) =unix=duct =life - crypto-core=* + crypto-core=acru-5 =bug == +$ ship-state-5 @@ -596,6 +596,29 @@ packets=(set =blob) heeds=(set duct) == +++ acru-5 $_ ^? + |% + ++ as ^? + |% ++ seal |~([a=pass b=@] *@) + ++ sign |~(a=@ *@) + ++ sure |~(a=@ *(unit @)) + ++ tear |~([a=pass b=@] *(unit @)) + -- + ++ de |~([a=@ b=@] *(unit @)) + ++ dy |~([a=@ b=@] *@) + ++ en |~([a=@ b=@] *@) + ++ ex ^? + |% ++ fig *@uvH + ++ pac *@uvG + ++ pub *pass + ++ sec *ring + -- + ++ nu ^? + |% ++ pit |~([a=@ b=@] ^?(..nu)) + ++ nol |~(a=ring ^?(..nu)) + ++ com |~(a=pass ^?(..nu)) + -- + -- :: $fine-state: remote scry subsystem state :: :: hear: awaiting existence @@ -1007,15 +1030,9 @@ |= old=ames-state-5 ^- ^ames-state %= old - peers (~(run by peers.old) ship-state-5-to-6) - bug [bug.old *fine-state] - :: - crypto-core - %- nol:nu:crub:crypto - ~| [%ames %strange-pk-reload life.old] - ;; private-key - =< q.q %- need %- need - (rof ~ %j [our %vein da+now] /(scot %ud life.old)) + peers (~(run by peers.old) ship-state-5-to-6) + bug [bug.old *fine-state] + crypto-core (nol:nu:crub:crypto sec:ex:crypto-core.old) == :: ++ ship-state-5-to-6 From a5b16b1673619b38cdef4ee738756bb7ef2834ce Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 4 Feb 2022 13:36:32 +0100 Subject: [PATCH 053/168] fine: consolidate duplicate logic Further merge cleanup. --- pkg/arvo/sys/vane/ames.hoon | 55 ++++--------------------------------- 1 file changed, 5 insertions(+), 50 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index b45eaa522..00a9df105 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -312,10 +312,6 @@ dat=(rsh 3^70 purr) == :: -++ verify-response-packet - |= rawr - !! -:: ++ decode-response-msg |= partial-fine ::TODO maybe take @ instead ^- roar @@ -325,12 +321,11 @@ |= num=@ud =/ frag=byts (~(got by fragments) num) dat.frag - =+ sig=(end 3^64 mess) - :- sig + :- sig=(cut 3 [0 64] mess) + =+ dat=(rsh 3^64 mess) + ?~ dat ~ ~| [%fine %response-not-cask] - ;;((cask) (cue (rsh 3^64 mess))) -:: - + ;;((cask) (cue dat)) :: +decode-packet: deserialize packet from bytestream or crash :: ++ decode-packet @@ -697,7 +692,7 @@ :: +$ roar :: response message $: sig=@ - dat=(cask) + dat=$@(~ (cask)) == :: $partial-fine: partial remote scry response :: @@ -2750,46 +2745,6 @@ (got-peer-state ship) lane:(need route.peer-state) :: - ++ decode-request - |= =hoot - ^- twit - :- sig=(cut 3 [0 64] hoot) - -:(decode-request-info (rsh 3^64 hoot)) - :: - ++ decode-request-info - |= =hoot - ^- [=peep =purr] - =+ num=(cut 3 [0 4] hoot) - =+ len=(cut 3 [4 2] hoot) - =+ pat=(cut 3 [6 len] hoot) - :- [(stab pat) num] - :: if there is data remaining, it's the response - (rsh [3 (add 6 len)] hoot) - :: - ++ decode-response-packet - |= =purr - =; =rawr - ~? !=(wid.rawr (met 3 dat.rawr)) [%fine %unexpected-dat-size] - rawr - :* sig=(cut 3 [0 64] purr) - siz=(cut 3 [64 4] purr) - wid=(cut 3 [68 2] purr) - dat=(rsh 3^70 purr) - == - :: - ++ decode-response-msg - |= partial-fine ::TODO maybe take @ instead - ^- roar - =/ mess=@ - %+ can 3 ::TODO just (rep 13 -) - %+ turn (gulf 1 num-fragments) - ~(got by fragments) - :- sig=(cut 3 [0 64] mess) - =+ dat=(rsh 3^64 mess) - ?~ dat ~ - ~| [%fine %response-not-cask] - ;;((cask) (cue dat)) - :: ++ send-request |= [=ship =path num=@ud] ^+ event-core From c9871ad2ef854206cfc730c0b3b0ebe8d9d876c0 Mon Sep 17 00:00:00 2001 From: fang Date: Fri, 4 Feb 2022 21:52:11 +0100 Subject: [PATCH 054/168] pill: solid --- bin/solid.pill | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index 1da0adbc3..a19bc225d 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c29577dc949ac0689ba3c97ad13b812ea6c3c6cc9d255b770d2da95fd9af84b9 -size 23121802 +oid sha256:747b275ccae57a572ef4f6b48d629d9101b55b30667d974b8b27a3f978af05e8 +size 24289683 From 5da80d7001e9d0b02f1baa3cecc34eb959a2a6ce Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 9 Feb 2022 13:04:22 -0600 Subject: [PATCH 055/168] wip --- pkg/urbit/Makefile | 7 +++++++ pkg/urbit/vere/io/ames.c | 27 +++++++++++++-------------- pkg/urbit/wireshark/main.c | 0 3 files changed, 20 insertions(+), 14 deletions(-) create mode 100644 pkg/urbit/wireshark/main.c diff --git a/pkg/urbit/Makefile b/pkg/urbit/Makefile index c079c2af3..e2a4fdabb 100644 --- a/pkg/urbit/Makefile +++ b/pkg/urbit/Makefile @@ -9,6 +9,7 @@ daemon = $(wildcard daemon/*.c) worker = $(wildcard worker/*.c) tests = $(wildcard tests/*.c) bench = $(wildcard bench/*.c) +wireshark = $(wildcard wireshark/*.c) compat := $(foreach dir,$(compat),$(wildcard compat/$(dir)/*.c)) @@ -77,6 +78,12 @@ build/urbit-worker: $(common_objs) $(worker_objs) @mkdir -p ./build @$(CC) $^ $(LDFLAGS) -o $@ +build/ames-wireshark: $(common_objs) $(worker_objs) + @echo CC -o $@ + @mkdir -p ./build + @$(CC) wireshark/main.c $(LDFLAGS) -o $@ + + # CCDEPS and CCEXTRA are empty except in MingW build, # which uses them to inject a C source transform step %.o: %.c $(headers) $(CCDEPS) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index e1c6f84b5..2e96f4d88 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -862,7 +862,6 @@ _ames_czar(u3_pact* pac_u) u3_ames* sam_u = pac_u->sam_u; c3_y imp_y = pac_u->imp_y; - u3l_log("ames: send to %u\n", imp_y); pac_u->lan_u.por_s = _ames_czar_port(imp_y); @@ -960,8 +959,6 @@ _fine_put_cache(u3_ames* sam_u, u3_noun pax, u3_noun lis) cur_w++; u3z(key); } - u3l_log("put %u packets at\n", cur_w); - u3m_p("path", pax); } /* _fine_ef_howl(): broadcast notification of newly bound data @@ -981,22 +978,19 @@ _fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) u3_noun her = who; while ( her != u3_nul ) { // TODO: prime cache maybe??? - //u3m_p("her", her); - /*u3_weak lac = _ames_lane_from_cache(sam_u->lax_p, u3h(her)); + u3_weak lac = _ames_lane_from_cache(sam_u->lax_p, u3h(her)); if ( lac == u3_none ) { u3l_log("no lane\n"); - u3m_p("for", u3h(her)); her = u3t(her); continue; - }*/ + } u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); pac_u->sam_u = sam_u; - c3_d her_d[2]; - u3r_chubs(0, 2, her_d, u3k(u3h(her))); - // TODO: fix for non-galaxy case - pac_u->imp_y = her_d[0]; + c3_d lan_d = u3r_chub(0, lac); + pac_u->lan_u.pip_w = (c3_w)lan_d; + pac_u->lan_u.por_s = (c3_s)(lan_d >> 32); _fine_got_pack(pac_u, u3h(lis)); her = u3t(her); @@ -1396,7 +1390,7 @@ static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) u3r_bytes(0, pac_u->len_w, pac_u->hun_y, fra); - _ames_czar(pac_u); //_fine_send(pac_u); + _fine_send(pac_u); u3z(fra); } @@ -1661,7 +1655,13 @@ _ames_hear(u3_ames* sam_u, c3_free(hun_y); return; } - else if (c3n == is_ames_o) { + + u3_prel pre_u; + + // we always overwrite this later + _ames_sift_prelude(&pac_u->hed_u, &pac_u->bod_u.pre_u, len_w - 4, hun_y + 4); + + if (c3n == is_ames_o) { _fine_hear(sam_u, *lan_u, len_w, hun_y); return; } @@ -2003,7 +2003,6 @@ _ames_kick_newt(u3_ames* sam_u, u3_noun tag, u3_noun dat) case c3__howl: { u3_noun pat = u3k(u3h(dat)); u3_noun lis = u3k(u3t(dat)); - u3l_log("fine: howl\n"); _fine_ef_howl(sam_u, pat, lis); ret_o = c3y; } break; diff --git a/pkg/urbit/wireshark/main.c b/pkg/urbit/wireshark/main.c new file mode 100644 index 000000000..e69de29bb From 39d99f69d6636bd107a95ebf7a6ccdf1d2ecf045 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 10 Feb 2022 10:57:04 -0600 Subject: [PATCH 056/168] ames: use set for subscribers instead of list --- pkg/urbit/vere/io/ames.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 2e96f4d88..c5f168bf3 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -974,8 +974,8 @@ _fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) if ( who == u3_none ) { u3l_log("no listeners\n"); } else { + u3_noun her = u3qdi_tap(who); - u3_noun her = who; while ( her != u3_nul ) { // TODO: prime cache maybe??? @@ -1398,14 +1398,14 @@ static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) static void _fine_bide(u3_pact* pac_u, u3_noun pax) { u3_ames* sam_u = pac_u->sam_u; - u3_weak lis = u3h_get(sam_u->fin_s.bid_p, pax); + u3_weak set = u3h_get(sam_u->fin_s.bid_p, pax); - if ( u3_none == lis ) { - lis = u3_nul; + if ( u3_none == set ) { + set = u3_nul; } u3_noun her = u3i_chubs(2, pac_u->req_u.pre_u.sen_d); - u3_noun new = u3nc(her, lis); + u3_noun new = u3qdi_put(set, her); u3h_put(sam_u->fin_s.bid_p, pax, new); @@ -1454,6 +1454,7 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) if ( fra == u3_none ) { u3l_log("fragment number out of range\n"); + _ames_pact_free(pac_u); } else { _fine_got_pack(pac_u, fra); } @@ -1660,6 +1661,12 @@ _ames_hear(u3_ames* sam_u, // we always overwrite this later _ames_sift_prelude(&pac_u->hed_u, &pac_u->bod_u.pre_u, len_w - 4, hun_y + 4); + { + u3_noun her = u3i_chubs(2, pac_u->bod_u.pre_u.sen_d); + u3_noun las = u3_ames_encode_lane(*lan_u); + + _ames_lane_into_cache(sam_u->lax_p, her, las); + } if (c3n == is_ames_o) { _fine_hear(sam_u, *lan_u, len_w, hun_y); From 39a0f7c431e6b7b017d5c13c8aae7e40c2661685 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 10 Feb 2022 10:57:39 -0600 Subject: [PATCH 057/168] ames: scry for lane if not in cache --- pkg/urbit/vere/io/ames.c | 96 ++++++++++++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index c5f168bf3..00e86d25f 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -198,6 +198,16 @@ _ames_panc_free(u3_panc* pac_u) c3_free(pac_u); } +/* _lane_scry_path(): format scry path for retrieving a lane +*/ +static inline u3_noun _lane_scry_path(u3_noun who) +{ + return u3nq(u3i_string("peers"), + u3dc("scot", 'p', who), + u3i_string("forward-lane"), + u3_nul); +} + static void _log_prel(u3_prel* pre_u) { u3l_log("-- PRELUDE --\n"); @@ -961,6 +971,47 @@ _fine_put_cache(u3_ames* sam_u, u3_noun pax, u3_noun lis) } } +/* _fine_lane_scry_cb(): learn lane to send response on +*/ +static void +_fine_lane_scry_cb(void* vod_p, u3_noun nun) +{ + u3_pact* pac_u = vod_p; + u3_ames* sam_u = pac_u->sam_u; + u3_weak las = u3r_at(7, nun); + + // if scry fails, just drop the packet + // + if ( u3_none == las ) { + u3l_log("failed to scry\n"); + _ames_pact_free(pac_u); + } + else { + + // cache the scry result for later use + // + _ames_lane_into_cache(sam_u->lax_p, + u3i_chubs(2, pac_u->bod_u.pre_u.rec_d), + u3k(las)); + + // if there is no lane, drop the packet + // + if ( u3_nul == las ) { + _ames_pact_free(pac_u); + } + // if there is a lane, forward the packet on it + // + else { + c3_d lan_d = u3r_chub(0, las); + pac_u->lan_u.pip_w = (c3_w)lan_d; + pac_u->lan_u.por_s = (c3_s)(lan_d >> 32); + _fine_send(pac_u); + } + } + + u3z(nun); +} + /* _fine_ef_howl(): broadcast notification of newly bound data */ static void @@ -968,33 +1019,43 @@ _fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) { u3_noun pas = lis; + // put packets in cache _fine_put_cache(sam_u, pax, pas); + + // iterate over subscribers, sending immediately if we have the lane + // else, scry for a lane u3_weak who = u3h_get(sam_u->fin_s.bid_p, pax); if ( who == u3_none ) { u3l_log("no listeners\n"); } else { u3_noun her = u3qdi_tap(who); + u3_noun him = her; // original ref for counting while ( her != u3_nul ) { - // TODO: prime cache maybe??? u3_weak lac = _ames_lane_from_cache(sam_u->lax_p, u3h(her)); - if ( lac == u3_none ) { - u3l_log("no lane\n"); - her = u3t(her); - continue; - } + u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); pac_u->sam_u = sam_u; - c3_d lan_d = u3r_chub(0, lac); - pac_u->lan_u.pip_w = (c3_w)lan_d; - pac_u->lan_u.por_s = (c3_s)(lan_d >> 32); - _fine_got_pack(pac_u, u3h(lis)); + if ( lac == u3_none ) { + u3l_log("no lane\n"); + u3_noun pax = _lane_scry_path(u3k(u3h(her))); + u3_pier_peek_last(sam_u->pir_u, u3_nul, c3__ax, + u3_nul, pax, pac_u, _fine_lane_scry_cb); + } else { + c3_d lan_d = u3r_chub(0, lac); + pac_u->lan_u.pip_w = (c3_w)lan_d; + pac_u->lan_u.por_s = (c3_s)(lan_d >> 32); + + _fine_send(pac_u); + } + her = u3t(her); } + u3z(him); } } @@ -1230,6 +1291,8 @@ _ames_forward(u3_panc* pac_u, u3_noun las) u3z(las); } + + /* _ames_lane_scry_cb(): learn lane to forward packet on */ static void @@ -1353,10 +1416,8 @@ _ames_try_forward(u3_ames* sam_u, // else { sam_u->sat_u.foq_d++; - u3_noun pax = u3nq(u3i_string("peers"), - u3dc("scot", 'p', u3i_chubs(2, bod_u->pre_u.rec_d)), - u3i_string("forward-lane"), - u3_nul); + u3_noun pax = _lane_scry_path(u3i_chubs(2, bod_u->pre_u.rec_d)); + u3_pier_peek_last(sam_u->pir_u, u3_nul, c3__ax, u3_nul, pax, pac_u, _ames_lane_scry_cb); } @@ -1389,9 +1450,6 @@ static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) u3r_bytes(0, pac_u->len_w, pac_u->hun_y, fra); - - _fine_send(pac_u); - u3z(fra); } @@ -1430,9 +1488,9 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); if(pas == u3_none) { - // TODO: send %bide _fine_bide(pac_u, u3k(pax)); _ames_pact_free(pac_u); + u3z(pax); u3z(nun); return; @@ -1457,6 +1515,7 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) _ames_pact_free(pac_u); } else { _fine_got_pack(pac_u, fra); + _fine_send(pac_u); } u3z(pas); @@ -1535,6 +1594,7 @@ static void _fine_hear_request(u3_ames* sam_u, } else { _fine_got_pack(pac_u, u3k(cac)); + _fine_send(pac_u); } u3z(pat); From a86664076dea8482310e81fc038435a3f72f56d7 Mon Sep 17 00:00:00 2001 From: Ted Blackman Date: Thu, 10 Feb 2022 11:39:31 -0600 Subject: [PATCH 058/168] lull: fine congestion control data structures --- pkg/arvo/sys/lull.hoon | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index febec18e0..3f25c1c13 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -547,6 +547,35 @@ rcv=(map bone message-sink-state) nax=(set [=bone =message-num]) heeds=(set duct) + =scry-state + == + +$ scry-state + $: order=(map path @ud) + seq=@ud + keens=((mop @ud keen-state) lte) + metrics=pump-metrics + == + +$ keen-state + $: wan=(list want) :: request packets + hav=(list have) :: response packets, backward + num-fragments=@ud + num-received=@ud + == + +$ want + $: fra=@ud + =hoot + last-sent=@da + tries=@ud + skips=@ud + == + +$ have + $: fra=@ud + rawr + == + +$ rawr :: response packet ::TODO meow + $: sig=@ + siz=@ud + byts == :: $qos: quality of service; how is our connection to a peer doing? :: From 67105a854be1ab180feedc5c82e47a197bc26bdb Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 10 Feb 2022 11:52:37 -0600 Subject: [PATCH 059/168] lull: move ordered-map from zuse --- pkg/arvo/sys/lull.hoon | 407 +++++++++++++++++++++++++++++++++++++++++ pkg/arvo/sys/zuse.hoon | 406 ---------------------------------------- 2 files changed, 407 insertions(+), 406 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 3f25c1c13..9583db07c 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -36,6 +36,413 @@ depth=_1 == :: +:: +mop: constructs and validates ordered ordered map based on key, +:: val, and comparator gate +:: +++ mop + |* [key=mold value=mold] + |= ord=$-([key key] ?) + |= a=* + =/ b ;;((tree [key=key val=value]) a) + ?> (apt:((on key value) ord) b) + b +:: +:: +++ ordered-map on +:: +on: treap with user-specified horizontal order, ordered-map +:: +:: WARNING: ordered-map will not work properly if two keys can be +:: unequal under noun equality but equal via the compare gate +:: +++ on + ~/ %on + |* [key=mold val=mold] + => |% + +$ item [key=key val=val] + -- + :: +compare: item comparator for horizontal order + :: + ~% %comp +>+ ~ + |= compare=$-([key key] ?) + ~% %core + ~ + |% + :: +all: apply logical AND boolean test on all values + :: + ++ all + ~/ %all + |= [a=(tree item) b=$-(item ?)] + ^- ? + |- + ?~ a + & + ?&((b n.a) $(a l.a) $(a r.a)) + :: +any: apply logical OR boolean test on all values + :: + ++ any + ~/ %any + |= [a=(tree item) b=$-(item ?)] + |- ^- ? + ?~ a + | + ?|((b n.a) $(a l.a) $(a r.a)) + :: +apt: verify horizontal and vertical orderings + :: + ++ apt + ~/ %apt + |= a=(tree item) + =| [l=(unit key) r=(unit key)] + |- ^- ? + :: empty tree is valid + :: + ?~ a %.y + :: nonempty trees must maintain several criteria + :: + ?& :: if .n.a is left of .u.l, assert horizontal comparator + :: + ?~(l %.y (compare key.n.a u.l)) + :: if .n.a is right of .u.r, assert horizontal comparator + :: + ?~(r %.y (compare u.r key.n.a)) + :: if .a is not leftmost element, assert vertical order between + :: .l.a and .n.a and recurse to the left with .n.a as right + :: neighbor + :: + ?~(l.a %.y &((mor key.n.a key.n.l.a) $(a l.a, l `key.n.a))) + :: if .a is not rightmost element, assert vertical order + :: between .r.a and .n.a and recurse to the right with .n.a as + :: left neighbor + :: + ?~(r.a %.y &((mor key.n.a key.n.r.a) $(a r.a, r `key.n.a))) + == + :: +bap: convert to list, right to left + :: + ++ bap + ~/ %bap + |= a=(tree item) + ^- (list item) + =| b=(list item) + |- ^+ b + ?~ a b + $(a r.a, b [n.a $(a l.a)]) + :: +del: delete .key from .a if it exists, producing value iff deleted + :: + ++ del + ~/ %del + |= [a=(tree item) =key] + ^- [(unit val) (tree item)] + ?~ a [~ ~] + :: we found .key at the root; delete and rebalance + :: + ?: =(key key.n.a) + [`val.n.a (nip a)] + :: recurse left or right to find .key + :: + ?: (compare key key.n.a) + =+ [found lef]=$(a l.a) + [found a(l lef)] + =+ [found rig]=$(a r.a) + [found a(r rig)] + :: +dip: stateful partial inorder traversal + :: + :: Mutates .state on each run of .f. Starts at .start key, or if + :: .start is ~, starts at the head. Stops when .f produces .stop=%.y. + :: Traverses from left to right keys. + :: Each run of .f can replace an item's value or delete the item. + :: + ++ dip + ~/ %dip + |* state=mold + |= $: a=(tree item) + =state + f=$-([state item] [(unit val) ? state]) + == + ^+ [state a] + :: acc: accumulator + :: + :: .stop: set to %.y by .f when done traversing + :: .state: threaded through each run of .f and produced by +abet + :: + =/ acc [stop=`?`%.n state=state] + =< abet =< main + |% + ++ this . + ++ abet [state.acc a] + :: +main: main recursive loop; performs a partial inorder traversal + :: + ++ main + ^+ this + :: stop if empty or we've been told to stop + :: + ?: =(~ a) this + ?: stop.acc this + :: inorder traversal: left -> node -> right, until .f sets .stop + :: + =. this left + ?: stop.acc this + =^ del this node + =? this !stop.acc right + =? a del (nip a) + this + :: +node: run .f on .n.a, updating .a, .state, and .stop + :: + ++ node + ^+ [del=*? this] + :: run .f on node, updating .stop.acc and .state.acc + :: + ?> ?=(^ a) + =^ res acc (f state.acc n.a) + ?~ res + [del=& this] + [del=| this(val.n.a u.res)] + :: +left: recurse on left subtree, copying mutant back into .l.a + :: + ++ left + ^+ this + ?~ a this + =/ lef main(a l.a) + lef(a a(l a.lef)) + :: +right: recurse on right subtree, copying mutant back into .r.a + :: + ++ right + ^+ this + ?~ a this + =/ rig main(a r.a) + rig(a a(r a.rig)) + -- + :: +gas: put a list of items + :: + ++ gas + ~/ %gas + |= [a=(tree item) b=(list item)] + ^- (tree item) + ?~ b a + $(b t.b, a (put a i.b)) + :: +get: get val at key or return ~ + :: + ++ get + ~/ %get + |= [a=(tree item) b=key] + ^- (unit val) + ?~ a ~ + ?: =(b key.n.a) + `val.n.a + ?: (compare b key.n.a) + $(a l.a) + $(a r.a) + :: +got: need value at key + :: + ++ got + |= [a=(tree item) b=key] + ^- val + (need (get a b)) + :: +has: check for key existence + :: + ++ has + ~/ %has + |= [a=(tree item) b=key] + ^- ? + !=(~ (get a b)) + :: +lot: take a subset range excluding start and/or end and all elements + :: outside the range + :: + ++ lot + ~/ %lot + |= $: tre=(tree item) + start=(unit key) + end=(unit key) + == + ^- (tree item) + |^ + ?: ?&(?=(~ start) ?=(~ end)) + tre + ?~ start + (del-span tre %end end) + ?~ end + (del-span tre %start start) + ?> (compare u.start u.end) + =. tre (del-span tre %start start) + (del-span tre %end end) + :: + ++ del-span + |= [a=(tree item) b=?(%start %end) c=(unit key)] + ^- (tree item) + ?~ a a + ?~ c a + ?- b + %start + :: found key + ?: =(key.n.a u.c) + (nip a(l ~)) + :: traverse to find key + ?: (compare key.n.a u.c) + :: found key to the left of start + $(a (nip a(l ~))) + :: found key to the right of start + a(l $(a l.a)) + :: + %end + :: found key + ?: =(u.c key.n.a) + (nip a(r ~)) + :: traverse to find key + ?: (compare key.n.a u.c) + :: found key to the left of end + a(r $(a r.a)) + :: found key to the right of end + $(a (nip a(r ~))) + == + -- + :: +nip: remove root; for internal use + :: + ++ nip + ~/ %nip + |= a=(tree item) + ^- (tree item) + ?> ?=(^ a) + :: delete .n.a; merge and balance .l.a and .r.a + :: + |- ^- (tree item) + ?~ l.a r.a + ?~ r.a l.a + ?: (mor key.n.l.a key.n.r.a) + l.a(r $(l.a r.l.a)) + r.a(l $(r.a l.r.a)) + :: + :: +pop: produce .head (leftmost item) and .rest or crash if empty + :: + ++ pop + ~/ %pop + |= a=(tree item) + ^- [head=item rest=(tree item)] + ?~ a !! + ?~ l.a [n.a r.a] + =/ l $(a l.a) + :- head.l + :: load .rest.l back into .a and rebalance + :: + ?: |(?=(~ rest.l) (mor key.n.a key.n.rest.l)) + a(l rest.l) + rest.l(r a(r r.rest.l)) + :: +pry: produce head (leftmost item) or null + :: + ++ pry + ~/ %pry + |= a=(tree item) + ^- (unit item) + ?~ a ~ + |- + ?~ l.a `n.a + $(a l.a) + :: +put: ordered item insert + :: + ++ put + ~/ %put + |= [a=(tree item) =key =val] + ^- (tree item) + :: base case: replace null with single-item tree + :: + ?~ a [n=[key val] l=~ r=~] + :: base case: overwrite existing .key with new .val + :: + ?: =(key.n.a key) a(val.n val) + :: if item goes on left, recurse left then rebalance vertical order + :: + ?: (compare key key.n.a) + =/ l $(a l.a) + ?> ?=(^ l) + ?: (mor key.n.a key.n.l) + a(l l) + l(r a(l r.l)) + :: item goes on right; recurse right then rebalance vertical order + :: + =/ r $(a r.a) + ?> ?=(^ r) + ?: (mor key.n.a key.n.r) + a(r r) + r(l a(r l.r)) + :: +ram: produce tail (rightmost item) or null + :: + ++ ram + ~/ %ram + |= a=(tree item) + ^- (unit item) + ?~ a ~ + |- + ?~ r.a `n.a + $(a r.a) + :: +run: apply gate to transform all values in place + :: + ++ run + ~/ %run + |* [a=(tree item) b=$-(val *)] + |- + ?~ a a + [n=[key.n.a (b val.n.a)] l=$(a l.a) r=$(a r.a)] + :: +tab: tabulate a subset excluding start element with a max count + :: + ++ tab + ~/ %tab + |= [a=(tree item) b=(unit key) c=@] + ^- (list item) + |^ + (flop e:(tabulate (del-span a b) b c)) + :: + ++ tabulate + |= [a=(tree item) b=(unit key) c=@] + ^- [d=@ e=(list item)] + ?: ?&(?=(~ b) =(c 0)) + [0 ~] + =| f=[d=@ e=(list item)] + |- ^+ f + ?: ?|(?=(~ a) =(d.f c)) f + =. f $(a l.a) + ?: =(d.f c) f + =. f [+(d.f) [n.a e.f]] + ?:(=(d.f c) f $(a r.a)) + :: + ++ del-span + |= [a=(tree item) b=(unit key)] + ^- (tree item) + ?~ a a + ?~ b a + ?: =(key.n.a u.b) + r.a + ?: (compare key.n.a u.b) + $(a r.a) + a(l $(a l.a)) + -- + :: +tap: convert to list, left to right + :: + ++ tap + ~/ %tap + |= a=(tree item) + ^- (list item) + =| b=(list item) + |- ^+ b + ?~ a b + $(a l.a, b [n.a $(a r.a)]) + :: +uni: unify two ordered maps + :: + :: .b takes precedence over .a if keys overlap. + :: + ++ uni + ~/ %uni + |= [a=(tree item) b=(tree item)] + ^- (tree item) + ?~ b a + ?~ a b + ?: =(key.n.a key.n.b) + [n=n.b l=$(a l.a, b l.b) r=$(a r.a, b r.b)] + ?: (mor key.n.a key.n.b) + ?: (compare key.n.b key.n.a) + $(l.a $(a l.a, r.b ~), b r.b) + $(r.a $(a r.a, l.b ~), b l.b) + ?: (compare key.n.a key.n.b) + $(l.b $(b l.b, r.a ~), a r.a) + $(r.b $(b r.b, l.a ~), a l.a) + -- + +:: +$ deco ?(~ %bl %br %un) :: text decoration +$ json :: normal json value $@ ~ :: null diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index 38cc98d1d..bea070310 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -5184,412 +5184,6 @@ $(pops [oldest pops]) -- -- -:: -:: +mop: constructs and validates ordered ordered map based on key, -:: val, and comparator gate -:: -++ mop - |* [key=mold value=mold] - |= ord=$-([key key] ?) - |= a=* - =/ b ;;((tree [key=key val=value]) a) - ?> (apt:((on key value) ord) b) - b -:: -:: -++ ordered-map on -:: +on: treap with user-specified horizontal order, ordered-map -:: -:: WARNING: ordered-map will not work properly if two keys can be -:: unequal under noun equality but equal via the compare gate -:: -++ on - ~/ %on - |* [key=mold val=mold] - => |% - +$ item [key=key val=val] - -- - :: +compare: item comparator for horizontal order - :: - ~% %comp +>+ ~ - |= compare=$-([key key] ?) - ~% %core + ~ - |% - :: +all: apply logical AND boolean test on all values - :: - ++ all - ~/ %all - |= [a=(tree item) b=$-(item ?)] - ^- ? - |- - ?~ a - & - ?&((b n.a) $(a l.a) $(a r.a)) - :: +any: apply logical OR boolean test on all values - :: - ++ any - ~/ %any - |= [a=(tree item) b=$-(item ?)] - |- ^- ? - ?~ a - | - ?|((b n.a) $(a l.a) $(a r.a)) - :: +apt: verify horizontal and vertical orderings - :: - ++ apt - ~/ %apt - |= a=(tree item) - =| [l=(unit key) r=(unit key)] - |- ^- ? - :: empty tree is valid - :: - ?~ a %.y - :: nonempty trees must maintain several criteria - :: - ?& :: if .n.a is left of .u.l, assert horizontal comparator - :: - ?~(l %.y (compare key.n.a u.l)) - :: if .n.a is right of .u.r, assert horizontal comparator - :: - ?~(r %.y (compare u.r key.n.a)) - :: if .a is not leftmost element, assert vertical order between - :: .l.a and .n.a and recurse to the left with .n.a as right - :: neighbor - :: - ?~(l.a %.y &((mor key.n.a key.n.l.a) $(a l.a, l `key.n.a))) - :: if .a is not rightmost element, assert vertical order - :: between .r.a and .n.a and recurse to the right with .n.a as - :: left neighbor - :: - ?~(r.a %.y &((mor key.n.a key.n.r.a) $(a r.a, r `key.n.a))) - == - :: +bap: convert to list, right to left - :: - ++ bap - ~/ %bap - |= a=(tree item) - ^- (list item) - =| b=(list item) - |- ^+ b - ?~ a b - $(a r.a, b [n.a $(a l.a)]) - :: +del: delete .key from .a if it exists, producing value iff deleted - :: - ++ del - ~/ %del - |= [a=(tree item) =key] - ^- [(unit val) (tree item)] - ?~ a [~ ~] - :: we found .key at the root; delete and rebalance - :: - ?: =(key key.n.a) - [`val.n.a (nip a)] - :: recurse left or right to find .key - :: - ?: (compare key key.n.a) - =+ [found lef]=$(a l.a) - [found a(l lef)] - =+ [found rig]=$(a r.a) - [found a(r rig)] - :: +dip: stateful partial inorder traversal - :: - :: Mutates .state on each run of .f. Starts at .start key, or if - :: .start is ~, starts at the head. Stops when .f produces .stop=%.y. - :: Traverses from left to right keys. - :: Each run of .f can replace an item's value or delete the item. - :: - ++ dip - ~/ %dip - |* state=mold - |= $: a=(tree item) - =state - f=$-([state item] [(unit val) ? state]) - == - ^+ [state a] - :: acc: accumulator - :: - :: .stop: set to %.y by .f when done traversing - :: .state: threaded through each run of .f and produced by +abet - :: - =/ acc [stop=`?`%.n state=state] - =< abet =< main - |% - ++ this . - ++ abet [state.acc a] - :: +main: main recursive loop; performs a partial inorder traversal - :: - ++ main - ^+ this - :: stop if empty or we've been told to stop - :: - ?: =(~ a) this - ?: stop.acc this - :: inorder traversal: left -> node -> right, until .f sets .stop - :: - =. this left - ?: stop.acc this - =^ del this node - =? this !stop.acc right - =? a del (nip a) - this - :: +node: run .f on .n.a, updating .a, .state, and .stop - :: - ++ node - ^+ [del=*? this] - :: run .f on node, updating .stop.acc and .state.acc - :: - ?> ?=(^ a) - =^ res acc (f state.acc n.a) - ?~ res - [del=& this] - [del=| this(val.n.a u.res)] - :: +left: recurse on left subtree, copying mutant back into .l.a - :: - ++ left - ^+ this - ?~ a this - =/ lef main(a l.a) - lef(a a(l a.lef)) - :: +right: recurse on right subtree, copying mutant back into .r.a - :: - ++ right - ^+ this - ?~ a this - =/ rig main(a r.a) - rig(a a(r a.rig)) - -- - :: +gas: put a list of items - :: - ++ gas - ~/ %gas - |= [a=(tree item) b=(list item)] - ^- (tree item) - ?~ b a - $(b t.b, a (put a i.b)) - :: +get: get val at key or return ~ - :: - ++ get - ~/ %get - |= [a=(tree item) b=key] - ^- (unit val) - ?~ a ~ - ?: =(b key.n.a) - `val.n.a - ?: (compare b key.n.a) - $(a l.a) - $(a r.a) - :: +got: need value at key - :: - ++ got - |= [a=(tree item) b=key] - ^- val - (need (get a b)) - :: +has: check for key existence - :: - ++ has - ~/ %has - |= [a=(tree item) b=key] - ^- ? - !=(~ (get a b)) - :: +lot: take a subset range excluding start and/or end and all elements - :: outside the range - :: - ++ lot - ~/ %lot - |= $: tre=(tree item) - start=(unit key) - end=(unit key) - == - ^- (tree item) - |^ - ?: ?&(?=(~ start) ?=(~ end)) - tre - ?~ start - (del-span tre %end end) - ?~ end - (del-span tre %start start) - ?> (compare u.start u.end) - =. tre (del-span tre %start start) - (del-span tre %end end) - :: - ++ del-span - |= [a=(tree item) b=?(%start %end) c=(unit key)] - ^- (tree item) - ?~ a a - ?~ c a - ?- b - %start - :: found key - ?: =(key.n.a u.c) - (nip a(l ~)) - :: traverse to find key - ?: (compare key.n.a u.c) - :: found key to the left of start - $(a (nip a(l ~))) - :: found key to the right of start - a(l $(a l.a)) - :: - %end - :: found key - ?: =(u.c key.n.a) - (nip a(r ~)) - :: traverse to find key - ?: (compare key.n.a u.c) - :: found key to the left of end - a(r $(a r.a)) - :: found key to the right of end - $(a (nip a(r ~))) - == - -- - :: +nip: remove root; for internal use - :: - ++ nip - ~/ %nip - |= a=(tree item) - ^- (tree item) - ?> ?=(^ a) - :: delete .n.a; merge and balance .l.a and .r.a - :: - |- ^- (tree item) - ?~ l.a r.a - ?~ r.a l.a - ?: (mor key.n.l.a key.n.r.a) - l.a(r $(l.a r.l.a)) - r.a(l $(r.a l.r.a)) - :: - :: +pop: produce .head (leftmost item) and .rest or crash if empty - :: - ++ pop - ~/ %pop - |= a=(tree item) - ^- [head=item rest=(tree item)] - ?~ a !! - ?~ l.a [n.a r.a] - =/ l $(a l.a) - :- head.l - :: load .rest.l back into .a and rebalance - :: - ?: |(?=(~ rest.l) (mor key.n.a key.n.rest.l)) - a(l rest.l) - rest.l(r a(r r.rest.l)) - :: +pry: produce head (leftmost item) or null - :: - ++ pry - ~/ %pry - |= a=(tree item) - ^- (unit item) - ?~ a ~ - |- - ?~ l.a `n.a - $(a l.a) - :: +put: ordered item insert - :: - ++ put - ~/ %put - |= [a=(tree item) =key =val] - ^- (tree item) - :: base case: replace null with single-item tree - :: - ?~ a [n=[key val] l=~ r=~] - :: base case: overwrite existing .key with new .val - :: - ?: =(key.n.a key) a(val.n val) - :: if item goes on left, recurse left then rebalance vertical order - :: - ?: (compare key key.n.a) - =/ l $(a l.a) - ?> ?=(^ l) - ?: (mor key.n.a key.n.l) - a(l l) - l(r a(l r.l)) - :: item goes on right; recurse right then rebalance vertical order - :: - =/ r $(a r.a) - ?> ?=(^ r) - ?: (mor key.n.a key.n.r) - a(r r) - r(l a(r l.r)) - :: +ram: produce tail (rightmost item) or null - :: - ++ ram - ~/ %ram - |= a=(tree item) - ^- (unit item) - ?~ a ~ - |- - ?~ r.a `n.a - $(a r.a) - :: +run: apply gate to transform all values in place - :: - ++ run - ~/ %run - |* [a=(tree item) b=$-(val *)] - |- - ?~ a a - [n=[key.n.a (b val.n.a)] l=$(a l.a) r=$(a r.a)] - :: +tab: tabulate a subset excluding start element with a max count - :: - ++ tab - ~/ %tab - |= [a=(tree item) b=(unit key) c=@] - ^- (list item) - |^ - (flop e:(tabulate (del-span a b) b c)) - :: - ++ tabulate - |= [a=(tree item) b=(unit key) c=@] - ^- [d=@ e=(list item)] - ?: ?&(?=(~ b) =(c 0)) - [0 ~] - =| f=[d=@ e=(list item)] - |- ^+ f - ?: ?|(?=(~ a) =(d.f c)) f - =. f $(a l.a) - ?: =(d.f c) f - =. f [+(d.f) [n.a e.f]] - ?:(=(d.f c) f $(a r.a)) - :: - ++ del-span - |= [a=(tree item) b=(unit key)] - ^- (tree item) - ?~ a a - ?~ b a - ?: =(key.n.a u.b) - r.a - ?: (compare key.n.a u.b) - $(a r.a) - a(l $(a l.a)) - -- - :: +tap: convert to list, left to right - :: - ++ tap - ~/ %tap - |= a=(tree item) - ^- (list item) - =| b=(list item) - |- ^+ b - ?~ a b - $(a l.a, b [n.a $(a r.a)]) - :: +uni: unify two ordered maps - :: - :: .b takes precedence over .a if keys overlap. - :: - ++ uni - ~/ %uni - |= [a=(tree item) b=(tree item)] - ^- (tree item) - ?~ b a - ?~ a b - ?: =(key.n.a key.n.b) - [n=n.b l=$(a l.a, b l.b) r=$(a r.a, b r.b)] - ?: (mor key.n.a key.n.b) - ?: (compare key.n.b key.n.a) - $(l.a $(a l.a, r.b ~), b r.b) - $(r.a $(a r.a, l.b ~), b l.b) - ?: (compare key.n.a key.n.b) - $(l.b $(b l.b, r.a ~), a r.a) - $(r.b $(b r.b, l.a ~), a l.a) - -- :: :: :::: ++userlib :: (2u) non-vane utils :: :::: From e97d99275b798f3e365943bb09eb4b3c5df980e5 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 11 Feb 2022 19:30:40 -0600 Subject: [PATCH 060/168] ames: congestion control for remote scry --- bin/solid.pill | 4 +- pkg/arvo/app/dbug.hoon | 2 +- pkg/arvo/sys/lull.hoon | 10 +- pkg/arvo/sys/vane/ames.hoon | 413 +++++++++++++++++++++--- pkg/interface/dbug/src/js/views/ames.js | 4 +- 5 files changed, 386 insertions(+), 47 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index a19bc225d..265e72314 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:747b275ccae57a572ef4f6b48d629d9101b55b30667d974b8b27a3f978af05e8 -size 24289683 +oid sha256:07ca78271e1697250ffab96acf20956625624ad41014dff66852e6a2a20fafc8 +size 24216185 diff --git a/pkg/arvo/app/dbug.hoon b/pkg/arvo/app/dbug.hoon index d42e08aca..8fb67e60b 100644 --- a/pkg/arvo/app/dbug.hoon +++ b/pkg/arvo/app/dbug.hoon @@ -702,7 +702,7 @@ 'fragment-num'^(numb fragment-num) 'num-fragments'^(numb num-fragments) 'last-sent'^(time last-sent) - 'retries'^(numb retries) + 'tries'^(numb tries) 'skips'^(numb skips) == :: diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 9583db07c..a96ed2b17 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -954,7 +954,7 @@ rcv=(map bone message-sink-state) nax=(set [=bone =message-num]) heeds=(set duct) - =scry-state + scry=scry-state == +$ scry-state $: order=(map path @ud) @@ -967,13 +967,13 @@ hav=(list have) :: response packets, backward num-fragments=@ud num-received=@ud + next-wake=(unit @da) + listeners=(set duct) == +$ want $: fra=@ud =hoot - last-sent=@da - tries=@ud - skips=@ud + packet-state == +$ have $: fra=@ud @@ -1134,7 +1134,7 @@ == +$ packet-state $: last-sent=@da - retries=@ud + tries=_1 skips=@ud == :: $message-sink-state: state of |message-sink to assemble messages diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 00a9df105..4c4141a40 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -313,14 +313,13 @@ == :: ++ decode-response-msg - |= partial-fine ::TODO maybe take @ instead + |= [total=@ud hav=(list have)] ^- roar =/ mess=@ %+ rep 13 - %+ turn (gulf 1 num-fragments) - |= num=@ud - =/ frag=byts (~(got by fragments) num) - dat.frag + %+ turn (flop hav) + |= =have + dat.have :- sig=(cut 3 [0 64] mess) =+ dat=(rsh 3^64 mess) ?~ dat ~ @@ -394,6 +393,15 @@ ?: (lte wid 4) 4 ?: (lte wid 8) 8 ?> (lte wid 16) 16 +:: +welt: like +weld but first argument is reversed +:: TODO: move to hoon.hoon +++ welt + ~/ %welt + |* [a=(list) b=(list)] + => .(a ^.(homo a), b ^.(homo b)) + |- ^+ b + ?~ a b + $(a t.a, b [i.a b]) :: +encode-open-packet: convert $open-packet attestation to $packet :: ++ encode-open-packet @@ -1095,6 +1103,11 @@ =? old-state ?=(%5 -.old-state) %6^(state-5-to-6 +.old-state) :: ?> ?=(%6 -.old-state) + =. peers.old-state + %- ~(run by peers.old-state) + |= =ship-state + ?. ?=(%known -.ship-state) ship-state + ship-state(metrics.scry *pump-metrics) ames-gate(ames-state +.old-state) :: ++ state-5-to-6 @@ -1617,6 +1630,8 @@ ++ on-take-wake |= [=wire error=(unit tang)] ^+ event-core + ?: ?=([%fine %behn %wake *] wire) + (on-take-wake:fine t.t.t.wire error) :: =/ res=(unit [her=ship =bone]) (parse-pump-timer-wire wire) ?~ res @@ -2513,6 +2528,328 @@ ++ fine =* state fine-state.ames-state =< |% + ++ fine-peer + |_ $: =ship + peer=peer-state + == + +* scry scry.peer + ++ pe-core . + ++ pe-abed + |= s=^ship + ^- (unit _pe-core) + ?~ sta=(get-peer-state s) + ~ + `pe-core(ship s, peer u.sta) + :: + ++ pe-gauge + =| =bug + (make-pump-gauge now metrics.scry ship bug(ges.veb &)) + :: + ++ pe-abet + ^+ event-core + :: ~& show:pe-gauge + ::~& num-slots:pe-gauge + =. peers.ames-state + (~(put by peers.ames-state) ship known/peer) + event-core + ++ pe-lane (get-lane ship) + ++ pe-keen + |= =path + ?: (~(has by order.scry) path) + pe-core + =/ keen-id=@ud seq.scry + =. seq.scry +(seq.scry) + =. order.scry + (~(put by order.scry) path keen-id) + =| =keen-state + =. wan.keen-state ~ :: TODO + =. keens.scry (put:orm keens.scry keen-id keen-state) + ke-abet:ke-start:(ke-abed:keen-core path) + :: + ++ pe-hear + |= [=lane =packet] + ?> =(sndr-tick.packet (mod life.peer 16)) + :: + =/ [=peep =purr] (decode-request-info `@ux`content.packet) + ?. (~(has by order.scry) path.peep) + ~&(dead-response/peep pe-core) + =< ke-abet + (ke-rcv:(ke-abed:keen-core path.peep) num.peep purr lane) + :: + ++ pe-update-qos + |= =new=qos + =^ old-qos qos.peer [qos.peer new-qos] + ?~ text=(qos-update-text ship old-qos new-qos) + pe-core + :: print message + :: + =. event-core (emit duct %pass /qos %d %flog %text u.text) + pe-core + :: + ++ pe-take-wake + |= =wire + ^+ pe-core + ke-abet:ke-take-wake:(ke-abed:keen-core wire) + :: + ++ keen-core + |_ $: =path + keen-id=@ud + keen=keen-state + == + ++ ke-core . + ++ ke-abet + :: =. ke-core ke-set-wake + =/ gone=? + =, keen + :: num-fragments is 0 when unknown (i.e. no response + :: yet) + &(!=(0 num-fragments) =(num-fragments num-received)) + =. keens.scry + ?: gone +:(del:orm keens.scry keen-id) + (put:orm keens.scry keen-id keen) + =? order.scry gone + (~(del by order.scry) path) + pe-core + :: + ++ ke-abed + |= p=^path + =. keen-id (~(got by order.scry) p) + ke-core(path p, keen (got:orm keens.scry keen-id)) + :: + ++ ke-abed-id + |= id=@ud + %- ke-abed + ~| no-path-for-id/id + %- need + ^- (unit ^path) + %- ~(rep by order.scry) + |= [[p=^path i=@ud] out=(unit ^path)] + ^- (unit ^path) + ?^ out out + ?:(=(id i) `p ~) + :: + ++ ke-encode-req + |= frag=@ud + (encode-request ship path frag) + :: + ++ ke-on-ack + =| marked=(list want) + |= fra=@ud + =/ og ke-core + |- ^- [found=? _ke-core] + ?: =(~ wan.keen) [| og] + =^ =want wan.keen wan.keen + ?: =(fra fra.want) + [& ke-core(wan.keen (welt marked wan.keen))] + =. skips.want +(skips.want) + =^ resend=? metrics.scry + (on-skipped-packet:ke-gauge +>.want) + ?. resend + $(marked [want marked]) + =. tries.want +(tries.want) + =. last-sent.want now + =. ke-core (ke-send hoot.want) + $(marked [want marked]) + :: + ++ ke-retrieve-req + =| naw=(list want) + =/ og wan.keen + |= fra=@ud + ^- [(unit want) (list want)] + ?: =(~ wan.keen) `og + =^ =want wan.keen wan.keen + :: ?: (gth fra.want fra) + :: `og + ?. =(fra.want fra) + $(naw [want naw]) + =. tries.want +(tries.want) + =. last-sent.want now + [`want (welt naw [want wan.keen])] + :: + ++ ke-start + ~| tried-to-start-request-already-in-progress/path + ?> =(num-fragments.keen 0) + =/ fra=@ 1 + =/ req (ke-encode-req fra) + =- ke-core(event-core -) + %- emit + [unix-duct.ames-state %give %send pe-lane `@ux`req] + :: + ++ ke-done + |= [sig=@ data=$@(~ (cask))] + ?> (meri:keys ship life.peer path sig data) + ~& got-response/path + :: TODO: notify subscribers + ke-core + :: + ++ ke-first-rcv + |= =rawr + ^+ ke-core + =- ke-core(keen -) + %_ keen + num-fragments siz.rawr + :: + wan + %+ turn (gulf 1 siz.rawr) + |= fra=@ud + ^- want + [fra (ke-encode-req fra) now 0 0] + == + :: +ke-continue: send packets according to normal congestion flow + :: 2,3,4 -> + :: 2 <- + :: 3,4,5 -> + :: 3,4,5 -> + ++ ke-continue + =/ start +(num-received.keen) + =/ ceil (sub num-fragments.keen num-received.keen) + =/ len (min ceil num-slots:ke-gauge) + =/ end (add start len) + =/ fra=@ud start + |- + ?: =(fra end) + ke-core + =/ [req=(unit want) new-wants=_wan.keen] + (ke-retrieve-req fra) + ?~ req $(fra +(fra)) + ?. =(tries.u.req 1) $(fra +(fra)) + =. wan.keen new-wants + =. ke-core (ke-send hoot.u.req) + $(fra +(fra)) + :: + ++ ke-send + |= =hoot + =. metrics.scry (on-sent:ke-gauge 1) + =- ke-core(event-core -) + %- emit + [unix-duct.ames-state %give %send pe-lane `@ux`hoot] + :: + ++ ke-req + |= fra=@ud + =^ req wan.keen + (ke-retrieve-req fra) + ?~ req + ~& missing/fra + ke-core + (ke-send hoot.u.req) + :: + ++ ke-decode-full + =, keen + ~| %frag-mismatch + ~| have/num-received + ~| need/num-fragments + ?> =(num-fragments num-received) + ?> =((lent hav) num-received) + (decode-response-msg num-fragments hav) + :: + ++ ke-update-congestion + !. + |= fra=@ud + ^+ metrics.scry + ?< =(~ wan.keen) + =^ =want wan.keen wan.keen + ?. =(fra fra.want) + $ + (on-ack:ke-gauge +>.want) + ++ ke-is-dupe-ack + |= fra=@ud + ^- ? + ?: =(num-fragments.keen 0) | + ?: =(~ wan.keen) & + =^ =want wan.keen wan.keen + ?. =(fra fra.want) + $ + | + + :: + ++ ke-rcv + |= [fra=@ud =purr =lane:ames] + =/ =rawr (decode-response-packet purr) + ^+ ke-core + =/ og ke-core + :: handle empty + ?: =(0 siz.rawr) + ?> =(~ dat.rawr) + (ke-done sig.rawr ~) + ~| out-of-order/fra + ~| wanted/+(num-received.keen) + ?: (ke-is-dupe-ack fra) ke-core + :: update congestion, or fill details + =? metrics.scry !=(0 num-fragments.keen) + (ke-update-congestion fra) + :: + =? ke-core =(0 num-fragments.keen) + ?> =(fra 1) + (ke-first-rcv rawr) + :: + :: ?> =(fra +(num-received.keen)) :: TODO: fix OoO + ~| failed-signature/sig + ?> (veri:keys ship life.peer [sig dat]:rawr) + =^ found=? ke-core + (ke-on-ack fra) + ?. found + :: discard changes + ~& missing-fra/fra + og + =/ =have [fra rawr] + =. hav.keen + `(list ^have)`[have hav.keen] + =. num-received.keen +(num-received.keen) + ?: =(num-fragments num-received):keen + (ke-done [sig dat]:ke-decode-full) + ke-continue + :: + ++ ke-gauge + =| =bug + :: =. bug ges.veb.bug & + (make-pump-gauge now metrics.scry ship bug) + :: + ++ ke-timer-wire + `wire`(welp /fine/behn/wake/(scot %p ship) path) + :: + ++ ke-pass-timer + |= =note + ke-core(event-core (emit duct %pass ke-timer-wire note)) + :: + ++ ke-wait |=(tim=@da (ke-pass-timer %b %wait tim)) + ++ ke-rest |=(tim=@da (ke-pass-timer %b %rest tim)) + ++ ke-set-wake + ^+ ke-core + =/ next-wake=(unit @da) + ?~ wan.keen ~ + `(next-expiry:ke-gauge +>:i.wan.keen) + ?: =(next-wake next-wake.keen) + ke-core + =? ke-core !=(~ next-wake.keen) + =/ old (need next-wake.keen) + =. next-wake.keen ~ + (ke-rest old) + =? ke-core ?=(^ next-wake) + =. next-wake.keen next-wake + (ke-wait u.next-wake) + ke-core + :: TODO: almost identical to +on-take-wake + ++ ke-take-wake + ^+ ke-core + =. pe-core %- pe-update-qos + =/ expiry=@da (add ~s30 last-contact.qos.peer) + =? -.qos.peer + (gte now expiry) + %dead + qos.peer + :: expire direct route + =? route.peer + ?& ?=(%dead -.qos.peer) + ?=(^ route.peer) + direct.u.route.peer + !=(%czar (clan:title ship)) + == + route.peer(direct.u %.n) + :: handle timeout + =. metrics.scry on-timeout:ke-gauge + (ke-req fra:(head wan.keen)) + -- + -- ++ on-keen |= =path ^+ event-core @@ -2520,17 +2857,8 @@ ~| [%fine %invalid-namespace-path path] (need (de-omen path)) =* ship p.bem.omen - =. want.state (~(put ju want.state) path duct) - ?: (~(has by part.state) path) - :: request is already ongoing - :: - event-core - =. part.state (~(put by part.state) path *partial-fine) - :: if we don't know the target yet, store the request for later - :: - =/ peer (~(get by peers.ames-state) ship) - ?: ?=([~ %known *] peer) - (send-request p.bem.omen path 1) + =/ peer-core (pe-abed:fine-peer ship) + ?^ peer-core pe-abet:(pe-keen:u.peer-core path) %+ enqueue-alien-todo ship |= todos=alien-agenda todos(keens (~(put in keens.todos) path)) @@ -2580,6 +2908,17 @@ |= d=^duct [d %give %howl pax song] :: + ++ on-take-wake + |= [=wire error=(unit tang)] + ^+ event-core + ~| fine-on-take-wake/wire + :: TODO: handle error case + ?> ?=([@ *] wire) + =/ =ship (slav %p i.wire) + ~| %no-ship-for-wake + =/ peer-core (need (pe-abed:fine-peer ship)) + pe-abet:(pe-take-wake:peer-core t.wire) + :: ++ on-hear-response |= [=lane =packet dud=(unit goof)] ^+ event-core @@ -2592,13 +2931,8 @@ :: so we should only get responses from ships we know. :: below we assume sndr.packet is a known peer. =* from sndr.packet - =/ peer (~(got by peers.ames-state) from) - ?> ?=(%known -.peer) - ?> =(sndr-tick.packet (mod life.peer 16)) - :: - =/ [=peep =purr] (decode-request-info `@ux`content.packet) - =/ =rawr (decode-response-packet purr) - (handle-response [from life.peer lane] peep rawr) + =/ peer-core (need (pe-abed:fine-peer from)) + pe-abet:(pe-hear:peer-core lane packet) -- |% +$ twit :: signed request @@ -2621,6 +2955,7 @@ $: sig=@ dat=$@(~ (cask)) == + ++ orm ((on @ud keen-state) lte) :: ++ spit |= =path @@ -2648,7 +2983,8 @@ ::NOTE path is expected to be a namespace path without the ship ^- hoot ^- @ =+ bod=(request-body path num) - =+ syn=(can 3 64^(sign:keys dat.bod) bod ~) + =+ sig=64^(fil 5 16 0xdead.beef) :: 64^(sign:keys dat.bod) + =+ syn=(can 3 sig bod ~) %+ con 0b100 ::NOTE request bit %^ encode-packet | [our ship] @@ -2672,7 +3008,8 @@ :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) - =/ sig=@ (full:keys path data) + =/ sig=@ :: (full:keys path data) + (fil 5 16 0xdead.beef) ?~ data [sig]~ %+ rip 13 ::NOTE 1024 bytes (cat 3 sig (jam data)) ::TODO should include life @@ -2694,7 +3031,7 @@ == =/ sig=byts 64^(fil 5 16 0xcafe.face) - :: 64^(fil (sign:keys (can 3 req bod ~)) + :: 64^(sign:keys (can 3 req bod ~)) (can 3 req sig bod ~) :: ++ keys @@ -2729,8 +3066,9 @@ ++ veri |= [who=ship lyf=life sig=@ dat=@] ^- ? - =/ =^pass (pass who lyf) - (safe:as:(com:nu:crub:crypto pass) sig dat) + & + :: =/ =^pass (pass who lyf) + :: (safe:as:(com:nu:crub:crypto pass) sig dat) :: ++ meri |= [who=ship lyf=life pax=path sig=@ dat=$@(~ (cask))] @@ -2757,6 +3095,7 @@ |= [[from=ship =life] =path sig=@ data=$@(~ (cask))] ^+ event-core ?> (meri:keys from life path sig data) + ~& got-response/path =. event-core %- emil %+ turn ~(tap in (~(get ju want.state) path)) @@ -2791,7 +3130,7 @@ ?: =(num-fragments num-received):partial :: we have all the parts now, construct the full response :: - =/ =roar (decode-response-msg partial) + =| =roar (process-response [from life] path.peep [sig dat]:roar) :: otherwise, store the part, and send out the next request :: @@ -3109,7 +3448,7 @@ :: packet has expired; update it in-place, stop, and produce it :: =. last-sent.val now.channel - =. retries.val +(retries.val) + =. tries.val +(tries.val) :: [`val stop=%.y `(to-static-fragment key val)] :: +feed: try to send a list of packets, returning unsent and effects @@ -3141,7 +3480,7 @@ ^- [key=live-packet-key val=live-packet-val] :: :- [message-num fragment-num] - :- [sent-date=now.channel retries=0 skips=0] + :- [sent-date=now.channel tries=1 skips=0] [num-fragments fragment] :: update .live and .metrics :: @@ -3181,7 +3520,7 @@ ?: (lte-packets key [message-num fragment-num]) [new-val=`val stop=%.n acc] :: - ?: (gth (next-expiry:gauge key val) now.channel) + ?: (gth (next-expiry:gauge -.val) now.channel) [new-val=`val stop=%.y acc] :: =. last-sent.val now.channel @@ -3255,7 +3594,7 @@ [new-val=`val stop=%.n acc] :: =. last-sent.val now.channel - =. retries.val +(retries.val) + =. tries.val +(tries.val) =. resends.acc [(to-static-fragment key val) resends.acc] [new-val=`val stop=%.n acc] :: +on-done: apply ack to all packets from .message-num @@ -3300,7 +3639,7 @@ =/ new-wake=(unit @da) ?~ head=(pry:packet-queue live.state) ~ - `(next-expiry:gauge u.head) + `(next-expiry:gauge -.val.u.head) :: no-op if no change :: ?: =(new-wake next-wake.state) packet-pump @@ -3342,7 +3681,7 @@ :: delay, as opposed to an actual packet loss. :: ++ next-expiry - |= [live-packet-key live-packet-val] + |= packet-state ^- @da (add last-sent rto) :: +num-slots: how many packets can we send right now? @@ -3374,7 +3713,7 @@ (add cwnd !=(0 (mod (mug now) cwnd))) :: if this was a re-send, don't adjust rtt or downstream state :: - ?. =(0 retries.packet-state) + ?: (gth tries.packet-state 1) metrics :: rtt-datum: new rtt measurement based on this packet roundtrip :: @@ -3400,7 +3739,7 @@ |= packet-state ^- [resend=? pump-metrics] :: - =/ resend=? &(=(0 retries) |(in-recovery (gte skips 3))) + =/ resend=? &((lte tries 1) |(in-recovery (gte skips 3))) :- resend :: =? cwnd !in-recovery (max 2 (div cwnd 2)) diff --git a/pkg/interface/dbug/src/js/views/ames.js b/pkg/interface/dbug/src/js/views/ames.js index 24d54fff6..bc1e75bd7 100644 --- a/pkg/interface/dbug/src/js/views/ames.js +++ b/pkg/interface/dbug/src/js/views/ames.js @@ -101,7 +101,7 @@ export class Ames extends Component { fragment-num num-fragments last-sent - retries + tries skips @@ -109,7 +109,7 @@ export class Ames extends Component { {live['fragment-num']} {live['num-fragments']} {msToDa(live['last-sent'])} - {live.retries} + {live.tries} {live.skips} From c98e3dbd7a3af80f02411ab5ef46760798ccfedd Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Sat, 12 Feb 2022 04:28:14 -0600 Subject: [PATCH 061/168] pill: update solid --- bin/solid.pill | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index 265e72314..bee0e858d 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:07ca78271e1697250ffab96acf20956625624ad41014dff66852e6a2a20fafc8 -size 24216185 +oid sha256:357e851fbd779f9d19c0bad88befcff118ce81cdfc7c3f05fddca1c434e3754a +size 24334333 From b2051fcc2b93957936f2dfc29c7ee112b5ebb16a Mon Sep 17 00:00:00 2001 From: Ted Blackman Date: Mon, 14 Feb 2022 10:34:26 -0600 Subject: [PATCH 062/168] fine: WIP second list for performance --- pkg/arvo/sys/lull.hoon | 2 + pkg/arvo/sys/vane/ames.hoon | 92 ++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 53 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index a96ed2b17..fe689a1a6 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -964,11 +964,13 @@ == +$ keen-state $: wan=(list want) :: request packets + nex=(list want) :: request packets, unsent hav=(list have) :: response packets, backward num-fragments=@ud num-received=@ud next-wake=(unit @da) listeners=(set duct) + last-sent=(list [@ud @da]) == +$ want $: fra=@ud diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 4c4141a40..cd961451c 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2598,7 +2598,7 @@ == ++ ke-core . ++ ke-abet - :: =. ke-core ke-set-wake + =. ke-core ke-set-wake =/ gone=? =, keen :: num-fragments is 0 when unknown (i.e. no response @@ -2648,24 +2648,9 @@ $(marked [want marked]) =. tries.want +(tries.want) =. last-sent.want now - =. ke-core (ke-send hoot.want) + =. ke-core (ke-send [fra hoot]:want) $(marked [want marked]) :: - ++ ke-retrieve-req - =| naw=(list want) - =/ og wan.keen - |= fra=@ud - ^- [(unit want) (list want)] - ?: =(~ wan.keen) `og - =^ =want wan.keen wan.keen - :: ?: (gth fra.want fra) - :: `og - ?. =(fra.want fra) - $(naw [want naw]) - =. tries.want +(tries.want) - =. last-sent.want now - [`want (welt naw [want wan.keen])] - :: ++ ke-start ~| tried-to-start-request-already-in-progress/path ?> =(num-fragments.keen 0) @@ -2686,53 +2671,49 @@ |= =rawr ^+ ke-core =- ke-core(keen -) - %_ keen - num-fragments siz.rawr :: - wan + =/ paz=(list want) %+ turn (gulf 1 siz.rawr) |= fra=@ud ^- want - [fra (ke-encode-req fra) now 0 0] + [fra (ke-encode-req fra) now 1 0] + :: + %_ keen + num-fragments siz.rawr + wan paz + nex paz == :: +ke-continue: send packets according to normal congestion flow - :: 2,3,4 -> - :: 2 <- - :: 3,4,5 -> - :: 3,4,5 -> + :: ++ ke-continue - =/ start +(num-received.keen) - =/ ceil (sub num-fragments.keen num-received.keen) - =/ len (min ceil num-slots:ke-gauge) - =/ end (add start len) - =/ fra=@ud start - |- - ?: =(fra end) - ke-core - =/ [req=(unit want) new-wants=_wan.keen] - (ke-retrieve-req fra) - ?~ req $(fra +(fra)) - ?. =(tries.u.req 1) $(fra +(fra)) - =. wan.keen new-wants - =. ke-core (ke-send hoot.u.req) - $(fra +(fra)) + =| inx=@ud + =/ max num-slots:ke-gauge + |- ^+ ke-core + ?: =(~ nex.keen) ke-core + ?: =(inx max) ke-core + =^ =want nex.keen nex.keen + =. ke-core (ke-emit hoot.want) + $(inx +(inx)) :: ++ ke-send - |= =hoot + |= [fra=@ud =hoot] =. metrics.scry (on-sent:ke-gauge 1) + =. nex.keen + =| xen=(list want) + |- ^+ nex.keen + =^ =want nex.keen nex.keen + ?: =(fra fra.want) + (welt xen nex.keen) + $(xen [want xen]) + (ke-emit hoot) + :: + ++ ke-emit + |= =hoot + ^+ ke-core =- ke-core(event-core -) %- emit [unix-duct.ames-state %give %send pe-lane `@ux`hoot] :: - ++ ke-req - |= fra=@ud - =^ req wan.keen - (ke-retrieve-req fra) - ?~ req - ~& missing/fra - ke-core - (ke-send hoot.u.req) - :: ++ ke-decode-full =, keen ~| %frag-mismatch @@ -2828,7 +2809,8 @@ =. next-wake.keen next-wake (ke-wait u.next-wake) ke-core - :: TODO: almost identical to +on-take-wake + :: +ke-take-wake: handle request packet timeout + :: ++ ke-take-wake ^+ ke-core =. pe-core %- pe-update-qos @@ -2845,9 +2827,13 @@ !=(%czar (clan:title ship)) == route.peer(direct.u %.n) - :: handle timeout + :: =. metrics.scry on-timeout:ke-gauge - (ke-req fra:(head wan.keen)) + ?> ?=(^ wan.keen) + =: tries.i.wan.keen +(tries.i.wan.keen) + last-sent.i.wan.keen now + == + (ke-send [fra hoot]:i.wan.keen) -- -- ++ on-keen From c02274dfddc0591110a4ff5ffa2434bf4faec395 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 15 Feb 2022 00:51:54 +0100 Subject: [PATCH 063/168] clay: sync files using remote scry When clay wants to download blobs from a foreign ship, it attempts doing this using the new remote scry protocol. If it doesn't receive a response within ~m1, it falls back to using the old ames-based syncing instead. We remember this "prefer ames" state for the specific ship for an hour, after which we'll begin trying the scry flow again. Compiles, but untested. Some TODOs and REVIEWs remaining herein. We intentionally leave the dist-upgraded flag in state to avoid cluttering the diff here. The next commit will remove it. --- pkg/arvo/sys/vane/clay.hoon | 248 ++++++++++++++++++++++++++++++------ 1 file changed, 209 insertions(+), 39 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 871bbe376..386f937c0 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -170,6 +170,7 @@ pud=(unit [=desk =yoki]) :: pending update :: REMOVE on next upgrade dist-upgraded=_| :: are we in dist yet? + sad=(map ship @da) :: scry known broken == :: :: :: Object store. @@ -235,8 +236,9 @@ +$ update-state $: =duct =rave + scry=(unit @da) :: timeout timer if scry have=(map lobe blob) - need=(list lobe) + need=(list [=path =lobe]) nako=(qeu (unit nako)) busy=_| == @@ -292,7 +294,7 @@ $>(%what waif) :: == :: $: %a :: to %ames - $>(%plea task:ames) :: + $>(?(%plea %keen %yawn) task:ames) :: == :: $: %b :: to %behn $> $? %drip :: @@ -332,6 +334,7 @@ $> $? %boon :: response %done :: (n)ack %lost :: lost boon + %tune :: scry response == :: gift:ames :: == :: @@ -1320,6 +1323,20 @@ =/ =path [%question desk (scot %ud index) ~] (emit duct %pass wire %a %plea ship %c path `riff-any`[%1 riff]) :: + ++ send-over-scry + |= [kind=@ta =duct =ship index=@ud =desk =mood] + ^- [timeout=@da _..send-over-scry] + =/ =time (add now ~m1) + =/ =wire /[kind]/(scot %p ship)/[desk]/(scot %ud index) + =/ =path + =, mood + [(cat 3 %c care) (scot %p ship) desk (scot case) path] + :- time + %- emil + :~ [hen %pass wire %a %keen path] + [hen %pass wire %b %wait time] + == + :: ++ foreign-capable |= =rave |^ @@ -1354,6 +1371,27 @@ (run-if-future rove.wov |=(@da (bait hen +<))) |- ^+ +>+.$ =/ =rave (rove-to-rave rove.wov) + :: if it is a single request, and + :: :ship's remote scry isn't known to be broken, + :: or we learned it was broken more than an hour ago, + :: + ?: ?& ?=(%sing -.rave) + ?| !(~(has by sad) her) + (lth now (add ~h1 (~(got by sad) her))) + == == + :: send request as remote scry + ::TODO can be deduplicated with the below? + :: + =* inx nix.u.ref + =^ time=@da +>+.$ + =< ?>(?=(^ ref) .) + (send-over-scry %warp-index hen her inx syd mood.rave) + %= +>+.$ + nix.u.ref +(nix.u.ref) + bom.u.ref (~(put by bom.u.ref) inx [hen rave `time ~ ~ ~ |]) + fod.u.ref (~(put by fod.u.ref) hen inx) + == + :: =. rave ?. ?=([%sing %v *] rave) rave [%many %| [%ud let.dom] case.mood.rave path.mood.rave] @@ -1367,7 +1405,7 @@ (send-over-ames hen her inx syd `rave) %= +>+.$ nix.u.ref +(nix.u.ref) - bom.u.ref (~(put by bom.u.ref) inx [hen rave ~ ~ ~ |]) + bom.u.ref (~(put by bom.u.ref) inx [hen rave ~ ~ ~ ~ |]) fod.u.ref (~(put by fod.u.ref) hen inx) == :: @@ -1457,7 +1495,7 @@ ?~ yen =. lab.dom (~(put by lab.dom) bel yon) ..park - :: an aeon is bound to this label, + :: an aeon is bound to this label, :: but it is the same as the existing one, so we no-op :: ?: =(u.yen yon) @@ -2992,11 +3030,24 @@ :: ?~ nux=(~(get by fod.u.ref) hen) ..cancel-request(ref `(unit rind)`ref) :: XX TMI + =/ sat (~(got by bom.u.ref) u.nux) =: fod.u.ref (~(del by fod.u.ref) hen) bom.u.ref (~(del by bom.u.ref) u.nux) == - %. [hen her u.nux [syd ~]] - send-over-ames(ref `(unit rind)`ref) :: XX TMI + :: cancel the request as appropriate + :: + ?~ scry.sat + %. [hen her u.nux [syd ~]] + send-over-ames(ref `(unit rind)`ref) :: XX TMI + =/ =path + ~| [%strange-scried-request rave.sat] + ?> ?=(%sing -.rave.sat) + =, mood.rave.sat + [(cat 3 %c care) (scot %p her) syd (scot case) path] + %- emil + :~ [hen %pass / %a %yawn path] + [hen %pass / %b %rest u.scry.sat] + == :: :: Handles a request. :: @@ -3019,6 +3070,19 @@ ..start-request (duce for u.new-sub) :: + ::TODO should this try-fill-sub or w/e in case its now in our cache? + ++ retry-with-ames + |= inx=@ud + ^+ ..retry-with-ames + ~| [%strange-retry-no-request her syd inx] + ?> ?=(^ ref) + =/ sat=update-state (~(got by bom.u.ref) inx) + =. ..retry-with-ames + =< ?>(?=(^ ref) .) + (send-over-ames hen her inx syd `rave.sat) + =. bom.u.ref (~(put by bom.u.ref) inx sat(scry ~)) + ..retry-with-ames + :: :: Called when a foreign ship answers one of our requests. :: :: If it's a `%many` request, process in +take-foreign-update @@ -3147,6 +3211,12 @@ [u.ruv |] =/ done=? | =. hen duct.sat + :: if the request was done over scry, clear the timeout timer + :: + =? ..foreign-update ?=(^ scry.sat) + =< ?>(?=(^ ref) .) + (emit hen %pass / %b %rest u.scry.sat) + =. scry.sat ~ |% ++ abet ^+ ..foreign-update @@ -3169,27 +3239,27 @@ work ?> ?=(%nako p.r.u.rut) =/ nako ;;(nako q.r.u.rut) - =/ missing (missing-blobs nako) - =. need.sat `(list lobe)`(welp need.sat ~(tap in missing)) + =. need.sat (welp need.sat (missing-blobs nako)) =. nako.sat (~(put to nako.sat) ~ nako) work :: ++ missing-blobs |= =nako - ^- (set lobe) + ^- (list [path lobe]) =/ yakis ~(tap in lar.nako) - |- ^- (set lobe) + |- ^- (list [path lobe]) =* yaki-loop $ ?~ yakis ~ =/ lobes=(list [=path =lobe]) ~(tap by q.i.yakis) - |- ^- (set lobe) + |- ^- (list [path lobe]) =* blob-loop $ ?~ lobes yaki-loop(yakis t.yakis) ?: (~(has by lat.ran) lobe.i.lobes) blob-loop(lobes t.lobes) - (~(put in blob-loop(lobes t.lobes)) lobe.i.lobes) + :- i.lobes + blob-loop(lobes t.lobes) :: :: Receive backfill response :: @@ -3202,7 +3272,10 @@ !(~(has by lat.ran) q.q.blob) !(~(has by have.sat) q.q.blob) == - [q.q.blob need.sat] + ::NOTE we have already fallen back to the ames case, + :: so we do not need the real path here anymore. + ::REVIEW right? or is this considered too fragile? + [[/ q.q.blob] need.sat] :: We can't put a blob in lat.ran if its parent isn't already :: there. Unions are in reverse order so we don't overwrite :: existing blobs. @@ -3244,19 +3317,34 @@ :: another desk updating concurrently, or a previous update on this :: same desk). :: - ?: ?| (~(has by lat.ran) i.need.sat) - (~(has by have.sat) i.need.sat) + ?: ?| (~(has by lat.ran) lobe.i.need.sat) + (~(has by have.sat) lobe.i.need.sat) == $(need.sat t.need.sat) :: Otherwise, fetch the next blob :: - =/ =fill [%0 syd i.need.sat] - =/ =wire /back-index/(scot %p her)/[syd]/(scot %ud inx) - =/ =path [%backfill syd (scot %ud inx) ~] - =. ..foreign-update + =^ time=(unit @da) ..foreign-update =< ?>(?=(^ ref) .) + :: if it is a single request, and + :: :ship's remote scry isn't known to be broken, + :: or we learned it was broken more than an hour ago, + :: + ?: ?& ?=(%sing -.rave.sat) + ?| !(~(has by sad) her) + (lth now (add ~h1 (~(got by sad) her))) + == == + :: make the request over remote scry + :: + =/ =mood [%x case.mood.rave.sat path.i.need.sat] + [`- +]:(send-over-scry %back-index hen her inx syd mood) + :: otherwise, request over ames + :: + :- ~ + =/ =wire /back-index/(scot %p her)/[syd]/(scot %ud inx) + =/ =path [%backfill syd (scot %ud inx) ~] + =/ =fill [%0 syd lobe.i.need.sat] (emit hen %pass wire %a %plea her %c path fill) - ..abet(busy.sat &) + ..abet(busy.sat &, scry.sat time) :: :: When we get a %w foreign update, store this in our state. :: @@ -4587,16 +4675,53 @@ ++ load => |% +$ raft-any - $% [%10 raft-10] + $% [%11 raft-11] + [%10 raft-10] [%9 raft-9] [%8 raft-8] [%7 raft-7] [%6 raft-6] == - +$ raft-10 raft + +$ raft-11 raft + +$ raft-10 + $: rom=room + hoy=(map ship rung-10) + ran=rang + mon=(map term beam) + hez=(unit duct) + cez=(map @ta crew) + pud=(unit [=desk =yoki]) + dist-upgraded=_| + == + +$ rung-10 + $: rus=(map desk rede-10) + == + +$ rede-10 + $: lim=@da + ref=(unit rind-10) + qyx=cult + dom=dome + per=regs + pew=regs + fiz=melt + == + +$ rind-10 + $: nix=@ud + bom=(map @ud update-state-10) + fod=(map duct @ud) + haw=(map mood (unit cage)) + == + +$ update-state-10 + $: =duct + =rave + have=(map lobe blob) + need=(list lobe) + nako=(qeu (unit nako)) + busy=_| + == +$ raft-9 $: rom=room :: domestic - hoy=(map ship rung) :: foreign + hoy=(map ship rung-10) :: foreign ran=rang :: hashes mon=(map term beam) :: mount points hez=(unit duct) :: sync duct @@ -4637,7 +4762,7 @@ == +$ rede-8 $: lim=@da - ref=(unit rind) + ref=(unit rind-10) qyx=cult dom=dome-8 per=regs @@ -4668,7 +4793,7 @@ == +$ rede-7 $: lim=@da - ref=(unit rind) + ref=(unit rind-10) qyx=cult dom=dome-8 per=regs @@ -4705,7 +4830,7 @@ == +$ rede-6 $: lim=@da - ref=(unit rind) + ref=(unit rind-10) qyx=cult dom=dome-6 per=regs @@ -4715,11 +4840,12 @@ -- |= old=raft-any |^ - =? old ?=(%6 -.old) 7+(raft-6-to-7 +.old) - =? old ?=(%7 -.old) 8+(raft-7-to-8 +.old) - =? old ?=(%8 -.old) 9+(raft-8-to-9 +.old) - =? old ?=(%9 -.old) 10+(raft-9-to-10 +.old) - ?> ?=(%10 -.old) + =? old ?=(%6 -.old) 7+(raft-6-to-7 +.old) + =? old ?=(%7 -.old) 8+(raft-7-to-8 +.old) + =? old ?=(%8 -.old) 9+(raft-8-to-9 +.old) + =? old ?=(%9 -.old) 10+(raft-9-to-10 +.old) + =? old ?=(%10 -.old) 11+(raft-10-to-11 +.old) + ?> ?=(%11 -.old) ..^^$(ruf +.old) :: +raft-6-to-7: delete stale ford caches (they could all be invalid) :: @@ -4778,7 +4904,7 @@ |= =rung-8 %- ~(run by rus.rung-8) |= =rede-8 - ^- rede + ^- rede-10 =/ dom dom.rede-8 rede-8(dom [ank.dom let.dom hit.dom lab.dom mim.dom *ford-cache]) == @@ -4787,6 +4913,26 @@ |= raf=raft-9 ^- raft-10 raf(pud [pud.raf dist-upgraded=|]) + :: +raft-10-to-11: remove dist flag, add scry availability tracker + :: + ++ raft-10-to-11 + |= raf=raft-10 + ^- raft-11 + =- raf(hoy -, dist-upgraded [dist-upgraded.raf ~]) + %- ~(run by hoy.raf) + |= =rung-10 + %- ~(run by rus.rung-10) + |= =rede-10 + ^- rede + =- rede-10(ref -) + ?~ ref.rede-10 ~ + =- ref.rede-10(bom.u -) + %- ~(run by bom.u.ref.rede-10) + |= update-state-10 + ^- update-state + ::NOTE putting / paths is fine, the path is only used + :: when dealing with scry responses + [duct rave ~ have (turn need (lead /)) nako busy] -- :: ++ scry :: inspect @@ -4911,16 +5057,36 @@ :: TODO better error handling !! :: - %boon - =+ ;; res=(unit rand) payload.hin - :: + ?(%boon %tune) =/ her=ship (slav %p i.t.tea) =/ =desk (slav %tas i.t.t.tea) =/ index=@ud (slav %ud i.t.t.t.tea) :: =^ mos ruf + =; res=(unit rand) + =/ den ((de now rof hen ruf) her desk) + abet:(take-foreign-answer:den index res) + ?: ?=(%boon +<.hin) ;;((unit rand) payload.hin) + %+ bind data.hin + |= =(cask) + ^- rand + ::REVIEW this feels a bit dumb, but the alternative + :: is reconstructing it from ref:den instead, + :: which is also weird in its own ways. + =+ (need (de-omen path.hin)) + =/ =care ;;(care ?@(vis (rsh 3 vis) car.vis)) + [[care r.bem q.bem] s.bem cask] + [mos ..^$] + :: + %wake + =/ her=ship (slav %p i.t.tea) + =/ =desk (slav %tas i.t.t.tea) + =/ index=@ud (slav %ud i.t.t.t.tea) + ~& [%clay %scry-broken her] + =^ mos ruf + =. sad.ruf (~(put by sad.ruf) her now) =/ den ((de now rof hen ruf) her desk) - abet:(take-foreign-answer:den index res) + abet:(retry-with-ames:den index) [mos ..^$] == :: @@ -4940,13 +5106,16 @@ :: TODO better error handling !! :: - %boon - =+ ;; =blob payload.hin - :: + ?(%boon %tune) =/ her=ship (slav %p i.t.tea) =/ =desk (slav %tas i.t.t.tea) =/ index=@ud (slav %ud i.t.t.t.tea) :: + =/ =blob + ?: ?=(%boon +<.hin) ;;(blob payload.hin) + ?~ data.hin ~|(%now-what !!) ::TODO + [%direct (page-to-lobe u.data.hin) u.data.hin] + :: =^ mos ruf =/ den ((de now rof hen ruf) her desk) abet:abet:(take-backfill:(foreign-update:den index) blob) @@ -5018,6 +5187,7 @@ :: handled in the wire dispatcher :: %boon !! + %tune !! %lost !! %onto !! %unto !! From 0375e0a53f5a8ee1276d10edec172c7213786e48 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 15 Feb 2022 01:02:19 +0100 Subject: [PATCH 064/168] clay: remove dist-upgraded flag Ancient version upgraders beware! If you're coming from a home-based arvo, you must first upgrade to the version prior to this, or else you'll be in trouble! --- pkg/arvo/sys/vane/clay.hoon | 100 ++---------------------------------- 1 file changed, 3 insertions(+), 97 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 386f937c0..f3a5a1d04 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -168,8 +168,6 @@ hez=(unit duct) :: sync duct cez=(map @ta crew) :: permission groups pud=(unit [=desk =yoki]) :: pending update - :: REMOVE on next upgrade - dist-upgraded=_| :: are we in dist yet? sad=(map ship @da) :: scry known broken == :: :: @@ -1658,106 +1656,14 @@ =. mim.dom (apply-changes-to-mim mim.dom mim) =. fod.dom ford-cache.args =. ..park (emil (print q.old-yaki data)) - =? ..park &(updated !dist-upgraded.ruf) migrate-dist wake:(ergo mim) - :: - ++ migrate-dist - ~> %slog.0^'clay: migrating for third-party software distribution' - |^ ^+ ..park - =. ..park purge - :: first make sure gall has molted and has :hood running - :: - =. ..park (emit hen %pass /dist/hood %g %jolt %home %hood) - :: now ask :hood to install all the new desks - :: - :: NOTE: reverse order, since we're prepending moves each time - :: - =. ..park (install-from-tmp %bitcoin) - =. ..park (install-from-tmp %webterm) - =. ..park (install-from-tmp %landscape) - =. ..park (install-from-tmp %garden) - =. ..park (install-from-tmp %base) - ..park(dist-upgraded.ruf &) - :: - ++ purge - ^+ ..park - =/ wux=(list [=wove dux=(set duct)]) ~(tap by qyx) - |- ^+ ..park - ?~ wux ..park - =/ rov rove.wove.i.wux - =? qyx - ?+ -.rov | - %sing ?=([%a * %app %publish %hoon ~] mood.rov) - %next ?=([%a * %app %publish %hoon ~] mood.rov) - == - (~(del by qyx) wove.i.wux) - $(wux t.wux) - :: - ++ install-from-tmp - |= =desk - ^+ ..park - =/ sen (^^sein:title rof our now our) - %- lime - |^ ^- (list move) - =- (murn - same) - ^- (list (unit move)) - :~ `create-desk - `install-local - :: - ?: =(sen our) ~ - `install-remote - :: - ?: =(%base desk) ~ - `publish-desk - == - :: - ++ create-desk ^- move - :^ hen %pass /dist/create/[desk] - %^ new-desk:cloy desk - (latest-tako %home) - ;;((map path page) (cue (get-tmp-jam desk))) - :: - ++ publish-desk ^- move - :^ hen %pass /dist/public/[desk] - [%c %perm desk / %r `[%black ~]] - :: - ++ install-local ^- move - :^ hen %pass /dist/install-local/[desk] - [%g %deal [our our] %hood %poke %kiln-install !>([desk our desk])] - :: - ++ install-remote ^- move - =/ rem ?:(=(%base desk) %kids desk) - :: - :^ hen %pass /dist/install-remote/[desk] - [%g %deal [our our] %hood %poke %kiln-install !>([desk sen rem])] - -- - :: - ++ latest-tako - |= =desk - ^- (unit tako) - ?~ doj=(~(get by dos.rom) desk) ~ - =, dom.u.doj - (~(get by hit) let) - :: - ++ get-tmp-jam - |= =desk - ^- @ - ~| [%missing-tmp-desk-jam desk] - ?~ tmp=(~(get by dir.ank.dom) ~.tmp) !! - ?~ new=(~(get by dir.u.tmp) desk) !! - ?~ jam=(~(get by dir.u.new) ~.jam) !! - ?~ fil.u.jam !! - =* fil u.fil.u.jam - ?> =(%jam p.q.fil) - ;;(@ q.q.q.fil) - -- :: +is-kernel-path: should changing .pax cause a kernel or vane reload? :: ++ is-kernel-path |=(pax=path ?=([%sys *] pax)) :: ++ did-kernel-update |= invalid=(set path) - ?. |(=(%base syd) &(=(%home syd) !dist-upgraded.ruf)) + ?. =(%base syd) | %- ~(any in invalid) |=(p=path &((is-kernel-path p) !?=([%sys %vane *] p))) @@ -4513,7 +4419,7 @@ [mos ..^$] :: %init - [~ ..^$(hun.rom.ruf hen, dist-upgraded.ruf &)] + [~ ..^$(hun.rom.ruf hen)] :: %into =. hez.ruf `hen @@ -4918,7 +4824,7 @@ ++ raft-10-to-11 |= raf=raft-10 ^- raft-11 - =- raf(hoy -, dist-upgraded [dist-upgraded.raf ~]) + =- raf(hoy -, dist-upgraded ~) %- ~(run by hoy.raf) |= =rung-10 %- ~(run by rus.rung-10) From a36dc3aaff46e70c2d823631cdc228cc55d69860 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 15 Feb 2022 08:47:38 -0600 Subject: [PATCH 065/168] ames: per-lane congestion control --- bin/solid.pill | 4 +- pkg/arvo/sys/lull.hoon | 4 +- pkg/arvo/sys/vane/ames.hoon | 126 ++++++++++++++++++++++-------------- 3 files changed, 82 insertions(+), 52 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index bee0e858d..346f14610 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:357e851fbd779f9d19c0bad88befcff118ce81cdfc7c3f05fddca1c434e3754a -size 24334333 +oid sha256:b82eedaf051560580868736e4fea667dc1ef5404f7fd694fe0c1d14886e50816 +size 24661918 diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index fe689a1a6..a57dcad49 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -2,6 +2,7 @@ :: %lull: arvo structures :: => ..part +~% %lull ..part ~ |% ++ lull %330 :: :: :: @@ -960,7 +961,6 @@ $: order=(map path @ud) seq=@ud keens=((mop @ud keen-state) lte) - metrics=pump-metrics == +$ keen-state $: wan=(list want) :: request packets @@ -970,7 +970,7 @@ num-received=@ud next-wake=(unit @da) listeners=(set duct) - last-sent=(list [@ud @da]) + metrics=pump-metrics == +$ want $: fra=@ud diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index cd961451c..740bf0e21 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -1107,7 +1107,7 @@ %- ~(run by peers.old-state) |= =ship-state ?. ?=(%known -.ship-state) ship-state - ship-state(metrics.scry *pump-metrics) + ship-state(scry *scry-state) ames-gate(ames-state +.old-state) :: ++ state-5-to-6 @@ -2541,14 +2541,8 @@ ~ `pe-core(ship s, peer u.sta) :: - ++ pe-gauge - =| =bug - (make-pump-gauge now metrics.scry ship bug(ges.veb &)) - :: ++ pe-abet ^+ event-core - :: ~& show:pe-gauge - ::~& num-slots:pe-gauge =. peers.ames-state (~(put by peers.ames-state) ship known/peer) event-core @@ -2598,16 +2592,35 @@ == ++ ke-core . ++ ke-abet - =. ke-core ke-set-wake + ^+ pe-core =/ gone=? =, keen :: num-fragments is 0 when unknown (i.e. no response :: yet) &(!=(0 num-fragments) =(num-fragments num-received)) + ?: gone + ke-abet-gone + =. ke-core ke-set-wake =. keens.scry - ?: gone +:(del:orm keens.scry keen-id) (put:orm keens.scry keen-id keen) - =? order.scry gone + pe-core + :: + ++ ke-show + =, keen + :* wan=(lent wan) + nex=(lent nex) + hav=(lent hav) + num-fragments=num-fragments + num-received=num-received + next-wake=next-wake + metrics=metrics + == + :: + ++ ke-abet-gone + =. ke-core ke-set-wake + =. keens.scry + +:(del:orm keens.scry keen-id) + =. order.scry (~(del by order.scry) path) pe-core :: @@ -2634,21 +2647,27 @@ :: ++ ke-on-ack =| marked=(list want) + =/ wan wan.keen |= fra=@ud =/ og ke-core |- ^- [found=? _ke-core] - ?: =(~ wan.keen) [| og] - =^ =want wan.keen wan.keen + ?: =(~ wan) + ~& missing-ack/fra + [| og] + =^ =want wan wan ?: =(fra fra.want) - [& ke-core(wan.keen (welt marked wan.keen))] + =. metrics.keen + (on-ack:ke-gauge +>.want) + [& ke-core(wan.keen (welt marked wan))] =. skips.want +(skips.want) - =^ resend=? metrics.scry + =^ resend=? metrics.keen (on-skipped-packet:ke-gauge +>.want) ?. resend $(marked [want marked]) =. tries.want +(tries.want) =. last-sent.want now - =. ke-core (ke-send [fra hoot]:want) + =. ke-core + (ke-resend [fra hoot]:want) $(marked [want marked]) :: ++ ke-start @@ -2656,6 +2675,9 @@ ?> =(num-fragments.keen 0) =/ fra=@ 1 =/ req (ke-encode-req fra) + =/ =want [fra req now 1 0] + =. wan.keen ~[want] + =. metrics.keen (on-sent:ke-gauge 1) =- ke-core(event-core -) %- emit [unix-duct.ames-state %give %send pe-lane `@ux`req] @@ -2676,35 +2698,50 @@ %+ turn (gulf 1 siz.rawr) |= fra=@ud ^- want - [fra (ke-encode-req fra) now 1 0] + [fra (ke-encode-req fra) now 0 0] :: %_ keen num-fragments siz.rawr wan paz - nex paz + nex (tail paz) == :: +ke-continue: send packets according to normal congestion flow :: ++ ke-continue =| inx=@ud + =| sent=(list @ud) =/ max num-slots:ke-gauge |- ^+ ke-core - ?: =(~ nex.keen) ke-core - ?: =(inx max) ke-core + ?: |(=(~ nex.keen) =(inx max)) + (ke-update-last-sent (flop sent)) =^ =want nex.keen nex.keen + =. metrics.keen (on-sent:ke-gauge 1) =. ke-core (ke-emit hoot.want) - $(inx +(inx)) + $(inx +(inx), sent [fra.want sent]) :: - ++ ke-send + ++ ke-update-last-sent + !. + =| naw=(list want) + |= sent=(list @ud) + ?: =(~ wan.keen) + ?~ sent + =. wan.keen + (welt naw wan.keen) + ke-core + ~& bad-update-fra/sent !! + =^ =want wan.keen wan.keen + ?~ sent + =. wan.keen + (welt [want naw] wan.keen) + ke-core + ?. =(i.sent fra.want) + $(naw [want naw]) + =. last-sent.want now + =. tries.want +(tries.want) + $(sent t.sent, naw [want naw]) + :: + ++ ke-resend |= [fra=@ud =hoot] - =. metrics.scry (on-sent:ke-gauge 1) - =. nex.keen - =| xen=(list want) - |- ^+ nex.keen - =^ =want nex.keen nex.keen - ?: =(fra fra.want) - (welt xen nex.keen) - $(xen [want xen]) (ke-emit hoot) :: ++ ke-emit @@ -2723,15 +2760,6 @@ ?> =((lent hav) num-received) (decode-response-msg num-fragments hav) :: - ++ ke-update-congestion - !. - |= fra=@ud - ^+ metrics.scry - ?< =(~ wan.keen) - =^ =want wan.keen wan.keen - ?. =(fra fra.want) - $ - (on-ack:ke-gauge +>.want) ++ ke-is-dupe-ack |= fra=@ud ^- ? @@ -2745,9 +2773,10 @@ :: ++ ke-rcv |= [fra=@ud =purr =lane:ames] - =/ =rawr (decode-response-packet purr) ^+ ke-core + =/ =rawr (decode-response-packet purr) =/ og ke-core + =. pe-core (pe-update-qos %live last-contact=now) :: handle empty ?: =(0 siz.rawr) ?> =(~ dat.rawr) @@ -2756,8 +2785,6 @@ ~| wanted/+(num-received.keen) ?: (ke-is-dupe-ack fra) ke-core :: update congestion, or fill details - =? metrics.scry !=(0 num-fragments.keen) - (ke-update-congestion fra) :: =? ke-core =(0 num-fragments.keen) ?> =(fra 1) @@ -2781,23 +2808,22 @@ ke-continue :: ++ ke-gauge - =| =bug - :: =. bug ges.veb.bug & - (make-pump-gauge now metrics.scry ship bug) + =* bug bug.ames-state + (make-pump-gauge now metrics.keen ship bug) :: ++ ke-timer-wire `wire`(welp /fine/behn/wake/(scot %p ship) path) :: ++ ke-pass-timer |= =note - ke-core(event-core (emit duct %pass ke-timer-wire note)) + ke-core(event-core (emit unix-duct.ames-state %pass ke-timer-wire note)) :: ++ ke-wait |=(tim=@da (ke-pass-timer %b %wait tim)) ++ ke-rest |=(tim=@da (ke-pass-timer %b %rest tim)) ++ ke-set-wake ^+ ke-core =/ next-wake=(unit @da) - ?~ wan.keen ~ + ?~ wan.keen ~ `(next-expiry:ke-gauge +>:i.wan.keen) ?: =(next-wake next-wake.keen) ke-core @@ -2813,6 +2839,7 @@ :: ++ ke-take-wake ^+ ke-core + =. next-wake.keen ~ =. pe-core %- pe-update-qos =/ expiry=@da (add ~s30 last-contact.qos.peer) =? -.qos.peer @@ -2827,13 +2854,13 @@ !=(%czar (clan:title ship)) == route.peer(direct.u %.n) + =. metrics.keen on-timeout:ke-gauge :: - =. metrics.scry on-timeout:ke-gauge ?> ?=(^ wan.keen) =: tries.i.wan.keen +(tries.i.wan.keen) last-sent.i.wan.keen now == - (ke-send [fra hoot]:i.wan.keen) + (ke-resend [fra hoot]:i.wan.keen) -- -- ++ on-keen @@ -2898,6 +2925,9 @@ |= [=wire error=(unit tang)] ^+ event-core ~| fine-on-take-wake/wire + ?^ error + %- (slog leaf/"bad wake" u.error) + event-core :: TODO: handle error case ?> ?=([@ *] wire) =/ =ship (slav %p i.wire) From e036c96b6178e88dcada09ad84dc08f95c06082c Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 15 Feb 2022 20:36:35 +0100 Subject: [PATCH 066/168] ted: add -keen thread for simple remote scries Produces a (unit (cask)), as per %tune. --- pkg/arvo/ted/keen.hoon | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 pkg/arvo/ted/keen.hoon diff --git a/pkg/arvo/ted/keen.hoon b/pkg/arvo/ted/keen.hoon new file mode 100644 index 000000000..425817e2c --- /dev/null +++ b/pkg/arvo/ted/keen.hoon @@ -0,0 +1,12 @@ +/- spider +/+ strandio +=, strand=strand:spider +^- thread:spider +|= arg=vase +=/ m (strand ,vase) +^- form:m +=+ !<([~ arg=path] arg) +;< ~ bind:m (send-raw-card:strandio %pass / %arvo %a %keen arg) +;< [wire sign=sign-arvo] bind:m take-sign-arvo:strandio +?> ?=(%tune +<.sign) +(pure:m !>(data.sign)) From fb4b3c719672e165ec6ee13a81c8d1f7e2af6827 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 15 Feb 2022 22:35:53 +0100 Subject: [PATCH 067/168] clay: update straggler state version number --- pkg/arvo/sys/vane/clay.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index f3a5a1d04..0861ed66b 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -4323,7 +4323,7 @@ :: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: =| :: instrument state - $: ver=%10 :: vane version + $: ver=%11 :: vane version ruf=raft :: revision tree == :: |= [now=@da eny=@uvJ rof=roof] :: current invocation From 6688b9e6ad5bb5c8679eb694556be4e7482d0ebe Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 15 Feb 2022 16:56:29 -0600 Subject: [PATCH 068/168] deq: add finger tree datastructure --- pkg/arvo/lib/deq.hoon | 286 ++++++++++++++++++++++++++++++++++++ pkg/arvo/tests/lib/deq.hoon | 93 ++++++++++++ 2 files changed, 379 insertions(+) create mode 100644 pkg/arvo/lib/deq.hoon create mode 100644 pkg/arvo/tests/lib/deq.hoon diff --git a/pkg/arvo/lib/deq.hoon b/pkg/arvo/lib/deq.hoon new file mode 100644 index 000000000..34ecb15b3 --- /dev/null +++ b/pkg/arvo/lib/deq.hoon @@ -0,0 +1,286 @@ +|% +:: +++ welt + ~/ %welt + |* [a=(list) b=(list)] + => .(a ^.(homo a), b ^.(homo b)) + |- ^+ b + ?~ a b + $(a t.a, b [i.a b]) +++ afx + |$ [val] + $% [%1 p=val ~] + [%2 p=val q=val ~] + [%3 p=val q=val r=val ~] + [%4 p=val q=val r=val s=val ~] + == +++ pha + |$ [val] + $~ [%nul ~] + $% [%nul ~] + [%one p=val] + [%big p=(afx val) q=(pha val) r=(afx val)] + == +:: +++ deq + |* val=mold + |% + :: + :: +| %utilities + :: + ++ make-afx + |= ls=(list val) + ?+ ls ~|(bad-finger/(lent ls) !!) + [* ~] [%1 ls] + [* * ~] [%2 ls] + [* * * ~] [%3 ls] + [* * * * ~] [%4 ls] + == + :: + ++ afx-to-pha + |= =(afx val) + ^- (pha val) + (apl *(pha val) +.afx) + :: + :: +| %left-biased-operations + :: + :: +pop-left: remove leftmost value from tree + :: + ++ pop-left + |= a=(pha val) + ^- [val=(unit val) pha=(pha val)] + ?- -.a + %nul ~^a + :: + %one [`p.a nul/~] + :: + %big + [`p.p.a (big-left +.+.p.a q.a r.a)] + == + :: + ++ apl + |= [a=(pha val) vals=(list val)] + ^- (pha val) + =. vals (flop vals) + |- + ?~ vals a + $(a (cons a i.vals), vals t.vals) + :: + :: + ++ dip-left + |* state=mold + |= $: a=(pha val) + =state + f=$-([state val] [(unit val) ? state]) + == + ^+ [state a] + =/ acc [stop=`?`%.n state=state] + =| new=(pha val) + |- + ?: stop.acc + :: cat new and old + [state.acc (weld a new)] + =^ val=(unit val) a + (pop-left a) + ?~ val + [state.acc new] + =^ res=(unit ^val) acc + (f state.acc u.val) + ?~ res $ + $(new (snoc new u.res)) + :: + ++ big-left + |= [ls=(list val) a=(pha val) sf=(afx val)] + ^- (pha val) + ?. =(~ ls) + [%big (make-afx ls) a sf] + =/ [val=(unit val) inner=_a] + (pop-left a) + ?~ val + (afx-to-pha sf) + [%big [%1 u.val ~] inner sf] + :: + ++ cons + =| b=(list val) + |= [a=(pha val) c=val] + ^- (pha val) + =. b [c b] + |- + ?~ b a + ?- -.a + :: + %nul + $(a [%one i.b], b t.b) + :: + %one + %= $ + b t.b + a [%big [%1 i.b ~] [%nul ~] [%1 p.a ~]] + == + :: + %big + ?. ?=(%4 -.p.a) + %= $ + b t.b + :: + a + ?- -.p.a + %1 big/[[%2 i.b p.p.a ~] q.a r.a] + %2 big/[[%3 i.b p.p.a q.p.a ~] q.a r.a] + %3 big/[[%4 i.b p.p.a q.p.a r.p.a ~] q.a r.a] + == + == + =/ inner + $(a q.a, b ~[s.p.a r.p.a q.p.a]) + =. inner + $(a inner, b t.b) + big/[[%2 i.b p.p.a ~] inner r.a] + == + :: + :: +| %right-biased-operations + :: + :: +snoc: append to end (right) of tree + :: + ++ snoc + |= [a=(pha val) b=val] + ^+ a + ?- -.a + %nul [%one b] + :: + %one + :- %big + :* [%1 p.a ~] + [%nul ~] + [%1 b ~] + == + :: + %big + ?- -.r.a + :: + %1 + :- %big + [p.a q.a [%2 p.r.a b ~]] + :: + %2 + :- %big + [p.a q.a [%3 p.r.a q.r.a b ~]] + :: + %3 + :- %big + [p.a q.a [%4 p.r.a q.r.a r.r.a b ~]] + :: + %4 + =/ inner + $(a q.a, b p.r.a) + =. inner + $(a inner, b q.r.a) + =. inner + $(a inner, b r.r.a) + :- %big + :* p.a + inner + [%2 s.r.a b ~] + == + == + == + :: +apr: append list to end (right) of tree + :: + ++ apr + |= [a=(pha val) vals=(list val)] + ^- (pha val) + ?~ vals a + $(a (snoc a i.vals), vals t.vals) + :: + :: +big-right: construct a tree, automatically balancing the right + :: side + ++ big-right + |= [pf=(afx val) a=(pha val) ls=(list val)] + ^- (pha val) + ?. =(~ ls) + [%big pf a (make-afx ls)] + =/ [val=(unit val) inner=_a] + (pop-right a) + ?~ val + (afx-to-pha pf) + [%big pf inner [%1 u.val ~]] + :: + :: +pop-right: remove rightmost value from tree + :: + ++ pop-right + |= a=(pha val) + ^- [val=(unit val) pha=(pha val)] + ?- -.a + %nul ~^a + :: + %one [`p.a nul/~] + :: + %big + =/ ls=(list val) +.r.a + =^ item ls (flop ls) + [`item (big-right p.a q.a (flop ls))] + == + :: + ++ peek-right + |= a=(pha val) + ?- -.a + %nul ~ + %one `p.a + %big (rear +.r.a) + == + :: + :: +| %manipulation + :: + :: +weld: concatenate two trees + :: + :: O(log n) + ++ weld + =| c=(list val) + |= [a=(pha val) b=(pha val)] + ^- (pha val) + ?- -.b + %nul (apr a c) + %one (snoc (apr a c) p.b) + :: + %big + ?- -.a + %nul (apl b c) + %one (cons (apl b c) p.a) + :: + %big + :- %big + =- [p.a - r.b] + $(a q.a, b q.b, c :(welp +.r.a c +.p.b)) + == + == + :: +tap: transform tree to list + :: + ++ tap + =| res=(list val) + |= a=(pha val) + !. + |^ ^+ res + ?- -.a + %nul ~ + %one ~[p.a] + :: + %big + =/ fst=_res + (tap-afx p.a) + =/ lst=_res + (tap-afx r.a) + =/ mid=_res + $(a q.a) + :(welp fst mid lst) + == + ++ tap-afx + |= ax=(afx val) + ^+ res + ?- -.ax + %1 +.ax + %2 +.ax + %3 +.ax + %4 +.ax + == + -- + -- +-- diff --git a/pkg/arvo/tests/lib/deq.hoon b/pkg/arvo/tests/lib/deq.hoon new file mode 100644 index 000000000..d54fc1d26 --- /dev/null +++ b/pkg/arvo/tests/lib/deq.hoon @@ -0,0 +1,93 @@ +/+ *deq +/+ *test +=/ big-num + 100 +=/ de (deq ,@) +=/ big-list + (gulf 1 big-num) +=/ big + (apl:de *(pha @) big-list) +=/ foo-list (gulf 1 8) +|% +++ foo + (apl:de *(pha @) 1 2 3 4 5 6 7 8 ~) +++ bar + `(pha @)`(apl:de *(pha @) 8 9 10 11 12 13 14 15 ~) +:: +++ test-tap + =/ ls + ~> %bout.[1 %tap] + (tap:de big) + (expect-eq !>(ls) !>(big-list)) +:: +++ test-left + ^- tang + =/ bar + ~> %bout.[1 %cons] + (cons:de bar 7) + =. bar + ~> %bout.[1 %apl] + (apl:de bar 1 2 3 4 5 6 ~) + %- zing + :- + ~> %bout.[1 %eq-1] + (expect-eq !>((tap:de bar)) !>((gulf 1 15))) + =^ val=(unit @) bar + ~> %bout.[1 %pop-left] + (pop-left:de bar) + ~> %bout.[1 %eq-2] + :~ (expect-eq !>(1) !>((need val))) + (expect-eq !>((gulf 2 15)) !>((tap:de bar))) + == +:: +++ test-cons-tree + =/ foo + (cons:de foo 1) + ~ +:: +++ test-cons-list + =/ big-list + [1 big-list] + ~ +:: +++ test-rear-tree + =/ big big + =/ res (peek-right:de big) + ~ +:: +++ test-rear-list + =/ last (rear big-list) + ~ +:: +++ test-right + ^- tang + =/ foo + ~> %bout.[1 %snoc] + (snoc:de foo 9) + =. foo + (apr:de foo 10 11 12 13 14 15 ~) + %- zing + :- (expect-eq !>((tap:de foo)) !>((gulf 1 15))) + =^ val=(unit @) foo + (pop-right:de foo) + :~ (expect-eq !>((need val)) !>(15)) + (expect-eq !>((gulf 1 14)) !>((tap:de foo))) + == +++ test-queue + ^- tang + =/ foo foo + =. foo + (apr:de foo 9 10 11 12 13 14 15 ~) + =/ expected (gulf 1 15) + %- zing + |- ^- (list tang) + =^ val=(unit @) foo + (pop-left:de foo) + ?~ val + (expect-eq !>(~) !>(expected))^~ + ~& got/u.val + ?~ expected + ~[leaf/"queue mismatch"] + :- (expect-eq !>(i.expected) !>(u.val)) + $(expected t.expected) +-- From 6bd6029f579521fbc664fc6cbc40c6bc8f5e8ac6 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 16 Feb 2022 15:35:59 -0600 Subject: [PATCH 069/168] ames: use finger trees for packet storage --- pkg/arvo/sys/lull.hoon | 303 +++++++++++++++++++++- pkg/arvo/sys/vane/ames.hoon | 140 +++++----- pkg/arvo/tests/{lib => sys/lull}/deq.hoon | 0 pkg/arvo/tests/sys/vane/ames.hoon | 41 ++- 4 files changed, 389 insertions(+), 95 deletions(-) rename pkg/arvo/tests/{lib => sys/lull}/deq.hoon (100%) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index a57dcad49..90566d3e8 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -37,6 +37,307 @@ depth=_1 == :: +++ welt + ~/ %welt + |* [a=(list) b=(list)] + => .(a ^.(homo a), b ^.(homo b)) + |- ^+ b + ?~ a b + $(a t.a, b [i.a b]) +:: +:: +afx: polymorphic node type for finger trees +:: +++ afx + |$ [val] + $% [%1 p=val ~] + [%2 p=val q=val ~] + [%3 p=val q=val r=val ~] + [%4 p=val q=val r=val s=val ~] + == +:: +:: +pha: finger tree +:: +++ pha + |$ [val] + $~ [%nul ~] + $% [%nul ~] + [%one p=val] + [%big p=(afx val) q=(pha val) r=(afx val)] + == +:: +++ deq + |* val=mold + |% + :: + :: +| %utilities + :: + ++ make-afx + |= ls=(list val) + ?+ ls ~|(bad-finger/(lent ls) !!) + [* ~] [%1 ls] + [* * ~] [%2 ls] + [* * * ~] [%3 ls] + [* * * * ~] [%4 ls] + == + :: + ++ afx-to-pha + |= =(afx val) + ^- (pha val) + (apl *(pha val) +.afx) + :: + :: +| %left-biased-operations + :: + :: +pop-left: remove leftmost value from tree + :: + ++ pop-left + |= a=(pha val) + ^- [val=(unit val) pha=(pha val)] + ?- -.a + %nul ~^a + :: + %one [`p.a nul/~] + :: + %big + [`p.p.a (big-left +.+.p.a q.a r.a)] + == + :: + :: +peek-left: inspect leftmost value + :: + ++ peek-left + |= a=(pha val) + ^- (unit val) + ?- -.a + %nul ~ + %one `p.a + %big `p.p.a + == + :: + ++ apl + |= [a=(pha val) vals=(list val)] + ^- (pha val) + =. vals (flop vals) + |- + ?~ vals a + $(a (cons a i.vals), vals t.vals) + :: + :: + ++ dip-left + |* state=mold + |= $: a=(pha val) + =state + f=$-([state val] [(unit val) ? state]) + == + ^+ [state a] + =/ acc [stop=`?`%.n state=state] + =| new=(pha val) + |- + ?: stop.acc + :: cat new and old + [state.acc (weld a new)] + =^ val=(unit val) a + (pop-left a) + ?~ val + [state.acc new] + =^ res=(unit ^val) acc + (f state.acc u.val) + ?~ res $ + $(new (snoc new u.res)) + :: + ++ big-left + |= [ls=(list val) a=(pha val) sf=(afx val)] + ^- (pha val) + ?. =(~ ls) + [%big (make-afx ls) a sf] + =/ [val=(unit val) inner=_a] + (pop-left a) + ?~ val + (afx-to-pha sf) + [%big [%1 u.val ~] inner sf] + :: + ++ cons + =| b=(list val) + |= [a=(pha val) c=val] + ^- (pha val) + =. b [c b] + |- + ?~ b a + ?- -.a + :: + %nul + $(a [%one i.b], b t.b) + :: + %one + %= $ + b t.b + a [%big [%1 i.b ~] [%nul ~] [%1 p.a ~]] + == + :: + %big + ?. ?=(%4 -.p.a) + %= $ + b t.b + :: + a + ?- -.p.a + %1 big/[[%2 i.b p.p.a ~] q.a r.a] + %2 big/[[%3 i.b p.p.a q.p.a ~] q.a r.a] + %3 big/[[%4 i.b p.p.a q.p.a r.p.a ~] q.a r.a] + == + == + =/ inner + $(a q.a, b ~[s.p.a r.p.a q.p.a]) + =. inner + $(a inner, b t.b) + big/[[%2 i.b p.p.a ~] inner r.a] + == + :: + :: +| %right-biased-operations + :: + :: +snoc: append to end (right) of tree + :: + ++ snoc + |= [a=(pha val) b=val] + ^+ a + ?- -.a + %nul [%one b] + :: + %one + :- %big + :* [%1 p.a ~] + [%nul ~] + [%1 b ~] + == + :: + %big + ?- -.r.a + :: + %1 + :- %big + [p.a q.a [%2 p.r.a b ~]] + :: + %2 + :- %big + [p.a q.a [%3 p.r.a q.r.a b ~]] + :: + %3 + :- %big + [p.a q.a [%4 p.r.a q.r.a r.r.a b ~]] + :: + %4 + =/ inner + $(a q.a, b p.r.a) + =. inner + $(a inner, b q.r.a) + =. inner + $(a inner, b r.r.a) + :- %big + :* p.a + inner + [%2 s.r.a b ~] + == + == + == + :: +apr: append list to end (right) of tree + :: + ++ apr + |= [a=(pha val) vals=(list val)] + ^- (pha val) + ?~ vals a + $(a (snoc a i.vals), vals t.vals) + :: + :: +big-right: construct a tree, automatically balancing the right + :: side + ++ big-right + |= [pf=(afx val) a=(pha val) ls=(list val)] + ^- (pha val) + ?. =(~ ls) + [%big pf a (make-afx ls)] + =/ [val=(unit val) inner=_a] + (pop-right a) + ?~ val + (afx-to-pha pf) + [%big pf inner [%1 u.val ~]] + :: + :: +pop-right: remove rightmost value from tree + :: + ++ pop-right + |= a=(pha val) + ^- [val=(unit val) pha=(pha val)] + ?- -.a + %nul ~^a + :: + %one [`p.a nul/~] + :: + %big + =/ ls=(list val) +.r.a + =^ item ls (flop ls) + [`item (big-right p.a q.a (flop ls))] + == + :: + ++ peek-right + |= a=(pha val) + ?- -.a + %nul ~ + %one `p.a + %big (rear +.r.a) + == + :: + :: +| %manipulation + :: + :: +weld: concatenate two trees + :: + :: O(log n) + ++ weld + =| c=(list val) + |= [a=(pha val) b=(pha val)] + ^- (pha val) + ?- -.b + %nul (apr a c) + %one (snoc (apr a c) p.b) + :: + %big + ?- -.a + %nul (apl b c) + %one (cons (apl b c) p.a) + :: + %big + :- %big + =- [p.a - r.b] + $(a q.a, b q.b, c :(welp +.r.a c +.p.b)) + == + == + :: +tap: transform tree to list + :: + ++ tap + =| res=(list val) + |= a=(pha val) + !. + |^ ^+ res + ?- -.a + %nul ~ + %one ~[p.a] + :: + %big + =/ fst=_res + (tap-afx p.a) + =/ lst=_res + (tap-afx r.a) + =/ mid=_res + $(a q.a) + :(welp fst mid lst) + == + ++ tap-afx + |= ax=(afx val) + ^+ res + ?- -.ax + %1 +.ax + %2 +.ax + %3 +.ax + %4 +.ax + == + -- + -- +:: :: +mop: constructs and validates ordered ordered map based on key, :: val, and comparator gate :: @@ -963,7 +1264,7 @@ keens=((mop @ud keen-state) lte) == +$ keen-state - $: wan=(list want) :: request packets + $: wan=(pha want) :: request packets, sent nex=(list want) :: request packets, unsent hav=(list have) :: response packets, backward num-fragments=@ud diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 740bf0e21..b88509f0c 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -311,12 +311,13 @@ wid=(cut 3 [68 2] purr) dat=(rsh 3^70 purr) == +++ response-size 13 :: 1kb :: ++ decode-response-msg |= [total=@ud hav=(list have)] ^- roar =/ mess=@ - %+ rep 13 + %+ rep response-size %+ turn (flop hav) |= =have dat.have @@ -1103,11 +1104,6 @@ =? old-state ?=(%5 -.old-state) %6^(state-5-to-6 +.old-state) :: ?> ?=(%6 -.old-state) - =. peers.old-state - %- ~(run by peers.old-state) - |= =ship-state - ?. ?=(%known -.ship-state) ship-state - ship-state(scry *scry-state) ames-gate(ames-state +.old-state) :: ++ state-5-to-6 @@ -2556,7 +2552,6 @@ =. order.scry (~(put by order.scry) path keen-id) =| =keen-state - =. wan.keen-state ~ :: TODO =. keens.scry (put:orm keens.scry keen-id keen-state) ke-abet:ke-start:(ke-abed:keen-core path) :: @@ -2607,8 +2602,7 @@ :: ++ ke-show =, keen - :* wan=(lent wan) - nex=(lent nex) + :* nex=(lent nex) hav=(lent hav) num-fragments=num-fragments num-received=num-received @@ -2626,6 +2620,7 @@ :: ++ ke-abed |= p=^path + ~| no-keen-for-path/p =. keen-id (~(got by order.scry) p) ke-core(path p, keen (got:orm keens.scry keen-id)) :: @@ -2640,6 +2635,8 @@ ^- (unit ^path) ?^ out out ?:(=(id i) `p ~) + ++ ke-deq + (deq want) :: ++ ke-encode-req |= frag=@ud @@ -2647,36 +2644,40 @@ :: ++ ke-on-ack =| marked=(list want) - =/ wan wan.keen |= fra=@ud - =/ og ke-core - |- ^- [found=? _ke-core] - ?: =(~ wan) - ~& missing-ack/fra - [| og] - =^ =want wan wan + ^- [? _ke-core] + =; [[found=? cor=_ke-core] wan=(pha want)] + ?. found + [found ke-core] + [found cor(wan.keen wan)] + %^ (dip-left:ke-deq ,[found=? cor=_ke-core]) wan.keen + [| ke-core] + |= [[found=? cor=_ke-core] =want] + ^- [(unit _want) stop=? [found=? cor=_ke-core]] + =. ke-core cor ?: =(fra fra.want) - =. metrics.keen + =. metrics.keen (on-ack:ke-gauge +>.want) - [& ke-core(wan.keen (welt marked wan))] + [~ %.y %.y ke-core] =. skips.want +(skips.want) =^ resend=? metrics.keen (on-skipped-packet:ke-gauge +>.want) ?. resend - $(marked [want marked]) + [`want %.n found ke-core] =. tries.want +(tries.want) =. last-sent.want now - =. ke-core + =. ke-core (ke-resend [fra hoot]:want) - $(marked [want marked]) + [`want %.n found ke-core] :: ++ ke-start ~| tried-to-start-request-already-in-progress/path + ~& start/now ?> =(num-fragments.keen 0) =/ fra=@ 1 =/ req (ke-encode-req fra) =/ =want [fra req now 1 0] - =. wan.keen ~[want] + =. wan.keen (cons:ke-deq *(pha ^want) want) =. metrics.keen (on-sent:ke-gauge 1) =- ke-core(event-core -) %- emit @@ -2702,7 +2703,6 @@ :: %_ keen num-fragments siz.rawr - wan paz nex (tail paz) == :: +ke-continue: send packets according to normal congestion flow @@ -2713,32 +2713,14 @@ =/ max num-slots:ke-gauge |- ^+ ke-core ?: |(=(~ nex.keen) =(inx max)) - (ke-update-last-sent (flop sent)) - =^ =want nex.keen nex.keen - =. metrics.keen (on-sent:ke-gauge 1) - =. ke-core (ke-emit hoot.want) - $(inx +(inx), sent [fra.want sent]) - :: - ++ ke-update-last-sent - !. - =| naw=(list want) - |= sent=(list @ud) - ?: =(~ wan.keen) - ?~ sent - =. wan.keen - (welt naw wan.keen) - ke-core - ~& bad-update-fra/sent !! - =^ =want wan.keen wan.keen - ?~ sent - =. wan.keen - (welt [want naw] wan.keen) ke-core - ?. =(i.sent fra.want) - $(naw [want naw]) + =^ =want nex.keen nex.keen =. last-sent.want now =. tries.want +(tries.want) - $(sent t.sent, naw [want naw]) + =. wan.keen (snoc:ke-deq wan.keen want) + =. metrics.keen (on-sent:ke-gauge 1) + =. ke-core (ke-emit hoot.want) + $(inx +(inx)) :: ++ ke-resend |= [fra=@ud =hoot] @@ -2753,6 +2735,7 @@ :: ++ ke-decode-full =, keen + ~& num/num-received ~| %frag-mismatch ~| have/num-received ~| need/num-fragments @@ -2760,16 +2743,6 @@ ?> =((lent hav) num-received) (decode-response-msg num-fragments hav) :: - ++ ke-is-dupe-ack - |= fra=@ud - ^- ? - ?: =(num-fragments.keen 0) | - ?: =(~ wan.keen) & - =^ =want wan.keen wan.keen - ?. =(fra fra.want) - $ - | - :: ++ ke-rcv |= [fra=@ud =purr =lane:ames] @@ -2781,23 +2754,21 @@ ?: =(0 siz.rawr) ?> =(~ dat.rawr) (ke-done sig.rawr ~) - ~| out-of-order/fra - ~| wanted/+(num-received.keen) - ?: (ke-is-dupe-ack fra) ke-core :: update congestion, or fill details :: =? ke-core =(0 num-fragments.keen) ?> =(fra 1) (ke-first-rcv rawr) :: - :: ?> =(fra +(num-received.keen)) :: TODO: fix OoO - ~| failed-signature/sig - ?> (veri:keys ship life.peer [sig dat]:rawr) + ~| failed-signature/fra^`@ux`sig.rawr + ~| life.peer + ?> (veri-fra:keys ship life.peer path fra [dat sig]:rawr) =^ found=? ke-core (ke-on-ack fra) + :: ?. found :: discard changes - ~& missing-fra/fra + ~& dupe-ack/fra og =/ =have [fra rawr] =. hav.keen @@ -2823,8 +2794,9 @@ ++ ke-set-wake ^+ ke-core =/ next-wake=(unit @da) - ?~ wan.keen ~ - `(next-expiry:ke-gauge +>:i.wan.keen) + =/ want=(unit want) (peek-left:ke-deq wan.keen) + ?~ want ~ + `(next-expiry:ke-gauge +>:u.want) ?: =(next-wake next-wake.keen) ke-core =? ke-core !=(~ next-wake.keen) @@ -2855,12 +2827,15 @@ == route.peer(direct.u %.n) =. metrics.keen on-timeout:ke-gauge - :: - ?> ?=(^ wan.keen) - =: tries.i.wan.keen +(tries.i.wan.keen) - last-sent.i.wan.keen now + =^ want=(unit want) wan.keen + (pop-left:ke-deq wan.keen) + ~| %took-wake-for-empty-want + ?> ?=(^ want) + =: tries.u.want +(tries.u.want) + last-sent.u.want now == - (ke-resend [fra hoot]:i.wan.keen) + =. wan.keen (cons:ke-deq wan.keen u.want) + (ke-resend [fra hoot]:u.want) -- -- ++ on-keen @@ -2999,7 +2974,7 @@ ::NOTE path is expected to be a namespace path without the ship ^- hoot ^- @ =+ bod=(request-body path num) - =+ sig=64^(fil 5 16 0xdead.beef) :: 64^(sign:keys dat.bod) + =+ sig=64^(sign:keys dat.bod) =+ syn=(can 3 sig bod ~) %+ con 0b100 ::NOTE request bit %^ encode-packet | @@ -3024,10 +2999,9 @@ :: prepend a signature and split the data into 1024-byte fragments :: =/ frag=(list @) - =/ sig=@ :: (full:keys path data) - (fil 5 16 0xdead.beef) + =/ sig=@ (full:keys path data) ?~ data [sig]~ - %+ rip 13 ::NOTE 1024 bytes + %+ rip response-size ::NOTE 1024 bytes (cat 3 sig (jam data)) ::TODO should include life :: sign & packetize the fragments :: @@ -3046,8 +3020,7 @@ wid^dat :: response data fragment == =/ sig=byts - 64^(fil 5 16 0xcafe.face) - :: 64^(sign:keys (can 3 req bod ~)) + 64^(sign-fra:keys path num dat) (can 3 req sig bod ~) :: ++ keys @@ -3059,6 +3032,14 @@ |= [=path data=$@(~ (cask))] (sign (mess our life.ames-state path data)) :: + ++ sign-fra + |= [=path fra=@ dat=@ux] + (sign (jam path fra dat)) + :: + ++ veri-fra + |= [who=ship lyf=life =path fra=@ dat=@ux sig=@] + (veri who lyf sig (jam path fra dat)) + :: ++ sign sigh:as:crypto-core.ames-state :: @@ -3082,9 +3063,8 @@ ++ veri |= [who=ship lyf=life sig=@ dat=@] ^- ? - & - :: =/ =^pass (pass who lyf) - :: (safe:as:(com:nu:crub:crypto pass) sig dat) + =/ =^pass (pass who lyf) + (safe:as:(com:nu:crub:crypto pass) sig dat) :: ++ meri |= [who=ship lyf=life pax=path sig=@ dat=$@(~ (cask))] @@ -3140,7 +3120,7 @@ ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) siz.rawr +(num-received) - ?> (veri:keys from life [sig dat]:rawr) + :: ?> (veri:keys from life path.peep num.peep dat.rawr) (~(put by fragments) num.peep [wid dat]:rawr) :: ?: =(num-fragments num-received):partial diff --git a/pkg/arvo/tests/lib/deq.hoon b/pkg/arvo/tests/sys/lull/deq.hoon similarity index 100% rename from pkg/arvo/tests/lib/deq.hoon rename to pkg/arvo/tests/sys/lull/deq.hoon diff --git a/pkg/arvo/tests/sys/vane/ames.hoon b/pkg/arvo/tests/sys/vane/ames.hoon index 9352340f1..922b87df3 100644 --- a/pkg/arvo/tests/sys/vane/ames.hoon +++ b/pkg/arvo/tests/sys/vane/ames.hoon @@ -2,8 +2,8 @@ /= ames /sys/vane/ames :: construct some test fixtures :: -=/ nec (ames ~nec) -=/ bud (ames ~bud) +=/ nec ^$:((ames ~nec)) +=/ bud ^$:((ames ~bud)) =/ comet (ames ~bosrym-podwyl-magnes-dacrys--pander-hablep-masrym-marbud) :: =. now.nec ~1111.1.1 @@ -358,18 +358,19 @@ :: ++ test-fine-response ^- tang + =/ datum=@ux (fil 5 32 0xdead.beef) =/ want=path /cz/~bud/kids/1/sys - =/ net=path /cz/kids/1/sys + =/ net=path /cz/~bud/kids/1/sys + =. rof.bud + |=(* ``noun+!>(datum)) =/ =beam [[~bud %$ da+now:bud] (welp /fine/message net)] =/ [=mark =vase] (need (need (scry bud %x beam))) =+ !<(=song:ames vase) - =/ partial - %- ~(gas by *(map @ud byts)) - ^- (list [@ud byts]) + =/ partial=(list have:ames) %- head %^ spin song 1 |= [blob=@ux num=@ud] - ^- [[_num byts] _num] + ^- [have:ames _num] :_ +(num) =/ [is-ames=? =packet:ames] (decode-packet:ames `@ux`blob) ?> ?=(%| is-ames) @@ -379,12 +380,24 @@ ~& rawr-siz/`@ux`siz.rawr ~& rawr-wid/`@ux`wid.rawr ~& rawr-dat/`@ux`dat.rawr - :- num - [wid dat]:rawr - =/ num-frag=@ud ~(wyt by partial) + [num rawr] + :: + =/ num-frag=@ud (lent partial) =/ =roar:ames - (decode-response-msg:ames num-frag num-frag partial) - ~& roar - ~! . - (expect-eq !>(1) !>(1)) + (decode-response-msg:ames num-frag (flop partial)) + %+ welp + =/ dat + ?> ?=(^ dat.roar) + ;;(@ux q.dat.roar) + (expect-eq !>(dat) !>(datum)) + =/ event-core + ~! nec + =/ foo [*@da *@ rof.nec] + (per-event:(nec foo) [*@da *@ rof.nec] *duct ames-state.nec) + %- zing + %+ turn partial + |= [fra=@ud sig=@ siz=@ud byts] + %+ expect-eq !>(%.y) + !>((veri-fra:keys:fine:event-core ~bud life.ames-state.bud want fra dat sig)) + -- From 60645131c4416f37d8d4fe05d2b1dd85c44b3c4e Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 16 Feb 2022 15:36:13 -0600 Subject: [PATCH 070/168] pill: update solid --- bin/solid.pill | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index 346f14610..062269426 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b82eedaf051560580868736e4fea667dc1ef5404f7fd694fe0c1d14886e50816 -size 24661918 +oid sha256:1a2dfd4f7850be3fd83cf3b7014cfd43aaca5ee4d12fd5ca8ec74a0801049658 +size 24897862 From dd4a115e5177028e2bdd465bb877947b6fdc1c47 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 15:40:44 +0100 Subject: [PATCH 071/168] clay: avoid %v scries, cancel scry timer correctly %v requests are already handled specially for the ames case. We should continue to respect that, only doing those kinds of requests over ames. Also cancels the scry timer after receiving a response, instead of not doing that. --- pkg/arvo/sys/vane/clay.hoon | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 0861ed66b..a3414182d 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -361,6 +361,8 @@ :: %utilities :: |% +++ scry-timeout-time ~m1 +++ scry-retry-time ~h1 :: +sort-by-head: sorts alphabetically using the head of each element :: ++ sort-by-head @@ -1324,7 +1326,7 @@ ++ send-over-scry |= [kind=@ta =duct =ship index=@ud =desk =mood] ^- [timeout=@da _..send-over-scry] - =/ =time (add now ~m1) + =/ =time (add now scry-timeout-time) =/ =wire /[kind]/(scot %p ship)/[desk]/(scot %ud index) =/ =path =, mood @@ -1335,6 +1337,11 @@ [hen %pass wire %b %wait time] == :: + ++ cancel-scry-timeout + |= [kind=@ta =duct =ship index=@ud =desk time=@da] + =/ =wire /[kind]/(scot %p ship)/[desk]/(scot %ud index) + (emit duct %pass wire %b %rest time) + :: ++ foreign-capable |= =rave |^ @@ -1369,13 +1376,15 @@ (run-if-future rove.wov |=(@da (bait hen +<))) |- ^+ +>+.$ =/ =rave (rove-to-rave rove.wov) + =? rave ?=([%sing %v *] rave) + [%many %| [%ud let.dom] case.mood.rave path.mood.rave] :: if it is a single request, and :: :ship's remote scry isn't known to be broken, :: or we learned it was broken more than an hour ago, :: ?: ?& ?=(%sing -.rave) ?| !(~(has by sad) her) - (lth now (add ~h1 (~(got by sad) her))) + (lth now (add scry-retry-time (~(got by sad) her))) == == :: send request as remote scry ::TODO can be deduplicated with the below? @@ -1390,10 +1399,6 @@ fod.u.ref (~(put by fod.u.ref) hen inx) == :: - =. rave - ?. ?=([%sing %v *] rave) rave - [%many %| [%ud let.dom] case.mood.rave path.mood.rave] - :: ?. (foreign-capable rave) ~|([%clay-bad-foreign-request-care rave] !!) :: @@ -3003,6 +3008,9 @@ ?> ?=(^ ref) =+ ruv=(~(get by bom.u.ref) inx) ?~ ruv +>.$ + =? ..take-foreign-answer ?=(^ scry.u.ruv) + =< ?>(?=(^ ref) .) + (cancel-scry-timeout %warp-index hen her inx syd u.scry.u.ruv) =/ rav=rave rave.u.ruv ?: ?=(%many -.rav) abet:(apex:(foreign-update inx) rut) @@ -3121,7 +3129,7 @@ :: =? ..foreign-update ?=(^ scry.sat) =< ?>(?=(^ ref) .) - (emit hen %pass / %b %rest u.scry.sat) + (cancel-scry-timeout %back-index hen her inx syd u.scry.sat) =. scry.sat ~ |% ++ abet From 347303349274c52e69648aaec3fdf71db0c628e5 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 15:44:16 +0100 Subject: [PATCH 072/168] clay: scry when doing file requests outside %sing In +work, we simply want to fetch file data, regardless of what the overarching request is. (In fact, %sing would likely never hit this path anyway.) In order to be able to make the scry request, we track the timestamp of the commit that contains a blob we're missing, and scry for that %da revision. There's two edge cases where we cannot immediately know the timestamp that are currently assumed broken. Fix soon. --- pkg/arvo/sys/vane/clay.hoon | 39 ++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index a3414182d..387208b04 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -236,7 +236,7 @@ =rave scry=(unit @da) :: timeout timer if scry have=(map lobe blob) - need=(list [=path =lobe]) + need=(list [when=@da =path =lobe]) nako=(qeu (unit nako)) busy=_| == @@ -3159,21 +3159,27 @@ :: ++ missing-blobs |= =nako - ^- (list [path lobe]) + =| miss=(set lobe) + ^- (list [@da path lobe]) + ::REVIEW should this get sorted so that we prefer getting files + :: from the latest commit, if there are duplicates? =/ yakis ~(tap in lar.nako) - |- ^- (list [path lobe]) + |- ^- (list [@da path lobe]) =* yaki-loop $ ?~ yakis ~ =/ lobes=(list [=path =lobe]) ~(tap by q.i.yakis) - |- ^- (list [path lobe]) + |- ^- (list [@da path lobe]) =* blob-loop $ ?~ lobes yaki-loop(yakis t.yakis) - ?: (~(has by lat.ran) lobe.i.lobes) + =* lobe lobe.i.lobes + ?: ?| (~(has by lat.ran) lobe) + (~(has in miss) lobe) + == blob-loop(lobes t.lobes) - :- i.lobes - blob-loop(lobes t.lobes) + :- [t.i.yakis i.lobes] + blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) :: :: Receive backfill response :: @@ -3187,9 +3193,12 @@ !(~(has by have.sat) q.q.blob) == ::NOTE we have already fallen back to the ames case, + :: (scry responses always come in as %direct blobs) :: so we do not need the real path here anymore. ::REVIEW right? or is this considered too fragile? - [[/ q.q.blob] need.sat] + :: actually yeah, we might retry scry later... + ::TODO also wouldn't this want to check if lobe was already in need? + [[*@da / q.q.blob] need.sat] :: We can't put a blob in lat.ran if its parent isn't already :: there. Unions are in reverse order so we don't overwrite :: existing blobs. @@ -3243,13 +3252,13 @@ :: :ship's remote scry isn't known to be broken, :: or we learned it was broken more than an hour ago, :: - ?: ?& ?=(%sing -.rave.sat) - ?| !(~(has by sad) her) - (lth now (add ~h1 (~(got by sad) her))) - == == + ?: ?| !(~(has by sad) her) + (lth now (add scry-retry-time (~(got by sad) her))) + == :: make the request over remote scry :: - =/ =mood [%x case.mood.rave.sat path.i.need.sat] + =/ =mood + [%x da+when path]:i.need.sat [`- +]:(send-over-scry %back-index hen her inx syd mood) :: otherwise, request over ames :: @@ -4846,7 +4855,9 @@ ^- update-state ::NOTE putting / paths is fine, the path is only used :: when dealing with scry responses - [duct rave ~ have (turn need (lead /)) nako busy] + ::TODO but that isn't actually true, is it? we might fall back to + :: scry in the middle, right? + [duct rave ~ have (turn need (corl (lead *@da) (lead /))) nako busy] -- :: ++ scry :: inspect From d6b5633c995bcae427448f7f0b244e1ca7e09023 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 16:02:57 +0100 Subject: [PATCH 073/168] clay: allow for lobe-only need This can occur after upgrade, or when receiving a %delta blob. We do not know the path or commit timestamp of a file that resolves to the blob, so we simply fall back to old ames-style blob-by-lobe fetching. --- pkg/arvo/sys/vane/clay.hoon | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 387208b04..6ae8e3228 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -234,9 +234,9 @@ +$ update-state $: =duct =rave - scry=(unit @da) :: timeout timer if scry + scry=(unit @da) :: if scry, timeout have=(map lobe blob) - need=(list [when=@da =path =lobe]) + need=(list $@(lobe [when=@da =path =lobe])) :: opt deets for scry nako=(qeu (unit nako)) busy=_| == @@ -3192,13 +3192,7 @@ !(~(has by lat.ran) q.q.blob) !(~(has by have.sat) q.q.blob) == - ::NOTE we have already fallen back to the ames case, - :: (scry responses always come in as %direct blobs) - :: so we do not need the real path here anymore. - ::REVIEW right? or is this considered too fragile? - :: actually yeah, we might retry scry later... - ::TODO also wouldn't this want to check if lobe was already in need? - [[*@da / q.q.blob] need.sat] + [q.q.blob need.sat] :: We can't put a blob in lat.ran if its parent isn't already :: there. Unions are in reverse order so we don't overwrite :: existing blobs. @@ -3240,21 +3234,25 @@ :: another desk updating concurrently, or a previous update on this :: same desk). :: - ?: ?| (~(has by lat.ran) lobe.i.need.sat) - (~(has by have.sat) lobe.i.need.sat) + =/ =lobe + ?@ i.need.sat i.need.sat + lobe.i.need.sat + ?: ?| (~(has by lat.ran) lobe) + (~(has by have.sat) lobe) == $(need.sat t.need.sat) :: Otherwise, fetch the next blob :: =^ time=(unit @da) ..foreign-update =< ?>(?=(^ ref) .) - :: if it is a single request, and - :: :ship's remote scry isn't known to be broken, + :: if we know a revision & path for the blob, + :: and :ship's remote scry isn't known to be broken, :: or we learned it was broken more than an hour ago, :: - ?: ?| !(~(has by sad) her) + ?: ?& ?=(^ i.need.sat) + ?| !(~(has by sad) her) (lth now (add scry-retry-time (~(got by sad) her))) - == + == == :: make the request over remote scry :: =/ =mood @@ -3265,7 +3263,7 @@ :- ~ =/ =wire /back-index/(scot %p her)/[syd]/(scot %ud inx) =/ =path [%backfill syd (scot %ud inx) ~] - =/ =fill [%0 syd lobe.i.need.sat] + =/ =fill [%0 syd lobe] (emit hen %pass wire %a %plea her %c path fill) ..abet(busy.sat &, scry.sat time) :: @@ -4853,11 +4851,7 @@ %- ~(run by bom.u.ref.rede-10) |= update-state-10 ^- update-state - ::NOTE putting / paths is fine, the path is only used - :: when dealing with scry responses - ::TODO but that isn't actually true, is it? we might fall back to - :: scry in the middle, right? - [duct rave ~ have (turn need (corl (lead *@da) (lead /))) nako busy] + [duct rave ~ have need nako busy] -- :: ++ scry :: inspect From 7c0f05f8c3ceaeec79b7f999032f26f31c86b885 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 16:08:48 +0100 Subject: [PATCH 074/168] clay: hook up /back-index %wake And make sure we handle the timer error case safely. --- pkg/arvo/sys/vane/clay.hoon | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 6ae8e3228..6163a6138 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -2990,6 +2990,8 @@ =/ sat=update-state (~(got by bom.u.ref) inx) =. ..retry-with-ames =< ?>(?=(^ ref) .) + ::REVIEW isn't this a bit much, if we're already partway through? + :: do we not want to just call into +work in that case? (send-over-ames hen her inx syd `rave.sat) =. bom.u.ref (~(put by bom.u.ref) inx sat(scry ~)) ..retry-with-ames @@ -4998,6 +5000,8 @@ [mos ..^$] :: %wake + ?^ error.hin + [[hen %slip %d %flog %crud %wake u.error.hin]~ ..^$] =/ her=ship (slav %p i.t.tea) =/ =desk (slav %tas i.t.t.tea) =/ index=@ud (slav %ud i.t.t.t.tea) @@ -5039,6 +5043,18 @@ =/ den ((de now rof hen ruf) her desk) abet:abet:(take-backfill:(foreign-update:den index) blob) [mos ..^$] + :: + %wake + ?^ error.hin + [[hen %slip %d %flog %crud %wake u.error.hin]~ ..^$] + =/ her=ship (slav %p i.t.tea) + =/ =desk (slav %tas i.t.t.tea) + =/ index=@ud (slav %ud i.t.t.t.tea) + =^ mos ruf + =. sad.ruf (~(put by sad.ruf) her now) + =/ den ((de now rof hen ruf) her desk) + abet:(retry-with-ames:den index) + [mos ..^$] == :: ?: ?=([%sinks ~] tea) From b91e3f425e6371ca3ef53608678cd9c3374d19c7 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 20:10:38 +0100 Subject: [PATCH 075/168] clay: retry with ames on empty scry response --- pkg/arvo/sys/vane/clay.hoon | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 6163a6138..a18472917 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -5034,14 +5034,16 @@ =/ =desk (slav %tas i.t.t.tea) =/ index=@ud (slav %ud i.t.t.t.tea) :: - =/ =blob - ?: ?=(%boon +<.hin) ;;(blob payload.hin) - ?~ data.hin ~|(%now-what !!) ::TODO - [%direct (page-to-lobe u.data.hin) u.data.hin] + =/ blob=(unit blob) + ?: ?=(%boon +<.hin) `;;(blob payload.hin) + ?~ data.hin ~ + `[%direct (page-to-lobe u.data.hin) u.data.hin] :: =^ mos ruf =/ den ((de now rof hen ruf) her desk) - abet:abet:(take-backfill:(foreign-update:den index) blob) + ?~ blob + abet:(retry-with-ames:den index) + abet:abet:(take-backfill:(foreign-update:den index) u.blob) [mos ..^$] :: %wake From 02dec3ef5b44d38dcb5e26add42ce137e7ffcd63 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 21:14:52 +0100 Subject: [PATCH 076/168] clay: scry files at aeons, not timestamps Turns out we can simply find the corresponding aeon in the nako. --- pkg/arvo/sys/vane/clay.hoon | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index a18472917..424af1c8e 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -236,7 +236,7 @@ =rave scry=(unit @da) :: if scry, timeout have=(map lobe blob) - need=(list $@(lobe [when=@da =path =lobe])) :: opt deets for scry + need=(list $@(lobe [=aeon =path =lobe])) :: opt deets for scry nako=(qeu (unit nako)) busy=_| == @@ -3162,16 +3162,14 @@ ++ missing-blobs |= =nako =| miss=(set lobe) - ^- (list [@da path lobe]) - ::REVIEW should this get sorted so that we prefer getting files - :: from the latest commit, if there are duplicates? + ^- (list [aeon path lobe]) =/ yakis ~(tap in lar.nako) - |- ^- (list [@da path lobe]) + |- ^- (list [aeon path lobe]) =* yaki-loop $ ?~ yakis ~ =/ lobes=(list [=path =lobe]) ~(tap by q.i.yakis) - |- ^- (list [@da path lobe]) + |- ^- (list [aeon path lobe]) =* blob-loop $ ?~ lobes yaki-loop(yakis t.yakis) @@ -3180,8 +3178,16 @@ (~(has in miss) lobe) == blob-loop(lobes t.lobes) - :- [t.i.yakis i.lobes] - blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) + =; =aeon + :- [aeon i.lobes] + blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) + :: find the aeon corresponding to the commit containing this lobe. + :: we unfortunately do not have a reverse lookup map. + :: + =/ l=(list [a=aeon t=tako]) ~(tap by gar.nako) + |- + ?~ l ~|([%missing-aeon-for-tako her syd `@uw`tako] !!) + ?:(=(r.i.yakis t.i.l) a.i.l $(l t.l)) :: :: Receive backfill response :: @@ -3258,7 +3264,7 @@ :: make the request over remote scry :: =/ =mood - [%x da+when path]:i.need.sat + [%x ud+aeon path]:i.need.sat [`- +]:(send-over-scry %back-index hen her inx syd mood) :: otherwise, request over ames :: From 2969b1aae16b960d49c7aa099ed7f4a1f993c83a Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 21:17:45 +0100 Subject: [PATCH 077/168] clay: clean up REVIEW comments --- pkg/arvo/sys/vane/clay.hoon | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 424af1c8e..e1232032f 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -2981,7 +2981,6 @@ ..start-request (duce for u.new-sub) :: - ::TODO should this try-fill-sub or w/e in case its now in our cache? ++ retry-with-ames |= inx=@ud ^+ ..retry-with-ames @@ -2990,8 +2989,6 @@ =/ sat=update-state (~(got by bom.u.ref) inx) =. ..retry-with-ames =< ?>(?=(^ ref) .) - ::REVIEW isn't this a bit much, if we're already partway through? - :: do we not want to just call into +work in that case? (send-over-ames hen her inx syd `rave.sat) =. bom.u.ref (~(put by bom.u.ref) inx sat(scry ~)) ..retry-with-ames @@ -4997,9 +4994,8 @@ %+ bind data.hin |= =(cask) ^- rand - ::REVIEW this feels a bit dumb, but the alternative - :: is reconstructing it from ref:den instead, - :: which is also weird in its own ways. + :: retrieve the request from the scry path + :: =+ (need (de-omen path.hin)) =/ =care ;;(care ?@(vis (rsh 3 vis) car.vis)) [[care r.bem q.bem] s.bem cask] From d8dca44bd2a355c93376a8465fe25231c122ffc4 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 23 Feb 2022 15:40:16 -0600 Subject: [PATCH 078/168] clay: refactor request wire construction --- pkg/arvo/sys/vane/clay.hoon | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index e1232032f..5ad22bebc 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -1312,6 +1312,10 @@ :: ++ static-ford-args [ank.dom ~ ~ lat.ran fod.dom] :: + ++ request-wire + |= [kind=@ta =ship =desk index=@ud] + /[kind]/(scot %p ship)/[desk]/(scot %ud index) + :: :: Transfer a request to another ship's clay. :: ++ send-over-ames @@ -1319,7 +1323,7 @@ ^+ +> :: =/ =desk p.riff - =/ =wire /warp-index/(scot %p ship)/(scot %tas desk)/(scot %ud index) + =/ =wire (request-wire %warp-index ship desk index) =/ =path [%question desk (scot %ud index) ~] (emit duct %pass wire %a %plea ship %c path `riff-any`[%1 riff]) :: @@ -1327,7 +1331,7 @@ |= [kind=@ta =duct =ship index=@ud =desk =mood] ^- [timeout=@da _..send-over-scry] =/ =time (add now scry-timeout-time) - =/ =wire /[kind]/(scot %p ship)/[desk]/(scot %ud index) + =/ =wire (request-wire kind ship desk index) =/ =path =, mood [(cat 3 %c care) (scot %p ship) desk (scot case) path] @@ -1337,9 +1341,9 @@ [hen %pass wire %b %wait time] == :: - ++ cancel-scry-timeout + ++ cancel-scry-timeout ::TODO make arg order more consistent |= [kind=@ta =duct =ship index=@ud =desk time=@da] - =/ =wire /[kind]/(scot %p ship)/[desk]/(scot %ud index) + =/ =wire (request-wire kind ship desk index) (emit duct %pass wire %b %rest time) :: ++ foreign-capable @@ -3266,7 +3270,7 @@ :: otherwise, request over ames :: :- ~ - =/ =wire /back-index/(scot %p her)/[syd]/(scot %ud inx) + =/ =wire (request-wire %back-index her syd inx) =/ =path [%backfill syd (scot %ud inx) ~] =/ =fill [%0 syd lobe] (emit hen %pass wire %a %plea her %c path fill) From 6b85022a6110afac7240bdda0e5fae8fdd38b77a Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 23 Feb 2022 15:41:19 -0600 Subject: [PATCH 079/168] clay: properly cancel scry timers and/or requests Use the correct wires when cancelling the scry request and/or its timers. Note that we may produce more %rests and %yawns than strictly necessary, but these no-op cleanly in those cases. --- pkg/arvo/sys/vane/clay.hoon | 41 +++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 5ad22bebc..8b17c6445 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -2960,8 +2960,18 @@ =, mood.rave.sat [(cat 3 %c care) (scot %p her) syd (scot case) path] %- emil - :~ [hen %pass / %a %yawn path] - [hen %pass / %b %rest u.scry.sat] + ::NOTE we don't know exactly which kind of request is exstant at + :: this time. or at least it seems very hard to find out. + :: so instead we simply emit the cancellation moves on both + :: possible wires. one will silently no-op, the other will + :: do what we want. this is ugly, but we should refactor the + :: separate flows eventually anyway. + =/ x=wire (request-wire %warp-index her syd u.nux) + =/ y=wire (request-wire %back-index her syd u.nux) + :~ [hen %pass x %a %yawn path] + [hen %pass y %a %yawn path] + [hen %pass x %b %rest u.scry.sat] + [hen %pass y %b %rest u.scry.sat] == :: :: Handles a request. @@ -2985,12 +2995,31 @@ ..start-request (duce for u.new-sub) :: + :: +retry-with-ames: we tried scrying. now try with ames instead. + :: ++ retry-with-ames - |= inx=@ud + |= [kind=@ta inx=@ud] ^+ ..retry-with-ames ~| [%strange-retry-no-request her syd inx] ?> ?=(^ ref) =/ sat=update-state (~(got by bom.u.ref) inx) + :: clean up scry request & timer + :: + =. ..retry-with-ames + =< ?>(?=(^ ref) .) + ~| [%strange-retry-not-scry her syd inx scry.sat -.rave] + ?> ?=(^ scry.sat) + ?> ?=(%sing -.rave.sat) + =/ =wire (request-wire kind her syd inx) + =/ =path + =, mood.rave.sat + [(cat 3 %c care) (scot %p her) syd (scot case) path] + %- emil + :~ [hen %pass wire %b %rest u.scry.sat] + [hen %pass wire %a %yawn path] + == + :: re-send over ames + :: =. ..retry-with-ames =< ?>(?=(^ ref) .) (send-over-ames hen her inx syd `rave.sat) @@ -5015,7 +5044,7 @@ =^ mos ruf =. sad.ruf (~(put by sad.ruf) her now) =/ den ((de now rof hen ruf) her desk) - abet:(retry-with-ames:den index) + abet:(retry-with-ames:den %warp-index index) [mos ..^$] == :: @@ -5048,7 +5077,7 @@ =^ mos ruf =/ den ((de now rof hen ruf) her desk) ?~ blob - abet:(retry-with-ames:den index) + abet:(retry-with-ames:den %back-index index) abet:abet:(take-backfill:(foreign-update:den index) u.blob) [mos ..^$] :: @@ -5061,7 +5090,7 @@ =^ mos ruf =. sad.ruf (~(put by sad.ruf) her now) =/ den ((de now rof hen ruf) her desk) - abet:(retry-with-ames:den index) + abet:(retry-with-ames:den %back-index index) [mos ..^$] == :: From 22f3e4982313e51184c1d42979b8ff7ea3e5a233 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 23 Feb 2022 16:00:20 -0600 Subject: [PATCH 080/168] ames: add |yawn, fix duct wrangling --- pkg/arvo/gen/hood/yawn.hoon | 8 ++++++++ pkg/arvo/sys/vane/ames.hoon | 29 +++++++++++++++++++++++++---- pkg/arvo/sys/vane/clay.hoon | 17 +++++++++++------ 3 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 pkg/arvo/gen/hood/yawn.hoon diff --git a/pkg/arvo/gen/hood/yawn.hoon b/pkg/arvo/gen/hood/yawn.hoon new file mode 100644 index 000000000..7388de08a --- /dev/null +++ b/pkg/arvo/gen/hood/yawn.hoon @@ -0,0 +1,8 @@ +:- %say +|= [^ [=ship pax=$@(~ [=path ~])] ~] +=/ =path + ?~ pax /cz/(scot %p ship)/kids/1/sys + ?> ?=([@ *] path.pax) + =, pax + [i.path (scot %p ship) t.path] +[%helm-pass %a %yawn path] diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index b88509f0c..575e70f9d 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2555,6 +2555,15 @@ =. keens.scry (put:orm keens.scry keen-id keen-state) ke-abet:ke-start:(ke-abed:keen-core path) :: + :: TODO: fix, only cancel on when no more subscribers + ++ pe-yawn + |= =path + =/ keen-id=@ud (~(got by order.scry) path) + =. order.scry (~(del by order.scry) path) + =. keens.scry +:(del:orm keens.scry keen-id) + ~& yawn/path + pe-core + :: ++ pe-hear |= [=lane =packet] ?> =(sndr-tick.packet (mod life.peer 16)) @@ -2687,8 +2696,15 @@ |= [sig=@ data=$@(~ (cask))] ?> (meri:keys ship life.peer path sig data) ~& got-response/path - :: TODO: notify subscribers - ke-core + =/ listeners ~(tap in listeners.keen) + =/ dat=(unit (cask)) + ?~(data ~ `data) + |- ^+ ke-core + ?~ listeners + ke-core + =. event-core + (emit i.listeners %give %tune path dat) + $(listeners t.listeners) :: ++ ke-first-rcv |= =rawr @@ -2739,6 +2755,7 @@ ~| %frag-mismatch ~| have/num-received ~| need/num-fragments + ~| path/path ?> =(num-fragments num-received) ?> =((lent hav) num-received) (decode-response-msg num-fragments hav) @@ -2854,8 +2871,12 @@ ++ on-yawn |= =path ^+ event-core - =. want.state (~(del ju want.state) path duct) - event-core + =/ omen + ~| [%fine %invalid-namespace-path path] + (need (de-omen path)) + =/ peer-core (pe-abed:fine-peer p.bem.omen) + ?~ peer-core !! + pe-abet:(pe-yawn:u.peer-core path) :: ++ on-bide |= =path diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 6163a6138..599dd69b3 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -361,8 +361,8 @@ :: %utilities :: |% -++ scry-timeout-time ~m1 -++ scry-retry-time ~h1 +++ scry-timeout-time ~s5 +++ scry-retry-time ~s30 :: +sort-by-head: sorts alphabetically using the head of each element :: ++ sort-by-head @@ -1331,6 +1331,7 @@ =/ =path =, mood [(cat 3 %c care) (scot %p ship) desk (scot case) path] + ~& scrying/path^index :- time %- emil :~ [hen %pass wire %a %keen path] @@ -1382,9 +1383,9 @@ :: :ship's remote scry isn't known to be broken, :: or we learned it was broken more than an hour ago, :: - ?: ?& ?=(%sing -.rave) + ?: ?& ?=([%sing %x *] rave) ?| !(~(has by sad) her) - (lth now (add scry-retry-time (~(got by sad) her))) + (gth now (add scry-retry-time (~(got by sad) her))) == == :: send request as remote scry ::TODO can be deduplicated with the below? @@ -3008,8 +3009,11 @@ |= [inx=@ud rut=(unit rand)] ^+ +> ?> ?=(^ ref) + ~& take-foreign/inx =+ ruv=(~(get by bom.u.ref) inx) - ?~ ruv +>.$ + ?~ ruv + ~& %bad-answer + +>.$ =? ..take-foreign-answer ?=(^ scry.u.ruv) =< ?>(?=(^ ref) .) (cancel-scry-timeout %warp-index hen her inx syd u.scry.u.ruv) @@ -3253,7 +3257,7 @@ :: ?: ?& ?=(^ i.need.sat) ?| !(~(has by sad) her) - (lth now (add scry-retry-time (~(got by sad) her))) + (gth now (add scry-retry-time (~(got by sad) her))) == == :: make the request over remote scry :: @@ -4985,6 +4989,7 @@ :: =^ mos ruf =; res=(unit rand) + ~& taking-foreign-answer/=(~ res) =/ den ((de now rof hen ruf) her desk) abet:(take-foreign-answer:den index res) ?: ?=(%boon +<.hin) ;;((unit rand) payload.hin) From 5f5092168f0c2600a6e0a79bccf5b76272d75d62 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 22 Feb 2022 16:03:24 -0600 Subject: [PATCH 081/168] ames: fix sig + data catenation --- pkg/arvo/sys/vane/ames.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 575e70f9d..2ec3d17fd 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -3023,7 +3023,7 @@ =/ sig=@ (full:keys path data) ?~ data [sig]~ %+ rip response-size ::NOTE 1024 bytes - (cat 3 sig (jam data)) ::TODO should include life + (cat 9 sig (jam data)) ::TODO should include life :: sign & packetize the fragments :: %- head From 2adc52e03ae2858f4ad137beb89e8ae0a76d766a Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 20:10:38 +0100 Subject: [PATCH 082/168] clay: retry with ames on empty scry response --- pkg/arvo/sys/vane/clay.hoon | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 599dd69b3..040a85536 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -5039,14 +5039,16 @@ =/ =desk (slav %tas i.t.t.tea) =/ index=@ud (slav %ud i.t.t.t.tea) :: - =/ =blob - ?: ?=(%boon +<.hin) ;;(blob payload.hin) - ?~ data.hin ~|(%now-what !!) ::TODO - [%direct (page-to-lobe u.data.hin) u.data.hin] + =/ blob=(unit blob) + ?: ?=(%boon +<.hin) `;;(blob payload.hin) + ?~ data.hin ~ + `[%direct (page-to-lobe u.data.hin) u.data.hin] :: =^ mos ruf =/ den ((de now rof hen ruf) her desk) - abet:abet:(take-backfill:(foreign-update:den index) blob) + ?~ blob + abet:(retry-with-ames:den index) + abet:abet:(take-backfill:(foreign-update:den index) u.blob) [mos ..^$] :: %wake From cdff1d91fac14d7522a62e05e1b6a0557294947d Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 21:14:52 +0100 Subject: [PATCH 083/168] clay: scry files at aeons, not timestamps Turns out we can simply find the corresponding aeon in the nako. --- pkg/arvo/sys/vane/clay.hoon | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 040a85536..d3e371fad 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -236,7 +236,7 @@ =rave scry=(unit @da) :: if scry, timeout have=(map lobe blob) - need=(list $@(lobe [when=@da =path =lobe])) :: opt deets for scry + need=(list $@(lobe [=aeon =path =lobe])) :: opt deets for scry nako=(qeu (unit nako)) busy=_| == @@ -3166,16 +3166,14 @@ ++ missing-blobs |= =nako =| miss=(set lobe) - ^- (list [@da path lobe]) - ::REVIEW should this get sorted so that we prefer getting files - :: from the latest commit, if there are duplicates? + ^- (list [aeon path lobe]) =/ yakis ~(tap in lar.nako) - |- ^- (list [@da path lobe]) + |- ^- (list [aeon path lobe]) =* yaki-loop $ ?~ yakis ~ =/ lobes=(list [=path =lobe]) ~(tap by q.i.yakis) - |- ^- (list [@da path lobe]) + |- ^- (list [aeon path lobe]) =* blob-loop $ ?~ lobes yaki-loop(yakis t.yakis) @@ -3184,8 +3182,16 @@ (~(has in miss) lobe) == blob-loop(lobes t.lobes) - :- [t.i.yakis i.lobes] - blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) + =; =aeon + :- [aeon i.lobes] + blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) + :: find the aeon corresponding to the commit containing this lobe. + :: we unfortunately do not have a reverse lookup map. + :: + =/ l=(list [a=aeon t=tako]) ~(tap by gar.nako) + |- + ?~ l ~|([%missing-aeon-for-tako her syd `@uw`tako] !!) + ?:(=(r.i.yakis t.i.l) a.i.l $(l t.l)) :: :: Receive backfill response :: @@ -3262,7 +3268,7 @@ :: make the request over remote scry :: =/ =mood - [%x da+when path]:i.need.sat + [%x ud+aeon path]:i.need.sat [`- +]:(send-over-scry %back-index hen her inx syd mood) :: otherwise, request over ames :: From aaa759268e18e7ce986bb8999897eb280bb9e975 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 17 Feb 2022 21:17:45 +0100 Subject: [PATCH 084/168] clay: clean up REVIEW comments --- pkg/arvo/sys/vane/clay.hoon | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index d3e371fad..0d42e09ab 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -2982,7 +2982,6 @@ ..start-request (duce for u.new-sub) :: - ::TODO should this try-fill-sub or w/e in case its now in our cache? ++ retry-with-ames |= inx=@ud ^+ ..retry-with-ames @@ -2991,8 +2990,6 @@ =/ sat=update-state (~(got by bom.u.ref) inx) =. ..retry-with-ames =< ?>(?=(^ ref) .) - ::REVIEW isn't this a bit much, if we're already partway through? - :: do we not want to just call into +work in that case? (send-over-ames hen her inx syd `rave.sat) =. bom.u.ref (~(put by bom.u.ref) inx sat(scry ~)) ..retry-with-ames @@ -5002,9 +4999,8 @@ %+ bind data.hin |= =(cask) ^- rand - ::REVIEW this feels a bit dumb, but the alternative - :: is reconstructing it from ref:den instead, - :: which is also weird in its own ways. + :: retrieve the request from the scry path + :: =+ (need (de-omen path.hin)) =/ =care ;;(care ?@(vis (rsh 3 vis) car.vis)) [[care r.bem q.bem] s.bem cask] From 4be4e9a7a0ef7fa7eef91af85e8fedede72e4088 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 23 Feb 2022 12:31:56 -0600 Subject: [PATCH 085/168] ames: fix keen ducts --- pkg/arvo/sys/vane/ames.hoon | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 2ec3d17fd..7bb0b2de7 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2546,7 +2546,7 @@ ++ pe-keen |= =path ?: (~(has by order.scry) path) - pe-core + ke-abet:ke-sub:(ke-abed:keen-core path) =/ keen-id=@ud seq.scry =. seq.scry +(seq.scry) =. order.scry @@ -2680,8 +2680,8 @@ [`want %.n found ke-core] :: ++ ke-start - ~| tried-to-start-request-already-in-progress/path ~& start/now + =. ke-core ke-sub ?> =(num-fragments.keen 0) =/ fra=@ 1 =/ req (ke-encode-req fra) @@ -2742,6 +2742,10 @@ |= [fra=@ud =hoot] (ke-emit hoot) :: + ++ ke-sub + =. listeners.keen (~(put in listeners.keen) duct) + ke-core + :: ++ ke-emit |= =hoot ^+ ke-core From 5baa1b8318751255ca288f5033be5a3aeae36089 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 23 Feb 2022 12:58:44 -0600 Subject: [PATCH 086/168] ames: add fast retransmit --- pkg/arvo/sys/vane/ames.hoon | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 7bb0b2de7..854ba6938 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2788,9 +2788,7 @@ (ke-on-ack fra) :: ?. found - :: discard changes - ~& dupe-ack/fra - og + (ke-fast-retransmit:og fra) =/ =have [fra rawr] =. hav.keen `(list ^have)`[have hav.keen] @@ -2799,6 +2797,23 @@ (ke-done [sig dat]:ke-decode-full) ke-continue :: + ++ ke-fast-retransmit + |= fra=@ud + =; [cor=_ke-core wants=(pha want)] + cor(wan.keen wants) + %^ (dip-left:ke-deq ,cor=_ke-core) wan.keen + ke-core + |= [cor=_ke-core =want] + ^- [(unit ^want) stop=? cor=_ke-core] + ?. (lte fra.want fra) + [`want & cor] + ?: (gth (next-expiry:ke-gauge:cor +>.want) now) + [`want & cor] + =. last-sent.want now + =. cor + (ke-emit:cor hoot.want) + [`want | cor] + :: ++ ke-gauge =* bug bug.ames-state (make-pump-gauge now metrics.keen ship bug) From 479e060e32a04bcf1e6b93b613693f2c20902ab3 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 23 Feb 2022 13:17:53 -0600 Subject: [PATCH 087/168] ames: add +load for remote scry --- pkg/arvo/sys/vane/ames.hoon | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 854ba6938..4d71027fd 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -641,8 +641,24 @@ == +$ ship-state-5 $% [%alien alien-agenda-5] - [%known peer-state] + [%known peer-state-5] == +:: ++$ peer-state-5 + $: $: =symmetric-key + =life + =public-key + sponsor=ship + == + route=(unit [direct=? =lane]) + =qos + =ossuary + snd=(map bone message-pump-state) + rcv=(map bone message-sink-state) + nax=(set [=bone =message-num]) + heeds=(set duct) + == +:: +$ alien-agenda-5 $: messages=(list [=duct =plea]) packets=(set =blob) @@ -1109,17 +1125,20 @@ ++ state-5-to-6 |= old=ames-state-5 ^- ^ames-state - %= old - peers (~(run by peers.old) ship-state-5-to-6) - bug [bug.old *fine-state] - crypto-core (nol:nu:crub:crypto sec:ex:crypto-core.old) + :* peers=(~(run by peers.old) ship-state-5-to-6) + unix-duct.old + life.old + crypto-core=(nol:nu:crub:crypto sec:ex:crypto-core.old) + bug.old + *fine-state == :: ++ ship-state-5-to-6 |= old=ship-state-5 ^- ship-state - ?. ?=(%alien -.old) old - old(heeds [heeds.old ~]) + ?: ?=(%alien -.old) + old(heeds [heeds.old ~]) + old(heeds [heeds.old *scry-state]) :: ++ state-4-to-5 |= ames-state=ames-state-5 From c16aaae2010e1492beed40ea3338d7bcce98b900 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 23 Feb 2022 15:10:11 -0600 Subject: [PATCH 088/168] ames: correct behaviour for %yawn --- pkg/arvo/sys/vane/ames.hoon | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 4d71027fd..6a6120117 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2574,14 +2574,9 @@ =. keens.scry (put:orm keens.scry keen-id keen-state) ke-abet:ke-start:(ke-abed:keen-core path) :: - :: TODO: fix, only cancel on when no more subscribers ++ pe-yawn |= =path - =/ keen-id=@ud (~(got by order.scry) path) - =. order.scry (~(del by order.scry) path) - =. keens.scry +:(del:orm keens.scry keen-id) - ~& yawn/path - pe-core + ke-abet:ke-unsub:(ke-abed:keen-core path) :: ++ pe-hear |= [=lane =packet] @@ -2620,7 +2615,10 @@ =, keen :: num-fragments is 0 when unknown (i.e. no response :: yet) - &(!=(0 num-fragments) =(num-fragments num-received)) + :: if no-one is listening, kill request + ?| =(~ listeners.keen) + &(!=(0 num-fragments) =(num-fragments num-received)) + == ?: gone ke-abet-gone =. ke-core ke-set-wake @@ -2764,6 +2762,11 @@ ++ ke-sub =. listeners.keen (~(put in listeners.keen) duct) ke-core + :: scry is autocancelled in +ke-abet if no more listeners + :: + ++ ke-unsub + =. listeners.keen (~(del in listeners.keen) duct) + ke-core :: ++ ke-emit |= =hoot @@ -2913,7 +2916,8 @@ ~| [%fine %invalid-namespace-path path] (need (de-omen path)) =/ peer-core (pe-abed:fine-peer p.bem.omen) - ?~ peer-core !! + ?~ peer-core + ~|(%no-ship-for-yawn !!) pe-abet:(pe-yawn:u.peer-core path) :: ++ on-bide From f1c24c07dd899e44e4b76e6312378a5ac758e016 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Wed, 23 Feb 2022 15:52:05 -0600 Subject: [PATCH 089/168] ames: refactor to remove unused state --- bin/solid.pill | 4 +- pkg/arvo/sys/lull.hoon | 2 +- pkg/arvo/sys/vane/ames.hoon | 123 +++++++----------------------------- 3 files changed, 27 insertions(+), 102 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index 062269426..241cf5bd0 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a2dfd4f7850be3fd83cf3b7014cfd43aaca5ee4d12fd5ca8ec74a0801049658 -size 24897862 +oid sha256:b570e46a0aa4cce20b341835e62a7f1c2d8a0fe73b1e170570b91988199c8351 +size 23402668 diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 90566d3e8..2ede9374d 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1222,7 +1222,7 @@ $: messages=(list [=duct =plea]) packets=(set =blob) heeds=(set duct) - keens=(set path) + keens=(jug path duct) == :: $peer-state: state for a peer with known life and keys :: diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 6a6120117..da626c50a 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -629,7 +629,6 @@ =life crypto-core=acru:ames =bug - =fine-state == :: +$ ames-state-5 @@ -687,18 +686,7 @@ ++ com |~(a=pass ^?(..nu)) -- -- -:: $fine-state: remote scry subsystem state :: -:: hear: awaiting existence -:: want: awaiting response -:: part: partial responses -:: -+$ fine-state - $: hear=(jug path duct) - want=(jug path duct) - part=(map path partial-fine) - ::TODO re-send request timers? - == +$ twit :: signed request $: signature=@ peep @@ -1130,7 +1118,6 @@ life.old crypto-core=(nol:nu:crub:crypto sec:ex:crypto-core.old) bug.old - *fine-state == :: ++ ship-state-5-to-6 @@ -1881,9 +1868,8 @@ :: apply remote scry requests :: =. event-core - %+ roll ~(tap in keens.todos) - |= [=path core=_event-core] - (send-request:fine:core ship path 1) + =< pe-abet + (pe-meet-alien:(need (pe-abed:fine-peer:fine ship)) keens.todos) :: event-core(duct original-duct) -- @@ -2541,7 +2527,6 @@ -- :: ++ fine - =* state fine-state.ames-state =< |% ++ fine-peer |_ $: =ship @@ -2563,20 +2548,30 @@ event-core ++ pe-lane (get-lane ship) ++ pe-keen - |= =path + |= [=path =^duct] ?: (~(has by order.scry) path) - ke-abet:ke-sub:(ke-abed:keen-core path) + ke-abet:(ke-sub:(ke-abed:keen-core path) duct) =/ keen-id=@ud seq.scry =. seq.scry +(seq.scry) =. order.scry (~(put by order.scry) path keen-id) =| =keen-state =. keens.scry (put:orm keens.scry keen-id keen-state) - ke-abet:ke-start:(ke-abed:keen-core path) + ke-abet:(ke-start:(ke-abed:keen-core path) duct) + :: + ++ pe-meet-alien + |= agenda=(jug path ^duct) + %+ roll ~(tap by agenda) + |= [[=path ducts=(set ^duct)] cor=_pe-core] + ^+ cor + %+ roll ~(tap in ducts) + |= [=^duct c=_cor] + ^+ c + (pe-keen:c path duct) :: ++ pe-yawn |= =path - ke-abet:ke-unsub:(ke-abed:keen-core path) + ke-abet:(ke-unsub:(ke-abed:keen-core path) duct) :: ++ pe-hear |= [=lane =packet] @@ -2697,8 +2692,9 @@ [`want %.n found ke-core] :: ++ ke-start + |= =^duct ~& start/now - =. ke-core ke-sub + =. ke-core (ke-sub duct) ?> =(num-fragments.keen 0) =/ fra=@ 1 =/ req (ke-encode-req fra) @@ -2760,11 +2756,13 @@ (ke-emit hoot) :: ++ ke-sub + |= =^duct =. listeners.keen (~(put in listeners.keen) duct) ke-core :: scry is autocancelled in +ke-abet if no more listeners :: ++ ke-unsub + |= =^duct =. listeners.keen (~(del in listeners.keen) duct) ke-core :: @@ -2904,10 +2902,10 @@ (need (de-omen path)) =* ship p.bem.omen =/ peer-core (pe-abed:fine-peer ship) - ?^ peer-core pe-abet:(pe-keen:u.peer-core path) + ?^ peer-core pe-abet:(pe-keen:u.peer-core path duct) %+ enqueue-alien-todo ship |= todos=alien-agenda - todos(keens (~(put in keens.todos) path)) + todos(keens (~(put ju keens.todos) path duct)) :: ++ on-yawn |= =path @@ -2923,7 +2921,6 @@ ++ on-bide |= =path ^+ event-core - =. hear.state (~(put ju hear.state) path duct) :: TODO: other vanes? (bide-clay path) :: @@ -2950,14 +2947,10 @@ =/ cas=(unit (cask)) ?~ riot ~ `[p q.q]:r.u.riot - =/ wanted (~(get ju want.state) pax) - =. want.state (~(del by want.state) pax) =/ =song (encode-response pax (fall cas ~)) - %- emil - %+ turn [unix-duct.ames-state ~(tap in wanted)] - |= d=^duct - [d %give %howl pax song] + %- emit + [unix-duct.ames-state %give %howl pax song] :: ++ on-take-wake |= [=wire error=(unit tang)] @@ -3141,74 +3134,6 @@ =/ =peer-state (got-peer-state ship) lane:(need route.peer-state) - :: - ++ send-request - |= [=ship =path num=@ud] - ^+ event-core - =/ =lane:ames (get-lane ship) - =/ =hoot (encode-request ship path 1) - %- emit - [unix-duct.ames-state %give %send lane `@ux`hoot] - :: - ++ process-response - |= [[from=ship =life] =path sig=@ data=$@(~ (cask))] - ^+ event-core - ?> (meri:keys from life path sig data) - ~& got-response/path - =. event-core - %- emil - %+ turn ~(tap in (~(get ju want.state) path)) - (late [%give %tune path ?@(data data `data)]) - =. want.state (~(del by want.state) path) - =. part.state (~(del by part.state) path) - event-core - :: - ++ handle-response - |= [[from=ship =life =lane:ames] =peep =rawr] - ^+ event-core - ?: =(0 siz.rawr) - ?> =(~ dat.rawr) - (process-response [from life] path.peep sig.rawr ~) - ?. (~(has by part.state) path.peep) - :: we did not initiate this request, or it's been cancelled - :: - !! - =/ partial=partial-fine - (~(got by part.state) path.peep) - =. partial - ?: (~(has by fragments.partial) num.peep) - partial - =, partial - :+ ~| [%fine %response-size-changed have=num-fragments new=siz.rawr] - ?> |(=(0 num-fragments) =(num-fragments siz.rawr)) - siz.rawr - +(num-received) - :: ?> (veri:keys from life path.peep num.peep dat.rawr) - (~(put by fragments) num.peep [wid dat]:rawr) - :: - ?: =(num-fragments num-received):partial - :: we have all the parts now, construct the full response - :: - =| =roar - (process-response [from life] path.peep [sig dat]:roar) - :: otherwise, store the part, and send out the next request - :: - =. part.state (~(put by part.state) path.peep partial) - =/ next-num=@ud - =/ next=@ud +(num.peep) - :: we should receive responses in order, but in case we don't... - :: - |- - ?. (~(has by fragments.partial) next) next - $(next +((mod next num-fragments.partial))) - :: - =/ =hoot (encode-request from path.peep next-num) - ::TODO ask amsden, should we shotgun? we can tweak this - :: for now (mvp) though, stay 1-to-1 - ::TODO update lane in ames state - ::TODO is reusing the lane fine? - %- emit - [unix-duct.ames-state %give %send lane `@ux`hoot] -- -- :: +make-message-pump: constructor for |message-pump From 801ef4b89ec32a340ec2fb4d745f8bf01cd33475 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 24 Feb 2022 12:02:21 -0600 Subject: [PATCH 090/168] ames: do not crash on invalid path --- pkg/urbit/vere/io/ames.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 00e86d25f..15735aa42 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -1563,10 +1563,18 @@ static void _fine_hear_request(u3_ames* sam_u, c3_assert( c3y == _fine_sift_requ(&hed_u, &req_u, len_w, hun_y)); - u3_noun pat = u3do("stab", u3i_string(req_u.pat_c)); - u3_noun key = u3nc(u3k(pat), u3i_word(req_u.fra_w)); + u3_noun rul = u3v_wish("stap"); + u3_noun pat = u3dc("rush", u3i_string(req_u.pat_c), rul); + if ( u3_nul == pat ) { + u3l_log("bad request\n"); - u3_weak cac = u3h_git(sam_u->fin_s.sac_p, key); + u3z(pat); + return; + } + + u3_noun key = u3nc(u3k(u3t(pat)), u3i_word(req_u.fra_w)); + + u3_weak cac = u3h_git(sam_u->fin_s.sac_p, key); u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); @@ -1587,7 +1595,7 @@ static void _fine_hear_request(u3_ames* sam_u, // cache miss u3_noun pax = u3nt(u3i_string("fine"), u3i_string("message"), - u3k(pat)); + u3k(u3t(pat))); u3_pier_peek_last(sam_u->car_u.pir_u, u3_nul, c3__ax, u3_nul, pax, pac_u, _fine_pack_scry_cb); @@ -1597,7 +1605,8 @@ static void _fine_hear_request(u3_ames* sam_u, _fine_send(pac_u); } - u3z(pat); + //u3z(pat); + //u3z(rul); } From b4da246f01870e475c0acdea18cedd11a320d66b Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Thu, 24 Feb 2022 12:03:07 -0600 Subject: [PATCH 091/168] strandio: add +keen gate --- pkg/arvo/app/dbug.hoon | 2 +- pkg/arvo/sys/vane/ames.hoon | 1 + pkg/arvo/ted/keen.hoon | 17 +++++++++++++---- pkg/base-dev/lib/strandio.hoon | 25 +++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/app/dbug.hoon b/pkg/arvo/app/dbug.hoon index 8fb67e60b..b3825509f 100644 --- a/pkg/arvo/app/dbug.hoon +++ b/pkg/arvo/app/dbug.hoon @@ -524,7 +524,7 @@ :~ 'messages'^(numb (lent messages)) 'packets'^(numb ~(wyt in packets)) 'heeds'^(set-array heeds from-duct) - 'keens'^(set-array keens path) + 'keens'^(set-array ~(key by keens) path) == :: :: json for known peer is structured to closely match the peer-state type. diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index da626c50a..b4fbaa56c 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2707,6 +2707,7 @@ :: ++ ke-done |= [sig=@ data=$@(~ (cask))] + ~& path ?> (meri:keys ship life.peer path sig data) ~& got-response/path =/ listeners ~(tap in listeners.keen) diff --git a/pkg/arvo/ted/keen.hoon b/pkg/arvo/ted/keen.hoon index 425817e2c..e1e017d0d 100644 --- a/pkg/arvo/ted/keen.hoon +++ b/pkg/arvo/ted/keen.hoon @@ -6,7 +6,16 @@ =/ m (strand ,vase) ^- form:m =+ !<([~ arg=path] arg) -;< ~ bind:m (send-raw-card:strandio %pass / %arvo %a %keen arg) -;< [wire sign=sign-arvo] bind:m take-sign-arvo:strandio -?> ?=(%tune +<.sign) -(pure:m !>(data.sign)) +;< dat=(unit (cask)) bind:m + (keen:strandio arg) +?~ dat + (pure:m !>(~)) +;< =bowl:spider bind:m get-bowl:strandio +=+ .^ =dais:clay %cb + /(scot %p our.bowl)/[q.byk.bowl]/(scot %da now.bowl)/[p.u.dat] + == +=/ res (mule |.((vale.dais q.u.dat))) +?: ?=(%| -.res) + ~|(%keen-mark-fail (mean leaf+"-keen: ames vale fail {}" p.res)) +(pure:m p.res) + diff --git a/pkg/base-dev/lib/strandio.hoon b/pkg/base-dev/lib/strandio.hoon index a83d5ae0e..a7f7786f9 100644 --- a/pkg/base-dev/lib/strandio.hoon +++ b/pkg/base-dev/lib/strandio.hoon @@ -180,6 +180,21 @@ `[%done ~] `[%fail %timer-error u.error.sign-arvo.u.in.tin] == +++ take-tune + |= =wire + =/ m (strand ,~) + ^- form:m + |= tin=strand-input:strand + ?+ in.tin `[%skip ~] + ~ `[%wait ~] + [~ %agent * %poke-ack *] + ?. =(wire wire.u.in.tin) + `[%skip ~] + ?~ p.sign.u.in.tin + `[%done ~] + `[%fail %poke-fail u.p.sign.u.in.tin] + == + :: ++ take-poke-ack |= =wire @@ -315,6 +330,16 @@ ;< ~ bind:m (send-wait until) (take-wake `until) :: +++ keen + |= =path + =/ m (strand ,(unit (cask))) + ^- form:m + =/ =card:agent:gall [%pass /keen %arvo %a %keen path] + ;< ~ bind:m (send-raw-card card) + ;< [wire sign=sign-arvo] bind:m take-sign-arvo + ?> ?=(%tune +<.sign) + (pure:m data.sign) +:: ++ sleep |= for=@dr =/ m (strand ,~) From e621744169ca1372c6e1808224807ea37dd57321 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 8 Mar 2022 14:49:47 -0600 Subject: [PATCH 092/168] zuse: add +balk core for remote scry path format +balk defines a datastructure for a parsed remote scry path format in addition to conversion gates to and from paths. The new scry path format is /~ship/rift/life/vane/care/spur. Note that desk no longer appears in the scry path format and should instead be encoded as the first item of the spur. --- pkg/arvo/sys/zuse.hoon | 53 +++++++++++++++++++++++++++++++ pkg/arvo/tests/sys/zuse/balk.hoon | 17 ++++++++++ 2 files changed, 70 insertions(+) create mode 100644 pkg/arvo/tests/sys/zuse/balk.hoon diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index bea070310..d60780fc2 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -5515,4 +5515,57 @@ ?. ?=(%soft -.wrapped) wrapped ;;(task +.wrapped) +:: +:: +++ balk + =< bulk + |% + +$ bulk + $: [her=ship rif=rift lyf=life] + [van=@ta car=@ta cas=case] + spr=spur + == + :: + ++ de-path-soft + |= [=rift =life =path] + ^- (unit bulk) + :: [care ship desk case path] + ?. ?=([@ @ @ @ *] path) + ~ + =/ van=@ta (end 3 i.path) + =/ car=@ta (rsh 3 i.path) + ?~ her=(slaw %p i.t.path) + ~ + ?~ cas=(de-case i.t.t.t.path) + ~ + :- ~ + :* [u.her rift life] + [van car u.cas] + [i.t.t.path t.t.t.t.path] + == + :: + ++ de-path + |= [=rift =life =path] + ^- bulk + (need (de-path-soft +<)) + :: + ++ en-path + |= =bulk + ^- path + ?> ?=([@ *] spr.bulk) + :* (cat 3 van.bulk car.bulk) + (scot %p her.bulk) + i.spr.bulk + (scot cas.bulk) + t.spr.bulk + == + :: + ++ en-roof + |= =bulk + ^- (unit [vis=view bem=beam]) + ?. ?=(^ spr.bulk) ~ + =/ bem=beam [[her i.spr cas] t.spr]:bulk + =+ vis=(cat 3 van.bulk car.bulk) + `[vis bem] + -- -- diff --git a/pkg/arvo/tests/sys/zuse/balk.hoon b/pkg/arvo/tests/sys/zuse/balk.hoon new file mode 100644 index 000000000..7942b81db --- /dev/null +++ b/pkg/arvo/tests/sys/zuse/balk.hoon @@ -0,0 +1,17 @@ +/+ *test +|% +++ hastuc-dibtux [~hastuc-dibtux 15 22] +++ clay-x [%c %x %ud 3] +++ test-en-path + %+ expect-eq + !>(`path`/cx/~hastuc-dibtux/base/3/sys/hoon/hoon) + !> %- en-path:balk + [hastuc-dibtux clay-x /base/sys/hoon/hoon] +++ test-de-path + =/ bal=balk + (de-path:balk 15 22 /cx/~hastuc-dibtux/base/3/sys/hoon/hoon) + %+ expect-eq !>(bal) + !> ^- balk + [hastuc-dibtux clay-x /base/sys/hoon/hoon] + +-- From ab116653e866de4933d7eab05c116740365691cc Mon Sep 17 00:00:00 2001 From: yosoyubik Date: Tue, 22 Feb 2022 16:04:42 +0100 Subject: [PATCH 093/168] wip fix dangling bone --- pkg/arvo/app/dbug.hoon | 4 + pkg/arvo/sys/lull.hoon | 9 +- pkg/arvo/sys/vane/ames.hoon | 317 +++++++++++++++++++++++++++++------- 3 files changed, 270 insertions(+), 60 deletions(-) diff --git a/pkg/arvo/app/dbug.hoon b/pkg/arvo/app/dbug.hoon index b5c4da98c..f0dc3c810 100644 --- a/pkg/arvo/app/dbug.hoon +++ b/pkg/arvo/app/dbug.hoon @@ -530,6 +530,7 @@ :: where an index is specified, the array is generally sorted by those. :: :: { life: 123, + :: rift: 0, :: route: { direct: true, lane: 'something' }, :: qos: { kind: 'status', last-contact: 123456 }, // ms timestamp :: flows: { forward: [snd, rcv, ...], backward: [snd, rcv, ...] } @@ -590,6 +591,9 @@ |= peer-state %- pairs :~ 'life'^(numb life) + :: TODO: needs to be updated in /pkg/interface/dbug + :: + 'rift'^(numb rift) :: :- 'route' %+ maybe route diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index c9f9fb10a..051419f63 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -59,7 +59,7 @@ [r=@uxD g=@uxD b=@uxD] :: 24bit true color +$ turf (list @t) :: domain, tld first :: :::: -:::: ++ethereum-types :: eth surs for jael +:::: ++ethereum-types :: eth surs for jael :: :::: ++ ethereum-types |% @@ -73,7 +73,7 @@ ++ events (set event-id) -- :: :::: -:::: ++azimuth-types :: az surs for jael +:::: ++azimuth-types :: az surs for jael :: :::: ++ azimuth-types =, ethereum-types @@ -153,7 +153,7 @@ [%plea =ship =plea:ames] == :: :::: -:::: ++http :: +:::: ++http :: :: :::: :: http: shared representations of http concepts :: @@ -340,7 +340,7 @@ == -- :: :::: -:::: ++ames :: (1a) network +:::: ++ames :: (1a) network :: :::: ++ ames ^? |% @@ -513,6 +513,7 @@ +$ peer-state $: $: =symmetric-key =life + =rift =public-key sponsor=ship == diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 6a3f8e7e4..ad692a71c 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -114,9 +114,9 @@ ^+ same ?. verb same - ?. => [ship=ship ships=ships in=in] - ~+ |(=(~ ships) (~(has in ships) ship)) - same + :: ?. => [ship=ship ships=ships in=in] + :: ~+ |(=(~ ships) (~(has in ships) ship)) + :: same (slog leaf/"ames: {(scow %p ship)}: {(print)}" ~) :: +qos-update-text: notice text for if connection state changes :: @@ -196,22 +196,40 @@ :+ (add 4 next-bone.ossuary) (~(put by by-duct.ossuary) duct next-bone.ossuary) (~(put by by-bone.ossuary) next-bone.ossuary duct) -:: +make-bone-wire: encode ship and bone in wire for sending to vane +:: +make-bone-wire: encode ship, rift and bone in wire for sending to vane :: ++ make-bone-wire - |= [her=ship =bone] + |= [her=ship =rift =bone] ^- wire :: - /bone/(scot %p her)/(scot %ud bone) -:: +parse-bone-wire: decode ship and bone from wire from local vane + /bone/(scot %p her)/(scot %ud rift)/(scot %ud bone) +:: +parse-bone-wire: decode ship, bone and rift from wire from local vane :: ++ parse-bone-wire |= =wire - ^- [her=ship =bone] + ^- %- unit + $% [%new her=ship =rift =bone] + [%old her=ship =bone] + == + ?. ?| ?=([%bone @ @ @ ~] wire) + ?=([%bone @ @ ~] wire) + == + :: ignore malformed wires? + :: + ~& >>> malformed-wire+wire + ~ + ?+ wire ~ + [%bone @ @ ~] + ~& >> old-wire+wire + `[%old `@p`(slav %p i.t.wire) `@ud`(slav %ud i.t.t.wire)] :: - ~| %ames-wire-bone^wire - ?> ?=([%bone @ @ ~] wire) - [`@p`(slav %p i.t.wire) `@ud`(slav %ud i.t.t.wire)] + [%bone @ @ @ ~] + %- some + :^ %new + `@p`(slav %p i.t.wire) + `@ud`(slav %ud i.t.t.wire) + `@ud`(slav %ud i.t.t.t.wire) + == :: +make-pump-timer-wire: construct wire for |packet-pump timer :: ++ make-pump-timer-wire @@ -397,6 +415,8 @@ :: ++ encode-shut-packet ~/ %encode-shut-packet + :: TODO add rift to signed messages to prevent replay attacks? + :: |= $: =shut-packet =symmetric-key sndr=ship @@ -502,6 +522,7 @@ :: $: =symmetric-key =her=life + =her=rift =her=public-key her-sponsor=ship == == @@ -529,6 +550,8 @@ :: This data structure gets signed and jammed to form the .contents :: field of a $packet. :: +:: TODO add rift to prevent replay attacks +:: +$ open-packet $: =public-key sndr=ship @@ -728,6 +751,8 @@ :: =< =* adult-gate . =| queued-events=(qeu queued-event) + =| larval-bit=_| + =| cached-state=* :: |= [now=@da eny=@ rof=roof] =* larval-gate . @@ -736,15 +761,37 @@ :: +call: handle request $task :: ++ call + => |% + +$ old-state ames-state-4-5:load:adult-core + -- |= [=duct dud=(unit goof) wrapped-task=(hobo task)] + ~& call-larva+duct :: =/ =task ((harden task) wrapped-task) + ~& task+task :: :: reject larval error notifications :: ?^ dud ~|(%ames-larval-call-dud (mean tang.u.dud)) :: + ~& cach+?=([%5 *] cached-state) + ~& queu+?=(~ queued-events) + =/ from-adult=? + ?& ?=([%5 *] cached-state) + ?=(~ queued-events) + :: ?=(^ unix-duct:;;(old-state +.cached-state)) + == + =? ames-state.adult-gate from-adult + ~& "state update to 6" + (state-5-to-6:load:adult-core ;;(old-state +.cached-state)) + ::=? larval-bit from-adult %.y + :: + ::?: &(larval-bit ?=(~ queued-events)) + ?: from-adult + =. cached-state ~ + ~> %slog.1^leaf/"ames: metamorphosis reload" + [~ adult-gate] :: %born: set .unix-duct and start draining .queued-events :: ?: ?=(%born -.task) @@ -829,24 +876,34 @@ :: lifecycle arms; mostly pass-throughs to the contained adult ames :: ++ scry scry:adult-core - ++ stay [%5 %larva queued-events ames-state.adult-gate] + ++ stay [%6 %larva queued-events ames-state.adult-gate] ++ load + => |% + +$ old-state ames-state-4-5:load:adult-core + -- |= $= old $% $: %4 $% $: %larva events=(qeu queued-event) - state=_ames-state.adult-gate + state=old-state == - [%adult state=_ames-state.adult-gate] + [%adult state=old-state] == == $: %5 + $% $: %larva + events=(qeu queued-event) + state=old-state + == + [%adult state=old-state] + == == + $: %6 $% $: %larva events=(qeu queued-event) state=_ames-state.adult-gate == [%adult state=_ames-state.adult-gate] - == == - == + == == == + ~& %larval-state-loaded ?- old [%4 %adult *] (load:adult-core %4 state.old) :: @@ -856,13 +913,26 @@ =. adult-gate (load:adult-core %4 state.old) larval-gate :: - [%5 %adult *] (load:adult-core %5 state.old) + [%5 %adult *] + ~& [%5 %adult unix-duct.state.old] + =. cached-state [%5 state.old] + ~> %slog.1^leaf/"ames: larva: reload" + larval-gate :: [%5 %larva *] ~> %slog.1^leaf/"ames: larva: load" =. queued-events events.old =. adult-gate (load:adult-core %5 state.old) larval-gate + :: + [%6 %adult *] (load:adult-core %6 state.old) + :: + [%6 %larva *] + ~& larva+-.old + ~> %slog.1^leaf/"ames: larva: load" + =. queued-events events.old + =. adult-gate (load:adult-core %6 state.old) + larval-gate == -- :: adult ames, after metamorphosis from larva @@ -934,27 +1004,57 @@ [moves ames-gate] :: +stay: extract state before reload :: -++ stay [%5 %adult ames-state] +++ stay [%6 %adult ames-state] :: +load: load in old state after reload :: ++ load - |= $= old-state - $% [%4 ^ames-state] - [%5 ^ames-state] - == - |^ - ^+ ames-gate - =? old-state ?=(%4 -.old-state) %5^(state-4-to-5 +.old-state) + =< |= $= old-state + $% [%4 ames-state-4-5] + [%5 ames-state-4-5] + [%6 ^ames-state] + == + ^+ ames-gate + ~& %load-adult + =? old-state ?=(%4 -.old-state) %5^(state-4-to-5 +.old-state) + :: =? old-state ?=(%5 -.old-state) %6^(state-5-to-6 +.old-state) + :: + ?> ?=(%6 -.old-state) + ames-gate(ames-state +.old-state) + |% + +$ ames-state-4-5 + $: peers=(map ship ship-state-4-5) + =unix=duct + =life + crypto-core=acru:ames + =bug + == :: - ?> ?=(%5 -.old-state) - ames-gate(ames-state +.old-state) + +$ ship-state-4-5 + $% [%alien alien-agenda] + [%known peer-state-4-5] + == + :: + +$ peer-state-4-5 + $: $: =symmetric-key + =life + =public-key + sponsor=ship + == + route=(unit [direct=? =lane]) + =qos + =ossuary + snd=(map bone message-pump-state) + rcv=(map bone message-sink-state) + nax=(set [=bone =message-num]) + heeds=(set duct) + == :: ++ state-4-to-5 - |= =^ames-state - ^- ^^ames-state + |= ames-state=ames-state-4-5 + ^- ames-state-4-5 =. peers.ames-state %- ~(run by peers.ames-state) - |= =ship-state + |= ship-state=ship-state-4-5 ?. ?=(%known -.ship-state) ship-state =. snd.ship-state @@ -965,6 +1065,29 @@ message-pump-state ship-state ames-state + :: + ++ state-5-to-6 + |= ames-state=ames-state-4-5 + ^- ^^ames-state + :_ +.ames-state + %- ~(rut by peers.ames-state) + |= [=ship ship-state=ship-state-4-5] + ^- ^ship-state + ?. ?=(%known -.ship-state) + ship-state + =/ peer-state=peer-state-4-5 +.ship-state + =| =rift + =/ scry=(unit (unit cage)) + (rof ~ %j `beam`[[our %rift %da now] /(scot %p ship)]) + =? rift ?=([~ ~ ^] scry) + ;;(@ud q.q:u.u.scry) + ~& ship^rift + =/ =^peer-state + :_ +.peer-state + =, -.peer-state + [symmetric-key life rift public-key sponsor] + ^- ^ship-state + [-.ship-state peer-state] -- :: +scry: dereference namespace :: @@ -1105,31 +1228,68 @@ ^+ event-core :: relay the vane ack to the foreign peer :: - =+ ^- [her=ship =bone] (parse-bone-wire wire) - :: + ?~ parsed=(parse-bone-wire wire) + :: no-op? + :: + ~& >>> "error parsing wire" + event-core + ?> ?=([@ her=ship *] u.parsed) + =* her her.u.parsed =/ =peer-state (got-peer-state her) - =/ =channel [[our her] now channel-state -.peer-state] + =/ =channel + :^ [our her] now channel-state + =, -.peer-state + [symmetric-key life rift public-key sponsor] =/ peer-core (make-peer-core peer-state channel) + |^ + ?- u.parsed + [%old *] + :: XX ignore events from old wire instead of sending nack? + :: + :: event-core + (send-nack bone.u.parsed [%old-wire ~[(spat wire)]]) + :: + [%new *] + ?: (lth rift.u.parsed rift.peer-state) + :: XX ignore events from an old rift instead of sending nack? + :: + :: event-core + (send-nack bone.u.parsed [%old-rift ~]) + ?~ error + (send-ack bone.u.parsed) + (send-nack bone.u.parsed u.error) + == :: if processing succeded, send positive ack packet and exit :: - ?~ error + ++ send-ack + |= =bone + ^+ event-core + ~& send-ack+wire abet:(run-message-sink:peer-core bone %done ok=%.y) :: failed; send message nack packet :: - =. event-core abet:(run-message-sink:peer-core bone %done ok=%.n) - =/ =^peer-state (got-peer-state her) - =/ =^channel [[our her] now channel-state -.peer-state] - :: construct nack-trace message, referencing .failed $message-num - :: - =/ failed=message-num last-acked:(~(got by rcv.peer-state) bone) - =/ =naxplanation [failed u.error] - =/ =message-blob (jam naxplanation) - :: send nack-trace message on associated .nack-trace-bone - :: - =. peer-core (make-peer-core peer-state channel) - =/ nack-trace-bone=^bone (mix 0b10 bone) - :: - abet:(run-message-pump:peer-core nack-trace-bone %memo message-blob) + ++ send-nack + |= [=bone =^error] + ^+ event-core + ~& send-nack+[wire error] + =. event-core abet:(run-message-sink:peer-core bone %done ok=%.n) + =/ =^peer-state (got-peer-state her) + =/ =^channel + :^ [our her] now channel-state + =, -.peer-state + [symmetric-key life rift public-key sponsor] + :: construct nack-trace message, referencing .failed $message-num + :: + =/ failed=message-num last-acked:(~(got by rcv.peer-state) bone) + =/ =naxplanation [failed error] + =/ =message-blob (jam naxplanation) + :: send nack-trace message on associated .nack-trace-bone + :: + =. peer-core (make-peer-core peer-state channel) + =/ nack-trace-bone=^bone (mix 0b10 bone) + :: + abet:(run-message-pump:peer-core nack-trace-bone %memo message-blob) + -- :: +on-sift: handle request to filter debug output by ship :: ++ on-sift @@ -1382,13 +1542,32 @@ ++ on-take-boon |= [=wire payload=*] ^+ event-core + ~& on-take-boon+wire :: - =+ ^- [her=ship =bone] (parse-bone-wire wire) + ?~ parsed=(parse-bone-wire wire) + :: no-op? + :: + event-core :: - =/ =peer-state (got-peer-state her) - =/ =channel [[our her] now channel-state -.peer-state] + ?> ?=([@ her=ship *] u.parsed) + =/ =peer-state (got-peer-state her.u.parsed) + =/ =channel + :^ [our her.u.parsed] now channel-state + =, -.peer-state + [symmetric-key life rift public-key sponsor] :: - abet:(on-memo:(make-peer-core peer-state channel) bone payload %boon) + ?- u.parsed + [%old *] + event-core + :: + [%new *] + =, u.parsed + ?: (lth rift rift.peer-state) + :: ignore events from an old rift ? + :: + event-core + abet:(on-memo:(make-peer-core peer-state channel) bone payload %boon) + == :: +on-plea: handle request to send message :: ++ on-plea @@ -1407,7 +1586,7 @@ =/ =channel [[our ship] now channel-state -.peer-state] :: =^ =bone ossuary.peer-state (bind-duct ossuary.peer-state duct) - %- %^ trace msg.veb ship + %- %^ trace & ship |. ^- tape =/ sndr [our our-life.channel] =/ rcvr [ship her-life.channel] @@ -1472,13 +1651,15 @@ :: ++ on-publ |= [=wire =public-keys-result] + ~& [wire public-keys-result] ^+ event-core :: |^ ^+ event-core :: ?- public-keys-result [%diff @ %rift *] - event-core + :: event-core + (on-publ-rift [who to.diff]:public-keys-result) :: [%diff @ %keys *] (on-publ-rekey [who to.diff]:public-keys-result) @@ -1655,6 +1836,25 @@ :: event-core(duct original-duct) -- + :: on-publ-rift: XX + :: + ++ on-publ-rift + |= [=ship =rift] + ^+ event-core + ?~ ship-state=(~(get by peers.ames-state) ship) + :: print error here? %rift was probably called before %keys + :: + ~& >> on-publ-rift+[ship %missing-state] + event-core + ?: ?=([%alien *] u.ship-state) + :: ignore aliens + :: + event-core + ~& ship^rift + =/ =peer-state +.u.ship-state + =. rift.peer-state rift + =. peers.ames-state (~(put by peers.ames-state) ship %known peer-state) + event-core :: ++ insert-peer-state |= [=ship =point] @@ -1703,7 +1903,6 @@ (rof ~ %j `beam`[[our %turf %da now] /]) :: (emit unix-duct.ames-state %give %turf turfs) - :: +on-trim: handle request to free memory :: +on-vega: handle kernel reload :: +on-trim: handle request to free memory :: @@ -1951,6 +2150,7 @@ :: =+ ?~ dud ~ %. ~ + ~& >>> bone+bone %+ slog leaf+"ames: {} ack crashed {}" ?. msg.veb ~ :- >[bone=bone message-num=message-num meat=meat]:shut-packet< @@ -2007,6 +2207,7 @@ ++ on-wake |= [=bone error=(unit tang)] ^+ peer-core + ~& wake-bone+bone :: if we previously errored out, print and reset timer for later :: :: This really shouldn't happen, but if it does, make sure we @@ -2287,7 +2488,7 @@ :: =+ ;; =plea message :: - =/ =wire (make-bone-wire her.channel bone) + =/ =wire (make-bone-wire her.channel her-rift.channel bone) :: ?+ vane.plea ~| %ames-evil-vane^our^her.channel^vane.plea !! %a (emit duct %pass wire %a %plea her.channel plea) @@ -2383,6 +2584,8 @@ ++ on-done |= [=message-num =ack] ^+ message-pump + ~? (gte message-num next.state) + "unsent message from the future"^[message-num next.state current.state] :: unsent messages from the future should never get acked :: ?> (lth message-num next.state) @@ -2446,9 +2649,11 @@ $(current.state +(current.state)) :: %nack + ~& >>> %nack message-pump :: %naxplanation + ~& >>> %naxplanation =. message-pump (give %done current.state `error.u.cur) $(current.state +(current.state)) == From 5ecf87cf52406ae09431a978683383dc3883ed9c Mon Sep 17 00:00:00 2001 From: yosoyubik Date: Fri, 11 Mar 2022 09:40:14 +0100 Subject: [PATCH 094/168] ames: fix cached state in larval upgrade --- pkg/arvo/app/azimuth.hoon | 4 +- pkg/arvo/sys/vane/ames.hoon | 211 +++++++++++++----------------- pkg/arvo/tests/sys/vane/ames.hoon | 102 +++++++++++++-- 3 files changed, 189 insertions(+), 128 deletions(-) diff --git a/pkg/arvo/app/azimuth.hoon b/pkg/arvo/app/azimuth.hoon index b737d7845..e30714852 100644 --- a/pkg/arvo/app/azimuth.hoon +++ b/pkg/arvo/app/azimuth.hoon @@ -342,8 +342,8 @@ =/ =pass (pass-from-eth:azimuth [32^crypt 32^auth suite]:keys.net) ^- (list [@p udiff:point]) - :* [ship id %rift rift.net %.y] - [ship id %keys [life.keys.net suite.keys.net pass] %.y] + :* [ship id %keys [life.keys.net suite.keys.net pass] %.y] + [ship id %rift rift.net %.y] [ship id %spon ?:(has.sponsor.net `who.sponsor.net ~)] udiffs == diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index ad692a71c..208d92e79 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -114,9 +114,9 @@ ^+ same ?. verb same - :: ?. => [ship=ship ships=ships in=in] - :: ~+ |(=(~ ships) (~(has in ships) ship)) - :: same + ?. => [ship=ship ships=ships in=in] + ~+ |(=(~ ships) (~(has in ships) ship)) + same (slog leaf/"ames: {(scow %p ship)}: {(print)}" ~) :: +qos-update-text: notice text for if connection state changes :: @@ -208,19 +208,20 @@ ++ parse-bone-wire |= =wire ^- %- unit - $% [%new her=ship =rift =bone] - [%old her=ship =bone] + $% [%old her=ship =bone] + [%new her=ship =rift =bone] == ?. ?| ?=([%bone @ @ @ ~] wire) ?=([%bone @ @ ~] wire) == - :: ignore malformed wires? + :: ignore malformed wires :: - ~& >>> malformed-wire+wire ~ ?+ wire ~ [%bone @ @ ~] - ~& >> old-wire+wire + :: later on we drop events that come in an old wire but + :: tracking it here let us print a notification to the user + :: `[%old `@p`(slav %p i.t.wire) `@ud`(slav %ud i.t.t.wire)] :: [%bone @ @ @ ~] @@ -588,6 +589,36 @@ :: +$ naxplanation [=message-num =error] :: ++$ ames-state-4 ames-state-5 ++$ ames-state-5 + $: peers=(map ship ship-state-5) + =unix=duct + =life + crypto-core=acru:ames + =bug + == +:: ++$ ship-state-4 ship-state-5 ++$ ship-state-5 + $% [%alien alien-agenda] + [%known peer-state-5] + == +:: ++$ peer-state-5 + $: $: =symmetric-key + =life + =public-key + sponsor=ship + == + route=(unit [direct=? =lane]) + =qos + =ossuary + snd=(map bone message-pump-state) + rcv=(map bone message-sink-state) + nax=(set [=bone =message-num]) + heeds=(set duct) + == +:: +| %statics :: :: $ames-state: state for entire vane @@ -751,8 +782,7 @@ :: =< =* adult-gate . =| queued-events=(qeu queued-event) - =| larval-bit=_| - =| cached-state=* + =| cached-state=[?(%5 %~) ames-state-5] :: |= [now=@da eny=@ rof=roof] =* larval-gate . @@ -761,35 +791,22 @@ :: +call: handle request $task :: ++ call - => |% - +$ old-state ames-state-4-5:load:adult-core - -- |= [=duct dud=(unit goof) wrapped-task=(hobo task)] - ~& call-larva+duct :: =/ =task ((harden task) wrapped-task) - ~& task+task - :: :: reject larval error notifications :: ?^ dud ~|(%ames-larval-call-dud (mean tang.u.dud)) :: - ~& cach+?=([%5 *] cached-state) - ~& queu+?=(~ queued-events) - =/ from-adult=? + =/ update-ready=? ?& ?=([%5 *] cached-state) ?=(~ queued-events) - :: ?=(^ unix-duct:;;(old-state +.cached-state)) == - =? ames-state.adult-gate from-adult - ~& "state update to 6" - (state-5-to-6:load:adult-core ;;(old-state +.cached-state)) - ::=? larval-bit from-adult %.y - :: - ::?: &(larval-bit ?=(~ queued-events)) - ?: from-adult - =. cached-state ~ + ?: update-ready + =. ames-state.adult-gate + (state-5-to-6:load:adult-core +.cached-state) + =. -.cached-state %~ ~> %slog.1^leaf/"ames: metamorphosis reload" [~ adult-gate] :: %born: set .unix-duct and start draining .queued-events @@ -864,6 +881,16 @@ %call (call:adult-core [duct ~ wrapped-task]:+.first-event) %take (take:adult-core [wire duct ~ sign]:+.first-event) == + =/ update-ready=? + ?& ?=([%5 *] cached-state) + ?=(~ queued-events) + == + ?: update-ready + =. ames-state.adult-gate + (state-5-to-6:load:adult-core +.cached-state) + =. -.cached-state %~ + ~> %slog.1^leaf/"ames: metamorphosis reload" + [moves adult-gate] :: .queued-events has been cleared; metamorphose :: ?~ queued-events @@ -878,23 +905,20 @@ ++ scry scry:adult-core ++ stay [%6 %larva queued-events ames-state.adult-gate] ++ load - => |% - +$ old-state ames-state-4-5:load:adult-core - -- |= $= old $% $: %4 $% $: %larva events=(qeu queued-event) - state=old-state + state=ames-state-4 == - [%adult state=old-state] + [%adult state=ames-state-4] == == $: %5 $% $: %larva events=(qeu queued-event) - state=old-state + state=ames-state-5 == - [%adult state=old-state] + [%adult state=ames-state-5] == == $: %6 $% $: %larva @@ -903,7 +927,6 @@ == [%adult state=_ames-state.adult-gate] == == == - ~& %larval-state-loaded ?- old [%4 %adult *] (load:adult-core %4 state.old) :: @@ -914,21 +937,18 @@ larval-gate :: [%5 %adult *] - ~& [%5 %adult unix-duct.state.old] =. cached-state [%5 state.old] - ~> %slog.1^leaf/"ames: larva: reload" + ~> %slog.1^leaf/"ames: larva reload" larval-gate :: [%5 %larva *] ~> %slog.1^leaf/"ames: larva: load" =. queued-events events.old - =. adult-gate (load:adult-core %5 state.old) larval-gate :: [%6 %adult *] (load:adult-core %6 state.old) :: [%6 %larva *] - ~& larva+-.old ~> %slog.1^leaf/"ames: larva: load" =. queued-events events.old =. adult-gate (load:adult-core %6 state.old) @@ -1009,52 +1029,24 @@ :: ++ load =< |= $= old-state - $% [%4 ames-state-4-5] - [%5 ames-state-4-5] - [%6 ^ames-state] - == + $% [%4 ames-state-4] + [%5 ames-state-5] + [%6 ^ames-state] + == ^+ ames-gate - ~& %load-adult =? old-state ?=(%4 -.old-state) %5^(state-4-to-5 +.old-state) - :: =? old-state ?=(%5 -.old-state) %6^(state-5-to-6 +.old-state) + :: XX this would crash with ames-state-5 but load is never + :: called with it -- the upgrade is handled by the larval load :: ?> ?=(%6 -.old-state) ames-gate(ames-state +.old-state) |% - +$ ames-state-4-5 - $: peers=(map ship ship-state-4-5) - =unix=duct - =life - crypto-core=acru:ames - =bug - == - :: - +$ ship-state-4-5 - $% [%alien alien-agenda] - [%known peer-state-4-5] - == - :: - +$ peer-state-4-5 - $: $: =symmetric-key - =life - =public-key - sponsor=ship - == - route=(unit [direct=? =lane]) - =qos - =ossuary - snd=(map bone message-pump-state) - rcv=(map bone message-sink-state) - nax=(set [=bone =message-num]) - heeds=(set duct) - == - :: ++ state-4-to-5 - |= ames-state=ames-state-4-5 - ^- ames-state-4-5 + |= ames-state=ames-state-4 + ^- ames-state-4 =. peers.ames-state %- ~(run by peers.ames-state) - |= ship-state=ship-state-4-5 + |= ship-state=ship-state-4 ?. ?=(%known -.ship-state) ship-state =. snd.ship-state @@ -1067,21 +1059,20 @@ ames-state :: ++ state-5-to-6 - |= ames-state=ames-state-4-5 + |= ames-state=ames-state-5 ^- ^^ames-state :_ +.ames-state %- ~(rut by peers.ames-state) - |= [=ship ship-state=ship-state-4-5] + |= [=ship ship-state=ship-state-5] ^- ^ship-state ?. ?=(%known -.ship-state) ship-state - =/ peer-state=peer-state-4-5 +.ship-state + =/ peer-state=peer-state-5 +.ship-state =| =rift =/ scry=(unit (unit cage)) (rof ~ %j `beam`[[our %rift %da now] /(scot %p ship)]) =? rift ?=([~ ~ ^] scry) ;;(@ud q.q:u.u.scry) - ~& ship^rift =/ =^peer-state :_ +.peer-state =, -.peer-state @@ -1231,30 +1222,28 @@ ?~ parsed=(parse-bone-wire wire) :: no-op? :: - ~& >>> "error parsing wire" - event-core + =/ =tape "; ames dropping malformed wire" + (emit duct %pass /parse-wire %d %flog %text tape) ?> ?=([@ her=ship *] u.parsed) =* her her.u.parsed =/ =peer-state (got-peer-state her) - =/ =channel - :^ [our her] now channel-state - =, -.peer-state - [symmetric-key life rift public-key sponsor] + =/ =channel [[our her] now channel-state -.peer-state] + =/ peer-core (make-peer-core peer-state channel) |^ ?- u.parsed [%old *] - :: XX ignore events from old wire instead of sending nack? + :: ignore events from old wire :: - :: event-core - (send-nack bone.u.parsed [%old-wire ~[(spat wire)]]) + =/ =tape "; ames dropping old wire format" + (emit duct %pass /parse-wire %d %flog %text tape) :: [%new *] ?: (lth rift.u.parsed rift.peer-state) - :: XX ignore events from an old rift instead of sending nack? + :: ignore events from an old rift :: - :: event-core - (send-nack bone.u.parsed [%old-rift ~]) + =/ =tape "; ames dropping wire with old rift ({})" + (emit duct %pass /parse-wire %d %flog %text tape) ?~ error (send-ack bone.u.parsed) (send-nack bone.u.parsed u.error) @@ -1264,20 +1253,15 @@ ++ send-ack |= =bone ^+ event-core - ~& send-ack+wire abet:(run-message-sink:peer-core bone %done ok=%.y) :: failed; send message nack packet :: ++ send-nack |= [=bone =^error] ^+ event-core - ~& send-nack+[wire error] =. event-core abet:(run-message-sink:peer-core bone %done ok=%.n) =/ =^peer-state (got-peer-state her) - =/ =^channel - :^ [our her] now channel-state - =, -.peer-state - [symmetric-key life rift public-key sponsor] + =/ =^channel [[our her] now channel-state -.peer-state] :: construct nack-trace message, referencing .failed $message-num :: =/ failed=message-num last-acked:(~(got by rcv.peer-state) bone) @@ -1542,30 +1526,27 @@ ++ on-take-boon |= [=wire payload=*] ^+ event-core - ~& on-take-boon+wire :: ?~ parsed=(parse-bone-wire wire) - :: no-op? - :: - event-core + =/ =tape "; ames dropping malformed wire" + (emit duct %pass /parse-wire %d %flog %text tape) :: ?> ?=([@ her=ship *] u.parsed) =/ =peer-state (got-peer-state her.u.parsed) - =/ =channel - :^ [our her.u.parsed] now channel-state - =, -.peer-state - [symmetric-key life rift public-key sponsor] + =/ =channel [[our her.u.parsed] now channel-state -.peer-state] :: ?- u.parsed [%old *] - event-core + =/ =tape "; ames dropping old wire" + (emit duct %pass /parse-wire %d %flog %text tape) :: [%new *] =, u.parsed ?: (lth rift rift.peer-state) - :: ignore events from an old rift ? + :: ignore events from an old rift :: - event-core + =/ =tape "; ames dropping wire with old rift ({})" + (emit duct %pass /parse-wire %d %flog %text tape) abet:(on-memo:(make-peer-core peer-state channel) bone payload %boon) == :: +on-plea: handle request to send message @@ -1586,7 +1567,7 @@ =/ =channel [[our ship] now channel-state -.peer-state] :: =^ =bone ossuary.peer-state (bind-duct ossuary.peer-state duct) - %- %^ trace & ship + %- %^ trace msg.veb ship |. ^- tape =/ sndr [our our-life.channel] =/ rcvr [ship her-life.channel] @@ -1651,7 +1632,6 @@ :: ++ on-publ |= [=wire =public-keys-result] - ~& [wire public-keys-result] ^+ event-core :: |^ ^+ event-core @@ -1844,13 +1824,12 @@ ?~ ship-state=(~(get by peers.ames-state) ship) :: print error here? %rift was probably called before %keys :: - ~& >> on-publ-rift+[ship %missing-state] + ~> %slog.1^leaf/"ames: missing peer-state on-publ-rift" event-core ?: ?=([%alien *] u.ship-state) :: ignore aliens :: event-core - ~& ship^rift =/ =peer-state +.u.ship-state =. rift.peer-state rift =. peers.ames-state (~(put by peers.ames-state) ship %known peer-state) @@ -2150,7 +2129,6 @@ :: =+ ?~ dud ~ %. ~ - ~& >>> bone+bone %+ slog leaf+"ames: {} ack crashed {}" ?. msg.veb ~ :- >[bone=bone message-num=message-num meat=meat]:shut-packet< @@ -2207,7 +2185,6 @@ ++ on-wake |= [=bone error=(unit tang)] ^+ peer-core - ~& wake-bone+bone :: if we previously errored out, print and reset timer for later :: :: This really shouldn't happen, but if it does, make sure we @@ -2649,11 +2626,9 @@ $(current.state +(current.state)) :: %nack - ~& >>> %nack message-pump :: %naxplanation - ~& >>> %naxplanation =. message-pump (give %done current.state `error.u.cur) $(current.state +(current.state)) == diff --git a/pkg/arvo/tests/sys/vane/ames.hoon b/pkg/arvo/tests/sys/vane/ames.hoon index 16638ddc1..97b24d978 100644 --- a/pkg/arvo/tests/sys/vane/ames.hoon +++ b/pkg/arvo/tests/sys/vane/ames.hoon @@ -1,5 +1,6 @@ /+ *test /= ames /sys/vane/ames +/= jael /sys/vane/jael :: construct some test fixtures :: =/ nec (ames ~nec) @@ -36,7 +37,7 @@ =/ bud-sym (derive-symmetric-key:ames nec-pub bud-sec) ?> =(nec-sym bud-sym) :: -=/ comet-sym (derive-symmetric-key:ames bud-pub comet-sec) +=/ comet-sym (derive-symmetric-key:ames bud-pub comet-sec) :: =. peers.ames-state.nec %+ ~(put by peers.ames-state.nec) ~bud @@ -44,6 +45,7 @@ =. -.peer-state :* symmetric-key=bud-sym life=3 + rift=0 public-key=bud-pub sponsor=~nec == @@ -56,6 +58,7 @@ =. -.peer-state :* symmetric-key=nec-sym life=2 + rift=0 public-key=nec-pub sponsor=~nec == @@ -195,7 +198,7 @@ =^ moves1 bud (call bud ~[//unix] %hear lane-foo blob) =^ moves2 bud =/ =point:ames - :* rift=1 + :* rift=0 life=4 keys=[[life=4 [crypto-suite=1 `@`nec-pub]] ~ ~] sponsor=`~bus @@ -213,7 +216,7 @@ :: %+ expect-eq !> %- sy - :~ :^ ~[//unix] %pass /bone/~bus/1 + :~ :^ ~[//unix] %pass /bone/~bus/0/1 [%g %plea ~bus %g /talk [%first %post]] :: :^ ~[//unix] %pass /qos @@ -267,7 +270,7 @@ !> :~ :* ~[//unix] %pass /qos %d %flog %text "; {} is your neighbor" == - :* ~[//unix] %pass /bone/(scot %p our.comet)/1 + :* ~[//unix] %pass /bone/(scot %p our.comet)/0/1 %g %plea our.comet plea == == !> moves1 @@ -280,11 +283,11 @@ =^ moves2 bud (call bud ~[//unix] %hear (snag-packet 0 moves1)) :: ~bud -> %done -> ~nec :: - =^ moves3 bud (take bud /bone/~nec/1 ~[//unix] %g %done ~) + =^ moves3 bud (take bud /bone/~nec/0/1 ~[//unix] %g %done ~) =^ moves4 nec (call nec ~[//unix] %hear (snag-packet 0 moves3)) :: ~bud -> %boon -> ~nec :: - =^ moves5 bud (take bud /bone/~nec/1 ~[//unix] %g %boon [%post 'first1!!']) + =^ moves5 bud (take bud /bone/~nec/0/1 ~[//unix] %g %boon [%post 'first1!!']) =^ moves6 nec (call nec ~[//unix] %hear (snag-packet 0 moves5)) :: ~nec -> %done -> ~bud (just make sure ~bud doesn't crash on ack) :: @@ -293,7 +296,7 @@ ;: weld %+ expect-eq !> :~ [~[//unix] %pass /qos %d %flog %text "; ~nec is your neighbor"] - [~[//unix] %pass /bone/~nec/1 %g %plea ~nec %g /talk [%get %post]] + [~[//unix] %pass /bone/~nec/0/1 %g %plea ~nec %g /talk [%get %post]] == !> moves2 :: @@ -318,7 +321,7 @@ :: ~bud -> nack -> ~nec :: =/ =error:ames [%flub [%leaf "sinusoidal repleneration"]~] - =^ moves3 bud (take bud /bone/~nec/1 ~[/bud] %g %done `error) + =^ moves3 bud (take bud /bone/~nec/0/1 ~[/bud] %g %done `error) =^ moves4 nec (call nec ~[//unix] %hear (snag-packet 0 moves3)) :: ~bud -> nack-trace -> ~nec :: @@ -330,4 +333,87 @@ %+ expect-eq !> [~[/g/talk] %give %done `error] !> (snag 1 `(list move:ames)`moves5) +:: +++ test-old-ames-wire ^- tang + =^ moves1 bud (take bud /bone/~nec/1 ~[//unix] %g %done ~) + %+ expect-eq + !> %- sy + :_ ~ + [~[//unix] %pass /parse-wire %d %flog %text "; ames dropping old wire format"] + !> (sy ,.moves1) +:: :: +++ test-dangling-bone ^- tang + :: ~nec -> %plea -> ~bud + :: + =^ moves1 nec (call nec ~[/g/talk] %plea ~bud %g /talk [%get %post]) + =^ moves2 bud (call bud ~[//unix] %hear (snag-packet 0 moves1)) + :: ~bud receives a gift from %jael with ~nec's new rift + :: + =^ moves3 bud + %- take + :^ bud /public-keys ~[//unix] + ^- sign:ames + [%jael %public-keys %diff who=~nec %rift from=0 to=1] + :: %gall has a pending wire with the old rift, so sending a gift to + :: %ames on it will drop that request, and print a message to the user + :: + =^ moves3 bud (take bud /bone/~nec/0/1 ~[//unix] %g %done ~) + :: + %+ expect-eq + !> %- sy + :_ ~ + :* ~[//unix] + %pass + /parse-wire + %d + %flog + %text + "; ames dropping wire with old rift (0)" + == + !> (sy ,.moves3) +:: +++ test-ames-flow-with-new-rift ^- tang + :: ~bunecd receives a gift from %jael with ~bud's new rift + :: + =^ moves1 nec + %- take + :^ nec /public-keys ~[//unix] + ^- sign:ames + [%jael %public-keys %diff who=~bud %rift from=0 to=1] + :: now we try a normal message flow using the new rift in the wire + :: ~nec -> %plea -> ~bud + :: + =^ moves2 nec (call nec ~[/g/talk] %plea ~bud %g /talk [%get %post]) + =^ moves3 bud (call bud ~[//unix] %hear (snag-packet 0 moves2)) + :: ~bud -> %done -> ~nec + :: + =^ moves4 bud (take bud /bone/~nec/1/1 ~[//unix] %g %done ~) + =^ moves5 nec (call nec ~[//unix] %hear (snag-packet 0 moves4)) + :: ~bud -> %boon -> ~nec + :: + =^ moves6 bud (take bud /bone/~nec/1/1 ~[//unix] %g %boon [%post '¡hola!']) + =^ moves7 nec (call nec ~[//unix] %hear (snag-packet 0 moves6)) + :: ~nec -> %done -> ~bud (just make sure ~bud doesn't crash on ack) + :: + =^ moves8 bud (call bud ~[//unix] %hear (snag-packet 0 moves7)) + :: + ;: weld + %+ expect-eq + !> :~ [~[//unix] %pass /qos %d %flog %text "; ~nec is your neighbor"] + [~[//unix] %pass /bone/~nec/0/1 %g %plea ~nec %g /talk [%get %post]] + == + !> moves3 + :: + %+ expect-eq + !> %- sy + :~ [~[/ames] %pass /pump/~bud/0 %b %rest ~1111.1.1..00.00.03] + [~[//unix] %pass /qos %d %flog %text "; ~bud is your neighbor"] + [~[/g/talk] %give %done error=~] + == + !> (sy ,.moves5) + :: + %+ expect-eq + !> [~[/g/talk] %give %boon [%post '¡hola!']] + !> (snag 0 `(list move:ames)`moves7) + == -- From 0587e0e836f5e16ebc44531bbd7af285e5f4caa0 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Mon, 14 Mar 2022 15:04:14 -0600 Subject: [PATCH 095/168] ames: add %pine task %pine automatically scries for the latest case of a path --- bin/solid.pill | 4 +- pkg/arvo/gen/hood/keen.hoon | 10 ++- pkg/arvo/gen/hood/pine.hoon | 6 ++ pkg/arvo/sys/lull.hoon | 5 +- pkg/arvo/sys/vane/ames.hoon | 122 ++++++++++++++++++++++++++++++------ pkg/arvo/sys/vane/clay.hoon | 4 +- pkg/arvo/sys/zuse.hoon | 61 +++++++++++------- 7 files changed, 157 insertions(+), 55 deletions(-) create mode 100644 pkg/arvo/gen/hood/pine.hoon diff --git a/bin/solid.pill b/bin/solid.pill index 590f14132..b505afde3 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d3ed6dfa5218a8cde06f4c85b710681a236ba8ad65929c04bb567520e848d1c -size 9313238 +oid sha256:5b0aa036abe4e982fd22de59ed5d3d4dfef14ebac19b7e5b2eda9b8ab01ee873 +size 9425630 diff --git a/pkg/arvo/gen/hood/keen.hoon b/pkg/arvo/gen/hood/keen.hoon index f57225d13..8c7c5a02b 100644 --- a/pkg/arvo/gen/hood/keen.hoon +++ b/pkg/arvo/gen/hood/keen.hoon @@ -1,8 +1,6 @@ :- %say -|= [^ [=ship pax=$@(~ [=path ~])] ~] +|= [^ [=ship pax=$@(~ [path ~])] ~] =/ =path - ?~ pax /cz/(scot %p ship)/kids/1/sys - ?> ?=([@ *] path.pax) - =, pax - [i.path (scot %p ship) t.path] -[%helm-pass %a %keen path] + ?^ pax -.pax + /c/x/1/kids/sys/hoon/hoon +[%helm-pass %a %keen ship path] diff --git a/pkg/arvo/gen/hood/pine.hoon b/pkg/arvo/gen/hood/pine.hoon new file mode 100644 index 000000000..3ad4dc730 --- /dev/null +++ b/pkg/arvo/gen/hood/pine.hoon @@ -0,0 +1,6 @@ +:- %say +|= [^ [=ship pax=$@(~ [path ~])] ~] +=/ =path + ?^ pax -.pax + /c/x/1/kids/sys/hoon/hoon +[%helm-pass %a %pine ship path] diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 7d2378529..eb3419d2f 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1083,8 +1083,9 @@ [%jilt =ship] $>(%plea vane-task) :: - [%keen =path] - [%yawn =path] + [%keen =ship =path] + [%pine =ship =path] + [%yawn =ship =path] [%bide =path] :: $>(%born vane-task) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index cb4b7c77f..b7accde5d 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -1130,6 +1130,7 @@ %vega on-vega:event-core %plea (on-plea:event-core [ship plea]:task) :: + %pine (on-pine:fine:event-core +.task) %keen (on-keen:fine:event-core +.task) %yawn (on-yawn:fine:event-core +.task) %bide (on-bide:fine:event-core +.task) @@ -1165,7 +1166,7 @@ [moves ames-gate] :: +stay: extract state before reload :: -++ stay [%6 %adult ames-state] +++ stay [%7 %adult ames-state] :: +load: load in old state after reload :: ++ load @@ -1363,7 +1364,8 @@ :: so we need to give it the right shape :: =* path t.t.tyl - ?~ nom=(de-omen path) ~ + ?~ blk=(de-path-soft:balk path) ~ + =+ nom=(en-roof:balk u.blk) :: we only support scrying into clay, :: and only if the data is fully public. :: @@ -1374,7 +1376,7 @@ :: ?> ?=(^ u.pem) :: =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) :: ?> =([%black ~ ~] rul.r.per) - =+ res=(rof lyc u.nom) + =+ res=(rof lyc nom) ::TODO suggests we need to factor differently =+ ven=(per-event [now 0v0 rof] *duct ames-state) ?- res @@ -1411,10 +1413,12 @@ ^+ event-core :: relay the vane ack to the foreign peer :: + ?: ?=([%fine %pine *] wire) + event-core ?~ parsed=(parse-bone-wire wire) :: no-op? :: - =/ =tape "; ames dropping malformed wire" + =/ =tape "; ames dropping malformed wire {}" (emit duct %pass /parse-wire %d %flog %text tape) ?> ?=([@ her=ship *] u.parsed) =* her her.u.parsed @@ -1725,9 +1729,14 @@ ++ on-take-boon |= [=wire payload=*] ^+ event-core + ?: ?=([%fine %pine @ *] wire) + ?~ her=(slaw %p i.t.t.wire) + =/ =tape "; fine dropping malformed wire {}" + (emit duct %pass /parse-wire %d %flog %text tape) + (on-pine-boon:fine u.her t.t.t.wire payload) :: ?~ parsed=(parse-bone-wire wire) - =/ =tape "; ames dropping malformed wire" + =/ =tape "; ames dropping malformed wire {}" (emit duct %pass /parse-wire %d %flog %text tape) :: ?> ?=([@ her=ship *] u.parsed) @@ -1761,6 +1770,13 @@ %+ enqueue-alien-todo ship |= todos=alien-agenda todos(messages [[duct plea] messages.todos]) + ~& plea/ship^path.plea + ~& ((soft balk) payload.plea) + :: + ?: &(=(/pine path.plea) =(our her:;;(balk payload.plea))) + ~& ship^plea + ~& ;;(balk payload.plea) + (on-pine-plea:fine ship payload.plea) :: =/ =peer-state +.u.ship-state =/ =channel [[our ship] now channel-state -.peer-state] @@ -2725,6 +2741,26 @@ =. keens.scry (put:orm keens.scry keen-id keen-state) ke-abet:(ke-start:(ke-abed:keen-core path) duct) :: + ++ pe-pine + |= =path + ~& pe-pine/path^ship + ^+ pe-core + ?~ blk=(de-part:balk ship rift.peer life.peer path) + !! :: XX: ??? + =+ wir=`wire`[%fine %pine (scot %p ship) path] + =. event-core + (emit duct %pass wir %a %plea ship %a /pine `*`u.blk) + pe-core + :: + ++ pe-pine-boon + |= [=path payload=*] + ^+ pe-core + ?~ blk=(de-part:balk ship rift.peer life.peer path) + !! + =+ ;;(case=@ud payload) + ~& finished-pine/u.blk^case + (pe-keen path duct) + :: ++ pe-meet-alien |= agenda=(jug path ^duct) %+ roll ~(tap by agenda) @@ -2744,10 +2780,11 @@ ?> =(sndr-tick.packet (mod life.peer 16)) :: =/ [=peep =purr] (decode-request-info `@ux`content.packet) - ?. (~(has by order.scry) path.peep) + =/ =path (slag 3 path.peep) + ?. (~(has by order.scry) path) ~&(dead-response/peep pe-core) =< ke-abet - (ke-rcv:(ke-abed:keen-core path.peep) num.peep purr lane) + (ke-rcv:(ke-abed:keen-core path) num.peep purr lane) :: ++ pe-update-qos |= =new=qos @@ -2824,10 +2861,15 @@ ?:(=(id i) `p ~) ++ ke-deq (deq want) + ++ ke-full-path + :^ (scot %p ship) + (scot %ud rift.peer) + (scot %ud life.peer) + path :: ++ ke-encode-req |= frag=@ud - (encode-request ship path frag) + (encode-request ship ke-full-path frag) :: ++ ke-on-ack =| marked=(list want) @@ -2873,8 +2915,7 @@ :: ++ ke-done |= [sig=@ data=$@(~ (cask))] - ~& path - ?> (meri:keys ship life.peer path sig data) + ?> (meri:keys ship life.peer ke-full-path sig data) ~& got-response/path =/ listeners ~(tap in listeners.keen) =/ dat=(unit (cask)) @@ -2970,7 +3011,7 @@ :: ~| failed-signature/fra^`@ux`sig.rawr ~| life.peer - ?> (veri-fra:keys ship life.peer path fra [dat sig]:rawr) + ?> (veri-fra:keys ship life.peer ke-full-path fra [dat sig]:rawr) =^ found=? ke-core (ke-on-ack fra) :: @@ -3061,13 +3102,57 @@ (ke-resend [fra hoot]:u.want) -- -- - ++ on-keen - |= =path + :: + ++ on-pine-plea + |= [=ship payload=*] + ~& on-pine-plea/ship + ^+ event-core + =+ ;;(blk=balk payload) + ?> =(%c van.blk) + =. car.blk %w + =. cas.blk da+now + =. spr.blk + ?> ?=(^ spr.blk) + ^- path + ~[i.spr.blk] + ~& (en-roof:balk blk) + =+ !<(=cass:clay q:(need (need (rof ~ (en-roof:balk blk))))) + =. event-core + (emit duct %give %boon ud.cass) + (emit duct %give %done ~) + :: + ++ on-pine-boon + |= [=ship =path payload=*] + ~& on-pine-boon/path^ship + =/ pe-core (need (pe-abed:fine-peer ship)) + pe-abet:(pe-pine-boon:pe-core path payload) + :: + ++ on-pine + |= [=ship =path] + ~& on-pine/ship^path + ^+ event-core + ?. =(our ship) + =/ peer-core + (pe-abed:fine-peer ship) + ?~ peer-core + !! :: TODO: alien handling + pe-abet:(pe-pine:u.peer-core path) + :: XX: crashing correct behaviour? + =+ blk=(need (de-part:balk our rift.ames-state life.ames-state path)) + ?> ?=(%c van.blk) + =+ nom=(en-roof:balk blk(car %w, cas [%da now])) + =+ cag=(rof ~ nom) + ?- cag + ~ !! + [~ ~] !! :: XX: correct? + :: + [~ ~ *] + =+ !<(=cass:clay q.u.u.cag) + (emit duct %give %boon `*`ud.cass) + == + ++ on-keen + |= [=ship =path] ^+ event-core - =/ omen - ~| [%fine %invalid-namespace-path path] - (need (de-omen path)) - =* ship p.bem.omen =/ peer-core (pe-abed:fine-peer ship) ?^ peer-core pe-abet:(pe-keen:u.peer-core path duct) %+ enqueue-alien-todo ship @@ -3075,7 +3160,7 @@ todos(keens (~(put ju keens.todos) path duct)) :: ++ on-yawn - |= =path + |= [=ship =path] ^+ event-core =/ omen ~| [%fine %invalid-namespace-path path] @@ -3097,7 +3182,6 @@ ?> ?=([@ @ *] path) =/ =wire (welp /fine/bide path) - =/ =ship (slav %p i.t.path) =/ [vis=view bem=beam] (need (de-omen path)) =+ ;; =care:clay diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 0d42e09ab..6b2722049 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -1334,7 +1334,7 @@ ~& scrying/path^index :- time %- emil - :~ [hen %pass wire %a %keen path] + :~ [hen %pass wire %a %keen ship path] [hen %pass wire %b %wait time] == :: @@ -2957,7 +2957,7 @@ =, mood.rave.sat [(cat 3 %c care) (scot %p her) syd (scot case) path] %- emil - :~ [hen %pass / %a %yawn path] + :~ [hen %pass / %a %yawn her path] [hen %pass / %b %rest u.scry.sat] == :: diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index da5ab40af..0ce27b70b 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -5625,6 +5625,7 @@ :: ++ balk =< bulk + !: |% +$ bulk $: [her=ship rif=rift lyf=life] @@ -5632,46 +5633,58 @@ spr=spur == :: - ++ de-path-soft - |= [=rift =life =path] + ++ de-part + |= [=ship =rift =life =(pole knot)] ^- (unit bulk) - :: [care ship desk case path] - ?. ?=([@ @ @ @ *] path) - ~ - =/ van=@ta (end 3 i.path) - =/ car=@ta (rsh 3 i.path) - ?~ her=(slaw %p i.t.path) - ~ - ?~ cas=(de-case i.t.t.t.path) - ~ + ?. ?=([van=@ car=@ cas=@ spr=*] pole) ~ + ?~ cas=(de-case cas.pole) ~ :- ~ - :* [u.her rift life] - [van car u.cas] - [i.t.t.path t.t.t.t.path] + :* [ship rift life] + [van.pole car.pole u.cas] + spr.pole + == + :: + ++ de-path-soft + |= =(pole knot) + ^- (unit bulk) + :: [ship rift life vane care case path] + ?. ?=([her=@ rif=@ lyf=@ van=@ car=@ cas=@ spr=*] pole) + ~ + ?~ her=(slaw %p her.pole) ~ + ?~ rif=(slaw %ud rif.pole) ~ + ?~ lyf=(slaw %ud lyf.pole) ~ + ?~ cas=(de-case cas.pole) ~ + :- ~ + :* [u.her u.rif u.lyf] + [van.pole car.pole u.cas] + spr.pole == :: ++ de-path - |= [=rift =life =path] + |= =path ^- bulk (need (de-path-soft +<)) :: ++ en-path |= =bulk ^- path - ?> ?=([@ *] spr.bulk) - :* (cat 3 van.bulk car.bulk) - (scot %p her.bulk) - i.spr.bulk + :* (scot %p her.bulk) + (scot %ud rif.bulk) + (scot %ud lyf.bulk) + van.bulk + car.bulk (scot cas.bulk) - t.spr.bulk + spr.bulk == :: ++ en-roof |= =bulk - ^- (unit [vis=view bem=beam]) - ?. ?=(^ spr.bulk) ~ - =/ bem=beam [[her i.spr cas] t.spr]:bulk + ^- [vis=view bem=beam] + =/ [des=desk pax=path] + ?^ spr.bulk spr.bulk + [%$ ~] + =/ bem=beam =,(bulk [[her des cas] pax]) =+ vis=(cat 3 van.bulk car.bulk) - `[vis bem] + [vis bem] -- -- From 92e52c9f7eedc6e45f52b913b10c01fafddf0d0b Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Tue, 15 Mar 2022 10:40:34 -0600 Subject: [PATCH 096/168] ames: fix path handling in %bide --- bin/solid.pill | 4 +-- pkg/arvo/sys/lull.hoon | 6 +++- pkg/arvo/sys/vane/ames.hoon | 67 ++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 34 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index b505afde3..3114a2302 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5b0aa036abe4e982fd22de59ed5d3d4dfef14ebac19b7e5b2eda9b8ab01ee873 -size 9425630 +oid sha256:13941f43472c8e7985f68d41cecd4facc534bcb171f553bb7fd6b20e6bef49c0 +size 9660444 diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index eb3419d2f..2de1b13f9 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1109,6 +1109,7 @@ :: Remote Scry Gifts :: %tune: found data for arvo :: %howl: full response packets + :: %miss: no case for %pine :: :: System and Lifecycle Gifts :: @@ -1116,13 +1117,15 @@ :: +$ gift $% [%boon payload=*] + [%miss ~] [%clog =ship] [%done error=(unit error)] [%lost ~] [%send =lane =blob] :: - [%tune =path data=(unit (cask))] + [%tune =path sign=@ux data=(unit (cask))] [%howl =path =song] + [%miss =path] :: [%turf turfs=(list turf)] == @@ -1224,6 +1227,7 @@ packets=(set =blob) heeds=(set duct) keens=(jug path duct) + pines=(jug path duct) == :: $peer-state: state for a peer with known life and keys :: diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index b7accde5d..e0486a287 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -1202,7 +1202,7 @@ |= old=ship-state-6 ^- ship-state ?: ?=(%alien -.old) - old(heeds [heeds.old ~]) + old(heeds [heeds.old ~ ~]) old(heeds [heeds.old *scry-state]) :: ++ state-5-to-6 @@ -1770,12 +1770,8 @@ %+ enqueue-alien-todo ship |= todos=alien-agenda todos(messages [[duct plea] messages.todos]) - ~& plea/ship^path.plea - ~& ((soft balk) payload.plea) :: ?: &(=(/pine path.plea) =(our her:;;(balk payload.plea))) - ~& ship^plea - ~& ;;(balk payload.plea) (on-pine-plea:fine ship payload.plea) :: =/ =peer-state +.u.ship-state @@ -2033,8 +2029,10 @@ :: apply remote scry requests :: =. event-core - =< pe-abet - (pe-meet-alien:(need (pe-abed:fine-peer:fine ship)) keens.todos) + =+ pe-core=(need (pe-abed:fine-peer:fine ship)) + =. pe-core (pe-meet-alien-keen:pe-core keens.todos) + =. pe-core (pe-meet-alien-pine:pe-core pines.todos) + pe-abet:pe-core :: event-core(duct original-duct) -- @@ -2742,8 +2740,7 @@ ke-abet:(ke-start:(ke-abed:keen-core path) duct) :: ++ pe-pine - |= =path - ~& pe-pine/path^ship + |= [=path =^duct] ^+ pe-core ?~ blk=(de-part:balk ship rift.peer life.peer path) !! :: XX: ??? @@ -2758,12 +2755,22 @@ ?~ blk=(de-part:balk ship rift.peer life.peer path) !! =+ ;;(case=@ud payload) - ~& finished-pine/u.blk^case - (pe-keen path duct) + =. cas.u.blk ud+case + (pe-keen (slag 3 (en-path:balk u.blk)) duct) :: - ++ pe-meet-alien - |= agenda=(jug path ^duct) - %+ roll ~(tap by agenda) + ++ pe-meet-alien-pine + |= pines=(jug path ^duct) + %+ roll ~(tap by pines) + |= [[=path ducts=(set ^duct)] cor=_pe-core] + ^+ cor + %+ roll ~(tap in ducts) + |= [=^duct c=_cor] + ^+ c + (pe-pine:c path duct) + :: + ++ pe-meet-alien-keen + |= keens=(jug path ^duct) + %+ roll ~(tap by keens) |= [[=path ducts=(set ^duct)] cor=_pe-core] ^+ cor %+ roll ~(tap in ducts) @@ -2924,7 +2931,7 @@ ?~ listeners ke-core =. event-core - (emit i.listeners %give %tune path dat) + (emit i.listeners %give %tune ke-full-path sig dat) $(listeners t.listeners) :: ++ ke-first-rcv @@ -2983,7 +2990,6 @@ :: ++ ke-decode-full =, keen - ~& num/num-received ~| %frag-mismatch ~| have/num-received ~| need/num-fragments @@ -3105,7 +3111,6 @@ :: ++ on-pine-plea |= [=ship payload=*] - ~& on-pine-plea/ship ^+ event-core =+ ;;(blk=balk payload) ?> =(%c van.blk) @@ -3115,7 +3120,6 @@ ?> ?=(^ spr.blk) ^- path ~[i.spr.blk] - ~& (en-roof:balk blk) =+ !<(=cass:clay q:(need (need (rof ~ (en-roof:balk blk))))) =. event-core (emit duct %give %boon ud.cass) @@ -3123,20 +3127,20 @@ :: ++ on-pine-boon |= [=ship =path payload=*] - ~& on-pine-boon/path^ship =/ pe-core (need (pe-abed:fine-peer ship)) pe-abet:(pe-pine-boon:pe-core path payload) :: ++ on-pine |= [=ship =path] - ~& on-pine/ship^path ^+ event-core ?. =(our ship) =/ peer-core (pe-abed:fine-peer ship) - ?~ peer-core - !! :: TODO: alien handling - pe-abet:(pe-pine:u.peer-core path) + ?^ peer-core + pe-abet:(pe-pine:u.peer-core path duct) + %+ enqueue-alien-todo ship + |= todos=alien-agenda + todos(pines (~(put ju keens.todos) path duct)) :: XX: crashing correct behaviour? =+ blk=(need (de-part:balk our rift.ames-state life.ames-state path)) ?> ?=(%c van.blk) @@ -3144,7 +3148,7 @@ =+ cag=(rof ~ nom) ?- cag ~ !! - [~ ~] !! :: XX: correct? + [~ ~] (emit duct %give %miss (en-path:balk blk)) :: [~ ~ *] =+ !<(=cass:clay q.u.u.cag) @@ -3182,14 +3186,15 @@ ?> ?=([@ @ *] path) =/ =wire (welp /fine/bide path) - =/ [vis=view bem=beam] - (need (de-omen path)) - =+ ;; =care:clay - ?^ vis car.vis - (rsh 3^1 vis) + =+ blk=(de-path:balk path) + ?> ?=(%c van.blk) + =/ [des=desk spr=spur] + ?^ spr.blk spr.blk + [%$ ~] + =+ ;;(=care:clay car.blk) =/ =rave:clay - [%sing care r.bem s.bem] - (emit duct %pass wire %c %warp p.bem q.bem `rave) + [%sing care cas.blk spr] + (emit duct %pass wire %c %warp her.blk des `rave) :: ++ on-take-clay-bide |= [=wire =riot:clay] From 4ae93c8bd07570bcf115efd4be70af3b59b5931c Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 15 Apr 2022 16:35:58 -0500 Subject: [PATCH 097/168] ames: strip out notifications system --- bin/solid.pill | 4 ++-- pkg/arvo/sys/lull.hoon | 7 ------- pkg/arvo/sys/vane/ames.hoon | 40 ------------------------------------- 3 files changed, 2 insertions(+), 49 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index 3114a2302..4c71cce06 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:13941f43472c8e7985f68d41cecd4facc534bcb171f553bb7fd6b20e6bef49c0 -size 9660444 +oid sha256:d324c1f4f09abe156de814718fc603c2faef65d8866182bf5135929bc69182c7 +size 9868510 diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 2de1b13f9..b95290010 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1066,7 +1066,6 @@ :: :: %keen: data request from arvo :: %yawn: cancel request from arvo - :: %bide: unix awaiting datum creation (%howl) :: :: System and Lifecycle Tasks :: @@ -1086,7 +1085,6 @@ [%keen =ship =path] [%pine =ship =path] [%yawn =ship =path] - [%bide =path] :: $>(%born vane-task) $>(%init vane-task) @@ -1108,7 +1106,6 @@ :: :: Remote Scry Gifts :: %tune: found data for arvo - :: %howl: full response packets :: %miss: no case for %pine :: :: System and Lifecycle Gifts @@ -1124,7 +1121,6 @@ [%send =lane =blob] :: [%tune =path sign=@ux data=(unit (cask))] - [%howl =path =song] [%miss =path] :: [%turf turfs=(list turf)] @@ -2994,8 +2990,5 @@ :: %behn: wakeup :: $>(%wake task:behn) - :: %ames: await namespace datum - :: - $>(%bide task:ames) == -- :: diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index e0486a287..428814ffd 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -832,9 +832,6 @@ $% $: %behn $% $>(%wake gift:behn) == == - $: ?(%behn %clay) - $% [%writ p=riot:clay] - == == $: %jael $% [%private-keys =life vein=(map life ring)] [%public-keys =public-keys-result] @@ -1133,7 +1130,6 @@ %pine (on-pine:fine:event-core +.task) %keen (on-keen:fine:event-core +.task) %yawn (on-yawn:fine:event-core +.task) - %bide (on-bide:fine:event-core +.task) == :: [moves ames-gate] @@ -1153,8 +1149,6 @@ ?- sign [@ %done *] (on-take-done:event-core wire error.sign) [@ %boon *] (on-take-boon:event-core wire payload.sign) - :: - [?(%clay %behn) %writ *] (on-take-clay-bide:fine:event-core wire p.sign) :: [%behn %wake *] (on-take-wake:event-core wire error.sign) :: @@ -3174,40 +3168,6 @@ ~|(%no-ship-for-yawn !!) pe-abet:(pe-yawn:u.peer-core path) :: - ++ on-bide - |= =path - ^+ event-core - :: TODO: other vanes? - (bide-clay path) - :: - ++ bide-clay - |= =path - ^+ event-core - ?> ?=([@ @ *] path) - =/ =wire - (welp /fine/bide path) - =+ blk=(de-path:balk path) - ?> ?=(%c van.blk) - =/ [des=desk spr=spur] - ?^ spr.blk spr.blk - [%$ ~] - =+ ;;(=care:clay car.blk) - =/ =rave:clay - [%sing care cas.blk spr] - (emit duct %pass wire %c %warp her.blk des `rave) - :: - ++ on-take-clay-bide - |= [=wire =riot:clay] - ?> ?=([%fine %bide @ *] wire) - =/ pax=path t.t.wire - =/ cas=(unit (cask)) - ?~ riot ~ - `[p q.q]:r.u.riot - =/ =song - (encode-response pax (fall cas ~)) - %- emit - [unix-duct.ames-state %give %howl pax song] - :: ++ on-take-wake |= [=wire error=(unit tang)] ^+ event-core From 72851e0ae7c23da1a73be890a05925dea932153b Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 15 Apr 2022 16:42:53 -0500 Subject: [PATCH 098/168] vere: strip out notifications system --- pkg/urbit/include/c/motes.h | 2 - pkg/urbit/vere/io/ames.c | 82 ------------------------------------- 2 files changed, 84 deletions(-) diff --git a/pkg/urbit/include/c/motes.h b/pkg/urbit/include/c/motes.h index 5b92c6a1d..ce34ca9c6 100644 --- a/pkg/urbit/include/c/motes.h +++ b/pkg/urbit/include/c/motes.h @@ -74,7 +74,6 @@ # define c3__ber c3_s3('b','e','r') # define c3__bias c3_s4('b','i','a','s') # define c3__bic c3_s3('b','i','c') -# define c3__bide c3_s4('b','i','d', 'e') # define c3__bind c3_s4('b','i','n','d') # define c3__bink c3_s4('b','i','n','k') # define c3__bird c3_s4('b','i','r','d') @@ -557,7 +556,6 @@ # define c3__hop c3_s3('h','o','p') # define c3__hosc c3_s4('h','o','s','c') # define c3__hose c3_s4('h','o','s','e') -# define c3__howl c3_s4('h','o','w','l') # define c3__hrul c3_s4('h','r','u','l') # define c3__hsbn c3_s4('h','s','b','n') # define c3__hsbr c3_s4('h','s','b','r') diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index b69c7a779..0d2e3a631 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -12,7 +12,6 @@ typedef struct _u3_fine { c3_y ver_y; // fine protocol u3p(u3h_root) sac_p; // scry cache hashtable - u3p(u3h_root) bid_p; // pending notifications struct _u3_ames* sam_u; // ames backpointer } u3_fine; @@ -1012,52 +1011,6 @@ _fine_lane_scry_cb(void* vod_p, u3_noun nun) u3z(nun); } -/* _fine_ef_howl(): broadcast notification of newly bound data - */ -static void -_fine_ef_howl(u3_ames* sam_u, u3_noun pax, u3_noun lis) -{ - u3_noun pas = lis; - - // put packets in cache - _fine_put_cache(sam_u, pax, pas); - - - // iterate over subscribers, sending immediately if we have the lane - // else, scry for a lane - u3_weak who = u3h_get(sam_u->fin_s.bid_p, pax); - if ( who == u3_none ) { - u3l_log("no listeners\n"); - } else { - u3_noun her = u3qdi_tap(who); - u3_noun him = her; // original ref for counting - - while ( her != u3_nul ) { - - u3_weak lac = _ames_lane_from_cache(sam_u->lax_p, u3h(her)); - - u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); - pac_u->sam_u = sam_u; - - _fine_got_pack(pac_u, u3h(lis)); - if ( lac == u3_none ) { - u3l_log("no lane\n"); - u3_noun pax = _lane_scry_path(u3k(u3h(her))); - u3_pier_peek_last(sam_u->pir_u, u3_nul, c3__ax, - u3_nul, pax, pac_u, _fine_lane_scry_cb); - } else { - c3_d lan_d = u3r_chub(0, lac); - pac_u->lan_u.pip_w = (c3_w)lan_d; - pac_u->lan_u.por_s = (c3_s)(lan_d >> 32); - - _fine_send(pac_u); - } - - her = u3t(her); - } - u3z(him); - } -} /* _ames_ef_send(): send packet to network (v4). */ @@ -1453,30 +1406,6 @@ static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) u3z(fra); } -static void _fine_bide(u3_pact* pac_u, u3_noun pax) -{ - u3_ames* sam_u = pac_u->sam_u; - u3_weak set = u3h_get(sam_u->fin_s.bid_p, pax); - - if ( u3_none == set ) { - set = u3_nul; - } - - u3_noun her = u3i_chubs(2, pac_u->req_u.pre_u.sen_d); - u3_noun new = u3qdi_put(set, her); - - u3h_put(sam_u->fin_s.bid_p, pax, new); - - u3_noun cad = u3nc(c3__bide, pax); - u3_noun wir = u3nc(c3__fine, u3_nul); - u3_ovum* ovo_u = u3_ovum_init(0, c3__ames, u3k(wir), u3k(cad)); - u3_auto_plan(&sam_u->car_u, ovo_u); - - u3z(wir); - u3z(cad); -} - - /* _fine_pack_scry_cb(): receive all packets for datum out of fine */ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) @@ -1488,7 +1417,6 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); if(pas == u3_none) { - _fine_bide(pac_u, u3k(pax)); _ames_pact_free(pac_u); u3z(pax); @@ -2075,13 +2003,6 @@ _ames_kick_newt(u3_ames* sam_u, u3_noun tag, u3_noun dat) _ames_ef_turf(sam_u, u3k(dat)); ret_o = c3y; } break; - - case c3__howl: { - u3_noun pat = u3k(u3h(dat)); - u3_noun lis = u3k(u3t(dat)); - _fine_ef_howl(sam_u, pat, lis); - ret_o = c3y; - } break; case c3__hoot: { u3_noun lan = u3k(u3h(dat)); @@ -2250,9 +2171,6 @@ u3_ames_io_init(u3_pier* pir_u) // 50 bytes (average) per path * 100_000 = 5MB sam_u->fin_s.sac_p = u3h_new_cache(100000); - // hashtable for notificatiosn - sam_u->fin_s.bid_p = u3h_new_cache(100000); - //NOTE some numbers on memory usage for the lane cache // // assuming we store: From 8a3ec4a8d86a0af9ee96c6bc04517a05cf5b9916 Mon Sep 17 00:00:00 2001 From: Liam Fitzgerald Date: Fri, 15 Apr 2022 16:54:43 -0500 Subject: [PATCH 099/168] urbit: lull@328K, zuse@417K --- bin/solid.pill | 4 ++-- pkg/arvo/sys.kelvin | 2 +- pkg/arvo/sys/lull.hoon | 2 +- pkg/arvo/sys/zuse.hoon | 2 +- pkg/urbit/vere/pier.c | 5 +++-- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/bin/solid.pill b/bin/solid.pill index 4c71cce06..16e0cba4e 100644 --- a/bin/solid.pill +++ b/bin/solid.pill @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d324c1f4f09abe156de814718fc603c2faef65d8866182bf5135929bc69182c7 -size 9868510 +oid sha256:3389f55cb7ba166add7504d8352d56f73eaa395e334f44e68a69482f551df5b6 +size 9975110 diff --git a/pkg/arvo/sys.kelvin b/pkg/arvo/sys.kelvin index e68acb6a4..b7bcb9ecd 100644 --- a/pkg/arvo/sys.kelvin +++ b/pkg/arvo/sys.kelvin @@ -1 +1 @@ -[%zuse 419] +[%zuse 417] diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index b95290010..e0444599f 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -4,7 +4,7 @@ => ..part ~% %lull ..part ~ |% -++ lull %330 +++ lull %328 :: :: :: :::: :: :: (1) models :: :: :: diff --git a/pkg/arvo/sys/zuse.hoon b/pkg/arvo/sys/zuse.hoon index 0ce27b70b..8a8ef0c2d 100644 --- a/pkg/arvo/sys/zuse.hoon +++ b/pkg/arvo/sys/zuse.hoon @@ -4,7 +4,7 @@ => ..lull ~% %zuse ..part ~ |% -++ zuse %419 +++ zuse %417 :: :: :: :::: :: :: (2) engines :: :: :: diff --git a/pkg/urbit/vere/pier.c b/pkg/urbit/vere/pier.c index 48ba9e0b7..46a11bbf5 100644 --- a/pkg/urbit/vere/pier.c +++ b/pkg/urbit/vere/pier.c @@ -686,7 +686,8 @@ _pier_wyrd_fail(u3_pier* pir_u, u3_ovum* egg_u, u3_noun lud) // XX organizing version constants // #define VERE_NAME "vere" -#define VERE_ZUSE 419 +#define VERE_ZUSE 417 +#define VERE_LULL 328 /* _pier_wyrd_aver(): check for %wend effect and version downgrade. RETAIN */ @@ -822,7 +823,7 @@ _pier_wyrd_card(u3_pier* pir_u) u3dc("scot", c3__ta, u3i_string(URBIT_VERSION)), u3_nul); u3_noun kel = u3nl(u3nc(c3__zuse, VERE_ZUSE), // XX from both king and serf? - u3nc(c3__lull, 330), // XX define + u3nc(c3__lull, VERE_LULL), // XX define u3nc(c3__arvo, 240), // XX from both king and serf? u3nc(c3__hoon, 140), // god_u->hon_y u3nc(c3__nock, 4), // god_u->noc_y From 12ca0f45e573aae29aaf3a055f531037b001ce14 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 20 Apr 2022 00:09:00 +0200 Subject: [PATCH 100/168] ames: move various types and gates into lull So that userspace may also en- and decode (scry) packets. --- pkg/arvo/sys/lull.hoon | 194 +++++++++++++++++++++++++++++++++++ pkg/arvo/sys/vane/ames.hoon | 197 +----------------------------------- 2 files changed, 195 insertions(+), 196 deletions(-) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 76b5bdb8a..7a17f4984 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1153,6 +1153,9 @@ ++ com |~(a=pass ^?(..nu)) :: from pass -- ::nu :: -- ::acru :: + :: +protocol-version: current version of the ames wire protocol + :: + ++ protocol-version `?(%0 %1 %2 %3 %4 %5 %6 %7)`%0 :: $address: opaque atomic transport address to or from unix :: +$ address @uxaddress @@ -1194,6 +1197,25 @@ +$ song (list purr) :: full response :: :: +| %kinetics + :: $dyad: pair of sender and receiver ships + :: + +$ dyad [sndr=ship rcvr=ship] + :: $packet: noun representation of an ames datagram packet + :: + :: Roundtrips losslessly through atom encoding and decoding. + :: + :: .origin is ~ unless the packet is being forwarded. If present, + :: it's an atom that encodes a route to another ship, such as an IPv4 + :: address. Routes are opaque to Arvo and only have meaning in the + :: interpreter. This enforces that Ames is transport-agnostic. + :: + +$ packet + $: dyad + sndr-tick=@ubC + rcvr-tick=@ubC + origin=(unit @uxaddress) + content=@uxcontent + == :: $ack: positive ack, nack packet, or nack trace :: +$ ack @@ -1287,6 +1309,14 @@ siz=@ud byts == + +$ peep :: request data + $: =path + num=@ud + == + +$ twit :: signed request + $: signature=@ + peep + == :: $qos: quality of service; how is our connection to a peer doing? :: :: .last-contact: last time we heard from peer, or if %unborn, when @@ -1465,6 +1495,170 @@ num-received=fragment-num fragments=(map fragment-num fragment) == + :: $rank: which kind of ship address, by length + :: + :: 0b0: galaxy or star -- 2 bytes + :: 0b1: planet -- 4 bytes + :: 0b10: moon -- 8 bytes + :: 0b11: comet -- 16 bytes + :: + +$ rank ?(%0b0 %0b1 %0b10 %0b11) + :: + :: +| %coding + :: +decode-ship-size: decode a 2-bit ship type specifier into a byte width + :: + :: Type 0: galaxy or star -- 2 bytes + :: Type 1: planet -- 4 bytes + :: Type 2: moon -- 8 bytes + :: Type 3: comet -- 16 bytes + :: + ++ decode-ship-size + |= rank=@ubC + ^- @ + :: + ?+ rank !! + %0b0 2 + %0b1 4 + %0b10 8 + %0b11 16 + == + :: +is-valid-rank: does .ship match its stated .size? + :: + ++ is-valid-rank + |= [=ship size=@ubC] + ^- ? + .= size + =/ wid (met 3 ship) + ?: (lte wid 1) 2 + ?: =(2 wid) 2 + ?: (lte wid 4) 4 + ?: (lte wid 8) 8 + ?> (lte wid 16) 16 + :: +decode-packet: deserialize packet from bytestream or crash + :: + ++ decode-packet + |= =blob + ^- [ames=? =packet] + ~| %decode-packet-fail + :: first 32 (2^5) bits are header; the rest is body + :: + =/ header (end 5 blob) + =/ body (rsh 5 blob) + :: read header; first three bits are reserved + :: + =/ is-ames (cut 0 [3 1] header) + :- =(& is-ames) + :: + =/ version (cut 0 [4 3] header) + ?. =(protocol-version version) + ~& [%ames-protocol-version protocol-version version] + ~| ames-protocol-version+version !! + :: + =/ sndr-size (decode-ship-size (cut 0 [7 2] header)) + =/ rcvr-size (decode-ship-size (cut 0 [9 2] header)) + =/ checksum (cut 0 [11 20] header) + =/ relayed (cut 0 [31 1] header) + :: origin, if present, is 6 octets long, at the end of the body + :: + =^ origin=(unit @) body + ?: =(| relayed) + [~ body] + =/ len (sub (met 3 body) 6) + [`(end [3 6] body) (rsh [3 6] body)] + :: .checksum does not apply to the origin + :: + ?. =(checksum (end [0 20] (mug body))) + ~& >>> %ames-checksum + ~| %ames-checksum !! + :: read fixed-length sndr and rcvr life data from body + :: + :: These represent the last four bits of the sender and receiver + :: life fields, to be used for quick dropping of honest packets to + :: or from the wrong life. + :: + =/ sndr-tick (cut 0 [0 4] body) + =/ rcvr-tick (cut 0 [4 4] body) + :: read variable-length .sndr and .rcvr addresses + :: + =/ off 1 + =^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)] + ?. (is-valid-rank sndr sndr-size) + ~& >>> [%ames-sender-imposter sndr sndr-size] + ~| ames-sender-impostor+[sndr sndr-size] !! + :: + =^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)] + ?. (is-valid-rank rcvr rcvr-size) + ~& >>> [%ames-receiver-imposter rcvr rcvr-size] + ~| ames-receiver-impostor+[rcvr rcvr-size] !! + :: read variable-length .content from the rest of .body + :: + =/ content (cut 3 [off (sub (met 3 body) off)] body) + [[sndr rcvr] sndr-tick rcvr-tick origin content] + :: + ++ decode-request + |= =hoot + ^- twit + :- sig=(cut 3 [0 64] hoot) + -:(decode-request-info (rsh 3^64 hoot)) + :: + ++ decode-request-info + |= =hoot + ^- [=peep =purr] + =+ num=(cut 3 [0 4] hoot) + =+ len=(cut 3 [4 2] hoot) + =+ pat=(cut 3 [6 len] hoot) + :- [(stab pat) num] + :: if there is data remaining, it's the response + (rsh [3 (add 6 len)] hoot) + :: +encode-packet: serialize a packet into a bytestream + :: + ++ encode-packet + |= [ames=? packet] + ^- blob + :: + =/ sndr-meta (encode-ship-metadata sndr) + =/ rcvr-meta (encode-ship-metadata rcvr) + :: + =/ body=@ + ;: mix + sndr-tick + (lsh 2 rcvr-tick) + (lsh 3 sndr) + (lsh [3 +(size.sndr-meta)] rcvr) + (lsh [3 +((add size.sndr-meta size.rcvr-meta))] content) + == + =/ checksum (end [0 20] (mug body)) + =? body ?=(^ origin) (mix u.origin (lsh [3 6] body)) + :: + =/ header=@ + %+ can 0 + :~ [3 reserved=0] + [1 is-ames=ames] + [3 protocol-version] + [2 rank.sndr-meta] + [2 rank.rcvr-meta] + [20 checksum] + [1 relayed=.?(origin)] + == + (mix header (lsh 5 body)) + :: + :: +encode-ship-metadata: produce size (in bytes) and address rank for .ship + :: + :: 0: galaxy or star + :: 1: planet + :: 2: moon + :: 3: comet + :: + ++ encode-ship-metadata + |= =ship + ^- [size=@ =rank] + :: + =/ size=@ (met 3 ship) + :: + ?: (lte size 2) [2 %0b0] + ?: (lte size 4) [4 %0b1] + ?: (lte size 8) [8 %0b10] + [16 %0b11] -- ::ames :: :::: :::: ++behn :: (1b) timekeeping diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index ed0a2acf0..464639f81 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -90,10 +90,7 @@ :: - sending packets: +on-plea -> +make-peer-core (make a function kind of like +on-memo) -> call +on-pump-send kind of like how +run-message-pump does :: (assuming as event, scry just stateless) :: -:: protocol-version: current version of the ames wire protocol -:: !: -=/ protocol-version=?(%0 %1 %2 %3 %4 %5 %6 %7) %0 =, ames =* point point:jael =* public-keys-result public-keys-result:jael @@ -253,53 +250,6 @@ =. private-key (rsh 8 (rsh 3 private-key)) :: `@`(shar:ed:crypto public-key private-key) -:: +encode-packet: serialize a packet into a bytestream -:: -++ encode-packet - |= [ames=? packet] - ^- blob - :: - =/ sndr-meta (encode-ship-metadata sndr) - =/ rcvr-meta (encode-ship-metadata rcvr) - :: - =/ body=@ - ;: mix - sndr-tick - (lsh 2 rcvr-tick) - (lsh 3 sndr) - (lsh [3 +(size.sndr-meta)] rcvr) - (lsh [3 +((add size.sndr-meta size.rcvr-meta))] content) - == - =/ checksum (end [0 20] (mug body)) - =? body ?=(^ origin) (mix u.origin (lsh [3 6] body)) - :: - =/ header=@ - %+ can 0 - :~ [3 reserved=0] - [1 is-ames=ames] - [3 protocol-version] - [2 rank.sndr-meta] - [2 rank.rcvr-meta] - [20 checksum] - [1 relayed=.?(origin)] - == - (mix header (lsh 5 body)) -:: -++ decode-request - |= =hoot - ^- twit - :- sig=(cut 3 [0 64] hoot) - -:(decode-request-info (rsh 3^64 hoot)) -:: -++ decode-request-info - |= =hoot - ^- [=peep =purr] - =+ num=(cut 3 [0 4] hoot) - =+ len=(cut 3 [4 2] hoot) - =+ pat=(cut 3 [6 len] hoot) - :- [(stab pat) num] - :: if there is data remaining, it's the response - (rsh [3 (add 6 len)] hoot) :: ++ decode-response-packet |= =purr @@ -326,74 +276,6 @@ ?~ dat ~ ~| [%fine %response-not-cask] ;;((cask) (cue dat)) -:: +decode-packet: deserialize packet from bytestream or crash -:: -++ decode-packet - |= =blob - ^- [ames=? =packet] - ~| %decode-packet-fail - :: first 32 (2^5) bits are header; the rest is body - :: - =/ header (end 5 blob) - =/ body (rsh 5 blob) - :: read header; first three bits are reserved - :: - =/ is-ames (cut 0 [3 1] header) - :- =(& is-ames) - :: - =/ version (cut 0 [4 3] header) - ?. =(protocol-version version) - ~| ames-protocol-version+version !! - :: - =/ sndr-size (decode-ship-size (cut 0 [7 2] header)) - =/ rcvr-size (decode-ship-size (cut 0 [9 2] header)) - =/ checksum (cut 0 [11 20] header) - =/ relayed (cut 0 [31 1] header) - :: origin, if present, is 6 octets long, at the end of the body - :: - =^ origin=(unit @) body - ?: =(| relayed) - [~ body] - =/ len (sub (met 3 body) 6) - [`(end [3 6] body) (rsh [3 6] body)] - :: .checksum does not apply to the origin - :: - ?. =(checksum (end [0 20] (mug body))) - ~| %ames-checksum !! - :: read fixed-length sndr and rcvr life data from body - :: - :: These represent the last four bits of the sender and receiver - :: life fields, to be used for quick dropping of honest packets to - :: or from the wrong life. - :: - =/ sndr-tick (cut 0 [0 4] body) - =/ rcvr-tick (cut 0 [4 4] body) - :: read variable-length .sndr and .rcvr addresses - :: - =/ off 1 - =^ sndr off [(cut 3 [off sndr-size] body) (add off sndr-size)] - ?. (is-valid-rank sndr sndr-size) - ~| ames-sender-impostor+[sndr sndr-size] !! - :: - =^ rcvr off [(cut 3 [off rcvr-size] body) (add off rcvr-size)] - ?. (is-valid-rank rcvr rcvr-size) - ~| ames-receiver-impostor+[rcvr rcvr-size] !! - :: read variable-length .content from the rest of .body - :: - =/ content (cut 3 [off (sub (met 3 body) off)] body) - [[sndr rcvr] sndr-tick rcvr-tick origin content] -:: +is-valid-rank: does .ship match its stated .size? -:: -++ is-valid-rank - |= [=ship size=@ubC] - ^- ? - .= size - =/ wid (met 3 ship) - ?: (lte wid 1) 2 - ?: =(2 wid) 2 - ?: (lte wid 4) 4 - ?: (lte wid 8) 8 - ?> (lte wid 16) 16 :: +welt: like +weld but first argument is reversed :: TODO: move to hoon.hoon ++ welt @@ -486,52 +368,10 @@ =/ vec ~[sndr.packet rcvr.packet sndr-life rcvr-life] ;; shut-packet %- cue %- need (~(de sivc:aes:crypto (shaz symmetric-key) vec) siv len cyf) -:: +decode-ship-size: decode a 2-bit ship type specifier into a byte width -:: -:: Type 0: galaxy or star -- 2 bytes -:: Type 1: planet -- 4 bytes -:: Type 2: moon -- 8 bytes -:: Type 3: comet -- 16 bytes -:: -++ decode-ship-size - |= rank=@ubC - ^- @ - :: - ?+ rank !! - %0b0 2 - %0b1 4 - %0b10 8 - %0b11 16 - == -:: +encode-ship-metadata: produce size (in bytes) and address rank for .ship -:: -:: 0: galaxy or star -:: 1: planet -:: 2: moon -:: 3: comet -:: -++ encode-ship-metadata - |= =ship - ^- [size=@ =rank] - :: - =/ size=@ (met 3 ship) - :: - ?: (lte size 2) [2 %0b0] - ?: (lte size 4) [4 %0b1] - ?: (lte size 8) [8 %0b10] - [16 %0b11] +| %atomics :: +$ private-key @uwprivatekey +$ signature @uwsignature -:: $rank: which kind of ship address, by length -:: -:: 0b0: galaxy or star -- 2 bytes -:: 0b1: planet -- 4 bytes -:: 0b10: moon -- 8 bytes -:: 0b11: comet -- 16 bytes -:: -+$ rank ?(%0b0 %0b1 %0b10 %0b11) +$ byuts [wid=@ud dat=@ux] :: +| %kinetics @@ -553,25 +393,6 @@ =her=public-key her-sponsor=ship == == -:: $dyad: pair of sender and receiver ships -:: -+$ dyad [sndr=ship rcvr=ship] -:: $packet: noun representation of an ames datagram packet -:: -:: Roundtrips losslessly through atom encoding and decoding. -:: -:: .origin is ~ unless the packet is being forwarded. If present, -:: it's an atom that encodes a route to another ship, such as an IPv4 -:: address. Routes are opaque to Arvo and only have meaning in the -:: interpreter. This enforces that Ames is transport-agnostic. -:: -+$ packet - $: dyad - sndr-tick=@ubC - rcvr-tick=@ubC - origin=(unit @uxaddress) - content=@uxcontent - == :: $open-packet: unencrypted packet payload, for comet self-attestation :: :: This data structure gets signed and jammed to form the .contents @@ -687,22 +508,6 @@ -- -- :: -+$ twit :: signed request - $: signature=@ - peep - == -:: -+$ peep :: request data - $: =path - num=@ud - == -:: -+$ rawr :: response packet ::TODO meow - $: sig=@ - siz=@ud - byts - == -:: +$ roar :: response message $: sig=@ dat=$@(~ (cask)) @@ -1286,7 +1091,7 @@ -- :: |per-event: inner event-handling core :: -~% %per-event ..decode-packet ~ +~% %per-event ..trace ~ |% ++ per-event =| moves=(list move) From a2cab5274213e07caff0e76599d40547169cfa4e Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 20 Apr 2022 00:12:32 +0200 Subject: [PATCH 101/168] aqua: minimum viable remote scry support Includes a dumb test for -keen. --- pkg/arvo/app/aqua.hoon | 42 ++++++++++++++++++++++++++++++++++ pkg/arvo/ted/aqua/ames.hoon | 8 ++++++- pkg/arvo/ted/ph/keen.hoon | 13 +++++++++++ pkg/base-dev/sur/aquarium.hoon | 1 + 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 pkg/arvo/ted/ph/keen.hoon diff --git a/pkg/arvo/app/aqua.hoon b/pkg/arvo/app/aqua.hoon index ca79352a2..3e8fa52cb 100644 --- a/pkg/arvo/app/aqua.hoon +++ b/pkg/arvo/app/aqua.hoon @@ -46,6 +46,7 @@ event-log=(list unix-timed-event) next-events=(qeu unix-event) processing-events=? + namespace=(map path song:ames) == -- :: @@ -223,6 +224,16 @@ :: :: Peek :: + ++ peek-once + |= [=view =desk =spur] + =/ res (mox +22.snap) + ?> ?=(%0 -.res) + =/ peek p.res + =/ pek (slum peek [[~ ~] %| %once view desk spur]) + =+ ;;(res=(unit (cask [path (cask)])) pek) + ::NOTE it's an %omen, so we unpack a little bit deeper + (bind res (cork tail (cork tail tail))) + :: ++ peek |= p=* =/ res (mox +22.snap) @@ -648,6 +659,37 @@ =. this thus (publish-effect:(pe who) [/ %restore ~]) (pe ~bud) :: XX why ~bud? need an example + :: + %read + ?~ pier=(~(get by ships.piers) from.ae) + (pe from.ae) + =/ cash (~(get by namespace.u.pier) path.ae) + |- + ?^ cash + ?: (gth num.ae (lent u.cash)) + (pe from.ae) + ::TODO depends on /ted/aqua/ames behavior in a weird indirect way + =/ for=@p `@`(tail for.ae) ::NOTE moons & comets not supported + =; task=task-arvo + ^$(ae [%event for /a/aqua/fine-response task], thus this) + :+ %hear `lane:ames`[%| `@`from.ae] + ^- blob:ames + =/ [amp=? =packet:ames] + ::NOTE dec is important! so dumb!! + (decode-packet:ames `@`(snag (dec num.ae) u.cash)) + ::TODO runtime needs to update rcvr field also + ::NOTE rcvr life is allowed to be wrong + (encode-packet:ames amp packet(sndr from.ae, rcvr for)) + =/ pacs=(unit song:ames) + %+ biff + (peek-once:(pe from.ae) %ax %$ [%fine %message path.ae]) + (soft song:ames) + ?~ pacs (pe from.ae) + =. namespace.u.pier + (~(put by namespace.u.pier) path.ae u.pacs) + =. ships.piers + (~(put by ships.piers) from.ae u.pier) + $(cash pacs, thus this) :: %event ~? &(aqua-debug=| !?=(?(%belt %hear) -.q.ue.ae)) diff --git a/pkg/arvo/ted/aqua/ames.hoon b/pkg/arvo/ted/aqua/ames.hoon index 80125cbc7..0c917f15b 100644 --- a/pkg/arvo/ted/aqua/ames.hoon +++ b/pkg/arvo/ted/aqua/ames.hoon @@ -21,10 +21,16 @@ [%event who [/a/newt/0v1n.2m9vh %born ~]]~ :: ++ handle-send - |= [our=ship now=@da sndr=@p way=wire %send lan=lane:ames pac=@] + =, ames + |= [our=ship now=@da sndr=@p way=wire %send lan=lane pac=@] ^- (list card:agent:gall) =/ rcvr=ship (lane-to-ship lan) =/ hear-lane (ship-to-lane sndr) + =/ [ames=? =packet] (decode-packet pac) + ?: &(!ames !resp==(& (cut 0 [2 1] pac))) + =/ [=peep =purr] (decode-request-info `@ux`(rsh 3^64 content.packet)) + %+ emit-aqua-events our + [%read [rcvr path.peep] [hear-lane num.peep]]~ %+ emit-aqua-events our [%event rcvr /a/newt/0v1n.2m9vh %hear hear-lane pac]~ :: +lane-to-ship: decode a ship from an aqua lane diff --git a/pkg/arvo/ted/ph/keen.hoon b/pkg/arvo/ted/ph/keen.hoon new file mode 100644 index 000000000..dead5bf60 --- /dev/null +++ b/pkg/arvo/ted/ph/keen.hoon @@ -0,0 +1,13 @@ +/- spider +/+ *ph-io +=, strand=strand:spider +^- thread:spider +|= vase +=/ m (strand ,vase) +;< ~ bind:m start-simple +;< ~ bind:m (init-ship ~bud &) +;< ~ bind:m (init-ship ~dev &) +;< ~ bind:m (dojo ~bud "-keen /cx/~dev/kids/1/desk/bill") +;< ~ bind:m (wait-for-output ~bud "[ ~") +;< ~ bind:m end +(pure:m *vase) diff --git a/pkg/base-dev/sur/aquarium.hoon b/pkg/base-dev/sur/aquarium.hoon index 96b29f700..60ca5fd29 100644 --- a/pkg/base-dev/sur/aquarium.hoon +++ b/pkg/base-dev/sur/aquarium.hoon @@ -41,6 +41,7 @@ [%pause-events who=ship] [%snap-ships lab=term hers=(list ship)] [%restore-snap lab=term] + [%read [from=ship =path] [for=lane:ames num=@ud]] [%event who=ship ue=unix-event] == :: From e4014a41b95364a39810fa3fbbdfedcb1631fb81 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 3 May 2022 15:57:00 +0200 Subject: [PATCH 102/168] vere: trim trialing whitespace --- pkg/urbit/vere/io/ames.c | 46 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/pkg/urbit/vere/io/ames.c b/pkg/urbit/vere/io/ames.c index 0d2e3a631..eca001bda 100644 --- a/pkg/urbit/vere/io/ames.c +++ b/pkg/urbit/vere/io/ames.c @@ -65,7 +65,7 @@ c3_l mug_l; // truncated mug hash of u3_body c3_o rel_o; // relayed? } u3_head; - + /* u3_prel: ames/fine packet prelude */ typedef struct _u3_prel { @@ -88,7 +88,7 @@ /* u3_resp: fine packet response */ typedef struct _u3_resp { u3_prel pre_u; - // request: + // request: c3_w fra_w; // fragment number c3_s len_s; // path length c3_c* pat_c; // path as ascii @@ -160,7 +160,7 @@ _ames_alloc(uv_handle_t* had_u, } static void -_ames_pact_free(u3_pact* pac_u) +_ames_pact_free(u3_pact* pac_u) { if ( 0 == pac_u->typ_y ) { // ames packet } else if ( 1 == pac_u->typ_y ) { // fine request @@ -228,7 +228,7 @@ static void _log_requ(u3_requ* req_u) return; } -static void +static void _log_bytes(c3_y* byt_y, c3_w len_w) { int i; @@ -360,7 +360,7 @@ _ames_sift_prelude(u3_head* hed_u, /* _fine_sift_requ(): parse request body, returning success */ -static c3_o +static c3_o _fine_sift_requ(u3_head* hed_u, u3_requ* req_u, c3_w len_w, @@ -401,11 +401,11 @@ _fine_sift_requ(u3_head* hed_u, memcpy(req_u->pat_c, req_y, req_u->len_s); req_u->pat_c[req_u->len_s] = '\0'; return c3y; -} +} /* _fine_sift_resp(): parse response body, returning success */ -static c3_o +static c3_o _fine_sift_resp(u3_head* hed_u, u3_resp* res_u, c3_w len_w, @@ -516,7 +516,7 @@ _ames_etch_head(u3_head* hed_u, c3_y buf_y[4]) /* _ames_etch_prelude(): serialize packet prelude */ static c3_y -_ames_etch_prelude(u3_head* hed_u, u3_prel* pre_u, c3_y* buf_y) +_ames_etch_prelude(u3_head* hed_u, u3_prel* pre_u, c3_y* buf_y) { c3_y rog_y = ( c3y == hed_u->rel_o ) ? 6 : 0; // origin len c3_y sen_y = 2 << pre_u->sic_y; @@ -526,7 +526,7 @@ _ames_etch_prelude(u3_head* hed_u, u3_prel* pre_u, c3_y* buf_y) // copy lives buf_y[0] = (pre_u->sic_y & 0xf) ^ ((pre_u->ric_y & 0xf) << 4); - + _ames_ship_of_chubs(pre_u->sen_d, sen_y, buf_y + 1); _ames_ship_of_chubs(pre_u->rec_d, rec_y, buf_y + 1 + sen_y); @@ -564,7 +564,7 @@ _fine_etch_resp(u3_head* hed_u, memcpy(pac_y + sen_y + 6, res_u->pat_c, res_u->len_s); memcpy(pac_y + sen_y + 6 + res_u->len_s, &res_u->sig_y, 64 + 4 + 4 + 2); - + return len_w; } @@ -955,7 +955,7 @@ _ames_czar(u3_pact* pac_u) /* _fine_put_cache(): put list of packets into cache */ static void -_fine_put_cache(u3_ames* sam_u, u3_noun pax, u3_noun lis) +_fine_put_cache(u3_ames* sam_u, u3_noun pax, u3_noun lis) { u3_noun beg = lis; @@ -1032,7 +1032,7 @@ _ames_ef_send(u3_ames* sam_u, u3_noun lan, u3_noun pac) u3_head hed_u; _ames_sift_head(&hed_u, pac_u->hun_y); - pac_u->typ_y = + pac_u->typ_y = hed_u.sim_o == c3y ? 0 : hed_u.req_o == c3y ? 1 : 2; @@ -1396,11 +1396,11 @@ _ames_skip(u3_body* bod_u) { } #endif -static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) +static void _fine_got_pack(u3_pact* pac_u, u3_noun fra) { pac_u->len_w = u3r_met(3, fra); pac_u->hun_y = c3_calloc(pac_u->len_w); - + u3r_bytes(0, pac_u->len_w, pac_u->hun_y, fra); u3z(fra); @@ -1414,7 +1414,7 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) u3_pact* pac_u = vod_p; u3_ames* sam_u = pac_u->sam_u; u3_weak pas = u3r_at(7, nun); - u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); + u3_noun pax = u3do("stab", u3i_string(pac_u->req_u.pat_c)); if(pas == u3_none) { _ames_pact_free(pac_u); @@ -1426,7 +1426,7 @@ static void _fine_pack_scry_cb(void* vod_p, u3_noun nun) c3_assert( 1 == pac_u->typ_y ); u3_weak fra = u3_none; _fine_put_cache(sam_u, pax, pas); - + c3_w cur_w = 1; // find requested fragment @@ -1462,7 +1462,7 @@ static void _fine_hear_response(u3_ames* sam_u, c3_w num_w = res_u.num_w; c3_w fra_w = res_u.fra_w; - u3_noun cad = u3nt(c3__hear, + u3_noun cad = u3nt(c3__hear, u3nc(c3n, u3_ames_encode_lane(lan_u)), u3i_bytes(len_w, hun_y)); @@ -1525,9 +1525,9 @@ static void _fine_hear_request(u3_ames* sam_u, u3i_string("message"), u3k(u3t(pat))); - u3_pier_peek_last(sam_u->car_u.pir_u, u3_nul, c3__ax, u3_nul, + u3_pier_peek_last(sam_u->car_u.pir_u, u3_nul, c3__ax, u3_nul, pax, pac_u, _fine_pack_scry_cb); - + } else { _fine_got_pack(pac_u, u3k(cac)); _fine_send(pac_u); @@ -1581,7 +1581,7 @@ _fine_request(u3_ames* sam_u, u3_pact* pac_u = c3_calloc(sizeof(*pac_u)); u3_head* hed_u = c3_calloc(sizeof(*hed_u)); u3_requ* req_u = c3_calloc(sizeof(*req_u)); - + c3_w req_w = u3r_met(3, req); c3_y* req_y = c3_calloc(req_w); u3r_bytes(0, req_w, req_y, req); @@ -1642,7 +1642,7 @@ _ames_hear(u3_ames* sam_u, // // c3_o is_ames_o = _ames_sift_head(&pac_u->hed_u, hun_y); - + if (4 > len_w) { sam_u->sat_u.hed_d++; if ( 0 == (sam_u->sat_u.hed_d % 100000) ) { @@ -1664,7 +1664,7 @@ _ames_hear(u3_ames* sam_u, _ames_lane_into_cache(sam_u->lax_p, her, las); } - + if (c3n == is_ames_o) { _fine_hear(sam_u, *lan_u, len_w, hun_y); return; @@ -2166,7 +2166,7 @@ u3_ames_io_init(u3_pier* pir_u) sam_u->fig_u.fit_o = c3n; // hashtable for scry cache - // + // // 1500 bytes per packet * 100_000 = 150MB // 50 bytes (average) per path * 100_000 = 5MB sam_u->fin_s.sac_p = u3h_new_cache(100000); From d5dca99ba8cf34deb8433feb744e377a9aaa6549 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 5 May 2022 16:53:39 +0200 Subject: [PATCH 103/168] clay: scry for files by lobe Instead of scrying for revisions of files at paths in desks, we now scry for data corresponding to a given lobe. This removes concerns of aeons, paths, and other such frivolities, and lets us ask for the specific data we need regardless of where it may live. How we're supposed to answer permissioning questions around data this way remains to be seen. --- pkg/arvo/sys/vane/clay.hoon | 83 +++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index dd9e9dbfc..739f41fa1 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -325,7 +325,7 @@ =rave scry=(unit @da) :: if scry, timeout have=(map lobe fell) - need=(list $@(lobe [=aeon =path =lobe])) :: opt deets for scry + need=(list lobe) nako=(qeu (unit nako)) busy=_| == @@ -1503,13 +1503,11 @@ (emit duct %pass wire %a %plea ship %c path `riff-any`[%1 riff]) :: ++ send-over-scry - |= [kind=@ta =duct =ship index=@ud =desk =mood] + |= [kind=@ta =duct =ship index=@ud =desk =path] ^- [timeout=@da _..send-over-scry] =/ =time (add now scry-timeout-time) =/ =wire (request-wire kind ship desk index) - =/ =path - =, mood - [%c care (scot case) desk path] + =. path [%c path] ~& scrying/path^index :- time %- emil @@ -1572,7 +1570,8 @@ =* inx nix.u.ref =^ time=@da +>+.$ =< ?>(?=(^ ref) .) - (send-over-scry %warp-index hen her inx syd mood.rave) + =/ =path =,(mood.rave [care (scot case) syd path]) + (send-over-scry %warp-index hen her inx syd path) %= +>+.$ nix.u.ref +(nix.u.ref) bom.u.ref (~(put by bom.u.ref) inx [hen rave `time ~ ~ ~ |]) @@ -3267,41 +3266,32 @@ work ?> ?=(%nako p.r.u.rut) =/ nako ;;(nako q.r.u.rut) - =. need.sat (welp need.sat (missing-lobes nako)) + =/ missing (missing-lobes nako) + =. need.sat (welp need.sat ~(tap in missing)) =. nako.sat (~(put to nako.sat) ~ nako) work :: ++ missing-lobes |= =nako - =| miss=(set lobe) - ^- (list [aeon path lobe]) + ^- (set lobe) + =| missing=(set lobe) =/ yakis ~(tap in lar.nako) - |- ^- (list [aeon path lobe]) + |- ^- (set lobe) =* yaki-loop $ ?~ yakis - ~ + missing =/ =norm (~(gut by tom.dom) r.i.yakis nor.dom) =/ lobes=(list [=path =lobe]) ~(tap by q.i.yakis) - |- ^- (list [aeon path lobe]) - =* blob-loop $ + |- ^- (set lobe) + =* lobe-loop $ ?~ lobes yaki-loop(yakis t.yakis) - =* lobe lobe.i.lobes - ?: ?| (~(has by lat.ran) lobe) - =([~ %|] (~(fit of norm) path.i.lobes)) - (~(has in miss) lobe) + =? missing + ?& !(~(has by lat.ran) lobe.i.lobes) + !=([~ %|] (~(fit of norm) path.i.lobes)) == - blob-loop(lobes t.lobes) - =; =aeon - :- [aeon i.lobes] - blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) - :: find the aeon corresponding to the commit containing this lobe. - :: we unfortunately do not have a reverse lookup map. - :: - =/ l=(list [a=aeon t=tako]) ~(tap by gar.nako) - |- - ?~ l ~|([%missing-aeon-for-tako her syd `@uw`r.i.yakis] !!) - ?:(=(r.i.yakis t.i.l) a.i.l $(l t.l)) + (~(put in missing) lobe.i.lobes) + lobe-loop(lobes t.lobes) :: :: Receive backfill response :: @@ -3341,30 +3331,23 @@ :: another desk updating concurrently, or a previous update on this :: same desk). :: - =/ =lobe - ?@ i.need.sat i.need.sat - lobe.i.need.sat - ?: ?| (~(has by lat.ran) lobe) - (~(has by have.sat) lobe) - == + =* lobe i.need.sat + ?: (~(has by lat.ran) lobe) $(need.sat t.need.sat) :: otherwise, fetch the next blob (aka fell) :: =^ time=(unit @da) ..foreign-update =< ?>(?=(^ ref) .) - :: if we know a revision & path for the blob, - :: and :ship's remote scry isn't known to be broken, + :: if :ship's remote scry isn't known to be broken, :: or we learned it was broken more than an hour ago, :: - ?: ?& ?=(^ i.need.sat) - ?| !(~(has by sad) her) + ?: ?| !(~(has by sad) her) (gth now (add scry-retry-time (~(got by sad) her))) - == == + == :: make the request over remote scry :: - =/ =mood - [%x ud+aeon path]:i.need.sat - [`- +]:(send-over-scry %back-index hen her inx syd mood) + =/ =path /x/0//lobe/(scot %uv i.need.sat) + [`- +]:(send-over-scry %back-index hen her inx syd path) :: otherwise, request over ames :: :- ~ @@ -4931,7 +4914,6 @@ %= update-state-10 |2 :- `(unit @da)`~ - ^- [(map lobe fell) (list $@(lobe [aeon path lobe])) (qeu (unit nako)) _|] %= |2.update-state-10 nako %- ~(gas to *(qeu (unit nako))) @@ -5036,6 +5018,8 @@ ::TODO if it ever gets filled properly, pass in the full fur. :: =/ for=(unit ship) ?~(lyc ~ ?~(u.lyc ~ `n.u.lyc)) + ?: &(=(%x ren) =(%$ syd) =([%ud 0] u.luk)) + (read-buc-public u.run tyl) ?: &(=(our his) =(%x ren) =(%$ syd) =([%da now] u.luk)) (read-buc u.run tyl) =/ den ((de now rof [/scryduct ~] ruf) his syd) @@ -5045,6 +5029,16 @@ ~ p.result :: + ++ read-buc-public + |= [=care =path] + ^- (unit (unit cage)) + ?+ path ~ + [%lobe @ ~] + ?~ hash=(slaw %uv i.t.path) ~ + ?~ page=(~(get by lat.ran.ruf) u.hash) ~ + ``[%page !>(u.page)] + == + :: ++ read-buc |= [=care =path] ^- (unit (unit cage)) @@ -5270,7 +5264,8 @@ =/ fell=(unit fell) ?: ?=(%boon +<.hin) `;;(fell payload.hin) ?~ data.hin ~ - `[%direct (page-to-lobe u.data.hin) u.data.hin] + ?> =(%page p.u.data.hin) + `[%direct (page-to-lobe u.data.hin) ;;(page q.u.data.hin)] :: =^ mos ruf =/ den ((de now rof hen ruf) her desk) From 80958c70a052544b9eda0c80bda7bf004d361293 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 9 May 2022 17:20:02 +0200 Subject: [PATCH 104/168] Revert "clay: scry for files by lobe" This reverts commit d5dca99ba8cf34deb8433feb744e377a9aaa6549. --- pkg/arvo/sys/vane/clay.hoon | 83 ++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 739f41fa1..dd9e9dbfc 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -325,7 +325,7 @@ =rave scry=(unit @da) :: if scry, timeout have=(map lobe fell) - need=(list lobe) + need=(list $@(lobe [=aeon =path =lobe])) :: opt deets for scry nako=(qeu (unit nako)) busy=_| == @@ -1503,11 +1503,13 @@ (emit duct %pass wire %a %plea ship %c path `riff-any`[%1 riff]) :: ++ send-over-scry - |= [kind=@ta =duct =ship index=@ud =desk =path] + |= [kind=@ta =duct =ship index=@ud =desk =mood] ^- [timeout=@da _..send-over-scry] =/ =time (add now scry-timeout-time) =/ =wire (request-wire kind ship desk index) - =. path [%c path] + =/ =path + =, mood + [%c care (scot case) desk path] ~& scrying/path^index :- time %- emil @@ -1570,8 +1572,7 @@ =* inx nix.u.ref =^ time=@da +>+.$ =< ?>(?=(^ ref) .) - =/ =path =,(mood.rave [care (scot case) syd path]) - (send-over-scry %warp-index hen her inx syd path) + (send-over-scry %warp-index hen her inx syd mood.rave) %= +>+.$ nix.u.ref +(nix.u.ref) bom.u.ref (~(put by bom.u.ref) inx [hen rave `time ~ ~ ~ |]) @@ -3266,32 +3267,41 @@ work ?> ?=(%nako p.r.u.rut) =/ nako ;;(nako q.r.u.rut) - =/ missing (missing-lobes nako) - =. need.sat (welp need.sat ~(tap in missing)) + =. need.sat (welp need.sat (missing-lobes nako)) =. nako.sat (~(put to nako.sat) ~ nako) work :: ++ missing-lobes |= =nako - ^- (set lobe) - =| missing=(set lobe) + =| miss=(set lobe) + ^- (list [aeon path lobe]) =/ yakis ~(tap in lar.nako) - |- ^- (set lobe) + |- ^- (list [aeon path lobe]) =* yaki-loop $ ?~ yakis - missing + ~ =/ =norm (~(gut by tom.dom) r.i.yakis nor.dom) =/ lobes=(list [=path =lobe]) ~(tap by q.i.yakis) - |- ^- (set lobe) - =* lobe-loop $ + |- ^- (list [aeon path lobe]) + =* blob-loop $ ?~ lobes yaki-loop(yakis t.yakis) - =? missing - ?& !(~(has by lat.ran) lobe.i.lobes) - !=([~ %|] (~(fit of norm) path.i.lobes)) + =* lobe lobe.i.lobes + ?: ?| (~(has by lat.ran) lobe) + =([~ %|] (~(fit of norm) path.i.lobes)) + (~(has in miss) lobe) == - (~(put in missing) lobe.i.lobes) - lobe-loop(lobes t.lobes) + blob-loop(lobes t.lobes) + =; =aeon + :- [aeon i.lobes] + blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) + :: find the aeon corresponding to the commit containing this lobe. + :: we unfortunately do not have a reverse lookup map. + :: + =/ l=(list [a=aeon t=tako]) ~(tap by gar.nako) + |- + ?~ l ~|([%missing-aeon-for-tako her syd `@uw`r.i.yakis] !!) + ?:(=(r.i.yakis t.i.l) a.i.l $(l t.l)) :: :: Receive backfill response :: @@ -3331,23 +3341,30 @@ :: another desk updating concurrently, or a previous update on this :: same desk). :: - =* lobe i.need.sat - ?: (~(has by lat.ran) lobe) + =/ =lobe + ?@ i.need.sat i.need.sat + lobe.i.need.sat + ?: ?| (~(has by lat.ran) lobe) + (~(has by have.sat) lobe) + == $(need.sat t.need.sat) :: otherwise, fetch the next blob (aka fell) :: =^ time=(unit @da) ..foreign-update =< ?>(?=(^ ref) .) - :: if :ship's remote scry isn't known to be broken, + :: if we know a revision & path for the blob, + :: and :ship's remote scry isn't known to be broken, :: or we learned it was broken more than an hour ago, :: - ?: ?| !(~(has by sad) her) + ?: ?& ?=(^ i.need.sat) + ?| !(~(has by sad) her) (gth now (add scry-retry-time (~(got by sad) her))) - == + == == :: make the request over remote scry :: - =/ =path /x/0//lobe/(scot %uv i.need.sat) - [`- +]:(send-over-scry %back-index hen her inx syd path) + =/ =mood + [%x ud+aeon path]:i.need.sat + [`- +]:(send-over-scry %back-index hen her inx syd mood) :: otherwise, request over ames :: :- ~ @@ -4914,6 +4931,7 @@ %= update-state-10 |2 :- `(unit @da)`~ + ^- [(map lobe fell) (list $@(lobe [aeon path lobe])) (qeu (unit nako)) _|] %= |2.update-state-10 nako %- ~(gas to *(qeu (unit nako))) @@ -5018,8 +5036,6 @@ ::TODO if it ever gets filled properly, pass in the full fur. :: =/ for=(unit ship) ?~(lyc ~ ?~(u.lyc ~ `n.u.lyc)) - ?: &(=(%x ren) =(%$ syd) =([%ud 0] u.luk)) - (read-buc-public u.run tyl) ?: &(=(our his) =(%x ren) =(%$ syd) =([%da now] u.luk)) (read-buc u.run tyl) =/ den ((de now rof [/scryduct ~] ruf) his syd) @@ -5029,16 +5045,6 @@ ~ p.result :: - ++ read-buc-public - |= [=care =path] - ^- (unit (unit cage)) - ?+ path ~ - [%lobe @ ~] - ?~ hash=(slaw %uv i.t.path) ~ - ?~ page=(~(get by lat.ran.ruf) u.hash) ~ - ``[%page !>(u.page)] - == - :: ++ read-buc |= [=care =path] ^- (unit (unit cage)) @@ -5264,8 +5270,7 @@ =/ fell=(unit fell) ?: ?=(%boon +<.hin) `;;(fell payload.hin) ?~ data.hin ~ - ?> =(%page p.u.data.hin) - `[%direct (page-to-lobe u.data.hin) ;;(page q.u.data.hin)] + `[%direct (page-to-lobe u.data.hin) u.data.hin] :: =^ mos ruf =/ den ((de now rof hen ruf) her desk) From bb7e74c1e971a3aa64203820b86703a6495c6807 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 11 May 2022 16:16:03 +0200 Subject: [PATCH 105/168] arvo: add %uv hash case to scry paths Clay desparately wants something like this. It helps answer questions around hash-based content fetching. --- pkg/arvo/sys/arvo.hoon | 3 +++ pkg/arvo/sys/lull.hoon | 1 + pkg/arvo/sys/vane/clay.hoon | 1 + 3 files changed, 5 insertions(+) diff --git a/pkg/arvo/sys/arvo.hoon b/pkg/arvo/sys/arvo.hoon index 6de32dbb9..0f8d01915 100644 --- a/pkg/arvo/sys/arvo.hoon +++ b/pkg/arvo/sys/arvo.hoon @@ -39,10 +39,12 @@ $% :: %da: date :: %tas: label :: %ud: sequence + :: %uv: hash :: [%da p=@da] [%tas p=@tas] [%ud p=@ud] + [%uv p=@uv] == +$ cage (cask vase) ++ cask |$ [a] (pair mark a) @@ -313,6 +315,7 @@ ^- (unit case) ?^ num=(slaw %ud knot) `[%ud u.num] ?^ wen=(slaw %da knot) `[%da u.wen] + ?^ hax=(slaw %uv knot) `[%uv u.hax] ?~ lab=(slaw %tas knot) ~ `[%tas u.lab] :: diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 0573f6d0f..2fc62350a 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -1754,6 +1754,7 @@ $% [%da p=@da] :: date [%tas p=@tas] :: label [%ud p=@ud] :: number + [%uv p=@uv] :: hash == :: +$ cash :: case or tako $% [%tako p=tako] :: diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index dd9e9dbfc..4f2f4e965 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -1451,6 +1451,7 @@ ?- -.lok %tas (~(get by lab.dom) p.lok) %ud ?:((gth p.lok let.dom) ~ [~ p.lok]) + %uv ?~(yak=(~(get by hut.ran) p.lok) ~ $(lok [%da t.u.yak])) %da ?: (gth p.lok lim) ~ |- ^- (unit aeon) From 5549071649ad163b645112513cb8c5c5e0a9717b Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 11 May 2022 20:25:48 +0200 Subject: [PATCH 106/168] clay: do reads by tako, not by aeon This corresponds more closely to how clay actually works/stores data. --- pkg/arvo/sys/vane/clay.hoon | 227 ++++++++++++++++++------------------ 1 file changed, 116 insertions(+), 111 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 4f2f4e965..568ef59ad 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -6,7 +6,7 @@ :: the entire contents of +raft. :: :: - Individual reads. +aver is the entry point, follow it through -:: +read-at-aeon to understand each kind of read. +:: +read-at-tako to understand each kind of read. :: :: - Subscriptions. +wake is the center of this mechanism; nothing :: else responds to subscriptions. +wake has no arguments, which means @@ -1374,11 +1374,11 @@ ?~ let.dom !>([0 *@da]) !>([let.dom t:(~(got by hut.ran) (~(got by hit.dom) let.dom))]) - =+ nao=(case-to-aeon case.mun) + =+ tak=(case-to-tako case.mun) ?: ?=([%s case %case ~] mun) :: case existence check - [``[%flag !>(!=(~ nao))] ..park] - ?~(nao [~ ..park] (read-at-aeon:ze for u.nao mun)) + [``[%flag !>(!=(~ tak))] ..park] + ?~(tak [~ ..park] (read-at-tako:ze for u.tak mun)) :: :: Queue a move. :: @@ -1451,7 +1451,7 @@ ?- -.lok %tas (~(get by lab.dom) p.lok) %ud ?:((gth p.lok let.dom) ~ [~ p.lok]) - %uv ?~(yak=(~(get by hut.ran) p.lok) ~ $(lok [%da t.u.yak])) + %uv `(tako-to-aeon:ze p.lok) %da ?: (gth p.lok lim) ~ |- ^- (unit aeon) @@ -1466,22 +1466,29 @@ $(let.dom (dec let.dom)) == :: + ++ case-to-tako + |= lok=case + ^- (unit tako) + ?: ?=(%uv -.lok) + ?:((~(has by hut.ran) p.lok) `p.lok ~) + (bind (case-to-aeon-before lim lok) aeon-to-tako:ze) + :: :: Create a ford appropriate for the aeon :: :: Don't forget to call +aeon-flow! :: - ++ aeon-ford - |= yon=aeon + ++ tako-ford + |= tak=tako %- ford:fusion - =/ files (~(run by q:(aeon-to-yaki:ze yon)) |=(=lobe |+lobe)) - [files lat.ran fad ?:(=(yon let.dom) fod.dom [~ ~])] + =/ files (~(run by q:(tako-to-yaki:ze tak)) |=(=lobe |+lobe)) + [files lat.ran fad ?:(=(tak (aeon-to-tako:ze let.dom)) fod.dom [~ ~])] :: Produce ford cache appropriate for the aeon :: - ++ aeon-flow - |* [yon=aeon res=* fud=flow fod=flue] + ++ tako-flow + |* [tak=tako res=* fud=flow fod=flue] :- res ^+ ..park - ?: &(?=(~ ref) =(let.dom yon)) + ?: &(?=(~ ref) =((aeon-to-tako:ze let.dom) tak)) ..park(fad fud, fod.dom fod) :: if in the past, don't update ford cache, since any results have :: no roots @@ -2632,7 +2639,7 @@ ~ =/ [=cage *] %- wrap:fusion - (page-to-cage:(aeon-ford let.dom) u.peg) + (page-to-cage:(tako-ford (~(got by hit.dom) let.dom)) u.peg) `cage :: ++ get-dais @@ -2640,7 +2647,7 @@ ^- dais =/ [=dais *] %- wrap:fusion - (build-dais:(aeon-ford let.dom) mark) + (build-dais:(tako-ford (~(got by hit.dom) let.dom)) mark) dais :: :: Diff two files on bob-desk @@ -3195,7 +3202,9 @@ :: foreign marks :: =/ base-dome dom:(~(got by dos.rom) %base) - =/ f (%*(. aeon-ford dom base-dome) let.base-dome) + =/ f + %- %*(. tako-ford dom base-dome) + (~(got by hit.base-dome) let.base-dome) (page-to-cage:f peg) ?: ?=(%| -.vale-result) %- (slog >%validate-x-failed< p.vale-result) @@ -3533,20 +3542,20 @@ (writ ?~(u.cache-value ~ `[mood.rov u.u.cache-value])) :: else, check to see if rove is for an aeon we know :: - =/ aeon=(unit aeon) (case-to-aeon case.mood.rov) - ?~ aeon + =/ tako=(unit tako) (case-to-tako case.mood.rov) + ?~ tako [[`rov ~] ..park] - :: we have the appropriate aeon, so read in the data + :: we have the appropriate tako, so read in the data :: =^ value=(unit (unit cage)) ..park - (read-at-aeon:ze for u.aeon mood.rov) + (read-at-tako:ze for u.tako mood.rov) ?~ value :: we don't have the data directly. how can we fetch it? :: - ?: =(0 u.aeon) + ?: =(0v0 u.tako) ~& [%clay-sing-indirect-data-0 `path`[syd '0' path.mood.rov]] [[~ ~] ..park] - ~& [%clay-sing-indirect-data desk=syd mood=mood.rov aeon=u.aeon] + ~& [%clay-sing-indirect-data desk=syd mood=mood.rov tako=u.tako] [[`rov ~] ..park] :: we have the data, so produce the results :: @@ -3803,6 +3812,16 @@ ++ aeon-to-yaki |=(=aeon (tako-to-yaki (aeon-to-tako aeon))) ++ tako-to-yaki ~(got by hut.ran) :: + ++ tako-to-aeon + |= tak=tako + ^- aeon ~+ + ?: =(0v0 tak) 0 + =/ a=aeon 1 + |- + ?: (gth a let.dom) ~|([%tako-mia tak] !!) + ?: (~(has in (reachable-takos (~(got by hit.dom) a))) tak) a + $(a +(a)) + :: :: Creates a nako of all the changes between a and b. :: ++ make-nako @@ -3855,68 +3874,68 @@ :: ++ read-a !. - |= [=aeon =path] + |= [=tako =path] ^- [(unit (unit cage)) _..park] =^ =vase ..park - ~_ leaf/"clay: %a build failed {<[syd aeon path]>}" - %+ aeon-flow aeon + ~_ leaf/"clay: %a build failed {<[syd tako path]>}" + %+ tako-flow tako %- wrap:fusion - (build-file:(aeon-ford aeon) path) + (build-file:(tako-ford tako) path) :_(..park [~ ~ %vase !>(vase)]) :: ++ read-b !. - |= [=aeon =path] + |= [=tako =path] ^- [(unit (unit cage)) _..park] ?. ?=([@ ~] path) [[~ ~] ..park] =^ =dais ..park - %+ aeon-flow aeon + %+ tako-flow tako %- wrap:fusion - (build-dais:(aeon-ford aeon) i.path) + (build-dais:(tako-ford tako) i.path) :_(..park [~ ~ %dais !>(dais)]) :: ++ read-c !. - |= [=aeon =path] + |= [=tako =path] ^- [(unit (unit cage)) _..park] ?. ?=([@ @ ~] path) [[~ ~] ..park] =^ =tube ..park - %+ aeon-flow aeon + %+ tako-flow tako %- wrap:fusion - (build-tube:(aeon-ford aeon) [i i.t]:path) + (build-tube:(tako-ford tako) [i i.t]:path) :_(..park [~ ~ %tube !>(tube)]) :: ++ read-e !. - |= [=aeon =path] + |= [=tako =path] ^- [(unit (unit cage)) _..park] ?. ?=([@ ~] path) [[~ ~] ..park] =^ =vase ..park - %+ aeon-flow aeon + %+ tako-flow tako %- wrap:fusion - (build-nave:(aeon-ford aeon) i.path) + (build-nave:(tako-ford tako) i.path) :_(..park [~ ~ %nave vase]) :: ++ read-f !. - |= [=aeon =path] + |= [=tako =path] ^- [(unit (unit cage)) _..park] ?. ?=([@ @ ~] path) [[~ ~] ..park] =^ =vase ..park - %+ aeon-flow aeon + %+ tako-flow tako %- wrap:fusion - (build-cast:(aeon-ford aeon) [i i.t]:path) + (build-cast:(tako-ford tako) [i i.t]:path) :_(..park [~ ~ %cast vase]) :: :: XX move to +read-buc :: ++ read-d !. - |= [=aeon =path] + |= [=tako =path] ^- (unit (unit cage)) ?. =(our her) [~ ~] @@ -3954,7 +3973,7 @@ $(pax (scag (dec (lent pax)) `path`pax)) :: ++ may-read - |= [who=ship car=care yon=aeon pax=path] + |= [who=ship car=care tak=tako pax=path] ^- ? ?+ car (allowed-by who pax per.red) @@ -3963,9 +3982,7 @@ =(who our) :: ?(%y %z) - =+ tak=(~(get by hit.dom) yon) - ?~ tak | - =+ yak=(tako-to-yaki u.tak) + =+ yak=(tako-to-yaki tak) =+ len=(lent pax) =- (levy ~(tap in -) |=(p=path (allowed-by who p per.red))) %+ roll ~(tap in (~(del in ~(key by q.yak)) pax)) @@ -4018,9 +4035,9 @@ :: +read-r: %x wrapped in a vase :: ++ read-r - |= [yon=aeon pax=path] + |= [tak=tako pax=path] ^- [(unit (unit cage)) _..park] - =^ x ..park (read-x yon pax) + =^ x ..park (read-x tak pax) :_ ..park ?~ x ~ ?~ u.x [~ ~] @@ -4028,16 +4045,13 @@ :: +read-s: produce miscellaneous :: ++ read-s - |= [yon=aeon pax=path] + |= [tak=tako pax=path] ^- (unit (unit cage)) ?. ?=([@ * *] pax) `~ ?+ i.pax `~ %tako - =/ tak=(unit tako) (~(get by hit.dom) yon) - ?~ tak - ~ - ``tako+[-:!>(*tako) u.tak] + ``tako+[-:!>(*tako) tak] :: %yaki =/ yak=(unit yaki) (~(get by hut.ran) (slav %uv i.t.pax)) @@ -4066,10 +4080,10 @@ ~ =/ [=cage *] %- wrap:fusion - (page-to-cage:(aeon-ford yon) u.peg) + (page-to-cage:(tako-ford tak) u.peg) ``cage+[-:!>(*^cage) cage] :: - %open ``open+!>(prelude:(aeon-ford yon)) + %open ``open+!>(prelude:(tako-ford tak)) %late !! :: handled in +aver %case !! :: handled in +aver %base-tako @@ -4094,7 +4108,7 @@ =/ other dom:((de now rof hen ruf) him i.t.t.pax) ?: =(0 let.other) ~ - =/ our-yaki (~(got by hut.ran) (~(got by hit.dom) yon)) + =/ our-yaki (~(got by hut.ran) tak) =/ other-yaki (~(got by hut.ran) (~(got by hit.other) let.other)) %+ turn ~(tap in (find-merge-points other-yaki our-yaki)) |= =yaki @@ -4103,19 +4117,15 @@ :: +read-t: produce the list of paths within a yaki with :pax as prefix :: ++ read-t - |= [yon=aeon pax=path] + |= [tak=tako pax=path] ^- (unit (unit [%file-list (hypo (list path))])) :: if asked for version 0, produce an empty list of files :: - ?: =(0 yon) + ?: =(0v0 tak) ``[%file-list -:!>(*(list path)) *(list path)] - :: if asked for a future version, we don't have an answer - :: - ?~ tak=(~(get by hit.dom) yon) - ~ :: look up the yaki snapshot based on the version :: - =/ yak=yaki (tako-to-yaki u.tak) + =/ yak=yaki (tako-to-yaki tak) :: calculate the path length once outside the loop :: =/ path-length (lent pax) @@ -4137,19 +4147,15 @@ :: at any of its children. :: ++ read-u - |= [yon=aeon pax=path] + |= [tak=tako pax=path] ^- (unit (unit [%flag (hypo ?)])) :: if asked for version 0, that never exists, so always give false :: - ?: =(0 yon) + ?: =(0v0 tak) ``[%flag -:!>(*?) |] - :: if asked for a future version, we don't have an answer - :: - ?~ tak=(~(get by hit.dom) yon) - ~ :: look up the yaki snapshot based on the version :: - =/ yak=yaki (tako-to-yaki u.tak) + =/ yak=yaki (tako-to-yaki tak) :: produce the result based on whether or not there's a file at :pax :: ``[%flag -:!>(*?) (~(has by q.yak) pax)] @@ -4157,8 +4163,9 @@ :: Gets the dome (desk state) at a particular aeon. :: ++ read-v - |= [yon=aeon pax=path] + |= [tak=tako pax=path] ^- (unit (unit [%dome (hypo dome:clay)])) + =/ yon=aeon (tako-to-aeon:ze tak) ?: (lth yon let.dom) :* ~ ~ %dome -:!>(*dome:clay) ^- dome:clay @@ -4175,13 +4182,13 @@ :: For the %da case, we give just the canonical timestamp of the revision. :: ++ read-w - |= yon=aeon + |= tak=tako ^- (unit (unit cage)) =- [~ ~ %cass !>(-)] - ^- cass - :- yon - ?: =(0 yon) `@da`0 - t:(aeon-to-yaki yon) + ^- cass ::TODO should include %uv case + :- (tako-to-aeon tak) + ?: =(0v0 tak) `@da`0 + t:(tako-to-yaki tak) :: :: Get the data at a node. :: @@ -4189,14 +4196,11 @@ :: mark for bootstrapping purposes. :: ++ read-x - |= [yon=aeon pax=path] + |= [tak=tako pax=path] ^- [(unit (unit cage)) _..park] - ?: =(0 yon) + ?: =(0v0 tak) [[~ ~] ..park] - =+ tak=(~(get by hit.dom) yon) - ?~ tak - [~ ..park] - =+ yak=(tako-to-yaki u.tak) + =+ yak=(tako-to-yaki tak) =+ lob=(~(get by q.yak) pax) ?~ lob [[~ ~] ..park] @@ -4208,22 +4212,19 @@ :: should convert any lobe to cage :: =^ =cage ..park - %+ aeon-flow yon + %+ tako-flow tak %- wrap:fusion - (page-to-cage:(aeon-ford yon) u.peg) + (page-to-cage:(tako-ford tak) u.peg) [``cage ..park] :: :: Gets an arch (directory listing) at a node. :: ++ read-y - |= [yon=aeon pax=path] + |= [tak=tako pax=path] ^- (unit (unit [%arch (hypo arch)])) - ?: =(0 yon) + ?: =(0v0 tak) ``[%arch -:!>(*arch) *arch] - =+ tak=(~(get by hit.dom) yon) - ?~ tak - ~ - =+ yak=(tako-to-yaki u.tak) + =+ yak=(tako-to-yaki tak) =+ len=(lent pax) :^ ~ ~ %arch :: ~& cy+pax @@ -4244,14 +4245,11 @@ :: Gets a recursive hash of a node and all its children. :: ++ read-z - |= [yon=aeon pax=path] + |= [tak=tako pax=path] ^- (unit (unit [%uvi (hypo @uvI)])) - ?: =(0 yon) + ?: =(0v0 tak) ``uvi+[-:!>(*@uvI) *@uvI] - =+ tak=(~(get by hit.dom) yon) - ?~ tak - ~ - [~ ~ %uvi [%atom %'uvI' ~] (content-hash (tako-to-yaki u.tak) pax)] + [~ ~ %uvi [%atom %'uvI' ~] (content-hash (tako-to-yaki tak) pax)] :: :: Get a value at an aeon. :: @@ -4260,10 +4258,17 @@ :: meaning we either have the value directly or a content hash of the :: value. :: - ++ read-at-aeon :: read-at-aeon:ze - |= [for=(unit ship) yon=aeon mun=mood] :: seek and read + ++ read-at-tako :: read-at-tako:ze + |= [for=(unit ship) tak=tako mun=mood] :: seek and read ^- [(unit (unit cage)) _..park] - ?. |(?=(~ for) (may-read u.for care.mun yon path.mun)) + ?. |(?=(~ for) (may-read u.for care.mun tak path.mun)) + [~ ..park] + :: the commit must be known, and reachable from within this desk + :: + ?. ?| =(0v0 tak) + ?& (~(has by hut.ran) tak) + (~(has in (reachable-takos (aeon-to-tako:ze let.dom))) tak) + == == [~ ..park] :: virtualize to catch and produce deterministic failures :: @@ -4271,27 +4276,27 @@ |^ =/ res (mule |.(read)) ?: ?=(%& -.res) p.res %. [[~ ~] ..park] - (slog leaf+"clay: read-at-aeon fail {<[desk=syd mun]>}" p.res) + (slog leaf+"clay: read-at-tako fail {<[desk=syd mun]>}" p.res) :: ++ read ^- [(unit (unit cage)) _..park] ?- care.mun - %a (read-a yon path.mun) - %b (read-b yon path.mun) - %c (read-c yon path.mun) - %d [(read-d yon path.mun) ..park] - %e (read-e yon path.mun) - %f (read-f yon path.mun) + %a (read-a tak path.mun) + %b (read-b tak path.mun) + %c (read-c tak path.mun) + %d [(read-d tak path.mun) ..park] + %e (read-e tak path.mun) + %f (read-f tak path.mun) %p [(read-p path.mun) ..park] - %r (read-r yon path.mun) - %s [(read-s yon path.mun) ..park] - %t [(read-t yon path.mun) ..park] - %u [(read-u yon path.mun) ..park] - %v [(read-v yon path.mun) ..park] - %w [(read-w yon) ..park] - %x (read-x yon path.mun) - %y [(read-y yon path.mun) ..park] - %z [(read-z yon path.mun) ..park] + %r (read-r tak path.mun) + %s [(read-s tak path.mun) ..park] + %t [(read-t tak path.mun) ..park] + %u [(read-u tak path.mun) ..park] + %v [(read-v tak path.mun) ..park] + %w [(read-w tak) ..park] + %x (read-x tak path.mun) + %y [(read-y tak path.mun) ..park] + %z [(read-z tak path.mun) ..park] == -- -- From 9286fc93b1f486082c4b0d1e559d41ac9bb6bdc4 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 12 May 2022 00:39:02 +0200 Subject: [PATCH 107/168] clay: give tako 0v0 for aeon 0 The previous commit already started treating the 0v0 commit as equivalent to the 0 aeon (that is, never-real root), so we should give the 0v0 commit for all 0 aeons. --- pkg/arvo/sys/vane/clay.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 568ef59ad..2fc8c6940 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -3808,7 +3808,7 @@ :: These convert between aeon (version number), tako (commit hash), :: and yaki (commit data structure) :: - ++ aeon-to-tako ~(got by hit.dom) + ++ aeon-to-tako |=(=aeon ?:(=(0 aeon) 0v0 (~(got by hit.dom) aeon))) ++ aeon-to-yaki |=(=aeon (tako-to-yaki (aeon-to-tako aeon))) ++ tako-to-yaki ~(got by hut.ran) :: From 70aeb2a7c1016a71bb6948078d045eddffefd903 Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 12 May 2022 00:41:58 +0200 Subject: [PATCH 108/168] clay: treat %d scry on empty desk specially Similar to how %x on the empty desk was already treated specially. We continue supporting %d on non-empty desks, but do add a print marking it as deprecated. --- pkg/arvo/sys/vane/clay.hoon | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 2fc8c6940..e98427dc3 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -3937,6 +3937,7 @@ !. |= [=tako =path] ^- (unit (unit cage)) + ~& [%clay %d-on-desk-deprecated desk=syd %use-empty-desk] ?. =(our her) [~ ~] ?^ path @@ -5042,8 +5043,11 @@ ::TODO if it ever gets filled properly, pass in the full fur. :: =/ for=(unit ship) ?~(lyc ~ ?~(u.lyc ~ `n.u.lyc)) - ?: &(=(our his) =(%x ren) =(%$ syd) =([%da now] u.luk)) - (read-buc u.run tyl) + ?: &(=(our his) ?=(?(%d %x) ren) =(%$ syd) =([%da now] u.luk)) + ?- ren + %d (read-buc-d tyl) + %x (read-buc-x tyl) + == =/ den ((de now rof [/scryduct ~] ruf) his syd) =/ result (mule |.(-:(aver:den for u.run u.luk tyl))) ?: ?=(%| -.result) @@ -5051,8 +5055,14 @@ ~ p.result :: - ++ read-buc - |= [=care =path] + ++ read-buc-d + |= =path + ^- (unit (unit cage)) + ?^ path ~&(%no-cd-path [~ ~]) + [~ ~ %noun !>(~(key by dos.rom.ruf))] + :: + ++ read-buc-x + |= =path ^- (unit (unit cage)) ?~ path ~ From 0251b127e194cdc01bdd2a4460f9788c3f1eb2cf Mon Sep 17 00:00:00 2001 From: fang Date: Thu, 12 May 2022 17:14:55 +0200 Subject: [PATCH 109/168] clay: request files over scry by tako, not aeon --- pkg/arvo/sys/vane/clay.hoon | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index e98427dc3..bfaf284b5 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -325,7 +325,7 @@ =rave scry=(unit @da) :: if scry, timeout have=(map lobe fell) - need=(list $@(lobe [=aeon =path =lobe])) :: opt deets for scry + need=(list $@(lobe [=tako =path =lobe])) :: opt deets for scry nako=(qeu (unit nako)) busy=_| == @@ -3284,15 +3284,15 @@ ++ missing-lobes |= =nako =| miss=(set lobe) - ^- (list [aeon path lobe]) + ^- (list [tako path lobe]) =/ yakis ~(tap in lar.nako) - |- ^- (list [aeon path lobe]) + |- ^- (list [tako path lobe]) =* yaki-loop $ ?~ yakis ~ =/ =norm (~(gut by tom.dom) r.i.yakis nor.dom) =/ lobes=(list [=path =lobe]) ~(tap by q.i.yakis) - |- ^- (list [aeon path lobe]) + |- ^- (list [tako path lobe]) =* blob-loop $ ?~ lobes yaki-loop(yakis t.yakis) @@ -3302,16 +3302,8 @@ (~(has in miss) lobe) == blob-loop(lobes t.lobes) - =; =aeon - :- [aeon i.lobes] - blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) - :: find the aeon corresponding to the commit containing this lobe. - :: we unfortunately do not have a reverse lookup map. - :: - =/ l=(list [a=aeon t=tako]) ~(tap by gar.nako) - |- - ?~ l ~|([%missing-aeon-for-tako her syd `@uw`r.i.yakis] !!) - ?:(=(r.i.yakis t.i.l) a.i.l $(l t.l)) + :- [r.i.yakis i.lobes] + blob-loop(lobes t.lobes, miss (~(put in miss) lobe)) :: :: Receive backfill response :: @@ -3373,7 +3365,7 @@ :: make the request over remote scry :: =/ =mood - [%x ud+aeon path]:i.need.sat + [%x uv+tako path]:i.need.sat [`- +]:(send-over-scry %back-index hen her inx syd mood) :: otherwise, request over ames :: @@ -4938,7 +4930,7 @@ %= update-state-10 |2 :- `(unit @da)`~ - ^- [(map lobe fell) (list $@(lobe [aeon path lobe])) (qeu (unit nako)) _|] + ^- [(map lobe fell) (list $@(lobe [tako path lobe])) (qeu (unit nako)) _|] %= |2.update-state-10 nako %- ~(gas to *(qeu (unit nako))) From 9e3bcf14c1df58fbef3586b78ebbddc777605312 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 16 May 2022 22:52:07 +0200 Subject: [PATCH 110/168] fine: more straightforwardly cancel keen timer When +ke-abet-gone gets called, we're going to remove this keen entirely. +ke-set-wake does a whole song-and-dance and may even set a new timer. So instead, we simply call +ke-rest, if we have a known outstanding timer. --- pkg/arvo/sys/vane/ames.hoon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 6fe924a8f..80db00acd 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2641,7 +2641,8 @@ == :: ++ ke-abet-gone - =. ke-core ke-set-wake + =? ke-core ?=(^ next-wake.keen) + (ke-rest u.next-wake.keen) =. keens.scry +:(del:orm keens.scry keen-id) =. order.scry From 4848d58410a7a0091d426668a397b4d57479b62f Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 18 May 2022 00:30:31 +0200 Subject: [PATCH 111/168] clay: properly resume work when +retry-with-ames Previously, when the scry timeout fired and we retried the request with ames, we would always start over from the very first request (ie, fetching the ""manifest"" containing the files we need to download). This behavior is not correct in the case where we had already received that initial response, and were now fetching individual files. So here, if that's the case, we simply call into +work after marking this peer as having known-broken scry, which will resume work as appropriate. (The actual bug here that broke the fallback behavior entirely was the busy flag not getting unset. We now clean it up properly.) We also move setting of the sad timer into +retry-with-ames, instead of doing it at each individual callsite. (In fact, one of the callsites was missing this behavior.) --- pkg/arvo/sys/vane/clay.hoon | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index bfaf284b5..7ff715315 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -3083,11 +3083,14 @@ ~| [%strange-retry-no-request her syd inx] ?> ?=(^ ref) =/ sat=update-state (~(got by bom.u.ref) inx) + :: mark her as having broken scry comms + :: + =. sad (~(put by sad) her now) :: clean up scry request & timer :: =. ..retry-with-ames =< ?>(?=(^ ref) .) - ~| [%strange-retry-not-scry her syd inx scry.sat -.rave] + ~| [%strange-retry-not-scry her syd inx scry.sat -.rave.sat] ?> ?=(^ scry.sat) ?> ?=(%sing -.rave.sat) =/ =wire (request-wire kind her syd inx) @@ -3100,11 +3103,10 @@ == :: re-send over ames :: - =. ..retry-with-ames - =< ?>(?=(^ ref) .) + =. bom.u.ref (~(put by bom.u.ref) inx sat(scry ~, busy |)) + ?: =(%warp-index kind) (send-over-ames hen her inx syd `rave.sat) - =. bom.u.ref (~(put by bom.u.ref) inx sat(scry ~)) - ..retry-with-ames + abet:work:(foreign-update inx) :: :: Called when a foreign ship answers one of our requests. :: @@ -5249,7 +5251,6 @@ =/ index=@ud (slav %ud i.t.t.t.tea) ~& [%clay %scry-broken her] =^ mos ruf - =. sad.ruf (~(put by sad.ruf) her now) =/ den ((de now rof hen ruf) her desk) abet:(retry-with-ames:den %warp-index index) [mos ..^$] @@ -5294,7 +5295,6 @@ =/ =desk (slav %tas i.t.t.tea) =/ index=@ud (slav %ud i.t.t.t.tea) =^ mos ruf - =. sad.ruf (~(put by sad.ruf) her now) =/ den ((de now rof hen ruf) her desk) abet:(retry-with-ames:den %back-index index) [mos ..^$] From 2e6a7cfec8e0210008ef821545e6a7e07c8f037b Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 18 May 2022 15:21:26 +0200 Subject: [PATCH 112/168] clay: track pending (scry) requests better Instead of having a separate "busy" flag and pending scry request state, we now have a single "busy" unit that, if there is a pending request, contains details about the pending request. In the ames case, this is simply %ames. But in the scry case, it contains all the details we need to cancel the request, timer, or both when needed. Additionally, we now make sure to always cancel the scry timeout timer whenever we get a scry response. --- pkg/arvo/sys/vane/clay.hoon | 93 +++++++++++++++---------------------- 1 file changed, 38 insertions(+), 55 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 7ff715315..1d8c6d82d 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -323,11 +323,10 @@ +$ update-state $: =duct =rave - scry=(unit @da) :: if scry, timeout have=(map lobe fell) need=(list $@(lobe [=tako =path =lobe])) :: opt deets for scry nako=(qeu (unit nako)) - busy=_| + busy=(unit $@(%ames [kind=@ta =time =path])) :: pending request == :: :: Domestic ship. @@ -1512,23 +1511,27 @@ :: ++ send-over-scry |= [kind=@ta =duct =ship index=@ud =desk =mood] - ^- [timeout=@da _..send-over-scry] + ^- [[timeout=@da =path] _..send-over-scry] =/ =time (add now scry-timeout-time) =/ =wire (request-wire kind ship desk index) =/ =path =, mood [%c care (scot case) desk path] ~& scrying/path^index - :- time + :- [time path] %- emil :~ [hen %pass wire %a %keen ship path] [hen %pass wire %b %wait time] == :: - ++ cancel-scry-timeout ::TODO make arg order more consistent - |= [kind=@ta =duct =ship index=@ud =desk time=@da] - =/ =wire (request-wire kind ship desk index) - (emit duct %pass wire %b %rest time) + ++ cancel-scry-timeout + |= inx=@ud + ~| [%strange-timeout-cancel-no-scry-request her syd inx] + ?> ?=(^ ref) + =/ sat=update-state (~(got by bom.u.ref) inx) + ?> ?=([~ ^] busy.sat) + =/ =wire (request-wire kind.u.busy.sat her syd inx) + (emit hen %pass wire %b %rest time.u.busy.sat) :: ++ foreign-capable |= =rave @@ -1578,12 +1581,12 @@ ::TODO can be deduplicated with the below? :: =* inx nix.u.ref - =^ time=@da +>+.$ + =^ scry +>+.$ =< ?>(?=(^ ref) .) (send-over-scry %warp-index hen her inx syd mood.rave) %= +>+.$ nix.u.ref +(nix.u.ref) - bom.u.ref (~(put by bom.u.ref) inx [hen rave `time ~ ~ ~ |]) + bom.u.ref (~(put by bom.u.ref) inx [hen rave ~ ~ ~ `warp-index+scry]) fod.u.ref (~(put by fod.u.ref) hen inx) == :: @@ -1596,7 +1599,7 @@ (send-over-ames hen her inx syd `rave) %= +>+.$ nix.u.ref +(nix.u.ref) - bom.u.ref (~(put by bom.u.ref) inx [hen rave ~ ~ ~ ~ |]) + bom.u.ref (~(put by bom.u.ref) inx [hen rave ~ ~ ~ ~]) fod.u.ref (~(put by fod.u.ref) hen inx) == :: @@ -3031,27 +3034,13 @@ == :: cancel the request as appropriate :: - ?~ scry.sat + ?. ?=([~ ^] busy.sat) %. [hen her u.nux [syd ~]] send-over-ames(ref `(unit rind)`ref) :: XX TMI - =/ =path - ~| [%strange-scried-request rave.sat] - ?> ?=(%sing -.rave.sat) - =, mood.rave.sat - [(cat 3 %c care) (scot %p her) syd (scot case) path] %- emil - ::NOTE we don't know exactly which kind of request is exstant at - :: this time. or at least it seems very hard to find out. - :: so instead we simply emit the cancellation moves on both - :: possible wires. one will silently no-op, the other will - :: do what we want. this is ugly, but we should refactor the - :: separate flows eventually anyway. - =/ x=wire (request-wire %warp-index her syd u.nux) - =/ y=wire (request-wire %back-index her syd u.nux) - :~ [hen %pass x %a %yawn her path] - [hen %pass y %a %yawn her path] - [hen %pass x %b %rest u.scry.sat] - [hen %pass y %b %rest u.scry.sat] + =/ =wire (request-wire kind.u.busy.sat her syd u.nux) + :~ [hen %pass wire %a %yawn her path.u.busy.sat] + [hen %pass wire %b %rest time.u.busy.sat] == :: :: Handles a request. @@ -3090,20 +3079,17 @@ :: =. ..retry-with-ames =< ?>(?=(^ ref) .) - ~| [%strange-retry-not-scry her syd inx scry.sat -.rave.sat] - ?> ?=(^ scry.sat) - ?> ?=(%sing -.rave.sat) + ~| [%strange-retry-not-scry her syd inx busy.sat -.rave.sat] + ?> ?=([~ ^] busy.sat) =/ =wire (request-wire kind her syd inx) - =/ =path - =, mood.rave.sat - [(cat 3 %c care) (scot %p her) syd (scot case) path] + =/ =path path.u.busy.sat %- emil - :~ [hen %pass wire %b %rest u.scry.sat] + :~ [hen %pass wire %b %rest time.u.busy.sat] [hen %pass wire %a %yawn her path] == :: re-send over ames :: - =. bom.u.ref (~(put by bom.u.ref) inx sat(scry ~, busy |)) + =. bom.u.ref (~(put by bom.u.ref) inx sat(busy ~)) ?: =(%warp-index kind) (send-over-ames hen her inx syd `rave.sat) abet:work:(foreign-update inx) @@ -3125,9 +3111,6 @@ ?~ ruv ~& %bad-answer +>.$ - =? ..take-foreign-answer ?=(^ scry.u.ruv) - =< ?>(?=(^ ref) .) - (cancel-scry-timeout %warp-index hen her inx syd u.scry.u.ruv) =/ rav=rave rave.u.ruv ?: ?=(%many -.rav) abet:(apex:(foreign-update inx) rut) @@ -3251,12 +3234,7 @@ [u.ruv |] =/ done=? | =. hen duct.sat - :: if the request was done over scry, clear the timeout timer - :: - =? ..foreign-update ?=(^ scry.sat) - =< ?>(?=(^ ref) .) - (cancel-scry-timeout %back-index hen her inx syd u.scry.sat) - =. scry.sat ~ + =. busy.sat ~ |% ++ abet ^+ ..foreign-update @@ -3314,13 +3292,13 @@ ^+ ..abet ?: lost ..abet =. ..park =>((take-fell fell) ?>(?=(^ ref) .)) - work(busy.sat |) + work(busy.sat ~) :: :: Fetch next lobe :: ++ work ^+ ..abet - ?: busy.sat + ?. =(~ busy.sat) ::NOTE tmi ..abet |- ^+ ..abet ?~ need.sat @@ -3354,7 +3332,7 @@ $(need.sat t.need.sat) :: otherwise, fetch the next blob (aka fell) :: - =^ time=(unit @da) ..foreign-update + =^ scry=(unit [@ta @da path]) ..foreign-update =< ?>(?=(^ ref) .) :: if we know a revision & path for the blob, :: and :ship's remote scry isn't known to be broken, @@ -3366,9 +3344,9 @@ == == :: make the request over remote scry :: - =/ =mood - [%x uv+tako path]:i.need.sat - [`- +]:(send-over-scry %back-index hen her inx syd mood) + =/ =mood [%x uv+tako path]:i.need.sat + =< [`[%back-index -] +] + (send-over-scry %back-index hen her inx syd mood) :: otherwise, request over ames :: :- ~ @@ -3377,7 +3355,7 @@ :: TODO: upgrade to %1 when most ships have upgaded =/ =fill [%0 syd lobe] (emit hen %pass wire %a %plea her %c path fill) - ..abet(busy.sat &, scry.sat time) + ..abet(busy.sat ?~(scry `%ames scry)) :: :: When we get a %w foreign update, store this in our state. :: @@ -4931,9 +4909,10 @@ ^- update-state %= update-state-10 |2 - :- `(unit @da)`~ - ^- [(map lobe fell) (list $@(lobe [tako path lobe])) (qeu (unit nako)) _|] + ^- [(map lobe fell) (list $@(lobe [tako path lobe])) (qeu (unit nako)) (unit $@(%ames [@ta @da path]))] %= |2.update-state-10 + busy ?:(busy.update-state-10 `%ames ~) + :: nako %- ~(gas to *(qeu (unit nako))) %+ turn ~(tap to nako.update-state-10) @@ -5231,6 +5210,8 @@ =; res=(unit rand) ~& taking-foreign-answer/=(~ res) =/ den ((de now rof hen ruf) her desk) + =? den ?=(%tune +<.hin) + (cancel-scry-timeout:den index) abet:(take-foreign-answer:den index res) ?: ?=(%boon +<.hin) ;;((unit rand) payload.hin) %+ bind data.hin @@ -5285,6 +5266,8 @@ =/ den ((de now rof hen ruf) her desk) ?~ fell abet:(retry-with-ames:den %back-index index) + =? den ?=(%tune +<.hin) + (cancel-scry-timeout:den index) abet:abet:(take-backfill:(foreign-update:den index) u.fell) [mos ..^$] :: From 055f31dadababb5bd5be87d985b2ab03de558c92 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 18 May 2022 15:24:02 +0200 Subject: [PATCH 113/168] clay: set saner scry timeout & retry timers --- pkg/arvo/sys/vane/clay.hoon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 1d8c6d82d..d9f2ffe13 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -442,8 +442,8 @@ :: %utilities :: |% -++ scry-timeout-time ~s5 -++ scry-retry-time ~s30 +++ scry-timeout-time ~m1 +++ scry-retry-time ~m30 :: +sort-by-head: sorts alphabetically using the head of each element :: ++ sort-by-head From c1ce8bcec0bb5fa3d71f5f28bda5dc5163792b58 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 18 May 2022 16:17:19 +0200 Subject: [PATCH 114/168] clay: don't clear busy flag unnecessarily Not every +foreign-update call means we got a backfill response. Only +take-backfill does, and that already clears the busy flag. --- pkg/arvo/sys/vane/clay.hoon | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index d9f2ffe13..1b45d9e42 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -3234,7 +3234,6 @@ [u.ruv |] =/ done=? | =. hen duct.sat - =. busy.sat ~ |% ++ abet ^+ ..foreign-update From 842d76fe0d4805e6de04a6b3d16083b3f7abbf2c Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 18 May 2022 17:04:04 +0200 Subject: [PATCH 115/168] npm: remove tmp api files --- pkg/npm/api/tmp/contacts/index.d.ts | 2 - pkg/npm/api/tmp/contacts/index.js | 3 - pkg/npm/api/tmp/contacts/index.js.map | 1 - pkg/npm/api/tmp/contacts/lib.d.ts | 26 - pkg/npm/api/tmp/contacts/lib.js | 64 --- pkg/npm/api/tmp/contacts/lib.js.map | 1 - pkg/npm/api/tmp/contacts/types.d.ts | 61 --- pkg/npm/api/tmp/contacts/types.js | 2 - pkg/npm/api/tmp/contacts/types.js.map | 1 - pkg/npm/api/tmp/docket/index.d.ts | 2 - pkg/npm/api/tmp/docket/index.js | 3 - pkg/npm/api/tmp/docket/index.js.map | 1 - pkg/npm/api/tmp/docket/lib.d.ts | 15 - pkg/npm/api/tmp/docket/lib.js | 54 -- pkg/npm/api/tmp/docket/lib.js.map | 1 - pkg/npm/api/tmp/docket/types.d.ts | 106 ---- pkg/npm/api/tmp/docket/types.js | 2 - pkg/npm/api/tmp/docket/types.js.map | 1 - pkg/npm/api/tmp/graph/index.d.ts | 2 - pkg/npm/api/tmp/graph/index.js | 3 - pkg/npm/api/tmp/graph/index.js.map | 1 - pkg/npm/api/tmp/graph/lib.d.ts | 148 ------ pkg/npm/api/tmp/graph/lib.js | 380 ------------- pkg/npm/api/tmp/graph/lib.js.map | 1 - pkg/npm/api/tmp/graph/types.d.ts | 76 --- pkg/npm/api/tmp/graph/types.js | 2 - pkg/npm/api/tmp/graph/types.js.map | 1 - pkg/npm/api/tmp/groups/index.d.ts | 2 - pkg/npm/api/tmp/groups/index.js | 3 - pkg/npm/api/tmp/groups/index.js.map | 1 - pkg/npm/api/tmp/groups/lib.d.ts | 40 -- pkg/npm/api/tmp/groups/lib.js | 139 ----- pkg/npm/api/tmp/groups/lib.js.map | 1 - pkg/npm/api/tmp/groups/types.d.ts | 2 - pkg/npm/api/tmp/groups/types.js | 3 - pkg/npm/api/tmp/groups/types.js.map | 1 - pkg/npm/api/tmp/groups/update.d.ts | 133 ----- pkg/npm/api/tmp/groups/update.js | 2 - pkg/npm/api/tmp/groups/update.js.map | 1 - pkg/npm/api/tmp/groups/view.d.ts | 24 - pkg/npm/api/tmp/groups/view.js | 2 - pkg/npm/api/tmp/groups/view.js.map | 1 - pkg/npm/api/tmp/hark/index.d.ts | 2 - pkg/npm/api/tmp/hark/index.js | 3 - pkg/npm/api/tmp/hark/index.js.map | 1 - pkg/npm/api/tmp/hark/lib.d.ts | 46 -- pkg/npm/api/tmp/hark/lib.js | 100 ---- pkg/npm/api/tmp/hark/lib.js.map | 1 - pkg/npm/api/tmp/hark/types.d.ts | 55 -- pkg/npm/api/tmp/hark/types.js | 2 - pkg/npm/api/tmp/hark/types.js.map | 1 - pkg/npm/api/tmp/hood/index.d.ts | 2 - pkg/npm/api/tmp/hood/index.js | 3 - pkg/npm/api/tmp/hood/index.js.map | 1 - pkg/npm/api/tmp/hood/lib.d.ts | 34 -- pkg/npm/api/tmp/hood/lib.js | 97 ---- pkg/npm/api/tmp/hood/lib.js.map | 1 - pkg/npm/api/tmp/hood/types.d.ts | 145 ----- pkg/npm/api/tmp/hood/types.js | 2 - pkg/npm/api/tmp/hood/types.js.map | 1 - pkg/npm/api/tmp/index.d.ts | 22 - pkg/npm/api/tmp/index.js | 25 - pkg/npm/api/tmp/index.js.map | 1 - pkg/npm/api/tmp/invite/index.d.ts | 2 - pkg/npm/api/tmp/invite/index.js | 3 - pkg/npm/api/tmp/invite/index.js.map | 1 - pkg/npm/api/tmp/invite/lib.d.ts | 5 - pkg/npm/api/tmp/invite/lib.js | 18 - pkg/npm/api/tmp/invite/lib.js.map | 1 - pkg/npm/api/tmp/invite/types.d.ts | 54 -- pkg/npm/api/tmp/invite/types.js | 2 - pkg/npm/api/tmp/invite/types.js.map | 1 - .../api/tmp/lib/BigIntArrayOrderedMap.d.ts | 24 - pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js | 131 ----- .../api/tmp/lib/BigIntArrayOrderedMap.js.map | 1 - pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts | 20 - pkg/npm/api/tmp/lib/BigIntOrderedMap.js | 102 ---- pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map | 1 - pkg/npm/api/tmp/lib/index.d.ts | 2 - pkg/npm/api/tmp/lib/index.js | 3 - pkg/npm/api/tmp/lib/index.js.map | 1 - pkg/npm/api/tmp/lib/lib.d.ts | 33 -- pkg/npm/api/tmp/lib/lib.js | 207 -------- pkg/npm/api/tmp/lib/lib.js.map | 1 - pkg/npm/api/tmp/lib/types.d.ts | 42 -- pkg/npm/api/tmp/lib/types.js | 5 - pkg/npm/api/tmp/lib/types.js.map | 1 - pkg/npm/api/tmp/metadata/index.d.ts | 2 - pkg/npm/api/tmp/metadata/index.js | 3 - pkg/npm/api/tmp/metadata/index.js.map | 1 - pkg/npm/api/tmp/metadata/lib.d.ts | 15 - pkg/npm/api/tmp/metadata/lib.js | 69 --- pkg/npm/api/tmp/metadata/lib.js.map | 1 - pkg/npm/api/tmp/metadata/types.d.ts | 76 --- pkg/npm/api/tmp/metadata/types.js | 2 - pkg/npm/api/tmp/metadata/types.js.map | 1 - pkg/npm/api/tmp/s3/index.d.ts | 2 - pkg/npm/api/tmp/s3/index.js | 3 - pkg/npm/api/tmp/s3/index.js.map | 1 - pkg/npm/api/tmp/s3/lib.d.ts | 8 - pkg/npm/api/tmp/s3/lib.js | 24 - pkg/npm/api/tmp/s3/lib.js.map | 1 - pkg/npm/api/tmp/s3/types.d.ts | 41 -- pkg/npm/api/tmp/s3/types.js | 2 - pkg/npm/api/tmp/s3/types.js.map | 1 - pkg/npm/api/tmp/settings/index.d.ts | 2 - pkg/npm/api/tmp/settings/index.js | 3 - pkg/npm/api/tmp/settings/index.js.map | 1 - pkg/npm/api/tmp/settings/lib.d.ts | 21 - pkg/npm/api/tmp/settings/lib.js | 51 -- pkg/npm/api/tmp/settings/lib.js.map | 1 - pkg/npm/api/tmp/settings/types.d.ts | 52 -- pkg/npm/api/tmp/settings/types.js | 2 - pkg/npm/api/tmp/settings/types.js.map | 1 - pkg/npm/http-api/tmp/Urbit.d.ts | 183 ------- pkg/npm/http-api/tmp/Urbit.js | 497 ------------------ pkg/npm/http-api/tmp/Urbit.js.map | 1 - pkg/npm/http-api/tmp/index.d.ts | 3 - pkg/npm/http-api/tmp/index.js | 4 - pkg/npm/http-api/tmp/index.js.map | 1 - pkg/npm/http-api/tmp/types.d.ts | 180 ------- pkg/npm/http-api/tmp/types.js | 5 - pkg/npm/http-api/tmp/types.js.map | 1 - pkg/npm/http-api/tmp/utils.d.ts | 16 - pkg/npm/http-api/tmp/utils.js | 51 -- pkg/npm/http-api/tmp/utils.js.map | 1 - 126 files changed, 3851 deletions(-) delete mode 100644 pkg/npm/api/tmp/contacts/index.d.ts delete mode 100644 pkg/npm/api/tmp/contacts/index.js delete mode 100644 pkg/npm/api/tmp/contacts/index.js.map delete mode 100644 pkg/npm/api/tmp/contacts/lib.d.ts delete mode 100644 pkg/npm/api/tmp/contacts/lib.js delete mode 100644 pkg/npm/api/tmp/contacts/lib.js.map delete mode 100644 pkg/npm/api/tmp/contacts/types.d.ts delete mode 100644 pkg/npm/api/tmp/contacts/types.js delete mode 100644 pkg/npm/api/tmp/contacts/types.js.map delete mode 100644 pkg/npm/api/tmp/docket/index.d.ts delete mode 100644 pkg/npm/api/tmp/docket/index.js delete mode 100644 pkg/npm/api/tmp/docket/index.js.map delete mode 100644 pkg/npm/api/tmp/docket/lib.d.ts delete mode 100644 pkg/npm/api/tmp/docket/lib.js delete mode 100644 pkg/npm/api/tmp/docket/lib.js.map delete mode 100644 pkg/npm/api/tmp/docket/types.d.ts delete mode 100644 pkg/npm/api/tmp/docket/types.js delete mode 100644 pkg/npm/api/tmp/docket/types.js.map delete mode 100644 pkg/npm/api/tmp/graph/index.d.ts delete mode 100644 pkg/npm/api/tmp/graph/index.js delete mode 100644 pkg/npm/api/tmp/graph/index.js.map delete mode 100644 pkg/npm/api/tmp/graph/lib.d.ts delete mode 100644 pkg/npm/api/tmp/graph/lib.js delete mode 100644 pkg/npm/api/tmp/graph/lib.js.map delete mode 100644 pkg/npm/api/tmp/graph/types.d.ts delete mode 100644 pkg/npm/api/tmp/graph/types.js delete mode 100644 pkg/npm/api/tmp/graph/types.js.map delete mode 100644 pkg/npm/api/tmp/groups/index.d.ts delete mode 100644 pkg/npm/api/tmp/groups/index.js delete mode 100644 pkg/npm/api/tmp/groups/index.js.map delete mode 100644 pkg/npm/api/tmp/groups/lib.d.ts delete mode 100644 pkg/npm/api/tmp/groups/lib.js delete mode 100644 pkg/npm/api/tmp/groups/lib.js.map delete mode 100644 pkg/npm/api/tmp/groups/types.d.ts delete mode 100644 pkg/npm/api/tmp/groups/types.js delete mode 100644 pkg/npm/api/tmp/groups/types.js.map delete mode 100644 pkg/npm/api/tmp/groups/update.d.ts delete mode 100644 pkg/npm/api/tmp/groups/update.js delete mode 100644 pkg/npm/api/tmp/groups/update.js.map delete mode 100644 pkg/npm/api/tmp/groups/view.d.ts delete mode 100644 pkg/npm/api/tmp/groups/view.js delete mode 100644 pkg/npm/api/tmp/groups/view.js.map delete mode 100644 pkg/npm/api/tmp/hark/index.d.ts delete mode 100644 pkg/npm/api/tmp/hark/index.js delete mode 100644 pkg/npm/api/tmp/hark/index.js.map delete mode 100644 pkg/npm/api/tmp/hark/lib.d.ts delete mode 100644 pkg/npm/api/tmp/hark/lib.js delete mode 100644 pkg/npm/api/tmp/hark/lib.js.map delete mode 100644 pkg/npm/api/tmp/hark/types.d.ts delete mode 100644 pkg/npm/api/tmp/hark/types.js delete mode 100644 pkg/npm/api/tmp/hark/types.js.map delete mode 100644 pkg/npm/api/tmp/hood/index.d.ts delete mode 100644 pkg/npm/api/tmp/hood/index.js delete mode 100644 pkg/npm/api/tmp/hood/index.js.map delete mode 100644 pkg/npm/api/tmp/hood/lib.d.ts delete mode 100644 pkg/npm/api/tmp/hood/lib.js delete mode 100644 pkg/npm/api/tmp/hood/lib.js.map delete mode 100644 pkg/npm/api/tmp/hood/types.d.ts delete mode 100644 pkg/npm/api/tmp/hood/types.js delete mode 100644 pkg/npm/api/tmp/hood/types.js.map delete mode 100644 pkg/npm/api/tmp/index.d.ts delete mode 100644 pkg/npm/api/tmp/index.js delete mode 100644 pkg/npm/api/tmp/index.js.map delete mode 100644 pkg/npm/api/tmp/invite/index.d.ts delete mode 100644 pkg/npm/api/tmp/invite/index.js delete mode 100644 pkg/npm/api/tmp/invite/index.js.map delete mode 100644 pkg/npm/api/tmp/invite/lib.d.ts delete mode 100644 pkg/npm/api/tmp/invite/lib.js delete mode 100644 pkg/npm/api/tmp/invite/lib.js.map delete mode 100644 pkg/npm/api/tmp/invite/types.d.ts delete mode 100644 pkg/npm/api/tmp/invite/types.js delete mode 100644 pkg/npm/api/tmp/invite/types.js.map delete mode 100644 pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.d.ts delete mode 100644 pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js delete mode 100644 pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js.map delete mode 100644 pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts delete mode 100644 pkg/npm/api/tmp/lib/BigIntOrderedMap.js delete mode 100644 pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map delete mode 100644 pkg/npm/api/tmp/lib/index.d.ts delete mode 100644 pkg/npm/api/tmp/lib/index.js delete mode 100644 pkg/npm/api/tmp/lib/index.js.map delete mode 100644 pkg/npm/api/tmp/lib/lib.d.ts delete mode 100644 pkg/npm/api/tmp/lib/lib.js delete mode 100644 pkg/npm/api/tmp/lib/lib.js.map delete mode 100644 pkg/npm/api/tmp/lib/types.d.ts delete mode 100644 pkg/npm/api/tmp/lib/types.js delete mode 100644 pkg/npm/api/tmp/lib/types.js.map delete mode 100644 pkg/npm/api/tmp/metadata/index.d.ts delete mode 100644 pkg/npm/api/tmp/metadata/index.js delete mode 100644 pkg/npm/api/tmp/metadata/index.js.map delete mode 100644 pkg/npm/api/tmp/metadata/lib.d.ts delete mode 100644 pkg/npm/api/tmp/metadata/lib.js delete mode 100644 pkg/npm/api/tmp/metadata/lib.js.map delete mode 100644 pkg/npm/api/tmp/metadata/types.d.ts delete mode 100644 pkg/npm/api/tmp/metadata/types.js delete mode 100644 pkg/npm/api/tmp/metadata/types.js.map delete mode 100644 pkg/npm/api/tmp/s3/index.d.ts delete mode 100644 pkg/npm/api/tmp/s3/index.js delete mode 100644 pkg/npm/api/tmp/s3/index.js.map delete mode 100644 pkg/npm/api/tmp/s3/lib.d.ts delete mode 100644 pkg/npm/api/tmp/s3/lib.js delete mode 100644 pkg/npm/api/tmp/s3/lib.js.map delete mode 100644 pkg/npm/api/tmp/s3/types.d.ts delete mode 100644 pkg/npm/api/tmp/s3/types.js delete mode 100644 pkg/npm/api/tmp/s3/types.js.map delete mode 100644 pkg/npm/api/tmp/settings/index.d.ts delete mode 100644 pkg/npm/api/tmp/settings/index.js delete mode 100644 pkg/npm/api/tmp/settings/index.js.map delete mode 100644 pkg/npm/api/tmp/settings/lib.d.ts delete mode 100644 pkg/npm/api/tmp/settings/lib.js delete mode 100644 pkg/npm/api/tmp/settings/lib.js.map delete mode 100644 pkg/npm/api/tmp/settings/types.d.ts delete mode 100644 pkg/npm/api/tmp/settings/types.js delete mode 100644 pkg/npm/api/tmp/settings/types.js.map delete mode 100644 pkg/npm/http-api/tmp/Urbit.d.ts delete mode 100644 pkg/npm/http-api/tmp/Urbit.js delete mode 100644 pkg/npm/http-api/tmp/Urbit.js.map delete mode 100644 pkg/npm/http-api/tmp/index.d.ts delete mode 100644 pkg/npm/http-api/tmp/index.js delete mode 100644 pkg/npm/http-api/tmp/index.js.map delete mode 100644 pkg/npm/http-api/tmp/types.d.ts delete mode 100644 pkg/npm/http-api/tmp/types.js delete mode 100644 pkg/npm/http-api/tmp/types.js.map delete mode 100644 pkg/npm/http-api/tmp/utils.d.ts delete mode 100644 pkg/npm/http-api/tmp/utils.js delete mode 100644 pkg/npm/http-api/tmp/utils.js.map diff --git a/pkg/npm/api/tmp/contacts/index.d.ts b/pkg/npm/api/tmp/contacts/index.d.ts deleted file mode 100644 index 4a272fce5..000000000 --- a/pkg/npm/api/tmp/contacts/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './lib'; diff --git a/pkg/npm/api/tmp/contacts/index.js b/pkg/npm/api/tmp/contacts/index.js deleted file mode 100644 index 5c8443c9d..000000000 --- a/pkg/npm/api/tmp/contacts/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './types'; -export * from './lib'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/index.js.map b/pkg/npm/api/tmp/contacts/index.js.map deleted file mode 100644 index e8bec26c5..000000000 --- a/pkg/npm/api/tmp/contacts/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../contacts/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/lib.d.ts b/pkg/npm/api/tmp/contacts/lib.d.ts deleted file mode 100644 index b81a69eae..000000000 --- a/pkg/npm/api/tmp/contacts/lib.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Patp, Poke, Scry } from '../lib'; -import { Contact, ContactUpdateAdd, ContactUpdateEdit, ContactUpdateRemove, ContactEditField, ContactShare, ContactUpdate, ContactUpdateAllowShips, ContactUpdateAllowGroup, ContactUpdateSetPublic } from './types'; -export declare const CONTACT_UPDATE_VERSION = 0; -declare const storeAction: (data: T, version?: number) => Poke; -export { storeAction as contactStoreAction }; -export declare const addContact: (ship: Patp, contact: Contact) => Poke; -export declare const removeContact: (ship: Patp) => Poke; -export declare const share: (recipient: Patp, version?: number) => Poke; -export declare const editContact: (ship: Patp, editField: ContactEditField) => Poke; -export declare const allowShips: (ships: Patp[]) => Poke; -export declare const allowGroup: (ship: string, name: string) => Poke; -export declare const setPublic: (setPublic: any) => Poke; -export declare const retrieve: (ship: string) => { - app: string; - mark: string; - json: { - add: { - resource: { - ship: string; - name: string; - }; - ship: string; - }; - }; -}; -export declare const fetchIsAllowed: (entity: string, name: string, ship: string, personal: boolean) => Scry; diff --git a/pkg/npm/api/tmp/contacts/lib.js b/pkg/npm/api/tmp/contacts/lib.js deleted file mode 100644 index e2177339f..000000000 --- a/pkg/npm/api/tmp/contacts/lib.js +++ /dev/null @@ -1,64 +0,0 @@ -export const CONTACT_UPDATE_VERSION = 0; -const storeAction = (data, version = CONTACT_UPDATE_VERSION) => ({ - app: 'contact-store', - mark: `contact-update-${version}`, - json: data -}); -export { storeAction as contactStoreAction }; -export const addContact = (ship, contact) => { - contact['last-updated'] = Date.now(); - return storeAction({ - add: { ship, contact } - }); -}; -export const removeContact = (ship) => storeAction({ - remove: { ship } -}); -export const share = (recipient, version = CONTACT_UPDATE_VERSION) => ({ - app: 'contact-push-hook', - mark: 'contact-share', - json: { share: recipient } -}); -export const editContact = (ship, editField) => storeAction({ - edit: { - ship, - 'edit-field': editField, - timestamp: Date.now() - } -}); -export const allowShips = (ships) => storeAction({ - allow: { - ships - } -}); -export const allowGroup = (ship, name) => storeAction({ - allow: { - group: { ship, name } - } -}); -export const setPublic = (setPublic) => { - return storeAction({ - 'set-public': setPublic - }); -}; -export const retrieve = (ship) => { - const resource = { ship, name: '' }; - return { - app: 'contact-pull-hook', - mark: 'pull-hook-action', - json: { - add: { - resource, - ship - } - } - }; -}; -export const fetchIsAllowed = (entity, name, ship, personal) => { - const isPersonal = personal ? 'true' : 'false'; - return { - app: 'contact-store', - path: `/is-allowed/${entity}/${name}/${ship}/${isPersonal}` - }; -}; -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/lib.js.map b/pkg/npm/api/tmp/contacts/lib.js.map deleted file mode 100644 index 5c0b9b03e..000000000 --- a/pkg/npm/api/tmp/contacts/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../contacts/lib.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC,MAAM,WAAW,GAAG,CAA0B,IAAO,EAAE,UAAkB,sBAAsB,EAAW,EAAE,CAAC,CAAC;IAC5G,GAAG,EAAE,eAAe;IACpB,IAAI,EAAE,kBAAkB,OAAO,EAAE;IACjC,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAAE,CAAC;AAE7C,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAU,EAAE,OAAgB,EAA0B,EAAE;IACjF,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAErC,OAAO,WAAW,CAAC;QACjB,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;KACvB,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAU,EAA6B,EAAE,CACrE,WAAW,CAAC;IACV,MAAM,EAAE,EAAE,IAAI,EAAE;CACjB,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,SAAe,EAAE,UAAkB,sBAAsB,EAAsB,EAAE,CAAC,CAAC;IACvG,GAAG,EAAE,mBAAmB;IACxB,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE;CAC3B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAU,EACV,SAA2B,EACF,EAAE,CAC3B,WAAW,CAAC;IACV,IAAI,EAAE;QACJ,IAAI;QACJ,YAAY,EAAE,SAAS;QACvB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB;CACF,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,KAAa,EACkB,EAAE,CAAC,WAAW,CAAC;IAC9C,KAAK,EAAE;QACL,KAAK;KACN;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAY,EACZ,IAAY,EACmB,EAAE,CAAC,WAAW,CAAC;IAC9C,KAAK,EAAE;QACL,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;KACtB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,SAAc,EACgB,EAAE;IAChC,OAAO,WAAW,CAAC;QACjB,YAAY,EAAE,SAAS;KACxB,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,EAAE;IACF,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACpC,OAAO;QACL,GAAG,EAAE,mBAAmB;QACxB,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE;YACJ,GAAG,EAAE;gBACH,QAAQ;gBACR,IAAI;aACL;SACF;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAAc,EACd,IAAY,EACZ,IAAY,EACZ,QAAiB,EACX,EAAE;IACR,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/C,OAAO;QACL,GAAG,EAAE,eAAe;QACpB,IAAI,EAAE,eAAe,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,UAAU,EAAE;KAC5D,CAAC;AACJ,CAAC,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/types.d.ts b/pkg/npm/api/tmp/contacts/types.d.ts deleted file mode 100644 index d002ebebf..000000000 --- a/pkg/npm/api/tmp/contacts/types.d.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Path, Patp } from '../lib'; -import { Resource } from '../groups'; -export declare type ContactUpdate = ContactUpdateAdd | ContactUpdateRemove | ContactUpdateEdit | ContactUpdateInitial | ContactUpdateAllowGroup | ContactUpdateAllowShips | ContactUpdateSetPublic; -export interface ContactUpdateAdd { - add: { - ship: Patp; - contact: Contact; - }; -} -export interface ContactUpdateRemove { - remove: { - ship: Patp; - }; -} -export interface ContactUpdateEdit { - edit: { - ship: Patp; - 'edit-field': ContactEditField; - timestamp: number; - }; -} -export interface ContactUpdateAllowShips { - allow: { - ships: Patp[]; - }; -} -export interface ContactUpdateAllowGroup { - allow: { - group: Resource; - }; -} -export interface ContactUpdateSetPublic { - 'set-public': boolean; -} -export interface ContactShare { - share: Patp; -} -export interface ContactUpdateInitial { - initial: Rolodex; -} -export declare type Rolodex = { - [p in Patp]: Contact; -}; -export declare type Contacts = Rolodex; -export interface Contact { - nickname: string; - bio: string; - status: string; - color: string; - avatar: string | null; - cover: string | null; - groups: Path[]; - 'last-updated': number; -} -declare type ContactKeys = keyof Contact; -export declare type ContactEditFieldPrim = Exclude; -export declare type ContactEditField = Partial> & { - 'add-group'?: Resource; - 'remove-group'?: Resource; -}; -export {}; diff --git a/pkg/npm/api/tmp/contacts/types.js b/pkg/npm/api/tmp/contacts/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/contacts/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/contacts/types.js.map b/pkg/npm/api/tmp/contacts/types.js.map deleted file mode 100644 index b27fd52b3..000000000 --- a/pkg/npm/api/tmp/contacts/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../contacts/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/index.d.ts b/pkg/npm/api/tmp/docket/index.d.ts deleted file mode 100644 index e06143cf1..000000000 --- a/pkg/npm/api/tmp/docket/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib'; -export * from './types'; diff --git a/pkg/npm/api/tmp/docket/index.js b/pkg/npm/api/tmp/docket/index.js deleted file mode 100644 index 872ee0de4..000000000 --- a/pkg/npm/api/tmp/docket/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './lib'; -export * from './types'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/index.js.map b/pkg/npm/api/tmp/docket/index.js.map deleted file mode 100644 index ee11f934d..000000000 --- a/pkg/npm/api/tmp/docket/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../docket/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/lib.d.ts b/pkg/npm/api/tmp/docket/lib.d.ts deleted file mode 100644 index 540c66f53..000000000 --- a/pkg/npm/api/tmp/docket/lib.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Poke, Scry } from '../lib'; -import { Chad } from './types'; -export declare function chadIsRunning(chad: Chad): boolean; -export declare const scryCharges: Scry; -export declare const scryDockets: Scry; -export declare const scryTreaties: Scry; -export declare const scryDefaultAlly: Scry; -export declare const scryAllies: Scry; -export declare const scryAllyTreaties: (ship: string) => Scry; -/** - * Uninstall a desk, and remove docket - */ -export declare function docketUninstall(desk: string): Poke; -export declare function docketInstall(ship: string, desk: string): Poke; -export declare function allyShip(ship: string): Poke; diff --git a/pkg/npm/api/tmp/docket/lib.js b/pkg/npm/api/tmp/docket/lib.js deleted file mode 100644 index a974be13a..000000000 --- a/pkg/npm/api/tmp/docket/lib.js +++ /dev/null @@ -1,54 +0,0 @@ -export function chadIsRunning(chad) { - return 'glob' in chad || 'site' in chad; -} -export const scryCharges = { - app: 'docket', - path: '/charges' -}; -export const scryDockets = { - app: 'docket', - path: '/dockets' -}; -export const scryTreaties = { - app: 'treaty', - path: '/treaties' -}; -export const scryDefaultAlly = { - app: 'treaty', - path: '/default-ally' -}; -export const scryAllies = { - app: 'treaty', - path: '/allies' -}; -export const scryAllyTreaties = (ship) => ({ - app: 'treaty', - path: `/treaties/${ship}` -}); -/** - * Uninstall a desk, and remove docket - */ -export function docketUninstall(desk) { - return { - app: 'docket', - mark: 'docket-uninstall', - json: desk - }; -} -export function docketInstall(ship, desk) { - return { - app: 'docket', - mark: 'docket-install', - json: `${ship}/${desk}` - }; -} -export function allyShip(ship) { - return { - app: 'treaty', - mark: 'ally-update-0', - json: { - add: ship - } - }; -} -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/lib.js.map b/pkg/npm/api/tmp/docket/lib.js.map deleted file mode 100644 index 7d7d1407c..000000000 --- a/pkg/npm/api/tmp/docket/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../docket/lib.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,aAAa,CAAC,IAAU;IACtC,OAAO,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAS;IAC/B,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAS;IAC/B,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,WAAW;CAClB,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,eAAe;CACtB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAS;IAC9B,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAQ,EAAE,CAAC,CAAC;IACvD,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,aAAa,IAAI,EAAE;CAC1B,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO;QACL,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,kBAAkB;QACxB,IAAI,EAAE,IAAI;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAY;IACtD,OAAO;QACL,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,gBAAgB;QACtB,IAAI,EAAE,GAAG,IAAI,IAAI,IAAI,EAAE;KACxB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO;QACL,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,eAAe;QACrB,IAAI,EAAE;YACJ,GAAG,EAAE,IAAI;SACV;KACF,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/types.d.ts b/pkg/npm/api/tmp/docket/types.d.ts deleted file mode 100644 index 594b0f310..000000000 --- a/pkg/npm/api/tmp/docket/types.d.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { Cass } from '../hood'; -export declare type DeskStatus = 'active' | 'suspended'; -export declare type DocketHref = DocketHrefSite | DocketHrefGlob; -export interface DocketHrefGlob { - glob: { - base: string; - }; -} -export interface DocketHrefSite { - site: string; -} -export interface Docket { - title: string; - info?: string; - color: string; - href: DocketHref; - website: string; - license: string; - version: string; - image?: string; -} -export interface Charge extends Docket { - chad: Chad; -} -export declare type Chad = HungChad | GlobChad | SiteChad | InstallChad | SuspendChad; -export interface HungChad { - hung: string; -} -export interface GlobChad { - glob: null; -} -export interface SiteChad { - site: null; -} -export interface InstallChad { - install: null; -} -export interface SuspendChad { - suspend: null; -} -export interface Treaty extends Docket { - ship: string; - desk: string; - cass: Cass; - hash: string; -} -export interface Charges { - [desk: string]: Charge; -} -export interface Treaties { - [ref: string]: Treaty; -} -export declare type Charter = string[]; -export interface Allies { - [ship: string]: Charter; -} -export interface Provider { - shipName: string; - nickname?: string; - status?: string; -} -export declare type ChargeUpdate = ChargeUpdateInitial | ChargeUpdateAdd | ChargeUpdateDel; -export interface ChargeUpdateInitial { - initial: { - [desk: string]: Charge; - }; -} -export interface ChargeUpdateAdd { - 'add-charge': { - desk: string; - charge: Charge; - }; -} -export interface ChargeUpdateDel { - 'del-charge': string; -} -export declare type AllyUpdate = AllyUpdateIni | AllyUpdateAdd | AllyUpdateDel | AllyUpdateNew; -export interface AllyUpdateIni { - ini: { - [ship: string]: string[]; - }; -} -export interface AllyUpdateAdd { - add: string; -} -export interface AllyUpdateDel { - del: string; -} -export interface AllyUpdateNew { - new: { - ship: string; - alliance: string[]; - }; -} -export declare type TreatyUpdate = TreatyUpdateIni | TreatyUpdateAdd | TreatyUpdateDel; -export interface TreatyUpdateIni { - ini: { - [foreignDesk: string]: Treaty; - }; -} -export interface TreatyUpdateAdd { - add: Treaty; -} -export interface TreatyUpdateDel { - del: string; -} diff --git a/pkg/npm/api/tmp/docket/types.js b/pkg/npm/api/tmp/docket/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/docket/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/docket/types.js.map b/pkg/npm/api/tmp/docket/types.js.map deleted file mode 100644 index 0dffe4f69..000000000 --- a/pkg/npm/api/tmp/docket/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../docket/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/index.d.ts b/pkg/npm/api/tmp/graph/index.d.ts deleted file mode 100644 index e06143cf1..000000000 --- a/pkg/npm/api/tmp/graph/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib'; -export * from './types'; diff --git a/pkg/npm/api/tmp/graph/index.js b/pkg/npm/api/tmp/graph/index.js deleted file mode 100644 index 872ee0de4..000000000 --- a/pkg/npm/api/tmp/graph/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './lib'; -export * from './types'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/index.js.map b/pkg/npm/api/tmp/graph/index.js.map deleted file mode 100644 index 5db9fcbe9..000000000 --- a/pkg/npm/api/tmp/graph/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../graph/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/lib.d.ts b/pkg/npm/api/tmp/graph/lib.d.ts deleted file mode 100644 index 1d8e9c69a..000000000 --- a/pkg/npm/api/tmp/graph/lib.d.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { GroupPolicy, Resource } from '../groups'; -import { Scry } from '../lib'; -import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types'; -import { Content, GraphNodePoke, Post } from './types'; -export declare const GRAPH_UPDATE_VERSION = 3; -export declare const createBlankNodeWithChildPost: (ship: PatpNoSig, parentIndex: string, childIndex: string, contents: Content[]) => GraphNodePoke; -export declare const markPending: (nodes: any) => any; -export declare const createPost: (ship: PatpNoSig, contents: Content[], parentIndex?: string, childIndex?: string) => Post; -declare const storeAction: (data: T, version?: number) => Poke; -export { storeAction as graphStoreAction }; -declare const viewAction: (threadName: string, action: T) => Thread; -export { viewAction as graphViewAction }; -declare const hookAction: (data: T, version?: number) => Poke; -export { hookAction as graphHookAction }; -export declare const createManagedGraph: (ship: PatpNoSig, name: string, title: string, description: string, group: Path, mod: string) => Thread; -export declare const createUnmanagedGraph: (ship: PatpNoSig, name: string, title: string, description: string, policy: Enc, mod: string) => Thread; -export declare const joinGraph: (ship: Patp, name: string) => Thread; -export declare const deleteGraph: (ship: PatpNoSig, name: string) => Thread; -export declare const leaveGraph: (ship: Patp, name: string) => Thread; -export declare const groupifyGraph: (ship: Patp, name: string, toPath?: string) => Thread; -export declare const evalCord: (cord: string) => Thread; -export declare const addGraph: (ship: Patp, name: string, graph: any, mark: any) => Poke; -export declare const addNodes: (ship: Patp, name: string, nodes: Object) => Thread; -export declare const addPost: (ship: Patp, name: string, post: Post) => Thread; -export declare const addNode: (ship: Patp, name: string, node: GraphNodePoke) => Thread; -export declare const createGroupFeed: (group: Resource, vip?: any) => Thread; -export declare const disableGroupFeed: (group: Resource) => Thread; -/** - * Set dm-hook to screen new DMs or not - * - */ -export declare const setScreen: (screen: boolean) => Poke; -/** - * Accept a pending DM request - * - * @param ship the ship to accept - */ -export declare const acceptDm: (ship: string) => Poke<{ - accept: string; -}>; -/** - * Decline a pending DM request - * - * @param ship the ship to accept - */ -export declare const declineDm: (ship: string) => Poke<{ - decline: string; -}>; -/** - * Remove posts from a set of indices - * - */ -export declare const removePosts: (ship: Patp, name: string, indices: string[]) => Poke; -/** - * Remove a DM message from our inbox - * - * @remarks - * This does not remove the message from the recipients inbox - */ -export declare const removeDmMessage: (our: Patp, index: string) => Poke; -/** - * Send a DM to a ship - * - * @param our sender - * @param ship recipient - * @param contents contents of message - */ -export declare const addDmMessage: (our: PatpNoSig, ship: Patp, contents: Content[]) => Poke; -/** - * Fetch newest (larger keys) nodes in a graph under some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export declare const getNewest: (ship: string, name: string, count: number, index?: string) => Scry; -/** - * Fetch nodes in a graph that are older (key is smaller) and direct - * siblings of some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export declare const getOlderSiblings: (ship: string, name: string, count: number, index: string) => Scry; -/** - * Fetch nodes in a graph that are younger (key is larger) and direct - * siblings of some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export declare const getYoungerSiblings: (ship: string, name: string, count: number, index: string) => Scry; -/** - * Fetch all nodes in a graph under some index, without loading children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - */ -export declare const getShallowChildren: (ship: string, name: string, index?: string) => { - app: string; - path: string; -}; -/** - * Fetch newest nodes in a graph as a flat map, including children, - * optionally starting at a specified key - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param start key to start at - * - */ -export declare const getDeepOlderThan: (ship: string, name: string, count: number, start?: string) => { - app: string; - path: string; -}; -/** - * Fetch a flat map of a nodes ancestors and firstborn children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - * - */ -export declare const getFirstborn: (ship: string, name: string, index: string) => Scry; -/** - * Fetch a single node, and all it's children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - * - */ -export declare const getNode: (ship: string, name: string, index: string) => Scry; -/** - * Fetch entire graph - * - * @param ship ship of graph - * @param name name of graph - * - */ -export declare const getGraph: (ship: string, name: string) => Scry; diff --git a/pkg/npm/api/tmp/graph/lib.js b/pkg/npm/api/tmp/graph/lib.js deleted file mode 100644 index af182a9db..000000000 --- a/pkg/npm/api/tmp/graph/lib.js +++ /dev/null @@ -1,380 +0,0 @@ -import { makeResource, resourceFromPath } from '../groups'; -import { decToUd, deSig, unixToDa } from '../lib'; -import { patp2dec } from 'urbit-ob'; -export const GRAPH_UPDATE_VERSION = 3; -export const createBlankNodeWithChildPost = (ship, parentIndex = '', childIndex = '', contents) => { - const date = unixToDa(Date.now()).toString(); - const nodeIndex = parentIndex + '/' + date; - const childGraph = {}; - childGraph[childIndex] = { - post: { - author: `~${ship}`, - index: nodeIndex + '/' + childIndex, - 'time-sent': Date.now(), - contents, - hash: null, - signatures: [] - }, - children: null - }; - return { - post: { - author: `~${ship}`, - index: nodeIndex, - 'time-sent': Date.now(), - contents: [], - hash: null, - signatures: [] - }, - children: childGraph - }; -}; -export const markPending = (nodes) => { - Object.keys(nodes).forEach((key) => { - nodes[key].post.author = deSig(nodes[key].post.author); - nodes[key].post.pending = true; - if (nodes[key].children) { - nodes[key].children = markPending(nodes[key].children); - } - }); - return nodes; -}; -export const createPost = (ship, contents, parentIndex = '', childIndex = 'DATE_PLACEHOLDER') => { - if (childIndex === 'DATE_PLACEHOLDER') { - childIndex = unixToDa(Date.now()).toString(); - } - return { - author: `~${ship}`, - index: parentIndex + '/' + childIndex, - 'time-sent': Date.now(), - contents, - hash: null, - signatures: [] - }; -}; -function moduleToMark(mod) { - if (mod === 'link') { - return 'graph-validator-link'; - } - if (mod === 'publish') { - return 'graph-validator-publish'; - } - if (mod === 'chat') { - return 'graph-validator-chat'; - } - return undefined; -} -const storeAction = (data, version = GRAPH_UPDATE_VERSION) => ({ - app: 'graph-store', - mark: `graph-update-${version}`, - json: data -}); -export { storeAction as graphStoreAction }; -const viewAction = (threadName, action) => ({ - inputMark: 'graph-view-action', - outputMark: 'json', - threadName, - body: action -}); -export { viewAction as graphViewAction }; -const hookAction = (data, version = GRAPH_UPDATE_VERSION) => ({ - app: 'graph-push-hook', - mark: `graph-update-${version}`, - json: data -}); -const dmAction = (data) => ({ - app: 'dm-hook', - mark: 'dm-hook-action', - json: data -}); -export { hookAction as graphHookAction }; -export const createManagedGraph = (ship, name, title, description, group, mod) => { - const associated = { group: resourceFromPath(group) }; - const resource = makeResource(`~${ship}`, name); - return viewAction('graph-create', { - create: { - resource, - title, - description, - associated, - module: mod, - mark: moduleToMark(mod) - } - }); -}; -export const createUnmanagedGraph = (ship, name, title, description, policy, mod) => viewAction('graph-create', { - create: { - resource: makeResource(`~${ship}`, name), - title, - description, - associated: { policy }, - module: mod, - mark: moduleToMark(mod) - } -}); -export const joinGraph = (ship, name) => viewAction('graph-join', { - join: { - resource: makeResource(ship, name), - ship - } -}); -export const deleteGraph = (ship, name) => viewAction('graph-delete', { - 'delete': { - resource: makeResource(`~${ship}`, name) - } -}); -export const leaveGraph = (ship, name) => viewAction('graph-leave', { - 'leave': { - resource: makeResource(ship, name) - } -}); -export const groupifyGraph = (ship, name, toPath) => { - const resource = makeResource(ship, name); - const to = toPath && resourceFromPath(toPath); - return viewAction('graph-groupify', { - groupify: { - resource, - to - } - }); -}; -export const evalCord = (cord) => { - return ({ - inputMark: 'graph-view-action', - outputMark: 'tang', - threadName: 'graph-eval', - body: { - eval: cord - } - }); -}; -export const addGraph = (ship, name, graph, mark) => { - return storeAction({ - 'add-graph': { - resource: { ship, name }, - graph, - mark - } - }); -}; -export const addNodes = (ship, name, nodes) => ({ - inputMark: `graph-update-${GRAPH_UPDATE_VERSION}`, - outputMark: 'graph-view-action', - threadName: 'graph-add-nodes', - body: { - 'add-nodes': { - resource: { ship, name }, - nodes - } - } -}); -export const addPost = (ship, name, post) => { - const nodes = {}; - nodes[post.index] = { - post, - children: null - }; - return addNodes(ship, name, nodes); -}; -export const addNode = (ship, name, node) => { - const nodes = {}; - nodes[node.post.index] = node; - return addNodes(ship, name, nodes); -}; -export const createGroupFeed = (group, vip = '') => ({ - inputMark: 'graph-view-action', - outputMark: 'resource', - threadName: 'graph-create-group-feed', - body: { - 'create-group-feed': { - resource: group, - vip - } - } -}); -export const disableGroupFeed = (group) => ({ - inputMark: 'graph-view-action', - outputMark: 'json', - threadName: 'graph-disable-group-feed', - body: { - 'disable-group-feed': { - resource: group - } - } -}); -/** - * Set dm-hook to screen new DMs or not - * - */ -export const setScreen = (screen) => dmAction({ screen }); -/** - * Accept a pending DM request - * - * @param ship the ship to accept - */ -export const acceptDm = (ship) => dmAction({ - accept: ship -}); -/** - * Decline a pending DM request - * - * @param ship the ship to accept - */ -export const declineDm = (ship) => dmAction({ - decline: ship -}); -/** - * Remove posts from a set of indices - * - */ -export const removePosts = (ship, name, indices) => hookAction({ - 'remove-posts': { - resource: { ship, name }, - indices - } -}); -/** - * Remove a DM message from our inbox - * - * @remarks - * This does not remove the message from the recipients inbox - */ -export const removeDmMessage = (our, index) => ({ - app: 'graph-store', - mark: `graph-update-${GRAPH_UPDATE_VERSION}`, - json: { - 'remove-posts': { - resource: { ship: our, name: 'dm-inbox' }, - indices: [index] - } - } -}); -/** - * Send a DM to a ship - * - * @param our sender - * @param ship recipient - * @param contents contents of message - */ -export const addDmMessage = (our, ship, contents) => { - const post = createPost(our, contents, `/${patp2dec(ship)}`); - const node = { - post, - children: null - }; - return { - app: 'dm-hook', - mark: `graph-update-${GRAPH_UPDATE_VERSION}`, - json: { - 'add-nodes': { - resource: { ship: `~${our}`, name: 'dm-inbox' }, - nodes: { - [post.index]: node - } - } - } - }; -}; -const encodeIndex = (idx) => idx.split('/').map(decToUd).join('/'); -/** - * Fetch newest (larger keys) nodes in a graph under some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export const getNewest = (ship, name, count, index = '') => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/siblings` + - `/newest/lone/${count}${encodeIndex(index)}` -}); -/** - * Fetch nodes in a graph that are older (key is smaller) and direct - * siblings of some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export const getOlderSiblings = (ship, name, count, index) => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/siblings/older/lone/${count}${encodeIndex(index)}` -}); -/** - * Fetch nodes in a graph that are younger (key is larger) and direct - * siblings of some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export const getYoungerSiblings = (ship, name, count, index) => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/siblings/newer/lone/${count}${encodeIndex(index)}` -}); -/** - * Fetch all nodes in a graph under some index, without loading children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - */ -export const getShallowChildren = (ship, name, index = '') => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/children/lone/~/~${encodeIndex(index)}` -}); -/** - * Fetch newest nodes in a graph as a flat map, including children, - * optionally starting at a specified key - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param start key to start at - * - */ -export const getDeepOlderThan = (ship, name, count, start = '') => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/siblings` + - `/${start.length > 0 ? 'older' : 'newest'}` + - `/kith/${count}${encodeIndex(start)}` -}); -/** - * Fetch a flat map of a nodes ancestors and firstborn children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - * - */ -export const getFirstborn = (ship, name, index) => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/firstborn${encodeIndex(index)}` -}); -/** - * Fetch a single node, and all it's children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - * - */ -export const getNode = (ship, name, index) => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/index/kith${encodeIndex(index)}` -}); -/** - * Fetch entire graph - * - * @param ship ship of graph - * @param name name of graph - * - */ -export const getGraph = (ship, name) => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}` -}); -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/lib.js.map b/pkg/npm/api/tmp/graph/lib.js.map deleted file mode 100644 index e62f9fff2..000000000 --- a/pkg/npm/api/tmp/graph/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../graph/lib.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/types.d.ts b/pkg/npm/api/tmp/graph/types.d.ts deleted file mode 100644 index 2c18e0103..000000000 --- a/pkg/npm/api/tmp/graph/types.d.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Patp } from '../lib'; -import { BigIntOrderedMap } from '../lib/BigIntOrderedMap'; -import { BigIntArrayOrderedMap } from '../lib/BigIntArrayOrderedMap'; -export interface TextContent { - text: string; -} -export interface UrlContent { - url: string; -} -export interface CodeContent { - code: { - expression: string; - output: string[] | undefined; - }; -} -export interface ReferenceContent { - reference: AppReference | GraphReference | GroupReference; -} -export interface GraphReference { - graph: { - graph: string; - group: string; - index: string; - }; -} -export interface GroupReference { - group: string; -} -export interface AppReference { - app: { - ship: string; - desk: string; - path: string; - }; -} -export interface MentionContent { - mention: string; -} -export declare type Content = TextContent | UrlContent | CodeContent | ReferenceContent | MentionContent; -export interface Post { - author: Patp; - contents: Content[]; - hash: string | null; - index: string; - pending?: boolean; - signatures: string[]; - 'time-sent': number; -} -export interface GraphNodePoke { - post: Post; - children: GraphChildrenPoke | null; -} -export interface GraphChildrenPoke { - [k: string]: GraphNodePoke; -} -export interface GraphNode { - children: Graph | null; - post: Post; -} -export interface FlatGraphNode { - children: null; - post: Post; -} -export declare type Graph = BigIntOrderedMap; -export declare type Graphs = { - [rid: string]: Graph; -}; -export declare type FlatGraph = BigIntArrayOrderedMap; -export declare type FlatGraphs = { - [rid: string]: FlatGraph; -}; -export declare type ThreadGraphs = { - [rid: string]: { - [index: string]: FlatGraph; - }; -}; diff --git a/pkg/npm/api/tmp/graph/types.js b/pkg/npm/api/tmp/graph/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/graph/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/graph/types.js.map b/pkg/npm/api/tmp/graph/types.js.map deleted file mode 100644 index 7a3e71902..000000000 --- a/pkg/npm/api/tmp/graph/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../graph/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/index.d.ts b/pkg/npm/api/tmp/groups/index.d.ts deleted file mode 100644 index 4a272fce5..000000000 --- a/pkg/npm/api/tmp/groups/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './lib'; diff --git a/pkg/npm/api/tmp/groups/index.js b/pkg/npm/api/tmp/groups/index.js deleted file mode 100644 index 5c8443c9d..000000000 --- a/pkg/npm/api/tmp/groups/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './types'; -export * from './lib'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/index.js.map b/pkg/npm/api/tmp/groups/index.js.map deleted file mode 100644 index 387cd9ddb..000000000 --- a/pkg/npm/api/tmp/groups/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../groups/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/lib.d.ts b/pkg/npm/api/tmp/groups/lib.d.ts deleted file mode 100644 index a75a837a8..000000000 --- a/pkg/npm/api/tmp/groups/lib.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types'; -import { Group, GroupPolicy, GroupPolicyDiff, GroupUpdateAddMembers, GroupUpdateAddTag, GroupUpdateChangePolicy, GroupUpdateRemoveGroup, GroupUpdateRemoveMembers, GroupUpdateRemoveTag, Resource, RoleTags, Tag } from './types'; -import { GroupUpdate } from './update'; -export declare const GROUP_UPDATE_VERSION = 0; -export declare const proxyAction: (data: T, version?: number) => Poke; -declare const storeAction: (data: T, version?: number) => Poke; -export { storeAction as groupStoreAction }; -declare const viewAction: (data: T) => Poke; -export { viewAction as groupViewAction }; -export declare const viewThread: (thread: string, action: T) => Thread; -export declare const removeMembers: (resource: Resource, ships: PatpNoSig[]) => Poke; -export declare const addTag: (resource: Resource, tag: Tag, ships: Patp[]) => Poke; -export declare const removeTag: (tag: Tag, resource: Resource, ships: PatpNoSig[]) => Poke; -export declare const addMembers: (resource: Resource, ships: PatpNoSig[]) => Poke; -export declare const removeGroup: (resource: Resource) => Poke; -export declare const changePolicy: (resource: Resource, diff: Enc) => Poke>; -export declare const makeResource: (ship: string, name: string) => { - ship: string; - name: string; -}; -export declare const join: (ship: string, name: string, app: "groups" | "graph", autojoin: boolean, share: boolean) => Poke; -export declare const createGroup: (name: string, policy: Enc, title: string, description: string) => Thread; -export declare const deleteGroup: (ship: string, name: string) => Thread; -export declare const leaveGroup: (ship: string, name: string) => Thread; -export declare const invite: (ship: string, name: string, ships: Patp[], description: string) => Thread; -export declare const abortJoin: (resource: string) => Poke; -export declare const roleTags: string[]; -export declare const groupBunts: { - group: () => Group; - policy: () => GroupPolicy; -}; -export declare const joinError: readonly ["no-perms", "strange", "abort"]; -export declare const joinResult: readonly ["done", "no-perms", "strange", "abort"]; -export declare const joinLoad: readonly ["start", "added", "metadata"]; -export declare const joinProgress: readonly ["start", "added", "metadata", "done", "no-perms", "strange", "abort"]; -export declare const roleForShip: (group: Group, ship: PatpNoSig) => RoleTags | undefined; -export declare const resourceFromPath: (path: Path) => Resource; -export declare const isWriter: (group: Group, resource: string, ship: string) => boolean; -export declare const isHost: (resource: string, ship: string) => boolean; -export declare const isChannelAdmin: (group: Group, resource: string, ship: string) => boolean; diff --git a/pkg/npm/api/tmp/groups/lib.js b/pkg/npm/api/tmp/groups/lib.js deleted file mode 100644 index e2d572986..000000000 --- a/pkg/npm/api/tmp/groups/lib.js +++ /dev/null @@ -1,139 +0,0 @@ -export const GROUP_UPDATE_VERSION = 0; -export const proxyAction = (data, version = GROUP_UPDATE_VERSION) => ({ - app: 'group-push-hook', - mark: `group-update-${version}`, - json: data -}); -const storeAction = (data, version = GROUP_UPDATE_VERSION) => ({ - app: 'group-store', - mark: `group-update-${version}`, - json: data -}); -export { storeAction as groupStoreAction }; -const viewAction = (data) => ({ - app: 'group-view', - mark: 'group-view-action', - json: data -}); -export { viewAction as groupViewAction }; -export const viewThread = (thread, action) => ({ - inputMark: 'group-view-action', - outputMark: 'json', - threadName: thread, - body: action -}); -export const removeMembers = (resource, ships) => proxyAction({ - removeMembers: { - resource, - ships - } -}); -export const addTag = (resource, tag, ships) => proxyAction({ - addTag: { - resource, - tag, - ships - } -}); -export const removeTag = (tag, resource, ships) => proxyAction({ - removeTag: { - tag, - resource, - ships - } -}); -export const addMembers = (resource, ships) => proxyAction({ - addMembers: { - resource, - ships - } -}); -export const removeGroup = (resource) => storeAction({ - removeGroup: { - resource - } -}); -export const changePolicy = (resource, diff) => proxyAction({ - changePolicy: { - resource, - diff - } -}); -export const makeResource = (ship, name) => { - return { ship, name }; -}; -export const join = (ship, name, app, autojoin, share) => viewAction({ - join: { - resource: makeResource(ship, name), - ship, - shareContact: share || false, - app, - autojoin - } -}); -export const createGroup = (name, policy, title, description) => viewThread('group-create', { - create: { - name, - policy, - title, - description - } -}); -export const deleteGroup = (ship, name) => viewThread('group-delete', { - remove: makeResource(ship, name) -}); -export const leaveGroup = (ship, name) => viewThread('group-leave', { - leave: makeResource(ship, name) -}); -export const invite = (ship, name, ships, description) => viewThread('group-invite', { - invite: { - resource: makeResource(ship, name), - ships, - description - } -}); -export const abortJoin = (resource) => viewAction({ - abort: resource -}); -export const roleTags = ['janitor', 'moderator', 'admin']; -// TODO make this type better? -export const groupBunts = { - group: () => ({ members: new Set(), tags: { role: {} }, hidden: false, policy: groupBunts.policy() }), - policy: () => ({ open: { banned: new Set(), banRanks: new Set() } }) -}; -export const joinError = ['no-perms', 'strange', 'abort']; -export const joinResult = ['done', ...joinError]; -export const joinLoad = ['start', 'added', 'metadata']; -export const joinProgress = [...joinLoad, ...joinResult]; -export const roleForShip = (group, ship) => { - return roleTags.reduce((currRole, role) => { - const roleShips = group?.tags?.role?.[role]; - return roleShips && roleShips.has(ship) ? role : currRole; - }, undefined); -}; -export const resourceFromPath = (path) => { - const [, , ship, name] = path.split('/'); - return { ship, name }; -}; -export const isWriter = (group, resource, ship) => { - const graph = group.tags?.graph; - const writers = graph && graph[resource]?.writers; - const admins = group?.tags?.role?.admin ?? new Set(); - if (typeof writers === 'undefined') { - return true; - } - else { - return writers.has(ship) || admins.has(ship); - } -}; -export const isHost = (resource, ship) => { - const [, , host] = resource.split('/'); - return ship === host; -}; -export const isChannelAdmin = (group, resource, ship) => { - const role = roleForShip(group, ship.slice(1)); - return (isHost(resource, ship) || - role === 'admin' || - role === 'moderator'); -}; -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/lib.js.map b/pkg/npm/api/tmp/groups/lib.js.map deleted file mode 100644 index 6c2d70922..000000000 --- a/pkg/npm/api/tmp/groups/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../groups/lib.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/types.d.ts b/pkg/npm/api/tmp/groups/types.d.ts deleted file mode 100644 index b838383f1..000000000 --- a/pkg/npm/api/tmp/groups/types.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './update'; -export * from './view'; diff --git a/pkg/npm/api/tmp/groups/types.js b/pkg/npm/api/tmp/groups/types.js deleted file mode 100644 index fe3fba155..000000000 --- a/pkg/npm/api/tmp/groups/types.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './update'; -export * from './view'; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/types.js.map b/pkg/npm/api/tmp/groups/types.js.map deleted file mode 100644 index e7f9f68e8..000000000 --- a/pkg/npm/api/tmp/groups/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../groups/types.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/update.d.ts b/pkg/npm/api/tmp/groups/update.d.ts deleted file mode 100644 index a8e74a551..000000000 --- a/pkg/npm/api/tmp/groups/update.d.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { PatpNoSig, Path, ShipRank, Enc } from '../lib'; -import { roleTags } from './index'; -export declare type RoleTags = typeof roleTags[number]; -interface RoleTag { - tag: 'admin' | 'moderator' | 'janitor'; -} -interface AppTag { - app: string; - resource: string; - tag: string; -} -export declare type Tag = AppTag | RoleTag; -export interface InvitePolicy { - invite: { - pending: Set; - }; -} -export interface OpenPolicy { - open: { - banned: Set; - banRanks: Set; - }; -} -export interface Resource { - name: string; - ship: PatpNoSig; -} -export declare type OpenPolicyDiff = AllowRanksDiff | BanRanksDiff | AllowShipsDiff | BanShipsDiff; -export interface AllowRanksDiff { - allowRanks: ShipRank[]; -} -export interface BanRanksDiff { - banRanks: ShipRank[]; -} -export interface AllowShipsDiff { - allowShips: PatpNoSig[]; -} -export interface BanShipsDiff { - banShips: PatpNoSig[]; -} -export declare type InvitePolicyDiff = AddInvitesDiff | RemoveInvitesDiff; -export interface AddInvitesDiff { - addInvites: PatpNoSig[]; -} -export interface RemoveInvitesDiff { - removeInvites: PatpNoSig[]; -} -export interface ReplacePolicyDiff { - replace: GroupPolicy; -} -export declare type GroupPolicyDiff = { - open: OpenPolicyDiff; -} | { - invite: InvitePolicyDiff; -} | ReplacePolicyDiff; -export declare type GroupPolicy = OpenPolicy | InvitePolicy; -export interface TaggedShips { - [tag: string]: Set; -} -export interface Tags { - role: TaggedShips; - [app: string]: TaggedShips; -} -export interface Group { - members: Set; - tags: Tags; - policy: GroupPolicy; - hidden: boolean; -} -export declare type Groups = { - [p in Path]: Group; -}; -export interface GroupUpdateInitial { - initial: Enc; -} -export interface GroupUpdateAddGroup { - addGroup: { - resource: Resource; - policy: Enc; - hidden: boolean; - }; -} -export interface GroupUpdateAddMembers { - addMembers: { - ships: PatpNoSig[]; - resource: Resource; - }; -} -export interface GroupUpdateRemoveMembers { - removeMembers: { - ships: PatpNoSig[]; - resource: Resource; - }; -} -export interface GroupUpdateAddTag { - addTag: { - tag: Tag; - resource: Resource; - ships: PatpNoSig[]; - }; -} -export interface GroupUpdateRemoveTag { - removeTag: { - tag: Tag; - resource: Resource; - ships: PatpNoSig[]; - }; -} -export interface GroupUpdateChangePolicy { - changePolicy: { - resource: Resource; - diff: GroupPolicyDiff; - }; -} -export interface GroupUpdateRemoveGroup { - removeGroup: { - resource: Resource; - }; -} -export interface GroupUpdateExpose { - expose: { - resource: Resource; - }; -} -export interface GroupUpdateInitialGroup { - initialGroup: { - resource: Resource; - group: Enc; - }; -} -export declare type GroupUpdate = GroupUpdateInitial | GroupUpdateAddGroup | GroupUpdateAddMembers | GroupUpdateRemoveMembers | GroupUpdateAddTag | GroupUpdateRemoveTag | GroupUpdateChangePolicy | GroupUpdateRemoveGroup | GroupUpdateExpose | GroupUpdateInitialGroup; -export declare type GroupAction = Omit; -export {}; diff --git a/pkg/npm/api/tmp/groups/update.js b/pkg/npm/api/tmp/groups/update.js deleted file mode 100644 index 3a8140041..000000000 --- a/pkg/npm/api/tmp/groups/update.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=update.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/update.js.map b/pkg/npm/api/tmp/groups/update.js.map deleted file mode 100644 index 67c69672f..000000000 --- a/pkg/npm/api/tmp/groups/update.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"update.js","sourceRoot":"","sources":["../../groups/update.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/view.d.ts b/pkg/npm/api/tmp/groups/view.d.ts deleted file mode 100644 index 9e8010ef7..000000000 --- a/pkg/npm/api/tmp/groups/view.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { joinError, joinProgress, joinResult } from "."; -import { Patp } from "../lib"; -export declare type JoinError = typeof joinError[number]; -export declare type JoinResult = typeof joinResult[number]; -export declare type JoinProgress = typeof joinProgress[number]; -export interface JoinRequest { - /** - * Whether to display the join request or not - */ - hidden: boolean; - /** - * Timestamp of when the request started - */ - started: number; - ship: Patp; - progress: JoinProgress; - shareContact: boolean; - autojoin: boolean; - app: 'graph' | 'groups'; - invite: string[]; -} -export interface JoinRequests { - [rid: string]: JoinRequest; -} diff --git a/pkg/npm/api/tmp/groups/view.js b/pkg/npm/api/tmp/groups/view.js deleted file mode 100644 index d8198797a..000000000 --- a/pkg/npm/api/tmp/groups/view.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=view.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/groups/view.js.map b/pkg/npm/api/tmp/groups/view.js.map deleted file mode 100644 index 000c52048..000000000 --- a/pkg/npm/api/tmp/groups/view.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"view.js","sourceRoot":"","sources":["../../groups/view.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/index.d.ts b/pkg/npm/api/tmp/hark/index.d.ts deleted file mode 100644 index 4a272fce5..000000000 --- a/pkg/npm/api/tmp/hark/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './lib'; diff --git a/pkg/npm/api/tmp/hark/index.js b/pkg/npm/api/tmp/hark/index.js deleted file mode 100644 index 5c8443c9d..000000000 --- a/pkg/npm/api/tmp/hark/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './types'; -export * from './lib'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/index.js.map b/pkg/npm/api/tmp/hark/index.js.map deleted file mode 100644 index 8624fd26f..000000000 --- a/pkg/npm/api/tmp/hark/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../hark/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/lib.d.ts b/pkg/npm/api/tmp/hark/lib.d.ts deleted file mode 100644 index 3b75f25f2..000000000 --- a/pkg/npm/api/tmp/hark/lib.d.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { BigInteger } from 'big-integer'; -import { Poke } from '../lib/types'; -import { HarkBin, HarkBinId, HarkLid, HarkPlace } from './types'; -export declare const harkAction: (data: T) => Poke; -declare const graphHookAction: (data: T) => Poke; -export { graphHookAction as harkGraphHookAction }; -declare const groupHookAction: (data: T) => Poke; -export { groupHookAction as harkGroupHookAction }; -export declare const actOnNotification: (frond: string, intTime: BigInteger, bin: HarkBin) => Poke; -export declare const setMentions: (mentions: boolean) => Poke; -export declare const setWatchOnSelf: (watchSelf: boolean) => Poke; -export declare const setDoNotDisturb: (dnd: boolean) => Poke; -export declare const archive: (bin: HarkBin, lid: HarkLid) => Poke; -export declare const opened: Poke<{ - opened: any; -}>; -export declare const markCountAsRead: (place: HarkPlace) => Poke; -export declare const markEachAsRead: (place: HarkPlace, path: string) => Poke; -export declare const seen: () => Poke<{ - seen: any; -}>; -export declare const readAll: Poke<{ - 'read-all': any; -}>; -export declare const archiveAll: Poke<{ - 'archive-all': any; -}>; -export declare const ignoreGroup: (group: string) => Poke; -export declare const ignoreGraph: (graph: string, index: string) => Poke; -export declare const listenGroup: (group: string) => Poke; -export declare const listenGraph: (graph: string, index: string) => Poke; -/** - * Read all graphs belonging to a particular group - */ -export declare const readGroup: (group: string) => Poke<{ - 'read-group': string; -}>; -/** - * Read all unreads in a graph - */ -export declare const readGraph: (graph: string) => Poke<{ - 'read-graph': string; -}>; -export declare function harkBinToId(bin: HarkBin): HarkBinId; -export declare function harkBinEq(a: HarkBin, b: HarkBin): boolean; -export declare function harkLidToId(lid: HarkLid): string; diff --git a/pkg/npm/api/tmp/hark/lib.js b/pkg/npm/api/tmp/hark/lib.js deleted file mode 100644 index 7ea20b407..000000000 --- a/pkg/npm/api/tmp/hark/lib.js +++ /dev/null @@ -1,100 +0,0 @@ -import { decToUd } from '../lib'; -export const harkAction = (data) => ({ - app: 'hark-store', - mark: 'hark-action', - json: data -}); -const graphHookAction = (data) => ({ - app: 'hark-graph-hook', - mark: 'hark-graph-hook-action', - json: data -}); -export { graphHookAction as harkGraphHookAction }; -const groupHookAction = (data) => ({ - app: 'hark-group-hook', - mark: 'hark-group-hook-action', - json: data -}); -export { groupHookAction as harkGroupHookAction }; -export const actOnNotification = (frond, intTime, bin) => harkAction({ - [frond]: { - time: decToUd(intTime.toString()), - bin - } -}); -export const setMentions = (mentions) => graphHookAction({ - 'set-mentions': mentions -}); -export const setWatchOnSelf = (watchSelf) => graphHookAction({ - 'set-watch-on-self': watchSelf -}); -export const setDoNotDisturb = (dnd) => harkAction({ - 'set-dnd': dnd -}); -export const archive = (bin, lid) => harkAction({ - archive: { - lid, - bin - } -}); -export const opened = harkAction({ - opened: null -}); -export const markCountAsRead = (place) => harkAction({ - 'read-count': place -}); -export const markEachAsRead = (place, path) => harkAction({ - 'read-each': { - place, - path - } -}); -export const seen = () => harkAction({ seen: null }); -export const readAll = harkAction({ 'read-all': null }); -export const archiveAll = harkAction({ 'archive-all': null }); -export const ignoreGroup = (group) => groupHookAction({ - ignore: group -}); -export const ignoreGraph = (graph, index) => graphHookAction({ - ignore: { - graph, - index - } -}); -export const listenGroup = (group) => groupHookAction({ - listen: group -}); -export const listenGraph = (graph, index) => graphHookAction({ - listen: { - graph, - index - } -}); -/** - * Read all graphs belonging to a particular group - */ -export const readGroup = (group) => harkAction({ - 'read-group': group -}); -/** - * Read all unreads in a graph - */ -export const readGraph = (graph) => harkAction({ - 'read-graph': graph -}); -export function harkBinToId(bin) { - const { place, path } = bin; - return `${place.desk}${place.path}${path}`; -} -export function harkBinEq(a, b) { - return (a.place.path === b.place.path && - a.place.desk === b.place.desk && - a.path === b.path); -} -export function harkLidToId(lid) { - if ('time' in lid) { - return `archive-${lid.time}`; - } - return Object.keys(lid)[0]; -} -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/lib.js.map b/pkg/npm/api/tmp/hark/lib.js.map deleted file mode 100644 index 8915f9d06..000000000 --- a/pkg/npm/api/tmp/hark/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../hark/lib.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAI,IAAO,EAAW,EAAE,CAAC,CAAC;IAClD,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,aAAa;IACnB,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,eAAe,GAAG,CAAI,IAAO,EAAW,EAAE,CAAC,CAAC;IAChD,GAAG,EAAE,iBAAiB;IACtB,IAAI,EAAE,wBAAwB;IAC9B,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,OAAO,EAAE,eAAe,IAAI,mBAAmB,EAAE,CAAC;AAElD,MAAM,eAAe,GAAG,CAAI,IAAO,EAAW,EAAE,CAAC,CAAC;IAChD,GAAG,EAAE,iBAAiB;IACtB,IAAI,EAAE,wBAAwB;IAC9B,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,OAAO,EAAE,eAAe,IAAI,mBAAmB,EAAE,CAAC;AAElD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,KAAa,EACb,OAAmB,EACnB,GAAY,EACG,EAAE,CACjB,UAAU,CAAC;IACT,CAAC,KAAK,CAAC,EAAE;QACP,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACjC,GAAG;KACJ;CACF,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAiB,EAAiB,EAAE,CAC9D,eAAe,CAAC;IACd,cAAc,EAAE,QAAQ;CACzB,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,SAAkB,EAAiB,EAAE,CAClE,eAAe,CAAC;IACd,mBAAmB,EAAE,SAAS;CAC/B,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAY,EAAiB,EAAE,CAC7D,UAAU,CAAC;IACT,SAAS,EAAE,GAAG;CACf,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAY,EAAE,GAAY,EAAiB,EAAE,CACnE,UAAU,CAAC;IACT,OAAO,EAAE;QACP,GAAG;QACH,GAAG;KACJ;CACF,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC;IAC/B,MAAM,EAAE,IAAI;CACb,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAgB,EAAiB,EAAE,CACjE,UAAU,CAAC;IACT,YAAY,EAAE,KAAK;CACpB,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,KAAgB,EAChB,IAAY,EACG,EAAE,CACjB,UAAU,CAAC;IACT,WAAW,EAAE;QACX,KAAK;QACL,IAAI;KACL;CACF,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAErD,MAAM,CAAC,MAAM,OAAO,GAAG,UAAU,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;AAE9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAiB,EAAE,CAC1D,eAAe,CAAC;IACd,MAAM,EAAE,KAAK;CACd,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,KAAa,EAAiB,EAAE,CACzE,eAAe,CAAC;IACd,MAAM,EAAE;QACN,KAAK;QACL,KAAK;KACN;CACF,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAiB,EAAE,CAC1D,eAAe,CAAC;IACd,MAAM,EAAE,KAAK;CACd,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,KAAa,EAAiB,EAAE,CACzE,eAAe,CAAC;IACd,MAAM,EAAE;QACN,KAAK;QACL,KAAK;KACN;CACF,CAAC,CAAC;AAEL;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE,CACzC,UAAU,CAAC;IACT,YAAY,EAAE,KAAK;CACpB,CAAC,CAAC;AAEL;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE,CACzC,UAAU,CAAC;IACT,YAAY,EAAE,KAAK;CACpB,CAAC,CAAC;AAEL,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC;IAC5B,OAAO,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,EAAE,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAU,EAAE,CAAU;IAC9C,OAAO,CACL,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI;QAC7B,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI;QAC7B,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,IAAG,MAAM,IAAI,GAAG,EAAE;QAChB,OAAO,WAAW,GAAG,CAAC,IAAI,EAAE,CAAC;KAC9B;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/types.d.ts b/pkg/npm/api/tmp/hark/types.d.ts deleted file mode 100644 index 475a0a62a..000000000 --- a/pkg/npm/api/tmp/hark/types.d.ts +++ /dev/null @@ -1,55 +0,0 @@ -export interface HarkStats { - count: number; - each: string[]; - last: number; -} -export interface Timebox { - [binId: string]: Notification; -} -export declare type HarkContent = { - ship: string; -} | { - text: string; -}; -export interface HarkBody { - title: HarkContent[]; - time: string; - content: HarkContent[]; - link: string; - binned: string; -} -export interface HarkPlace { - desk: string; - path: string; -} -export interface HarkBin { - path: string; - place: HarkPlace; -} -export declare type HarkLid = { - unseen: null; -} | { - seen: null; -} | { - time: string; -}; -export declare type HarkBinId = string; -export interface Notification { - bin: HarkBin; - time: number; - body: HarkBody[]; -} -export interface NotificationGraphConfig { - watchOnSelf: boolean; - mentions: boolean; - watching: WatchedIndex[]; -} -export interface Unreads { - [path: string]: HarkStats; -} -interface WatchedIndex { - graph: string; - index: string; -} -export declare type GroupNotificationsConfig = string[]; -export {}; diff --git a/pkg/npm/api/tmp/hark/types.js b/pkg/npm/api/tmp/hark/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/hark/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hark/types.js.map b/pkg/npm/api/tmp/hark/types.js.map deleted file mode 100644 index cc26b3540..000000000 --- a/pkg/npm/api/tmp/hark/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../hark/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/index.d.ts b/pkg/npm/api/tmp/hood/index.d.ts deleted file mode 100644 index e06143cf1..000000000 --- a/pkg/npm/api/tmp/hood/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib'; -export * from './types'; diff --git a/pkg/npm/api/tmp/hood/index.js b/pkg/npm/api/tmp/hood/index.js deleted file mode 100644 index 872ee0de4..000000000 --- a/pkg/npm/api/tmp/hood/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './lib'; -export * from './types'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/index.js.map b/pkg/npm/api/tmp/hood/index.js.map deleted file mode 100644 index deed8c74e..000000000 --- a/pkg/npm/api/tmp/hood/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../hood/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/lib.d.ts b/pkg/npm/api/tmp/hood/lib.d.ts deleted file mode 100644 index 3886ad812..000000000 --- a/pkg/npm/api/tmp/hood/lib.d.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Poke, Scry } from '../lib'; -import { Vats, Vat } from './types'; -export declare const getVats: Scry; -/** - * Install a foreign desk - */ -export declare function kilnInstall(ship: string, desk: string, local?: string): Poke; -/** - * Uninstall a desk - */ -export declare function kilnUninstall(desk: string): Poke; -export declare function kilnSuspend(desk: string): Poke; -export declare function kilnRevive(desk: string): Poke; -export declare function kilnBump(force?: boolean, except?: string[]): { - app: string; - mark: string; - json: { - force: boolean; - except: string[]; - }; -}; -export declare function kilnPause(desk: string): { - app: string; - mark: string; - json: string; -}; -export declare function kilnResume(desk: string): { - app: string; - mark: string; - json: string; -}; -export declare const scryLag: Scry; -export declare function getBlockers(vats: Vats): string[]; -export declare function getVatPublisher(vat: Vat): string | undefined; diff --git a/pkg/npm/api/tmp/hood/lib.js b/pkg/npm/api/tmp/hood/lib.js deleted file mode 100644 index 885f9395b..000000000 --- a/pkg/npm/api/tmp/hood/lib.js +++ /dev/null @@ -1,97 +0,0 @@ -export const getVats = { - app: 'hood', - path: '/kiln/vats' -}; -/** - * Install a foreign desk - */ -export function kilnInstall(ship, desk, local) { - return { - app: 'hood', - mark: 'kiln-install', - json: { - ship, - desk, - local: local || desk - } - }; -} -/** - * Uninstall a desk - */ -export function kilnUninstall(desk) { - return { - app: 'hood', - mark: 'kiln-uninstall', - json: desk - }; -} -export function kilnSuspend(desk) { - return { - app: 'hood', - mark: 'kiln-suspend', - json: desk - }; -} -export function kilnRevive(desk) { - return { - app: 'hood', - mark: 'kiln-revive', - json: desk - }; -} -export function kilnBump(force = false, except = []) { - return { - app: 'hood', - mark: 'kiln-bump', - json: { - force, - except - } - }; -} -export function kilnPause(desk) { - return { - app: 'hood', - mark: 'kiln-pause', - json: desk - }; -} -export function kilnResume(desk) { - return { - app: 'hood', - mark: 'kiln-resume', - json: desk - }; -} -export const scryLag = ({ app: 'hood', path: '/kiln/lag' }); -export function getBlockers(vats) { - const blockers = []; - const base = vats?.base; - if (!base) { - return blockers; - } - const blockedOn = base.arak.rail?.next?.[0]?.weft?.kelvin; - if (!blockedOn) { - return blockers; - } - Object.entries(vats) - .filter(([desk]) => desk !== 'base') - .forEach(([desk, vat]) => { - // assuming only %zuse - const woofs = vat.arak.rail?.next || []; - const kelvins = woofs.map(n => n.weft.kelvin); - if (!(kelvins.includes(blockedOn))) { - blockers.push(desk); - } - }); - return blockers; -} -export function getVatPublisher(vat) { - if (vat.arak.rail) { - const { rail } = vat.arak; - return (rail?.publisher || rail?.ship || undefined); - } - return undefined; -} -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/lib.js.map b/pkg/npm/api/tmp/hood/lib.js.map deleted file mode 100644 index 79f13c95f..000000000 --- a/pkg/npm/api/tmp/hood/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../hood/lib.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/types.d.ts b/pkg/npm/api/tmp/hood/types.d.ts deleted file mode 100644 index 92ff9ed7c..000000000 --- a/pkg/npm/api/tmp/hood/types.d.ts +++ /dev/null @@ -1,145 +0,0 @@ -/** - * A pending commit, awaiting a future kelvin version - */ -interface Woof { - aeon: number; - weft: Weft; -} -interface Rein { - /** - * Agents not in manifest that should be running - */ - add: string[]; - /** - * Agents in manifest that should not be running - */ - sub: string[]; -} -export interface Rail { - /** - * Original publisher of desk, if available - */ - publisher: string | null; - /** - * Ship of foreign vat - */ - ship: string; - /** - * Desk of foreign vat - */ - desk: string; - /** - * Aeon (version number) that we currently have synced - */ - aeon: number; - next: Woof[]; - paused: boolean; -} -/** - * A tracker of a foreign {@link Vat} - * - */ -export interface Arak { - rein: Rein; - rail: Rail | null; -} -/** - * A component's kelvin version - */ -export interface Weft { - /** - * Name of the component - * - * @remarks - * Usually %zuse, %hoon, or %lull - */ - name: string; - /** - * Kelvin version - * - */ - kelvin: number; -} -export interface KilnDiffBlock { - block: { - desk: string; - arak: Arak; - weft: Weft; - blockers: string[]; - }; -} -export interface KilnDiffReset { - reset: { - desk: string; - arak: Arak; - }; -} -export interface KilnDiffMerge { - merge: { - desk: string; - arak: Arak; - }; -} -export interface KilnDiffMergeSunk { - 'merge-sunk': { - desk: string; - arak: Arak; - tang: string; - }; -} -export interface KilnDiffMergeFail { - 'merge-fail': { - desk: string; - arak: Arak; - tang: string; - }; -} -export declare type KilnDiff = KilnDiffBlock | KilnDiffReset | KilnDiffMerge | KilnDiffMergeSunk | KilnDiffMergeFail; -/** - * Cases for revision - * - */ -export interface Cass { - /** - * Revision number - */ - ud: number; - /** - * Timestamp of revision, as stringifed `@da` - * - * @remarks - * If \@da is outside valid positive unix timestamp, value will be zero - */ - da: string; -} -/** - * A local desk installation - */ -export interface Vat { - /** - * Desk that this Vat describes - */ - desk: string; - /** - * Hash of the desk, rendered as `@uv` - * - * @remarks - * Equivalent to - * ```hoon - * .^(@uv %cz /=desk=) - * ``` - */ - hash: string; - /** - * Current revision - */ - cass: Cass; - /** - * Foreign sync - */ - arak: Arak; -} -export interface Vats { - [desk: string]: Vat; -} -export {}; diff --git a/pkg/npm/api/tmp/hood/types.js b/pkg/npm/api/tmp/hood/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/hood/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/hood/types.js.map b/pkg/npm/api/tmp/hood/types.js.map deleted file mode 100644 index bbc8fe4cb..000000000 --- a/pkg/npm/api/tmp/hood/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../hood/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/index.d.ts b/pkg/npm/api/tmp/index.d.ts deleted file mode 100644 index b0576ccfe..000000000 --- a/pkg/npm/api/tmp/index.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -export * from './contacts'; -export * as contacts from './contacts'; -export * from './graph'; -export * as graph from './graph'; -export * from './groups'; -export * as groups from './groups'; -export * from './hark'; -export * as hark from './hark'; -export * from './invite'; -export * from './metadata'; -export * as metadata from './metadata'; -export * from './settings'; -export * as settings from './settings'; -export * from './s3'; -export * as s3 from './s3'; -export * from './lib'; -export * from './lib/BigIntOrderedMap'; -export * from './lib/BigIntArrayOrderedMap'; -export * as hood from './hood'; -export * from './hood'; -export * as docket from './docket'; -export * from './docket'; diff --git a/pkg/npm/api/tmp/index.js b/pkg/npm/api/tmp/index.js deleted file mode 100644 index 75b48a634..000000000 --- a/pkg/npm/api/tmp/index.js +++ /dev/null @@ -1,25 +0,0 @@ -export * from './contacts'; -export * as contacts from './contacts'; -export * from './graph'; -export * as graph from './graph'; -export * from './groups'; -export * as groups from './groups'; -export * from './hark'; -export * as hark from './hark'; -export * from './invite'; -// this conflicts with /groups/lib invite -// export * as invite from './invite'; -export * from './metadata'; -export * as metadata from './metadata'; -export * from './settings'; -export * as settings from './settings'; -export * from './s3'; -export * as s3 from './s3'; -export * from './lib'; -export * from './lib/BigIntOrderedMap'; -export * from './lib/BigIntArrayOrderedMap'; -export * as hood from './hood'; -export * from './hood'; -export * as docket from './docket'; -export * from './docket'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/index.js.map b/pkg/npm/api/tmp/index.js.map deleted file mode 100644 index 91d106aaf..000000000 --- a/pkg/npm/api/tmp/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,cAAc,SAAS,CAAC;AACxB,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,cAAc,QAAQ,CAAC;AACvB,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,yCAAyC;AACzC,sCAAsC;AACtC,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,cAAc,MAAM,CAAC;AACrB,OAAO,KAAK,EAAE,MAAM,MAAM,CAAC;AAC3B,cAAc,OAAO,CAAC;AACtB,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,cAAc,UAAU,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/index.d.ts b/pkg/npm/api/tmp/invite/index.d.ts deleted file mode 100644 index 4a272fce5..000000000 --- a/pkg/npm/api/tmp/invite/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './lib'; diff --git a/pkg/npm/api/tmp/invite/index.js b/pkg/npm/api/tmp/invite/index.js deleted file mode 100644 index 5c8443c9d..000000000 --- a/pkg/npm/api/tmp/invite/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './types'; -export * from './lib'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/index.js.map b/pkg/npm/api/tmp/invite/index.js.map deleted file mode 100644 index ebd16bd59..000000000 --- a/pkg/npm/api/tmp/invite/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../invite/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/lib.d.ts b/pkg/npm/api/tmp/invite/lib.d.ts deleted file mode 100644 index e8c18e884..000000000 --- a/pkg/npm/api/tmp/invite/lib.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Poke, Serial } from "../lib"; -import { InviteUpdate, InviteUpdateAccept, InviteUpdateDecline } from "./types"; -export declare const inviteAction: (data: T) => Poke; -export declare const accept: (app: string, uid: Serial) => Poke; -export declare const decline: (app: string, uid: Serial) => Poke; diff --git a/pkg/npm/api/tmp/invite/lib.js b/pkg/npm/api/tmp/invite/lib.js deleted file mode 100644 index db7195c3c..000000000 --- a/pkg/npm/api/tmp/invite/lib.js +++ /dev/null @@ -1,18 +0,0 @@ -export const inviteAction = (data) => ({ - app: 'invite-store', - mark: 'invite-action', - json: data -}); -export const accept = (app, uid) => inviteAction({ - accept: { - term: app, - uid - } -}); -export const decline = (app, uid) => inviteAction({ - decline: { - term: app, - uid - } -}); -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/lib.js.map b/pkg/npm/api/tmp/invite/lib.js.map deleted file mode 100644 index 8cfb7eaa2..000000000 --- a/pkg/npm/api/tmp/invite/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../invite/lib.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAyB,IAAO,EAAW,EAAE,CAAC,CAAC;IACzE,GAAG,EAAE,cAAc;IACnB,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,GAAW,EACX,GAAW,EACe,EAAE,CAAC,YAAY,CAAC;IAC1C,MAAM,EAAE;QACN,IAAI,EAAE,GAAG;QACT,GAAG;KACJ;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,GAAW,EACX,GAAW,EACgB,EAAE,CAAC,YAAY,CAAC;IAC3C,OAAO,EAAE;QACP,IAAI,EAAE,GAAG;QACT,GAAG;KACJ;CACF,CAAC,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/types.d.ts b/pkg/npm/api/tmp/invite/types.d.ts deleted file mode 100644 index d9418ba8f..000000000 --- a/pkg/npm/api/tmp/invite/types.d.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Serial, PatpNoSig, Path } from '../lib'; -import { Resource } from "../groups"; -export declare type InviteUpdate = InviteUpdateInitial | InviteUpdateCreate | InviteUpdateDelete | InviteUpdateInvite | InviteUpdateAccept | InviteUpdateAccepted | InviteUpdateDecline; -export interface InviteUpdateAccept { - accept: { - term: string; - uid: Serial; - }; -} -export interface InviteUpdateInitial { - initial: Invites; -} -export interface InviteUpdateCreate { - create: { - term: string; - }; -} -export interface InviteUpdateDelete { - delete: { - term: string; - }; -} -export interface InviteUpdateInvite { - invite: { - term: string; - uid: Serial; - invite: Invite; - }; -} -export interface InviteUpdateAccepted { - accepted: { - term: string; - uid: Serial; - }; -} -export interface InviteUpdateDecline { - decline: { - term: string; - uid: Serial; - }; -} -export declare type Invites = { - [p in Path]: AppInvites; -}; -export declare type AppInvites = { - [s in Serial]: Invite; -}; -export interface Invite { - app: string; - recipient: PatpNoSig; - resource: Resource; - ship: PatpNoSig; - text: string; -} diff --git a/pkg/npm/api/tmp/invite/types.js b/pkg/npm/api/tmp/invite/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/invite/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/invite/types.js.map b/pkg/npm/api/tmp/invite/types.js.map deleted file mode 100644 index e163d5eee..000000000 --- a/pkg/npm/api/tmp/invite/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../invite/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.d.ts b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.d.ts deleted file mode 100644 index 4dd317c53..000000000 --- a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { immerable } from 'immer'; -import bigInt, { BigInteger } from 'big-integer'; -export declare function stringToArr(str: string): bigInt.BigInteger[]; -export declare function arrToString(arr: BigInteger[]): string; -export declare function sortBigIntArr(a: BigInteger[], b: BigInteger[]): number; -export declare class BigIntArrayOrderedMap implements Iterable<[BigInteger[], V]> { - root: Record; - cachedIter: [BigInteger[], V][] | null; - [immerable]: boolean; - reversed: boolean; - constructor(items?: [BigInteger[], V][], reversed?: boolean); - get size(): number; - get(key: BigInteger[]): V; - gas(items: [BigInteger[], V][]): this; - set(key: BigInteger[], value: V): this; - clear(): this; - has(key: BigInteger[]): boolean; - delete(key: BigInteger[]): this; - [Symbol.iterator](): IterableIterator<[BigInteger[], V]>; - peekLargest(): [bigInt.BigInteger[], V]; - peekSmallest(): [bigInt.BigInteger[], V]; - keys(): bigInt.BigInteger[][]; - generateCachedIter(): [bigInt.BigInteger[], V][]; -} diff --git a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js deleted file mode 100644 index 04e568ef3..000000000 --- a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js +++ /dev/null @@ -1,131 +0,0 @@ -import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; -import bigInt from 'big-integer'; -setAutoFreeze(false); -enablePatches(); -export function stringToArr(str) { - return str.split('/').slice(1).map((ind) => { - return bigInt(ind); - }); -} -export function arrToString(arr) { - let string = ''; - arr.forEach((key) => { - string = string + `/${key.toString()}`; - }); - return string; -} -function sorted(a, b, reversed = false) { - const getSort = sortBigIntArr(a, b); - if (reversed) { - return getSort * -1; - } - else { - return getSort; - } -} -export function sortBigIntArr(a, b) { - const aLen = a.length; - const bLen = b.length; - const aCop = a.slice(0); - const bCop = b.slice(0); - aCop.reverse(); - bCop.reverse(); - let i = 0; - while (i < aLen && i < bLen) { - if (aCop[i].lt(bCop[i])) { - return 1; - } - else if (aCop[i].gt(bCop[i])) { - return -1; - } - else { - i++; - } - } - return bLen - aLen; -} -export class BigIntArrayOrderedMap { - root = {}; - cachedIter = null; - [immerable] = true; - reversed = false; - constructor(items = [], reversed = false) { - items.forEach(([key, val]) => { - this.set(key, val); - }); - this.reversed = reversed; - } - get size() { - return Object.keys(this.root).length; - } - get(key) { - return this.root[arrToString(key)] ?? null; - } - gas(items) { - return produce(this, (draft) => { - items.forEach(([key, value]) => { - draft.root[arrToString(key)] = castDraft(value); - }); - draft.generateCachedIter(); - }, (patches) => { - // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); - }); - } - set(key, value) { - return produce(this, (draft) => { - draft.root[arrToString(key)] = castDraft(value); - draft.cachedIter = null; - }); - } - clear() { - return produce(this, (draft) => { - draft.cachedIter = []; - draft.root = {}; - }); - } - has(key) { - return arrToString(key) in this.root; - } - delete(key) { - const result = produce(this, (draft) => { - delete draft.root[arrToString(key)]; - draft.cachedIter = null; - }); - return result; - } - [Symbol.iterator]() { - let idx = 0; - const result = this.generateCachedIter(); - return { - [Symbol.iterator]: this[Symbol.iterator], - next: () => { - if (idx < result.length) { - return { value: result[idx++], done: false }; - } - return { done: true, value: null }; - } - }; - } - peekLargest() { - const sorted = Array.from(this); - return sorted[0]; - } - peekSmallest() { - const sorted = Array.from(this); - return sorted[sorted.length - 1]; - } - keys() { - return Array.from(this).map(([k, v]) => k); - } - generateCachedIter() { - if (this.cachedIter) { - return [...this.cachedIter]; - } - const result = Object.keys(this.root).map((key) => { - return [stringToArr(key), this.root[key]]; - }).sort(([a], [b]) => sorted(a, b, this.reversed)); - this.cachedIter = result; - return [...result]; - } -} -//# sourceMappingURL=BigIntArrayOrderedMap.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js.map b/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js.map deleted file mode 100644 index 81db34c03..000000000 --- a/pkg/npm/api/tmp/lib/BigIntArrayOrderedMap.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"BigIntArrayOrderedMap.js","sourceRoot":"","sources":["../../lib/BigIntArrayOrderedMap.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts b/pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts deleted file mode 100644 index bcbcbb0e7..000000000 --- a/pkg/npm/api/tmp/lib/BigIntOrderedMap.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { immerable } from 'immer'; -import bigInt, { BigInteger } from 'big-integer'; -export declare class BigIntOrderedMap implements Iterable<[BigInteger, V]> { - root: Record; - cachedIter: [BigInteger, V][] | null; - [immerable]: boolean; - constructor(items?: [BigInteger, V][]); - get size(): number; - get(key: BigInteger): V; - gas(items: [BigInteger, V][]): this; - set(key: BigInteger, value: V): this; - clear(): this; - has(key: BigInteger): boolean; - delete(key: BigInteger): this; - [Symbol.iterator](): IterableIterator<[BigInteger, V]>; - peekLargest(): [bigInt.BigInteger, V]; - peekSmallest(): [bigInt.BigInteger, V]; - keys(): bigInt.BigInteger[]; - generateCachedIter(): [bigInt.BigInteger, V][]; -} diff --git a/pkg/npm/api/tmp/lib/BigIntOrderedMap.js b/pkg/npm/api/tmp/lib/BigIntOrderedMap.js deleted file mode 100644 index ee37d9aef..000000000 --- a/pkg/npm/api/tmp/lib/BigIntOrderedMap.js +++ /dev/null @@ -1,102 +0,0 @@ -import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; -import bigInt from 'big-integer'; -setAutoFreeze(false); -enablePatches(); -function sortBigInt(a, b) { - if (a.lt(b)) { - return 1; - } - else if (a.eq(b)) { - return 0; - } - else { - return -1; - } -} -export class BigIntOrderedMap { - root = {}; - cachedIter = null; - [immerable] = true; - constructor(items = []) { - items.forEach(([key, val]) => { - this.set(key, val); - }); - } - get size() { - if (this.cachedIter) { - return this.cachedIter.length; - } - return this.generateCachedIter().length; - } - get(key) { - return this.root[key.toString()] ?? null; - } - gas(items) { - return produce(this, (draft) => { - items.forEach(([key, value]) => { - draft.root[key.toString()] = castDraft(value); - }); - draft.cachedIter = null; - }, (patches) => { - // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); - }); - } - set(key, value) { - return produce(this, (draft) => { - draft.root[key.toString()] = castDraft(value); - draft.cachedIter = null; - }); - } - clear() { - return produce(this, (draft) => { - draft.cachedIter = []; - draft.root = {}; - }); - } - has(key) { - return key.toString() in this.root; - } - delete(key) { - const result = produce(this, (draft) => { - delete draft.root[key.toString()]; - draft.cachedIter = null; - }); - return result; - } - [Symbol.iterator]() { - let idx = 0; - const result = this.generateCachedIter(); - return { - [Symbol.iterator]: this[Symbol.iterator], - next: () => { - if (idx < result.length) { - return { value: result[idx++], done: false }; - } - return { done: true, value: null }; - } - }; - } - peekLargest() { - const sorted = Array.from(this); - return sorted[0]; - } - peekSmallest() { - const sorted = Array.from(this); - return sorted[sorted.length - 1]; - } - keys() { - return Array.from(this).map(([k, v]) => k); - } - generateCachedIter() { - if (this.cachedIter) { - return [...this.cachedIter]; - } - const result = Object.keys(this.root).map((key) => { - const num = bigInt(key); - return [num, this.root[key]]; - }).sort(([a], [b]) => sortBigInt(a, b)); - this.cachedIter = result; - return [...result]; - } -} -//# sourceMappingURL=BigIntOrderedMap.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map b/pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map deleted file mode 100644 index f907f6444..000000000 --- a/pkg/npm/api/tmp/lib/BigIntOrderedMap.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"BigIntOrderedMap.js","sourceRoot":"","sources":["../../lib/BigIntOrderedMap.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACpF,OAAO,MAAsB,MAAM,aAAa,CAAC;AAEjD,aAAa,CAAC,KAAK,CAAC,CAAC;AAErB,aAAa,EAAE,CAAC;AAEhB,SAAS,UAAU,CAAC,CAAa,EAAE,CAAa;IAC9C,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;QACX,OAAO,CAAC,CAAC;KACV;SAAM,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;QAClB,OAAO,CAAC,CAAC;KACV;SAAM;QACL,OAAO,CAAC,CAAC,CAAC;KACX;AACH,CAAC;AACD,MAAM,OAAO,gBAAgB;IAC3B,IAAI,GAAsB,EAAE,CAAA;IAC5B,UAAU,GAA6B,IAAI,CAAC;IAC5C,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAEnB,YAAY,QAA2B,EAAE;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE;YAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI;QACN,IAAG,IAAI,CAAC,UAAU,EAAE;YAClB,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;SAC/B;QACD,OAAO,IAAI,CAAC,kBAAkB,EAAE,CAAC,MAAM,CAAC;IAC1C,CAAC;IAED,GAAG,CAAC,GAAe;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,IAAI,CAAC;IAC3C,CAAC;IAED,GAAG,CAAC,KAAwB;QAC1B,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;YAC7B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;gBAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YAChD,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;QAC1B,CAAC,EACD,CAAC,OAAO,EAAE,EAAE;YACV,kEAAkE;QACpE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,GAAe,EAAE,KAAQ;QAC3B,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;YAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YAC9C,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;YAC7B,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,GAAe;QACjB,OAAO,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,GAAe;QACpB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE;YACrC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YAClC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,CAAC,MAAM,CAAC,QAAQ,CAAC;QACf,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACzC,OAAO;YACL,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;YACxC,IAAI,EAAE,GAAoC,EAAE;gBAC1C,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE;oBACvB,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;iBAC9C;gBACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACrC,CAAC;SACF,CAAC;IACJ,CAAC;IAED,WAAW;QACT,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,OAAO,MAAM,CAAC,CAAC,CAA2B,CAAC;IAC7C,CAAC;IAED,YAAY;QACV,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAA2B,CAAC;IAC7D,CAAC;IAED,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,kBAAkB;QAChB,IAAG,IAAI,CAAC,UAAU,EAAE;YAClB,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;SAC7B;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YAChD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YACxB,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAoB,CAAC;QAClD,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QACzB,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IACrB,CAAC;CACF"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/index.d.ts b/pkg/npm/api/tmp/lib/index.d.ts deleted file mode 100644 index e06143cf1..000000000 --- a/pkg/npm/api/tmp/lib/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib'; -export * from './types'; diff --git a/pkg/npm/api/tmp/lib/index.js b/pkg/npm/api/tmp/lib/index.js deleted file mode 100644 index 872ee0de4..000000000 --- a/pkg/npm/api/tmp/lib/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './lib'; -export * from './types'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/index.js.map b/pkg/npm/api/tmp/lib/index.js.map deleted file mode 100644 index f4062559b..000000000 --- a/pkg/npm/api/tmp/lib/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/lib.d.ts b/pkg/npm/api/tmp/lib/lib.d.ts deleted file mode 100644 index 2600d247a..000000000 --- a/pkg/npm/api/tmp/lib/lib.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { BigInteger } from "big-integer"; -import { Resource } from "../groups/types"; -import { Post, GraphNode } from "../graph/types"; -/** - * Given a bigint representing an urbit date, returns a unix timestamp. - * - * @param {BigInteger} da The urbit date - * - * @return {number} The unix timestamp - */ -export declare function daToUnix(da: BigInteger): number; -/** - * Given a unix timestamp, returns a bigint representing an urbit date - * - * @param {number} unix The unix timestamp - * - * @return {BigInteger} The urbit date - */ -export declare function unixToDa(unix: number): BigInteger; -export declare function makePatDa(patda: string): BigInteger; -export declare function udToDec(ud: string): string; -export declare function decToUd(str: string): string; -export declare function resourceAsPath(resource: Resource): string; -export declare function uuid(): string; -export declare function daToDate(st: string): Date; -export declare function dateToDa(d: Date, mil?: boolean): string; -export declare function deSig(ship: string): string | null; -export declare function cite(ship: string): string; -export declare function uxToHex(ux: string): string; -export declare const hexToUx: (hex: string) => string; -export declare function stringToTa(str: string): string; -export declare const buntPost: () => Post; -export declare function makeNodeMap(posts: Post[]): Record; diff --git a/pkg/npm/api/tmp/lib/lib.js b/pkg/npm/api/tmp/lib/lib.js deleted file mode 100644 index 6b52d21c0..000000000 --- a/pkg/npm/api/tmp/lib/lib.js +++ /dev/null @@ -1,207 +0,0 @@ -import bigInt from "big-integer"; -const DA_UNIX_EPOCH = bigInt("170141184475152167957503069145530368000"); // `@ud` ~1970.1.1 -const DA_SECOND = bigInt("18446744073709551616"); // `@ud` ~s1 -function chunk(arr, size) { - let chunk = []; - let newArray = [chunk]; - for (let i = 0; i < arr.length; i++) { - if (chunk.length < size) { - chunk.push(arr[i]); - } - else { - chunk = [arr[i]]; - newArray.push(chunk); - } - } - return newArray; -} -function dropWhile(arr, pred) { - const newArray = arr.slice(); - for (const item of arr) { - if (pred(item)) { - newArray.shift(); - } - else { - return newArray; - } - } - return newArray; -} -/** - * Given a bigint representing an urbit date, returns a unix timestamp. - * - * @param {BigInteger} da The urbit date - * - * @return {number} The unix timestamp - */ -export function daToUnix(da) { - // ported from +time:enjs:format in hoon.hoon - const offset = DA_SECOND.divide(bigInt(2000)); - const epochAdjusted = offset.add(da.subtract(DA_UNIX_EPOCH)); - return Math.round(epochAdjusted.multiply(bigInt(1000)).divide(DA_SECOND).toJSNumber()); -} -/** - * Given a unix timestamp, returns a bigint representing an urbit date - * - * @param {number} unix The unix timestamp - * - * @return {BigInteger} The urbit date - */ -export function unixToDa(unix) { - const timeSinceEpoch = bigInt(unix).multiply(DA_SECOND).divide(bigInt(1000)); - return DA_UNIX_EPOCH.add(timeSinceEpoch); -} -export function makePatDa(patda) { - return bigInt(udToDec(patda)); -} -export function udToDec(ud) { - return ud.replace(/\./g, ""); -} -export function decToUd(str) { - const transform = chunk(str.split('').reverse(), 3) - .map(group => group.reverse().join('')) - .reverse() - .join('.'); - return transform.replace(/^[0\.]+/g, ''); -} -export function resourceAsPath(resource) { - const { name, ship } = resource; - return `/ship/~${ship}/${name}`; -} -export function uuid() { - let str = "0v"; - str += Math.ceil(Math.random() * 8) + "."; - for (let i = 0; i < 5; i++) { - let _str = Math.ceil(Math.random() * 10000000).toString(32); - _str = ("00000" + _str).substr(-5, 5); - str += _str + "."; - } - return str.slice(0, -1); -} -/* - Goes from: - ~2018.7.17..23.15.09..5be5 // urbit @da - To: - (javascript Date object) -*/ -export function daToDate(st) { - const dub = function (n) { - return parseInt(n) < 10 ? "0" + parseInt(n) : n.toString(); - }; - const da = st.split(".."); - const bigEnd = da[0].split("."); - const lilEnd = da[1].split("."); - const ds = `${bigEnd[0].slice(1)}-${dub(bigEnd[1])}-${dub(bigEnd[2])}T${dub(lilEnd[0])}:${dub(lilEnd[1])}:${dub(lilEnd[2])}Z`; - return new Date(ds); -} -/* - Goes from: - (javascript Date object) - To: - ~2018.7.17..23.15.09..5be5 // urbit @da -*/ -export function dateToDa(d, mil = false) { - const fil = function (n) { - return n >= 10 ? n : "0" + n; - }; - return (`~${d.getUTCFullYear()}.` + - `${d.getUTCMonth() + 1}.` + - `${fil(d.getUTCDate())}..` + - `${fil(d.getUTCHours())}.` + - `${fil(d.getUTCMinutes())}.` + - `${fil(d.getUTCSeconds())}` + - `${mil ? "..0000" : ""}`); -} -export function deSig(ship) { - if (!ship) { - return null; - } - return ship.replace("~", ""); -} -// trim patps to match dojo, chat-cli -export function cite(ship) { - let patp = ship, shortened = ''; - if (patp === null || patp === '') { - return null; - } - if (patp.startsWith('~')) { - patp = patp.substr(1); - } - // comet - if (patp.length === 56) { - shortened = '~' + patp.slice(0, 6) + '_' + patp.slice(50, 56); - return shortened; - } - // moon - if (patp.length === 27) { - shortened = '~' + patp.slice(14, 20) + '^' + patp.slice(21, 27); - return shortened; - } - return `~${patp}`; -} -export function uxToHex(ux) { - if (ux.length > 2 && ux.substr(0, 2) === '0x') { - const value = ux.substr(2).replace('.', '').padStart(6, '0'); - return value; - } - const value = ux.replace('.', '').padStart(6, '0'); - return value; -} -export const hexToUx = (hex) => { - const nonZeroChars = dropWhile(hex.split(''), y => y === '0'); - const ux = chunk(nonZeroChars.reverse(), 4).map(x => { - return x.reverse().join(''); - }).reverse().join('.') || '0'; - return `0x${ux}`; -}; -// encode the string into @ta-safe format, using logic from +wood. -// for example, 'some Chars!' becomes '~.some.~43.hars~21.' -// -export function stringToTa(str) { - let out = ""; - for (let i = 0; i < str.length; i++) { - const char = str[i]; - let add = ""; - switch (char) { - case " ": - add = "."; - break; - case ".": - add = "~."; - break; - case "~": - add = "~~"; - break; - default: - const charCode = str.charCodeAt(i); - if ((charCode >= 97 && charCode <= 122) || // a-z - (charCode >= 48 && charCode <= 57) || // 0-9 - char === "-") { - add = char; - } - else { - // TODO behavior for unicode doesn't match +wood's, - // but we can probably get away with that for now. - add = "~" + charCode.toString(16) + "."; - } - } - out = out + add; - } - return "~." + out; -} -export const buntPost = () => ({ - author: '', - contents: [], - hash: null, - index: '', - signatures: [], - 'time-sent': 0 -}); -export function makeNodeMap(posts) { - const nodes = {}; - posts.forEach((p) => { - nodes[String(p.index)] = { children: null, post: p }; - }); - return nodes; -} -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/lib.js.map b/pkg/npm/api/tmp/lib/lib.js.map deleted file mode 100644 index 8d263d786..000000000 --- a/pkg/npm/api/tmp/lib/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../lib/lib.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/types.d.ts b/pkg/npm/api/tmp/lib/types.d.ts deleted file mode 100644 index f35993cc3..000000000 --- a/pkg/npm/api/tmp/lib/types.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Martian embassy - */ -import { BigIntOrderedMap } from "./BigIntOrderedMap"; -export declare type Path = string; -export declare type Patp = string; -export declare type PatpNoSig = string; -export declare type Serial = string; -export declare type Jug = Map>; -export declare type AppName = 'chat' | 'link' | 'contacts' | 'publish' | 'graph' | 'groups'; -export declare type ShipRank = 'czar' | 'king' | 'duke' | 'earl' | 'pawn'; -export declare type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete'; -export declare type SetElement = S extends Set<(infer T)> ? T : never; -export declare type MapKey = M extends Map<(infer K), any> ? K : never; -export declare type MapValue = M extends Map ? V : never; -/** - * Turns sets into arrays and maps into objects so we can send them over the wire - */ -export declare type Enc = S extends Set ? Enc>[] : S extends Map ? { - [s: string]: Enc>; -} : S extends object ? { - [K in keyof S]: Enc; -} : S extends BigIntOrderedMap ? { - [index: string]: T; -} : S; -export declare type Mark = string; -export interface Poke { - ship?: string; - app: string; - mark: Mark; - json: Action; -} -export interface Scry { - app: string; - path: string; -} -export interface Thread { - inputMark: string; - outputMark: string; - threadName: string; - body: Action; -} diff --git a/pkg/npm/api/tmp/lib/types.js b/pkg/npm/api/tmp/lib/types.js deleted file mode 100644 index b5d0954fb..000000000 --- a/pkg/npm/api/tmp/lib/types.js +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Martian embassy - */ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/lib/types.js.map b/pkg/npm/api/tmp/lib/types.js.map deleted file mode 100644 index 212a6e318..000000000 --- a/pkg/npm/api/tmp/lib/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"AAAA;;GAEG"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/index.d.ts b/pkg/npm/api/tmp/metadata/index.d.ts deleted file mode 100644 index 4a272fce5..000000000 --- a/pkg/npm/api/tmp/metadata/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './lib'; diff --git a/pkg/npm/api/tmp/metadata/index.js b/pkg/npm/api/tmp/metadata/index.js deleted file mode 100644 index 5c8443c9d..000000000 --- a/pkg/npm/api/tmp/metadata/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './types'; -export * from './lib'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/index.js.map b/pkg/npm/api/tmp/metadata/index.js.map deleted file mode 100644 index 7be78af17..000000000 --- a/pkg/npm/api/tmp/metadata/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../metadata/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/lib.d.ts b/pkg/npm/api/tmp/metadata/lib.d.ts deleted file mode 100644 index 221a2d820..000000000 --- a/pkg/npm/api/tmp/metadata/lib.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Path, Poke, PatpNoSig } from '../lib'; -import { MdAppName, Association, Metadata, MetadataUpdate, MetadataUpdateAdd, MetadataUpdateRemove, MetadataEditField, MetadataUpdateEdit } from './types'; -export declare const METADATA_UPDATE_VERSION = 2; -export declare const metadataAction: (data: T, version?: number) => Poke; -export declare const add: (ship: PatpNoSig, appName: MdAppName, resource: Path, group: Path, title: string, description: string, dateCreated: string, color: string, moduleName: string) => Poke; -export { add as metadataAdd }; -export declare const remove: (appName: MdAppName, resource: string, group: string) => Poke; -export { remove as metadataRemove }; -export declare const edit: (association: Association, edit: MetadataEditField) => Poke; -export { edit as metadataEdit }; -/** - * @deprecated use {@link edit} instead - */ -export declare const update: (association: Association, newMetadata: Partial) => Poke; -export { update as metadataUpdate }; diff --git a/pkg/npm/api/tmp/metadata/lib.js b/pkg/npm/api/tmp/metadata/lib.js deleted file mode 100644 index c6fed6976..000000000 --- a/pkg/npm/api/tmp/metadata/lib.js +++ /dev/null @@ -1,69 +0,0 @@ -import { uxToHex } from '../lib'; -export const METADATA_UPDATE_VERSION = 2; -export const metadataAction = (data, version = METADATA_UPDATE_VERSION) => ({ - app: 'metadata-push-hook', - mark: `metadata-update-${version}`, - json: data -}); -export const add = (ship, appName, resource, group, title, description, dateCreated, color, moduleName) => metadataAction({ - add: { - group, - resource: { - resource, - 'app-name': appName - }, - metadata: { - title, - description, - color, - 'date-created': dateCreated, - creator: `~${ship}`, - config: { graph: moduleName }, - picture: '', - hidden: false, - preview: false, - vip: '' - } - } -}); -export { add as metadataAdd }; -export const remove = (appName, resource, group) => metadataAction({ - remove: { - group, - resource: { - resource, - 'app-name': appName - } - } -}); -export { remove as metadataRemove }; -export const edit = (association, edit) => metadataAction({ - edit: { - group: association.group, - resource: { - resource: association.resource, - 'app-name': association['app-name'] - }, - edit - } -}); -export { edit as metadataEdit }; -/** - * @deprecated use {@link edit} instead - */ -export const update = (association, newMetadata) => { - const metadata = { ...association.metadata, ...newMetadata }; - metadata.color = uxToHex(metadata.color); - return metadataAction({ - add: { - group: association.group, - resource: { - resource: association.resource, - 'app-name': association['app-name'] - }, - metadata - } - }); -}; -export { update as metadataUpdate }; -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/lib.js.map b/pkg/npm/api/tmp/metadata/lib.js.map deleted file mode 100644 index 933172f52..000000000 --- a/pkg/npm/api/tmp/metadata/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../metadata/lib.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,OAAO,EAAa,MAAM,QAAQ,CAAC;AAGxD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAEzC,MAAM,CAAC,MAAM,cAAc,GAAG,CAA2B,IAAO,EAAE,UAAkB,uBAAuB,EAAW,EAAE,CAAC,CAAC;IACxH,GAAG,EAAE,oBAAoB;IACzB,IAAI,EAAE,mBAAmB,OAAO,EAAE;IAClC,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,GAAG,GAAG,CACjB,IAAe,EACf,OAAkB,EAClB,QAAc,EACd,KAAW,EACX,KAAa,EACb,WAAmB,EACnB,WAAmB,EACnB,KAAa,EACb,UAAkB,EACO,EAAE,CAAC,cAAc,CAAC;IAC3C,GAAG,EAAE;QACH,KAAK;QACL,QAAQ,EAAE;YACR,QAAQ;YACR,UAAU,EAAE,OAAO;SACpB;QACD,QAAQ,EAAE;YACR,KAAK;YACL,WAAW;YACX,KAAK;YACL,cAAc,EAAE,WAAW;YAC3B,OAAO,EAAE,IAAI,IAAI,EAAE;YACnB,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE;YAC7B,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,KAAK;YACd,GAAG,EAAE,EAAE;SACR;KACF;CACF,CAAC,CAAC;AAEH,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC;AAE9B,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,OAAkB,EAClB,QAAgB,EAChB,KAAa,EACe,EAAE,CAAC,cAAc,CAAuB;IACpE,MAAM,EAAE;QACN,KAAK;QACL,QAAQ,EAAE;YACR,QAAQ;YACR,UAAU,EAAE,OAAO;SACpB;KACF;CACF,CAAC,CAAC;AAEH,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAC;AAEpC,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,WAAwB,EACxB,IAAuB,EACG,EAAE,CAAC,cAAc,CAAqB;IAChE,IAAI,EAAE;QACJ,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,QAAQ,EAAE;YACR,QAAQ,EAAE,WAAW,CAAC,QAAQ;YAC9B,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC;SACpC;QACD,IAAI;KACL;CACF,CAAC,CAAC;AAEH,OAAO,EAAE,IAAI,IAAI,YAAY,EAAE,CAAC;AAEhC;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,WAAwB,EACxB,WAA8B,EACL,EAAE;IAC3B,MAAM,QAAQ,GAAG,EAAE,GAAG,WAAW,CAAC,QAAQ,EAAE,GAAG,WAAW,EAAE,CAAC;IAC3D,QAAQ,CAAC,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,cAAc,CAAoB;QACvC,GAAG,EAAE;YACH,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,QAAQ,EAAE;gBACR,QAAQ,EAAE,WAAW,CAAC,QAAQ;gBAC9B,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC;aACpC;YACD,QAAQ;SACT;KACF,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/types.d.ts b/pkg/npm/api/tmp/metadata/types.d.ts deleted file mode 100644 index 7459689b8..000000000 --- a/pkg/npm/api/tmp/metadata/types.d.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Path, Patp } from '../lib'; -export declare type MdAppName = 'groups' | 'graph'; -export declare type MetadataUpdate = MetadataUpdateInitial | MetadataUpdateAdd | MetadataUpdateUpdate | MetadataUpdateRemove | MetadataUpdateEdit; -export interface MetadataUpdateInitial { - associations: ResourceAssociations; -} -export declare type ResourceAssociations = { - [p in Path]: Association; -}; -export declare type MetadataUpdateAdd = { - add: AssociationPoke; -}; -export declare type MetadataUpdateUpdate = { - update: AssociationPoke; -}; -export interface MetadataUpdateEdit { - edit: { - resource: MdResource; - group: string; - edit: MetadataEditField; - }; -} -export declare type MetadataEditField = Partial>; -export declare type MetadataUpdateRemove = { - remove: { - resource: MdResource; - group: string; - }; -}; -export interface MdResource { - resource: string; - 'app-name': MdAppName; -} -export interface MetadataUpdatePreview { - group: string; - channels: Associations; - 'channel-count': number; - members: number; - metadata: Metadata; -} -export declare type Associations = { - groups: AppAssociations; - graph: AppAssociations; -}; -export declare type AppAssociations = { - [p in Path]: Association; -}; -export declare type Association = MdResource & { - group: Path; - metadata: Metadata; -}; -export interface AssociationPoke { - group: Path; - resource: MdResource; - metadata: Metadata; -} -export interface Metadata { - color: string; - creator: Patp; - 'date-created': string; - description: string; - title: string; - config: C; - hidden: boolean; - picture: string; - preview: boolean; - vip: PermVariation; -} -export declare type MetadataConfig = GroupConfig | GraphConfig; -export interface GraphConfig { - graph: string; -} -export interface GroupConfig { - group: undefined | {} | MdResource; -} -export declare type PermVariation = '' | ' ' | 'reader-comments' | 'member-metadata' | 'host-feed' | 'admin-feed'; diff --git a/pkg/npm/api/tmp/metadata/types.js b/pkg/npm/api/tmp/metadata/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/metadata/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/metadata/types.js.map b/pkg/npm/api/tmp/metadata/types.js.map deleted file mode 100644 index 8a55fbd72..000000000 --- a/pkg/npm/api/tmp/metadata/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../metadata/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/index.d.ts b/pkg/npm/api/tmp/s3/index.d.ts deleted file mode 100644 index e06143cf1..000000000 --- a/pkg/npm/api/tmp/s3/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib'; -export * from './types'; diff --git a/pkg/npm/api/tmp/s3/index.js b/pkg/npm/api/tmp/s3/index.js deleted file mode 100644 index 872ee0de4..000000000 --- a/pkg/npm/api/tmp/s3/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './lib'; -export * from './types'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/index.js.map b/pkg/npm/api/tmp/s3/index.js.map deleted file mode 100644 index c694f0ff7..000000000 --- a/pkg/npm/api/tmp/s3/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../s3/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/lib.d.ts b/pkg/npm/api/tmp/s3/lib.d.ts deleted file mode 100644 index edbfa465b..000000000 --- a/pkg/npm/api/tmp/s3/lib.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Poke } from '../lib/types'; -import { S3UpdateAccessKeyId, S3UpdateAddBucket, S3UpdateCurrentBucket, S3UpdateEndpoint, S3UpdateRemoveBucket, S3UpdateSecretAccessKey } from './types'; -export declare const setCurrentBucket: (bucket: string) => Poke; -export declare const addBucket: (bucket: string) => Poke; -export declare const removeBucket: (bucket: string) => Poke; -export declare const setEndpoint: (endpoint: string) => Poke; -export declare const setAccessKeyId: (accessKeyId: string) => Poke; -export declare const setSecretAccessKey: (secretAccessKey: string) => Poke; diff --git a/pkg/npm/api/tmp/s3/lib.js b/pkg/npm/api/tmp/s3/lib.js deleted file mode 100644 index 4f363769d..000000000 --- a/pkg/npm/api/tmp/s3/lib.js +++ /dev/null @@ -1,24 +0,0 @@ -const s3Action = (data) => ({ - app: 's3-store', - mark: 's3-action', - json: data -}); -export const setCurrentBucket = (bucket) => s3Action({ - 'set-current-bucket': bucket -}); -export const addBucket = (bucket) => s3Action({ - 'add-bucket': bucket -}); -export const removeBucket = (bucket) => s3Action({ - 'remove-bucket': bucket -}); -export const setEndpoint = (endpoint) => s3Action({ - 'set-endpoint': endpoint -}); -export const setAccessKeyId = (accessKeyId) => s3Action({ - 'set-access-key-id': accessKeyId -}); -export const setSecretAccessKey = (secretAccessKey) => s3Action({ - 'set-secret-access-key': secretAccessKey -}); -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/lib.js.map b/pkg/npm/api/tmp/s3/lib.js.map deleted file mode 100644 index 769f49c50..000000000 --- a/pkg/npm/api/tmp/s3/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../s3/lib.ts"],"names":[],"mappings":"AAGA,MAAM,QAAQ,GAAG,CACf,IAAS,EACA,EAAE,CAAC,CAAC;IACb,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,MAAc,EACe,EAAE,CAAC,QAAQ,CAAC;IACzC,oBAAoB,EAAE,MAAM;CAC7B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,MAAc,EACW,EAAE,CAAC,QAAQ,CAAC;IACrC,YAAY,EAAE,MAAM;CACrB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,MAAc,EACc,EAAE,CAAC,QAAQ,CAAC;IACxC,eAAe,EAAE,MAAM;CACxB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,QAAgB,EACQ,EAAE,CAAC,QAAQ,CAAC;IACpC,cAAc,EAAE,QAAQ;CACzB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,WAAmB,EACQ,EAAE,CAAC,QAAQ,CAAC;IACvC,mBAAmB,EAAE,WAAW;CACjC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,eAAuB,EACQ,EAAE,CAAC,QAAQ,CAAC;IAC3C,uBAAuB,EAAE,eAAe;CACzC,CAAC,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/types.d.ts b/pkg/npm/api/tmp/s3/types.d.ts deleted file mode 100644 index 924749718..000000000 --- a/pkg/npm/api/tmp/s3/types.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -export interface S3Credentials { - endpoint: string; - accessKeyId: string; - secretAccessKey: string; -} -export interface S3Configuration { - buckets: Set; - currentBucket: string; -} -export interface S3State { - configuration: S3Configuration; - credentials: S3Credentials | null; -} -export interface S3UpdateCredentials { - credentials: S3Credentials; -} -export interface S3UpdateConfiguration { - configuration: { - buckets: string[]; - currentBucket: string; - }; -} -export interface S3UpdateCurrentBucket { - setCurrentBucket: string; -} -export interface S3UpdateAddBucket { - addBucket: string; -} -export interface S3UpdateRemoveBucket { - removeBucket: string; -} -export interface S3UpdateEndpoint { - setEndpoint: string; -} -export interface S3UpdateAccessKeyId { - setAccessKeyId: string; -} -export interface S3UpdateSecretAccessKey { - setSecretAccessKey: string; -} -export declare type S3Update = S3UpdateCredentials | S3UpdateConfiguration | S3UpdateCurrentBucket | S3UpdateAddBucket | S3UpdateRemoveBucket | S3UpdateEndpoint | S3UpdateAccessKeyId | S3UpdateSecretAccessKey; diff --git a/pkg/npm/api/tmp/s3/types.js b/pkg/npm/api/tmp/s3/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/s3/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/s3/types.js.map b/pkg/npm/api/tmp/s3/types.js.map deleted file mode 100644 index 651890e84..000000000 --- a/pkg/npm/api/tmp/s3/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../s3/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/index.d.ts b/pkg/npm/api/tmp/settings/index.d.ts deleted file mode 100644 index 4a272fce5..000000000 --- a/pkg/npm/api/tmp/settings/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './lib'; diff --git a/pkg/npm/api/tmp/settings/index.js b/pkg/npm/api/tmp/settings/index.js deleted file mode 100644 index 5c8443c9d..000000000 --- a/pkg/npm/api/tmp/settings/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './types'; -export * from './lib'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/index.js.map b/pkg/npm/api/tmp/settings/index.js.map deleted file mode 100644 index 06b65a2d7..000000000 --- a/pkg/npm/api/tmp/settings/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../settings/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/lib.d.ts b/pkg/npm/api/tmp/settings/lib.d.ts deleted file mode 100644 index 8e2da9a75..000000000 --- a/pkg/npm/api/tmp/settings/lib.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Poke, Scry } from '../lib'; -import { PutBucket, Key, Bucket, DelBucket, Value, PutEntry, DelEntry, SettingsUpdate } from './types'; -export declare const action: (data: T) => Poke; -export declare const putBucket: (desk: string, key: Key, bucket: Bucket) => Poke; -export declare const delBucket: (desk: string, key: Key) => Poke; -export declare const putEntry: (desk: string, bucket: Key, key: Key, value: Value) => Poke; -export declare const delEntry: (desk: string, bucket: Key, key: Key) => Poke; -export declare const getAll: Scry; -export declare const getBucket: (desk: string, bucket: string) => { - app: string; - path: string; -}; -export declare const getEntry: (desk: string, bucket: string, entry: string) => { - app: string; - path: string; -}; -export declare const getDeskSettings: (desk: string) => { - app: string; - path: string; -}; -export * from './types'; diff --git a/pkg/npm/api/tmp/settings/lib.js b/pkg/npm/api/tmp/settings/lib.js deleted file mode 100644 index c863ef963..000000000 --- a/pkg/npm/api/tmp/settings/lib.js +++ /dev/null @@ -1,51 +0,0 @@ -export const action = (data) => ({ - app: 'settings-store', - mark: 'settings-event', - json: data -}); -export const putBucket = (desk, key, bucket) => action({ - 'put-bucket': { - desk, - 'bucket-key': key, - 'bucket': bucket - } -}); -export const delBucket = (desk, key) => action({ - 'del-bucket': { - desk, - 'bucket-key': key - } -}); -export const putEntry = (desk, bucket, key, value) => action({ - 'put-entry': { - desk, - 'bucket-key': bucket, - 'entry-key': key, - value: value - } -}); -export const delEntry = (desk, bucket, key) => action({ - 'del-entry': { - desk, - 'bucket-key': bucket, - 'entry-key': key - } -}); -export const getAll = { - app: 'settings-store', - path: '/all' -}; -export const getBucket = (desk, bucket) => ({ - app: 'settings-store', - path: `/bucket/${bucket}` -}); -export const getEntry = (desk, bucket, entry) => ({ - app: 'settings-store', - path: `/entry/${desk}/${bucket}/${entry}` -}); -export const getDeskSettings = (desk) => ({ - app: 'settings-store', - path: `/desk/${desk}` -}); -export * from './types'; -//# sourceMappingURL=lib.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/lib.js.map b/pkg/npm/api/tmp/settings/lib.js.map deleted file mode 100644 index 7c6f13886..000000000 --- a/pkg/npm/api/tmp/settings/lib.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"lib.js","sourceRoot":"","sources":["../../settings/lib.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,MAAM,GAAG,CAA2B,IAAO,EAAW,EAAE,CAAC,CAAC;IACrE,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,IAAI;CACX,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAY,EACZ,GAAQ,EACR,MAAc,EACG,EAAE,CAAC,MAAM,CAAC;IAC3B,YAAY,EAAE;QACZ,IAAI;QACJ,YAAY,EAAE,GAAG;QACjB,QAAQ,EAAE,MAAM;KACjB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAY,EACZ,GAAQ,EACS,EAAE,CAAC,MAAM,CAAC;IAC3B,YAAY,EAAE;QACZ,IAAI;QACJ,YAAY,EAAE,GAAG;KAClB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,MAAW,EACX,GAAQ,EACR,KAAY,EACI,EAAE,CAAC,MAAM,CAAC;IAC1B,WAAW,EAAE;QACX,IAAI;QACJ,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,GAAG;QAChB,KAAK,EAAE,KAAK;KACb;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,MAAW,EACX,GAAQ,EACQ,EAAE,CAAC,MAAM,CAAC;IAC1B,WAAW,EAAE;QACX,IAAI;QACJ,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,GAAG;KACjB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAS;IAC1B,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE,CAAC,CAAC;IAC1D,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,WAAW,MAAM,EAAE;CAC1B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC;IACxE,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,UAAU,IAAI,IAAI,MAAM,IAAI,KAAK,EAAE;CAC1C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;IAChD,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,SAAS,IAAI,EAAE;CACtB,CAAC,CAAC;AAEH,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/types.d.ts b/pkg/npm/api/tmp/settings/types.d.ts deleted file mode 100644 index 9e58650d1..000000000 --- a/pkg/npm/api/tmp/settings/types.d.ts +++ /dev/null @@ -1,52 +0,0 @@ -export declare type Key = string; -export declare type Value = string | string[] | boolean | number; -export declare type Bucket = { - [key: string]: Value; -}; -export declare type DeskSettings = { - [bucket: string]: Bucket; -}; -export declare type Settings = { - [desk: string]: Settings; -}; -export interface PutBucket { - 'put-bucket': { - desk: string; - 'bucket-key': Key; - 'bucket': Bucket; - }; -} -export interface DelBucket { - 'del-bucket': { - desk: string; - 'bucket-key': Key; - }; -} -export interface PutEntry { - 'put-entry': { - 'bucket-key': Key; - 'entry-key': Key; - 'value'?: Value; - }; -} -export interface DelEntry { - 'del-entry': { - desk: string; - 'bucket-key': Key; - 'entry-key': Key; - }; -} -export interface AllData { - 'all': Settings; -} -export interface DeskData { - desk: DeskSettings; -} -export interface BucketData { - 'bucket': Bucket; -} -export interface EntryData { - 'entry': Value; -} -export declare type SettingsUpdate = PutBucket | DelBucket | PutEntry | DelEntry; -export declare type SettingsData = AllData | BucketData | EntryData | DeskData; diff --git a/pkg/npm/api/tmp/settings/types.js b/pkg/npm/api/tmp/settings/types.js deleted file mode 100644 index 718fd38ae..000000000 --- a/pkg/npm/api/tmp/settings/types.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/api/tmp/settings/types.js.map b/pkg/npm/api/tmp/settings/types.js.map deleted file mode 100644 index e768750c4..000000000 --- a/pkg/npm/api/tmp/settings/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../../settings/types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/Urbit.d.ts b/pkg/npm/http-api/tmp/Urbit.d.ts deleted file mode 100644 index 9b4570b1c..000000000 --- a/pkg/npm/http-api/tmp/Urbit.d.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { Scry, Thread, AuthenticationInterface, PokeInterface, SubscriptionRequestInterface } from './types'; -/** - * A class for interacting with an urbit ship, given its URL and code - */ -export declare class Urbit { - url: string; - code?: string; - desk?: string; - /** - * UID will be used for the channel: The current unix time plus a random hex string - */ - private uid; - /** - * Last Event ID is an auto-updated index of which events have been sent over this channel - */ - private lastEventId; - private lastAcknowledgedEventId; - /** - * SSE Client is null for now; we don't want to start polling until it the channel exists - */ - private sseClientInitialized; - /** - * Cookie gets set when we log in. - */ - cookie?: string | undefined; - /** - * A registry of requestId to successFunc/failureFunc - * - * These functions are registered during a +poke and are executed - * in the onServerEvent()/onServerError() callbacks. Only one of - * the functions will be called, and the outstanding poke will be - * removed after calling the success or failure function. - */ - private outstandingPokes; - /** - * A registry of requestId to subscription functions. - * - * These functions are registered during a +subscribe and are - * executed in the onServerEvent()/onServerError() callbacks. The - * event function will be called whenever a new piece of data on this - * subscription is available, which may be 0, 1, or many times. The - * disconnect function may be called exactly once. - */ - private outstandingSubscriptions; - /** - * Our abort controller, used to close the connection - */ - private abort; - /** - * Ship can be set, in which case we can do some magic stuff like send chats - */ - ship?: string | null; - /** - * If verbose, logs output eagerly. - */ - verbose?: boolean; - /** - * number of consecutive errors in connecting to the eventsource - */ - private errorCount; - onError?: (error: any) => void; - onRetry?: () => void; - onOpen?: () => void; - /** This is basic interpolation to get the channel URL of an instantiated Urbit connection. */ - private get channelUrl(); - private get fetchOptions(); - /** - * Constructs a new Urbit connection. - * - * @param url The URL (with protocol and port) of the ship to be accessed. If - * the airlock is running in a webpage served by the ship, this should just - * be the empty string. - * @param code The access code for the ship at that address - */ - constructor(url: string, code?: string, desk?: string); - /** - * All-in-one hook-me-up. - * - * Given a ship, url, and code, this returns an airlock connection - * that is ready to go. It `|hi`s itself to create the channel, - * then opens the channel via EventSource. - * - */ - static authenticate({ ship, url, code, verbose, }: AuthenticationInterface): Promise; - /** - * Connects to the Urbit ship. Nothing can be done until this is called. - * That's why we roll it into this.authenticate - */ - connect(): Promise; - /** - * Initializes the SSE pipe for the appropriate channel. - */ - eventSource(): Promise; - /** - * Reset airlock, abandoning current subscriptions and wiping state - * - */ - reset(): void; - /** - * Autoincrements the next event ID for the appropriate channel. - */ - private getEventId; - /** - * Acknowledges an event. - * - * @param eventId The event to acknowledge. - */ - private ack; - private sendJSONtoChannel; - /** - * Creates a subscription, waits for a fact and then unsubscribes - * - * @param app Name of gall agent to subscribe to - * @param path Path to subscribe to - * @param timeout Optional timeout before ending subscription - * - * @returns The first fact on the subcription - */ - subscribeOnce(app: string, path: string, timeout?: number): Promise; - /** - * Pokes a ship with data. - * - * @param app The app to poke - * @param mark The mark of the data being sent - * @param json The data to send - */ - poke(params: PokeInterface): Promise; - /** - * Subscribes to a path on an app on a ship. - * - * - * @param app The app to subsribe to - * @param path The path to which to subscribe - * @param handlers Handlers to deal with various events of the subscription - */ - subscribe(params: SubscriptionRequestInterface): Promise; - /** - * Unsubscribes to a given subscription. - * - * @param subscription - */ - unsubscribe(subscription: number): Promise; - /** - * Deletes the connection to a channel. - */ - delete(): void; - /** - * Scry into an gall agent at a path - * - * @typeParam T - Type of the scry result - * - * @remarks - * - * Equivalent to - * ```hoon - * .^(T %gx /(scot %p our)/[app]/(scot %da now)/[path]/json) - * ``` - * The returned cage must have a conversion to JSON for the scry to succeed - * - * @param params The scry request - * @returns The scry result - */ - scry(params: Scry): Promise; - /** - * Run a thread - * - * - * @param inputMark The mark of the data being sent - * @param outputMark The mark of the data being returned - * @param threadName The thread to run - * @param body The data to send to the thread - * @returns The return value of the thread - */ - thread(params: Thread): Promise; - /** - * Utility function to connect to a ship that has its *.arvo.network domain configured. - * - * @param name Name of the ship e.g. zod - * @param code Code to log in - */ - static onArvoNetwork(ship: string, code: string): Promise; -} -export default Urbit; diff --git a/pkg/npm/http-api/tmp/Urbit.js b/pkg/npm/http-api/tmp/Urbit.js deleted file mode 100644 index 4f38123cc..000000000 --- a/pkg/npm/http-api/tmp/Urbit.js +++ /dev/null @@ -1,497 +0,0 @@ -import { isBrowser, isNode } from 'browser-or-node'; -import { fetchEventSource, } from '@microsoft/fetch-event-source'; -import { hexString } from './utils'; -/** - * A class for interacting with an urbit ship, given its URL and code - */ -export class Urbit { - /** - * Constructs a new Urbit connection. - * - * @param url The URL (with protocol and port) of the ship to be accessed. If - * the airlock is running in a webpage served by the ship, this should just - * be the empty string. - * @param code The access code for the ship at that address - */ - constructor(url, code, desk) { - this.url = url; - this.code = code; - this.desk = desk; - /** - * UID will be used for the channel: The current unix time plus a random hex string - */ - this.uid = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`; - /** - * Last Event ID is an auto-updated index of which events have been sent over this channel - */ - this.lastEventId = 0; - this.lastAcknowledgedEventId = 0; - /** - * SSE Client is null for now; we don't want to start polling until it the channel exists - */ - this.sseClientInitialized = false; - /** - * A registry of requestId to successFunc/failureFunc - * - * These functions are registered during a +poke and are executed - * in the onServerEvent()/onServerError() callbacks. Only one of - * the functions will be called, and the outstanding poke will be - * removed after calling the success or failure function. - */ - this.outstandingPokes = new Map(); - /** - * A registry of requestId to subscription functions. - * - * These functions are registered during a +subscribe and are - * executed in the onServerEvent()/onServerError() callbacks. The - * event function will be called whenever a new piece of data on this - * subscription is available, which may be 0, 1, or many times. The - * disconnect function may be called exactly once. - */ - this.outstandingSubscriptions = new Map(); - /** - * Our abort controller, used to close the connection - */ - this.abort = new AbortController(); - /** - * number of consecutive errors in connecting to the eventsource - */ - this.errorCount = 0; - this.onError = null; - this.onRetry = null; - this.onOpen = null; - if (isBrowser) { - window.addEventListener('beforeunload', this.delete); - } - return this; - } - /** This is basic interpolation to get the channel URL of an instantiated Urbit connection. */ - get channelUrl() { - return `${this.url}/~/channel/${this.uid}`; - } - get fetchOptions() { - const headers = { - 'Content-Type': 'application/json', - }; - if (!isBrowser) { - headers.Cookie = this.cookie; - } - return { - credentials: 'include', - accept: '*', - headers, - signal: this.abort.signal, - }; - } - /** - * All-in-one hook-me-up. - * - * Given a ship, url, and code, this returns an airlock connection - * that is ready to go. It `|hi`s itself to create the channel, - * then opens the channel via EventSource. - * - */ - static async authenticate({ ship, url, code, verbose = false, }) { - const airlock = new Urbit(`http://${url}`, code); - airlock.verbose = verbose; - airlock.ship = ship; - await airlock.connect(); - await airlock.poke({ - app: 'hood', - mark: 'helm-hi', - json: 'opening airlock', - }); - await airlock.eventSource(); - return airlock; - } - /** - * Connects to the Urbit ship. Nothing can be done until this is called. - * That's why we roll it into this.authenticate - */ - async connect() { - if (this.verbose) { - console.log(`password=${this.code} `, isBrowser - ? 'Connecting in browser context at ' + `${this.url}/~/login` - : 'Connecting from node context'); - } - return fetch(`${this.url}/~/login`, { - method: 'post', - body: `password=${this.code}`, - credentials: 'include', - }).then((response) => { - if (this.verbose) { - console.log('Received authentication response', response); - } - const cookie = response.headers.get('set-cookie'); - if (!this.ship) { - this.ship = new RegExp(/urbauth-~([\w-]+)/).exec(cookie)[1]; - } - if (!isBrowser) { - this.cookie = cookie; - } - }); - } - /** - * Initializes the SSE pipe for the appropriate channel. - */ - async eventSource() { - if (this.sseClientInitialized) { - return Promise.resolve(); - } - if (this.lastEventId === 0) { - // Can't receive events until the channel is open, - // so poke and open then - await this.poke({ - app: 'hood', - mark: 'helm-hi', - json: 'Opening API channel', - }); - return; - } - this.sseClientInitialized = true; - return new Promise((resolve, reject) => { - const sseOptions = { - headers: {}, - }; - if (isBrowser) { - sseOptions.withCredentials = true; - } - else if (isNode) { - sseOptions.headers.Cookie = this.cookie; - } - fetchEventSource(this.channelUrl, { - ...this.fetchOptions, - openWhenHidden: true, - onopen: async (response) => { - if (this.verbose) { - console.log('Opened eventsource', response); - } - if (response.ok) { - this.errorCount = 0; - this.onOpen && this.onOpen(); - resolve(); - return; // everything's good - } - else { - const err = new Error('failed to open eventsource'); - reject(err); - } - }, - onmessage: (event) => { - if (this.verbose) { - console.log('Received SSE: ', event); - } - if (!event.id) - return; - this.lastEventId = parseInt(event.id, 10); - if (this.lastEventId - this.lastAcknowledgedEventId > 20) { - this.ack(this.lastEventId); - } - if (event.data && JSON.parse(event.data)) { - const data = JSON.parse(event.data); - if (data.response === 'poke' && - this.outstandingPokes.has(data.id)) { - const funcs = this.outstandingPokes.get(data.id); - if (data.hasOwnProperty('ok')) { - funcs.onSuccess(); - } - else if (data.hasOwnProperty('err')) { - console.error(data.err); - funcs.onError(data.err); - } - else { - console.error('Invalid poke response', data); - } - this.outstandingPokes.delete(data.id); - } - else if (data.response === 'subscribe' && - this.outstandingSubscriptions.has(data.id)) { - const funcs = this.outstandingSubscriptions.get(data.id); - if (data.hasOwnProperty('err')) { - console.error(data.err); - funcs.err(data.err, data.id); - this.outstandingSubscriptions.delete(data.id); - } - } - else if (data.response === 'diff' && - this.outstandingSubscriptions.has(data.id)) { - const funcs = this.outstandingSubscriptions.get(data.id); - try { - funcs.event(data.json); - } - catch (e) { - console.error('Failed to call subscription event callback', e); - } - } - else if (data.response === 'quit' && - this.outstandingSubscriptions.has(data.id)) { - const funcs = this.outstandingSubscriptions.get(data.id); - funcs.quit(data); - this.outstandingSubscriptions.delete(data.id); - } - else { - console.log([...this.outstandingSubscriptions.keys()]); - console.log('Unrecognized response', data); - } - } - }, - onerror: (error) => { - console.warn(error); - if (this.errorCount++ < 4) { - this.onRetry && this.onRetry(); - return Math.pow(2, this.errorCount - 1) * 750; - } - this.onError && this.onError(error); - throw error; - }, - onclose: () => { - console.log('e'); - throw new Error('Ship unexpectedly closed the connection'); - }, - }); - }); - } - /** - * Reset airlock, abandoning current subscriptions and wiping state - * - */ - reset() { - this.delete(); - this.abort.abort(); - this.abort = new AbortController(); - this.uid = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`; - this.lastEventId = 0; - this.lastAcknowledgedEventId = 0; - this.outstandingSubscriptions = new Map(); - this.outstandingPokes = new Map(); - this.sseClientInitialized = false; - } - /** - * Autoincrements the next event ID for the appropriate channel. - */ - getEventId() { - this.lastEventId = Number(this.lastEventId) + 1; - return this.lastEventId; - } - /** - * Acknowledges an event. - * - * @param eventId The event to acknowledge. - */ - async ack(eventId) { - this.lastAcknowledgedEventId = eventId; - const message = { - action: 'ack', - 'event-id': eventId, - }; - await this.sendJSONtoChannel(message); - return eventId; - } - async sendJSONtoChannel(...json) { - const response = await fetch(this.channelUrl, { - ...this.fetchOptions, - method: 'PUT', - body: JSON.stringify(json), - }); - if (!response.ok) { - throw new Error('Failed to PUT channel'); - } - if (!this.sseClientInitialized) { - await this.eventSource(); - } - } - /** - * Creates a subscription, waits for a fact and then unsubscribes - * - * @param app Name of gall agent to subscribe to - * @param path Path to subscribe to - * @param timeout Optional timeout before ending subscription - * - * @returns The first fact on the subcription - */ - async subscribeOnce(app, path, timeout) { - return new Promise(async (resolve, reject) => { - let done = false; - let id = null; - const quit = () => { - if (!done) { - reject('quit'); - } - }; - const event = (e) => { - if (!done) { - resolve(e); - this.unsubscribe(id); - } - }; - const request = { app, path, event, err: reject, quit }; - id = await this.subscribe(request); - if (timeout) { - setTimeout(() => { - if (!done) { - done = true; - reject('timeout'); - this.unsubscribe(id); - } - }, timeout); - } - }); - } - /** - * Pokes a ship with data. - * - * @param app The app to poke - * @param mark The mark of the data being sent - * @param json The data to send - */ - async poke(params) { - const { app, mark, json, ship, onSuccess, onError } = { - onSuccess: () => { }, - onError: () => { }, - ship: this.ship, - ...params, - }; - const message = { - id: this.getEventId(), - action: 'poke', - ship, - app, - mark, - json, - }; - const [send, result] = await Promise.all([ - this.sendJSONtoChannel(message), - new Promise((resolve, reject) => { - this.outstandingPokes.set(message.id, { - onSuccess: () => { - onSuccess(); - resolve(message.id); - }, - onError: (event) => { - onError(event); - reject(event.err); - }, - }); - }), - ]); - return result; - } - /** - * Subscribes to a path on an app on a ship. - * - * - * @param app The app to subsribe to - * @param path The path to which to subscribe - * @param handlers Handlers to deal with various events of the subscription - */ - async subscribe(params) { - const { app, path, ship, err, event, quit } = { - err: () => { }, - event: () => { }, - quit: () => { }, - ship: this.ship, - ...params, - }; - const message = { - id: this.getEventId(), - action: 'subscribe', - ship, - app, - path, - }; - this.outstandingSubscriptions.set(message.id, { - app, - path, - err, - event, - quit, - }); - await this.sendJSONtoChannel(message); - return message.id; - } - /** - * Unsubscribes to a given subscription. - * - * @param subscription - */ - async unsubscribe(subscription) { - return this.sendJSONtoChannel({ - id: this.getEventId(), - action: 'unsubscribe', - subscription, - }).then(() => { - this.outstandingSubscriptions.delete(subscription); - }); - } - /** - * Deletes the connection to a channel. - */ - delete() { - if (isBrowser) { - navigator.sendBeacon(this.channelUrl, JSON.stringify([ - { - action: 'delete', - }, - ])); - } - else { - // TODO - // this.sendMessage('delete'); - } - } - /** - * Scry into an gall agent at a path - * - * @typeParam T - Type of the scry result - * - * @remarks - * - * Equivalent to - * ```hoon - * .^(T %gx /(scot %p our)/[app]/(scot %da now)/[path]/json) - * ``` - * The returned cage must have a conversion to JSON for the scry to succeed - * - * @param params The scry request - * @returns The scry result - */ - async scry(params) { - const { app, path } = params; - const response = await fetch(`${this.url}/~/scry/${app}${path}.json`, this.fetchOptions); - return await response.json(); - } - /** - * Run a thread - * - * - * @param inputMark The mark of the data being sent - * @param outputMark The mark of the data being returned - * @param threadName The thread to run - * @param body The data to send to the thread - * @returns The return value of the thread - */ - async thread(params) { - const { inputMark, outputMark, threadName, body, desk = this.desk, } = params; - if (!desk) { - throw new Error('Must supply desk to run thread from'); - } - const res = await fetch(`${this.url}/spider/${desk}/${inputMark}/${threadName}/${outputMark}.json`, { - ...this.fetchOptions, - method: 'POST', - body: JSON.stringify(body), - }); - return res.json(); - } - /** - * Utility function to connect to a ship that has its *.arvo.network domain configured. - * - * @param name Name of the ship e.g. zod - * @param code Code to log in - */ - static async onArvoNetwork(ship, code) { - const url = `https://${ship}.arvo.network`; - return await Urbit.authenticate({ ship, url, code }); - } -} -export default Urbit; -//# sourceMappingURL=Urbit.js.map \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/Urbit.js.map b/pkg/npm/http-api/tmp/Urbit.js.map deleted file mode 100644 index 2ef2ed00d..000000000 --- a/pkg/npm/http-api/tmp/Urbit.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Urbit.js","sourceRoot":"","sources":["../src/Urbit.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/index.d.ts b/pkg/npm/http-api/tmp/index.d.ts deleted file mode 100644 index 5c39dfc41..000000000 --- a/pkg/npm/http-api/tmp/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './types'; -import { Urbit } from './Urbit'; -export { Urbit as default, Urbit }; diff --git a/pkg/npm/http-api/tmp/index.js b/pkg/npm/http-api/tmp/index.js deleted file mode 100644 index 46ce972d6..000000000 --- a/pkg/npm/http-api/tmp/index.js +++ /dev/null @@ -1,4 +0,0 @@ -export * from './types'; -import { Urbit } from './Urbit'; -export { Urbit as default, Urbit }; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/index.js.map b/pkg/npm/http-api/tmp/index.js.map deleted file mode 100644 index 011e99d58..000000000 --- a/pkg/npm/http-api/tmp/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC"} \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/types.d.ts b/pkg/npm/http-api/tmp/types.d.ts deleted file mode 100644 index 361d94378..000000000 --- a/pkg/npm/http-api/tmp/types.d.ts +++ /dev/null @@ -1,180 +0,0 @@ -/** - * An urbit style path, rendered as a Javascript string - * @example - * `"/updates"` - */ -export declare type Path = string; -/** - * @p including leading sig, rendered as a string - * - * @example - * ```typescript - * "~sampel-palnet" - * ``` - * - */ -export declare type Patp = string; -/** - * @p not including leading sig, rendered as a string - * - * @example - * ```typescript - * "sampel-palnet" - * ``` - * - */ -export declare type PatpNoSig = string; -/** - * The name of a clay mark, as a string - * - * @example - * ```typescript - * "graph-update" - * ``` - */ -export declare type Mark = string; -/** - * The name of a gall agent, as a string - * - * @example - * - * ```typescript - * "graph-store" - * ``` - */ -export declare type GallAgent = string; -/** - * Description of an outgoing poke - * - * @typeParam Action - Typescript type of the data being poked - */ -export interface Poke { - /** - * Ship to poke. If left empty, the api lib will populate it with the ship that it is connected to. - * - * @remarks - * - * This should always be the ship that you are connected to - * - */ - ship?: PatpNoSig; - /** - */ - app: GallAgent; - /** - * Mark of the cage to be poked - * - */ - mark: Mark; - /** - * Vase of the cage of to be poked, as JSON - */ - json: Action; -} -/** - * Description of a scry request - */ -export interface Scry { - /** {@inheritDoc GallAgent} */ - app: GallAgent; - /** {@inheritDoc Path} */ - path: Path; -} -/** - * Description of a thread request - * - * @typeParam Action - Typescript type of the data being poked - */ -export interface Thread { - /** - * The mark of the input vase - */ - inputMark: Mark; - /** - * The mark of the output vase - */ - outputMark: Mark; - /** - * Name of the thread - * - * @example - * ```typescript - * "graph-add-nodes" - * ``` - */ - threadName: string; - /** - * Desk of thread - */ - desk?: string; - /** - * Data of the input vase - */ - body: Action; -} -export declare type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete'; -export interface PokeHandlers { - onSuccess?: () => void; - onError?: (e: any) => void; -} -export declare type PokeInterface = PokeHandlers & Poke; -export interface AuthenticationInterface { - ship: string; - url: string; - code: string; - verbose?: boolean; -} -/** - * Subscription event handlers - * - */ -export interface SubscriptionInterface { - /** - * Handle negative %watch-ack - */ - err?(error: any, id: string): void; - /** - * Handle %fact - */ - event?(data: any): void; - /** - * Handle %kick - */ - quit?(data: any): void; -} -export declare type OnceSubscriptionErr = 'quit' | 'nack' | 'timeout'; -export interface SubscriptionRequestInterface extends SubscriptionInterface { - /** - * The app to subscribe to - * @example - * `"graph-store"` - */ - app: GallAgent; - /** - * The path to which to subscribe - * @example - * `"/keys"` - */ - path: Path; -} -export interface headers { - 'Content-Type': string; - Cookie?: string; -} -export interface CustomEventHandler { - (data: any, response: string): void; -} -export interface SSEOptions { - headers?: { - Cookie?: string; - }; - withCredentials?: boolean; -} -export interface Message extends Record { - action: Action; - id?: number; -} -export declare class ResumableError extends Error { -} -export declare class FatalError extends Error { -} diff --git a/pkg/npm/http-api/tmp/types.js b/pkg/npm/http-api/tmp/types.js deleted file mode 100644 index 3d3a607cf..000000000 --- a/pkg/npm/http-api/tmp/types.js +++ /dev/null @@ -1,5 +0,0 @@ -export class ResumableError extends Error { -} -export class FatalError extends Error { -} -//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/types.js.map b/pkg/npm/http-api/tmp/types.js.map deleted file mode 100644 index 1c908503f..000000000 --- a/pkg/npm/http-api/tmp/types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAmMA,MAAM,OAAO,cAAe,SAAQ,KAAK;CAAG;AAE5C,MAAM,OAAO,UAAW,SAAQ,KAAK;CAAG"} \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/utils.d.ts b/pkg/npm/http-api/tmp/utils.d.ts deleted file mode 100644 index 75bdaf067..000000000 --- a/pkg/npm/http-api/tmp/utils.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -export declare function camelize(str: string): string; -export declare function uncamelize(str: string, separator?: string): string; -/** - * Returns a hex string of given length. - * - * Poached from StackOverflow. - * - * @param len Length of hex string to return. - */ -export declare function hexString(len: number): string; -/** - * Generates a random UID. - * - * Copied from https://github.com/urbit/urbit/blob/137e4428f617c13f28ed31e520eff98d251ed3e9/pkg/interface/src/lib/util.js#L3 - */ -export declare function uid(): string; diff --git a/pkg/npm/http-api/tmp/utils.js b/pkg/npm/http-api/tmp/utils.js deleted file mode 100644 index 4a99da707..000000000 --- a/pkg/npm/http-api/tmp/utils.js +++ /dev/null @@ -1,51 +0,0 @@ -export function camelize(str) { - return str - .replace(/\s(.)/g, function ($1) { - return $1.toUpperCase(); - }) - .replace(/\s/g, '') - .replace(/^(.)/, function ($1) { - return $1.toLowerCase(); - }); -} -export function uncamelize(str, separator = '-') { - // Replace all capital letters by separator followed by lowercase one - var str = str.replace(/[A-Z]/g, function (letter) { - return separator + letter.toLowerCase(); - }); - return str.replace(new RegExp('^' + separator), ''); -} -/** - * Returns a hex string of given length. - * - * Poached from StackOverflow. - * - * @param len Length of hex string to return. - */ -export function hexString(len) { - const maxlen = 8; - const min = Math.pow(16, Math.min(len, maxlen) - 1); - const max = Math.pow(16, Math.min(len, maxlen)) - 1; - const n = Math.floor(Math.random() * (max - min + 1)) + min; - let r = n.toString(16); - while (r.length < len) { - r = r + hexString(len - maxlen); - } - return r; -} -/** - * Generates a random UID. - * - * Copied from https://github.com/urbit/urbit/blob/137e4428f617c13f28ed31e520eff98d251ed3e9/pkg/interface/src/lib/util.js#L3 - */ -export function uid() { - let str = '0v'; - str += Math.ceil(Math.random() * 8) + '.'; - for (let i = 0; i < 5; i++) { - let _str = Math.ceil(Math.random() * 10000000).toString(32); - _str = ('00000' + _str).substr(-5, 5); - str += _str + '.'; - } - return str.slice(0, -1); -} -//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/pkg/npm/http-api/tmp/utils.js.map b/pkg/npm/http-api/tmp/utils.js.map deleted file mode 100644 index a5238c348..000000000 --- a/pkg/npm/http-api/tmp/utils.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,GAAG;SACP,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAU;QACrC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC;SACD,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;SAClB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAU;QACnC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,SAAS,GAAG,GAAG;IACrD,qEAAqE;IACrE,IAAI,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,MAAc;QACtD,OAAO,SAAS,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IAC1C,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,GAAG,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,MAAM,GAAG,CAAC,CAAC;IACjB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IAC5D,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvB,OAAO,CAAC,CAAC,MAAM,GAAG,GAAG,EAAE;QACrB,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;KACjC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,GAAG;IACjB,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC5D,IAAI,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtC,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC;KACnB;IACD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC"} \ No newline at end of file From e7f9686b1c9a9eb5382ac0041461e8004d124b15 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 18 May 2022 20:25:57 +0200 Subject: [PATCH 116/168] fine: re-enable scry permission check Only expose fully public clay data over scry. Other vanes and permission modes to follow at a later date. --- pkg/arvo/sys/vane/ames.hoon | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index 80db00acd..cc078cbb0 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -1168,13 +1168,12 @@ :: we only support scrying into clay, :: and only if the data is fully public. :: - :: ?. =(%c (end 3 (snag 0 path))) ~ - :: =/ perm-omen (need (de-omen %cp (slag 1 path))) - :: =+ pem=(rof lyc perm-omen) - :: ?> ?=(^ pem) - :: ?> ?=(^ u.pem) - :: =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) - :: ?> =([%black ~ ~] rul.r.per) + ?. =(%c ?@(vis.nom (end 3 vis.nom) way.vis.nom)) ~ + =+ pem=(rof lyc nom(vis %cp)) + ?. ?=(^ pem) ~& %denied-lol ~ + ?. ?=(^ u.pem) ~& %denied-lol ~ + =+ per=!<([r=dict:clay w=dict:clay] q.u.u.pem) + ?. =([%black ~ ~] rul.r.per) ~& %denied-lol ~ =+ res=(rof lyc nom) ::TODO suggests we need to factor differently =+ ven=(per-event [now 0v0 rof] *duct ames-state) From d58f559b66487bc041b17ffb9d231a284df6d052 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 23 May 2022 18:57:37 +0200 Subject: [PATCH 117/168] vere: disable broken ames sift tests --- pkg/urbit/tests/ames_tests.c | 41 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/pkg/urbit/tests/ames_tests.c b/pkg/urbit/tests/ames_tests.c index 392fdf5fd..8dba7fe45 100644 --- a/pkg/urbit/tests/ames_tests.c +++ b/pkg/urbit/tests/ames_tests.c @@ -13,7 +13,7 @@ c3_l mug_l; // truncated mug hash of u3_body c3_o rel_o; // relayed? } u3_head; - + /* u3_prel: ames/fine packet prelude */ typedef struct _u3_prel { @@ -61,8 +61,8 @@ _test_ames(void) } } -static void -_test_sift_etch() +static void +_test_sift_etch() { u3_head* hed_u = c3_calloc(sizeof(*hed_u)); u3_body* bod_u = c3_calloc(sizeof(*bod_u)); @@ -85,25 +85,26 @@ _test_sift_etch() c3_y** out_y; - c3_w pac_w = _ames_etch_pack(hed_u, bod_u, out_y); + //TODO fix me! + // c3_w pac_w = _ames_etch_pack(hed_u, bod_u, out_y); - u3_head* nhed_u = c3_calloc(sizeof(*nhed_u)); - u3_body* nbod_u = c3_calloc(sizeof(*nbod_u)); - _ames_sift_head(nhed_u, *out_y); - *out_y += 4; - c3_y_ames_sift_body(nbod_u, *out_y); + // u3_head* nhed_u = c3_calloc(sizeof(*nhed_u)); + // u3_body* nbod_u = c3_calloc(sizeof(*nbod_u)); + // _ames_sift_head(nhed_u, *out_y); + // *out_y += 4; + // c3_y_ames_sift_body(nbod_u, *out_y); - if( 0 != memcmp(hed_u, nhed_u, sizeof(*hed_u))) { - fprintf(stderr, "ames: header serialisation mismatch(a)\r\n"); - exit(1); - } - if( 0 != memcmp(bod_u, nbod_u, sizeof(*bod_u))) { - fprintf(stderr, "ames: body serialisation fail(a)\r\n"); - exit(1); - } else { - fprintf(stderr, "ames: pass (a)\r\n"); - exit(1); - } + // if( 0 != memcmp(hed_u, nhed_u, sizeof(*hed_u))) { + // fprintf(stderr, "ames: header serialisation mismatch(a)\r\n"); + // exit(1); + // } + // if( 0 != memcmp(bod_u, nbod_u, sizeof(*bod_u))) { + // fprintf(stderr, "ames: body serialisation fail(a)\r\n"); + // exit(1); + // } else { + // fprintf(stderr, "ames: pass (a)\r\n"); + // exit(1); + // } } /* main(): run all test cases. From e6db12cd820f0b4a1cf3b6cf6b1a4f4637490056 Mon Sep 17 00:00:00 2001 From: fang Date: Mon, 23 May 2022 23:25:33 +0200 Subject: [PATCH 118/168] testnet: tweaks for ropsten --- pkg/arvo/sys/vane/jael.hoon | 2 +- pkg/base-dev/lib/azimuth.hoon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/vane/jael.hoon b/pkg/arvo/sys/vane/jael.hoon index d335f2359..aa0709763 100644 --- a/pkg/arvo/sys/vane/jael.hoon +++ b/pkg/arvo/sys/vane/jael.hoon @@ -304,7 +304,7 @@ :: =. +>.$ %^ poke-watch hen %azimuth - %+ fall node.tac + :: %+ fall node.tac (need (de-purl:html 'http://eth-mainnet.urbit.org:8545')) =. +>.$ :: get everything from /app/azimuth because jael subscriptions diff --git a/pkg/base-dev/lib/azimuth.hoon b/pkg/base-dev/lib/azimuth.hoon index d9c6a1b2e..b0c2c2b6c 100644 --- a/pkg/base-dev/lib/azimuth.hoon +++ b/pkg/base-dev/lib/azimuth.hoon @@ -78,7 +78,7 @@ :: # constants :: :: contract addresses - ++ contracts mainnet-contracts + ++ contracts ropsten-contracts ++ mainnet-contracts |% :: azimuth: data contract From 6eba8053f8070c0ad7a735b69da34a336fbc1850 Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 24 May 2022 23:55:32 +0200 Subject: [PATCH 119/168] various: further tweaks and assets for testnet --- bin/ropsten-ivory.pill | 3 +++ bin/ropsten-solid.pill | 3 +++ .../app/azimuth/version-0.azimuth-snapshot | Bin 2771810 -> 230651 bytes pkg/arvo/sys/vane/clay.hoon | 14 +++++++------- pkg/arvo/sys/vane/jael.hoon | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 bin/ropsten-ivory.pill create mode 100644 bin/ropsten-solid.pill diff --git a/bin/ropsten-ivory.pill b/bin/ropsten-ivory.pill new file mode 100644 index 000000000..5f3e6dc8d --- /dev/null +++ b/bin/ropsten-ivory.pill @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:666fb799fb714579e17a919cc81e8e28c178e9dbb6af7bc01cd9593aad7adf37 +size 2336718 diff --git a/bin/ropsten-solid.pill b/bin/ropsten-solid.pill new file mode 100644 index 000000000..2e75668d3 --- /dev/null +++ b/bin/ropsten-solid.pill @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e75d72433a4809fa4ea60e2c862f7d87c3afaddbee37981d6f144e2637a6af54 +size 8244444 diff --git a/pkg/arvo/app/azimuth/version-0.azimuth-snapshot b/pkg/arvo/app/azimuth/version-0.azimuth-snapshot index a664ca92f4cf45c1c2c05846c402107d4143d141..1d05e2943dd5ffb1630d94fccc126952977cdc6c 100644 GIT binary patch literal 230651 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
    >XBsPkV6tRQ!|7;$VcTraJLg}Y06 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%0DaD74G68HZ5-VhDTLq=nC)R$?cK zyXbsicld(4j7)Kx9VXzvhny}Zm}M6y`P+F)EspB~D*+sm8gp3IJM=Br_XJ5IM zSY3N>MRD$We%$~OOAvn#8I$qC+hZF46dZD z51*@)TV{Nf-dLe2yI#T783>I8!Rm#;JEYXW&?(~ zWBMnvBC(6L{=V4aJ9nWM|Hsx>hE)}HTOT?_x|C25q(izpq&uWRy1QGtLAnH_JCu@= zE1h zVh_-K^+B3@CuJr}7wY7i@w2zeE46S-$#nz5m0M1wg#eZL;pVdI>qHXPy?m%^0ZO6m30z+&6iZG$oAU9!(~3 zdupS$(OYCT6RaH8dZ3lS{{G;2o3jxZE#%f;S6REeRZU=~IJa-hXvd%#gw-+Q;5xZi zj3(sjaf2yRgM+vRhJ_2eHD>{GIN$8@W15bbJh5QE?<)Wu^_FEc33O#FuxqtJt$dfy zZ)5sWaTzGeR35*Hw0vSl;4qH=`eUA2($GTm6p&9!SV)Paz>u$MOO_3F*k3OZ(3AV? z0wAMFDdmMSJ_q5ZR2D4W;KB;!eb1?mVSYw*S*TgRO>>hw*WFQww!k))0>h-av6s0lrvc z8V}COB$Y-(74<;e*YuCa1XyE_3m3iF^?mH~(OElr2Q-@W8)%N{pB8OoTT=L%amM$I zY+)l*whr^WxjU}O^(3#M94Z{SfqB|2Tj-rb+qL3d?rGwo-?TK;&G~}=Z6UckxlM_$YD!27t~cm@BeYTRB`rf(pB>cgsT6v@ zv7h<_MTLeBLXbQ;`!P6hrov=AnzxFMT?-WFd@0n=WAu30uF*d+O&J@#{7j<@_y*i> zD0(RGWC}JH`^2Z8#a@P3=c)kTkP1)ZQ;1DJoL}y0r{C%&opH$ibc~Lh|OdyZxNM2Qdx-^jafBL#NzT^R^*DW zevNMG6f42zCbOvfy;Bp{^n%-KtH`s+HS^^*7B%-Vok78hXg${wN zHm+;}bFk2neo6b=lT-<2$KkP4a#KqOw}o(|reS>q{V>&9qoDHDl@0m94V^0R&a;z%2H8myitI@E9;ja> zSBju4h^@2KrG`rx|zNqX|Bn>Cy7ZQ9rUDV^rG z=lN3i@xJPxGo)x?F@p&{+i@OPqsk!^z4P~FLkV;Q7*9L$`$Rw^-zHjHeOa+C(G^^v zJ!F+Pdt14-a}mV4=&HA^K~tzC)qJpitC9 zW2l#-x{BKSq-jy-2^Dobumu4s)3h|`qmb(!6IW4{qV#65FSDTQgp#>`%^>m~*i?Nh zQ?4Y45+`Q+=Xjr<2X8G0zE}`AuI$;6N_z6S;}bKg@F$F%3i0>rz&uj^r>a8i%(=OBX`9!S*_!%C_+2XZl(cTd?A@opZ@tGD<| z*TPT#T1<~Y-p^86Y?!qq3}55egpIc2{Q-9rlPL5B!ydb**FEwW72({d^r|vdMl3cy zalNwkCt`XH%ICodiKL}N(0-81<)^*cI{BKha+gINNxGuZYt2bP)BW>d;zb zA&l$ z1dz#>pZ-X{tCeGB3MH%JbCSeJAtDgK5J62W7$1nob?N4;ile@1FW3xpGJ~2f+PHCX zS}Qo^^*K*lDT0bwxRC~TP69Q_=mLW-AysUFsv4C^$S{I@&#PWt1{Uh4#vpB0#4gY#T&rn31Ax>JT#Gg

    MJoQP&^yL5-~$v&^>E30sETbp=T6`7 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

    )f6jZOP!yinR}D;W3Kb?Nz2bkJOx&Nz?|7)S zF$|HCkjGaSGylbMsZ|;Rh5cp>1qc!VW4?AYF!=)v#zU!EAD-?#kg->DNBFs6+nA40 z;{apS1oMt2=c#M_gdVf7Y3roEV{UTHLP1<=s)4SPKe7x>rdHVqXcc3agnMzj1_pCb z8AjTh5fjYb;&Q0skkaJA={ zBj>SH-R1=*sAlp+_j`m?CmTM{FfrJ2vC5wQs4oqQc!5B7B^f260JBRNgBl{~FbuI= zkGWF(u1!?X@l5Vz$L4&fN{qFKF3h`1s8e_Su0KE2)jX*mregWMSMgcI4|qmrAPv9> zhrvg*wA>Gk$-B|d&^g}!m193~za#Ew>(S07>+mBk90`cx-1$d~d?PtDU0VBVNbc6= zT3g>t&#uZ7!q?q~9axvG`edho$fF@BAjsrryH&x%_mg19nQ47~XeqH*_tO_H@EsZt z%44{Cg=tR`a4@a|#qsniwd1TTl84=$VK9rg}q}D7@MCDQ-uyLQ3A@S2MA*xCXB)h^A4gQ z?mxQ(tBQdT$%es5|01y6dcB>%Auuiy6VH?G5WO6@JhzLC0y|mhK`QT&@FFp;ef9&%xu(C&i&}~N zo@2d*@vuk0EusZ1bi0Ph1dEgEyXg4h<4Ab(IA5ZMq`*))wT_A^C^9#=IJKV>HH-HI z{e>|35zj2WP`PY(q4ziVfyi#{=`O3^S%1wKdG4JO_)zUZme+5q;qu<)Iu?>q52Opx zC(j7P#D}zY^&L>ngF^YZGnbaH_mS4irHHud#LA<{*pA2gT}v-KtKyw0E5_bm%k?ML zCx!>W^hdu1krbxHtz^3=^D4IJ&U>buL&Rf*QMZkrsOv#EOPxUKSBV>ylsvMp>b&1DOx2s@QnTP|YUXX1H! zee2LN5wHSa#3Rqk)-px<4O?K#>yg%$P?v&_ulh<* zeBtlt9t!P0=kZdLHVj{dI7rC7%<@+!t{eLuT?%fqbcsE z(&LlbHhIVm!E2wTRsSUpDm6Y4M)WZ*Y1&}1>lpbNz|ve{!`^UKnuhO} zxIKm|7(Qw$g5zx;7CHj7!S;71>Z%SIvh+(cOk0_ht?W6UIf70oJPu1VHy^Aw);j+i zo$z_zLaI+EKt)7LM>tq6n!9LjsDNjQE8^f>YvV1OFoiiIJxZStskp@Aj}Z z_4)1fOViccNBF`gFsQbQN&NITWq|GHb>JRlP=JmI?5-Rlo;F=@d+DP2V)$_Sr8XW7 zn@dp-unGkCeYU$#&_`NDT&L04BE&|hWjfZaU;R$xF2}NPVV%kN=?N^-Y4io=wfB-n zA26{m%=2|7Fb1^e8CE5{nM;nNE*j+R}xmootDr5n)01tVX7LLOM81#|+w8g1}vysX+) zCEZH*c#+>uRaV~fl>yK&f@N?pD+5g(@3>jrFJ++j*f5l%;ef;<^vhdgGRx^s@=Z|6n z%xF{+|Dwq`9u=b|p){48Z^Q3rpyi)G8i@SwB6FeL$2x3SGVwzl=eOdS}vPuz;?v|*9aqQLE(neHAY)`xcU0M z9gq@nl9QELVHc{2{9Odkwt&OgEf7!*g=$aU(JQ{`#==VI(cZzB7OEANggb?_%Rdm` zPst4da~!4;9J6n6sLF5ewVro<#Tn%ZNcrl}IyHf!Ne~$Coi~$tz{zM35pu$uTbPKn zzBa{e)Q^4Qfs(cCVxRE}bn_IUk8DVP}#Lr_LxA?G}1_vtUf!rb@! zTUf=m=yAiw)JdP=jkpcypHimXr2Aj(%0usAJn=js*SKA5L(BA~Ay5%2^X}F>;+@f_ z6onp|5e?hbm~*34^Jf+4Ph%6e67&J*{a32oTEe_ZAscF?xBZu`239)`Z9}-p; z26GVf7THcO`J9%qv7uvx& z?0v5+jUuFwsPp{B<2??j%qZLvAZ&?aeTm>}fjPkP{utG)9FdtQ(=7(B%!CDv?@9B^ z3WC(r`#z7=5^6P)G{Tj69k-B~jFyrw?78v9(w8`IBaw*Em?@=4^Jx?R;=k9$T>-Oj zuCoHzHS@QQPbxSNQLrgHvChOS50I9?D4?aaHDKn=%C?!AZ@V%n) z=N85`8NznjHds^29~n3XaNC(zzt=AGxgkX##nm&ptBGFUY{^!R3|2ureh1+B{Xmoz zlWkC~npk>qJuyPepa2|b4EY>BI$qs+v~l5u-G8G!McwC|XAoud27lZ`U)kyKAJuKT zfo(hwfOXj7E!05y2;7`EhQNV_py>FpPuY30tom`@S)1O^!qO9rK<`|gN-kuykj(r9 z?Prch0All(Cbw^Q-g$}_cO<{tR=-#q$D|@tu#Y@V>q-8ilT3pSkNCBckq`nJt?dV= z8~?pJDazb{0GZY@4gn?h<~Fk4Q2Ow2h90_+ml2U`v-&JTLGt)ENQ}Ih3&j-KP zAzaIEn@b~$2SnkhIxX(&rp0KlV~moCF5F+#e6XG%K*J0#GyrN)<>z#Y<@_oT@jI#1xFy-oXi^2u|+iERF~!-wckHQGnkt? z=bRkrT)FmtDc$5H{%#Xw3=z?>>H}*{Kq)`~ZTZnG0kvzi=gU$iz5Lp?$~{RYr93zj z$&@(xcLKMEm`fd>2(AM|yZK)G-3@go#t+X1{dKCdcP>iS$Gu)Q_gJm&lFG6lw2D%go=Aa+-Ufo0RHm(m+9H;ruQBpIU*0BE&p^| zh36DNm=@eN(?rcHPktkQF#anq@t*kuW5WWQ9BEwem0uRaW$UdULio zTl?t34Pradqo-Xlifg2-HE_**CV@mc56f(5*Jo(Yw^{_><_Cyeo1EN`g|-i~f{FPt z9*0PCN0#rdQ?=3>F`swl_H%*w+hEWv^{@BufM%ZVqaS47zQ5Mh3d60?*clO)#+(lA z%^yeKqyi&y#PVXsdzEHNJ5een9Cabfu4++L^_5f@? zp{{$Cm=4NJNqB{*n}Z#q`uGOC6~r7KdF2S~@;7Axclrwst{^}D9q(Np6e%J{Hk5LK z_{r6i`=<XxKTeOJu+GtCZ;lS_i6rym;giHx=zaJQyixc?_GDx$@5+tPwF5rr-^H zI{!dh@z;nQ zO$i?vq3`#wH zGsGv9%)cvFpUlsosC@Zm8h&d%lO00(`D(FONWfDu+*?T zLc)^}S$sG(r z20lj)bp7?rCvDUH33o&rqtj59ect#Twt{O6ffHhxg=rhVIxz_C z-f?(N(6ikvW9MK7W;e(Jtp*wiRL`&ar|(~zo&MrG)Lpwf?lr-}9#t$14Z3im)!sUy z5;ev69AT~oIUchiRrz@)%!Po~Vu&r}h#44x^BuZHPoUECvug#7jb^%}?@dxz$OAqR znC1XSV!1UyIGnn9neW+`D~fau6Mom0gqmin;GsVNj-Ts*SPJ_iu!;IYQjs^F`-+lu{^o=$|NVm(eA-Lk$VyMZ-G&xv4lz@iue0TOiv(e z>^7~>D+HrX9b_DZN6ZaG)2s=g5Ss~lM$@%-z7L`?>7}asjhl6PrYq|@6l`#rp9}08 zlz_(W4ncxl07N)Pci-3b;Gv&pjVnW`=2)=LO&o6ljXm?>>G!sli=z5(_K7$S{;RS5WKe`vZG2$Z98bAvhRrwjbV?L4GB z9cE%p1}U7YSGdY1!{8K#WFZx2OV()VK=?d|vP?e-ADe9tJcedwpxS05o=gP^Xph*} zJEmzEQ{Qt8K(Ur?3?@40-*jmPxW(sxj(Q1WCgVP4!VzcW4jk%`2RJ6}Xn0Qy(#jQE z>Hp4`VgVPVTO>f3+!Zk(ktb~2+z3OCdhMlQtz3cCdpK=wFWRX(Q}lrctM_B8N+jCZ znm40ycg^W&iZizRw%>1JNWakIkr%jZAH<8w511(I!Z;q(yyy9R>dD*RA9=W@`8lCMfAQAw1`8@u=s;by4=;4B%9NGynhsPOJeXdgw}j?w6V9Ta`pi{ z!b=2P;}-Z*a@z9c`$rMZgG)50G6d(MTbBfduB ztV6#29}_8c6gO3yyT!BHCg4~LG4PwCVZT{JD>bv$INM&Tn}V&EA<}Atka)BC4gvr^ z;hX3tKPLdW1T=jJ)bwPUj!M4@7qw~6cZ0xi0Fnzc{dAm*vpJgH_&wB{Tb+V}3Gc9nKsuZh5I?P(lB*~?bnB1kEF8OdDw7+{@m$QAE;BBPeP8L zFJ+t-wD2eutJOV95+bIDFRTvfBjvF!{<=v_QACN_vU0qSqZoRZXQ1M84KHNwQTici zGDv=NO63{bq{jLDr+MZD5&h~5aZ2FQ(0fk~ChbE>h$VZR7oMpY`AR^1by7t2Sg>UI zhX(3A*ehT*&kg2fR&w0a{~}ohW1hZVW4_ElXIy|@Oa136U_W0xY;DYSO< z^Nts$gT6WHNCG%p3JtP9o=|F=*Jk&_)OYWqLxc)6yXphQ&ZqTqB7R&S{pWE5Ksjw+czVL4U6soT}>c^bA{;v zd`IN18MEjkvF(r(m%s9Q@6P)5Bj4YEUVzp!{7XltY6o?F8D?v!hNt8Fn6S}pyvq?V zWr`!v)m*~AFKfpW(;^rjCz$`&)9Q4|SxScS9|pp4#-1$^&d&Y${zzR0@6>60mjI;R zEs@t~E{`J&()}hs{U?1WO#1UorqM};`C>T74_)`arK2+H5Q+@m;+$;25AuTjQD%YB z&&O1utiPg&*}wH@Puk-m?jgcwguHepW|q~@q(9kT*=LzS`IF zn}1(X+xA!Pd>XT)zo3v0=5a+Yd-hmQ%qw=$nL9iN;N~B-z zlW=$!z>s-|Y9o=7!ppcGp3bS!jS~5;8pUVstkzq6Z3FN%#m`9*%I{6R*O&rR>IbeX z>Q;}aCGU#KvGGfj#4Ai!qWQPf!BQfXPr9$ajK1SwK5E&(n^H-$2HGoUkaCXr)&3Of zXpwLdoyR_i{b96Izfee?;ZEhGWkD}XdYK!q)wo_bqxUm$viR`82q2@-|reEP2` zFeeDqruGapP>rjOc3~m#j+B6~@}k_n0&z@s7&r8!c3)$ z6MHwMm>uLKIq}}`?Eoy>XPJkVUteq?Kl3K^e>r(y`FFQ5tgMDXtd;Ho0^ z#;{6pLZ^MFS)zBRRj_gY=#?Z`(;_D;P4+9lHY#~*upzuvw@`a{W~T^$hOv>_5W?_c z&rmOi*1kduk@m~8E~5!6qB87CNs1&NvOOb4 zEv$aOoR}jvd?$-&P!=J**b@uJFZQ%h1{8I|rT#DsgZUc8zUe@zIodrImRBhb!8! zATqqO-`hDso#XHPQqv+eXh3+S^Y4<;*j+z0Bvf_E9N_P2>|ekCJ^ygVE(>XFK@vYs zmGpAhAxC5qg|@|Dm(8QS)SE)+^aU}GF1j*a^CBmc($t@yq^^9(=YKbVkP0*2xfJ)?rr`hHm}I}Z-C`OF#!My#gNv!bZs;(!iou;ANdXDV5WH_dQT14c4Lsfi$1XXM`exl<0ULn+en2}0onrr z3jPd(9#Pu>~Au18TzaX*e zccGA4u6f2z!=n&*SH_qYPTaH}XUg2dD@-m#5BbLzrZY;d_jd~3-;$a z0flJ%d4d1y_>Kzud0T0{dacQ3caPt!Rml87Ol{7|U(w<=5ivs@KT&>&u9g@2WjG1zjJMWawoQM z`y#Ml0PiZ~E}REE4`tc0Vh_Rk@LE_oTcNw_R?UL*;;3EitdODrs&TKOy|4d7E(d{<<&V)~f zqwp3Y?NONXKkuW?B~I<_Y-2{R1NNl=Xc|_!KtT#mzo|bt7i3neaMo-+9>poe3Z=F5lZe&{AaO~p)%TL?bk-bg9zRq~cyGITr+=s&^ln4Vz7)GWT{+t zD*yf$sVf(yq^9|)+jSJ>x>@jZ@Db4%jaR0UvJ1qe6=;2^(HXT@S5m5_h=2YN(~cJ4MzSQ?<44di z&ZOK6`h(AdQa!5Arg>vF_@#&Rmz~m&SgYIN+xh1M%OBmeBBAj%kkf;vr+N0PPcq9+ zCN8lVgWLJqSbzgT(J5{S0qx}vBpQxqf*ug3@E$U4ea)!MylM1cI(mR}1F92{3i^P9 zj~WVU?B>YG`p-P0qvZuZOgHIHu7cvhW5_2BK^4wb{xc^y-ZZl>TwcA(-Q=sc?Bcsh2A8F5#%RCIkiVkok?EM^KQ6_Z9cc#8>pw2b>Sd1-FXDP zSs{=mtR*e(+*8O-Bo1-JCenH_Hd&0uXk<>M7vbV{2v%`)Ef6!{)3vgkuEOZt0dD4& zL*E{r#bK`Pzl%d5ORfcn7SygmH|yp-?{V5}jRbT#px%OiEjiG(60tsIY6RE_xR$na z2PTRD6Gt>zyz$Jx^kI?!PFWa3fZ=pO;eHk>SOPAAOv(%&v_Gb0yU2ScHNxv{}H^M+{!hW2drZhO7FcXz#@pN;A|yKoGV^rav7#Qoj-)Xd`m z&>83`c8y-%BMVGNxSouerL(G7?R=0WtNr&9Yx)PDXoBNkJ`ve=)_(Dj%gEb!0ldQs z{tmNfPg~}gIYZB|Uos60sqcj*YeC}b{Uavs9eQdq-RsUMbXSDwjvfY0&%0hGLH2@s zg(Koo!Ncao#4eH>-)x)37tm1R)OPf_HpGw*kbjuHm_`(gSFa*vevao_X4HH9-WM_u zRMVoM$0*Bqc{{}y0znD~LTnKH$~<0&S{aS)Qj2c zAdqyQ(`@ak0`BpE_b zk~Ti^u&${$Zdf!^u-HLT8Rd#Blz#5*Wp@Gd69A1b3Ni2qe`q-j8>0p|9sxOka1Y)% zl89g_Bh%(W0uM&$&wl3wEu&?yEc5Gq`*I%Vk-;#=NOfDx6U{0SXlO{P;K6>bbUbxf=To1Bl05uy@Lp2)J`D`rFW!;hb=8w zpFhZpI<3>N$N#4lA#knm`%o(X*ZapGk{D^e45k3x`#89l?@?ftey zswf$*#8)G96r;>V2W|&vuu+>u>|TN6;(yX%4*+h~$s6-E9ly7O}>nYLePE zguBuvv3wF|;$S`VvJ8w3R5d0X8ktIhy&MklvMP`r!woR%hcCiF4)Fd@J#H^h3Nf^!l~_D03cpo!@fZ}Kcd5Z zE;>yja9H}}Qf{drZP&vi?v`jT7Wzv6Xh&9rCynousC_Y-JWEAH)?=c*i&w=T&Eoe*% zV=;BRTa=eQrKHvf{5c3y)%%>FF>N!G==2HvCMK~vPx5@T_Ge#{SLn9kkG7A>zM9ls zl;}s8GreVzs<4uZu|D%VHo@alm2on>Xhi#adU2($~;>PvsIp2>Jub-v} z{P28y8117SngaLh+)OFxP{}-6V zO~^`YvPE|I!;8~3v`XcXAWr|Y3B~EH3=&uy#vbKxxA9VBpht~oz+sB-8PVo~> zE~z=9gRCLRXS2cY95{;|J$rmwzQFSgAZ-OlfJ2IOhy$)%kob|^!o@=Lac*Ku-U1yf z5I_dL%_H#JSk2-d37=_p={@VS)_UVskmYBN089wM7Y~q0hvDXKX%vVy;}&wklKgQ# zpA4^fefsr#m^u&V$Xq|sKKZ@jZQhlM_0yMcr%hYp7L~uba*F;)-kP*4mVJ#Nj+D2X zbm-z}tP_cuZus)ux{(ur%DA4w3HeknWO3N=jM;>27K1Ql#U%0-pQ*{`tcLPWGNX zvu0+^8sI#MM@Wlhu{b_SSGAQv@S=Jey(r--%dXb05K2Nn=4()o^eGVJg3p3Gq87>X zccpV35gePM0)h~FHnZguy%4-cn}848P9f*y4jJ^3Ciu)9tfwBNvB`X>j8y=hn=boR z`L=%hkN7@}qXPP%LZT(}@Rz4};a_E_>(+EyuzF+K~gu zOT@W9#aEAU#EHS_ljuSIqHG=_`mafIIqWx1MniIK?0!$LA+HI(^MbfPCK%~&Oh(kr z0KaC_-*-Pc0&>*|2H`3DKLTF^gR(f&*rTnnTQ_mOb1H$TR|~VUL{d^?@K~v>_^%`I z&4Ij-BIqlOOGD{|+iTa?8Xwc~0w(J@JL6gZK^k5rSPeyAxEWB7I^NPT6|vEcalSTy ze8pj}sCEjV^^kwJStwNx!#7?Sz2&2EHI3=ZIqVMITVijZ21RSr+QIuG)W>)yZr+4> zH-+&X=a-oA`V1sBGM8U&Uw}|IXwrwOOAK6yJY?80;nK8uBX`J3cJK*G=#cYTP6qsz zT&R^MU%xfvNj>TVmb!m$w`J&}JhMbvjC;POKoK8Qp3&uo2>gzcm6k^6jr}b>o9dCk zAsMF)xK-QxE5#Yv5+U?+QmRDfNcz4?$-EaFe)W=s?}J+n-!fnZVN;0HIrW1JjCkGWVyjwL+_`namn#KG&;t@*g+ zgjg5f)mY*D{bzuq4Z4yws}Q7D)V&gDc6{B(rT&QVdhy2$kUElmQYgL88^K`8rW_8B z{k$^h%iNF8aAqxABTP}FYM@BoPEf`oV)A0euJkn@s<3zPwx}&ussI2gFerg6qW*Vr z-Z4YS?EA*>7SYG0qxCIx8c$ZgQk4vYXY(r>LUM)f98{2>@p( zfbH02SNz=aV%G+nF$un2IuF%%*)RxCs>t_$->(g|R?@uvOU4ge#&s0;%QsQ4YIAyY z=?=YOm)eR30ENt-&??R4p43iY+7{;#eH?rks1LuI6S=Fu(sYAgv;o0XARd*myW`@f z5%3>f;LGu)@zsNWF`QwwFBH2@RV1oiHur5GlIRP9pkNI+xVzdJp?WUq5`GOT_Cs{r zR-!RPNd>8*foBO2IViwPSWe`rk!jvZe{!M@nYY z8X5}_0H&*`Q2#Tch4CUAAop!06ot3bYY}&ZY(kij+woF3U}Jk1Q^Wc9p&rVE{}VgJ zJdOQqSiK`xBASvcu=_a?du|sp9KuR55qypG?c(b`4G_azi3Sj|o5R9L1Ymbiq}dky zZ3RTY2ks?F$@DiFm~}Rlpz{yoazMe$LnsB%?n^Yjp>QwF3jgktV3)Eeea(R^Lb$mo zbs3t&L8>K{$Ox}%(H@g!1d1#%f!du{H8}OkyE`0suaCtln}`vPLMzKdhW%dxhWrbE zRBWz=Kx1@$KCKKZFV@ZDcO{Y%*{m8E)&F2+S(e==B3breiS*G0{6?^iDL}bieo!~K z#+*(@#27_f;?yAf`fH{bRff&B`^%?S>5n9;RMK)IIoKw*(z`Y>so}qRzRQ4e>?VID ziG^obZV7labD0R6U6IXyPkO!$y~&2+w2&p2es5s2q9}cv7#{%YZMwrL`UeDp?sUA+ zwIZD@46kWF?*pN6R>9y;OXyz^&af0l_RaXWglo|P71&50(|c9%%4bJ8o*ey`a*$n< z)%M=LDd478dY!cXis|J&y7MbA@15>3L&?`vO7=ik^ftZ zJBG!=?_z~#@N#3RBOg*daY4R#W5~Ic`6>X}?U*!(ZVB3{OJGnn9q6um?vvwR|9x%v zZ93I(3i_DIKhSG5pF|XctBYs(>dRr*bD#x}>|E*ON1n$#us`^J%dzfcyY_Av#Fv9kZ5YYuHr0%pUz|k~0OBaSB3t^R?gk>oZZ^E8YB##Glx(+70rU{>%hX* zF8BeUR~lE8ogU7{Dg4#&48e7zZ{Dl}Z;5q|A1cFoJ+B@cAohYmF_pt;pzU$?X)c+@ zg>^m$zFwud2TKk?s_yjaX zRmsL4^6d=AqDdkZM9&4Haj@?YC%laxnA@GVYu5Z`qEwh$jEEcz=5=!)C$f%TEj05f3XlJboEnxDtK-$Lj zD1kVN9`zRe=0EJv1y)&|7TUh|jBgHkflb@xv)RSFO&XH|CWhHZ?~xgIT!)oJ)47-; z+&j5ed~AjgxczVBTA^7;V*lO{HPZTX_Ez4k zxFKUW7Nf|!FfV8f3M`gIaSVAASBrN-tx+K#&V~M(i>DsXc)em9$S7^+p-iqo=W5fMW#1j#>;yz*kdTb}k zO#mVQLo6(%wlY9hC!qD$`KME+B^!6_ChnyMHj%TIrrTJ=HNT7FTP>bx$)TY?yo%HC zK1;MA??$~f`5mCAqYiM*79s3TL=MO@aN){=sa?r;+kuG%qy^W%$lncd1XY8@ofBmd z@XTd6)XA49X*X80$GJ{C9w3RnSf{GYd2i8V$~h72D7t_jv>2W1i_D?yCBI^skt8m& ztrtK66k2nNmq`|1;2J55wGkrP)QY~OGBlH`iI|eu1=uQWJp0N`kjI|iTb`?|>;3~P z?`up`(GP7}NM6tlZjzMhd{p&bzldkIngwpyTZjy@G)e%$DA4}0iz$I%ws4eVMaefe z+RKxo-%E@DhLJD>Rh;p@$Ib$$P-6vRpo-@YzA&E%Qggfa}@)}{hWQE4RpZCi^EXXH&w#yHuhye@skV!Y^UzHyf zn-;M5K8@lX7krXZZu&C}=9?poXUZhr`c?WcnD|UM8S@$*XSF|9BvZ_tUB7MpVcq(Q z?ay=h>z33>i~lx3>m{|;d_wnaZ!q9uDB$CPB9ZU9q)zbs?Nvl=a$76hHB_0*xf9>L zJ|%y z^+3~;PSYlo#tGZ7`M(Z8Aqbc3fN@EAWE^vhxld6V8atFog_VO;K>SO{+VUit;sdI% zyp7LaZvW|T{IguZ%>?aE2QDST0K|vUv*wTG*kt@N+6`9<__o5q86|Ie`#y?W9!_Iz z6F5)~v)e!&JbcD~{^#L!MRlg(rm(kq0q4&M{svKef07p~&!J!x6bdkccMYz-&zwLV zToae)j`H3_HsmJ)2^_#FZht>s867}39^Xfcd)&%d$?2qzfm_J6g3nJX4SbdT6)7Z~mFXvD2NnBL z1GwuHlayc`opG~W-fMg2`jU%gGsT`oa_IzIoc3o>s!!B+)S-G%o-9Rw71Q`}mbtpo z8HX+7K}gs~<(GG{2H<}2f=}WlaU;oe2-7L00PR-}C;wTALaVXqDQmj0euA@S+%p3H zgQvyq9dhk91Qy`m3KK)atqa(kJ-(l6!xHA|v|E4Ff4zcTT_L?NN zw!6M1ZK0SgWIZWI(^sblf4*u+6Sq#yVX6JCgSlF@u{g=Mh`u#N#)rk-S7zT7Fx&K< zCUtbc>hks+j=20U_5mR5^oUg9ne7T5sMlTx^FoNhWimJ9RzQu1Co&N58BT+rp>mKH znue=QM&d_%ldTs$WPvew7!YM%u8zx077yv}XrXmZvkz13go1jXpPpftFv9TV_Al?| zZqqi0c*znB8anQh(ft08p%@njX?%0; z#~!M7uU|=6^V|9c4uw0wp;6fDrRlKQUd_2@C}PgrT##Gp%+)B<`|3iaTw_& zgh>i`WKJNtCB;mUxtVVf9$yKf#oAO#EZc$c3-h;cZ1nWj_;kMLeGzAYojlMlKubfbm8h!#&SyA(!?53N z+kUU?%2SBTpWB=BSn-b+AG>kxjIe84es~*n#QDy^HP;-D5VacSNL2$zgxuYalkgD*d*n6I>s(5G{NTo={D38`93QIdu?-{-L4cw!(!NSLC!dK3 zxc>M9RK$W2KQy>Zyo|4Y@WMAlgDNod{lkI2_9zjHQwa@_I2hy$NadsU z;0eeXevrGonuF4o@1K?XC-lG1=z>Vt`wzyYSc?7dmgz`oR9=6VXsks+1kp1Y7nNNU zA*DG-iaq!q;$=tJJfs8vg@3D{PDnhaSNddl9=O_Da^U*`*43j=Mg?n3of5T!z^JHW z#m{fqWV8r2_C-b@69DzgDZum#Vb8pn`~!+c>Z8n>!J>-CLHjwGMljO*nNPhTPQ@WV zyw@2%-PZG-nu>fBl8A_PR%{JyRC!V-Zdz)zb-x{Pqm+M}Y3YjpHLw_&beFXSNFCVr z)!tk)vhMsqY2Rh+?Sm-l7%bi8cRb*&g}Z^tf717i^uSUBh~+hUVvYKQBqE%}Fa<91 zxBUfWP{0QS=6j0;usOZmhwIdo{MhapO^?MS*=CEeGyMhXxC;5NgMKWzn5djS?mjc& zY--n=qSchdxR$+IODxV0^$H!^SXUOcTaZ}>Akv2zn>O6h*B>hfa&?A-(~E{k{;3}4jsn1K zZ>T$$!MU@1u8rIW`>Vq$jh>jrhCX&a8g9$oXn!37?LhS~hy;h4-wsM7AL1DueanSB zW$|TYp7Zkm>6|QrKX%uk-Ahv~`W~w>e7{+0{502tVhSSrkia=&7#>&0{hm6Q@VXI( zmA}5l^XX%A;Fqa>^>lgFUf(%KZQDy=e^Gq1(;&>N|D|q7fpHbcjSQAogWHPti;#2C z#S0+&c#FM2Z^cLlhamKtd&804e&E?L6+xmM+VxJ5n-V!PNs62c6f*j^_bPYKbW))A zf^fc6)OqYg1Gji_2ucf_pmqQ{WMlha)18M3jPd++iwCf#K_Od76_-A9@dJ?tLE9Wl z<98_g%xb6f*9wRDY;R>kS8)6I;w)#O@{x)nE@7O`dj$C{L#&KEUE9w!4Hcl)Ff%|jhPc#(afx4- zXV!NF>hO9c)R9INoPNL-C+ffyq56_ z`sbqnu@-~Q-nfFbRDgxwb}(3G$fMo%5k3KAFgH6j7;Y2Fstt#Mo7m%Txn;)RZ${B< zyzi^3zAvIzilupLUnZ3@dE+g6wCJH8sQFri>=@=e|9YNKjf2>?wf~nk;aTLl2s(0_-O$h2)&R zF>`ZG3?W_k0w%al2mek;JQ=AwvU1_8sr%X+ebUkS%#@!cs`^FAuF0+luyGPmKa)mg zSMTv%z?+*$w(fbfuaSegTTP(C!cVlL(4p@8EH}@h*Er}Fc4fq3S;w78X!~QB2y`~U zW$FZCV4h^2EviZGxUUMnmf5=KwG`<9|BqO(e9}0#yQQjAaspfsu2MzI zH|F_DYrp4D6aVAE`!_w~=##wyUMaKm@K-Si`mi%P2ILx*-lSU~=d0v%|48qv<^a4tu}1eZ)R z7dmIgeR&Sa#MqKrQWl(y0H|7ta{V{fPSN;WyfNg{L<&7FT3?vk9^UcgbeMJ|7??cU z>n!*z7}hV*2swqaEG)Q(={%Oilyq}UmY*qF-~{awyI(_J2wE%Xbgl0iIPbUal(Wjb<- z-#sBt2$)QRSQHy^=~^pzi#u|ng1ZhHv} zZeXoSM`wgwWdg?FOm;bz2Gy9Mpw07Dib3$h!rAe?gbNoLTBc4+y|f@gWO#l{&=mc` z)1WEP@{Yl$jp%&RZJ_Y3)U+g)6tMjZFq6K00%l8WHSCPciIvRJ1})bWr~*dr`;y{o zA>II%kD3Z_#l-sS5v#N1r%FCekK}nf#a>x5kMObqk)wwzJO!X*Hi!R4R@pj)IAxJQ zu1Ey#(rZT7Rk^=@eN62fXYTqbb?^r*c?ZDqL)!(M%NC0J1h*c&gXTM{?QAm=q;uSJoO-7nXFct|0xDQxY#3_siuw?C7VWfN6DMnwFvTg!ChBRu*8IT! z_6+Xy#4`c*;5ChRATkq|q75URI#I)Qe;Ry{YG6OBIL~(evxXd|F-0fXH<};(+Q%<> zYqT3lDlwllCk3nIaS!&5Drs3?5l>{0Y4ulwMOan}D;HZ|JP9q_khVI`AxRbkBp(-V zIfLS1IxG1MZ~WY`Z|%1XaAIN=0MII*0MUb@qtmEmZR$-|Mb59iC|6LeWM!^u6_PfB zg;_vhgBj=<*T7LW{&gUHDOP;eEOLPsU6SoSmcVpNiOn-WX zAHB%|;Y#`gTy*523XDie*b4dUmTD_~bb4Z^4P#^P`&CuLN<~V>0kC{C`9yb^ohnoH zQIFb`qO~JIdLH{`Szf-PIYncoV#xo|os1!;(UZ;ClNXNbH&FIhP^($(aLhN)1`;WR zFFq{RYlL8##Yq(TCf6feCu%)0M~^#QoUHDB8zfiMSHg0-v~On6`@akP;`(`zyrq>Z z#)Q6RG!3;2(7WO4mQxT2D|q>5zR&&rF`a`%N;%CRI=nO6Z&wr^--cA(F@Y5uXDe<&JD6wJs5dV}5t?5nWy*x&j>ulF2%ZNP~ zb3EUoCVj;AWr-QPfNuNiOxPs^Yp7&u5#Z7(gZ<->MwZ%vjW)J7atj`lKk@Y91p#(%G~(*Y!hhxlSR8`3X+kuL|&Xb>~=4Spv^&60&|0U@^39x?y zJx^kwus~5;k+CUI1MteATNMo5Qn4wq_@*kFlq?17)SuX~;W*#+ph1==RX? zy^(Zg@{5B~{>apPy~(`;UJ@33wl-RCDa!_H97rAK3ows5h0JM-Bl4{!VCc%IH|`3L zobg|dLliPF=U z=J2ZU3~~>bU+QT#8N^=Xk%$oKx3kFoJX!M@1icvGRytz=KWT`%P$o)Lo5`-u|E)j9adb*dPAg(7XU8nQqgSNm{Irx1~PPngUtOk$KYlZam zlDMbYs87>Fa=R|S`9P9o4Vpjn9wIT=rkL`G1KUC*iA`?Y?xEYbEip5|^qxj!>EOjF z0el&~8G$9y_e(!RI>KPyMt#^!)x4v%+vm|dV`x-!2+wK-h6L|~@e<(mCHK3(Ylg4Z zA9QI-QK2TXithO@Q}?>5H-^{P zCgMj+ekNdh?HmbgbiRo=PuKFBs;^+|AC>l zLH4>!h?^S5U0d&Mc8Tspv0ht0>3Sg#b}|@yr8iu#W_`ROyQ)!%__(wR{8vCuWje6p z^03lt^sXX{w%L_icI5Ym4`EO`R=-HvZpy?%!ki<#>4EA+Duaoy3Tq7t|NKBseCOK6 zz9qFw5o1%gg9*jJ72f9DPX-orfhF*O(9_Lbc%ddFXQr(?8q|K=XLO#nVu2}V7=1-y z|Kd*UYmi69`Rjvgg?E1Y2Sb+8`g^x-(RvziUsHx*tC>Z?3^Wf@`V?I7cl=w`{YFY3 zxDK2!B6!gxm8RW}`Bq5rU0?4D#146(*^nxi{Be{~PHx$*i>IULf((9`78=cR_SMe6 z$zCoMkfXfZj?Y(tD2Z*`D_whS32bw>VLqxn{x~14Fqj588IVBR5>MwE>uAIqy}!NL z8lqhMb+73aH}YnKkO>juOk-$qx1?EBCt{Uujzeb{x5I^>ixKN5~r?iQ|< z^g4l^4A6>AK(YAHIH>2vIwgs=Su0sTf`@q}-vO=zBzrahntB)5)X!yctzDVU@W+p5 z>5t)NTej{~qt^bTdZYnhkU?%B&&tlF5UJymOK^PH7D1%h0QlAAg&VAM_$Y)Ya4_^!Sk&Da!z=a)S6P!0*5UeaG65m%gmt z7?DYANbJEr<&ve=IODO9nlFGRTlj+V67zU9ZVR4G{Iq~}LHemgtz3IP+%cSprzAe< zj&6bbkHan|9u=9YFgbQ`55bz292&z|i?KRhz!u{hQZ-uQulLFue0%QY1)Pt8tEkAe zybc$TNn;>;1G4zhwd!B$1Nrd_S+{0`qgITMLWB=tU^PEadpG6fi`LYHs6Qc*9((x8 zRCLBNPfg-e5-lzPu5L^&^Owz*)5|G*jnoVnL`3;QRQh`>H7O~;)a8W-!VTJ{o1tsg zCz{=k4=BUg=g9VCVj?IZ-=&;iC>{M58QH**QTaTj_YbO;aG8S+ziWF<+FM?;AaKFn zH#|%@277z;%9MylO!4A|96@5?;weBI_hzbQb|?9^qAGjb54OQ&qgy+oIs^ozA;MB{ zYSPpL$;ZUAXO|Zj&5!)zn84+{%9P3##^!Cu4yz{qnmD*DH%H)lFz`;m3(YBHZwf*W z&&v@k<)cE-2Sl671P8Vu3nbQ^PZFuZTeX~**;eW;#2HyWA-{RH4QgYnk4%@-kB3L8 z?w<-Lmg1V~m_BNta5GA_sSGV-r~&?ENFd;Zi&xkKcMdsAg^izw;xyK&KI-zP16~+irA5h=bZKZ3B4;xdXKI*ZtY01z z!`FAnaM|a!1)$Y3@WWF#$B^Y|ocmnvJV!(xO8jWcm=5PCZ9mnP_V*1n_Df;L9 zkRbq}{FTznD&er$)<^oJMRvrBO?CdK4u}7^@*xsifBu%c-q^*c@L#blj7guUpL*Tn zOzNh(UOBV?D9gp&xv!zWJg_?lqWSSZnw(2sZt7+5b5mXvn0BL^g@F_GE?9y!u!9yS znT{xxu=#hqVQ6PpLYS+8`)c6~+=i8jmj%4$W!nFJq_I1QIxI6;E!z1^%t%^2Q2{jf z9pZnh`u%+|fWXBIWjutNE7~^w;sj|>AQo_=B)hmKAvo&Dwb zb1@C$+{%zw*VkL1Ws{-X#{G45Hz^$djxzT~cBZA3BAP~^nm9j)9%h&Rc=iQB@7p@Z zzkpCoe6=%g+MPr~SvUrkd8VlH3Zfs+XK}?RJ0QXbTuGwn4+UAYJiXXe`ep*tL@P+{ z6RI(t;+}&43D^rbd#+I(8Hf~-&JF@h$oXpPT{d~2mufvA-2}_G-5fde5(rqHSG{ZU zX9pIV%FZJ~J_-MsT95|ZkK-oY`8uS_=g4EzPq$5cBARl{-}~-WwM-qXlhMox8o+CV zrt9(tFDAb#I}cBBoAFrmd2vggoLl9ZM16Dpzrpzie`F2-a7~b%%1;=OLZFry903QU zZR@(ju1_uu|CfGaO|9T`Ue8hip9LKH<4)7x67WtiPbpSPoAh_kAnjKaKm@e?y#r7~ zEh@?QBBn5NC-0Fzz52-$m5u#9$!F=RxUjds2Vq>Yym+~I~W8J*H{Z!#dc<0NuX|#AIve|Bi=88FEkf8M%oV@B)sPk zZog<*kQJ^P^X>}-eq1btHUxwgI{y`MQs5r%yNRglWs!iR)^<^~_&s^GfcMhhk2-xe z&3}HOW<9GFk%XOhgfBuiaT$lJ-QaA3s_`Sj{&V0T1Ysaqxw_Wz83*zap?hZ9lhUX_ zICl>a4m+J1R(AYDqnU2f!Bz1>`lv#)!}Eb{*xXid0_eFU&Z8890?eCA+;@X zz2u}6QmR_t0B`iQ&I7`AB}%?khCfb9m85Uff|M$4wMJp?G0^}Td~M6HkUR_MyMVJT zv*X>yz$ykHusvX@HuZr7MOgpR?RU6DQ@eC(4dhKbl9O4SbQI(;u{y|`)aJbvL^67* zl~W!gEf@F~|VAl;3f3DBAbD;7TXYVI?p+Rq3tOf3jX^ z5`}k77A@D8xyhBYZgwo~JpCJ!kJvS+*|&|Er8!nbFjuAc8$oQck#IoC5x<{@GDNLP z63Fg%DMFV^M+QryAK0HQpa?QOqohFJS*vNY89B}l_5JPU$2#*~6>!x{3cyPGN$EiT z#`=6HQ7onUQa48YS;w79`eEN=L)seUma!JAZy;yhE~@tV6k6fB-eb-oHWb`)@PfhEJ7Hb{|)K+u>jx0 zXUJ*%R8(R8zWzl`0e^SX?=_}*)B94e?9O<7)#$;u>?sM>Cf<6%HZ#6x+uvcJK-%mC z+$3uS+~b7)oiO{?OC2khS@->FWWIf~HrR<)RkbJ!+avf>bP;CP!PpR+7p@AY^Spa~ zf(LD|>DaJh&A<3AkS_VAo&~nBjr}b^knmi)Wy5cwbpOIxChrhOC ztJ;9}IcIOy@f0CvB~?FD`Ay0bBKNHy(6MN^9&lyV4oAaOF}WXV>RKbQFR|GFFzgeN z44F!lzjM#{P}ssgKnT4n9;7%%o7{1YQXf`31~?s3kkOu2vm=U44Hcgcj~`)XSt5+} zv$d|_jh!&dipa1VrQFw?RK7q4rhK(?mq}QMDVc$=uf6b*Gsfw@hR6L>ZN^{$APloP zg02p@7o8v;yvkMdM-jj4KRs8kF}}RFA8dObFX6Hsz|W~cK+s*#uBk7bwl(diOJEB6LHXt!+?>5eAi2mDT54o7h=dW-}LalSd@7{&kn@qINlfZ zi`gpvm&dGu^?D9*7Bq3xp?Zr|1o5&Q2{e|BM`;XzN#d4_?v^h)2A^{0eG5x+v_!$Eqrz=Rkw^CSPdqx@}O-?D*N zG(Dzanar18c!A)VA3@nj<3CYdYlubmXcL6w`!c?Clg}G@2}ZT8e^1%{5NiktkY>n-#v#a5ojCB3$!h2D3i}fX z%7O$)fX*2rA=MFrj`H~hX+xy2)X2N7ud1Y0tpQ+%q{8YxH~}MaQ*2s|9pc~$`1Bltyc5dU-s7t=QGy1oylJaV5%^V-mHuBb&oCOAB?Okka#lxpm9aakNNaeW= z?WwPVU;Y{_+TsOuPieHi0(A)tfFB_Sj^kH0PEKL!?$>7O2EqkaU3rG<+HGmj<+xK{oyGd$ z#*x=@F)Gw_vpyXiervrpJnCO^5h9((%bs8H$A&qQS*@~rjwBf1Dxv)^O40f$^xh~J zrO;AiHB6L#-ZC&G3~aBNZBe?;?B~11^C)dlacOUV#`hQt<$}`=r}5oMK!qh18v>af=(#%wcc~! zCJwM(ngzzm=(YnF-b@+JaTB>L3biv=aD)KgBhWB=G)%mMc(|^_4lgWQjHQX=As=U& zFR3Z4QHMMf$EK>pzTZ6n*4Q#|(fe*-JOdT~oovhcBDV*Zx8SJCp_~xSMuIC2;&buF z7_9ItJQ$ytPfB*1)a!8DpI})e_B*Yy^jUZTi36gt=PM+6y^nQUm~nK<)-CCbOE1qG zI0}v@zY)wNU0cvqTGLrsYdzp?ew4?5hj{Y&6PZtfjv>36zfG@;StP?H6F|9<3tpQC`O=u(V}1e8=d6YH(o(pK(Txj6HOCW_9$hyx&NFt*V4i za{LiqW;^+kGktZL?P@%8x_b^26#k_#)t`6DK^6i8nLvjKfZUs!c809Oo41%`z8207#xWMx z5>Ee9*9RsSkj*kJM4Z~lZ!&nw)23@>7+}yiEJc~XZYbV_s7d9XeI+rkpeI%(=*MMq zoHKBl5x72Bby-Gw)P>#ik5}f8FtNW}D>WWmcJF>GIfve&n^(#x09Jb=T}(YZcm2mo zVcL$^h|EOuim@0nerP@gyW?4`56<(&A%Z`Zew-~1YfIX2`CARn_;;q4d;(_>F6d_= zsgt~UH;S(5Ut?E4y6{P6ITInqbEQm1T^}spsd*vz75n?T3w}`Rs7aMXCBodOL`65# z4n6eMSU#e^tXRyvAJu)m>~FJHmQQczS48-S9`pDlVJ(?kpNrW@92{V!NY6@I$?0g- zQrg$z!zL`$!fqa478F6Db-aGQ(N$}WM%Eeaqt*@dj`MYUuJ2Qk!~Y?#etQ0ZyLh=P zeMhEa{9vrgD7}RYch54f(Czh|5wJ@mw48x#)WV{YP zx*T#Rf5vFdCbZnT;j~)z&E2j%NK)%{D#<-R)ED7jsNn$|fT)O#qs-O<`jIja2&}X< z-quWSPv16g4!mM;(KEF=RD`Gt0waSo2o>egdpa7c#nL4XXuRZtY8WobP|AA`#%99b zk{x^EtTvfFy8m_Fa9t4G+FzCh>V7%}GQ z`$PuSe_ixP^SkJyS?qOh&>x@@tQ>2tGNpzv{l##bZT^Kw64hF=em%CIV4Ksmt3}Ex zh$L4HjMjO;uXrh|_9_!p7eBEtt3q3sH>x($5!+iPk9Z3gRVs5RhAl0txEc5su@`Xj zmBzy^xSO9?a%(?J%>w1b*V5mPkos>%Qlk~=E0VGAkb;LU@R3@BEuTLKfc#=Aa|)BQ zQd@mDlAFBmy8mhL4}unqAxc1E861gk5?7L-HwcKhv?A9f&_ynRwWMb82`JB}`f?sb z8jn#cBK`Bq?!aA7;6F=zD0?an$4?E(qVkybtxpjaqd#gPI2<5cj&ym!RUE{y z1^rwZjdgHcJlA=m<~*F|o46~JO>U&&&xIDs(7ufF6SQM?&<#@!o3QL;wFg!$>*C;c zV_r^%37lJPhKM*&^?4)`)1(;9H(h@oY~Scec&=LNfPwwMn1ce#W!$2#zmiT^RG#ME1(gqzbH*#CS=FY;78#OoUZ*0E=jQ|gL6whWPN81YR~ zv93!LLQ^8Y9}xKi5Y&h-9t|GEEBM3;F0skS3ry5-rJ;yFD41UcFEYrdK7Ym2TRI<|U2EKX~~e&yeFP^{@6ss^vc!wPEU>evcfMRApP2ot@$S--;xp%iv7QKiVgPMS=#}#B+O}`0 zw@CX#bHQIk;|e2_GiVB=Z6 z0ra*fpg*}D_%tEY&%Q$Q;)TOWN;@)0lTh`fZ>(5~iNK;_c|SHy2!CAnaLVQS*pFA` zDC{a25 z5BAxy)f5#&veWG|axZ7fFza+Ms~46a&AzqAAdWN>{I`<^#A0KQ1>wg~s&SOpidUf> zewa5`UMnzYYeq%tBT)w-Lz;%QU2pJlB?Ar#vEgKnBh<#ljx5&&p+Q9^kdy$>YwLnc zehuN;{s09%PQyo`=Fk0mvRQ;L&b*Lva;=?La5j9Rz28hEz0EMXVE)1?#uGYy#HwEy zM~8pIr$>XvD3nA97p^vcU1+Bf%~0JQA}>G;drEEt7nQN$?TDG~3S~_#B-;;1EuXAh zI#YS(yJ{}!7yvp9bl@IEAPCwAm$kP><<%cp=}$Fq4NKZesJ_>ZPcuS55Qbl-(VsFu zSoQ7~*|4j=;);6SgURyWF+_$C=IJ{9Wh)dBp$ZCAIsnu= z9OH@$58j-Y|7Oeb-vioX*m8jXn*KMkT3nge z;=bHdgu3RdS?=E2;ojelOz2lmS@p?jFVrf;=M@IC)*oKhPUl4(`bG1I>zwBwrVw*5b3%edvl^zCd8z{89R=2@~%a1K7B@e)T@sN60R?aKFvQzu%DB} zT4B9K36-V8978Y|qX=T=c3N+D9zTb`6L)=U5d=>9;ZP(;MQ0il+Y;c9y(7ga_R#UJ zXSndv9;y&chB+^LE@6l*?YK3^DHb#?||?8kXY<-wuo0i z=po%SQ2X@@WVecfQXO9F!rz(!>0fZn(3}Dw8;p=R*1*H?o=pNX+Ii7(u~!9ON4RG* zay4V7^}rv&qsaEK)9~(5!LdFeUpZ{NZe;!%Qgs4ArTtz?Cl|=05|V-SuFojr;hZ*# zt3L~Qs4OB`x|npr2i5|Eqm74T?Z$ckW#iSznqyIl$_(vz1<;L^(@MK~(DQ?KI*tNM z09|unu9-Zwh0FF_^2P<6TzwTWwDUf;Z84+&iA-l*E6SxAO&;zm0Y@F4zAgZ}V9q1%$+XVcNNw`c!X ze@@&D(@r{*imh~`yCsnK1Z@?AMy&<=Pl{+`)DN~H4kf#;4zoM$UlL-VD|NtlliFK+ zxk@Es5bc8ro;D$Ce~8O_k>{pb5cI{OrK|=ntkbuu@DA7gY6(x9$}aizPa0Mxy#dfR zfJdlHdIf_w5_Q}&)*9uRFx{Wf9PcP5-XwUa7SH=;P7FV#D*=$bGYwgZ81MfS1C%)yXs=Bjj20yS=rF+ zF1&0+`!|=n9>J4f*JeZQ{}6}K%OERQQz`q-pi?T5KjH|Rn7&6r9$QSMXX}Es%KHhm zh`k4QsGU}GMB`M$Qna00nH`7q>B9a-y8}Daz}fG$$9JoY2d(IIg+c*u#shzh#;lDU z!jt`SLY-nbYI!Px@wyHE|d&IAF^*g`}SX3un6%0JX6W`inti zqhYXDh+ke2vwZ|gXl6S%n>lw&7bcf!XKb9D!a@U#y)tjdk zvrp7%wm_JxjwSYRe`=?EZ)u`zpYV|Zak!!5O%0C(T^R~uD4G0?g&;U50fqB;NH}*- zW{Mlp^oyFkGv_mEJGs%`(Fr1;U3f+vC8x>bcK}$KlS|Weitu#TfR}TJYoo?%!4m05 z*oUgUzy%0#59H1R>cNHDpt3I?4s72_A!rqD@)}c-I>twlL8ud^d*A$uHbwBnQQlnHEYw)rwnZ$4dcUv8dpO(60r~%GlK{vX-|m^k6L*J6F)49A z?uwzYy{)ZGUPw9DOwPEh98V|o+AgT?*zWu8XNC;#C!pLViWeG9@VhU}R{t2$?{i<* zvhEVeX4}#JiT}r~#PlwpG6DgwUx*>=Q0{z`5|IGgY}PAQfa*S=()%FTDFdK#w)_12 zzJUWJ?6lgCfC7dJ7w!aj3^N*oz^sNVu;^{z=#doGb{d8MDvM-vgqVx`*`0a_n6WI*XZH z|7;KDfwy)-Bl9g`CIJoKfIOnuD%c}t=oy(MB!>DOsjeN(@Cm(Vg1@kZXjC)I<-}iEB%KzZ?^ryYg;@E=<`>izSaM8F$JCc)@YH9USoI|aTVYpC;$z&o!l-#h ziFZAE5hyCw*LsBd2~{-2h4ANa_mR*yvE+AAFKYig`y+zi`A3xlN~8&!yS*+W=oyO5U4_D(~H z|FXIKSZjVVM&oZ`$Z2yKhrgG1YZ%_&6>BoMM| z(g%|mQVZ1>l(MsDiz0EU*ghUqw_PYiJfmL*u#u6sXsbvs7r(M}STGFSM)0J&#)tg^ zew#Or3Y_^#J8la>5}z-j!Vr(egn+vqn1I@3Vx24{wKN7_&dGYmdu}xPZMY-cKGI#z z;=^0#SP9qstOJe^9lrK*-(?oECPTOsw!^F8pYKvFr|P|*VdMxHE004Ofn<;%Z$<^C zv#LmQ%%T2`=0dXy7&MbTgDsq~rvdNmzWR74Z|RsTLhGuSg81VEFa~9hDDYghkSq%B zcHu023?TY)nU)qAuA?bu@1E7|F$0upS-QBg0NggJYRb$3KC8;o9(B<*9WK6}&q#md z<&WD6c`4@JNd}Tv0gn5C5Z_`@!*Cl&@I@8;LFlc5?$yC9gxv! z2A;~wh~qhSR5;UDaw2JZiG=%CB3(xKd(GpN42zH=laG0LXlCtH6bv$iHZZ zA0;m6fs&Xf=CjpsPkeG6VD`-c9*PofeD6t|+sxsWU|{Z_?_`8l8Q}(2)Iy~4bx$u@ zVGl@#daG0DQjG_lZ^QYld`O~V7&uSgAm7M~Yl~cna%ahQJkH|8myw>>#B$3cQ3!Zw zt6w+SIR5(1f-I_;GUuoyYmI{E#_iS3OgD$zch-xG=L9hqh}nb2OND_W@!-d}2Y!sL zZB2;4R4Lm|xET}36lhHOx6yAOBc7v6U5?)y~!dDs?$Im!9m zCVfhS2vz@Bk!`=2`!ingyS)Rn+$ogt&1xw!pU{c> zFRx<>308S~K~-M}h7W+uWS*;8jf7lVK7RO;ck){xhRF;?j}?pzJYA7E6uqX7_+0NL z%8Mcw;jOI3V*BqyON3Yh5t0CN9ix-2l*6z{akN zzcMD}7zMqahHV1Lz;^XH~$Gn1*N}0eHN`K$)=z3OR7+ADi=p^`5(t8c(UdO z_Dg(Wv8tRn$5i$IkE*YZs=9l=zI1m8NJ>aZi-6K1-QB6Al!P>wlrHH`3F+=m>F!49 zl1Ada0pI8S{mEJ^)`xTEOzhdS=Z1u^mu>>4PLX%XCyUU`MfL9s_SU0KB3(3>e`clr5WNV4t+Y{Yatu^qRbs`0 zon-qU9`NH#AUKcs3vt~s)1(CHkqY6BPT%3VFa%cuFn+r4LnAmi>v4y!T`GQK@iWNZ zcDZ6~K-Rq;KXmP zH&PiAn8C;22R{Bb`A$}*&)Hf%N%iOOINLV2m9qWi5 zn5E~#BiF~P73Jicl2~a8dYOzyO0>dsNp_KRj#q1IDY38cdF?b40LFkl;cncl&lf?F zzQgcMmNoI{t*9SGlk@;Hh48h42*y*ny$G>b?5X4W#%r`@YGq;esE>|RM`UK6kX1`p zC)&NM){5!s`m49UGTj@!-G^Y-ouyob z=ps7+>?BcpW1mMeNy@``CZVbyA8!OdiNAD`_xzrTs9%dpH1ssaU>Vy0kVWFye&2p2 zPVoEa-H?N!PKI4-*^I^~Gs}QQ2S7P*Qg3a!O9guVveZq^gt)iE>4P+z+LJOC=yp#bK&FIhNHzI5f~x1h94xbd8hNU22pWW%d+Q9MKyJ-| zRBSmKyyYpAC7<1)20uDMKC;1WFLgMQ)Etz?Utg3j$j8_Ducb5#rTgnYc#__}Mys~g^w%5p z=4mR~>DB?8+406l>>E)RA@(mk43qsK_ZfcmbQ4c%Egm;bIeaHC?ld;LjJ)M(QSn$W zw>%K2uBOTDnt^Q<1#qTBs&z5oFCr>dyv>uX2Qziz^VdI<5e=wZc3ABHV{@wJU$JDn&hS#W*z^m3n-{cQM+a8GUHb*=pvA;6rfc*rZyt? z4z_YphFJsQI9+$=>|gw9o2mqbug;ZFlg; zSXJ#kG;njn5#RU?mtJh^N;tExv^J71>N6t0A;SFX1!-r3zM>5B6`n;e>2~JSPMt+O z;x*%`CHNVKW1}H=A}-p86Z+zV{UM*<&C*a;Y#sk+tw+!Du$hgq@hAC#{GQ}&BkRMp z11k2Z5A&#PiaqAK#2<%h(4c1kO{`4^v6{=7*8WxISG)$Bgt}-nYHSRDBMZ!<89qZgc6_7N|Hu!QE8dFOrn`An9CT#V543|J1rgs@yYIiABcns=V)DjXH?*jG&;G#JMDE3QOkt8EibuV=f45sQ zg7zt_I}ZnYbe4|ftVc{88yZ=m#f$y1_-}uWf<*J~8?~#;4>}uzIWr1<&D1h@VN5#i zH8zId>2G7iq1^p|LtMs+843Q3`tRSq3W2w`%6TKc)FiEF{&m z+S4BkL!cR5UhukcVfW1^)H3`R6G`2cNNt2!+z}W+3Ah`Voo8*Wt}`K)OF#07o9hpF zP5$tCvKMJNNkorQ5SGN@UcL5unq^f1!eBw&_58PxAv6X>dX)tMv6kmEwO$o*^G}2_ z2&twEd>vQpbEb3X(K^JGIWMLu#oQwdW?SbV{)4>e@QB}?={9-<;}4?toH!FlQ|seN zKXir|U>+JvwQPtz^ZUj6?xH9AZ!Ah`MAv2H>mbCv1w8<47wNzIdgM3IAr<{-c z*%>MllU+NGmm@ElvQ8sw;8V~Zp6PzUiBlpv$fpeJYs;09q&tC6d5rDhaDz&41akxu z%lxFNQgKK(7FaT&ce$ZO#CG-e-F0t$lPOA|9dP?L4qV4N5rT|W20|xG?^Vj}{V;Im z>NocN`}MN}4cB>Q$hu|Zis2@gp`{Ok)t{H&`ONl4{h{I{fx3@2FC5&pizGURTsQ{D zKY**T90Y!^uvx2Aq~HD#D^n901Z}Nqg`bfTq9+lH!pHmVPl7I1qROu(XfbtE^aAme zICa5m8&VNefZmWX2axd0Z(VOmjcMY=K&-?xI@qAioQ(el3_!;D4(jW2q_zYaTS3~B zRDGh!R+Y_DxeHKO&XreS!%72pV?ZRDY^#j*Z(t>-8?^Lq6TIxa!8BfNlukRYWg555)pqxkuymbKH=HF@rk^-pxpnokDs3sm`OQ0->fDL5Kcf6H~(R;MnUtXTAMPwDZ){K&J_pUAXC z*=vzwVVG3#84_(-GItv>iTGcxT8%mpD1o;8wysM>R0@0{#ZD71O{ZYpH_%Xic1M}n z!5;B!%YY}5LE}AB;17v_eu#w}hQY9X=tta8`8}eBW07g^3utSoir^f>>J|LFp~iqA zWpc%D;7mUZ8CIK&rzphx_Ov*^fx*)w8*J&VjIeU<#kn(HIqsa9oNhX{cL| z2OoEvZ!e8DA_vPdKgu-odNxUraet`iSekm|RE6OLaxaQ|@*L>|g51Z*cS z_A|tT14SDKTjkYA_=dTcQ%FSkQBce)OmFKakV5nDTWm-_THxW!a?R3pwSRK&%^Al% z)=BPtwvgs)4cURW$S#O+C-iN-CF?e$x2)sc7|*Ldu%(U6zI^j`(1+Xc3Gf1a29(m~ z4QxH25mb_X<&@9IDtf!n>y;D#IGF`%6@a4rYY4MR*p@wZCNKZ1C419%JVaXicXf@1 z(@*LxptScp#Q(uHZAUlvR!p6BthFTNQgF`^!Z1V=k zXdi+Q+88$;o=`Te32D6GTXv@Pms-3v4P7C?hLsUd2HNO_R)&=s)?q>*K*F(Jzg|Y? ze05ag_L#tLs$_&Sl&Y6?S+1RQ!zgJr`^m_ap>bgUy@aosY>)_|cLV8UnX@6WbQUzN zC=}`5ItY(#g#Gqn!SSaZ7LwWW#uEZQtDt}GRLq9*YiM3Jg(&~*SsJ<1ov8)f%f(&; z=Kbb<06cbB!G1*eVe@GhSfgk+$#7J=2zaDx*S_7ODEb>1@nkJP==xSAe-aGKH5bB` z!LTaI#UG@&2Es~@8ZuyY0t6!H1`E%#)ZI|M+TZ)D3Hzv$b6#)DZ8VZG9gQK{bp)GBA#F?p%cuO|=K=wUTx#|BrfC7X-<0Qrm z6OQ(7{u%Jq?`GoYl-ypmMu=Wag8ASF7{0xo&#sxYG^GlCZ z((m(nc#$+DQSvw>TK-%9U}cvknvKY(!0YtGH_oP>nTRwmac1iW4K|0Ha8a5(dwG( zP`{)*P^?wr&Y#iHo}cVMIou(jQS9czq-!(?fG zsc8CtUNrzpl)7JCP_T95$nCmNa~AHR74<|ZQ+&dn2n;en>vI>%Jia`tG=Xl01kz$k zu{Rb7B2i^SFbY6B-KNAfK{UdAQhEdZ5+SrxDSv*z<3 zF~|&ni5VbBYR?Sj=9r{^I|t0IQ5M_f>U?eB5%{5U1ba0EGNcAgU{|NW8Phg0gVkDG-gK5WK1;%XGI<%unNbwKCRM>m`cVRa`Jl*W zl<}(-|4k;u^Ozo&SlnJIK@k34CV1@DUm;4OY`ufUnq}UbOSX3*< zXPgkNNjb-r4?%jda&XugyElE|)sCBT;_|nCU+*zH*<=Cbm&fPsmK~|P`^KBl)c~OT z2JJ3cpj^bk0!he&Hx@9qwG~3b@8oY~H7YJ`)s?(a*Q^Q}ggdw~KM1Ppb4yFh62>8x zih0X9p^Y}T)g_E`2|b-rteQY$pqDz}fY5rz*QWCx&$CBF+l2a)A3xXST(`b$SMPA9S`55-~~cD(qWa_c z!1h6^bQ#cS02na@GrlRIv~vqYb1u3)&(H{;0$`S>tMS;hNZR> z>D8|NoByX-sXf&jh9RkY_VJAnfUI~Jaw8ceC-a|f8Z*nRe;sohqx7u(6m5oX;Zo7u zW=7YHFz9i(xD6Z9{d;o5tnxI8)YXBGN+1$37D&Nj*}k7z8f@l79Ypps;@_XGz%7;XRVaQ9?+l(+Xv}_Y@J?-rb48(mmzd&6lA)X(}5mH6a&rwGp^} zWPQ}TFbMd+y4>gZ%UU-)0oTO@)b^Zgfd#U7pxE-G?GP=K7)@JlbN4q!vdf%RF}UGZ z0)j5eAS}T%KwasyU_TkL>Gc`Ke)ft~yq#9e|H*Vap_#5^%(!#SC2C4jte5V3-5+Tr zL=T7&BWDqJ$LV5|j#9|poS>QLeQQo)3U~^?_Q+^nr#Gx{%bh5%-e7Vf!&CKNqWnQn zr|oKx9CFw_0EJ%$P9Hg)x?HxcU%=d{h}|=lVNdk_JWH!Lkr`QmN|jHJ`xv_5;&Zl3 zW9hXJP=8Di2tTguCq=vc?mxsFbip~03nup_%-H~*e`WbRoP29#S!LPsb{nF3b<5^O z%bYdu+LV`TnXZ+;4!D)PPkDU!fNqm%!MJyy1a$0PkqTIh>=nT?1~F4edBMHv`eIpc z@CJBCc3Q`rUQ(+lWST7~EbnYy&NItiQH&O4wTdtw*>ML|3k9J<5Gup%N4LY#7pOfL z!ZR;acE%U$`}gC^K_5Hn{~WY*<1~%m_f2D$muM9lN^@#6k@9sn4KstG#AWt%ONE=! z2M}A>@`MgSK`qK+Szj5Cjn>R5&xHQfFFN?m(x^U$6s({p_=g56;5~D^OWwCh&5P;a zm+7O3w%Kr&{}ak(08hPul5R-re6*8TJ9kNn3RtzN0h{+_!=99^O$*8jwffxgHwBKN z$w1p?2ye-k45Kzr2HMLxv)7X$g-3dGf2JFqsC+M9eQxDP_N!N6$^Pd+3)$eWEx=7T z9?P#+rtJ3NhWX9AsnIqGV<$l2&|epJk=KZ2iaWzkk<1jDuOwB#a>-BW^`4Lj=r?nt z%TrQcLR7x@KVN)&;W$KUAnsv}??`h#J+Eb8_1I+|CFX0wzofe_olB$cWE{0k-35Y{JIM7V)z^_`bx0x2V%ZiunoWPafaXL1 zmTNgL0ulmTZg$#H*eo`#>JvU*Tz&j`V(0e z8nC@|ph?4iL(5w_k^dSV>;pBy$s*({zGRJEDE@SR#z-y7-;wo+2lH)1!S?karf>zR&-tqpCyzQCsu?Z9wZtTJ(WeV-4(ZPLZJEjC=$vwk!BSj{skH=rFHzIa;s$!0RV zw|OH>?Vs4rZH)QxQ=g8zI@yYJy2j#M?6VekUW8FrjMBUIiGg`+RMc?d`<1*iEA~;- zlh4#=hA_+emE{{y-YY5_C4?&hPh~#-PHpBxtG=4FwXz@^d1(lSB;-j`*m3X}el8yC z^`eVX&E_}r!+vg zRUk}8B<@{q&6-)r{=M#_aGlsry~=>nrZ>2UZn_2Ovx6K<2RNM=r8aV5W}V3()BSK8 zUfpO%)GI=t29XosL?e>^O5j$|bzImcDzS29_*(?rOHwAbKErezC3FLgkKLeTyqy@D zPKkO`F1{J?C#3l^(@6On2h6o+0$a0{`rr!&ClkPB$hEbjxdbh=%MQ@~i@g!}Kq)>K zpz;rTV6vx5>Tic|Y8B8-FzEl3s!A-5K54NL_3+76^RFw+ZcztNx^G+C=HoG5swr}n z^lNmty^CN(9JP_aF$ottA4L1`e8pig`lY2aoCVD}6RleL)bcxiO4_Gui-c@_xGm#w z-+?c`4tEXUdcbwFD6GyG)qxw7D^|;SGy*N z73k?{A0wC$0yh&=Vtp%|mWIjNsFHioGbq+D^2tP1t^3V_i1>v#)5aX#_ckeGR5xtN z{X>ydk-)$MxX5XP@O`#Vctp`!(y#^aO(JoxYJ@moyi<_=zdYIl@*E^|$t>dGRtYdj zXDaozRq}?J(Kh}EV`hWPP#`p;iCb~Iqn`I6QFL0t+bY_zRM$a%^danLQu%CwLGt?b zHQ`4uXjEN zU$QsP1pM3~ZXLhLaIP-wAvP;i)$H=zXD2dj0OL_#(Zk4btO8GjKtVGm1AP?``(xRM zctf}69kX+|&-E~UAI9p#S#%t(Pp8-CSDw7qD-SSj-D@bP3F?Ib|wH@tidkrWhMkkNw z0i4)zjG3bQT$V8Romb~gxm#3%vqo*9i%Q2r<#~tqkrm+XohTeiFZaLx?~7#u)*eWc z*f7R2;Z(e$KRXtAX@>j2YDe$DUqK0J#wvIASi8nzr18^R= z3UMN53LMg{#CQXe0T#FPX1D$1w;hFf|0fTmg8s1(J441RB60pj-*8%&khjw=bj|hP zVrF~p>oNEZ>o?`E zI#55+et`Es;)z;CZ+1KqfM9+^D1 z+y4h3X+S>J6)-uHTg8MwJg48jXw=2P`Ikx#D&XL75j%sae!Y@h{UfFbTb=0@nLqGx zmgk}MwyixhYwz8Cvq#ALlWxXSl0`-*NoUa>E`Ot~(0qEJ7s1LU(H!psIZvDc_Kk9A zT#-Inwgofc=005$D%zD%Nz))Bd{Vq_v57`(zUN~1 z`#@0hIi+Ip^L0gvaW$5KtI~C1XaeyElsHU9E&s4j{^c*#{=;nBAo|zHu;Cj2B9#E| zX{|G^kH&&wu;J-bpyP@~Zuq)Jzc#XBkUKxWcb&z%j0=6-#EK2rOnehq#G|2SwmOup zk{C?TSR#6Rtp%%e&~6vYCFuqlEBe{ECdMSMirAc}*vf|d{HQBh`x<%C4q<@lW3~WN zO#KrwY6UqC`M4Iz0{xgWTAp$Yi$?NSgh4}v5SpFmY-W}VV|9zB(8|tXh3dYEt-0mS zWBN!*jEd!R%?FDj!4u@+6(xGk`O<(mCL|yEFaB!iPlH*Uwg;cl4K;qsB2k`=r4T_B zz&`IgF+QG3ei!X^kA2Nec&KC|D5f4j0GWQ`(4h>%vHmN0$$b!4~EP`UY@MlUuQ;Ymh^m`pk415$;wt4u)u@GDtbrusBleY$kqUohJs zEdo8AOtIR3Ifhn%qS#4_uN}kYNkk;`!b0rbzg!z~k;0yi!W4WIZ6mD`s|7w@vm54Y zX!I>fEJRK!VGyP9+dyAkG`Io`&UEhn#8FGcFP+2RL!SU2r6isu0S*EdKDV$QHq9+p zE=)3;FD(Ud19l!2#Qr3pert*i;@}~iKuu4V09McVj)b@rm2~76MT~0@>w#t29J&}2 zRDA|O`~sy?O9!Nr=tQy=oR3d`-i^Wng9vXfC zFk*cNr43~t^Yd!5;SeI!62~fGF*}U}eW^~T1DSKXg#Xnpk4G1Wz9tMx z93|U5TRFR;9MQh&ANej+z7Rwf`L8E^gY2CGyTgvGv*SZubxbh5_meMWeX&-h8Byxr zD3KQ`kQ#C?vvA9Q?fHyNY0oM2gu_v1OC^qA9Tl{(b;AO{d4r{|8 zenl6i<@A(@2tm1y^H%T;@-CAaL(6%j1syip@Z}k>(ET>QPS-lR{P{e%2)!PLuF1*E z8bK&SAqQAl^7yP|p=b5ATa^RV`^~|?k2kZyKAXCUz^3P1PEPM}*-(Ul=)jqBn?mHK zEE5hIz|O@d5uVy+{3Q}C6lVX`y=@W5Heqo0F$v1$UE3p^w+Vlt$oav4o9^;` z%YU)54YIRj|F&PwNZzmCGc^(YYEN_db?9*lWLyKACgK>uIV4brh$^_4kvQdGb`SB_ z(@bOioFWVx=gLXS%<|F6K@+}{MH#9gsw%u4A2$bq-p2E`2fX5+nDJ@PTo~Y$zsjNK zh+^&)-c6qPFfUk{;nCMGf?Jf2sDB>BX>T*X%~Q{8=JyiE@QiQWclq527YLCzyTwm< zZptIQ^HJwkKz-CM^RrAx=KiC#x6Pi^z#h(>-lEj|9&+8BU&L(vX|%uK?m|@fEc~`4 z07M45MRZ1pZ+vNk5V$B{f#&7rL`EG_?k^ud-=9Pju$m27aS5(oi6Fd8A6z_mnR>gt zy~Jjl!PNuSBM(NKR`APj8)@nO5lDA7kf0gz?(OboV}BiyF=%XgL9o+ zA_45ikbjLN!S8m4^Vl?TcD1N7^O7JN{-B+L80dBd+AntnKP+r3%mwI_?C%HmeH@K` zf-4+@-W>T4!K2^!`pcBb@)4)d{20!2AG3N-LCvMh#@C3#&SlIa6CCQunOdK+b2hfR zF(mt14&l-O_elCY^=1+^a$y9KHEM#>_6%noE4#0&iU-3DSyoU_iotFWyzdhP?k+$& zfZ1)@zOyeG4b|zkEbE8Pe~PLk(mb)AL06XnxjIieJW29H^0988_kIq`Ax0$^q-{;m zF4dJOb0?yKA0Sisx<9}JskO>gElm`q)~6QxAxrBBNyroyd)3K7!UR@euA_L}l|~tj zP}8ZX(u8|);9^z^xyA_96e@QKLU5tM^6$Q6OqC}gjs1x&U`18ua{wk*Ae57VMGYji z8!GLW3l`I*E2B`0(v`@53{!0(YCL#}Wy34!Q{hL{H-fUnjCW|*?@qFiU?{vLBCE-O zfL<>5Sj8|Flt%OtcE=QpTznSJ%mNDu4qZlU;z}&VL+H_f)zLCsAw)Y#in9`>;BGcC z>l=c*BBMG+J~#|W^_O0%@Gwp<#QZ~&v-pa4ulBVXIzt&Kw*~n8nS>?i+wQI&xg?-+ z(4sgn#ki~?d(>FFf~x&jpup?)-^v!=p`TZ+;pr4J4ZyYiS4hDOgI=t!efAW1M;5qX z8UVjw1934m^a%Rkq*|n%Qwyi4iJ!~zMUYR);1}UGQ0sdjNWFe76qaQ%#6L6X`snml zyJ#gf>c7`ClijO2HPplczT-N*9! z>dhKK<=I%Te;myTLfy!yzO_sP<}qPebM#2iU+viQgZqc-g~)DrUIc=yjRh7w5a_~x zhzK|N+(1+b3FfVGk)x61(7qGL-+${meB7>N%kEE-E^SAk{=_PBqst@Up8@(A1mqVs z#Z|@0d$%Y#V%d~p?H;^HN#^-KjaCiFxqF(OJ+wE*>u9OV3zpQYcl}O^Bp05 z0RX=3FNSzXi+n&8Q91sXu?#hdf=*U%^4U~wAML?=$}27CoGX~Zvw8yg-nSp|Sidh9 zsEJPr_*ZfbM4()lq&+qsz`im8`n7|u%X(+t2~+xx=g!MhdUa`K!lVC-$<-hmHGtZv z$Di$P|9#qeHoy?3TaTfYX)mr06rre-!PXoZG@6THqiJjSnNL$6VVeUbHr}631bxz{h%H z-m-8;-Ic6U(^s@RW1`~AklYWuQ6A2FVdat{}zpJ$7>WMfh*{I6Zc83eJK8_UL zC!fb-l$ZJI&vVH5-!Z%Ks6VKhrIhxWDx~rIHwEc@2ON&LukYlYTM{dg^~zE7ZmejjXa}mE>E{UB8HDd|j}>kQCg8I-h2ogT*;kq2@%= zcs;H}r3*rs-uI8r$3R17Ce@SvJG*wySfD`DP+@l_mTv8;_lc&U?RsQdI=T>mnBi6V zSM!8;Zl;Ism#yYqLm!c6@m~y;E96POTO!O%5?#}imGVfLC*88 zH-izU-TL&^n^CTFV$#=+uzmX0`nYD8l;467H8oL_PPYv&ery&AUa!ZLES&E4knjBW z8Me@c5|pPW&ELN)Rvy{B6WIA7Fo}TRX$z$^Q@sg;b1zW;sU?3$tjxX5?4NuKsw$z| znY1ox*3d~VQ4MLV!|iRIEdOR+tsJf&M8aor*K^rPfu_ldE?^j=C+_Bg<83+hq7q@Q z?}jKnO~mDDg)Cp=4*K3h0~DCza|IotAlCB<{+l_*<@+&gTRge#pve0`5%MA5g^tir z)v{((wlbRPDqXNlJzLM8Bv^+jdB$$$o@|@HzRucXu3es`Xe$03$ z)MxoJH0x38>9L)30?9L|3Wqz8NYwXTQKsjjfSSI0pfXy;3C@E$0S2-o1AYfc>B;5q zo6qqA`6KU@M>1vvOA9o4%Ag3Ov)A78r0UH*N+#GrL^0q@%WmNRmB|i_Z&AtWtbnI% z%WhJmQO94M>PW1sCybvTHTT&f^3ij&r*n*FrNF2|1MW{&;|W{PR&{>Z4S&;0sj+g zARKyTNoO?sG>P6uCq94|SnvYgX+0Yz5DZh)08PNZT6e4fRyA|Q_rQ@oOs?$_!}M(1 zCeQphxSqA*BI>Y4O8K+G2|goTtxSC#xMQ&H=0gqy@JNR>)G`}?{-JQ)fh~%LDQW)eQlbb9;Et`Z{BpZ1Vq7Xn(hy09)#&Frd$(kE1jVo`4x(rC9&hc zcTN1BWU{se@Azs2XT4|8thXo!DforCd0usBt%dfKnQ^1>d+79P<|+dcLNNLi*|+VQ zngNn(FH=Q(+2A_c1@(`T zk~>VR72LxVJ4F~65dUd{OR5_j#G8m1)}DK92Ftl;?TDnp!j zCs{w`(|80LTN{MDam6l5TFCojV4X6S;)jOP?-H$SnNUciNmFpE(kdvEnAL;bFFJB+ zd55@5vI1UjNDP|xpT+#TdBinPrISR_r3OUCiApCGU&ie-Qu(!IoH-Z(iZmrsOym@T z=#z$>axa~JM|w0}aC&2QwbmCN&Oe*j?}xy(;5_#)B-!4ota-<{RDEOObS`jV8~#j0 zATJPd7-`2&0juUda2LE+O@|J$${1wN6s8{Q)T>52?9cz)-Em&2G4$Kk0TdjfN?=hf zU(dT*C&&#n?1J*#4oke?fo{br*FMd4cmzBk(lA5WEqZs-KNM+hrqFND(RGlIgG}(O ziVv}<#JiKIboPW>Bz;;|77 z)u)`2BRW@7Dkm;(n1}my`a1|i$g_oF3HaPwlxFWdHK-&;`M4QY<`f#4XGby_TjB}^ zNB4)HO%3BL{CVXnRP$2??bcZ~RGp6eRV)BLkZjLR=Cy!gvnfo9>};YT%(!8;cSodO z;WNQZJW2^sD9)OVfDAzVB?}1*5_pQeez0dg*9a!4mCR_hF5*RjP}TX=RNjlXA7#l- zeOEF~vc?#{gbUn*0)ub`B{7I(vAFCPcH{)5pwi z4wQb6(!Jx>_{ed`%rxv-Az5x_W){YP;TAD*Ds%VKA$K?wDi?!Dq)-O-X4v?;QRcz( zqaP+bNELYnjl~WsZcU(psOzdtKbo#**%ztBK*jMdS@6|kK%e>s}e zs2=>*Eeq{8(oN9U4}Q`Z=~$7hy9mb-82{uF4NIdhioQ+I6rdE8RnS60NPoc7HpNB| zo3q;aMdSIAk`uCDgY}<0NO#vv4r@UaV@ddB454;>g^Rq~8e-Yx;|rt5B(at>Z-_Xag`ntE?`0jW%vf2_$$PbavA)v4vRe7ir+{SVco6};v7o|FlQZdp7m7ZmknI@#tMCb~&wLS<(^+&D6}FM?k?VVhU&dC)QJ z2}@|W43Tozb;;)&)|nnNm>c20cTqG68pYs2cwHC@1A`r?^4aMN7#cZ*te$6t{K*X% z-&tDI1pFaiVY*LHNNSrt?HDjU=t#j`38=(PL2;-^vm0FA=pgQPAHu@s98Hk_;~RcS z5Wq)}H7fob^A^cr+cSZKby5)5mPWa_k-Y^W?*SBwR=4-N^V3MFkYp3Pr8-$V0ZG}s zdidqk0hx%@xpt)bkV>)*kqGp@>}wEdrLREr+8l}sGEiC%x+ek%o6B<^33)fty?0Z4 z?@iD3WpTV{l`G_)40;#;C68{b9(HUVr^+sMX#!IG<{z;#!L**?wBYTt-A(j~g8O2U zw{-W(?Ak-0e-gsqH?(lGfSg?QT#EnP2WebVU|?27;72#yj1lz7BD;loe2rZ?%Ctx6 zJqs9EAj~;r910mE%1t(%WQ{$aEYYdTvG0J!<`)gcro=8yeK+x~nGaXUY) z?P(t@BeHQ$O_<8-hpvMz2WOq36io^P%0B`Ualf=dw$l~_Edj>I+o zz?KmL87dU?@(LO5uwAeI8&Wsf4ANHASM78Je@GeJy41_Frj*(Y%AJ!!n}uFI>e3pJ z3o1hs#1s-#CNnF67ij|C*3jWBxXa5iYk$4{?f z=W}PR&n;9}f_9ak9~^x$881Bbf-;}of!_;cTl**YmL1q*-V~KO?QsFdTS25P_^& z@IntqD!E+yru+-d=U9s@hl83N8h60mH1BfZUbt0kr<@({@*)?`s^jE!WzVDzyQL@{ zwnxl9v;oQtz7}!l6v#3fbB^pjfROv84Xx0m-geySNI2BDD1Y3y+ci<<`c*qh6#m)2lzmHD2j%r z`gV45U#~87okF00D~|V)-7^ zaQU`NTWEEN6muh_fu)} zAYmDF9=1}D^Wev(A4wMu>0Jm%FGL_IumA z9f8NUFq@nv7rp>a>1A2rdy$DcBvR?A@1i{BM*RUC-;1t<)*tsAGp_=$p+l!68K;_G z64KBlm)><}^*H(cYw(SSgyBHCSydlJS<@BOz9inT=YwyRV@#jIutOiwPeE3nU!7qi5>#IxHK1Coh~@DzvwrC_l$=ty=45cSeBe_x18o!(ynCek-lP^BY?s$i@` z67z69`V32eFhY=T@QHKIPu?_7Q8O3y&zo~ZXEp_BJcl%eFq+sSero+DE0g4kBZv+z z{TL|K@mNE*wPSbIss5@JVhD6>CX$)-S+U&}*#8*ja}%m|L4!v`4ZO{B3!i8@G=iDn zgW(PiOwsseR$J|~J3<)sjlLy2lZ5n30u#t805(v)J(3~62ybGzU>L-;^xwRf+Q_8a zkYR;mYHE(N-*w2Y`G;uv`pdqrX~is5pS&o#>eo`jH_hY)#@`zz26R$?@yMT&27kBo zx=X)4y?7o1fUhfZ;Qpi||8_$UH)@GQ!*(^aq^^RjY+FXCQDC^1uLY7o0RaXE=Fl)F z@j*&NjYq&PBEW=Z`SR93NeBp$K+Qn%<6MU$DE^4H;#K9d8V*ahsW1EpEM4g@T~OXk z?hL`yM8nG(tS(-L67OudBMRUi*LuSasYJtJQy%0U9i${9v&hR^2-G?ybBVK`?kqRt z?CdXJVZBPua{}cfso*5K<1^HG`FyKqpB@fRDo&5_KDHoRV8_>+1czlC*dnkEKS1;= z&qfzsp{Fh_Xwl*uuI_DI&R<$EBtTqCFNp@$0s=DJX$ZdceS-abZYEF6V{_93y*5BV zI0VXF5=5Ol(d|m1 zZ^geHnMr|g%$S8M{k$XzHFkEHCtQ)g4zU4_Y`1s={&DT$C z=stNkHXR5I!|nT881D_A2}sa@C54CLdUJl)6@qMV^1nHBq5gwd7@{L`-l%yqG;{aj z@jVIsl6R`amvZaNm;9k}Bs@y%d1$6abP?-N(kZoW$t&>|=w(&au_q1NW%BvPUIrsV zeBM>Vid)7JX@-%IyA%KStTT#Vg(vt$0fQF7i?)RgClWR+W%2S;;`O@fkNOs^RYzhV z#(|^;6H(d58++#bOFZmQMJc*liREc7KJepv$3hVs4GhIrqu0j7EvKzPmoS6)R!Mp(bVhxhJ@BWuhwb9Q2f4J)VNy@#KBEHreit{OX2 z9Z!>KoJO{!OV$b$B!nXe^~Tl~7x`W~Zl1tm3#l3;Wh;mEbk1;`)*lGm9p;ti#lWzO zUMGF0tp23A0~S~YZ?*@SDg71*=)q7T5d*9DBD3uT_G^b4i+q2Z_OqE4=C>H@mnfq# z22xs*$#eYJLMc$fGxfIXVuMbE$Vz98{@V=<^?5$^Amy2A$d$xA-Y;C!6Nvru06<|i zKux@I)DEQ0hu-LJ-;ol}&^_W(z>((SeSopB=*#%SZ2kBk-Ey`LiLy;d|M+lqy94cT zx$$)#|3e>Btf<6^J8+R(Zt#_Bs>9`|?&2OvYp4H>Vk;;zDp+NFP!y>azWU;FZJ zWKa^cgad@O2mw}@aRNKoX5Um|P5k?$&tRg^6)}jSI-RBVa>e+st(FY{ma?`)dmr{$ z&Pjl=zTQTq@!z&(%tmc%-n1rTo6jZ>x0t+x;1Nhz$~Fig$WZGoy8w~xZD%6Y>S%mq z`mMuSGqfEuGZmX>uWK`V*{UCjB0<_-;+_8_UNtctO6tJ7o2HAU>TDd-HJ~=(wa=Nm z7h^YA&K6tUKMc4pnB>#r=KgK?hqe^WB8k?N*8kM%4R%ye-{7KY9VuPydrW%-QUEOE z>4w=Dd%~rD75XmPSp@&;JGH$b#5S&y=p&oB zaT+CLihY52wL-=5wP`Xv7A|7#G~WQ(CngA#H43Myuv4|g`1{j zmdjQ|12$x!6euNt+=jY#axOs(JOvWj2e2BGXCE(`Go3`iNLbbMs2 zj16*cq^SoVMaC9vk6;Z6#ysjpK))-;0mpbnW7ZSN=lViS>U?~4{trnDbvAJF95#JKkBncI%s{Y<#Qpb`i%I{cRQFAls-OOX`zTWYBuBKUlPE? zTzH{K(7Rm=S)Wtz2bqZ`$VgTpT~o#px!WMdE9!P-Es;6xqsbd&@M4 zq3fSClY0M9@t0MfU1;I8t-k8XEmk+`hO&W3m{=&yr~4D;(vKH^7i09^{8XE_1ElHx zDz!=Hsw%SK`oqMo#|z?#9|7y#zz6&Rn2!?aL%;*xO*Sx(9|M>Hfon4i+xX{oFk}ld zf69C!e|K6J948Is3&XdMAO@y(IkP%dHmsg9{cUfK;sXH&n7De;>Oydo65znP`mOd0 z$Ga(m$Z3k6XD%%M#|)UJfna?u@GrH&Qr3Z8*0J&yFXbYdHL;F*6j~$#bx*n!+#KXT zefR12i=`VfuFNSl<(+de3)dPy^m(Yux~uH4O&jC-TKftk=5nd&d3BA7a)rc&>XnDu zn4D4*kPGPbEfcqPVZBn2i&xrY;)^;bvm%YP5cRFGX-JBiHr>0c$W9#?G+-M9&Kp%+ z7@#K_izD`(!5tE}t`}!`+XYoCu=ub(WGq{nVyMUd^WQ6;&uPR6c2M4An_%y^T=K>} zjYPC16g#GYK>wva+;&Y*cGlTiV0GzzGDy%PJa;*OkA%XFOd5uFsE`CzMQV!dBOP;b zmC-5TnrV(7_({G3_&_Tc2LEq6N%INJMP%b#9EkfbsLrUOK^<_)HCh)08h{VvKGGRi zv}bgFSk-q{HAzfcz%=L3TS5t*H~*SK%$U~cWm45eYOJe6q#K)lK3OZjYEL97?!cm^ z?~G;?&GMvd;x14mP@mE9Uz^6iDaJwoJdhFgb5@SvEaDIEy-r@hTu=GJ?SdnmfU}eT}u}bzW{0&TAb@e_{F@ZI3;H2l2I0 zC@%RZZ8mQc%d7ii5+?6KUD|{H1o+Ep=5OBk8g?wzgiZm;M(2`9wf#<`i*()`e*8aO zoMn*?GY)+md6E2rfEg}6Ttbn&E;Y%6K@1(ERLeCq9L|(elmOfY&H!H8G{QTP*{3{eygBqgWw^>0v`Jrhvi+Otd)1SrV8mS!Gr{zRiY4T zBldH9Ltp($j3)x|sd)k4cs=&46kvoBMDNLby`xj}sSXzA+_(Pt#eHxbnQ(cC>E_;z ze)7Rd=j}Kw79g{Z8pn_MS=M+b82J7$nIOVt>d4B8{|)0gCLLRNhetgNwL(}3juCNI zzE(Hg%1|FhBx|8WISs|38;8!o=0x2mnN9wxI=Ei0FcNPT#4079|F1%mvtPU9`zxok zo^LDUrpm_W@h~Hv58+K52ZKoZ>*5K(ByOr#`^SbHw%AWR-BTD~U4`ptnm(NsHyu!z z;aJ(hy^j_7%W45UM>OXW7h@vUxG3aGNh96Hel0Mmx7DTNz4Dc9(CC= zs^pZ_9Mo`H1BJgR{Bmz_9u*`u$qXCKTWD^2teFV9Lw9Kr6t`w=Bz8{JKgk%lH#%31 zcXiEObm%3;-0K6uGyJ~RaLdXPBBEF4s7IZ)YMx#@I$DfFc;+4=@bYvJlN=fr5JZO{ znF+G#>P(Q_kHCSDpwGKbN;^}tvG&lX=I%3Hb_i?Ku^o%;^roAJznyJF=-*RoQZbZC;}ef`zvosAqj(>pSUrrgr%0UBheJMzJh| zEmiT^ueejUDu~b+3HWhQ$T51R3)}sifE_C(NnvlywUOz?tg;~!CgFd1VUP@8ggrT(wZX;!_12& zt8BTU^?|@4Mw}ROBSTfLR{lLE5ARfAKAIzu$I*azUOYB)U7zL0m4?{b&EjQkDSYjl zuUtbJd`T-(mc@)D8OO6Zt_gxwUd`_v*Vdn9TbfWh%k6Z?#G}-krv0lKV=`FFj#wl5 zXcf>=bb(IV`|;x;bXCO++!O6-{`xEfFCmzP%Iz$$O@@Y*x8*@1E@?FT;C)uLC6vav zZ9YD64YKH8m}$O1`r`CEmhXe0O`8;5WlyBFM~6GfEX=7*X!O*%+sKJk=7}YHj3|f0 z3q9KU-d8Krg*m*g0!0-Pm?r>Q9ReXk2D2cGizCmIYls`V;2Sd_b;lxsoVG5Y*r5Ah zcKxbD3V5vw_LBnuPi}VFnU82#fF5;sOcn3uXW38 zFFU>L5ia{qu-?Zbh;h&JLWj`TO<$v!J)6_`j>YlB{iaG#nfyR*r0!m zYrJ$J1m#Kf&vg!{s4lnus$~=LeINz-n>wqOb&-*+{2Y zuoKlT2!JzA5G*jSVq&Rm!vX3@D}jUALt}ZvQ4@6?p%PO+1rjdHCC+`LWf5f9FS4~= z!97)IS->c!liVlc%)3pjET(@&B6W$ONN+wmgO+J0!^xGzF5u2NCU4*~mW!Kt5->Dm zmq7PuJWpMIC*_7v-%RX$l~(JM&%fzrDICMzRwHis&G;<>a!0zrlYw-6EyqmBJj~ItlRdI z)B0fv&J&L(CS?ABTZDIZE!B0;0Z?}3=d_wTzm2sOxxvCU0K|i?D50|O{f!_? zkuhDOYn!7_k|FUE-_iuaC&UHijxov=1c+o_XbZ z*5=6Irfg?aQ<=ot;YCBl2!Yj@QT4aRM=0z__6z~q1w0c4JAh6NR?9_wR|e2l&D*T< z@F~TKg=Bns>eHnZ*CqTouJD!L^YxgC0}Ets>=l|#iAR_JI0LI5@iMJ;=|m-A;C%E4 z2P`+zE{7lUH#jOcs5i{B#UKs+TAJ)|fUm-gSw69?&IYsufvdOg<}1r7x-~*Yi3u#a zS?ZEs{b9M$95u+AC}{b=hGf~C+@BK1>_$bz35i!wy zN^H*lGjM42EOu!P0?WC4XWXaEV!sCzZ6}eAZD_K{*=zO2IDLCsN)2OXpV1;?Kz#Tg zfU!h-?NtDhxC;7dKWvlI=pS8>QWj_Br`q8`x=%_|n+jC^{KyMzUrOEyQ^jq}BdEvV zl{^#aj?erMT20UBCi!9g3Ji}ie0`zmagCsNNggs4%$P#nRuuk>;*lzuF~me@CIUDv zd7QAnJDiPYlE$q`2-ev{O#}p^tLFV@9P{1x<00{db&`SZnM5^G&V&y+aITZfr1LJo zPKrZfgo^UXHtVVO%?8t)`5%MiDGL3Y(@mQBUIV0!ymJ630Ot}>kgvWe?cvCj*@z#y zK~a48+IUQaz#w%P3<`ELh4OQ^>8M>v#8K=gVV+k<`oFP;KBzgY1yQ2k$@6nNsjQKC z?cUYu3MMd1DNMm;LNp%MCn>}&4_t)C#qjIifsQZv%Y4EJQ?B6yRWCJ#b$A(Z*rZ7p zAsH*+^B`Gs6r7Fgu&&-KBKjEJ2u{20#7)o3$M+-*aZ3IWwbx}V&9{ZzSWQquwjw2J zccRp-ZLtEvi?LrsuKQ{zj7j6uL*9Kille$s=r%7S<#aaGpXLcc^c#n zG#3Ez5;Bl^w}Z%eH12`Em9JB}_+@0i;|?Aiblz=8YP{g4YhzmD%OPiu#JW|U&n{vA z`i?HkNT)4m@b-~}JFQNK{@^BPyNZy{9ef-+QuGU0xx;Vq$*EB#Fj-p;Y$Sh>4bpF% zi68qo;6pju<=CRxR5NAh(DQZx?0_IO{{n2p-+Z$_oNaWQsJRiJr6kO%XhDD+JbCl` zfXD<+Uz6pk7QQXjCo-27#*aE?#{2!_7vbLeTV=kU&lsq=qK!r<^%A3l02UqRjwc9-GMf(Cjk73K*8Q+)~^X)DOQ4vOXAd(`4LHw#2CoBZ#4x@%|V z{rofgvhr^7;d4-H4rKnGz*B*ExP8#y@2`49+UP5xTGbbGXtjZALK0F)eojZHWf=T%arGH`g&Tm zMg50V0QznRCOfIzPKg`BAyzM_n0RUmMZh+ga=1arbir=H+BNKxb22(7$b0|QIV3?t z6wQR-=g5|({uH0DqGf@{)bkS_A+YVX9MGZ=4e#X2O{O!29j;zjE#wq>FPUV$N7U#$ zB9f&$6}63{Ht9g(>yxp~PAe$*addhw;kht~q$TbR=nA!>>TateX~0)(z%IxuVQnaq zlVFwG^}7M%1L@dWj{q3MWB3|@`9IjE_xe3RHw#s%8SkvC{8Iv=7KSBS5+;1>-_cH3 z{2*3Vx#KHL9cnmiP=?gp#%lfy+eqpthZ0pWA`k3j04bJPe%<|Z1EqOppPsj1+Sv^R z-v!R-g89T1BSj?b%<*(Q{YFwdiQV7LLj`F##&_6s_#Rf>s!{5lRVlWU7`ii$f^_EE zTejn!XxEarMq_E3KNq9kh@8>d!pougu7`GpbSaaxJOoKKF;uAGf6e0K)2BzA+6eHp zXE#FgnV=v%6)81pa0Fu?BvDaF@|jwj?iO-`9)Q)#AbX41o~w`LBL!uy$TrnXvd%PW z=0}WlL=X=MF6r829%H-cfaMF6Lzd1sV%8JvoAVzOHGu{V;(JBmtRtkj3Gbqjmzp!Z zlk(C$MOrZL>}GkM%=lW@H|89vFBRwc$+}kccnJgUumz6l2?XXSBX^}fS$uPjEcTFV z9P60+k()&uIy>n*DNDe(%C(8#e%npeq*S&t_7w(j$8U+e$v`kPWYe$RnLn2oIsO^S zdA8g@=^~ZSp-+1EVpjC(%LBPH4DwK^SxE&lo@zWt1ThiXoqySYa*1a;D~E?zhA8Eq74YG|kf#A&Mop zccrg2P{MoSJB!pqlF@^{!~~`xgK+xX(R$;gNHREq1rQ-*_pEnqKw6N%^5#n{nE+Sc z%pmR9y^T!>wfSmh%Wwgs7Kcr|Ng_9*hQAM&GxSjqe>l;`sPg$d5VXvP9yH_(k7t3j z5r!5`(3(yznLCo5qy)NnLaS=9|3cwAdth_s;5aJDXU4auT>&c^c_Si%7X6}tz6Rv- zOiM7>_~2-@lwUsOZlKn&jZEixFZ?iSa%LfV2dPlR4fkV3tyDS0O7Sw*Xf~xE#5%ohFMo9o2GacsJDE-sgSj2Nhm$V*ORLk! zbR+G;u)f^JtR-H}iacnaQl7zgBz^>BOhB0ea17{#LWa(9`2oLa7}>ALR3hY(s&J%t zozMX)p#BQ#2uULH@;}72a(=N1*BzpZ(AP4x5h9ON+Ld*<;PTvB?7DXjnWf%{sU&KX zIiW<1bSRD$KVwFmre)CGI*Ar*UKFcX#jCjpU3$4^!=3w_5Y; zO-PJ4&Tdn1r+#OJmcwH89g{ko@1OR{3`61&*eF;b5Qf1mvz`Wj7vvr5931;Wmu3%R zFa}yAK}-6|Y3eQruOunyU+D7?^?h|a;^1C(8j3dMRboV+-K192_~ha2 zB9jiEV>O4c&JlFw=s=g0=*1f`t$5XEiurpKDaiB0kn%VPjY&l{p!p-jFJt+(Kxsxn zO)r-pE(-HZ6J-Vqeo9ddrAN@M_Vg|el25eGXP*Dato{nij5jS~q4}??p8FS)dEp4! z*%3_F9VwzmJK9d%Tcqe;NW%{ms>c;<9|e))U7$vq<k2g82%FHEAX8y>uva0b&EFzDI_Iwj+P&+3`94?O0=Ydqkp!?=Dbi zy#!gDTBfFFkN=0xYR<%SROMOZ*D=wS9sYk>d=kcK1fq{KNlxXn^~-~pj!I;k7+>st zGCO*&=R61{)V?3@*;`X%FSqz71;yHSI9yhTq@LbNWu^A;fhP6C-6%}n<;k@1JV*8ZI74GK;)kbiC?KIY@b_q+X_1DyMU%-hS|X0sO-HqT1u8wAeuRPANeZ>!j_)~P@+zG@fd zJ0%8@roAs2c(v*y_x%oGigZUjGu&;vy`=#u}daa6ax%@j^`OT&U zT&+>br@r7ZIRS}(2@XNXKfz+bP!1L!Thf%H;t-OqKczWUp&51Y3N-YNu8?jiyg_{O z_oKd^{{(Ab&e?Z$=tDk@#gvREZsPwGnxSO)WkWeYO!IV6a^dH3Klkx{ahl>Z2)<>Z zLr}JgNj6bT%6m$4)zgBG->u(p1;B3zPJxsPkdJie!Qmf2m^?-8u&F8A zFj`v>gNzaO9;)|dkb7WJx@w+YVk5oTh>b!zfAqXd&+V7LBv}PqD9i1!#HT!gQ4CVy z&g`u72}_ZYbH<-1Y!SxSUC!nGu_*0sNP@k>I}jI<$w$Y-sU3+@`o-c z)&F2uvx9__pZbOPw#=&G+;8z+8sy3%vsczm+#0yejoYZ_0OHLzB_8E*L&$@QoJOaQ zfLbQ{ebp!SiDTszCFVaod`+j{EQ2`eS7CuUuncb{K6GZK+Ug5QtW@qVSGC{ASSi#W zHNLo@ldLfGSNtz#n}WZX5xv-(>w-_TGOFUAs_TqrHFYmxt05*%9*xfE2S49i_$}|* zlL?AX#*^R3|0UZ~G?BRL@MD`*wKQ&H(TK&L%R@T%DzFXqI24PO(zP&PP7eqtWWw{& z`_XH^F^JRpVG(_>8Nh9szWUh~O33zAJ`?~^gupX{u92gO@_%uyNx&p%3a5p5ZRwDx zJN~#M)um}{@$_}#l0?RMZgBLIe|oLX!&pBo zVizr}YPByQ9omH_%D{Qui$71?tbf2@(>r>Z^?8Cv*8EZ=Ze}y+2R8&ol><1t1!BKn zb!n`ga-mbokResFbw9Iid25^n>A!_19)fY+XT+LpwY~3#Rbmf?)fFiI7bNn1ripA- zjg5SniTKy5XdTDMi06x29O6~lluKUiT$_L%0`Qt8ujnt@{WFYkd|NiXjlNCSmgAV5 zT#CHo!*5O9eHz3E&Nm=)pf3G{9rX^ENbHj@B@S9z*J^#qa9%+x*Q!shzppzAUs8WV zdiOJo1<^(6O79Wu`=VhMVJ*oeP<=wj&J}&R?y$>Y{*!8?{y2ih`Zdx_A~50hXJ$tq zelBbn<8zNei=av`#S|S0R3Tz!Po7Zz->s=YHvbE7CVtQ$v2QdeQH4n4Zy>})t4s6; zHYGr15n`E9;T8IEPi-Pw(&WyFUX+p$3YJP2KdKQ9Fi5sJW|y~g9@qmyn$s#@#TLku z^W$AMv{SkApV_B??vq_bpPQIn1iVkpId>F9%j!IsBlxjClB1{+^d_!aWDN|gf!FaK z(we#ES1R}G!|SHqHp@A~*K3xk59ZKS9+^!hUuuF$KC|i>a^b(OMuX{C{?~bNn@SnV zrv06yKSvAm7hITU&V3^xGPgaE{H7V@WTAmrAq=u_1IH&#Tpk?$XXfTVqnzIz4g}}e zm>eCrFNumX&;`7yZzfBVyv#-SyLE1A0`1r&%CL`>K zhl2;&xwpAm+q^gL`zV!6jtjJjzcl|%eQ~s|CxU%quL~$MV2=V}cQffj3LD@$`S&8G z#JpX7NLE%lIYOYAw#6KY&EZPBZ??hy$cH~{ke?Q%=FzhnnHD&~>1poPBC)lgt+B0> zC2SQ@(&%+sj1wEuvSbY6iwddJV@GbGmT0_QnMEEK{;-_f?M*xE_vAr-x>V76qX?=4 z0Iw9fI|Ev=g4mYF}x`>2f7Q(#t*Um!rS#H`> zEhYT&4++FIjmeeKuLa>?FX>NYGhcEd-+rsMp{l1!$7fQD`-b549KSgNIcV^oL=? zAVabzs#njc(W~AxD*C}{>HIwpiqh^7c?xNFJbkI56H38c#U=h5QLtTd>tLRfI34Cp|&VpcPu?>-%WnJT_l@E5mR9c6DbcE8q3Y*wrfWGi3j8M#>M+Z9rsne>GfB93i zEJ)~e8-WpTc4%7(NwXew1K_z3nFSy9T9%KEXOxQU9z}Sir13xbM1wYbJq73=v`m#c z8#LHwlGT?=_oCKs=^(5Ag;0Ra?dwx*q+cr%>XKYBVXi7^Hfcz7`ioSBiFfen%w1G= zFv}X0T?XDXqa|MrznTN!kDxu-)y#=2Q*6g_mz2_L zLk{o6Kh?-4LIYCO_Gczyv1u_O$3T{q$+E_+#jwYgz56hft~80^n;Rl|Zp4|vY|osr z$*~SA>t|!V1kW=zzTvbqPrdD9By~VakKo+ny8S_(5b->r4s&s!X#$D9*zD}q`4P!L z*fUBt+?YAK7X^IQcOR^j)|Wo1QWgLDr(|IHib8S5oVf^~vgk zjC&0h^GK_i03(uWV&Xrk>B{2M?nOiQC(ipvX)iKvReVXf_UT0;SLGuk;s)V}BXO2; zes5K85g#sv$F@~dkz#6U@BJ%zfuphq{)mMC$vZH%#{Ar$-c2Lq_lsbbg|EK|O*b1k z;U61ZOpP7xY@OG|j~1_4LS^`o>6p(ZM$n6=z8y<%}{wZwCh)%v}#5# zUffFE?4DAvf^O+j?88IBY#WpV1uXLrY?;V2B(aST$4T&XFJF9c_$-|MRN;^U;;}@2 z=c;q>m$Hz?RtQHDBlNgBDNE`=!`Q97btZmL(kB$hsmrGCi3;vT(eEy&j5qzbwKbNknNY2Df{~IK2h+|@l-hLNU4>--_V=MbM>^d9#i{bVF!3`3m7b4D(D3XMH1_% z3YC1@6W0HVaPM0lLaKcUovN~Fk;Io>E`z1Oi(>1Z{6v6B#lH|^lF*yaKb*cqKm6r7 zuy0A(<}FTT*(v_n7b(-fL)yyrLynG%$bSW7*LWrmc47dv09?9+s88qW<96Ko-9oG(NUv;{-tQ3Mm@Ovnye&hG^^CLVAC4+ubnPUZo53&nyKh4v z^_{(lMXpX_kmmLg->c7`+8N`6I1)Mm_@ay zf6Y!4<`i|x%q+$dWUJC{7zU$i2tt0$d zDplO8=#}F#Xwm~4Ss2bx%C#>CaQ!9tp(rUN64McF4 z8(14p<^svtbg0AxTHti!U9Qga{ZXn}9J1OZ4WG6BfaqqH;OmF5gJQz?#>Dvk`BgcA z%g>Q{535;JYN8>>DA*W!7Q4UqNAxpg)R6GTVJ<=#-6J)3SDYr{&H3EJj0S^X==j)7 z8Jmp|mkg8NWX(b8tKJzmFd|+b0kE%(2=I=DV;N;B#jP~e%LCo>gc zxb=14u!?-Hk`7)~u+~AEZyiL`UvRuanwX}iPXzm6O z9WP*3NsJ!t#Y?ho6I=0LMU#@KNlIW(4v>=AR5a&NuWXb=nv=F%uqnLR_)+X&@ltYT z4Le!{_UhL;C`7&IsWSBpub$I1B-NSxTs78ij$hxu)?+8w>`rl#bQ%JePynFi5)%2; zS#+yzdeCMz)a-uk{>tKT(w3ft?zSoZPJwXgTqiY$u(38AS9D#wNmBSP@=1IR*>2l$ zauI^xvcg96#V19NC|SnNvHu`Y^(E_!A%Vk zd_J>4Y1kO?2r(wJ;Xx!L-Z^xWc#)v#(AI-J!q)QorYe}<@^-4tB5SallL)WKy=|PI zB5mUjzLh5?jaZ&6%XbYLjR(Cv;-OH`2iqbrQ1KIl%z$H|i+i&k8U5D7TXDSHA$RB% zg602XJZ_%$j_rhY{Pko<#UnQ=m8_wcmo>({=-G|bQma%-OqKT3@ zu5;qI0eb`cUCt`+9!o|n4%#o$BC;06tk)ZYM175Me=OG);j^q;l$2J01$sj9n%Dlr zJ+5f86PaYHN-4(bQ~OWv6a!w|N~6Rm&r1G!D#N2WL$;j)(SHFd3%VaA$;0p7EYn+n zj#vV1)sVrfNb(B0ABC-({QY$nyQC^Sm1~)Qnf8V+ZYVSvTxyza79`UUVMdN)nv@k6 zo~i$6b)Bx^>;7SSPGYH&cmk-??HO{~I;M@;KHBhL_T9+6(OGJ=FXhpsx*$-~9n@9RljTOLpUZ9RF7v&X z1>GP~`u$yyJ4FdYGnxO$iZO3P$d0vHG-VMY`|;c~+P@lJXh#63xd%`)D)@An7PiA@ z$8#QP^J*e*0|qK>wQZBiz?03uH59;ALhE+0-CK+r{axyXx9?x?A-)X3$3m;Ehg_u` z+W7gOMbeK$m{iK2M6M`Ia5-=OmAb}C&nWfsddB-#DN?V_S+*}DM6$#7@>uMS<&rvE zS&_GhEPcYe%aGl?A6#L@^JbPF+Y<&hhlzJEMz4;1W6&ygfvR|b>4$)=`jEplBrF`Z z->Wo$+2O@Sh(=?4UK(wr73wQ_73Q5j{pg0NeBOB4xF%@-J^O?h zK7c^!MlBSKk{()##5LCF`}RCO%8BrKeMZq~fxJYBG}i*odnJuhxKx^e^R{2IFWgwVS4 z3qI7EAfgv6#@`fEKJwBJ%NttROC%Xs=}|qnSgk+hF1BTY2-R$S$SOV`b;^)>fF3?n z{}E}$WxtwH8g)5cK9iA$HDn{^^+K)nb(0}S*Gjfm#2?*ieG__Eq^v`1?) z;Jv5EAHB4WC_I%V#5+-)xPut_O|<^#e%8Mp?^9opU=e|q$Vf&lQg@>_e{&crEt*7; z=11AMHT?(k#LL@!^v9BEXe~2a^F3q8zC16BR6WZ;V%*gUb9p)@59~{zmqM^^=t}#b z_}wtF%Ic%mAu@;?!L8SqflitiE&n5MWm%3@zCdp`RNX0xMtD8w;3{pOyMooDa;9Hj zL^%eASVl5_8G5cF+ph+52nQ0>RzzcZ)_8#=4ly%-MtCbnl}bCLS51E9g#iKvw&v{z zh^qSx)M^H~1zH$6UiULqGMp47nSC~Lhw?ZBCP)I9LEr3)Gi3WGe_Idca4#7v;{A`L z$EonwRthf<_c>kmQ%{hvBR&v*Vx`SIZjc%&Ct<~dZxeTu2LXkW*Jr1o--ZLOWd0xS z)&Hasp;9TSUg}uf^~5gaJ=SnsqAIa{W~au&vBhb6KMU(FFSo~#Y3S1zF7%AVGtwC! zzRa#Dv+-@Hg+td}=f!s%(c0g^u6!>toHqW>_UJ@9)P_FB>ljEVj!inITF}Y&)RdPq z{OXP6H6;r)5+EAalcw8^q&Q;irKfPx=e{dU+jT<*6W)N67lp)YtXs)%j-AGy<3v=ZvY9pC z*OFCM9+Oaj@Gb<049McFrHuftQ$MEGLDV7{!3Q=zP^<`(8Dx%$M^kVq_4H^lk3mag zH~**nfLbFFI{=w7n*v1yrnnmKczBrU5x20;6G6YSX)1_*aPYiIYW->}O2fCd545cv zzhiHE`gf6}J>Uu{_|~YQ*Q{oaacPz9H^V&(c54P8NooOaX9`-&e|kg*^W|2>N7%+L zWf`AwobHLG?LTS-h#2YMk6$KH%U^lxE@UMlsL1!ZAPVWg%(ow60LqfuqT;AT!xfRQ zR&y2SGuP96?;nTQo!hvnRv5iO%}tIQ@px4_9OXUhvyx&V)$WTwl6;eu#sh+JF)~02 z*yk1uWYHB*8zkR6^u`i@pU640|7H4Xyh4!S;{!txrGm&hj%9MZKEW#03lsOT=w zJ}tuIUw~>qrNApRf;I!5M_6Wk3zW%})h=<5>KS=D_I`fwAFUz@f*pY%P=9M~q~ah+ z8$I^qdp%}>G%UzbqKwO>b3&OcmC`fEdl%L0-j)lHdKjvFFksLQ*a<}PTC$i*L3X2s zgMY6%DE!oipC9dhwj2W5J-(b2B|V?Os{KVmUG`M2EYnY#$@!5zpbpF?wkd3u(i?QG zB=TvK&PXq%sOk+sdq*BYP_C_134?4Duo`i0<^9WZH$f#2{xd}df~Dkl^GYO`BO5}U z_TI0L+%NFSAnPfR9a+7vCG}p=I2D@u2ORLK-hI)NhN6b2oEgc3R6zK@hibbSs|dgG|J#8S0<9#Lo9Y zb|Ar-i^@CoZB!Ch<>~d~(u0;Lh+qp(RSSp`T+Xb#|9kNe!6tLVMWB&}1~lM4RHxsb z%kt&-=N($;u=5s{opV$U;C{~gb+g71$YVi8GaEy>!hi~H{cLvc^t1nkJK z^blJ?udLle`)k-nMz|@9Qb*nwif>FLu&AC5E&j&l$3;f5-^^ooz%^82=s|>J_`sJL z1sl`lFrAy$TT|pW?>oeQPQ41y`4#ZY@c#uVUuf$vEs`<^7ok9(inXz-A-}XgQb8?L z?`|*4#>D3BuzC-39aXshL(mh`sSAoLh9YO^wLQ|Zs=QLL>>WFv!@D2Kn%sTV_gJ8` z(OB$=QiKaGCA(_Y$^Q{6V1_NHi?w`9d{M3Lj?FPhgfI1u3_G-JJZ7U_5mW_vD&43CiTVFzgf_p$!Pc*!K~+Ca=&$ zsy$hPrl;%g+ZUDOvoGdI7~uc*}oU4pMNv;=KK5S!HY9R@1g#t0SrB$VqgLO-Rj-fbSpeB z&R0o4G+Mqy;4MM?4VH)$tFnhCYw~!>xi-w*=nS6Vz`rSTudQp4`+udE|MI8dP-s!q zB4d}}Sif>@%-nOG6P6wY0BTU!q7~ZCR=w2btDoYD&9yvklNr9jw)g_A(QFIk@*| z@1O!s%we2$l8LxLbw+tOLD^jg$$=zz2R@x)`UMZ|Z{#ga6Xb}({Y`bo%fFTi$WvNT zjyl*Tba>Zjtcex`7-H)mn^2HNTcGoL7KZ%%71aKYEDDNm>T8ljNoJD)ooObJ0>2Kt zSBnbmsPNYf#y$j2GtbqLv%h-0U6^2EdZJp0?MVSlLw+FBvo(iX-4J$FjaoXWi7`2v z@i__Tzi%l`em-L43`|D=3jCM=69Hyb{v$_4hfcChv!1A^uCA4Y(=vDP;E&h*dQ{2p z4HLFS1=sXsWI}MHJEHpN?T+8@kA5xmdtiipaVftL1-i$f7-+3dMg4qCT6Tj!xH3$& zs6c!0S?k+9p1w~>RNv44(g1THW@C_}Lm<)yb##Mwj*+Q~guk*tI1e@N-W9>4s0hNP z-^)>CGz@pl{etRnj?ey*$sj@PbDeo;+WAmYAe=l1_DSVS6A^r+gc`EO=2qH~z^?Or zVGJ{2v&!``dcWFpOR$;(guF7yOCSksUHL1dth z<759Wi6|`MPl4Lm$Gl@xYcXekDL>V!^@Z5;%J}XyHSa{j#?X=sj2C3ACpkcHo4|oB5=6C&~Tq z?~sb0&4EeoI&l=m572kE>2q_CD_Nk3&X*en3f!0KKQTlyd|$W3Y38+z$AvCp1hbn8 z!r%faGNlBN1|d!@FLIw+K8X3HqL;@UcIlRF=ygA)84!8(78{*35x>i_o4;7>;kkKV zhUts^UO+km@5IZb9O%8|C-Ilydyj0t?Mvw$Q*>rF=csMQnZ29lXVBaZe`qMyiK??$ zGig4VUmX@U;@V~3TVBtw^J&zHyyHT*hmOfl^u?|+pEbZyfNI|kaNiztg4YBnyR)Si zj+s`cKAf~S98N_D`*qFB{8;f9K(*QH&;PPSe`H`q(5%DJ08b^ln(vl$ zWN~sCq@0J#!OLZsg8xPg9$QYx?AgQ8Z_K*esP;6#Yx+YrU0#+~Q^XtxI8#^|tgM#) z4RHA!X2A?e8Y#O5$&1723K>aX)KC>W@LV%sI_qsajRg?vPkTfXBsQWJ=d{jXer-lL?cR0wcg-OQWTOSG42dh9vtWa(E-^IU# zFA1~8?lJK+s~xfHJ1GK=A=V~;3}z^y!}2*o6yv_HuImJ_uB1v4r}M-jug^jPkO-oY zo4vcVpo>E@%g-N-c!JNwy@8#Gj*p3>m?I={{5ZK)Oa8rXIabw|A+o zOs%YOzxJ++_1?Gltq9^w!vICFQS2rKaV;TQfz5f#UXq}Z_Y$#uJ11E_ zry&HyQ=8mykLJJ$J;bw6{Zb_^Sk&00K5ex3M}jM-WZD0Zg{Uj0D?37UqM= zbD*dW5}S;mRgqXh!boD-z=Hd>aJKq&8GGN1ejlhxkjjCt(yh^mu|&!lo?PW#^2FU3 zIwTMTbNLMk^fcY%c2kwL{+=~ar?;$YIa#tBA)L=i`lcLJ0A?2r-{)9x#9@{wCUN%@ zK2OcvGc@=%+ST%>bGai`&Z-m8Vp-tY)WKh@MF}VjA>7$ek&INMd5v>!t3mHY3tbVG zl^$+k%uba7bFPu&Lr`dZwq;rVulPs9$}`9PaL32m+G?EoT%N>LiVcfD;TMB&#^0>1 z%_CC~?4_HAZprDs+Do3Dg0?8s!TI44Sm&OpE-zrMDK)0&;bY#D2}$OWy#viAcR2MB z5RdZU`2-%6<#8k-n`n1$)fr!*iXmYOy8Tcs8y0i&zf~_A$X;83WA6RwTb135)``ZEj38%>Ti1xcb zk0?+yI^pI^dC8VC`PR>*=}s|e95kg0BQe7*d5Dvveu7|3BBW#d+Ge%q6N7{HFqTMlA z3dqRIXw)3?I#1K(4rDY|CWX#D4we}s>7iI@j1IeIy)@vFQRQ|M8qRX~Yy{(jF54KV z$>R+-mBHN0Q2(ZXTx6gz!o@T;KXs(R4tw022!@q=;O|fT>HmOQ1^7NPyMW^ zW~?7QP0e*zmv8vo2L;3wTq|TB-zyqmSF&f_aPr^ET%bP&YV4MlgRtKFfHL3Zsy$Z( zilqLp?RkROECM(~FHAaH_0-8*npt>}){Z;Hk$sbXgphvVv;2K$f|bZRrTzlWpX2&n zq&>J60a?@@@+m~pL*-*}m^<H%4HJOm3UxgM23G_%~+M z#kV-5BI7!IGjh+D$=E}*FPmK41s@Hw7-E>46GaC~^9+Brsti8_Yzb8pI{HdLJFEVr z{$#N&S_%9{(p5~t$-b1n>`@JU9Y!KuxRjTw0w;ghe(b_neAE-K>Owbq9^qB=itGAK ztBn%uWld~}e;xNGymaDC*4NNil|>T?yY~KHc~#HnaqBp7E&xXXz#;&~wm@7(M!WRx zz;uAg@?~Jz8mY=J8}-x5Ca`PWv^snqDY=Cb>)8jlH^XQmePm(t4I1v1mCAy({_L!F z_qyK9d}K}oc1xi$U8G)ArK*lT46A$6`99ntS>#C|QJdyj5oy)gW~*a;#Jv+{YCnmx z-MF}{4&VGI<-tN0Y$01S+&)_@Ii-#s+ZQ=DP^4hQHqe2v0wO8#$?@j-i)EJ*u+0wJo7segRWs4KmmR04>n19=|UQ^Wtt0;9Ua&Sa}F0c zG(f2hCbpMo*=vEHX7*O_@HclAMpd2uK0?qM&;Y$i(2hB__M2eFrk9rVegha5FcG%|_55WW zvKoS;e_Uy;Y+*?Mbogv1M}k#pVBqevYq4Izr>_J=H&sW7Wja)!Q}q2Ku~{dDy&OKu zI}2ae`O6fa@uSUE>Xg1r^GaXV`64QI@df5|5Jf19HL|13#urw$i?`x?{1D9bGT)VX z;exHHG%h31-tGjZBZ%ZLf zSDLhr-v}0`>=8mP!cGa)GNNO{pz(f24Joro!SA$~C8FoE$PpeadD#ly+4>Oh=cS6* z{RX*%pYd`zViSwDe!(I=f)`!H(OmQo^g}3wgoWJ3W$zO=N==+`cELqd>?X#p(U(cL z^AN_HYHE8bmve*=zF=@BgwwQ7e(g-g>d~aSvn_qZ2mZ!cH9I#G1heK=q_*{7z243y zV_yB!J|Aiib1M&;(Qb7?uI$73{1oLqLt9paoSNa)BHU#s>FOoLaxDbBfsuPTB~)@9xDgzOp$?PP%tiAMn}hO}l)wc)1Hrh15!-11OU9ZkDN8b! zW+^ekxtDEzp4}qE&0F$GVBo$J$00nq-3`!5@P?UVk_FUeaM3%M_+*6?yNF1)2p(;U zyknHn@BXyYlY_*oJMZw{RF-OA6w#pyNYjIFzw%qUv~N0ivOY$%fdxf}5hQCsvI7C1 zNg#MSuq7CE8|soA62FD-iLH)W0U@QKhSgE<|BrlwOvqRYVub4xzp9@+i4QY)NwT

    FmT*YNXKkndwvWNJzf{m`faASMwzFp>I0#4$Q75v{q89u~kT?t*uPUrF4&iLz%L*IkYc(yKli4y{~g+>fiVx&KJZI|1^? zO5pcI0qUG4$kCE5J0VEpCC}WR8O_%vKcjmFR!DC${Lzi#_E(?qi}BCxzS0(v8VfDZwgEa`FnVeIL?rJ0QoeEhpe8l^SHyr=?scge`>~yuY0jr$g&Pqc11;E#d&P=1LQewYhSH#sOo2Md1u@5{mg%+ z(t_vpEehXP zf>xtXLNnb4Oa#pFx=KmCJhUySz`SrZoa4-K#&Z2vvU$LVev?vhVr3 zw>oK?H{DA=y{S*D%%{IR0vamxjQZ$Zv50+EXB@_FPxF*?8{BQjp6T}qP*|!l^hV&c zh;WX02gH_=YQ>Wt>HgWo`e;M^3HcB=n5>JjL|Vyn9nu>CsICxG|eV3tZwOG8SD`pl`(qO&hyDP+ay$>}w?O&$_ysA2bi83;*!@jWlTK)JT zGFLQNm^wdF5WH(3bKEB*(Rj%7-~+-f!)gQHgEXt)f9xAeZw)$9MKE z)u_@F>X#pH2I4hTugjrI#I=nz8^_6{#l^dXx2r<$v?aW}Ck}r9&3(diilqB%DBcJJ z8^<{?+2V?=-)^q2>1zTy$hNfKcNe(EW5m~Z6?lR=3V;c)!Y~DK`wV4p8j>?y48HCC z&))cX3Th+vh(eyw={tr6M@;*8Y8pR#zU3BH1cixYB3NA1^DN z2|IV_uhDBR_g7S-Q8JJLz7+_7I&Z73@WWje%8G#Q1iVs-fBX-W2f@mOr~c>EN~ZXWB%ZE;QkkAe4v;Xx|7eU9qUdT4d`sq-uZLc zm3!U&tV%%Yl;3jt>QR)L1AH}N$f(M{l8qKf7#J!VCf8BpR8I6P?_8Vi8-0sgJ5eSv z{{&21z-P{MqM|1ne^0&Yv8&(t0Pw)lfME;iCBijm-|1ohUxDJ_I|qu`!(gvYZm;!Vgz64 zTB}o&^ivqchL>gYHhMu=mL9c@2Y!%}7mQ!|Dy|&8pW;CHhw5LXB}po)l%OG+%2%0Q zKFm^-Ms3P$gsj(e(OS9sQfT31z%$8hM&&A%kr$Zk#n5DUGip6_6)}>s=0rH575v(t zqkpP>c#w!Ri za}p?)#&0D&c~0_KDSVZCbR)C=j)|Gy1S(W6eOe@0ZD138|m&wx>LFvq`ON> zrMp{7>5zPu-R1NBJ^#zgyZ1eJ;>?*dPnMNUCv_;qvCO7A4G*hIcpU!alaV3obC}ix z60N{Af+Uo`8==;7)_8wjPuGTu@kMuCg7x<5m^!Bg{w5Nk5a)mRs%RjsVXof^ti9of z{LO&4kqBYYOpm_ko%@(Eh8Oo;{H&Ll$IQXjZ5CDruFFRRZ>V!(Y8D?1(pzGafmU?% z*aPO?$|1qZ*Dud<`ombaJ9n?aeFy(Xkb_RGzgje21ghJOx8foZYt^h&O)P*NGy;zP z=SGALrR-6cVug#`&ei7O2}m+Ju(7$4qC2yS(!u^?UXuh~;gSYsrTBJ!{vh_13Bd6b z>P|CpF2!IIqqgF;#L&B%pIj(qrf1A0QfT^h`8{hAg))B6?J zB>2pMtzs0K79iXW{Dq5@ohOKe(2)V(fO|c)Xs(cpV(_%jCWa>9 zgxh(m^ne8Rr-e|o0H_|&rIw32Jr zy)&Bvks;oukesq8ZVuLRg@Gp z%q2?Y#!ICVng=L{7ZKl;X(BEQkluqIyf9ysaVB^x@EX{?*4(Ae0b1JpObQ z-=B^#mqO-PqqmdeK@Rmc3bA`8!e9Yw^*KwB0YC?W3;>pGS0HlHA{3>_gp6Oq$m9~I zWF8zG54nqkM?OcDTSd)v;eBbW|C^r+sfe!eC4>9;yZ;oNW)0LW%&7flw76j!4cX_3 zBpus6>cRwWrCH-1ATwD%@iphtJzGc@zrX#ZxaK|~p&*Pn$ofU|hZ|7oVdUwgeNQL7 zo|i}aIo?<&zM|c3?pe7`6?G+1@|=URKp}#)7-H!EUiVn)F?h*%{hnA;*DK{w_>&DX zuur`YhrsrQ^;+v6d9yFfH?e@+gJ+6AuQTSRdoOLbf~!Wm(|iMo37V9wFx8MAH3D_7 zjv!(%09I(2pTk^&Rf;mgJ0K$VXitZmf>Z~ha)2y`7xK-Ymfatrqq zHNe;04LUsHC!ETEo0vNybH~W@W+Rh#*pwX5&xAnW-${a84*9J^FO6^Fd+dqIdd#ym z*8{!!!!l3}KaSND{sV*JL4o*^t=z1~O4|ww5mIkeYOELg8lEz#x%_Z=N%AW!i&%!y znNU?QNPL>0!(9CnP=VJqo&rV=LHqAJD%@|^%kDe2?}@PyYB_DLf z22W|@-JwGC-tVN#TvqO%UxGL%1V+6$EWmb||M5i=wUju@{Rd21U*nkS+Az1e^)QU=C(xV#-#0q4T3VpzD}puh zCS!r9Q(&4;+{WCt3e@NP_~beWz`>vYVedgesAyJLz9aCK<>+hwFGrBt-krir{KM*C zaSzmb+*V2v4IN1lM^DIA*r=keRol67H;M~=j(~Ptk8&~lJNH_kW_WYQHID+?5uU<# zrjPO^8^*2mor9f%8kY8es-xzUX(D2ZI&5Sg0CcRiyYn&M73(-spw5G@jNI*x4>4I!9#0vtbm0pq=Dji{ zQE5{S^AwMY{@gy*2PYhN-3Q?f&(Wfq03IY)Q zOi-QkWNTGI29)&b%ck;cNq|X&{vaxDe#l!BoXeY6#JqbjrMmW#R$gBH$qaU=AGfDBL2$>!QuT1u61TICF#&%-Pzf8aBHqQJlFu4fkxk zyYBJFPO&F$L`XkGmfR&6xQ*+CZqu7_laPWA8>_?_vDqQ8xAKqCK0LdT$j(0Rp?Twc2e*JNIw;oIAS z=7y2=J9RwF|mD?;4}J9|X}k1lim^>whb_XF*2 zxgPSc*62j#VcXsiToi2m5C`0H4)^GsWXz9tzq+c9P@lTnfaJpk`qCitM3uU+M=nAX1MIiC2`Y}E4=39_z>gNK0mSkBanw{&$ z>N5;D3F}M3Ok7VF9^L+;>iA2webw_~35e`!0L>QzY`##hSga}f3kZumEnh0zEQYxq z(}O#9yUF>NRtoOfH?N5azQ3w$mOvOqoC726k4BDA!CEWC54y1of4+NT{`(=8)a?9Q zU+Qov2c>(f6DV@0J~VT-7cMd@D7_kh)F!?)F>CvxBA|4J{-CP zGhOnP^gC~g2b0M#x33(A@Y5hFgSYwLv~4(NLDv;cHaOy%gn|l|?RZG>*d@7rei>v- zZ@Af_xZ5v%H6W77`0iant_2HaXY^OHKS2HFnda~)mrmD75_h+1>h`hAk-de=X`u-r zkqYu3euo&lPf0V-%Hly~#^fOywKSOult@p<1~MC5;)a?)85jVDulQTTQBnMTt#W^8 z)%VbswM)y--1TSTga4+wm>N|}UClA*~N^9~zGQjZ#u(+Gei&*J0 zMYro(_QFlH$tJ_u;NI)8(<94fL|?w?gLrBM&`m@&Da7!3eJLV~Ch(kZNqd99#oq(T zSAf7h@armozivZ6`Fgzu=l#_$jhf>^Exsvi0l8<&B`_X>)q@5+*TdwLmGa$sX3hqg zDo>7=t_(p@S#GbV+>Cd<+xonHVOhR4z+E}&8r);Z&T^tSCAlK+`j=;<;x~ImNAG?; z5#%)g;OHZ-*Z(PX8sS)eXDVFw#67>jU^9ySmuc)}Ph3J+q_#w0 z0n#RMXZrmop89NCpo0C8OZCG`aN%!*Thwu&aLk|O%Gk1gp6dMK zW#_x17w_WwEnNP6SpDTk|Xvu%2 z>Y`78OC1~8_g|qY49;SzQOP+!QmPmoU=`yRrNz^c&aypiGXWvBNJ6$?#h05KGd>i| zEe0L`CU{>LD`&htdR=hFMOu-zS|-`rT0|u`Ey&ycsuFIi9*p_yFv{^7qS~|cHeg;S zGHK6*^4e#p7n&zjY3XqwR25VMH?N@3-+oS*hDr{2J^ubAOygGg^ebHT1~kJ9t|5A> z-ga*=U`YW!gB(k&5|&dU**nSE-6=+1|4Iy*PoOg>bk+H2(_>-hjs1$mzvn@p_OwfZ zXe`4P$FHR>NQvIL-iJ7jB>yhvYSDeoX2gnt*CBsa#;azC*HfG*}I$i-y8Dx6`MJ3=b}YI=WOROYXgtl$OrJQ575 zFQDzQd2rb>?l#@~gbsJ2c7f*A9~cEQ)`@PWkQE(vur{`)6XV8JK7_fFKp}%PuT%PV zs`>z15c=AMmsz)Q+=FfdrLt{%$^9Q;B8;_vwboWejgB5AwXrqC=Vt@$i#T8Y?Fdjj z6#ATwt4PF;XFBB{OK_~=SeMon(&@NiTsWZBtEJN4#R&)qALdVCVQp%vZn(dHIPzSR z!V~FKWE8u=`jeDj2=Fxo-tSZK;`a+|kPoZl9j_#b^TNJzv5EMb%WSK+gUfhiLzDWS zMM0GlN0v-X!`Vn9%2y!}kK}8?-;5&Dpki!JzT6|><9FN95ic!=z&S1J9OklX*W@g7n^KU_fyW#Tu|B98BIm?Uh!S}4a6;`0^MQ|8a(K&!p2)R8TP6E za@{|%n$42=jxDr2`}|hz&0yQ&2u3F?YeO$zVV}G4nx4mCYF}Q27HG`LeH_?>LS#9Q z#s3&8(Px8F?m4#b)ovXhYYsnpUa^=@_Wa(D?F*2g`y}K7bj9hQfG>uzS`=mcjS|aP zIp{qsnpPOIa4VR6(}6@KochsTwX35{vNHh{Hk2^g0s>G8vH6ou&hdN>JS^@TlW%ZK zl)X-8J&(=X3c8R}e?&r}20;BJu1ippE91{w#5FL5#WsA6d2Z(^3|+LOG3w(#Dr7WOCIg>y<^!+2^Kk@qQ=W6c ze8PmFBke$YifAL{e=Wage^6|DDq#%b!ZgS&mf0Ap10H{Ox0Tm^X}kSf!rK0#aK#XN zf-H4%Iy}v0#;?>Qf&e)9{Z#Nnje<B9LQDWe-9N6C!it$M#Nzh37;J`$zs#3z5yH9C#g;`ow9?D%o@ z8YkN*`R9BzJ7g=#V_lmgof+|zM%QvqLyi`7O7|aB647-Gj8>V6Iz1CzAe_JigM5lT z_HR?oC^BUANR^3zyiGo~Jm7*sh_#{1+l%6G z(9}cof2Gb-%Ha!6IVPR3MWr;*_?!`t`D^hB zuioOilt2_geY=}9P6LyNS?YR2$^(%$eL!A>l2j1qD)pXR)k|tS@5#lR-rJh!qimwC zj>*Sfxdy0S516OlyRqvi}Z%s^#7MGae*1or?MRASVyfMrRpA%DS~D^MFwQxeK~_F zf!PZWbXaT$+X!~9x$3Sl;$5?loSe{$$6^XPnHpW-5{Zl*UFB`yXHGkEhnH8rc-D>Z zT(UriFV^31T)LL%+n~!c`_GAkjNLshj4l3$uqw^0Z(r!>Q-=g-aS=d^gD>ew_#eOn z1!nzsw_b(!5Z(Pb2spDWT}|<_(MU@Nvi>zl5QG3iRV46VT~5s$2Ijopamcu0E%uZw zFO!5b>15c(+@ib(Kr0WcZTonCsL{Id@$#f+G`!slK#OPnbt&nG_4w~j><;q3$ARo! z!Mw}~?{%r!n5`sR;R5I9KUYRbkW@VL$?+C|a^PD3Q08|WhI+SeWJ+UD!gdioO~?LQ zbpd+mK#NfYIFq18VP7T^-b3~K;_=&$w@rr^G=mB)s1Wvf=}~bTnyZ?j+!qM1n7qBN zz?tP*=UpY1p|4)Q;w?u*&^RZTj@r~M+zO${J!7j6x~=5{`kL+`b&u2h-*W|0ZJY1G zY1c+vl1Gpj1rTWY3BXJ($v(zpKQwrcEcn{cLssgtBHk0>?6Iu*BmVwd6QGoWnAFOR!_SBX4Y|=+M-`SuG0~5CUx*M^Y@55yzD{jTJR$VJ z^5E0c3toF4rAMI4B7rG!==8Gm+dmHW>Ch83$6aYrTM@^l44 z33J>XMpt?lt!L;HT1!k{*O0KQ_a*)Jo1D?4q zrZ?Mmr@0ICcm@6q48<>ggqUUdlUa6+M&jzoai`w=nT|%(`~j;XOXlMaVhP@nxS(nE z=){@*eIKl4g{~+@$f=7Bf$ZcF$W1Royltj$5f!Z4bUz-I$+C(81vH2qzo z=>VHSKtr6q70Gs|1ZpAz^IY)k4_U#%g9PdseA9Y?)t`G3__qDa$}zBLJv85Osx2ww z7Db8Q*U6?2uGE6XYt7eADrlWy%-9jpXoWBsLNT1lzb{0}dKy*DcG;r%Rt;a1p=EOk z;~XxQ~o}KOkY?BFSKq8mOhO6DMw6y8JEO1jDF$7EhN5D~wA)rocLLX;f(jodt0qnQkDbzT*|Qe9ceYkP^LKz|QSoFJRZ5Y2V%@G;#e&2HYWvdUvw~6t#*k)hkhZR>0L8FRT{oNP#ru5vu9T!AaNO(?@5$?@v@jw)#CG$ z;4?4^tdSRCR6DN&^jIm!&-^_qDt=s}NE>6c=myG4k9{^ITLcmoS{-A9wv(a=O1P2T z^J*Of)j2+(oK8Mqc?v7bnp;;uRONw>ULO>;CG9W_e#7KBV-0T`odZ6=?@6b@FaNK- z1~m^#JE2wHqobzAdrt5WK8`T>agwWWErEHOD;<1fc8aom~HA&k2SCw~hY1@x4JzOMOX!XK>+s!K=S^JQ-66WOR|X_U}0XP_Msj zC;m&W7;m_#SX!|akhy`^Cg0_<$D7%NhGH>DHr#&_&yvEM( zovKI+=;CLs{)TXTWNWC8W$=>y#pH2#=hhNS#`64RJ7PpcRBmu-`@!$K|25nepT5WS zzXI*b)e)SpQ-a>)oO-G7u=et>|EG=h6XZ*y9mIz2{=j}4P_H^TPp@+-WzaSR%M*WV zk`v2x;opdJNHvPr$eGez=q?6Zn2;}^z{LyW47q!9w=8k+Yn$FJOFUQepAS>z6SnzZ zRn?sV&;XQNBHlr(KSWZ0ZHY-dRteqYtX^92D8M(W67DW)9YRWBNziIq;n{r$Nqhl) z+=w?Tn9Iz>q=eB|V^2{<58;ifb7f-7$l5S09+m$UU9LcB=kp<$U@6VkX{DPgazqr* z$ELr_2<^b^)H1(%a!VEav~1^A`3>!} z=RTKp1U~;Fn8d#DJ)e+tku$~j?}A+p_}}q-|KvpXrH;Bn=i!(d81`oQa$$5O9Np!{I z0=~so1+$xDtk%#s;eErYWtcC$&`rUG(U#1D`?x+ZHCV;(wbG6T(NjM##omnx!DC`5 zjqDZfP9!AGczV>w zjUj#b0aK_wWc@c6m&y#DJHK7xTDHpUWFHu+n*Je=wHxryLfuWuq|OF8Qco9z{F-w# zqoP3VC8417_&J%cNbs+KjVcdv4~|dwkWB}@o}$k2(5QMR=H@N2%?eyOb?|@4AYl2^ ztT20+es+6QdUhtX_?+;B<-ZX#5G&LHW(!?bpr6B?9M;{1*68QdE}`OL%AeUUZ5|6I zvSG2jo4yGRyXe=rh}LNqzzSNo7YF_v;8GllhpSNbM@xP^9mI0f>NyRo_&RsPWC?mX z&&SPVf1z#6uE!bUZ{Pi_L*cG|_8=O!)^! zRD{nxjekW7A-Uid_|@L{9Ot{{z+%@RF?=!KYIDhW7hDK_wNLj&0h+Trq{uj#G06~s zcO+~sudg9(VolHkh0){M^9sR*bkDx^-Mi*mn)|S1fbaTqU!&EZ5?}= zPw{1m2!r37tif=1=0%p%e`f$#MDdSee=xY0EcpKzNC>Hq58h zCrqE~gcZGGSalnfi;sNZ@)rPl3U@J7(A5XSW5Yo=3369ND(Rv@%OE;PSG1E~6Jm2< zdLIY6b$A!Hx=BZ*{S%)^l+=O)#o^7odb6;;w#2QOwQB;*V~H3@~#IRWlD zWBqnN3@N_DVtrhzr=(jx<`H{YKR?N*Lne|WdFcsB)VjcPkAw2MuZEbSJuyG8^f4A^ z#Ah7sfm;7v@)3RCYyJ)3WIq%gNL)9&U2YdpE<;Ldf@Z$xN7=V$i>& zxa2n%WJY*v=p+d20auqQb?)m~EqK0VF6e2iS)YFuuA6C`8&eORj;`H*QUNKWfm;9G zpwF=@{I=Q3xP}n0UEDe#8J9c^AD#1mK=U!M3@`iZEDBQch@Z$yQ|m4~XFNEBoB5#3 ze5_`qG`>^nd%_P*(mBz6zI=w)`eopx^75bNab4J`{>@)M>NBK@QTd{c3Own*MH$C$ zU!WXI-m&_+KX~1QMgD?imu2K_)~ZEEJIS%p!epVL4M!F_JXPBSdJb?Rcn3-;GQG0z z@(`Ne5v!|A+^elJjvbC?fy7Y{lRqvepe^2WtVJwGBVdVo2@S>ygZx8&=| zBhDc2JxYXRwg3<%F-A*K#a+nvG9J;MjB^7vtlXwy7&KEC(riF0s^Grr!-^a4GlXLv z8r&iZUPCJMsLDuSV%DCKr4ap&F>&aG*jlZZqnMPmC0dSu z@<2`L0lMbQT>z{?1mcR^xRO?dkjN-`a%I#voX=Qa@o!*0Rn@A5Up6g4Xg3(3GmvNZ zew~!Eq)_n+DjnabgjtIgM)MaMglPXb`gZic=Pv1PMWxLv4XEVjQX6F}@Ml#vNl z(W1UwNd&e!!2EL-(BPnVx=d$F_2&DSxjwvj#Ca3US-g#2P$|Bvbe|jRmAMwc{;4jS zuAFZ3r*9|(IlcWp?bVG3Tc5y`XFZ#RdCe}Hg?FIvgV*mh97%rKG%;|+#<#uTO7q(D z@|g1RV8x$wf-+&#*n|!{V?Dp^_jWxqA+!sK=*gAwa@^9x_piJCgHC!1F8ue!>*-Ht z$Sz`I9@QVCbLw!9>EWf%yHima*Lhw|TcGgGN&WRvu_ua3XRbE+w@rr3);za;o(4mc zjHG{7w?Kimi3=@40F->TKa|u06k@adebjvYi?hSo+&B7DR&}h9hVe`AK$1~v+9sK2 zaZ-(<6J|UP#&Q}Fb@Bf~0Kg7ZVEa~_fBTIStV*7-;3%4jkkDXU-}Ha*$smwN2y4+hC*J1`-he%W z&aZoo{ng^nO+|`zPWIW?Ds11StKs7aD&9`rNA+%32GmI|z7OEOxlcsVBZs=FFj#L< zvqVWup2Pp0Mj%8^^|SaJkxx4TQ}Q%TIWQdt_lsS@$>Y1&nWzt9sGQPdeY;DDTM1)5oPXtv6_e&j>*b8%+&7FY8P)uJVRv>EUT@(NztFuEmY9gq zsqys+%e5VCH1IOfU7S1SssV1xVjm~3#Zenu^QXt{@Ox)~oN%lFjn%uc^J#ffm0XM) z$U*`gb_;aa4Sg(Hubr(a10-qXY&a2fE#ou#|3d&215bS!u}sUQ*c{lIpIr}=-psKE z@$8!XH?+eH^tQ@iZ#(HX*_ScJ1;agMc$O2TB0a0jWBcT7G5Th+)I2u356T|3v82UN zMR6W}zXUIo13$ambfAFPUr0e|UxFBo+sCez4%WFo_X^ zym8wtUw6wui}S#S8f|NvKoSQ{6^e8PWaxvKXe>|Mc+=Hb&^{0#D9!{5MA2UioP(&N zh7Y~PUck5`Pd8{0j_>|&wF3}j`3nN3&(ddmG*ne&?DG=|NNBrIR)v%pz^%}9oTI;* z(h(e0YmX=5oxQ{g1KAb8{4|DX5U72c9YE5t;j^up+!HP)Imli}nyX-YM5jh@tt}=q zEBK3t+!uh|MfciOFTz2@@FAVY+cbnx^XE*W-%Jti_zA@0m^gdsZp1XAF4M7SDx^M= zq+ytS1F1bKo;*tSz(}y{fptU0#Xsm$t;`vfQX8*8@EP6~8csm_skAT{@^-QbT~M6l zdO|j+T@T36T{KJa>{uk<{W%v29H?MSr9YS|p;vcV^9+0!U<`e2YU&>B=BB5qW?)ZF zt~5a1AL(bPDVAyp9lLGkIX;30DX_ug@aRWpsSedwKC0X*dtX=;Xf7A7&cO{@tzEhx zj)0>cIuiynjXZUYjL}6L2sR^xdKr^I3|w}=Ifkf}6_JC2dwxLNcwQ?9O{-8H9Wcr5 z>mxtsl97T?okzt(ebfA~?E{BiI1J@>#N0QXt(8m;dkLn6L63m&*nFZdZMz%?v5RwC z_Wq&9@HBQW#K2+|Z5cA(pk-|CCNsvcq*4#MKCCo7Yq0zFT7NV?O1Cts_qlyt@8is4 zg*PAU&@pBDh4(v2T4|nu??bJ35c4dR&ZM5lpSrZDbt=JD#6840)(6&BZxtTiB@Zx= zUj_6Noa$3CEI=KOJBx-LK4`-cdM!WKsX)qmTtU%!QIs=$8=PbNAq$7>;1Lscn-4mZ==_Z?wj{O5%MS5X<%myw7(iwwz1WBNKlwo4&Z<5 zTpvJZ9vg}UE(?{M5@od3ln^fj^(ys*<8WgU07j51mr<6J$MnOeHy`YcdT83PPNvo} zy7?v3bo;zWKQH1m!U5HfEXW7-^04&&jj}3xak{Q6L@_Iw~*s;`N+lsUBk&6=nEtr$Taj=yGL( zWArqn>-~~x2Z`A`oAMA1YE_n5Lkw zQRP|*4c?$gX8jxnw5S-^OKk!5nuz>;M$A$Wi-NAd>C-l#wVBj))c-Ff$aVl#(L?9| z4Et)0tEL+|J_L<-4IlEI)vm!NKV6 zt_Rv%nGCm(wL$gB6)m^O&%k==c@za0&GSHSPr@q|^Ai4U0A%$To*<$VOaLE@%7kaYA!r3M7XabA)4gC))&Y)4waEtSZ>VU zdTE>kN+-WB`1Ts>Dm{7fV;D0G`S`V-FfRQ>gai`~=yLJ4^k=?$?ayVHS$3|I!Ef}= z8f5!3-ujlBzw`yfihq-=z|2dm0=vecK3-Jq+_O^!{rfJPzGFMYZ{O6WXc_%=uIp3i z=Y9uCoRh)f1Q1_2A7o+T|EA`_0f$ZQtUwhOH0pA^$!9PEwe2p?aZ}a%_d`$gD=z8| zaN;Z^a5v3oiL#T;pP0a7CifQi>kGsLJCrK|yEOEuG!*?f#ptd21!3S^|lSM2w|L(`>(7)3P)%w~{txH&KFmeATLrK;` zoR*{ABN=PcY{DEq2$lkJ1|L4blK~}G({Lb7c|_SY6h~>DbBivBpzFH-(jDxG zd_m8|dx}>lGVU&LCf%?fTl)L&oWPX&HcJ!WZD*|&B&Ve*(QL~ zKyVi%>m2iYHK`@AP+LJLOkBHYWXKxC=GVw<-=Y8y%wFG(y601m-~3gg;JIYMPW@`OiTDnNESMQ5tfv%J6^`4}65U)67M-c4T4>5YVyW`enG^mfG z=&qYIGg#KB)8Xn#>RCy(iU4Fd3g1iyNmZluQVwzr*bm)NaDRJ5+2u0crhA8x&}E?L zg#CrYRFGg$RV}vvArG%s4c#!kRJn)oQO&Zz0x0c8@7-NPeoyY?dOx$w3gbl#fcri0 zylJ4R0_}>0O)Ji2WI>ed4sX|>k1io+WS|@)qSac;M(iHg!%TW3N?WCzV9e)#C#FJ5 zG$uoz{^jOP0z!|a$7ZKa3xrpQ0lo>53mHn9<-2dz4c=7Hcth^k%_Tjcn~3@G8b9mR zS+#wVbGDq(cbOA%*p((o@2_C(ov%&5cjZ^cmqp3LVG9G%(kP1?akWA)3@>v%Jih}T zcwbP6(7vG(3i@T-$6fIY57j<>Q**nIbz%(v<^^kQbrJU8@M0 znHA@)-olCYtxFz*7jYkI_NwzrinF4)){Sv)np=A6ih@fzj#z=NomrW@hhXPe+0*Vd zV8%WO_A8ajVJ{>AffWW$SqKs}w)SRmqNbpX9jIgxn9aJ!K>rGxP(~_+<*vRH=~>B# ziFsk*;kN-pucEd_SuF>VTVIBhHoH9cz9viWzqlJRsHIvM^yt%^fZYA#Z8zmXycC^u z%|#+{37Pn)Km@3n7+}E!8GHllbJQHk-IEUTq3L?t?7bjY2-8(x5e0M5ve-f}_bVR6 zc1<5~g#JEOZuDB@Lfl&yNiTi8jQMfA_6tLOo4^ZLjE_x=g6WODuM5${k+Ly?95nm$ z3q3=>)Lnc&{x}u~x?I1hPoG6K_ha@DGzdDXT&lsNy}-xp2>v4Ky$#;K;7OJ>yZJOx z;jdz1XbB2IUnDfU(Qif|20o7zD^NEBja@HHga-1Mv#56I?#lf0ds;QSQD*+iozN7< zEy>=)D`wY!q&_*rg*zU7=`e)axApl%_V{*Q%h*@6=Uc?m0*pr2mChtzc2@)hpV$I@ zk&KbK-wsXFaSDuxyM0^0ry9DGxBt8y2B@k6PMf@aC${jz0m$hw+{(I-@?XS0m2HC4 z48WTziCksvb`&$K)?)H_Pwg7|XNHNE(xPsX*}NZ1v+}I>XaF8|NmQyhc0ETE-)DP` zT9iu|jBFLX(L@x7WwGnfhChn8+{?S2E~gw`mcHm@(2l)}lEAbH0zI^X5D@z5BoszV z6nW@>1*oM$y2!HpXVqW?T zykY2lRi-mnd$R-v^}Q@=#M5^C7$7jV#$0Fc<&Ck@OKap&lwhcq_eFVc?><4x+?3CA2V}dPl1)E?*q>Cpd9`1n^Mbx*Dp_)6^*J+!9*n zMuiqKW+hiH5A&{;Bab8)Ne!qVdZxhrL{y9d$JA2i3b#@Jfx_I6YT67VY&BXomAN2* z()~9^Umq0?>5qRduDwY82aHY)wvchCj^Xe?;x==%3D)kAOTLX_whvRl5^mHf932Pd zbu#e`?C~m;NPEVZgx-(%0co9K=~`RZk43ZGtZCeW#{jQyLLfme6e=>Q z_*O<0k#{t_-1*P83Ur1E?1nb14fRu^6#ZXzv8pX4jz8?cXAtsHR9djeyjk0C_2Rao zvC_E}D)f<0@n6jHto8he)gp?rrpws6DPZ-pUfin)CchB{(~Vwj@e{D9&Vl+E9Nxu5 z4Jk&z8)t=UQvSL#5Sr7KS+Vp)EqvXip)0rqy{ZtAL8kt=nTE46XfQl{_D zp=6+$thkrx6?=6ZKCa~93eK_sZBIekohKq)@DEe0#@*gfN;3lRXDz1`bV+t=1rd>$=;AGfi) z&r!-Q>KV(A6QEh;sx{501-Q3>UhrD{`bPDQO$Xy>{6by!5v~+)>N$Hx!XN4qI zYPh}~W2=Z?Ht?@)bR7r?u0DMIFLUfZ1!Zb2`960O43R)ujZE)cAj=(3Y9{sn>Fd4( zy@rf1nlXGSHD)4Y3gtti=(mzvK0F{u*Wdpt3kxTS2Bz~+;LLi|Z*c^wH`EZu_-S2m+55GFfos`GVfoB;tD3TOhg}?F)~BE`943CyTkq{svfbfKvm%v#0yIw!2N3U<&q^2}}LZ z|Du;)cJfQt|K+8mf<2gMIW^;_*#*^NYa4g87so7bX`$PnyvJ?|&KT}y$2|L1&41;wYy)SPgP(IkpxeyoU01-v3~(Pv{O{{ zFwFinl>8W|Z85Rh`OgPEghYtNG%NzP)c#|BEd;sS0f9x1X4%Hox-0Lk(di^Mu}c3) zFlog7xB3M%Lsedo> zKDW@L0ALPZwg2c%_tmq(xR1~wKe zZ!AXfjo<+XnUlWmuW%s7%OhsJHqb^nto>9O%n4nDNOiI+4!|ric>up}0BGsh*6v1W zz}7ITsewKBu=p5Itv~Y%C;=X9{@UI7KFb>qxmR?(AK^rSp3(;>9s2eO2RmwMcJ4tx zRjp8^T|)mLqS87j)2w6=H5a9T5vOSt^9|~5aZSJUB|&ahI-magwD!Cokx z2%pu)eusAUQq_OJQdCZHq8PyorA7LVndcde>jK>cEQ8Uyk6V9U>zy21M*Z)lheWs`$3@x9#xkb0x^-E-NW7%ZO5$oa?2m1!v4~_c=Ks zAoA=}g0)se&z`pW?=Bca)evfCK(x2%wH+oHz(q`TscrYyWu#w}nF?VPcZk^kLkad_ zWAf&AvbCEIWUMdDIh3)j>}i-N_)B)1knVtcSxehilYtxMNNh7z_g0$@a)r^MPg&Gy z`Ryez_~hINu_u+!*lPX$YfH_6m+Qq*+!Qi%a?RY;%SxpBtliwz0{gm8Jx5blH9i;K zof+3bjnrDtfB~*>5if9F;S2a#9{(X(^z_Bw%7lLw`;tmYT z-?+}HWKJA#fzuBQ*~WqA&r88P^UGPV?wH@iPg1i8sj5{>N#He4EjH*J<~6JM(uWQM za~X$5R9#03RVM7g@{B-OPRsHANp{?FDJI?&7U{itVu|lR{U8eZ=tVg}jNPtR+lrcxR4xn1B2+`O{~Jfd z04oY5H~$G-?&W9?Hx*=tGiO4~5sq2{m+ZmOO+wxNvC>QvU83?<_3!UYZJ&inVon9K z#(Xb6cp5GyP;jxLiB1%(XBDAFZFC0%ys88$5?RJy6#gqqtI1UODN;nq-yRg~uIl`W%`EbAjRbv0WN(U=l9KVMAy zxU7mW$*^@X0NWT(NlLaSC`Ht_R5Z_C94L&WL>Nh4B^M>D#c=^OG05k&>EU&A2VN4o zRlRnh6ks6A*nI|a8tWrs>Ixo6al#A!iloQ~>nLWe>|_Z1xO-0*$MU)E0dNTw1t)D| zw=Svc$HwHooYkj7=RWO*IH4>=dmwkTZ?py>l7r50uHfg$b4bPNV*)?^RZ0CVrG(!| z@$=477I!y&WH!F_@joI({+PjN-CZ`@FUdcOD{~RAyR&vcAyQC(a~nnE(Ns?LvEL@; zOD9l9Dz9Y7WS2V3&aJjrMu6mGzTlsmQuU+g<8kxkHXi6FFcP^tM8XRF)aOp&cR!C5OMOyxk$0u4wsh8x3&O7yPzrqWkLZ`s1?2Ch$4R zn=WaEIN7>DZ)L1{iZK9#dwd1(#1(*Cc#~lMc z#wYi|u~oX(TG;_DsLHQKNd)<9MxdG_I)}!(b(Z;>p@hboSx7$nlVJ1gGpff?AN}Y=1Dd-S7aHGLXaxXq5*4a8ua&J2lsH3XHHqLX;=w! zd<~OQX%M zHA#QS{#H?GpsEp|5KDpTH0pIjjI(8$qzWl{5kH21W%;R%9FU^g6rbFW>8r61^cwIh}rKIqBa9Dk+2^6q3I4=s27$SA#sva*Zm#j+u zZa6uC{VNpsq|k$sR6**RJFR4$2wB@PRNb^8m;X@>p5S4>JCGk9#_KxO-q2LzAnOc{ zZV9Vhv#H1jHZ*boW1p&Qb=$Io--AO zoS|Yj!0I7DmoUl$^VQ+U64@`q^T1f}JcH5&x>Yh-=gE$ZngYV`%Y&EUE8UqI=cyol zo%5=J{BUDx8Iu6nhLF^DisTQCCI28mV79`;7xU5kt8eX-R_1?Scv+^@n6GjcpJ2+p z=;xYCvjHwNC^nGgoH(jUpL)yIm@K};+0eGO+d=>GW0@n-D7PwR0SFO!QmM%XyI7Lp z^JL%M$-c4qffTL%dtO^g^KYQ6Vc?~=>qw5IC_WVGAC}qWNEchbU(ZGOo5BdQU*WtH zR@Vlu18q0K@Tx&|i#vj4x-@qxYM!v+fSXlSM0DTOus$Z_%-1*UNuLxK;;X{G7n5}dikVd+@B_yRwkWP6I_c{Ka|ND_I zT>I>M_RN|!Giy#_AVeAR77o5t=h_A)X@>rc)PY+3jQuE-C`($17}_K#bGP%knup8Q-g4xc2UBiN$|X6}rr}>8)L_H-@B4 zVj!Y*PyM-rn;}Mt*CQ1T9!6PSqz}1ie>W{L`mEH_!2*4!%jo{7h62H^h-KlXm2%>H zsSkl%7YbOTX@iu5c9GZMGdxb$>;R^j5v$sx`dr!WZ4LF)oiOiu{`jc01z=c&N;w0j#Hh61!m*v?0M)iCQwhYL4kP+rX@(&UlzJI)SYTpXCT~VN|YovJ)3IRBgc9ZL_(E{{#=zR57E;afvu(5Q!&KM%Hg@bZ6z zE3o90s_2ZB;)$FgqQ}wUncQ>M3~Uwfg99Wm6JkA9w(H*n_-%4mMx)raRqN}>Kr>iT z-uFrJ26vyIuPSn|eS<+ytWJL;ePErKXN5dVGU#^)Ztg^8#%E1f8?VClcFSzieT%1e z%eJXF`QGD0=7hM8irzf*dHe-@TBp8yFEb3fr~|@n@65qD5q_-{~Afd3#RVCSYn(~)TIcoQ>xr*QnHb-y^Zi| zAJtuY%F4l4eK{QtyE%b;zw6_C>TloKIDXoAG61CunI}acco5K1j%9{k6=wbNx1MkK zgv%R0Wpq#^X%PSk1sim?=?d~MWj-nB$i|?QA#QQ({ey%@kw`WC?xktvL`@{OWi!DN zB@zUMeYhj(J6#6!0y;7v*!I1CxEd+z(=*%aBFc)wmf42Y#%0^fU;RQpIzRk#d!be8 zJ0LH_Qi|C7G}IjqcPH~l=p(rhjZN!B8^E4E8%n*pc*V%J#~}0;jg0R!E^ayDUzU@^ z>YXgMVoCjh(nOCz(RQ&f8h5)Q=$V1oQywnk&WcpfUzpH2t#o1g6^4B)ze6 z5-@z@`e38vrTxdA&cnfb%O#I?q`O@e$ zQ~;1b83q{*qW*(92ZK$2>K&4UcvkAXpD|={viV;>KfbST`=h0VIQW!0T#?YaeE~^r zH)OoexczPnDK4e|9tn9!*MlM9C8+8=qm^v;0-1+fj_N=(6L| zlmh4>C6U#b(7c3xBqVU4UkjDu=1p;u2=rQ!sQ4(%j zEBLy@#-&lW4_a-f-~W#zPy_kF0X}tyt#}XvcT;jPal>a8@l7E~pENcwU4OYSs_x*Ui6S)Lx?L#DS*jHP2M?H3z8$;NFeMS(JZ!ZE^a%LkFB7 z24q~Fp27K36}Q{?zIlB@`Xo+M6YcgzqPgfZX$)92Xz7my)B&-E_=C2Bk&6@`eF@ZO zQ81G@hJD4Y5DiCyx35!MG}*XsG*p?Qa$s=HtAfIy$M~SRka|eUNKq&+%7rK}topKY zU(EDMeE^%3Wi0*f{t4XG=jAUI?2(>a=Bp?#7{!0?x3|Sopyk04X~{jSoLpXWdh9g= zn-LzwjMSoyD3^=lR8^W~$~icFG8NasVlu!m*CVZ>27;x2yt36of_+zW=gw-L?Aur6 zYE7%J7^M0jwCtj;vTurssbAu%3)LJ!8NGm9SRWX z$!x=++VuxVHES6GCMoYZ8f5u<$tx&SH|$P1&aT?f>05YTca!rLoeTbRXT}kgU_rN!iA@u}{>ZGo z<{zkLvyA)^j=#bPTSk3?l{~H{D?(##)@Dtch*|JaxhHcETI+4>OUP!U#8p2>>I5hu*AJ6n6$j<;d?|5*MykgA#eBy#N zRF{!hR$MMZpk~GJ1%V1QBIlpwlBPnPXZvLdP$UB$e^u!avv%AI?GgFgSsajUET_+TE&SbKHZ1m^3FB0yH+2`r{iYkukOZYkSvwnq=1ZalnE10(TF39w;-zvLmmPv`ankDg19kq)MfD z7A20}n?C`2$(Zs_afB(<;Y_)%$*xF$lsUnLsy2aBlE;vaS z%IkVWdHpC26+30JyxAOJXnl%Wx(zAq zjTk?0m;I72^2HAP9gx85tm4M<>0fD2+z{W0WM6krLYDR|6=u$U%Rw&hz6ESR)){EC ziRvD_xgGx{@1#;12ribvi{e$)>y^(%g-*Y*_|P!v2m*<}!}k9N0m%UfIF=zy1Xoze zh|>4r^yR&TwG|>I1$eo4Z(sx*m6)mXwB6X;sfWnxqk!W;3EUAqA08nG6Qf@|I6Vt( z{ZD-#j3*bH7_Mj{29=iS>N1j1UdS+S79^o(kzns!6-BIX{&SeH*Z?Z(I}03_HML3S z!RnEhOUJOMC&qH$h1Mg$rV4VXbiOls#OxBl%gLf=t$DBSw>UgF_J#EqS185OkD0f? zhuRR-I)<}zdv}Xf`o@00+D;(AqtWxrrKucI+w75jeW-v2By6u@J zqKPTm%aLaw7<)|jc9gVr4tPR?h$E?(gr_l|+$?{+TSH>pO2vPvQUVw)8`yD1LmcOT z#}kX+h@)bdos1$Mid#?ksI1TaDU5?X9`v^znS84xmGWrrt~5>v8`$r~=s&W2T>I(q zT&W|bE^LeGfMp-8_V;*3vM%et?QS5PFE!IB7e%38Dw#D>$aodlVc;s|-N>$U;R%^e z{8PZ8zl{-T{Th#~d??$_ZCU(!`_p;HJzCXm4}W0^i=Ye{xK<0^48RUPY!T$J^W}SA zuKeAUNy`ZkNv^!BLC+Af|L?G{ctGSbKiRD~AVxHrG~O_(_grdV4l^NvBsvI7U- zYyLgBj+piVX7#I&pmyz5wCuDp8l{uJK%~AsHQ`t23t#|D4=Xz53;tZwVXDelt-Mzi zTNv3sN(GP(U*8dzqZS|=ic!5YDK|HE8r8j-fTY7&nQDcEL*M=Q;pHT58hNOMo%fq^ zc=U?n-=ZGR`Wk3wB93E9460LYv?d7IUht2s8ok6UA7!lkhW3j)i>`sI?+q;&&TE5h zO#p(iy$g(5b?bKDp)N6;(zC1{lG^ReLvHID-1h{wL=}h+PwDEDZBIzmJeOks5m(Ro z?v*Z~1z?HJhVQ!35d23b=D$5*qg^_DHyiTwpBCY<$r+6Pf=txS&>6-C54I3PAtm3! zp1drDFT7ac`;0>H1Vmp(uQY9E3wE;LfVhf}G@>oG-#dB*A=>V-9@Faa3}~-C7z#sF zm_N0(v7PDOaO`_u__n;?@s1rCTmsx@ns`M0>F<`+1WWe)Y~&;tn!p}T=vJNwspkU+ z-eOOVI=yu~viJ<#)m&+H)}KF}uc(wAOkTTuBIbKwb#uf0q{wcrnX?D=+x+PL2JPt2 z`VWP>?905&6KFS&YzhnLQ#epDhAVDLlc3hN=?x0cKY3=^?WD~^4m8LO;N|MaQp-^CN&zz9M*4v6}HB)?wt2kkx2d)w*95Wp}Lp+aF z$o8ag75<5EV|C7<`s64N)LM#VB5evZrU1l`0L0hxjA>|U-S$sWOaD!kPSB6LVj7?S zSG7bHQ+@}eTDv@Xqh5DNsy_PX&(Hdk3d6-Ee1Ln+JTvN!4j2Y4KYjMluQ18z_l_D7 z+C&2nDkHiSkQk_H!{5CV+3+|cyDUY)3RD(fZM5*6LiiGnaJ=&4+7$jIKr9bLIUsXl zDbqx%xh%J5Ks>D*z=k5Rt^e3t2lgJrfcFq}!vDNGK@;uV1;5?xLPzf|V$WpsXy@a& zF~)wF9ZX3x!L9v4@j_ zi^G%EHbge;Y9i{uXRpF25no3p(%zh_^a{BUTr-p0A@Vq z(!`I>ifSit3$bOExZt~n?K^)T8m(HzVG4jwg-;+ndDYUyGL#aRBEm9#q+Z}4LHmz4 z>t?YuES4Jp)zHurN_g~o-dkL+RWZTw8k@`gcrQf-=FP?frTKReEn{WLB7bMO!vs+3 zUpsaw8a#hbQr7o7iO>I$Hv@YBV~7W60PRpU?O&leuPm!kfLJYY-)8|mVOZ1LvF&93 z)w?S2zXv9$}J-GioK+tgH6Tv&`in746A~DG$J{BWX=NBEptk^FfY{+Ca^kAlM zQ;BjaZH$*@;r!))a3u;q+z{qIn^Ku4-WC8c6wCq+AouYuNPxQtN!CwvXSu{u@^z`! zFWW~^i*?_Cth~?rwUpcCRESI-^qpm{-Q!|wD4zn_D)I2_lr_&&&)3S?-7}Y)U3X_| z(CY4ciStbog}RA|ej6N?FZJE;r*+dB3KwlltZ8~QRlQg^l@jGt>1^5|igsVyz>-{# ztyW+k01-i_bCfplO1O(Y)(x@qqfk#NeK}bVNU!)gQqK*cPDjl!%H;AbStS&?B%J?~ zLlQ$BbCe#R5XGK5F?bemL^!mvt|343A`~(90cjH3Yf`}13;R%=1Y5NWgve6cSH#^R zq%y=`dpnRn?o`kk+Vyb#-);C&0k?r%NZs_3Z>|M-&L4lv{H_VU2vrffwC5`rbG8Ey z>#k;3ec^`5JKttup_U0|$*&IaiOs(zUoajM0;17pvkku++ap;ncoTAVSaB*BLj@to z{9ewWXpO---l+>Y>;0=Qn>un7FK(b2i{12>hUF=##iDpIBw`^14nsbB{bxH3r3opz zu^4RA%;2o)kiR1I99QT{#~%f4>Z3^vUKSZ!qKvn?91U*YZpic9e+bEs0{BH1E<0DI zn=Gt9VO(yv1Abzz>B7!HmcJS8NeN|kO^1=+h4%b(@zl07XJP|CK!gMS)kpq_$a{HcG6 z=$QoD%75p9SS#JF|r(q>zalNvQ7|k#Am6;*qzDP{V%W z@6Mdl9k&Z%CG|yP>xsuxr-Ugu_s!G1-`*^SGA>tuD|)e6nKW_y?T{*nUEF8Tk2lJ} zR2?c<17_NEz)oHakWln6(K&oyXY^TU+%=~ZbDa(=p@h-oU&jpCU}GRmawV>;;hKed zC9A{`>2^u_1$%c8z#aN6Qo+oWX*W_l2|a#}?Uk&Za-5s;@AK->JZQkAAeNFh$2J#( ziP;mIXK*j-{_6 z&-+MZW%Yye4(Ohss|k6*VF_M(W)aNg_05St-1b-F{vZt5fG47(Dp-Tp^dCNw%XD4Rd=-eA2+50xUp!m5wom?XEVy;GG8+_VvNP)Syld94UX^IKJb_T zUm4v^FMaTqwA`lMwn(TSRExHEhxyk*2#$Ekfbme?V_Vp&^OuLS;C>ol;p;*wu)%Ko zU#i=W8E{$s5)ZEyFNs{R3Y&T=;|Hn=`J$gd!gC{epPkD$lERjO}qj*AbqnE0=^TX>=g24Fl`xPH2jy|7dMM$CTjhtvs*HEqhPMe--U76c5G&?^}u$fzxcS7A>c(GPiAKoKAqHj|)&x_G=(bi9lA| zH|B1Mu$qewfTvL}y92-P@jzmvRncTUVuZi3a$SFF2tqqmmR;P#NFKhB2 z)-Imnt2lj~Xg311D%;VSl^(M8((`dhFBN}SVb0Hb#kND73>Aps;@xxcKPjuvGhQvg z>tz~ZT#4lNs)s4aJsV`jFf*eD3#rb97jr!2JQ(}9BE8{^9*`Z{M*VR+fT!Tduq%z! zYY)g*A4wK_Q?NNl56{_0AIE+NM{Agb$IChHq9(R0wLH19i>jyLTOwq9yOvM_smmAj zIc8FeY?Q=ZAbz@abkL)xjlPGv^Q_(HERJqno{N*>gs~k=maAy5v5dddz0|}D${IS? zF2nK#q42r(AJe6`qefpn!@j-_jumg)F=Mw!MSoW^f`Qo93u%=Ad+HsC*sTJ3z+P}C z`E`gUGRL0%t$NKiKQQsUDzl3a`ttaX@99{7aN8Z%qFPA)CWLnZ!K5t@`p<;HBY8}v z-Y83+vORU2`6@gcq1R>}#sio83EawlYr^t6NR;LyJp+qm!GMv-7cKXUX*dT9Sfled zd+ztK(5zDzcp%DzIdG^G!pxkq*~#679#bEs2*jHqRt-Q-4#1|F8XajJr1c4mH;vU8 zLJ8LNGhwvmfU@<7;}!LG=>CBmdDc6`oT^;@Iu$N3N=KwZzFJc0S1p7u$y(V)I!PHd zFBg)Wc-%n?mRkbj>jwX(mhS?nP5p!-ZNr(6R^uYaC^F7 z0YBMXijLmk!U3xWEseDT{(_?Vr^9+hdlWi~sWV;O4COb!cX2>N4*X`fan{I7r#|Z8 z>hwtm&mmF5nQ2JGTcuP--8|+-^&+nt88;vx?H}2?8BQL~6(*xOI>B|Y&IHGoSi$n~ zSNYOUJp>v#h+fN^Wmo+io2QA)rYW6A-rGI^&p!jnX%b-Ss$7A@{3mi~-cD9}#WKhE zD4ot45MqNahk+l}DoM=(mciD9uA}49z4sDo>Z_!|Yh!w4`FK1wu7Bx9#6L^cZt_ht z{?eb`4>9thT*ng=$x_fLgl9%4kFXE^(({6<_WoD*aqdF<>8I|b0HU@NaMXQVWe$!) zz^!}Z9Kt7H7i&%N4j>fb5+a?qv0ME4|7eA7;L0-dT&6g7qF{gZsNXJ!9UH3N^VSpt z#dw^%#JQ*g=Wred^EukOyVw0kzAezsu(pzeEjI=$2Go2myl2CcVD4?%h!JmW1;cc zWFNzfMsb7&-a<2ykXW>K**pKEW>HStE;e89(fAZOAETQ(gTuEe9o`e$&o2JXd`XBE zJObT$O5_ZJcN$iJomR9Nkp2$TaJFF=*;NhRliwnsd!W-WmbXJ_h5R)Pso&T_Y~Q&e zJ)Z@=9s62O|8Ixx>Vof_H$mxW&0j|Tcb*G!(PR1Zy5$B67+Kv9Z!9!GVDs@3$P=AC zXL0*;^tyT1t}?(DH_n0>>#rcyV1#9!LjD3YjHCczBw*0mFH(Hfxqe8f5wwLJ{*qO1rITnPutMquzTVX&lrQsr zr8G!>pEDi&&8T@>Ip5vv%c=2oUGgAZfE?Es1@z?5~`Ws@5c!haGuHiXcAd{IBW~O#qOBg2d&1His(LDe-OC-XUhV(0|)qOcgm3( zJ+aBdskPx$aasLp66WQ?&OljVe6QI3qLAv{>WMyEtQ!Uo`!}LQ@W$*%W#pT-*-m^P zHNi3N;(XuaZ{pk{7FVT{!8I~Y$UmuRmuxM;+pJspUA`PTwERLGZFbH)VBpg`@~?TA zd@;Wjp6ho^xb@$A^9A0UZDsn3ezFoz{;KawAIf>D9}x~ZK=S5&a&(6%p=`qux_Z#} ztA&{LiT+X=^wm>wggNW^6EZctK6p}>21_F08VyRNC3&4E)rcA>w24CC3lfiVy+$+) z{i|9+T3e+XX{K60D+1f~(qZ5mVddve<^kxH@d7bJ_Ph|&^U2qGBD~e<#LX5au6j~a zuqgJUY{%FmarNcV!p6G{gfBA1PbLi(7sgTagB61YsmpQUzzDB5%Oxo6!f67VJYL< zXvaX*Rb2@?tFx6|vU-*F>dUiS$<|u&l(FsqXn!Xl3SxZ@>}JduT0WU@%$QOYla8|K zAp*22cH9@p;d*SYZFuJcl9fMK0eh$JU!{ok&|s`U4Qh^&XG^J z`wia<3M5As-g>>z$Dif)dG7=9)#^(weJUVf%6`h9+tj+(T7~zHP*~DH$uU+pfVn3B zoJ8SpbthgRQU^ttjV*wr84+hzi>IH**E`hNJicH&nU9D0+j`{o)>8ZLQrRW(l)~j_ zc+H5HGSC)YFgODCiBz73A}7&R^py{%eBiLX?GqDREVO{a>c_af3R!XG)j@7||Kaxh zjDT}zL`hBYl}xk!|0GhtzrqU0DWLIVklh&ziQ}|2y7>7mRKg3YAN3fKi@>(}W4y!g zu_)lzI{5)4lNubKB{-6LVdD_ea$7+T^{nkE?9WNz)$`ap4=rw*Nie&#?J4#nVXE&& zWf&H{5i#gMFmi;^xL83euJ*s+ql`!UJWAdNs98J+4NV(&?c5u^bp%76$HUJ-4zE}? z9(7Oove-awW^`xWJx^vL7MK&oI-~Y5W$Z!mA$H@WPe^KV37i#C|5t#l=@02bOBmSc zyt<^Z8#`G$)4G+zQX>#BNNBd<))rHPK^8N^dd0tSn(6Y3he@W>O)-}+%-d73B+dRc zhh~WSZ~~wr1aMbCn4z+mYbikEnWUmUw!XF7qz@pwpG<(1yk^P`MhY*!dEiIjDTgj$ ze4%>IUkU*TS#4XnYjI2PeYf8gyb4}j_e^s0EJj~-uEH<=ec)3*9s-vjGnj}KkP*Em z+SX=ni1zR|Tix~5bzm9I@Z6Rr-aSKr!aw&%!*9oA+Fv3@$quc*Cxj<(9DlPd!jA@4 z9FG9&*k&2TsQvuGOmq~hRo5-bTnp|X-l($qu@@o5ZedpL>Pild?#)?2@@-p^{TbHrGAZ*TK*?zAE-B6~T%*!}7^8EX`n0s4d1)shG&>G3_n4E13U)#59;30229!{WM)f ze4&}}ayW+)8&-TU-Z2kC=1>T0Az0j8+af8pB2q?_n!N2)>w!4OtEBBZ;hpjjquXGO z2c)JCjhQ5Qi39Q8=Q)Y_!D*TtzhJKjL77Z;S{JeVx$J*$O=AXHK6fI9wviHvXwzGS zbSs5Hi3kvI5m~UfjV37fO!R@=-IrhIpTOT& z3Mj*YWxD>{+$?GUln@?D;~og>PL@CJPWkPezf0l*ancJOEa+fymhG)~!B*VijF^m^ ze1*$W-S`5=Ecxsm!)tPSQHqEExJ1Z0AK9OLEr(pPBDQ(0ie-e3JVXR!s{hH*qKb(@ zw$?BQ6?tBv8b7i67;cy^X~Q6?_|yFV=0w15O91#yelH`iH&49g+HfTjQVmfY*v^Qw zuON~BYgVDcwkh_`PVsJ{e5FAObDq_A@B&a^qrAZ6B)AvtoqrBy(mWUFaB#zzI-$SZ ze1OMOa%&3NnFO9n%sD?9)eeW;8}%FmdwvDAKDQ%P0;PZ3b_E}sPtnIMYJM>H(fw>sdspck>N=rG-uQ)kIJW zPIG%})xTl@4-#!N^N0Dxufy+1_{KVW2aT!VI%MZjtYgsNIR%gx6bb zpe89*gL@_W>5Wm->G%h8He&@@Jpmr*G^&qN@wnhdfqQ}m;VoRCKx3xuv1Yd6S*XL} z>8nb#x^FbTJ`^0A8_ND291KL&Y1IvW6sF_K;e>Ex#au5xvJ(gt{-2e-1ilAy_YZ09 zm_4tX26LEYfl)fl;C^)IIzxbi2dwO@;Z&bL?Q>gB-b)pX<(9Gh5+R~Fpb{sWCqI!R z^4$X^J*YdXJX|biS=({}0(-7GB`ky)5MVqgs)p!T7x51%r*Tb{db~&c1ROn+x3kd1 zKrSg(%q15vzf- zK!8j@nMYb%@8g+M_G7*U9{%>EeA170BrR3?fI7sk`vD~>2NI4eDgRXWcRVZA&G`}h z!*#}3>=WMwio$a=LSK2yb@e5FESLi%{z)h8$ZnnoxVL0T%qaJymm>+W3g4u!#0^pE_!ZipTfN z{C2~>E8?yBYc6#F=cg)PzW0ByClA1(wEpZI_!3s&Tu~G&uD+)h_o;t8HC!aw|Cmin#U=Bt z0tPut=Q{kGm(veaxttVU#AkQ-<}i4267r?B*<`A%7=-ozSHY17@(iSsw`L03uxekj z)|2>bHe9&>GK2!bNvJ;5K#pp2bDR3!rx7Pw#V@-wZ4wHHGtl9WDU~^8e22N7WBqC3 zJ1-qJ`1w{{{M5qe4?RJO3kX)(ZD;JhcU#Po($Tv6QYVh7vj)Y`%ue~#wr6E);f?*;yC&_xbe^F!}v)hyCH7x4IvgWUeI(4=nSf2E~tnEz2k%gKXQ@Zr)`HU-gd-4EMVO@bfAW(2RTH= z>))`O+@C-ZCWRBEUu(nhxi9{kW(Egn$SN`FHAFx3JgOFp*Jr~=&-cs4F)ytDhpZO^ z{uMc^2O0|I!j~ZYu35%UWt4wD&v8S_mkI%Cd6I|t-c7j4N$_=LafuVZ-a-=%--9WJfHZBGk4R6*(R1X8*MrLF(ItpsovR90fPd=V1)e8J)*c|rNDFA%JM zDgVz1MlO&EjGb?|yCc3+5^yV~L08N<(i(bi0ZrE*;}&F(+gaAn6)l+`Tn;P~ZLig% zC`EjgK9v7QE}5KHN}2>oSTG1#jFyW$#|;QVn{ znDHJ8Q62}7xP{26_Fuez2~wLtR=}uW_?-v{$o6bp5PJ2we#obhABXq1x#I( z0Wo|^d{KoU5qP;7)9rbS(yMAOL za)(vD>v}Ej9VcqnyR(ll+fQf*k153o(u-fPY=i#Z?<(J7Ff{n8f^<#xc|)>hQdil3 z2D7qXdfu19q+$JluwH(e5csDi;2}v)y{E3$OPk*pxQLFqE)O&;oP{VGR$9v0TimrG zxcq53%jky*gw6|JZL^r)GubZ^nD@4Tbh1cBC62LEN?BVvo1Se=Ag36SfyL2m{-%^B z&xD9%{&X6QTIX+!Nrc&@y*qK%B((b88EXX=!h$xW09SD=X~L%))We81DIZwFYd+hu zl$-+Iw*rg|Ln^(>kKYIcfB2z@lGxUC`Z#V?SG35?+hpf50f0SJydR0}3i*sv9)1gI zZnQdx@O#gDKqqC}BVNAjStRjQ=l$Vn&6bEZV?G_*Od%I<-8qDU>9D>7W|@1>XH+B3 zKtsi0a8_DRU=#w?G8e^RO8BuuC>nqr?^o~U?H1Q+^`mHxQU5Ia*S69j05S2| z55$@Ag>eTx@SWZ6#7w=iu1E8p_^U!}kwnMR`G!9oQDU-k0iUv884D`O2S&rtjdBUW z)~Hu`>~(L2xju`DG9|f*Q3BP69l>K+T9&Smv;SpPJ#*!}K1BP4%%p&RA)PzJ(OPjzwsxp< z@T5ojU*K8_B?NtBR#6N>_`t|N zFQVU;ybp2Md@Vup(mMSmA*}C_@qdpu3t|{msMLx^3E_i(%v>w<4YJ#_>WR&vQTDN2 zbPjOye#uVGiWNWLeaiig0x!RjRyBH+Rscybru9?lw{jk#1ub!(g$TNb7?yW>!EP~# z&6x}Ya{%jiyU&c_LMA^gs$)jE|Cj1)kK8U=5dBl(3B@9#HkeA&Qz|LDFUNI3APIWP zHK+g^N>bI0$!W@-kvp%~C?f{mN&V;-ePI5Z@yPN}7aKXQs~3E1`LU7e`*dKt0{3O|4dP?RWCB zv$q@z44Sb*g<=J^FI!80xVj>k=*894k>^x4?3bTbK$6 z(@8ekQYHy#h$qygD-pObPwPa^Z2jx00`d?c(&-;?)A@5$xKg}doGTwjJ#E})fvDBU z8b64Fe|(djLcX|}(Yp%2--!r8y{iTUfl{#P+$#_Cp=ngoYw5ws74Urr!Mf?JeSBOn zerD)d>3xhnoZ?5ST=7ZB#q!^H&gCcY#a1+S+<7fbhnwF6G69d>HXvXnDSQH-xmwY( z;*c;-+TL;E7}o9wSrZ^^W%(cMToBD7sY@t?oUCE2eGU1P4BbLY!D=wAxwNL$A4A}qPz~3M3Nxx9bEkho?8Pe@k5pCtkacOLVX2dd>4q z0Z?pmF7MmtQkDibHH*YZcO9mG-uhaC1J~$dHK@uzUzhB$@fHnY$LQs`(l~gYg}QXL zt5X#^biW_x?PaCw9?mrZM` zf?~c$(IxO<1%$MmF>AmV`>7guZCxGnjAn8vRITI)PP*=kTX+6B7!Vng_oyQ-mn(rO z-wZD8T?7K(kl?<5>`%{ zMTs@}tqpp>C}T+TGQe@)<Hw}u|M+Gm z+MQ9ygC!xG@1Y!nwiqiKI@08GdVbyW>KDxZ2hAkodg2m+5HJ@Av^Oq1o?+*@J;naDcG9tH z)yI$c3$&K<8xqI=)1Wp9NxNn{0;ny&U2luIdvuPxAj=wN3xv3!sz{}*^Hi;#1@7`T zKR+Y<#cXOXs0&(&{b+DmVJ}IXIf{)$AW|^_FZ97w5jlarH>@5zOzu0n7)Xb1GJp&j zyGCuGO$5e$zQl?0HFlD+mo92r7+;dM-2`>8;3E$>1vx}c2uXu34sv0ZwXVY-vl;`h zz!nH-rTa1c+Eg*v3S;p3k29tFLKbVQDQHP##pW9cZo>EYj%pEaf9{Hr*L;1=j5Sk3 zI-TWp{JJ5-aC1o-H&P@jUN+qtRQfZv)asH$0%kU{VZucLf-d1+4JH5Osg*z`mg!n! zaDKt^_bozly+-8B(Tf0*f;wOTrdYn1Jg^1BzCATW^&I2AF!Dz>RMk7H?R?t3Q?~2j zLZC@bg)7F|*|4r zGSDldt#BcP`lD0%4mpOhxG1KS=f!j1RO}TcO1CItlPX}ed9FCm^XIqq<8I8v@AhT1 z9Om~lx+Rdyz%u-V{T`Wz1iagY=Qqxi!*Q$kAMQi0N}jF~lM=Ih-{Jv}NeY^nPSmab zm5XFD2y~6XG`p>(du>>X2`AE_KsA$&kPA&CY=JaF_Dg-~ja)ZvjMQw))@#gK(7^`X z&;M0~fN21rb9d${TM4IW;fuhT+Ytvhb=D%U3docd&%IsPFlU@I2M%7SEv_JyB!}Kx zh*Lc9Zw@Eux~e2U7W$g%`_b>@{oxPZ8*9?{)o}GG9Ym0L*AlEpXQu~d(`(n_rCXN zdF!n*@I*)d)OZ9u7c@z$>@~&bAzXp?qwF4j%73Tn4}Dz8{Tri@6qFB6$k5KvN??ay46>cF4F;O*wc6Mf)m$*uG>DUd9Ms(=(x@*&i zXU1HpCTK-3j0GXZ2rkGOaF)NU+f7AFI$8=RVDB^Ye1N6@pH6%+U_B%J_1l`$93N_l z;$L|yiLNN?Y0>C3knF2Qhp97@r@10?5kA>_%=eo)vzs0?`{F9{K8P7`%6f3aCLWba z;3u}r!njsEG;^x z(+v|3g4YH)Rr1REnWh>f%F4oY%4XTbivG1J7b(Nf@(59#2oxL@nqajd_Lc|CFC({6 z<~_x57^|ADMyM2pr}^{F3wx`(x}gW7Y9)Aur3lmP4(kxj6@6iQ5lp z*q%22NY|2qz6)#mj8-oI@j|W@_BUM^=w_ll*KUg7v1^8v_3HcFv+Y#2ziB8ll&~lk>YfMn*50&bV?Qr|X$WR#g}+ z!p8ZRp$#>UCY;>Ry5?fbdPUVFE1g>LU+c2*_rqNDDZ4(EVD$Cozhj#5prf$MJcyc2 zm}2wor&G6BGv~7^YUI#%`1{Kp+8qY59Oj4$mXGk=(yEx5O81F^xJx91;gE90+Hbew za|9ndq?(-Ts8mCLY0?++U_QBnCaCOjyO-pq#be^M1VBDxH~7uC)_&LdkY@>J(mPt8 z0$1Jx-&E9x3`I4wxqvWzLg!M5ES6i8Z>d#vUsDgXk!6m zHDY~083bz`H3NRFosxP8xE8!mwoK@cQwC=HJ%($9WEswce2m~*z|lBc>c)JEdo|bIp&nAd{*HmEB~&xZsDimu4K>) zph4#zn?P}U!D3z8NZ6D(T4KV3&0_=UM?5q ze)Y(rFc*S3>Io8@-VBKY+7~L{}sTK~*-DRjn0k#(0z-xRl(|z8jXdY}tPIOECi+x5MF6SO91r8f z7k32i$d$pm^?z@~;tk1+`seZJ9g+Ouo`%#OqS|#4J$PK>%WBix@(!8n$4F=UFR@^^ zi=wjEkH~G0+sHNsOPhT6xZW@24sj{R`C-Y2iQh-I_Mae)cq=JMyQ|&P)SXI8CX4TBHBtoXvjFYV1eK+Z4*TzJ4F^_Eub-WFL zP-HTI!S z=$6AK1qRuAvQ}KzuPmy7DWzHDNSG&%(pr(~p!<#Rrd`)&497sRep2+%48-XI0r`^? zGEt9v0#-QLkn?|4c~~!`Qp*4gAhF6?0dOEp&vx?r!0jrO&l6TMTwd;TDk4D;UV!E1 zb3)f~>_*fbh0d4C{X&+ujbdm|U@%=D%X*!w$8>ecUk^b?eoA&pwOwc4W9`3mZl+yp zmY{1XW3o`|H1#kUO%Zi(mBsZBUPk9w|BtGxjH+_mqKEDjq`MIW0VzpAN$HdnX_W2` z>F#cnZV-@`4(V=?25AAwclgfn-uwPKaEyJvz4nT^)|!*P%Q(a)cIHB50s6>5D-UN# zniVBVisgSg^Cp3nJ}#}Nj$j`TK-erFTd?pS#rU z`V>!E?6Jagpp(}}z{MDdPo{_ce(5&Ltam!xP8>G&O9U324cA+P`>1*ZBZU^64Og_c zpzLsjT!QRc1JNN5&WY!<<;Y44rMqB2NJby!S{hE!`wvkLap||+h$n~$mx)S3uha$% zWD0*3K!5ED@WqkmU__6o=%q>Id5cx2$tfZkboGS)4=DHP1`M`Fm|Mg2{RmRv(24As zJ9qp!Vs_8ozx(&R5M|6k#QT}s08iI-wOq1I>akQ(G^#-0{xHslQg4}muHQ7|j*vCd z`tvAeLTNL$twc!!dSBU*ii)Jun(E$5jwy;;*z5+>{`U6dI};~x0m}-?&{gm?CWgeX zWzXPKFMWSx)J54aQw?4dh}8(e4Q7U-f`|Z1nS#i^J09siJ#F#<<+J?MG*Z9qZ^dw}CpE1I1J`@m6#<&q@!7hls+i7Vz4mf z;}2e$(YOJm)4$z3#m~&iL9;KJC+r8u|Fm@WM4j?RNZExJb-{VPTNUh51Km#^<-xN5 z>GfN<=?ME8GE*neJ||f(tZx72B}IRSljFa;_bL!cHxIR>`{yyKYx}5@bE&H@&4YH^ z>;46!V1t2Fw^s_Un}mog<3+u%qCt(EF80Co!6E>{Y)G-F9R}MVk4jEZPVe&|zm~ZA zhX&3$wf8tUyUK-Cna{uvy+G2{45nObUhMBw%~i zXKhJD7Q`__d9OcG5L@7Z19k0>0qqzHWn$zP3#W`uY=KTH7Ej-XHt#hw0+~h8)3FkL zi*p2Jr({MqX=PzflW5exoTR8Sc(8~Dbfh^$o;L2Hx~}D4j}51!KQj6jhEurIOMuxk z{kT!1L<6YrH1;T~&XgX*xm%xcsrah*&<-1wmflOHLMLYZfiHnv^`o@zWl;zEIkmXsn_Iq^sH{toevpoqyNX}cG+6srhTg|8Af+mT_S6*-Xu^%C(%SPQn{!$c3y zkbuM9LzA%$I0JmN=Z=TY3yPmVut%}QI6+Ot{DvEl9R4kf&u~bcbDnPL=gulyW}@I> zaS3P+75MJQqYqeS67+B%H%Z@=+NC9K z9t3$1S%YqO$%H={ge3~MU)-A11@xkAkVm#V*`jKOI|>9Qw`*)i0W3$bA&{pWv9vtU z5M#1;yx>n=LGr_-j_NhE>VfhYLi}#r0e>)C^j!h<*}Zq8u-@UZVMzm!D41`~T*mpc z`dpGNFD~UbpRYy+i9nPA+q}fP1C@pej(qj)zfdZ+*0xN&iB$jUz+7FBq@9KH<0+0v zE7^0R$Bzu=pRJEa$ojk%3yc~&pyCZ9g0<4l&#*(S1;>boX|Xnli)=aTIKgp=O(OyW zukZPLH4C@jxcxi9?9=7<+mt%6U-1DX5eG;bBaM=JHAP61xEsBEcaC7N$D^tgnyvp3SL1b z_XdH5Llu&gV8wpA;E$0K1+0n<_Oe&K2{=eV9QS{E=u=qQ2%-$WVHLLA0#>T&Il~g z{O~qGwm^5YR^dAtrL{OA;;jOqHAv#6me?~=wfR~d+d_rg9)1+1!sz(p!;C5_F z{n8TCt3s@MBKMk=>C!ps#hLiT)8%Uj-<|!h zRn81m{^DO$#JY2@=F#kP5b?m%F1#9MAV=uxV>{&Kb&|q3cTkLdd9#=gQ+_DuN8@WG z4_R$```tP5L!&H_rW8*0XKn_?Z5JU9XbHm>YrHKuI(XVHQxb+2=15D^a}|_cX`H3> z%GFih$jgS)iF^)) zP$6rCX^@~*=f}aKy7=JOp+T7&i%O7r*9W2ko6^hGG9Qyrx$m%yNNt zknde3>lWb-yS@vS`y*HeF&c#+qoaPXXCcQ~#jq83F|-B2Qf|H${83$OxZvI4TJZ{I z_KsmT5m~(JrTO$=DlN}CE0jA&67uXe2XAR0J#m(SJIU?LM?9dA?qRiae(+Oyj@ZBAz}g#n@EY7fk14?fvq(Vx|y1+JDg+NB{PgmSOz zP9lcPkJ(X&VTFe};4TBdX`9wRvZkAGn$?%MHZQ_O$Z%q15-pieHvar;)#O2a7J_bM zZ2{;;k%$jwI=T`aOh*3_!B=|4AJ*`) z&mn$_+Y8h{-YAAl&9BoFQjVY5{@fXu*Wkcx6GkSB^(o^2#s9(5?(NgBYYcRUe2+*^ zFggx;)k26%TER0~ND<75Bw1(W=n5O>2k)EbgLb7l3EEz_K(5d?1-QcA zkw?kx5pvIGVZtwFT6%u5v8aAu&b9=0or;!1^`EyhEDkW#QSo#>%lT*^i(dRBVE0Y_ zH$Uw-X=e~DIzEnL7v?DQRuUOoiQD3cb@YedL){MhI7(VPrl1KFXrgNjxv8P6iHYa& zNw}ZR-=>mQh||eC%gQ|jC~U5o^poPpZ5X*-LNsbU_QW}F;ldy*7~Y=P_R;CEy&do6d0YYx%6bv*?62Gc2WXN&$O#LOCy zx@Gcx+HAZkBilPk8?)ldics=&8h|eA!54_<`R2zBkV#qQ2h++8%b<^LuthD+g)6cR zP-E{3)qq7^^#shH7@;^~Oe6Z5qO1tH! zF6@c4>DBqo6*7~*%A;F8Kwb`XWOf_k;-nWf+>#VidSESgjmONmmUOPUGJv73ty5ZJ zyk~G-+jCCV(fW!8Ml7Ane}}rbQFVHx*I9YB*$Xw#zfM+EB8RG4Vk+no*WnN%hE7Pq zoQ1x#877k2 zNwO+;8*mf0b>IE`jYHx7jMbTe^}t^KanRg{cz~hfD=cn*WrKGGby(6O zN}`V&S^ko{WGUF47o&t<`5!!l5fHQXy)?ctU!QAc9bT2lkGHHh?=%$@0@6$Qx!#>j zR2>k57Fm$~jkK&vC?ywkcL7$Cp%sg_Wy|h{JqSb9>YE=589KYH}pSfyEjbYxREkXlM1mMOfhld`+sa1DYWY~oi zr=Q&g2qM0z(mE& zT~DPa8ZDDt;ckal$|G*hXKQlrRHsq3Xsz^&V z3>(N=3-`aT8uqC+PfVZzXb`x$bdvEk^T|08eKV)*Th{H@q!o_*kdCFTR4>cBr=sF# z9&^op`;4=?$wyAmdO0&pgP|02^KM=_Y2eD+di zr#>4_Wh6r{%a9Nx+IN&wiQ1#PBSE39NxJWmpm3TTU=@+g*A=_JQAo=bq|c|U&+@h5 ziBG^RpAWeD!wiA`KHwOnkEW|?1Xq2oM&@S+1~=ZRQpS4#(+Bjl-S$!u9~IR8!jrNfKf!Iz!|PSXDI_|80CnGf9?^j@vAjSE&y%k?S|amL-+WZg~76QJIRSUET(4`UNB%T?64y;)#(049>Mz&}?eZ7s+gtDLry@ zC<(wl6C(3r%A=G-^O$19XVzK0{d2FU+USsJJT7wE*FN6xf?%4Q)d;W_DvOQmr5uBX zl=vhR!ePo{bm4xTxn+eKvMND8gaX7xH^iUwTjV1bN&G;p=9U=@sGj@)X_r;}}_L6x{AG#H5?|?S6BM>of82laoo$EkO4H zp0CuN$)zcE+owdVbM0L|TTT1MV=@FvFnwM|(P(|}PgGNZoB~gn-Rx^l*Do{5k%(&k z8it0P1t4AtJ355M^w{_Ne_zv4G3#O zH@LdRAS78QVq5uBY0PmeJ{a<8MFR3S;f+2~SB4|mAr9Y9vGkVSbmDHfN{~aWD^p*u z3AK$o8)J=wDBtDEfR>o+ze#cGmaNx_2PA26d*5TLq{)8J#+&-I-}=F`H1l1pM3QMM zb@MXHGuFIEq3Sn~w;{3%$?ql5IlUIGZ3U1?WA6j~PUtTbC?IEW&`29z|Im(Y+)ts= za>%TbB*6<+`MFUK3Qiki?M$u@o7B%bOS4f(3}?{ADh~0xay>Q9l~e||8q}WYDK{?g z)%uTFpacP2xMQPM{(m4+|C}4gh3Dw{`>>GHJ8{nt{jK)bLY`e(65lize|f@8EE^_0dia}suI_g%laXH`W8tsSw=6_jIH^} z-1O{VF9VrJHIwKPt++KBev;h%YH;ruwf z{Fh-DJ5fYfncs?-T7rPsfPHXc`I|rpVZVY^?taejdv1f>+~0|e-W5cXJsyEo4)vGU z-!)E@=yvp4qd-+^c|QnBB!>_vkSM)dTH$>2@2p2nuTS?3B*pBmUaYB}%c)F$@Kb-0 zq1v_gH>-e!WEBN`FRK+(XqYZmf1)rXh?4zDU;Z@pFPp11@MX`!KE@dTlDnIYK9P1A z?=_~fz5BiUe{BVC$d4L(?b74vTGusu@H%Tz{czf$ms$i!E+g%2HE#*ZkG0Lv2J9je zUbr1GX8irKlJh(agT)pz&RmjJJ760%HqCT1o*xky_EY@T`I+vZ%VY}P@*fk||8W7|<1#^>1+3joe zc{Ualo%6iY_lehIRNSDZ3CYvxBw@B7>eKJwAO#_n7jXi7$Y}0sdUd(1(l$1+66}rU zHy_|OEB|x+O~}LP)PIW$$K+?Y%pM&~KuI6@)j-n&IIR6-z{h@_=o%Jg9Nj_5h{d=A zxwAtE>$_I~Jqj5kvE_CjsW}ga?ulfn$sUGLr?^nzrDV+d2m`zKec#pf0%ldU;a9x5 z2K!FihUfSRqEzeodF^T#QEZkUz{M{lCxvZ$@QN!v$ozlg%T+L7+Z29JUs1U;2I`JO zrJo-V?E;8Z%vpcby^DMo`RVN4!N??Nn~Qsx;6GL8CFE89+}1YgVyA9AT;w|^pIWa& zj^GG-c$HZuKl*ymNUOejmL752T^8J^%kVz=%O1rIZ)E7HVZy&*B&^eBw*2F)zFw=r ztsc!$r11@!87r99&F6Kq%qYh6AJ>m~d_0zi;QeaW{!Rtn1~;{ieiXH5rw}Lywh5AB zcWJ{qSF~`+li(3ZOe63K5m%-H!)Ne(7D1=)=H8H>kNrfl)c(W{uiRG;U4&XbvA8wi zB2l(ErcRsb8o4$9)*Xt8kcmO=R)-Q&PGSc}EIeMWNc#6QG0Gr}$kbwaW%@YSEXy<> z6?rx-G&$Z5Z_6wmb*SqdS=@1O{nj!=UumRV=Ifc~6XhC6| zD@Bj_q7pL_{jaz|mg+(tMbXfpY}mde!S`!i_g_8c2r~t-Ce94pRouC92qRXAQb|Iy z*M>sMMsHusB$TUs=EfTecoF$xfte_j?N{ z7VDe|d}2pT8;Nq|vHNcZcYg^v_N`+25clwrDP%>;yk*$Xa;F(YJ6YM*=;7Y0hqa7U z!0eOoaQzqY4{XAeDUrN|cQS6dP_Bc{y?W>IC7uTK|U1hxq1b0(in%^&n` z9b0vgJ04wM=?Zptd$2$k{>W(@6_SP^YTRcnsWvn?+b>7v59pEtzlxVyXI+MBnJ@Q!;NdA->QO^#oN z5eKtf$n<;6PkO^!p>XyD6O!qyd+oD%c8+PiTrJhnLrSkdh)UIf!O41H!d3(Mde$|& zl2S|3B`31}No?RDibl#e11@Q}4xye#!MMC5+Vd8=3J95W}H-5s(C>dCD`C2M6_S?k#9OvlYq zr0S~pC1z=WAm9z_{NP+~yf29s2fqmvgj8$nuW1sPnAv$l=vqf+C{yOMg-8)tGguEa z5lY!e39;*-wY=n3jz`w_E1cz-m)uIA3DTqE2^dP7HM?5dpW&2 zcS8t#dYU%Aju!jHo8;_ExG$V~8fPU-6tugR6>2Ld(QZRV2O=NDVXO(wkqOkU!?$*v zoJw%gleygiqt+vqXYXczmr*H73OoKb$tl)2O_pm62pDLJ!Y%U^odZj`JaD42K~c=|tOYE%|!XBT%6lb{qqBn;^v z$iWM48x2@FC-W9hHQpgc7Q+hLw^h%`=9+)v?Iol8o_cp}gVYfhvHOd}D@MxGv`2DW z((&y1?cc=UZlN5)ZI=&4z>JNv6}udLQQHqnHQLNa3YiCQzNP`0Sg({S&Z*iO)BEE< z^G>;pc5~?$O@BK-q*ELm8Z_yAS8t@haYVcs)bl%|$i>K+x>(jsPKxXQ<^Vm$|eCP4U%;&vs)0Y&;BIr5igurTt`|9wl)38J`N?pO!p2*3)&Nyo~oma+*g>FGF9@%5CB355;Zu^4 zZ+avMzQVvX*yu9}EbrkfGpV1Og_)8&rIdZf9Lj}t;|j_p?%)ZN2idNbhZh9h3qDJe zYLa4hS4|stJeHhdY1IU`2+B$8O;wXejY`u-<|->;L( z7H~xF(F!iO17nD5{7Le>efUM%pR4pBzGzK-9@E2M@qBXvIuFj<1h@@)!XDI$xr1w0 ziX}c9;ydL^s)2LBZA3L6<0XH8!X3*wt=A0Clj)&cBo2k&c8$7t6n)NJla29CGeoMC z<)WrS5&0-71O^Fbjh{#jBOKi)H^G~yomamt+B(PIOh^(R&^yF?H8G{m>J#8Npfmy9 zG{Xbm{$HX~VR~Hb(wY7zM9R7c+|KrLH5inKP?0!f?3~RmObVXUH=k#A3xnF36G~4w zdfaz*?00Yl62L?j;GGVnwF;{Fk?Vwk(z6?O7jeGbD_ycNmXWU}_znV|XL3;LMwr!q z6VIdfc&G3TKk}4*_~9*L*3tF7?rjW)WIo=YPmkoeOQ-W(Yz_1_-b?>M-j@_DD<4Yy zOgVbH7P~;&4m!_ncbceaGR0IKlyBkb_k3!$XpHzM=V!A0M*om-t>PabmwV^};sVx{ z`6FMLE8^$0yOIv^qff%+YY4=J0G$l7L2dT7t%&r)+;vq~9j-%(lRYt>#8RoZ!G1-7z*Ifq>ij`sw2ulHWVAAUsjh|e5iVkGn1 zc{~I=vKvV{5^@5?u-6_QBQ~u(#j&yK*=LacYzrA@r@je$*Wnd|&t4m|)CfyrX7E-=0RFl($=GE!1 z(EZtj9rJyEkyFX=U1jU%8~cLv&`wE2Fso#$zRmJt14;s6b>Z-sMq+e@viSwWtYJ%1 zcVN2%+jYP{l@Vln3R0LQYX#RJt*bj;jbX3lYs2!0hBU;5NU&1MD3QBvtasx|+WumQ0`AS_T+? zkeMD-IaddgDtNP%?G>+(!CP(7I|qd4r;9X|+WXKfl)@leC3J>C?y-50Fnu`%UHFn( zgzz@)zAWEYu_*b=d$0g9zR%O1v0rsQlPrr>p-#MiV zP==&i)OH+Z#~!g~5_a$^OaEGfqp5>@VGB4S2Xb74GDCZ_-GEf3Q&LmyTE!; z+3Wqi;o~5OM3lzkpk!Ntsm`5mjA!$&b+L{*utY#leCqk$9%sC;NX1C7*xL)Wc)!-? zqT8qOtmcoDuOZgRKX_R(kX0#+kQWyPSrBA47ZW27hI?k)S3R!#=~Ug$_ZdBR3_W#ztirD1?Fx!8uhx+YDN91fE7*B zQ&hHRo4hy|O0Ta4Ii^P}3yrrS?@OfBt;2z%4PRf`z9-_Dzgrz6q58)IMDwrHwqXVH z792B}D_$K_TBvH-V-`Ekd00#@%&iS9LJ@RESy{h{e6=aHq=2$NfKDH#JH<8%9_Aue zfY2M1z%-Pzo@Ny`>S`Vm;F%qQQBwy@d!0q?IICl|^L`z+{5rfzqw`$EuMwIwZ{II6 zsSgSBxFIW*ho;1aI6ByQS&_XC^VKAAx22~YFNE1=kOO#jiSVI zuXWh$eg9hSOrJaJJ_D%du{uqIPKu*0BHD^@)3bg3o-`KiGPz%ielCe)ZT-C0nmXU4+h?9$xy&X4 zc;LexE#>b3zIjST?3KUE)+0cLYw|r(Rlk$tONU6z8vos5g>p>JDzMS-$yj;wx5)uNph1(6PtFn@YPSl)&ou(JLb>l8cEYk z(Y;K|gAobZgK{Y}++#whb+dfn`S6vj${NVaA zV5Fh2RwGka+^bADQj)`s15=``krsTg2kp5WNZoZY+Nn6ZqAk4tHJLXosKURWs{?3o zAg8!ysiNM=DOO(8PV9>l%#vWEvMS2#+UVWr-L0M3}$wJ z5$LWTW+XJ=ZS~$3r%7z2fxOYadHwVFQ#8fs=l*t8Y{)CEzM0Ry508*jdr_}2a@@0J zR8%kc&Yt2;AK8e03NmH20o@0D(GM1&%kn2Jvf0t_0{uehGS86>92t%wv$$>)F$Cim zfC$+hV8HP3yVzQ*Sy`|D7zl2P%`eK6ecOhpAT3xtWk-#}#i>-HNZpmcs^c(uruf&( zNCejkdl#4Wb~?Q$dVZu5dh^0>>GDPGtyk`QM7wqcL2ob9>0hXS*3GGJ;kGOq>J~nm zi{!V#!0N%`S?}tZ-F<|TZi#^1FIcktou6Dd|BivfQk5CSI_YmT|1niSLeT^0*Ia#P}7_OWoq%GYb%-Blk*zv&ik%!vO5n}$^=F97j zuQc4;<0fKf>r7>}AJQZGrcOzEg_ClkutdBKzgxmpuMPF0;KtQdU)R4J*GG`g#oN)8 z)3STyMoF~}`C#pk5B5ncoU|hZ`=(zT-6@wx{(5h3iwdg$2pxl50>XW-%;9BHQ#VD( z$NF6uH!||>sr^QP;p9dmrK&j zm%I4zgR^>yw=a-1KYcDcuDOy6mKH3*JHdzG8+APDw0_H+$K!~$XG6O*BmuAvp-@oJ zi~aDo{qr^3RUCPKa*1nKa~Arq+`Btt5(TAYeq^3maF?wTa4thn8C3~MedtHA%xqK{ z_Sz{-WanQJ>{eIe+dOC?K4jV-AX$SSn%V%lC$oiN1UJ0v#vYgV$8N>{WZHGW!^3a} z5f2FG$l`vG%RJD#6(s+jqX6VLk@zqrO1OfyVriny6T69ik;k}WfAgC>JYt{keTMVX znng{!}r4+T^sA@aln9Vl=W5S>0Bc6!iy_^s@vml1k| z`ZApU#d}v$(0bA)Y^|zu>Guv+*E=?9R>akUacl^t_G~wwl#?QkM5?u69nOnk^X<1? z1w@raNSxomC2lF6QB86zjwVj%LgzZHfzL&{gk(}NO6!$2Kq_iBdhD`tDjx$*rax2= z_5q{FVTMi+8psEH@yP9=LRi<3Zx$LT>euNnutN8^*qC+5TPpo;=hSxmI;@F6>}0vzt5t319Xyy(;|N%%pgc z>iKf0MakLMPzvbdn3uwq1vnF*9-+;rrH)z_kF-!)F;4!3N%KQN&#>Y}weJrFCYaTHMK4Z8G$(m|9#d|UMeXPd zig>0wuS`S{wW?jUPOjiADw=-luxI1c$60umCVnm-w~TAwUa`dTlma=!p)HD@L2==K zS_i!?53kQtDP5>#dK3MUM6n{|s8LsI0+B@3K7Z`|HAe)%)$^_xRr5lVnM@JU%{*5Go=) zbF>)^g3x(V#-R;N9e36=;|Rh zUcSqbT^61{@NXe48fH@=ueC7b_XnN`#mG=c2t%uYJhh8~FsHpmn|LY?l#>R&!qSKY zo<*6{?knL&P$!SENZsaPNJxfkzk{EWR_b&*Z`m~doe^lmTe2H|e2|7v z8BkAZ)LXu48!K92~}pkyBQQ!+XF#V)t6RN1Hm46=w#>yIi0% z3#PlcK?i+zn>icT$!wWg2;dSVCuE)pP@^xbgE&M&{hFE+Pw;ZU<99Ut?!sD3ADKbQ zew{^W$LQe93SUJ64@-{mx&l|({$*8s*CFbMhC_QQ~K+# zD3wQ(oq}3Ey(|WawLogn$>aezBA_h3d!aNM!Ump zaR}nIc-G%Ci#_@s`>6yZ|L+&yuk?H9T=vCFd}+Gj&U5d`r}ZRB(BGh zBrDu0#@D^}&LjL1E?wAup$z6^3#B`a8Q|4bYWN1w7Dtp`XJwUFlFvPD3G%f2JK;mi z8St}!;M2Ey;y9%Qc_cgZmgV4gdA}NI3G`TdyNEAf_Prur5uu^I%VK{^l=;cF=sjLl zU~-fRi4NnCAwl;Gj(unyw(yYKh+tb4J~QH%HTgV-n0vRKc+>nVw+@1wg(!dSY5PKl z*5jcK3V*8{G@qLK^RK*e(^cx5;Bo!&b^P5u<1Z13lM+mauN1Ge`!r(TN1mR7$sq%X zZn=utYB^je^@q(rg_P%cx*+)%MI5=ATNyLtdq1=$V&fRvd2+n8sMJ{8 zwBYmjlh_@ha3+{pl-IzZD3GC+M9}($Gl4u)gtkSDv0_)!fC$d)2ZvU1Fy{x9Dt!gW z^ROa)Gw@0@UQ$U>xWZJ%ZZ7b6Xg~|BOtSFLQ<396rFWDHF{8G7?U^GGL^Z25DJ_A! zIinOcK$5?QDEW)5aBMHQ-I{4c-X}Jr*rZaj1MPcz7cNy94S$j+C>MgiebNNF zP4M^(POZ009zlDv&X7<)QF^&z%BjUcj$W3r>ypT<3?Hoo#<47;iXz=0zZ3)m zYR3U|Wfy`fNDh`L=Gu;CN%h#-zYx8Qh=*3~<=&Vg*q;HLQV=JR5?D%RrME++r6`Es zmdIz}Dh1G3+pBF54mJX%-WqBzzrnL)B=}lwh)sEecF&v3VB#ku^Ij7fFkx%a+#psZ z`lBe3bkAHL8SLG3f$jz*@|AfPCwElXw<5EAxQ#B3Pxi8>72B33! z3Zxg?is{4yEuyUxgY9Rjyx4u&nU?7P;pkWJ1foWhZ=ZoKljxTtv$t_H9a~RYmVQhF zQ6nlz`-IKJ_NM?b5@)5$Nl{r2CsR3;w*h0wIZq-UzmZcE z<=a1rHY6#5b;s2CoO)pn@jN%v)b$oZ6R4I373medOcqbu+Iw;Jg-1q0D#8O$ef>GX z(?i{+tKt|FQ|PfZ7qi1cU>(M`arnrbHx=P;&B!~ZNWkIY0ilZmn;6L_+=+iB`jUh- zwD26k;i4A=uLR(Cg2Z+js&EBOCw_0_(iN6O4`6a7v;HnrfZNCZ01RN5iY;4ywJu!z zg@ETf|5q`Bw|4>%?rnYs#F(rSiv-aIxddse)Nq6s@PptuS3d$)-_sxjtxMi$J5Sj8 zb<#X9De4qz=hXPAqSYf8hsayQi38TR{kHoYMG~Xdor-he$L8d!yGh8S9G$$eKOeH_ zqb)5Xz?0Ky2w+Z^62Q=gL2(RQ+w`9h^}}Lc;UD8gyYz?xXqu;a#)w`L4DClxsmrO! z$Md3w3p@*u60%+xTen!EOSaLs^&*+&`ByCL;CN91`(%d}C;T^5Gq$YW_tIQH{mS3I z*B5t{BBpVr67?SSdt4@FWU1-c8@rLS2_CsmLofvSRslm385p0uDlXV$;j{RK%#dEE z23y7108ZnK(fuak^Cjv$TPfjZFXX;W9<8^3sl+G)dPRK%S4ik$44tyt)ueyaPIpo} zYib6a3-wbDib~+OwHn5)Howk?7JcSHXI%$-fxoa)~RoDG{DhR|Z~D zROh}7oc*vmjghZ1;~|;`p5QitA@Ob-1bCCM`}VlZ4dQ5nT0A!ozMuI2m^!Wc47~iR zQiXz8{|vtUT#vj`L;2WeLr-7*C2ulzIoa~k6}Rm44f{D&_a&O~j)4O9(k16xj>o{DYk;)OJimHWI=5a^!!t2N!4(u%NH5xcXv>X41Z#r;oFc9H+uFNr4zMud1G%*j$Y&X- zxO@-L!;8Px$?DPNV@fCcZD_qYA((~W9hzFFyc^je9Ur#fO0oqBN+-m5!IQ5hg~0PYk5weLU{q3-%5k@ku`G2Ba)d{~~@(Eql@jr}{72)@J* zQ;@X(&gI>fCr--OIqUWUbMK#D(v+SaoA@4P8i;i}EE?ndlJ+I0u)>w9 zndB2kxS6fb8_Y|Ng=e-Ha3^f8DEHw*&XQB)+codaw5zKpA5}o|a7qv*HVcr5X9h)z zVNK_mV|JyNbm~klI>@@tK`7@=FjkcojMi}u9R5gmfl%7ro;~{gkgr66gISPgOAoCo z0@>upow&Mr>fvhdmzsE&N~d8_eAq~DN{bPW*sMP4t{SQ8Q*QUFX$DexOFh$z3H0Jx zL7JpJ#ed}B`hf9(@5Gw}BAD{lViaqqQZY!ZPW7esF;k1*JCA|C7y~j0xr7ViFZ`RO znRLshR#F(M49jYFWz$dLfQ=>5GIC!SiR^AcgsvFtOv8JcU{Q?Bzp$wq8{)Jc(H_^} z#BX`GVJR$miQ#bHLXPnlMfr=L{S)D^y%|n^m<0de%ZPJiE~Mq?^TJ)t|EgYgDCmB+ zh2?pn2XOepgWwOdA#DJsLxL3CK)7k%fw8M_m8K-4)LWp=bybk8tDTmKQXWQD#6r0l zkU>haafjM*;sAIq(#59!2`zqC=6JRRCc5*_8q{ABdxKN^JCE)w!Fw5Bj0noq-}2ry zsn#>evC-&U{nS#qD`T7q9#1E@Nbh-|_wWXJgIEDw72SRpd21LcwH-8O$IT!y7wP8B z-3JezC4q#J$uWiErJwYU*j0`ZO8v17%RUeU_u6$4+~iqH!U zDU&*|K0Q2o8Thk^D*AeW@z17*e~>7C_)Zl+krxY5sp2RN*S#k{k<8dhu)eYbyeVcu z)5p#&R;xxKf|3^*FVhG)L2Q4Ab`+85U*mtSU5w)o^;p=*-ppaM$v2i5rs2@E(%sa% zxdFjj{|>>@H789_dE?*;yG$PT1`XGb(fOM?GOH`i0wHxD*s>l-eZl82to4ge@u&u; z38MJGq9S~km?`zltw<7YKRxxGLzC-N#C1GS{AOWjU~;!==%HT_)DD%zxN|YqO=v@l zU%N4#D{|H;+e&0qgnci`B%7r*`!I7mhnK}#(vs4Ty21SVPkOBPby=5Mbci_6C76y% zciD9I0`s)q$p&Xh#PFs7N2+Xt0pA>V4S&jm7;})>I)0j~gMp9$n9j-L5rwt-{%bT5 zIzCX%mlaiG=?yRnu}DBMj@3k$T(tJKt-KUzOW-syURpD}G2^?+2Ak#Mn-M?5$Lt_f zaPmQ1;yDBMq~QAp`!SHGMr00Go;NAh+i5eDVkx+SZ9lQ#hhl~d9Aq#>V8BlaLrr)e zd=)^!^b8~nZw6i~UmV3(CBu^|ZW2mLQ_3g6M=ak+?vw=-SHrn1C&c}*y|xO zIYJVyzXz;kt(nq`bZ_-s!hh*!_b)xfb`Tz5p1y0}mp5d_1{GMZUf9v6l)@T^UPDO5 zuxW;+!W*-r=(KlPP28ufPB~?Cp~VIK3cHn%dMJa88RvOiSnaQ)cLM_>6yE}ohWlz5 zSy3OU!c&4yF}exhVtkSL!g(Rs? zK1WZ~zhuK}KF4HK-CR!FS_f`BV=&gHs$O*_O8WgIj7eoHsYF)MICM5+A#@dKrD}|o za<>@deraZla^nN)ERyH33i+@(p<;5;K26_WQCgU|LDl()R^h=zZ#X`~?j z+7fbGAOxm(16zYO!ldSvZNhm; zV-`bR5sS!_TRx{J3EY=%U{@MJ2giuJ5UzMfN;)X$3Z*};zpc4V(TB7##Dpx5N!k3z z&o5TC<%VZ_+3Tx(p{ZyDN{g7MQ5cL3GgSn(@$r(Hj@VuzH*BAK&yJXod3_95zEIua zW2*L(8HUCwBj32ec8C1e=0_AMuQg9uh{0L!V!{vzO7^pOTe%_bq%e$Z)HkThZQM?YSC>{VH08=La-Wc4a zki~m!W4dPd#s(=g9<}?%_s^!dm8w2)096SXjrk8)P^!MEBvcR{eqGy1@%L-qu>7ZW z*+~16!`Fskl|n3L&|$OX-I#7RJXKOX?K_`jS7SrKGHN-<_QLgf^&UOze4*r@LWcuo zx;9*6Wk`P>Og{SNqhWA*|A0$$Y)IfbhDVA7ka|u_enHze62GtUQ)2z&NXCPc+p~s? zeaD8La2yT14+uY+-zpt~~8dz7KvUW%JMvbd#*hQAR!&@1TDd6}bj!^VnjZ0-sRxtrJI>DW>|=Maq_ z3~k2$X1ub_@>O>BhxMN|F(_M%DT-x{7hG!h_wd&vqX0(!g;E$EDCfTvn=vHfLftbm zg-0j(C!U$Ct!);kk*mXvk_mMbz|X+RPlrKkEx z6x*4?NU9JkE5DM(Yo-y~&r#LyqWM__<$9&6Dfrq&yF2BY{o=Rq_uMbr3>?v0OTD{X z*2|~Mg8+uLg-yf4^0$PdTkkIZQt@!<=*5?o6}_6kZt9e-QXtZF(TS`A*c5R{?7B_f zMcdK*aO_iQM%pcNEc6d|lKE>v#{h!fSgIL_T?}Tmg)PtOdOnm2#!Q+mWe^*qibrH3 zz3K&BTOatQry76dn6(ep?ocyGoZULOOP>=-;MQzwx0b&tagz5nfECWPx16Q*J^!Kr zi~Zs|bmELy+~5nV*SDRzsmC6;<8@YkysuF}Q{MG0RQQ8?$FqL-Hl<=<34V|@--sjS zVKv2?POD{33OHzp_#i+7+-Fcw{ti@X#3WwE!6=g}&#KJpTOXFbJPxhVdS6Fx3wT3x zVizIK%Jt#!SFvn0%Xs?Q?)D=(4M2hZVtuomZ+Z@eX!74cn)_7?C-6>KJ4fZ>zdF96~q z_Zwg4On!>E#J=}V%>a9(Es#v~b}6`KcK|;Fd>#NR{Nq5#+3`!hzkB{h^zNQ^@?n9f zd&1`9HDs2caRu=4;6aane0;&LdI9rb`>*%Y@7|G`Axlw-(W*jiC5~zz1hvJiJI>UR z>&Z=fTJqRlB<;SY zUa(n-zL}<~i+PZCh4j-d)JTYLM-9`O3f{SgmvE!g$ai?BTzQwryf8D8!iGq5evit+ zPWyD$!){SnzkF=0DMa?x-GhvQu>AEaL;%wUA>OQz(f ztScAuTo`nHXLI@cS*4S*(S!hH5x@sl{Qz(~FwBG3ZH}XtKN@QGOzb=UVs5XT^`u2+ z;&1p&bOp!p7UHFMHaMRU#I~`gIw1WBFey1teRJZ$YYSX^e?hl(?=5Zt#w-_Wqa|7F zs|xBN@#o=2MOR)@I5mF|X_VN?n{KodW}a2vztI~s^G+q)tabgN*bLi!aSRS(h)v!e z3ncS?`1#iH{*4FgyC!eK$a=0+fXY_^Bt^WC96MnA%|!>?hchLC&%-!w%(;pUXrx>N zC6bE8?}uKFV6BYaJeX2=q)K#{1&a(+j*|ULPbyT! zyUvdKo<5rWKD{xq8G|7W`H_b0iL5$g)x6%*KrOwBp=7m{>Q>m0(Z z4}@bUatb`;b@d7NwQiWQ2*$shiAfdIh`IpmchA2T*3e7a^tuUllRbLtgHK)J+y|+J z6P^iBJ-}m)7#!e*%YRn}5{1VSI3sxlPGdXRUj+G7Fb_DG|CADdenb4k0@K4UR#;iG z3aiCmKKIgg*nZ8ku0&~yA2gLBCuCqY)Z!Y^7ofw$AirP55vSaXjKJ8crBJC?X10ko ziN0h%_^I;a^|kABS>E3Tz^4l%zZjea{kKn1xh!gETZ&8mEbrudR8U#)#UR-41(f|D zN6jY;Wmf5z)Z~e^cqZ1}Cb=Lm<3EImX!Iu!3?@{}ITE-x2=Lfy`WeOBzkNei3ES4u zc1Fy&Z1h>|H zmM%CCxIcgSF$9ANLu7`{0*x>Oj&S#{ehATDdDBm&Wi67PNG>z-4bC8exSe!H`mOI1 zOhOjo^2Hg}<_YnQJN2X)XPuaBOlnw@S(N8oE0!8v9=~bSH9Nbj+U^^n{U45S1G24Q z=mlS-t@Wr52zSJeviwth)j|XwMuo~O|76J;3d+yMLk9{K*|`TpK`F`kaQoG#UT zPU2V9y-6N$-w+!JG(why7#uOc&w*N{QNF5+b9CjJn4iAPdl9Y1-7Gc4@iP5D*<@0==Nm>@;Q_SM$KHaDd%*3BKrOdaH790XuvIK=&>AY*ekN8b5 zwu#Oe)1iGL(i~J;4)`5#{>0zuj@45s%d1&VG7Ram9cno*0(;K~@ci+X;P9-!b&1&S z{$iY7punW`C6PJVY}(%+$E2!J@d;bi7|}9<2V!rnZL)OcjpSSY4<=R3C5W`Jj#5*?5q(1@c!V-EU* zC>MNg4rPH9>N)0JwZ{NqT-hCnIqLw~VgrU3ghaKT#(C+=cc?5ShF=US9cgprO_)Hk zvk8>8<=!1un{b2~;uF8RaKfPWtp-Kl;X9m=BVTI>pDMHQ&n9cHBiJfGX8mC`=xTCc zp8YzCABNU;?hCj0y4B7@`LyV^H!YdFY*q6{EG{NgA;#Q4*_4}rbRN$GhSdlWx9ZXJ zOY-ZEGzt$Mk&_)Hur%mzag>1K=E^`L2T88juNn4`kcZSPm0!jf-ZgrGKoe)JMH`7u zoq$5C#yL5Z#v)HD1V6i>=&N4L^5M?K3B~yh&trq5IOK59$E6L2-=oy7(o{L?Z?{U^ z96w3_!%-Rub~a`yXpVX6ZYwYwZf{$-Av$Ds@pMb>m!!(PxYQ*--(hTxir>xctwcfr zSPqM_8?<=1@YMv8RY|SGGCas5=A?zCu#LKXD)(2RgF^t4JYW>I)vg+rrw9{I55(~2_%??(qRDoA0wAr)-TQTF?K z=185XwTN?*I{L@0hBM95ZNT85f_m`1ibaWI3UT`mOOf8Io7>W)Zuhd!JUDO$Il%Pa zPlnG=`jAy;lCLK((EUiSJWy?eShB^skIezsx8@( zA2Oogs2W33mE%6mA0CZDr&Xmgcn%-9Et~Lp(-Z$&54t&IJ+1T^auTL0L^tIgJ|vBZ z=nmP)Dn&#Ta6KFd&)7D+xTSQl;>3yQiCt4s*WH-ZBkvSz zeJ8}5SMJP|U=`$<7@Y3qJPkWSxUOEU*l?yeN;KYU{wuedqn!Ci82wJkUJ37sSd1ze zK8lsPbZRa8<0_doOn+{le(@#i?R#|l;1Oz~3`R)$w!gSrch1m}1(Pk6+L6FfZN~1y z!+KQm4%l87#P<5+IJR4!hMv&$n(BK$@$$?GXWT=i;#|N-azlhJ+>QYgd)wlW)G|Tx zcIa~ADLHJ0V~RYKw22IIs2>-M7ZJX{pG{~CCU*V@8=~v9AXG1t5lr9L7tgl4-D&uv6{+B zeN<|SfREKT9YfP0zKrcG_TB!L>{hJ3RiFo!UPD+)kP=735H@7mdblKG$Ff%NRYYg; zo~Ql`cZRnsOaj;N0in$NE0hMM7f;G2$k?rXr_|>>(U}<2e=og3rZz+w;*d;e-=A4g zPL+}ZrcW{Ku(8c#vqfC*O7<9zRICP|Rr7aUuzzlf7W;Sln{($vrDAV~6ZTYxk2s>f z(H{VU|Ncft3?XORt@%lUTj=)Lq0j6;C2&nRAY3%yD?%W?!Yzx{`UVCkEXiWzB>jU$ z6L(ppzz2l)0we-O0wi`+$3D}&xzqD8^V!@bIQxA2*4-DV_z!I8(7zihuKJaEIY|>^ zIm2d*gT_v6nbfx538o>|FTnp$NYast{({SIg{JwMTw01PbD|aK^g{as4HMkxS%fL~M zLF9@V#uZ-&D%G8?{O`9ss^YURA3*?;ZN|>-6Uuwf*?=7HrQH2b|OK2zUkTSj6+u z=LSJ%J?b&>%$+u8qM-XHt_bwC=UtJ+d%G;@UVWmu{N;$Bm@^XAsQVDa%%3sJ1SRml z?`Y{Zjk=5zr|jl0I^-wjR5d7d$mS^xJ8h4|XSX!ge1gxSN+tTEB=y4kV8XBNJ=*&H z=^;G1Jn#zj*i_~*9Jvm z8cj03vJzkah>`a>3yH)Tbh^A-jB?9(pAe_O!hL;&m@o8faPG-f9G)uD@<5xg!41|7 zkC>f0ijnh~Nee+R{+kUkPdu;q`DiTBFb}zZ`c9ig%WuutoAOfV)A*xGru>Byaa>nc zOb-x=!%@wEEO}+6%jsoSDZNqXkC-hW>88+B8#Y8~E-!Rvru13$zY=%~5XZL%<^Fgw zcaFg*6Wp0pFn0ktB!8uAaGXeH#nXdwtry;c^exo+L=?|SZU5v7AT;@R(Ir8@F1lYX`+PvU z20@eh$ewF*-nY6qZxxfW3ad%;`5ZuWh}xh=$n%MtCpC{;wj%laE*!rg9^`aSQK-6v z2uWb82uBr;n6pJM#Ix~&@y2H<+aGzUYMdl~E#Gz#wJRod@~d}T@c!VNb57^Ot5;dW za(wBK#8GiSlben#^Fgn+bA{6VofHJ$n11YNmAT8u_h{26tL#YL5_WnNCh>k|{rtBP z{6bxw18#bl7WyzoE8kJ})p@SFzs<)Gig*R^M}tr~%93*sES}5L3#lI=Nx5P`8)uCd zkIDhXAzcH^i6f;QXK@Yb3=N{XXMzfMm4Y-mP*JQAIA8pC6eBkG5!g|+;_rVtk$6Pr zb~!Nrwub!@0#g8@3^;t@@3OHk{uwjH{mda-=U}g*sXHouI)e@$L9Y&aBSz?I$}TO{ z&5qSl;F#;MFN{Y%Cbr4>c9yJF`QfU@jQksgai?aCb`y=e#xC;J4t$^XU))xk)>hrGPiz5f86*v*jh{et$prHT{zzP~u9^CFMph9 z)!Y-_^@UGy#DDBthv2=)P8ZmT)q^WUrTR}ZOFniN-?NZh|5D>r81@V|r_C_aI-R^TwTgtlT z*kEYGg7+1g866G?hfFT$#x7w+7@tT;zx^7P6Xs7f^Uk6cgfW0c_=AfmHRE_YCv}i` z(@jN_P>uTaJ!U?PBt&c`?(}ylC~E1OU6LaFz=(`Cf`h1Z?kX0?n2e&x_D`m73*m!aOW;#6?jUpTp#X zl#(0d@XLTVF9r~`bbHsU)oyyx7+R-Cc;mdj{$U8R2Z zNu_*84xZfET<;w3tSTyJ6kw1xnf0OJV$nfOamy*@bL;SWoZ2bi(;1i|QY3Y(sou^f z?%X;ePIv5Hg#oaU1J2(F#reRYr_Z_|A>1-~?YlP(aRc3@0n_E1>2Z>)LNjdOwTxsL z4d8Kwe-e?Ke)6lad93x!5`vO;7Hh?!mFh@71fa9f1UfyC(Wm9srg=9v%Y6~UlE@(~ z!?1irVZ?||9s^0}o#@tVLx%!?;0I&&bKF(WX*m62_ze+I0I5qtq%MJ0JIu+gHcU!q z-^Ng*yo8q`Gxi3hihdCEqM+Tg#0N{v|NLH}$hA8@97$_i=!m8T1@LrM=+kv?vv6h0 zw+@|CW69pb$UbV2FDgSleFLKCxE+h)ua7x8J#Fv_gmGK!S|XM8Dp0{Q;LE?BT)fYg zrKmuQX@)O;{WUXD;m~foLU}ndn&Ya%fyZ;fB!rm6-=SZ||5}`K%JA9N0zTW|90MX3 z8S|s#{Y@!$?6GC%zqdJE6x?j`i$;yxI6uw{Gh+^-N>2(T_IsPs=*Opcu93;R`FzmA z03m@jdW}lJ9@e#Z&%xHHulqsr7CLWI5`K$m#yMftbfli3Jv~DifryVJn9`(~@T%!j zv0zj_{gH4qJ!-y`BZnNL%^pr3I>)*kAb4K1x2d&RkeXyj7TI7MpHFG9C%pX^&L7ixm8c(xC)lmOf!@)J*FnUok>3Jmc?!%8d{)>*svOiYqe7u4V z(2v~Ol)3=Rk$~W48TrY2{M1czAFtkj8FfpWcvQTAa>w3dhcoNskSom`(n)4Fzr^n@}=I$Xu^mTMbtCPiUlqwgoZQLm165-7YIX>hOW z^G8XS9>SOR79&1JGkkV^dF}ZkK;i-WIG7wTXoKy!wbnJGB5HEH%V=ey^+9DW4ZaRknZ-p)XLyBj`$x2`#+!JBSB2 zRy>XI{zs`loB+V!pkE-l1jG4Ge+`cR_GW9+rY&AT3dGVq3FJqOL3H z;<{5;?zGa`;%nI)A-({_TyRx4pfA9aVd@Z|o$bLeeR%s$=+e!^1x#AdVE}N1F0cnw zkUhYx6S(g9fRfzgH_d?Y%*+o;SS5x6Dwg_N0h$TJ^mG;uTdk^axv*$iekxfgAmq?% zi{!?0t*p`tZdGhYQ&!~gdkHh@nVOjZ)@lx*ojc#eFbAqFd3tU%a1Wx*AKOLmiId@x z@bfkn)^`lE4!;HncR$7_53Gbm_NFp3WeEtAZ)nKfH{;B?zRY>Kh&PMRhQWyp8S5HB zG68I`PhV{Msqj*5q9z;XhGeO$y`T$nmeUq9EonCoW}`=;d7Afg^w8K{mo20MFMQ)l zZISKHimy10!rA)i@vx5ih%j`}p6#;gI9f2DjW`;vYUVk-w$w>Rk*V%#OWj8g9ISam zd^zyOPY!BI5_Yvz5M6mp4snR+j#afuBPg>{xhhMK<_4tNI$?1;8Xk6}oI0 z4JW&)rd#%f47t6uqNX;6tBcP-{R6o>fLz`{`GS4+znpJ|oH*JCi-)8aSg~(PHJ1KbU8a zjoUb-pPXYq8KlV8MZysMg#DO}BJ32Ad-$@yKlliEPc~Jab)(bo7WltjYZ9p&kBJv` z(PljLd!z3h+_0-|5QXWF6IV_Iudnq=FYcKgzinDG6>7k!lQN%rl$!ti^t9!2b~Y1B z5s-A<2ZZhj5&H2$=U(P?;}~wZQ%zQ}tKqf(^MY~63yAE`W!?Su8-u)W zBQ8Gwx%E0n1v{ck113`T&|TG%O61hI`f2cx?fR~1>fzAaclGJ0(7_9VMHfsOrk)dN zCk+b-1J_Ney%eNQgdu!;D&Tn0$NpUna9&n68EcJiJ6lKVGH<1j<##C--Z!Yw(FX|~ zJ_Iz)DPMaS-3*%*s4m9x%9`tK{1@Ks{?#xz&Q;UZbWci%r~)O<28cLuB|Ua^(0U_R zL^^I~XGEN$Epq24{7;yPfj}6TjZES{VpGF3V^;yzh{8}t{Hx1Os4#;Do`3ku2H~w+ z%l0&GeuU3I?e8BMStkrhr-vh3&wx*;hxi1>+bmd3^o)K-#?4e3p`X6YXNLRgA;AD( zel_yWWbXTHJm1VbYY)E887#3e+=TZ(SVf?_(MjjkH3Q|Z`xRlJjW-s}rttM$8$Ki4 zudwk;lXROF*MHu3i6i7O+NAgvWX}5v+dn*YxlTNZ9i6yASBvzrKEWy{_2oyhVT~WZ z554Q(aU0x-7@?6Xc(Lv53c|a%s>IMXqmG#%hY>xTu}bMp&&IUP+JuwY_8*ZzXyc4+ zwU3-7ve&yQdpfDUH4VQRr&X!xLn0DjdIfDAV1^nnbz*dezq=IPs&lb>Mn692@~8VIlCD&} za$@*AyM-!G&}Si5rK&fn%qF57d9GbH=sLfNPQF?)9-^Y<0+f;*0%-dft5P(ihu$8= zTG)%RU%!6dikv?JR7ynB3|=z(m(DOQ;J=KY&%LP_w3^fIOW3N1R=KT%z_CCV0&NTl z2MCWGtKK$cV8F&yk{la^+glMKkVep@i9^u%9dc{yi!4cVhnZ_JF&ds%IrYxrZ=g)X z5s(cq4T#?6$=Y1_NFL^X6sGD1X^&$!h7s8PDkZZ!X;h)!V*16TLdk};^68yTt^x|) z!J#@;zVYtD^2Kp^b@$J(*DCIN&D^boA8whxv+fCV1PR=J33| zDOaXPVO2KZJDl?DQ7K988R?u^yb*cxZrS;k5M}F)88!C@oojA|EVJ90*$Da~eOyAB zF6<=FsMfQ{zKOsll!*1x8ENb!qWOc?T>FS8 zeoyurE>f>%x7>Y}PTw)hn7=D8+P7ke&i-&Pgj2!E(ef6u#3#wfKwefD5K2GAK+TyL z6igMS)&86ci(4LXnTR+sfT-!s^I9}49f|mD@0;AWpQS-f=HorE$1KaD-k1^?z1sAI zt)~{|8j}3wC=09nnLk0%Kpb%L=j-2C1KBj^-qZIbi%y^KQnUrL&Jk-yR&#+Kwqh=Sq#%Rz3J*>Iusf_qoUZhfa% zD9b<%=PI}@cFjDtBx|DZ7j-0EU`v^5TZyvMW3*U0D`oQJdmES=49WMzW~sRI*ltRH zpK}^0ntE`MlqQoWDUy4XBdpT23S_RJP78wIskrK-hdaaX9OH{bYx`-6-~sEvtvK5gmMSP`?Ng?s41@D8M<*&46jANgngGL zB$QljM6)7WACtYuSW^~6<}7Ux`@?+neu@8e ziIN7)a+ea22*OxEHut%A%c^kpIL4ylIBD$o!d?X;Ed$NF0P^^8 zy59txruRMRe>fYj`IcG`mY_u=`woEf$bse`qg~CX;X317z1@*hGjZdDU&u`wQN9Tc z!sdg^g?mYuUB&tAsL;D^RAMmU@?O8`4>eGPOSjb7HkIj`}{Hjc?qjujk6R!Aic*%{dy(=nZ~f?Z?g~kk-WAV2ICg~b*aZA zE+$H$TMVnD!0bOAdAhX4$oroQFXjHo5mI|GqWjxVmX546>X{UmC^9S6&a!36eMw`7oFQaA>_?ti}^d}l5S~V%GWGA zyZGkB-1@*Jh~d(+#t$yemhH~!KDSH9$rb}9)c5r6q))uUdsdL$rQs%Wu8<>QB` z71#LDLK|+n7B}>Sn>)tIGzd7M0bVB$guQV{*h}x0HG+$5Jw~7TbSPF$V>mF6-d}*q z^=u(g$t$a(wVQcjr=a-e(JIYz&Fd5_V+JUh^g(1YsJcV8dXU@qX{Mx+(^9PFH@%SW zS*lkFrUg(!q^ZD$y$Im|I)BOD7Xu06&M(n>=zq$O4MgPwx1lvBPs;aQCm483pm)|c|l#&eXV zQsVDMS?H^pG9(1%XYu-Ef^LhH-TMl5zyRy{0MRRn-eQR_Z!+}GPpbtk%+CDUukRHv z2CWBKlQn`jDg71O;rX*<=3n2?e)qyA(Uu()jnqFJ`h=*RGo1zjP#p<8bm~uJ4!c2o_^r2jwF{E$WCzYs=226U=oKbuK-u5!Bl9OTERnWVfm7(BW z6MyqK=%2%B_a2f{%D^SEs-0eqY?3_eL{voJCwD+TSy($p_`Bi~KFu|Z)~`}=xFwdK z98g3HFyDaq=$(}W0}p3fE=%Kb`Yfhg&7v>0GLe7s4a7tk3G0MNx8m>V>&vc;Ixk|I zKfgs=MBapkOD(_O$(QWsZB;tnsIKX-o@(_5An`|lGx#PG?&V9D-AW;|3%o;e-B3v^ z1W#vWSJkOGvxrQ&(%BA=k>RsZmb@Te+00=ZTreVYM+PGhN2JLlhYa}`-X3nS<{6% zstQ%ku1RtDoi58>lNSii3FmlvG^Rdc%;_g5dy6EP&EV>URM8;!{Ppkp8=|vD(?fL$Eh!{Vsg-^YU|jBW9yn`Of~7$SM7fT;3Mt|bQnvYf zJ9V3P?=DC(=s2B6)#rEp&=IWb4YQBMX7P^42g>c@#dmMWRPiNAo**Y0R412T9MCN1 z$z~mIj>=%hU11s>I75tm4Lj6=%swzNzol$1SEDEv9rRMpXg73t46v}SnHGDYFT8zK zH>fIj*`q+KBUOJ|x!)bTh_jROMbE9?+KhICfM_ed7JMb*A`RZb)JiFqq0Fg+^J|v2;H?#e|jE8Js^InEBz4{r{yEQ z&=IVYAyIaK$i7E^6W3sNexc@-rY8(N_j7Vupb%4)R}q-B2+0E zBvPE;0LKevIT?_B$87ApWiDgM9_st^o}5=}ta})x?A{qj2u8>MhhU*@_4s>;b<8C_-y9LAq`=nDSa0=P&D4h)d_8>iT~ zehVKKU;JFCIw4_nf-jWS?z>st{{RVnkS~}aUZp&wGr2(H0lq@`q-^P@4Tm#E_Bj)(>m#YU`Z5uCUn!4H^ZgN*>Dy?62b>G9R@A~ zo_CU|a~reMKsq5VH;&iWbolY5pI~Oh$U%E+X(}|$ZP7AqE`|~h=6^1t2{nwL1Is!p z=QyA*CfCwMgzE);$^&J?gRt|_d>00lHJdi8fMLcS64oO4d5$^4+4@3)b(qq6rP1>i zXclO$rs=!I`0{5#`WT|$5)2tViTqoWgSkgPqaLRhZur%yAi6VP`P~RICSaJC1@ni^ zu`b)LQ|z*=`fEJL`fhXw;mR2=iLHOKsmL0oH&!rzX( z+bVu#T+#L!mBd(8U7u*jv>{-$xO%^7C6R_74VQPu5cdv;e9{K{{-b;7IbXf#8FlRB z>wb-s%xmdB5@jsFe&#&Y**a$n=L!S~&=IWgXQo3G!z@CliOvWZJT2uI?5 z+rO9d=@eb?d|z4abs3A|*{129p&tF{Y~pCpvmbq<#WhAX&b`%w3UawV%_hgCB%;0uR1v zO`xkvTI$1Ronb9!&Ly$0O@r+B03yMIh(t_MBXy!mDcr8$;TFqF8<>mX09elho zSP~IrNy6qYIxjqQX_>wdd!i!~Fv>P6Q;kSkb$}Q6L0_OyMSP8j z)=clZy`rMp6&ft?1p=U#BY`|#qI*9v?KVyGtJ#!=@HAfHe%T7`U{o2vCf*26+CW=S zvtn2x>D((3yH)+_(7LrnKY0!TL^SlQu}&oHZtfQHRL;efeiHG@J+wNz{^yj*>&w$` zlSPl75FS_WN^3iA_1NhPIFRSZJ>?I7m`{TX|I{?hzBF*v(wkY-x`eCeI*i|ORbi!C zrB7b!ZfH>31~}w^7Y&aC0+k1-=J`lyH&PfZ-Lm(2cY0%lk#&{&ztkxp5>hEJ3gq7( zrCzHxxbQPr^z5l4&%#bg>fHubzTgYyK_QI=0J$oRoc z{xYPazN0`N@CKWkwrcZUFWAtAKpshsorTe)-RX0 zq`&V>*dKDgGZPqZ8B>zXx6DQ>731-VgW+y?`_sJ-HZDK!>Le(2RmjempQUotkgdNx zmF{@)b&^;tkL_A1hNd%l0&O|6=mwl3^duDKgo0G+rNjuflXEpDs$Y|C@A+6S*4|qVq6evuR76uYSfET&M8$DY8WYynqGr0x>cDvh7zkVUb~M z(hZ>|D!v_g>0YM35(fn1yG(_>7 z8}xk=%L>zeaHUn-gaLNBi{y`kjE3msD=(IqjJ@sjcf~#Q{N=Xkfh&Eu2v(HTtQFvH z#Gw=!i)$WI_cm)ZJKj@`2djor?%e8f2bYgjGe5{5;OwEf7I;J&w#W6+^{bRZb}wVY z)e%f&oe$pOL7aYMg+r|XiOfMys49WQ4 zXs&)Mt$z`6kf$a?ebnGUNvm$plrl<&q^)8Bk?A=^@Qe!Szpj56noM&sx%6ba>4E%% zgnD_@M~VX<3A7O=zB~@z*3HBiEL0GGj#1)&;*M*8$OeLf4FqfDLyTMYFw4N+7&0GNQ0ig~&X4&UKg!p6uN?iNRqVX!?cgRNDcN@V?PsW;GeUk2 zZ*7-~dj68>f=SZt67IUUEThocWDtSGr% z)FW1}Znu)3+FD!}vP@LM_Us1l^aZTr1;jeiEp=615sm#Ctt3ohEMk?~AmexZ6BeK| zR*sL?in2mfzv;a~t7%!;uB)A{*bDqG7Ne&^UXYPFz^TTHcC76(`v7etk!KR}q*)?v3O~Xyn$b1`BWoAx3 z*MlUbGdsBgSk^JrvLbJg6YHc{I=u=&SLNs5j5#oFwE_R}4#>@A>jA-ga4HH8mlL5Du#6Fe*N`9`kr}}IerasmCR&63ixpRnfFO7R9jI?z zzKocdVkHbH&%uAu4tWM*+*La}y@dYQW%8$HySkb6MT;vJJ`AO%l0_fhIO!4*d>GkL z&)fYFec_v%k8-J=+?r!y!{bUO)yq0_hVCyT=IRQsthHSWvj!(#fj(mc`epqZrmKfl z$_I)I8h7f^1(V8D_hkOZXNW?KLc;Pf1zvF`4Z1=GEt%{}T|*v+O7ed(7!8~e^H0?K zOm&Yd@P7KwHvR)Mc+@$u&dci{+6bP$1H1ruND8l^_gha~PGl3FUJ5_!r^h#D$2oGS zM-eE@jeK8?CwV7Q3v`zItW|y=uUP>73XKFEIvjDoN3S?}i*~e^SBQ7>j}1HJq@9m= za(EgVZJ2Dwf& z!!5Gxnt-Vn}*i@Q&2FEbGSh}=(OkeK;byn^E}5U-lX&aWR_m8beh z&~kh0xgy?Kx}^b@Uy4w3)6e+M{DJeL#pcw94Dyp4bM?BWa+FZ~phBtO8hR0w(ENV7 zJ_%cbV3e|7fr1|a?SrNk2iej9*x^f4-t6(Dz?GT8!}?A4$VxVk|D1CGl<}C(8F6*} zacyygqFSd`!iujOn^HcK*$-?gFO+0f%yA;X!S=ZHy&~rNX<+hp`^xQLlu8;yR1$8v zli-#>AU>sd&d~Mey<-~d=j*r5P7Dr$NY6KjmJtr*+4dePUMuN7IT?;$FyE-TJcbgG zan-*$4DpOFwnXFN`AI{pSj(&{UOk*zSF;e)AV4_#9w2`#MtQ#Ad}ZSwBu6r&(hLOD zXncvP+sL^zCi6nv3!_N~v#}2&c;|zPo=b$l&kiKQ2y(_04FZh9XekfB3bT>mSW|Tn zP~+R=zSlVa$-mOa2ZsJw#HEHWa3v%6;>%=3P7%rk&sCc3I2n>yxMmxkSZ(o{FUo-K z5{(bz)d=65*2HJkTQidPZ|bnTz(xrX4iO^b0xR0@yYDfQCR3QJ&D{>--%XW-AkNYt zQHK!7G5nEGBa0tsqMqXYLgmbXZrNy4cb*Q03t|nrN(9$PR47-HLgPPGEZ!BNW_Od) zJ0LFBxc5}+K~zJJD=P|_`N?k8kF5CJYe;f zDkJk5PXd`muV>bB!w&l;B#8+~4Ei7+zi{ogm|UmURC-PYC0%rv=dPuq*g9&r8Nna{ z!>rSaban8^3`_hpP<64yP4XlqsT%K(%bFdCd9riT_1`__t68%}^|F+9Kuq3mK{++?ED-@0O zIvL+qGebwhRNWCXg50Z9WgQ zc_RA|fKs%A&qtA6O4?^oLE|Y~oZ*=N4Bd4RAG^(mnWI6r`BRLU+Os88LdyaC znsv7FU*}FFS6iQz;+DRR((C!-JD@aT+_>@ush99?C2FSiG#;1o0yfC0rv8M$9>^}* z=N0{)5)z@CSGj1vUdPD9k9XPae;|+?sG>`hD6p%rrV`yXZE|V5f8+R$&Kjc5Mj)tm zkPt5H_JOYQSJHsgK$_0Z#C__(QoXpdC~sj5p*3e%I+_U+#Fd z2TP(1tl@!d9Q3T>(D4%-wcnRB4IF-^zqp=|QPL`u=6}8fInxzb{~WM>AbXcf(!)W| zsH5bOSsffZ(jQ2(bU@53!zAp&JufVrE?L%s9kkr@39~y?66>rxC-%uQtJ6zDn`^k+ z^_inS&u72gpSCg@StQ(|DmMTqnusxdf00HpR)J=p((GxuWXCd*17*e|lF zLc1q_rx{=M3xY;`<{SGU+q#oXIZm?tf}bx}=tZztV$b%SQ?pI*3&334e*%&Psb=@y z9MFj|ki_5ZI=r^+=<+&_X;o_gZj0s6PJRKm9)x>`|k` z1HJ#L`nDi??=@ODtjCceF(-0R{@i{0_aNn3h~|H2O9n(S;lbyzw(auCOMd9v{-|A* zoO>fRuKg#Kdkj^IpXaX^?%zu?3V7coG8@hL_}(v{v%y|Kl!qtL@v|xQV1Eq``NsxEZ?whXD(~X$^od{_yfM=cddC!~MmZ317$M~Bg_PMC zxqUhAM=CJijrf(88n~DCf1w_vm&3-JXK=PAr@n}cFi_>+8G5zd+%hu=7REEu$BE^F zAzW>vn9=1{_a&6LZC+;~(Vsa>-d87Dm(r4N^-n3$MDi{Qq)V!aibV+H+>j0?B^$-q zCz8;9ikUIrK*oPv@z+iYQBbvDq=qxwD}zbr`e5VPTOc_BSTU3kkLyLdI-R{$+R)PL zMZ=eD+Uq6XY4XRrVndjC0s9+0P2Ih!`FfaghrY0or|LYuzy3$j+98TYPfx%}8QMa> z8^^}&`vqs#_dLL zg){Mh725^qKRCa)z02`n^C2j-to}Y}s7`vw?T+&IjNoLSze-L<_EMZ#_>#BO5AQ_7 z;qbmNzeoNP;LlS*GjD->FMV);%ZzEFp2OW}zSte#!nN9~H_isJAsUtt6~f~M+;IPQsq8hBbSebsdN^Xp?Fs3R5u_y zRyv(9BuOE{`Tl{_%S(6+SEV;a1M5*A+yMFD47v50&fu~!qg^&B=BdSPchAY)qqEWh zO#4EhU!dzFtuGL?LtHPK`$NK`hkpDv(c?3-1^0jrvIjn;YjV5%&Y27EZ0tLlXZqza z%YL@~an8^)6~qc`aMi#uyD0hZ)8@I90@?!)r;$?>0q3j%p`#wF>T>fizSUlMryeua z^S~!vx**0H^~HXWGZh(f7d!&E9>qFus}WXfg+_&xJn>ompG3C?`o$fO`ul6btkZ`Q zb@E&c{WyP#q#vT3vnm?i77#B0V$^FI^qG5hFJUR|rbdfP(p?-+*ZUAd2={BBooIy- zuM~}c`#-j>GOWsNTQ52!6_D;OX%M7AN|Z+F6zK*D=>};K>23*W1nCY*K|;E_8}175 zoO{>(yPqv{Yn=JZ8Lu!)Yt|870jwC^LP2W~fU=?jJOywqXn+2Wnc+KuUAuVcUe^N!x z>O11Zd1>vOpJE;hoF=HbCXnYiDl;4`ERvx@^8T|zcHMFk1VS*5`vffDsD<3O8(}5G3eoh-GS?FQoQ`XAFU$3@VcLlm z-JH8P;Lc~6)TeB$Fo3n8TEnJ~!BCJ5fh?>BxK>uJ6X6$L*}=aCt4t_|EvQ_Ki;(+K zHq0;7qWWVw3?S0tE(6>(4OAN&Xtmkb!f42q)QJ))e|9F0^45+ViGcgzz4f5DwaAe@ zCUrK1%KyS4ybbh!&-Y1Nu>1gQsv#(D9a?P)LsWG?S4&aO;FdL;=%qM1w|$oSSO0ne zC4e3r7be-Ju!A~1YaCAz)TX7AjbCOymm;=n2M`ZA*%^#>*3{+}TZ3+8{ zDFe|c=P5%y5>y26gTCuw6rs-d0T;--C_ssgRf%wldwh1VhFA{##4K|6`FBT||N4S5 zs4u`$p?Txl@A9GowV*%jxfQMYGK#M>n4AS1GD5vE{HO7fk8WD@hP(B~Cfh>23o}&# zD4mBP2>*!%X8a!49xFIM#EevouiLUM#MX5`{4l!{r(B z4Zd&GN=LN+toMV9Wk8r@uQT|XOMe89lQ9UfQX@43B`~R29@`6$H1C{wex27E`By5G zpQ?RjY{$Z>pYD`Or$*RL1^Hq7gMwn|@B zc$y`U`2Zm$pGhb=NY5!IVi2L2HYWHI8?qqxNu z2b$kJV?e9UNN_3*MW{Z1Y$u@Lb%PF>{summ8Ps$6d>>{rLHUWTWS5A|l2R(vw;SyX zCg}tt&uQR&!tS>XXD}%h9oVr1H}E(JwuE&tblQQ}cZxb+zjB^dqQ84mS&75s%9EQ% zJ=JmFyk7duuJxy4R+c1s*oJ~@`qVGor2yVRvs1>TXR8)dRHd-z!bp8*yi@k0CFf&JkqM{lim0U4C%09^+cygC8-qxJ9@G!a2by#`SGbEgi@i4e@!n9! zoWP%_0_=;y6K?!5 zLn+t&%>a1zq{nmf_>Ww8(@<0JgC7UD{@(~kuj@J4mnR>M3h9`zMPy3zo`rWW`9G+Y z_YstyD1@w9U#LEz;v$Y0aaKu1X04*50rwJv^aLO3G{;6FUdBg$$#E?vI~TL;7`-vi zSkE6EA{Nw)5|+_m)QARcGu$5^`cV(c88iCX-3iFrE8w5Uf%@~?$C&yFcA7c0A02$v zN{7(|w9{_hJUkXYc!Ed}1}TlR_tY)ZAq+>fF3Lf{hxn`#RFy^!c?P5npnt{^gJ8z) zaQp6X@}Nnwbb)BBue?zCb%0yjyjYBrCOJX6qFjmyjqzf219!Qcm)dl>uV$$ zHolXO4J6O5g%Ffh@v-nqx|S?Bx-g&}>NhT+%ZiJHolJ^B`0 zmPQ-U1KlT&7NH~{WmQ(+*o7C^VI7Qk-G+J?&6NM?KF11j%3e^{sNhT8W~zK`vs8MJ zkwP-rgghq-Z(P$ZDaY<>51_hgKiH>zc=DD| zCm9*_RT*=krQSE)#;)?;kj)C)RnkwbU#aL@ilMe#uXK;j8GPA*Ser>CxebiifIsEO zPIS_d+pj)izTwbIjbZh9vzH%(@7W8)TFpYCbkUYN9`&)GISrM)Hsg#f0q8->==y@> z2V5F=sQ33s4Rz{kKrfPMyXWU-ug7p`rMPBTOy($H>Ugk)T!FepvQhOdW!{i3ql+$o zsvfc773Hbd_hS{n1QygC4%sgWvqa_ePnrE-YJU3>T_#$nWc|N-I|iTtx2X8vHd>CY zwVpls{3!0L`jF};!8QNo6QGqTQfQQPmW_3T!0dFtEiv%N*%elX|y z=H+1-y?K9W2L7y7jx?g&%sT+U9ZV@6gz*9w3v|fe+^+gCVlIViFaQsHcCf5-cb1#6 z6j+HR@?$YSV*^pNaei?1zl`DWMN<#n5(92XaUO%UJKQukxk(!fP+*8%ocqLIg_gCy zY@lsi{oz|I?zSIHhA8yt)|+_iz3z95 z&7aCA=WxazMO#MGpZxO)g+QMGY#o_->y%f2Nph0@+vu%iAv?TkURnm2vxmVcSLiB& zyI3{9eg(DXwU#31Mg$~$N+*NUO?zQvs=3N)keHECwjGv<8bXVFVG!R>Y_3b1^BSI9 zgt`A}P*=dLi`;8he@OL(bflwZ!zdh`v#81}*UzsMz(IOY>xdVWRh;j-GEv-%d(&PS zd|j-|`4!fw@Z9rXjdB#~>4irM{_-+3qzka@=l{xVA6b^|+6DKzfo?DoYPxRnYv;ki z#Eb4`$>LOiV3mWDY<|SUsuWPMPYX)e;T6BX7~#ah?Jj&1e3Q zLW4>uwBduZb1dS{27A=TQtb`1;9sy5RT}qSmUkD*W~8tx`A;+VHOpbDuNru||Gsk* zY`LGw1>p@p=y!5ybt-=3gl3|cWBWWNQIR1fzdZCG>^z5hr(gb`w9sfihe%zR_EqE_ zh}QE^s6mJ!fp+&Vl$?p~iM|zm&+VA>%2WIL-Cve^QlIkO2N2%^rFtTfBf0nnWd8OW zJ1Gb_xy5YkY)Z-5kaQu)z<5I+2x}WqfWWWOy}A}zOshh%|IJAF80C1dfoV(p5i+uh^ga2OucnE!^?PiD$-twjlN|<`7lBD~pgJv230@!8fFJ7a! zy?dT!^Bh4hqocRn9gvZ@GXOEFQXt>72K_JmtNV)Or`DJr*RS8fd+~$``Gpt$#|(=? zPeo$h@~TZ^7C7`=sYVG8BiF9&bkb5Li5HmGadhRyhR)W`giBzA}aY)5t9s z`R>3+#(+Dyx+uKPV*=yOCM^4iGdYRzvRaZ#j{r<+JDUC%?nYCfjc~vYk}D{|!6JVS zlQ6+>`j>nE5a6%5DA1f(2HsTw0v*{0BQ;q z`SgELAvrzjW=(kT-7B60CvyA8!|&z4^nM37&x7h3Z-FiWSZmK{*cco-`mpG%uwsV$ zQ%@exaSq&#sYgc<%5xNI(n2n35Es;DWj6ELxd3t{dUpZOJLu6eB&5p2P@8;a{PF+z zVQKN}+oJRy`hFRy8ivD4-=a+N{IHm2wu{)?5>Y5?o7M_nU^EXWikpE zK4UoN!RGm#0Yw*fKjvw)S3HAggKVV^7cPm3Rdt@nXK;)qytV(^9ws%0vG<9=oAkxL zXE#x2G7uYv3|KmbcSL(XE?Lvwdumlde_XmGRZ2lA*vT2Vyg(Olji#r&{S}KsEf^1- zQT6h7RS4_ngF=6=1Xt_KYRfTUQ;MB`F_xYO)Z2U@=K7W3_~-g;{l&aO9=nd!J~KLG zsVLCuEkj#93-o=SS-KJrA(4`p$lCE z?e#!f{?mcc1JoGOdK8L+C1(kBhMNsp=nFhC+V`eY;6)FbK&1dc5oXWR**E_3ZO~Z8z!g#|P3ofA9?Zd2UEs3U0WO3bZ|FjPow!Le~EoT4X!g z{6XeB#0aFP*(((&_9A^~zL+J0%aNUtefnD@Ls=SCPyK)rXtD*7$eVF(L~?6gG5?w@lVbENQ2Mcex}Uh z`$@Dc1Qjn>(3tc8=B*XwA6Zt!L|yqIp>O%elQXMAaW>=vbf5uPMiEgjs9#7WrwqI? zAZLLiDDaq3xsWy+))s&mUSKi-3p$w~E<>CVv0NO_vb8hxJYB+9A=XLgz7}N$gPYzA z{i;Kxg-$A!;~1vTe)$oF!pkl>c_jB45qH>*jQwp_h31|O$R`a_rCFV`5c@ay`R3JT>hQ0BO3hi)M9@%L0{W*st||k+tE+p zU{;Gqkw2a(X>EJqG-rpfkBPHSG1hDCgw18t<(2fToddHew)`%{Nxr0dsZI?U>z*PO zC@sEF(n21b;HG0O-Ga9$l_C`?kf;+S-UjaaPyvmaAmf`;3FY(XhU`RrB z-+rj1#CovQ;~DMb-3vkUH`A9&Rp*LS)=FK^-!6SB*rssJB4mpPZXyIkk4lGD61lz8 zysr2Ujt6%%)9*reFq zpeiHKQXoTF3gP{A`_f(YV>cegjz7tD$as8p)c3p+xas7r&YTb)*BY6K)F@|-6PdZEz{@(}a4Lni+ z@JO%PLHG!R*U#Knt&sz+z7>lw>@;}J4X9rpEEm91 zYX6n>1@-;`?_vsKymbmt&<#X2I^^e(msk^DGai3$E(5;^s;n^?L8_xoUd@iyBhfGm zZaee8z!w3jg78gdill9CT#^A_Wt*V8trc@mGF;$6>R|QVTzt8rBC!`BAs*e+RTYhW zH1!V;hBnK$>F=(Q<(`a%>MGyq!Z#Bu?^VGBY+XN~d?%wp*BKUgZ(4|=U|Rk|Iiw%5 ze?|L^_Q22GU*tO+2*Fwa!p0u|;}(bqnQs!4li9?3yv1s60fba%6VhXj*$AT*U#hL`~gK+K-*dbdX6$G z7%LMZ70ca395nH5!@E{AtFvG*f$AW^6y>u<{9uGq3={>;>R}bmUE+sau^c?x#sW8k z)R@J_jcloXP`r<6InyKZy{Z;B;l|Hz1A#2y4$)z%2B?nG^?6?^g;v;X7w6umxMu}@ zI2O*uPwrv@1tyCdPB8H=3f#1;fd#y>H{^Z1X0s8B_ARQ(K$}M5B$0RTf3Iv-#Q3ZIY)uOl7KI5(K zeU;Hoj)x>KYyae5@|97fB^c^Fsg@<0nVr?a#NDb#)_8k82=TFVkhCQ5JQ7gnf#1+X zCsN=Kg-@+^bH@=?lVmdG$ADyZfZ7cDT-YIdm+cdG{Qc>p`L;aDcju;Rk7|b@Eb>`= z`c4;hSTx_Q-)zx@%3Dhj4(Z-g5LnBp9BuG!2^TP^as|BWVxLXvkGRd@w3}*TDNk#& zL4mnu(z^)j`l0-j;$;ci3H>2smetNrJi;opWK{q1*{ zrI)T94l66uzs$_o*%m0Ql)XL-Hn--s8a&q&;k$GL+Z-Pnc*By2NxWhl^>5nB{Rk9CdAN9l>!C`jHyRtKf!XdcDnXoibK zqxN$gJw;pFNUMf8ODu9xoM_tm8qq&*p0Ya-AR-C7Jr`!iUsmY~9M!>oByxh)EX>(y zcc3vXC~!NVK*yV?_!iwfp-r9H`fnA|ucTg6I$KCD8y3_)9dcxtTt@w%j{Z8|4)oHA z$S;mz;=Pb!I`DDSfRBUgMgBGDoRB2ph-9G#E<=|}?IYUEia3~JK&5hOKvx&({Q9#u z1$J;-GYwx))$Tpv(24uJ9{wY_#^)lXdW28hdPrYq%e)gT3yoAwk!3*>!x8bM9Vg-2 zV(lv|`!mhPAFp$|`_5eF>7(~k@6MCH)Z%1;S1BOSO9RcN8o)>5H)R1`F)O$HtAuv^ ziCS*;<;?>KA@_OR=QKi>h)t88L7f*J(l^7zs&f!!xk*&MdP>}1((uMq%G=_Qa*fmu z;fC)#KvB0xK)H>=k_P}2Tk_4~2U65icnKbA?w+S>xD+}Iii;-gb*&y)Yt9bD_XZ&! z${-+5Wzh*7pW9XLirp%yzO6uyCO_i*uhvB^Xt^HG)gy=}F4#D5(-e)qxE0Ew54`7^ z0$TY{D62}!I{&EZq$n?ajYF}9Xo=l{j{OsOcn+jCpao6;n@@FnJ^9FK=^IX9UEJ!= zh_qJwv_=vz!yH8Ze4avM%&7ODs)~hvz&_(+^w0cB+)w{<=)R8yh%m#T4n)>GJu&Ml z=0W9llSgztui=NF@}}aUV-^@ZKnd4;-s6v=`iE9OFbKpoGh>@vJ`TGZLfZX+o`(ZU zlYLT6UYR5??VRFT7mHVZ#?h>eSuJ}=e*uF>BB)Og3{A3UjrR7BYs0ll!g|RwV>D(B z=3)eafH8=DJG#7W{$p+S`3v9ImG76PAp!}Bli<7xlC(GmD;kV5U)jJ>TeTTwMpi}P zLqDOABk56JshxrE)mM@dMRV%LLFssB91`5W5i|OzBD~f%Jb^H(_9QS@1gK~Y zv=jf&N5)fg418CetjP^5X+i$#{A*x2v*|zg?ge%4j(~7n?{VN7 zR0t6P5Px)o70P4(Q%&A#4Lrb9f~$+&lwr3QKml&}Bk#@?*0oaoEGnn~oA*8M3#qc& zmr~&59*7Q91duOhjd^9>!c9Ud2}itxRv*d9az%7|jMh;Qx%$(H4ruq2)BBEfh#PO` zE6QF<3=07=m@E4`zUkshqcWzksF%uu^RaJ%=h%nBLHoYqe*)?Evdd%Niu)`0eI+$Y zRc(i4k%6xdHlTV)lq|S^yax z#FQJ`->zMGj!D-ycT9b9s5|GL1c54HK(%v)QoD8qZiH=Y7!#k0BpV`!Me6*(aPbG| z1_O-@N$O>;^_%D#75o`OOUVqE-nYFazVE3U1A^z4I1u{Te`0W@op_psIPqt};6g}b zd@kbeeie`j2Ovt1-SrtUl8RuMn*S;1UI4PL(2uqI27x`Uw~gcj+K)5FK0M4!Sw981?4y%YsCcK{WXFU+_A9D@u*5z&{FLgWLuW8|!H=xzvwJ)X z%|nyso(4~bOk@20f~u<|CY*B!eRUjMT?eTdGZdK!vMY%?RV8hQW#@@RBzDlVC^Dgd z;D7H(38lrN2`C%XYP==cw)-v9&js5x@`iGfA*n`G1!#65@*vhvM?TehH>gW`#IrKH zehuDi-T&}r0Mrv*pT{+IYUB7KFteOXKAmh~luA-yd%$iYQ0zz|LkAxUb7QRM;*!jp z=ASW@jFbn^Li+W9UkeY3EPnbT#^yks-}Oz>OpcO2NLNPXn(CA_mRG_R+B zmOk<3XX_x~IV8jq@%q$a=URdE=v#3ET?F?e6?M+9YLn?F0dehY8~JPe&kX=~w6+Z# z1xA2yEf;P{19%Z^_{!nUx)&)l%kj_I@QJ;k4byHn5IaT3;oXp2kn ze6*`nGf*ACBXfSxpNoFSd$J|2AyEBK8qsU=DTtKR&RrU-<>(erJQ+yL#E>>ml6=bT zU1YQ|Pvcx%z%8*)?sdaijQ0DFrDGtbw((BzPoHlQ)+#L0qN-v=)mNuRV%$Kt4D=|V zjOaY*>R^z?w2<6z-Vx;qq2LKN)Lo&S=5BijKO#s)fuqkE(Vjq^_axrpT9Kz*G65}fjs*-yLz854)5dOXwV}K83Z|> z+Yx$f1T=3SGqGa!XiuI);+Sfmiu#@0X6d1WthDxPoE1}L4Q&YQ+pe) zXB|d=o)4 zuCGp*V)jyH{<_)dT}6JW(@a4!-T_l6gBtg2fKQ|b@Nnv)FsUU#&1Q?D8o6Zo9qA5ZFHvO*#O*)0rrtz%d%-3D@_`&ADuD+|KqU<^?>e+!5IDyVA z73xml%bisTmtVc+arlzUdV8BVtJmwibDz~_0Sc5fw5jL!qMkpa9U|eNzj^VL3T9;{ zEUOcAAP}hz@He2@!Dfo34w1%^W&oac{KSo?W)fPQCg9rKJD{kPL2I+b(jBbzLaU}k*z`a z;)P#BJv=VB0s*QGfypue@Pep;Z=aoGw?*Z3Gxw4Xt-On*Z~>#4ggTd~Kc&g&h_rd* ztodyNLL4co5bJ=f2d6~J;A!0JwR56h)aDuZlam}k#TPqmF@kdB$Tz2knob4}3zu7k zL_FBddgT(CVC1R4D$-Kotg|H{7?onn`ic}{9umOjLD1Z`L_$LpkttN&s}lve(EY;l z=%@H>LWeEj_C#(Vl!kIl1J(v9P2TrV0@aCo06$6pcBrmvzYG4;3g8fF#ai@NQaS8q zs;QQ>Y#c0Lv~qExTwm==F;;Lp&kZn13!0$%*T_ZraSNST3#=JJ7#b!z@MgqL z`y`v4%;9iDrTd@1_$)t7|H9<0PNvDEZDlmAwvHi#7s)s;S+-e50K4wl5X))Ohtn7m z%-9@U`D^jfGZACV{GT-%Tp<&$1VjGZ=V5h$5`iibX{DpPFZx5%zeaRSq^3yG`S(Ro z#r;R^MQ?Czi6hx5y?;BI|6#SPE+xDm(Ex$$R_PSOC{TT$>>wy<#o)2S6tucot2p)(iDFgxL4ie%~5(LIRgK41v z>;{U28mdEKN#23srj3~T&eG{(PFK~vBkgNE{L7kvyZrCk(Ks32(nSZV5>ms65%@64 zNSu;>K>=S6Er47*_rAnC9_&k&&iS9pkLeKVB)zWgD!Pnt8%8CA{M7thRiTnWs z>UqEYtlX_?H1k)IfS2AZheN)%n~8gAFv4K9bJ;A9O z2F#mvwZW0A#Kxf)+5YNww*;Dz%WPgA)F;mqSaJ<1GAevFA4@LR=B-eXbEqI@QzkBO zOc%p|_gtYWG=r9z0^n(y9UHcOvZ@OI=^EYRgWvh6WnaU8e}#i^vaix{EsjoE+=Bm> zq&cHX{|cvgaWbPe#^z<2RAmP^sd=2{XK*CXdU))YIuFnAoyJ-&F6#Ht`&6eXjQ%dS z|HK=R?_ze5doo(SDzNZb^ni9U0#oW!w-4mIA~Ag`WRpn@(3Q0?%%6+12IpMO2s*XP z!QtS}T{4dQ_yTUfSrM78AigG3wd;Gs=M`=Js`t3ddo%V_G|nOWG~I4aI{uJI2X z&)JuYG#`@%`J~*-eDg|re`xT&o)a2dhP`kA4>K2r-k)-sb`!Z>9J7~58H`?@o7Y)? zye2jyr#sG7Q%)G<*WiaFzq}bT6$YUHiZoEU-)Ro?K_Fs3pbrXl3FbQgWQg!;J^~;Z zFC&n}`nwwBgVtrZj~Cm6gKWyV^=BI*ezpJR6srOjtZE}|0jIP4mToTA_&9@Vqvvp3 zWH`8;MU4i$o0eWvgI^K?aD=?BbLdekx^>TM*&ol({T_3^vxe!sRQm3z-uoiMSO(Sy zG;s%X<^5peFKU&H&%jhe7ws&6UgsI= z^+1}}@pg%e1-PfGyKoan@r0?dMh*=#jx(fnG4-e5eMdr?jK+t|Bhs8Bdug@3(7ujC ztcoqnytu!ik71P%?5IZI$(yq_Vs{#HhlFpAhG3087K_GbQ4i+R?Ih(;_h-yD%&ma- zj{%cDTp&@`ql2v=L*p4E>Ax2G9aI|lh^t#80un5Al(LT?AlS)g-_fel@2DSlW~mrH zz=5q6yObJCf)z|d#7RZxDeBetbJ6(fiC6KhD_<{YAEAl>e#pI*W6)3SbL~j;`WWQa zhKwuhVNx;h?z?>u6Q))D$bC824CFeSBbxbz^%*mhZ);u*79F9bV@mCZjf49$XUVPg zD4S7CJF#l_#iTTzy(=T3fjq}NSvAZE6IyGgM`D+1^atn4k8E`mvL;&nt-Kgw|w} zzlDz|-FKFxM(p6s^QY*CzmzEmiFY{LbQdP(=nY1X;p<`Yg$L7~JQ9g{J(r#&h%O=-^*acc(z0kqop`J8mQ)>zlmG)P6QA@xbzI;jDWw}DRh`r1L z_8IN5(^tPLV=8}QY~T6})sD%&`}eQ_Lz(bd`Py5oZ^>h-wlg;-lmU_Mi%WS@#3Ue<6G#_Ei>FEbPR ze3ShU*8Jl#+UW)Av8{?_+Zb3>4zAuOZ!?m1{BTvA^?~6vC=hA}EwY9|W{e@P?+IeF z%W}>7*^Z)hJ;@!$2T4fn($wJ^0@%0p?mPygR_BYE%8`p6$`%KDdS{IM2+!m2gd$gv z`Sj3trz7>HkET`5=1pBy!m+#nKR&st|ka3dU7=}j$DcjVi(Md4#LRxlpkZ&p^P66F41=$-LBy{>whXN(pIk^{ew|49We=os^K$Vy+~C5DCbS#DGAF5dA9h)T*sRtLm(K1o&N zb~&@sMT-sFR-mxb%k;g!3%vw7v3DEfT-Rq_>;@NDZ?Q8A#?_qST~&;NKZMZ2k^|da zhRskyHdy)ySa*!b@`o2n5B^Gw{aR>Pe6IK2Pt`*E1Tv8dbRUagtC^PgbyLfbRAHvV z)!L`THeRv6f+r8`KG@gurdJxieOtMrt8rQETI{u6UbydfX!dO32x$GJXe!I8SK>n+ zn|IYTIx0~=GwxDO6v+Hs8OVx&F@$MpY6e^Vo9#_zJV+#F6J`XLvjl934%tag5M8GvG#a!;O?%0l z2*)5*8Q66*42pP32k*$<4)}6~V#GZPY9~JUa}G4B6VM&@*G}_+1ntF<+o|&&x+z}VIX?J7~%L_1^xGw*nm|$ zItKuTFHxw33GoDtdWzSca+@aG@59|MiP9tVn`z`=%#K6U`;fx{tfyGR_@+@9J28?e z8{={7JT=%HjiZoeoL0Jg48g0dr#9u9SLM!?P5~FN-ySCDKTXJ8mNYuun&C|Gx{uSS z8e9gVeyWrp{BkYgH8gCI1~`mp-J8#wP_|j*z_*}c72`6MxlNM7KS1)@uLI z1|ymZMrQB?%a(5d!{5y>@O5UBlpSQmV>iq}j?AE2I_W}KwPW*|x!fW8h<-HtPx8G~ zcrol)xsfOGIX|uENv`)om2_!64SqvZEep7-*45hFyDeOuw^VP^37$?k0 z43owuEWfy)nIj9}G3fvJ1c~#!Ou%^lE5qN9ow>-aU1#X5&c^AB3>O1E5R>)9ZyTw< zb=pwRhuPl-;NWB3F(iBM$JlnH=uM>-Fxk4KZ15Ba_cKB>#bX7Z!8-XcMRJ`CUjy5c zD$pCZvfEunSR+s1fw1^z1n3%*lGM zbIw+SLqY(S3C#Ubn`aqr0B3c?M-snBp7|ku3*CeiEj>AT>Z)roF?I ztT?6Wk4Zp$%4=(cR!iySS*UIL8{I^ukKDr@X}Sfw!}lFS-U(ZD|Dy!{KPm)j-VXzf|9JVKN1wmKuNo8-f53*j85uY6s%64U2e%OCd4?j%O z?v7c)7epadO-xeXhmB;n1X;c<%u`@kvH#`X42D~u$n;G1lotwVcVf3q?YI0W=kJ?1 zkH^E_-E1&3>Tc8tl*#z-x@IA*nOzWkTcc zcwDgh<(C|rkr*d7ZqVtGhf|%vYXEHXSKdh3Tflff?2GZlK_wrlp>MqF7P#mWYys(x zNrA0EQvm|_lMq9Jwap^%?&G;&lq_Y9J{RA{B?atnh@l`4S?qtTPlY|-!qV!^yq{>IeBy~2e>hHEVm5W#4mZjwyBeMR!ea6o}u?-WaIjiT{&Q$b!YXTE0Y9!)b1d; z&8tUy<{n?^da6uGTOw*w55cW_@GF(1>K8Y6-XFCPBeohaUQ*so6g@z1=9w;`@g0Yc z{#%nRXfY%>xP5zn;gD<|kFy7bl#~Cm2HXvchB>knUOK-UUj3b5i{m5~G(*GLTA)nq zej^eo@Obea>t%oy6^_BHv(^eNWdAsjB^k49DPd$^3j8KRaPQu**oP4>Tnex_Eov3+ zjnaG7K(O8=lWW{kPsVs33YQU0MOp7E=F$dtB#v%(DGscqTK%{w;D%UL1_36S+kAQ* zO)`NhD-oUZCmm&z_m$BZZ4034^j=Yc00M|_*55ty#whhQUOzWil*+YIm!$ms!UcQ= ztSfVJzR5T$ZX#(FiI2-Dt&b+>8z5&mjhdo_>Cbt69?Dq4*KBSTS>(I-?vrNPYqj9@ zRR484Isi;zt;)WQrj#;wm%nbP5z7s;_C(y_lxbX{koBFCpmX)T1Mvg{?_Xx4SO`D4 zR*q5Kyb0kB|8muu84rVi_jR)TBYZaEKo?~}>}2)6w{T5zPm>-T`d`!&y9N;+iXzyl z-fKHVpO8N*GeI1-%rWf~h(}{;&%EyP6IB@9O-TnLt~Nq4hef51;npl9d55ih3Ju2n z-ZTR9^xzOg1SApZCUVYHyjg??2`3er! zP1Y3%xLJ3WPx2J%{7Y$OneH|4J!cU{MQA>x%~AK2ocxUnp=Jrp^)sP-r084O~?l#2-*hhn7wKeg02Buz)PIz}6^CRoN=^xnrsisk*30s4`PRG2yph z{a8=#%@o1cW65Ay%~#u-T|SD0D_i{Uy4?q8>~+uAgK zs6%c~ZDFyzFx3ytHdZ}@Nfkb0RQQy^iTJB_oR#W)^_gUqFAg=hr{J;y5tswuUHm6S ze=Ire{4Myv@6gnq7ddV57o03l5xau_p6A?Vz3o+Zcw%+zmEI%24RK@SA`3jc-PkcW zG&nSgAy|WDmKNmghv@OA5j{OiKXzIh*u6YUXAwlKN?^6_)}(tX3%R*`ed7*C`kJ%1 zXke31YZrhD0_x;w23rc``q1~V87v{6Zw~kY$d4;%h}?H;A!{y41;!1s2P|9JYd5$S z5p71yw9| zbdt`2-K?sYX6XRjBr&5#II4e?=R{5Jzs#aEkZT=SO=Dvphi#-bAPuzr`fBX#8G!|i z=WnovAiqVkJbdw?Ca?Gh%a-%Zb4LM6ru%-VyB!Wqb;MPH-#KyyHk}ufCZV&-So13? z0k7cy#?&6CzXqHPixS(EsdQbr1SxC5Pa8N}3upNu2(B+SQOr;clB3_J%RnUfY5+Ub z_o@zMEu?pbURIsvMzJKYnFO=oOhFV@C~W}k9)0sjWM6$exkCqnH$KFB=y~c{%2Mgf zy<@_liJUpVL`aVHve3_g*DVsv@4-e0*n&NOdRmCwqp)HgCh`i$I;~3WQoGSDBN;Yq zN&h`vvaoOBKk&Z}K7|j46@Z=C;WjS3PgIyc?>j}~%XagRUVFTb8#8ox>1>~4XL;-Ru1XuTnK>IkfU{vH5}d{O-(V%!$> zYjgXr7JWT>0+9%5qb%Hpv=Tf;OKGDN;8lPcu}Hxbb>xd)I410sGN_r@;Te7u#!<43 z-ymCfB>X$tiwx0Z$G*l;3lmDZmJ0PJ0c8`klh4H>ZaAfGEBmc^7~WbQP390PJeFWN z6FP$0aG57NvOfSmXqM?xUMFSiv69xh4IW`r_N#W~R}!o~sBeukTxnD?@9Vs5P}JS$ zJv5c*vxKzSWUUh)laQh#YFk=L|MgIQh6F56d&{mVFoQ5>OjJ+MGzCUFvg#YbH89tC zC4$UZ%1w1@q3FzZC9EF0qS(uj+*Xl%9t?7xpmkags@0zu?`!&~W=qx=j17zF&zcJ(eV$-wke zNV|G-(>3fgQ>(&|D2H)OE*$DE!i3Ogd_@xBC#%m7177kDk~DiBx4uz43`P9n z+62{kiTzr^eGVB6?2G8uSBg3Jf_ycTwco0{(N|^nT4ca4l)Rii{F^@U)j)Al_-B_Y zAfGGjq@Y%W+Wr;g%|<`QtJa1Me z8*Iiu7bhx|7UblEgyLKVVIPT#0GLF8}G2Z^+-LyZ}!a+)FY~h|r(xEfmXK zsXW2M82KjXYw|Xd+6%9*Vpk4`2r*D&FGlSBmMKw#g_3+-Y}?NmUEHr_ncRwwU&;zk zL)iC#72Pjj*;Hr{S-jF_{jJX`h(I#;g1*7@2qzsZn;|!wpS7gd-hZ3%cc#Pi{`?u! ztpxHOBG)WNTGM}0qzq(o7!A^1%len`cCn~rjN(MC5jR%7W&*$<%2N&4n5Jys>15Qk zEy0~ViXkfGx!W4*6m0$WSu=L)9*@O<&kza6Fwl=;>3BGG9aN2GvjSWuF9pei< zf9eJJP`L6@w!F}WK*3uZ>+irT*zB~|Fi86Jl~w9UT1(;A_ZUP5ghBMWOpzp29#u!@ zQCxF__;n z`W6#F=~Kpl?nV#cpG%CliRHV1#jDEKqT-#FQ~hwP=2)SfRhM3)J6N!KRB-!&jxC4y z|InBM7>zwQs(3L;;_xW>^_G7MtGk#Q9J@Vud5N97$YRDo!S64ZWTZGIgF=JFe?QLN zCwb`IiS=2`%qgAln~?n2e!jB${f)lNNxm6vU4AID(eE1^*1W|2cTdI34h>PF4#7>1 zg7?e1>t|h5{V?38lA?IYKRh6rCea*_p}@l7XpA8?b2v1kq`}qxev-Xz#KHue;|AoDQ_LYI@#4n zUOsO4K1Y9tEUC~>JC-x=V93Gv(|Oll3^*aFQIM>HaYAz;lR$lC5Ip04sP*T3iPA%0hYq-GXk_ro6V)<1`#PKW zGFLP~Z6#mMD%J5>a{F)3CB&b3>#$hlr9`@!tM;GLZ>#P44yi9|sq9b1oSJ(V11PWa zmnU8VQycdWk_>u~<~OeJA2%CyE~!7yzON(*E>tt4s062`;ZgSD)QJsTR$-SHiPVV&>3JuCxo7PLa|DozC{Gx83?b6-dAxKK6bf+{(O9;{_A>EC1H%K=~ zcL);FDP4kqlyv@<-Sxen`yYJw*_ktEX3or5eA$aqK7tK49~_Dcdpk-8Ek}eb2Y}ud z(W2ujaIKgjSLtMIuve5(V$vn^cK5C;Brh#J63hj0AqyZo6`cXq>8Z7csEiqU9WFn7 z;QP)eQ(|&B+64}$tMqarhP)>CvWFSX#I&v1&&^}>-Gp|Wqu98~i9m^3q>m>VkXk%s#N zi+-DVV#s(9!pEL$2&rpKSrPbD6O!ksS`8SdE`aO)vQEeVRKf_OWhu0NzI~hmM?Oq? zd#>p1rGsEg=RGe&~@SNEOHQ&j}mTn~l?l}40V z4g}ZWi0(G{hfIH`rdN*D$`i1UW)qEAwjVnApn$kXb#h#ABYq;i*4d zZ>iDO?@%05BfvCkm|ds>3)b< z3l{i;$LoNyC5z?{Ia=-2N8<_4?2={2Ad(p)2skS-#mAIw*$ff(ds{h*T=)y_X+<|EN%6ixebZk|*ChgXQ??-!9% zr{at@%XFeAp%(`6XC@@xl;(Y#dcCzz6Cc8LLODFe_jiq6#dssfoCPwc9H9Da5|s4o zuc_xH+snz)BA~|6zYqy{RtbXE=)D;&s^3+Axocq5weyK^1S zx0Bx@5nXxo_L#x{*V?3&S@qYxp``Y$7=}BNae{kf@wV}asp=B=n6!NN5MT^=z!JaS z;mSPx82Q}@Ck*xj2hTw;X0xN^UU6Zuv>pl`XiXSUUI|94;Xfm4A8}#2TS@_GHk9|L zc_@bx;9`@|V5<83*ySJ4UgUFr!y!_@x{6n$vFfg|*&E!(LQ5<0+X^$*Br zR$Ezn1MgtVnAnS|`vL{}+BYSHRqi+uf%uJmUN1%EO=3u4pv$_G{8i3e~+13SFyFS@Eidi6f^_8jk*nRRDHV zSO=U;O8^rv+q)90@62kLSy_@sy(o|&-32*Ad zI^edP*7VE5OY7?R0BJ3C9^6MxD#wKncvP>CrgX7y*Qw_qA-xPlvSxN)N8<`uvfP&T zG!6$CJ3DsKUW1xP0s41HFR+t&7>ms-eSXue*YICg+5RJ032(xWh$m5&lnBWLmMQzt zM%ntYd>96YG>#_{$3JTd0iZ;6D`hB7(0lh^o@xKN#D(kh=Sz-T63$5HWqy;h!4eDM z-KAi1Ggv`G*?H0xBA3zDtOZ@17ReX|Nm8JUKkq2ebw*ff~fO?Ks&j>OXdj~&(2?W4E!MqhJh5C_c+HcO^F zJIE;J)~k*Ae%@B*0aZtvD*R>7r8hm0r&?fY;Oc+MJcLrIM)H8o`f7brKm;D6KFwz^ za_{T!E3^Cnt?|O$+K=$@3G5>4o!1@u^wQ2F$dYz?HxV10@YG?d2hdYiF%-xxCWu^> zfXfF#h6!GL)Q#|01b973Vf)C^hcjRGcyIVqCqHZ^;r(kMfh_a8zhmqwm-&>zyBumP z2NOcarOYc+5Ng6A93Z*cRJzgTO#0{*ySr#y$6bP(SO6&5&*@4V2~&2rrWO&h)ZeJp zrck_?_3&S|JmLW&T1H@??wk5a>;-H}9|-DQb!Tm-f9g^p#Aa(+@T%&>qr}QhcR@(+ zcQ9=F<}>K$c4wVhJ$%QUG5hJ8NwK){44dmRuf!YM-;Icv&2x*C+4A4B@cZ_Hwj7iRqjNmXhgiCGh9nFNEnetdNC}0ifWqXR>9b)NT9>6RpM@7m{ zpgcjBv(^OnM#hIUQ^%oauOA~w%Y~@j3l~j5QnBYlYH*YmZ?o^d5vLx)8|aji$Wp?y z%dRnicb14&v7^4zq~vtz`zgZSa?o)tP00ZEjS~#pob3ssKc13#oOeB+CRprDjV=(? z_+J`jNyDA`wm}2WLld{p=+?TOr@x>G{V<(hG{Ut~oqcn7Sd6;c>T50X3xb&IAbVJ_ z{FRxRp}-iwiA%ur?VE+22vg(~IRD_X-b74$*qxI25naDP?q;4ZqVkXKs;D&nbzI?& zy!-**CQ8uHXFMIHK*~CD7pLJwR`%G#1amF(di)gnD%UEPRgI8LtN-+>yi7W{?sFG)iABn413$RS^{+oX!6Mku-~1Ki6!|?+dfO5#i%Zf+|?abxTV0lI!Q>Q0(!6Acz@MVeD=gk z?!GMOlq-`prf+CU;KcZv_A%1(hZwLhuC7?eQ0#qWcfP>_07R>Ll@95{pp#Iw_cAq3 zy4G+0%Z)3aVY_B)=of>pg{k2Eo3#?YPZ-|Se-5fZFEQrzYm-hD4B>@mG7xpAyjl@LM=7 zq}mx;VqB^;_|p7lduPlK!?6tM@Y?MVh30O)QcN#NP0L;Jl}7cdLtcJhg( z)dE2Ct$Tk$JnC|7A=|*ET3rv43FW||*LTIj`nV;2zh9*X;h7#_p4t8>&f(bfL(==7 zri?i@GOciHyGo!!oUeu)t*n?1vD|%nE7)cueJh=@cW4x_%3!O;Nl>OEblao#KnKtC^w!Pqs(iPT-XH z^DNQ?*f8~_--bAL{rZZ$|LM(#rS5UxvHKUGze724(Rk<#*x=)pV#kCBWzm|E%2Y$3)t zGOG#W@ZJuQcs@*+&qjm|~b2Y?;zvdFZkvKV8Qm8DbBmtyuX#2IqtG$Gl_!=w4{>rOSiOKnPBRqaUT^@VTtSn8licr+eqv4z!bw~( zm=BkCVI}L;5}Vhaq&CKax*xIf7+pX5%-z?r+!n7SQz1#@a{o16dF&if)KwrWLl+n~ z@|?Z`KcXA-5wK}OvW=!)$coDv7U*Y&0#NvU6ysoC6=pE&a9T>?U4WIT&lApxBArg~ z?`nCW=3xJum=7|!B{OkRBkaeHPVcQV%7(+DyFW0LWUTc99yK|ysoE4N`@59iE8ckp zZ?D5dAR_oOcnpO2PdTezRzZ|&2B6p>s~+0YR<@PD6Z)$w?}bZ79jXZ&xKr|@Q+Qa4 zVcSSZ)pJq+ibYF^AEgQAep%j z*g;Fj%=tX$*R<6F_FaTZO54apSwz8^xoO0O7E(@xC$E}XAdgDk1E)DTgiZLQ4e7V7 zB+1q0yf6yMZz5%n4wW|2_quk;@P+jy={y1s@N(~v%RX)+eaocIV7Dz<@saj3u7-haG}CAFVcyX@GGREpZXb?xH`{6> zVeQqsdh3Z|=^DOByn<7++11)zN7UEen*UAz0Bk@7|G1W`ECQT@RNsjd*1gbcyN%Z+ z9-uIqE#!)VtYr3daJKexRf7~aM>!;57Lt#Cw4uH!*f0EA5WO0xS+z_uL-uA)t*sjO z<}i+FjCm>?`kMESd?flw9o!+l9!EJ6#Rpt=uL@w%Z5j2?-!zK8I06;9*l> zBKY;4yT^su8VnWjJ5zq5j)M=~)%wq9B^tZmkmXIN8}6jJ2^Bdpe@fW_U!Dt2el90B zDvbYd^HgjXl5mKMICLKy5Z}o3*=cXrYf~=1S*Hd-nUs-mreXN7MQsw&!%I|;Xf)^p zklND%ZQymc^7B)S|8rA6&|93pci)-I3S|yH8$q@{NQ~o98chW)Ls_Rgd5Fh_Kl1+6 zhOx2uy>2$#NlOk~9{@lhrYUp&2>iySPV@0jHplyAkuNE>=oohmZhkU=)GA*Y>Tob~ zeHn4Q>A_n}&8@!LK%^&A@qiX@50$dQu#>7{YzUnG^wfgVpZBwFiK83~BTiPot4uiP zPj}I-U_c#zA6SWcO^%g)yL2w`K=Q(*7#;KF=X?}@5DK%~0qgo*(NcdO)J@gJT7Jz= za+!(ePnc}xp)*)*Mht9X(MMOOd<*Wda*w|&Zi9$8vcE4SoK|<&bNO%C7?&~)iy;2- ze3us3i5kMh*_F5XjW~J)ZGo`PlCvlc4PLe(Iq*AbLbs#&{ei^rYfLQSmRz2FaODaB zRg=+al*B#B(A&7fcwYZLgeGzC=8S*f&1D$d4$CY`6cplwpco7uMf1G!(5^CzR>Zze z!`t`bb_)^F(hB{-dZnrYV7+hd0w{d^?2h0~HD)xo5M?xb1*6DZYfYI3+SMu`A4(F+ zR9p}Zt*G^8Jf)8#<&7_7H4XIreTS6qVB3~8+z%5?>X&!dCamo_)|z}{+-x_VKet1H ztz9NAI`=oozA24lu+ z!diMe_hnus%x`B}Jf7JoM zMbKNE?Hg&I&LH?l{+;HOwvp$1m*kRv1Yg zZ_GK}BJY@c2csLvN96u;M!vH~n3aL88zOmxjV->|5=DRbo)MpsnaY4E-%92OIDREG zwKvP!s_CYR7DpIUdmIl~F0z|b0{UfrIZ)9W22+tV5 z`swqRR0YwGnIY!_9s}(U=tc3Wdm@ChYMydme)o)cuRV)3u-M;dAL-k!a{FJeHW}n0 znNEM!ZF}y&Hlex(>iPbBxue}zbL~;{>p`t~Lp-C+To5kab?R@K_ z5wF`L`WbV;?ninWC)tj;bbhM{OVwXrGCLOlu#`DzT1|GHoKeUe(8rjZ@MI5z; zP}S^dnro!Dj7%G!m1v~)ZuhnHr+2cWHCh?|Z#ekpvvppJRriJ1m(D6IB^+4Kd;#1g zi4BT_V+i^Y(|rMdYAS9yW(vvmN8I%d+0G03cUaTozOEXT!8R~|p_Cw)l?}!$E`&ov zW@B4UOaTS9B2hyAZB==N=eMZYinm_-2HFSUGUI9o;@b6uP2^0 zU}e0^xr8X!EI`H?X1pr+b;m1KXj`MenyQfE8yZDDC_jfaF5wB+Q3$6|&LU#CZF!@Q zcNfkJQKN{AoOof7l>W833O%(Ct4NToUup&V;}udz2O7N1ACy(@d@atMN4W=w3woAM zAN9%o0Pm=SwxiIn_TW<4_8B;}t1B-H6=O6FViB<4mfiLo*F)%y71&QPNf6OaMQl1@ zB>vKR-|?<}XX;u733E2Mc~bMJ*;-)iBmAxv3LF-{7U4j;QGS;3)MNE){qrk>4^4eX zKdod0d6@deiqGH{*l4k%0a8Fo<fyuU&!rpvpG@o+LN3HGpRZ-(`Q_m4`H>b(2E>cEu1rW$EvNorH)wlqMJ-GU-k=s* zvW*o}68h1~ANCNDQGNdh-9j%bp*$BC-?(Bp>}zBIQaH2A$q~}FV_!5iqC^Oe;EIYg z1;07Iwr`DzJIPB;td^QPI{~N{9IVB@He3AUG=M7jZ|PS6`2X0G6?&0Ym9?3N7-P@K zp|1pWDEbLp^XJw(p@F}NwMy&D9oSw<;hGxOKZaBi-+iWr(~`B%4K1$8qw;1lE!JBv zBcah|^*=^HlXn&R3%766wHgABadY&e~n;?48W@&L8GDkEI zDyyo9@onYS?MyYS&Ki;&W)ZSUkgS2*ayQ4a?6-ud)S`Qz946LX!|1+rLP2V~-7Sr) z0e$Q0o7K(@cql@TOKo!wuqZDq-eUU5=%t7F2m*&Bf|aC*Xots_XR@Z)<}^=ePWv{L z{C<0x;NBh@1--F=)bZv(b-Zyw!c1`k%xd9tD2?&o0c`eea~WVcBc&GFBx4hcO@h;$ ztTI@xLK9eN4;_A%Gm15W>)Z-F>B%a^B^8C{RTJi1 z{Kz+4&P(?6Du?r%h(HUE$RnI+O^^aL=@j7ca-K`QslVySmiuQvSn=DX?|E zS{ZW86KgxtSHX0};oF*5ZjCWtOs|8#VnUh1Mxx~_ z{|}7>JYIN7Ue#4q9XZ0|F|&d|g85P>PH&inrm{#ml$kgFjGxlZt`Zqf!`#=ts&!?d z+^PoQ`xq1dfP{2s5U-%it15hjok}TsZ#ZUpBXh@19@Y%%4F*hPDRo^nF5)=aMGCeZ z9rOvzd$mBU0EN4dJT#dtLP5Bc{u z$Fz9An8?kXe-@O{S(hN)tg{M1RD^z@cM!&$R@#m23{TtG)-)F;!dke;ZU@9R>g}6Yw(}3?(4fBj>t*z{$7Y8n0tVB zKK8ejWe%In%8*|PJ6kGk1-elVpUXq1-Rr!Gc*pNlbOdNOL)Xstb_p;)N(G!v5W~13 zp`#t-oEa6xI8lk8@iFgm8Cz>Jp{gbarNAX_ofB<)HdTfV&8WD{&7SaXx*wPSa&xwg z7pClay=?uq%fY4Yg$`ddzsGxgbJ@Kwd4bVc-P{Si_x6sW@dLRi@fJazn<~TSLv^~O zSu;OAbg?QyI9FO}A_!Wp0MYXQZ)FXj=}S*J2v0$FY=1MrkN3xj=%XX#!UAy19O&8h z{8>pbY>hfzVTR0nsMM86=n9DF#eu6-)d81!au^{-)Cmw^MI_FiqQ-#M$46aL@euzh=}ud?@veO^Jr_MNyDF4 zgh>fQ^eR%*1gf-wVi?V5dD1or4uO(-g8gTnPp^^lpzs*}*TWTfSQm1ELI;`c%@e)G?D4j#& zud$^&$i0F7i#v*%*Kd+u;TRD#w6%C^mGZ^xeqjuPY>prjwD)e>2#zoLB!q?I*XwsH zL)bemQs6tnHv&3}xH8cl_cpeaezhsw*vC}%|BT3Tof&!2y00L(ucAke$TlCXG{nW{ z@?K}JnYdSlD-kL8sZVy;^F7c&W13=_5*Y9MQE9jjPl}!O zRjK&q^ne$Bz=aJzQNY$Zmx`IV;!mtD#*Y1DPvOU)@+TFKpApgW;&HY3egJLbWSOyY z&OdeczRc1iR-gRC9<66vl6HP)!lgz@ucd+l-t!75Q4qcb?Acr0xK=Q;1g;&j((&0cG?Q;Fa2bHZBkx0p9&pMYEX#p* z0R_FmOJ1HmbHu>{Wb1j}>2Qu9&Ra)t&^vc?@>Z&UeR?XMJ~@Bin7Sj#2?_s{er3cS zq+Sz$qx05UYMgz}N_19U(tVh$@R9m7%YAc62b=;kk^J^y_?;?X;+@hr&aYqPUe&~T zNdNW4K@fQFMdtRG8|d86TEZG|yW|EDYmK>B+i)|Q0RDovPMH|-C>PW&*`t>ulFS;2 zxKyJ5;NT*7fhS$S|8MmIaSM`IUj1X#S{W(MH*2 zI5=u7>E32C#Ws5htnKu?qbbCm-DMG}+1MG^dWd|krxnyWf@zPCifl1$dKAedz}owa zK>MJd4KA^~<0$*4#)MD9!>^n!E<_Pe+WF(3@`3GhnELzPK!QQn&{13?s3)F3O~pV5 zv%`qEBxNKMY=NirV|LgkQ@+J|dpr&+`*&to!O+n1-ESFhfyy%rtU2tst$%+=fGfyX zOQfI|2%|;29!=14=PJ+|8BH9n!M+;D(sjC*)70;wmNer@vRBG_JOClcq5zhb9u_xV z62yH(Vpa07)$AB7z$*IIBr0^4ZM6BWxd8xrk5$6#$BG!0C6D1kQ)gjs&l=48{&`d6 zl%bI;`6YfzAmW2XF<~J4^w5Py+96EcYSN+MgW>#}Zk(b{Z3)U_6MXd7;p<g5DVoW+pxY@F*KGz-hcA3Oy=kJI~Ftnqv4_77qaBKP zg@|`Aenue=dYJwA(zu0*cD5mT#}t+0TnJUF>~IeuWw~I`a^=SSqF^3jT=H(*s&VqW zhUTa*8pub+?_U2lB5L>=fMx=nKpnU4PM;Qd3>xhKKw*dc#!SJN63-j|T=$Nkm_*4! z@k;rFJF)p59G#TCgdcEo^!t|;r26KB%`dk?_ef0isPA-Fc8mKuRulLdTc88dfrXyu zo?x8&VWU_R+*>bw(U6UN z1Z)UCbROb=g9g`V8nJgep*v>epI- zNIP^CuBLw-)U|SiZvrLtVpkdMwL#n5$_%HpX@d<;Cs4bP>#5f=vc!5A<=iaYiL|&x z1F1{GyEdw13S)RHh=%X$m<|S@7eb+1^3RwVa6eb1RPKrJqwd#*M+$iyi(?kcU+Rf} zO#3f+I|1`UiSBE(i<};CHo_dFDhZ^k&uau`*7BhlC;ZY`x3%*?P8zD3Ow<*; z_bSWr*FXubZ0XMl=(B&Vf|3ZS9YB$~^18T?@K`R{jb@CDw_OPDywjcM5dJ_(072Mr48}Xr31SFgruC-;6C2uU|6u|oa%bl(s6o1Fmeok7mA&7JFEXxfl zJg6g`U}AB&V5?qYm309;MJJMZ4bZsSW9gDABjSvX6KITmGrc;*k6xmZUxlvhg-F-B zo+H_W#2;7r^|A&3oqaCz`{3M2q`j#l5YHmceUS`jakKS(hx@RK4e_NuJ3-t(=$4`` z*QdJ=qJf$c|E5Ex63mjyna^*w%M;|}Y}0U~$nEF*MMVuxqb(z|r+8`k*6~HD;SyJi zvw|HKKx%3GYX~+(og=yi>J*sB;)k^EX`EN9;r2C5|n+75WT zMO;S#*@W*yQXn*|yZDJu#fF?^@8mAWDs{}(GMKZK%^dE8So9lp$mU}ZX}3tU!{2nJ z4n}?F;KPkt3j<{ejO|eqA%y696KY+n?o^=O_jx5pPba9h@uk3hVeVY#u5yz*EGi7y z2VoQ!A5`1$q1TgrA54HOz)ZfT_kngpB24lCQuDgzMGE?ecBa(9Z=!H5cSG6{q$N~; z^?lS=wqa6ze(h@=uyuol`96WA*0%bSm|4-E*r<-h^!5lLBUxFSp4OZw=ROE#?t$RS z=?i_4MN2r9A=3e&<~#dL4651h;8A8o3|LBqjxCP8UzHo*5cN5{s@ZcO|3>$BJ{s$m zN&b|egXmjf9n`ExxEFlZq#lBs#gn3ls|G9psIZ)zP@I4YN%k*dqB}(s(9@rT6njeF z$^Nigr@gl_`xi*>L4kC(lkL-;qS8AGd{XUM9n$OqpeW&6m~z_P|o;R zYH!59fiy#pF6!4j5!b9MBQAq78gVrwP1HQ}Zm0I7D#U~VI%@3Z;TG8Y2VG<72JyUl zS}3@WQQ1bQuj#3$cRS@)Klt{8VweicCu^FUDCA#{ZNGcHGgEv}h&3TIlCaH|uM52R zm*s|ca&z6T_YS?XE;GrWh_{d~=~FjmgzR8r*YwNgLJ@R)ill;t|!PmB|si^y#jjM?^Dh&JaM97n?#d0?O93WK-ImrnTT49eU6a_T@8 z7P>gS*a(exY^5rBZ$;LRh^n?4`XKTk-=m*COdFwalcpFdq^etg%M^RCjXK%BN9#rV zOq*w71J5rc&Fgw(+b~MwbU7~3=Gxh0O1;5|3)klI6K)8wP7?uV$j=Ef%<~OY(U_bD z7VQjmu2{HSqSud5+yZa9i@^zqmgv(@SPW__n7ZlM!#{7FT031-A^riFZTRWGa~lP< zACQHwy%1mB596qXWI9#B5b?2zH7kkR?@^WJ2Nb`n0_@m&>qUD6KSQq}<71|(T47vf z@YS(wJ!G7k(g74bjJ_&$xf6#A*NZBYVi|2;zanS~06#?+4bGw|d7R$FC*4k21;y$u zhC=XDi28hA4)U%uU5D#Tfdw?6re8@Eq1wdUrzP6(WibfI0>fw*9WTz!(}=6KHg<0| z>Y(!tUx@$GTBd`lxQPwf_3PyS!YH{NsNHQB_&vZTlRK?FJ&V|_EnO$iV+pjIh7|YXUujWDDVdsG;KMb+C%1EFs}yL>b5)YKYZV_ zPQ?)wX`gJBm6yzEGbJd5akF$dJM9rsOowXixFT#>OnS-xe32VSuIQUV5(u`EBCnU} z>Q?arVJr!96TBQl_PZeOm?+Yy#Z0r89i*`v`7}hAk!JLQrU8KRVlCJy0pI}ecWURc1I#?_%x8Ogy_9tz0z9FN|)(x@25H?Ml zJrhKOuo}$e=amQifo>Cxr7^FV9b`&&Z3`%Rl}?z!CFz<-I+-mQ0QK@{oik~?(X{T^ zA*6>kK`{Zakoy%NV+gnGRZuYfr)p$|5S4E=lR^R!LFiZ%7aDUtLkJDc{Od;jU93tg zW<}oaqchoWoZ8}3iJm7$0TU&!f3qTDea}E~QV{0&qwMS}F3O)=?{lcsz_kQUE3h(V zt;cz~XkWTfOQ(53=GQb9;yghiB!r2+9xdossW-&JvQbn>oZawP$w`$A4`D=#Bc@tX z2}uU>nn}c0?(F%DX#)Y5m06znIyy109fu+;S|?i>=*t(AfFbNzHx>)BOxUEE_X#>~ zhciycBL@D1>eGT;^SmH#MP_<3ymi|qnPHy}vl%#^X-Tk-_K$JrYVEqYG(s&0TWyqM zutiB$e?)#Oh+wT~SRmBfS5`s@g$P)hoAhXQ)l~fU_NZb5erL*bo!gc^ce6<2OYPOT zLjnXT*g!_%!+fE<#2UDedKg2-B-}1;xMp%10nUJ4V3V@Kc~u4)!eteqWZV?_r7VFD z4FI6NVkRJcxm+*U#Bq06Q{}6ck{0}?E42VKtc?9hfa}5y3eiZu@?JaoG$Vijh%!B;mL}u^w_nixgy-0`h-{MWMX4ki7X- z$Y<%uTL2HQKuv#GDFln41Y3uEVcj^5#@#72S1ezmf7-POX*F|T{18_`vs~O;R5FQz ziz+m08#0}=g=&8l$)W*(Uhap9qvUQ3TeuPwb%;~rQHX{5^X2Bx{#IH7PEzI7^E{Wt z&T|~~13d*INBA36QvVvfqHW>OPgQ}8DAtXfZ*YbwR_d*xvrN9U; zNFgn@Xu}m*ut2&c75B=`;_GRa!^so-@E2lKgx|{{>`6VS>s=kJpZlyESCv-P2Lz5) zTOV!gk+^nxkyo}g#?Z&`$AP+-XQWU8BZVunp0}<>;NJG5!DerK(icMtLGEXy=pL^c zh3C^N6nna%ZtOOC7;JIT8T;35Z>FF?7t`=POx01xX2)frznY65#D&vjstQ>6Ywh0b z4TA}Qr|1yLDj#EDTJETKf1CNx?O$AnMCGtZ*L5k~Ao?0OZU|y{y&xYo<=@kvxquCm zEk$r-Tox%MJuTq_i*ptujdsR`s*%*-@2{$4gS;gK*de*#Q{RfA7B=7;lw8FMb&cnK z>RH&UIQy+qzbJ?L*V7fXssLzuNB+v`rHL$keO156;THAwLFj2_WGcU*hgUD?PD=hA zQU-3q0NbWm>bZ4)CI1gL+Raux765@T-QzLHHgiR{k^G5d3UuC@4}FcsO77o4vw92p zL)Jh2%7P8)!#T{I4-<)We@d3}rz$Df4!Mv05K>#3l8d(fl$WWRneLhk_ad6S&IYk6 zTsC1jRBkkQ;({pkl_9L^e*y>qh+iR6vv_+aUx{8Wq3odBBIeh1QEpwLncCzc;P_WBs!WVO-ANQV zX<@@*NYzMzB|;)2N(}mqcg+okm2K=hAKD|@@V*)ivQ6D@-j{!Ss=hWU7_W_0G_TeCOMx7% z&=_$lSYFI*k2|C#xSuJrU*s&!#c=y9YHy_1ycGaI@q7#!j3EgvD03k}3cAS6StnV3 z_-3h9%K5`d3udO|0#emf0ilJ6FLioOGwCgdh2|EW{#XmbBuSC`bA>=9L4lG%;i64e zsJp(Dnd#}POwC~jB$T>GD-{onwl+7KmRMV|7s5L8U7RsV&z37h6||MVT}=Zn%|S{T z&Ds(>LQC{M-Uz<+c+*<|*ApdX1c)tjNVQDIID|+Kz$RhkiNNVkW`UdT1NuHrD|=M%Jf zOaPvAgbE)vOlp(-)70nd)GT@5LaA27XiH?7AA`R=E85WC>{__ly#pC0=+svvi0|&X z{&~yJH}^W@+GR+Cja27F6Ywq6L_ z2u<>~xYzQCRRNYu*3r$c@OC=yr;P2iJps^!upLG;82o5clQhHoZb4tC2T48r+=Hby z#uH#4)7D)6Wny5&5`1`t{=J9~t&-#qd9k=7+^bmBc@Sd7+*VbmK}}}R&NaRh?#I?$ z^2w8ci1Htjo2*d{b$wu%#cJ&%A7YwxaXV$ae!%E0P9faj=>%{CpwwIo#WKa-2I5Ak zDs4PXcGtFMzf^ox;mLdc=3X&m==qS|^L~DkXS&-RGfycXx!NFqK8*I$q057BXtBU& z3DjK0qh`O*rb-O_5-%LxOc|?9RlmFQFNBav5on|wXojUxxG@+iPAK^=zC9cX-v4|S zQ`8o`RBQ=&+CyCQ#e&(qQR~6s4s|R3Np+R#g{Fjotv6x~b(vV#4Ji-|JiEul^o_ju zz`{D`eIuqUW=k8oHdFj92(Bo#{NBKezcw_^T-k96ydZTcI#B)qfhz#Yh7d*!;jDPP zVMIW&ay^6__pQz8a6=f={I zT`4VB&ZT#Qn>b2(lEZlvBRuJ`z&z}^sLBDN+*$5Es)NVvZPT#PxVksy*sR>Z*|z5m zkv@;eiY}`#Y0JkICI%wd^V6E^uJPcH*uzk%2@o0Mj^Xnut--f*=W=riJqT{(_pUCf z80|(*6a@-Q+qLOv#lQIfwzh?B{T1JDGhIURi&OQ4zURkIrsU%pq@LLgHp`D~fxMbx zxHoA>c1l!8s~y``=b~WBP3k!qm+89H#2Swzb;R|va^ZJ2Wa--_nLKLsv}CfIcXVl^ z;)GY8rufa8(O$`l7j*pno8$L%eoy`irjKMY{DSDRR9eCwKW^x96ip{ND&TBk_~2r2 z82*Cl%g+s|b?|3MS9>T5`nR-~HCZY84;*38hYRR}y+h?IgAb+!>kT1#Cer(mpzY?5 zdjAH?ylgw8+mCS=qV6OGhGU%)H1d5VABB#+lv!<%wG|R!p|7vb<09T{2I$$Eb<9#~ zRvh8Ssa6m%d4`HznQOnLEqDS+OrLk{16n`{h*Q9vjMG!N={; zej)y0cv=#RTSW};xbTXxmT3PscG<0&dABlg&5U7RO}S}A=WiC7FW&0P$yb6i;~tSx z7Rn5O(m(J*w99HQs?NWExzt-2tMwBFLugIPY{{dA8qZnH2I8a?pqzA^K~!S|xfp7% zT4wt+*V;xD@#8coCpBDnb&N^5cpU-dyjvi<7k@Me`%hqM)Wzw=d})<(gM=$Yq&I8c zTD$p_Yuia|S`?KbFl5J$*WJb42gM)tq6Skm-e9?Kj=iH|Wo#!_)vQZECyugz2+a*l z{MQ{pLJ+c5&H4Fgt1fRLI*YsbUn2%`#_=8OD9uY(^H2ZaZ<9L)1@))^J&yR8c_4>*yR=!v> z?Uaa&`#PH+`*?c+$?#}>+3;oZpGKVyRyaz4*#qFbEheGBZ9Bc*kLEWM zmF_ftgGK^FQMz~BFD#`;NHpIDRaF^X31pM$QcWXV(C{?{@)d}XNIbw*RmU{aqRW{X zF^YLcH2W%h7%am4L3XfFoPx=dcZ!?eoz`v0H;ZTN_V}J=aV#KDq91CUblAA@y6lMZ(HRoND5IY) zRNv?Dpk)54{Yy zWAVM_f@h_$W3|l>h?0;N!+&Q#vP4n5pI?9HOY7n?5;Z z_$wkx6#+t|BHpg1drQBPEG}XLZ2W~-=HDGV|Lurk0DT7L6N_O_=aze;{aYd+L2#ToadWbMtbawGl}b2z7tQX z88gO8dA$SN5dU1gq{akG7CVj)f$dxN=* zni!@RW!V;v5aRC_siO)s@kzNq=!EnY>OXzs`3T0ht)sd9d;pKa?~^_w`#S);XJ)vkY`vvmm<~k*1ph^)0$v1TOEYlieqt&U3VT1vQ5g8 zt&i|$WCbmdV*45Utn}#L#B&Qd+01o(ae8J4+%pS@>=`To#-znATD|VwQWwK73@IHFg zVvcwb=D9)A{Uk6uhj22KvJQKqyA@Cz0dy&|meY9IC z`ibC}IjP7Fos5vw;}%+%Bef2U-E`}QkDc3?*Jdv#_lk9)p?W`#ul$3}@|~FMnDbwT ze=|opHnSusxpW5;RUCuo(B+;JvylhDTebYjzcWB|Amy^GF@)V9nv zG}VU)*LH}Hrh;r@@XrP8)Mt)K_!`Z3w(3qc6fx*GAd)w}>t62nHp#C!PL5g~t$_RU z2&LvKWX!JFWBY32i)w7%P(GqLBeig7H9^e1sI8@EOExctDsr(Q2Md>3Vtp zlA%uVw~H!4UqhZuox}=Z9orTFvBrhrvG-zLZdwm&YR2x@TLQJJn@dJa*KK6j@7pfd zYQQ*g_xk{lXozRXVUeC23`>UKS97{Xa1vPp%c|3B7izWz{>@N7K*8$co{GVta}pWr zeIW+i+iwS75|$y`M82Hia-(2RS@Xn&P@W;3h*fPLjtrgU}T>TrWVbJa+>zRb!0!0O( zwVa?|9LsHpEb+0Q$@6GT{KukHFy9k$Ptmhl0MSEq8cI35eLTcJapSw)_TaEovJ1F` z>IYceM5GTyEgNGw_mo0Y!$@|D#ve>vr0MSuvHPPDC>{b7)%wADh!oTTI2Y=1XijKp zwq8TK`3;94bsF~VzhjDQ2EF|AxR8o7h}tqdIny^sA9D{&vyczu-5{RI*B^rW)A_h8 zj4v-#-h{(q)=0G2EKUE}`}Y>8XhGYHYXc+=FK>+qRjoz2rs|O$C?Bw1>6CTT$w@N! z`4XJe<g zIlL;MS^iz`M(e*Nkr(djp8bvpZe;) zqqc9LW}PDX+kkUpSD1Z1(KkN~1X{V!jZ;*u5<}X1E1`eEC0`X&xz;Xv`64Z-lt0h~ zYvcYCdsPTft)zLGQkb$FaNprYB{I3BkId~N;C-idsw32#B#1|wpp(su{nLJVFZ|K7 z>G=8!f?M39p@$9oWUJjuMFuaH(|libOdBD?VVA+FSD3;R zA15y-Ui0M_4`L@G_&QoAc8bXTpGMN@KcZ*Wj~S-ALRJCyDq>}B1*K;NbX}I}P1Uim z%LV|m6+@LjdWNxdW&ph}kdJ_&0e?hP)hXs25%*;XY;fNE-PKMr?v6kYzNGCR)TN*RuNKi)p+8w$ED*|3BOwLWPDNHKYX>(<+&(bmW8z>(Va-#y zNXk~uMO-qunVPJYj76tr_D*{;J_af5qB4ufFWLv3hc*`n=f5SB@uuWDwC6bFGOIzg)i^N9bk&8P}#^0_Awe=&;~WhM@d1q@#Z&y=NOjhEe-SH$~%A}1T0Q% zI{kzMpTKhrWYR_F_|GVeE-;;5KC}nY2QKydu0IJ4FxnZfPt&EVRtENZM6JYx2a~A!_tGxfU#ev34TrQSdqnJ+yc2;M%oN*nXD|}UCM(d*Az_RB833Cuy1-1y zd!ERMa8=o`5_nQ)%1@JZ?goLuGhZmD4lYSJ?Y2Sc3UVu%O_F+gZ z`_~7j4ptv%bK(?o5@&xM_*-g*f-{XinKL0zF1)}(Uj$Pg;2ni~y1t;Pk_=*D>h#cT z>(hP`e98sdyJ~piRp4)kXOe3}HFWw|bUsh1SphGsspMd~0u?*pRe9{0Z%+?m<4{q}wim35Irl>sy8K&WNfty~C$@@O4O! z3LN{0!7qM$)x_j?!4-Jj5!m(zl8)Z6*Y8aaED^bGadspXoiwTKQB#i|#@ezHMgGo3 zNqPsufHgflt80Iy)xK2}bC*K6)Q zD60o0QNy*K67KaAb~QjeLpJF)~#>~h37FM85=Tm9CeXO4c|NHSN?70ouv8T2+l z{D`5MYUMwEZ!q{XQk#z6x3|2>IArrKyLm3xyzPnq93run5q}AP+9cl-i@VLZ@L>gA zS-nUZWTOrle*vdrLAQ@raZIl^Yqr3}%qJe%OZF7PN;pLEIcwV1gdM9O9Y4*V||;*1PX&dB9 zrc;YbNZFbQTZNL`2F-0(I4^tiNMu=?ThFlPSVeN0ZV0_!3z8PPvb+avu=J~N$EqWOqVDm_BNpVez-_(&dKhPp5+U2!O#YOYY-9X`ipuX4|fhZ}TW7 zLNq8xDS2n{bohK!NJ|uP@ogdWEFP>4n#%X(-V=!bhKWJ@!Rz(U0VUu~5yt*Ljiwwf z@%>9*Kq4CqIkmobhohEGiXORY5K~*PVZh07=Z!FhvRZEE2-HA6qjCPw0bT;%c{#yb zP_K+Tm4!P+8)VQBMRTo!%`~5Qr#d1&`Nws}I|ydZFGRWe?#mH#o@j35_$j?ME2@UIWYx8>Rf zUSwd0gohs{r)je$;=xk=zQe552G(fjHB{xS74kac;#tn#WqoSZXw)Y|a6XQHu&Q!{H(@v+vl1iTlAB5^v8qyS% zG90C^%lrVam$5EX_IB*fG^s6;Y@^R*Jn5B(qf>~Y+;5Y-7SuUqp?;GJVy41krG93I zPRd+NUb)_-m!w5eKbjxS^b*r+ooT?k3Kpfd`ExTLq17^aNixJ`>HFY}(+I~u^dVRE zPE|eAiHB_y%&kvBx92_&e&ZXt6b`fXfZY?a*^TyjtkJv7@T+8)%}K}2aub@IQ_X?V zClb$dXfY`XfgI)gBogn@&j~qdjEDW{v`MjHihhDqUH?`FMqh`JL4OHrmoQuITj$W47QCM=e;VcY0*PdlsIMMRNoy5xM%v zE62A3RAXbMLxz*}bk2|$A?(vodZ)-1k70BuYP7p;Rqv;a{qed-l&h+z{zJPu0t!g{ zn-G2-&~UG@5T}Abc>6o((-`I9%dLuI73yapv-3#JR`~dx}X9ElCV1 zo`xP8(aFGPAtJ!v-e8JPZ<$w)OdJ!l#ul~B2VSI=-UGO6u_A>y=(#`z53Q9fb_|S)l7kI^SmghD)Ay^IB$odGC!FtONmfqDJBb zt-3;{I9gMElgL|s;v3DF9TTsA#GXMhmBg=Wzvw*O2OBEhwkJVe%BcPlO(qNB6V-xtlq##!1QDioh(SM`9q_V)Iqm_YrggY zaO1qMAQ;359KM$)LXGxoreLY>6 z2GioXqb2W?cCR3~Jc>1&G#!S#`${I5n$urk*_|QZ|ejTTcdt#kY@u+BCrr+lA~R+H&G2y408Uv zk0bDX@b7L*e^r&qtjHSrsMIAzhu+5Na;O)h$M08}UUZZmM;@zWF>?+!S zfP^-gDt*9)d#B$Y1_r3xw1&8f0Hha68mgPl?_OMP>3;A|ga_b&*Ua5AYBI87{JY|8 z`PiOo(~-GgG}tK#If&5@+$jIa>>zC60#|~M2v5hQ!ClQ__dsl=}bko)vn*k~^Q04;8uoetbw*D>@O}$`KvRsy; zT?{knj{?WA^jW||B%*(mjM$~YJ;!XNk*cJsEEFM-YDH(Hw#%7X01fnAA!}ffmZ-QN z8!2Eu$Y8cmZutKN?)@FP+ghSrQ(M2F+qR07`pUzKzpiKlXjd*0>(^)B-GY{b(~srg zXqI=_Cs=pFM8qEi3QR=EMf5DNoSvq3vuF!=!c2*F}9sj`(nqcX>VI9F1 z3iais;y*W}Z%vaXzRj?i+PWvNWtbedIIRMSIB86v6yBc`g`ugykECSC>pVvkv8zQw ztU6^HDusy=%zuPyKue~J9{ohRS;ZGh&UT4lE9zTx>Uskd1f@hgFjq~e1obcWEDn*W zb1g&i@KTb`guR6U^c>VP){Mnubk|j!2=fT2f2B9RqW$?pz0iN_Zx$_ZjFl2Z|G3TN zedaY@KTzG5FgAvfzmk}aycTp-Fj1Xk1|xh}3`I)P!AXt#XM*~-!e}#!Vhx?nlTo8L zmdf+)k0~BTc1u@qmfXIF0wVR?8WOv-K5^XC)56x=^h51i3k|0tEbJdEEi^xKBhoaO zzuDYP!9<>^dyP@~KAeCQLa-Y2M$kWx$48Kq;E(ghY^S1`9ZBs&JcIU?cffsR z(fJsKgV$ZwNe*e9{eOzWLZmv~AuSS0!D4N1Vqx{vlrboBKN39n9zFggJUggw(cJ5nTK1%QtGO@>u_VzJAK64sOT_! z7NDL9JX!13?A?y}g$^fc<-5g?ulTpOC{K%-2y4cXEfUE^r(2HxgQvl7lZ;kkkLs7{ zlDrY`#v6xBj!3@tgpye>QOxVB?FM&p2bJV-9P$t@kVBuIQ2vQBM}5*%+&Xr8BOvzg zo`{}6&b9I~)dj~0KAx?%=;EmK9pG-R(@oTzzv`-R!P~V|(X7dXMlX$o(SCn;PwqVPq2-pKHw86yVj^BBkD=jJ0j1ErdeC^?c+x+~ai zib&q{uVU~u5yM^G*g2W@x}1~vgIyL`D2rTSOaJCAIuVO36-_2%t-+EB^fP>;m?}5Y zC++{*T%iShR&5{Goqd_#^t-1ce)LU2lqeSBa+*!rho4!Nrp(9s)Fz%yvNiALsg7Sq ziwY+hpnX5_A_twuBe2Ta0Om*K{!=?B7$BBtUG;;DPQ1#Hq@t1lcks|P-clojXufVd z3`fj7&PTcM57N_6$mCo35fFFyj4{{ta_fS?C!vyS2H7_LEw;+vN&s3iCCG2Ob?5zh zUv-(g4fCb-$jv>B)g22il*s54u3|d*@LG5o)NhtROr*E0#Zf8mOGS_Ie#)yEY8@fm zZb(YulFt((Y?5o*jbXnPVv_#WvNl=;@+|aQI!{*)tgIud>0gG*@gjd1z5k*&n9NrW zCqG!TZTF=M21A(SWqiQ|=SYOfNA@p(iVcw?V%p4B3w^C7MMSN741uS%?hH79bjW{9 zoT^%L-onZ-Q2i36fiFaz0)7;!vDs3D+L+v|Hjc3UMePX8@QBDzU==2~cSwmqt%$|& z<0h(Ao!W7DoVZT&D#-u$H}johjTIj&6HbeBqSLYT z(kae^`U+vd`xAL=!;?Q$_!Ol03Bh6C+%O+n1sz5jPyFyivogPG17ONDU7{q%(l1#~ z25j}?VpOf&j#w3MFYyFs1ZX zC$+=Hy)CdE%XxVnTT-TtL#3!5n(Ye5^84>yzEzw4e*MRWcUG0IaoFt#7rP@vPAB8Q zx)?i$?>&caI2lTCQG{beM@tUBBZ--~#J+$vxwO@5#%`;)*I>@W<7$<*-;ehZML9z? zTR(&N@<>g!S4QUeVH;fN*Q;b;^TLm)<~1UAxJxs~$kN?T6GP{(P^8f}s!uc7)hFySC-`Ff2@&y2jJY~l8o zkjh|6ulLQ<3Pc}H?wl!vJY*xG;%Q|b?RPA1ZBL^*IbWM-I(Yr#*tZ4T0rG^~by{y~ zDw_RWP;+bakZc4REfl}ywjs`lRlunpK*A~6-lM;o(JV#EJaNT%UlXc6dL3X`Yp1vq z@%Sp1dkR#lYq@=c@LOzy=h$HLvv)<6o&;Qz_3;+x#jwBRbTgtMlwD!1@=IBx!y3V| zYUa-st>XHC=4E#93d0NYQ7?5Ip9xM8?{BZ1W>bU@@l`*exH{@l=af95;(h8 zKN2%H6rRSHK9L#;cM$J7?F@<9B;|j4>$L*xt=;hr`qtc(UK5wr1HAoehRLRe!O3Pr z9zSp(k_B@jn18O}sZ}6qEmhKi6+;UxjH4ihag{%wJyw7^y|k?}-`E;OddrnK7-de+ zg~=mUW8O&d>cdLZ1ub|DH|! z?syk~DD2xL)>Ek~Xk$dFFQIvew;YuA!-vvfSDiJ%K4z~+8F?FAhdpwFk|Fs`O2Cv& z%pRq*XB1jR?*wtO&{4c1IKSbXy9=Af7f9M)yB8HYuWjemXIh4wg|Bx&(7{Yq*ka+0 z!HL+y&XC9LsWNf+o#d-={m+Q|ykGEr0TL+v{66H}JLRx0_LfXh-&0MHw>N1*I66ze z;WX;Cv_i4GQ3#;ewnSB6^-DJ?lc~u;S6H0xI`fki7*GtDoZ9}^urIU8?8YTH3pd`& zj==YX+EA*Iv1(I%cYfVb%?GrTQW#4v$QoO4iD-&1RLV2#`wD>FA}SP8<5L;6)RFsg3WN5#a<8Z3PyQIIphfYz1ZL(9a0FZ^WWj6v-@> z3@_dS?%LFHOWp3$I0I58s3HlSm;LYFf3QNlEa@H&NV`N!0I9-52>?~#C>ETyVaET( z?xzs%yRx_Ya#tmj-ChtWLV;AE&B`=tFIgn@nN3xcEU?-CzrxtyL^QVSY!jvs{Uz4! z#F-nsooRJX``Aw}6Qd9ve`Z$zOujbUT=pV`i|wIz!Fr?px}(ZgM8k!M&c8I>f045 zC{%xEqs24M0hCQ|EM^wt5FW749)UjNaVOO>=v{DW+?9bEqt^LEpr-&h^<8Wm;CIDA zb$%TtkW@;Xg|;i4hlW$QR}8wrQSc4UkB(})>y&0Rd#xno&~C@ZxUQ$qw^_0)vBMYkT!walER}iRRac zVJ3m#7=}%i_kXUz>x{afp1w6vK0fQ==W(Wpiewst(h@FxC2NcX?!h@Z>i6|JJpm9ac>VM3 zM@9X!4d$3>-(6H;qPyOYvAc{#Y};ct{n>x)9!Du2Yw5a2Yg(3yf_W9lamI8MwZcvs zgc7w#M+*F;u#tQK)=`D6L z3A>h!xv~n;KIZaAGCL(x25Dxp90f`yWG?Y%sBohrF$+-@W?P{F{Gp>j z55AV2+8C;YAJoqMXVK|ki*~Qakr0c<0IW~#l6c-6Q=xTw^H@JR*{ElGFtFo=Nd0dmFaEQ1Q4s;urEJ!s7=7jw!vUS}4Clj{7^ z5cS<$WDJkjsx5t6BUo@c?_m@rS~i-XAK?pE^%3~`co?L_evZE9b&%r=uz1nwE$>>x zYc>7ta+{#l2Z@|kGm`kVT2qg)0nr>|?jcP#ezz|Fa%Hg7M%{LR+Qn zV2gvFr1s%35BqT>k2by9co%`MNUYGf5hoZR=wL zq5LG+s3@D#V(rSMLNypewby?m-79jmZhqYQXy=fZ<=}6dJSS^)6GIVglFHCf`1wKa zO$kkwC-zH0=!VT zb_|nmmvXMjK4lQegg<)4*OP)^E11HgQCai*VkRo5rWPK2GPk&PTNai?BX-&uoiCkVzxzk>^4U z%emM<61nv;UWH3akxT^R!H@e;$lSmM{R*v}Ci|a!;8d(GgPj1nG46Tq6a-gj8GgUF zX&l}6oRoge>I14fg(0pe6#t_s+=*P;t=+=WWnTJ6g^(n{I`OhBxTSSkf@GP;OIibX z%l+$`FH_xTjilH>=3+A|@n)AHGFiaKLd1S_ymQj~8VU&eKnx^Ts1oLfVv9DPq)krx zmw&w9Q7j?6wdi)`twPD(xa_NK%`K{h(2rQ-pPw?a=49^iQ5du6Gfph;BTu$?pt8rY z>hI|T3pScN8Dw_vRGg4<}e7;jL&>dPJu&)~@Nw05~z)>XAYH^baIRuK1;^e54VmB=Dg z331)%8ky=*GmILJOIv=lYqxlQ1^|2IM1J3>o^rWVNQJ(=9TZHva9;MwE;yxi4M5BscUJ{52`f=&nRIYow~KsA z`1h`T)_+p_Z~HrGrno+3uEER?O;GU(9`JSefASSk`UP)|z^-=O;a$@@b~cesJVu_ehIg*48{d1>K_%(CzN?uYKjwX9^EjLYQG){?6jr zo2h&Vq}~Zj7C3{=gU+DSEk`}5q=x~RC`F{d=;x%4h`t7 z5f`7~RVHgzO7s4eR>C$$XQqZ@ttAtO_4T!Cz%3WP5Po>S6vJRRX+$mAKlN%`iQo+B zcR|6|87l4eZT`F@YIf*l;6ZFdM)w^NeSo9h&CSS1JAczsO^5!9N83o>bZW;B0+hCU z?b(MT6yIX*IN!BFd(47H2w|-=SnqQPkg2AAP0f71_wlL8A=fT(7$fZ{$3uZ56PD)_ z&-G_1al-HXdE-4^*G2Jm1Jxh*jrSt?L%3B*E+mjX=9(Sg7#6HTyY6qoG34OZW|*7# zik_KO>yKajQ4QulLOR=9)J* zty8aEThMMbzwkf(cHrvcvp5pttuYYL<{mUQgLk>|AtG7{6Q_gdE%*?wA*Xp(N7B`a zkERbSe}~N{$b3pR`&`4jVilrhJQtBb{U8i^Y}JJz#oC3ii@4rNb+6e`6+IVB1jVI zhT$d*G8}mw@#a|pU(CxQ*H|J8G52Tj=H?BM_;KVTpCDr_P_W_YC`E4!^c;+hd?Ws2 zoX5EVXi83{Z?Or|PQ|K8I9F(DoTd+DM+i(gh?>&8JyF)t#4{=Ax~#|=-v6(n?|pn1 z=~B+ciq0#OdTJ?u21R*UsLrL8o56%%fj@sb*#qF(qY*!Jy$w4=sSvG#g;GpmFC#Mj zyjQspbq3Cum?S2eH};IB#J^6wnW{pSPvV){g(GX-u<||{O^4x=^z2r4s`+gb_qs=- zyZN({b;(7xDrL(u1pG@s27`aIjM(45Fd6IfW~bmK36}knI83VrhYxAIBb?EHxCJ!C zgFpRZ#|cGXKjA|qNv=%qJ5nWMXhL>0X7<7p8i|}r(J3nA`X}gqCwyJx=|WldnL8gH zN#Yyk43)UxXO$%ygZU|rqi@7yJkrWFs?SsLG<5~>SHr=aEf#gp{#$FDFnNQR7;eB!XT&P5lChH?dL5)Ml;YUlq!nru_|GX=3&(X3glR40{@iDf z=#4GFRS}0fQvAej-FqXR=fq5#yU_owKjtASUHO1qc5b8MJ65Z#HKcRa>G40Swb*k!18_O@?Zb`aitH)>5vQ$f>l8HA?(Q8)b7|$i3$(7g-R@i=2 zO_5REqA+bag}<{CbHfOx6@G&(3I0NYh`XSjcP{lU`lz#g(+oQAQj!~HIIHQ zTm9F9s&B%e@N)VWXawnYl;?6SrocpyCm*5dM{RP;U=W8U-qt5-nJLE7grq%45!Ch< z96wG?p_I@jwM!mRR7>$ z(Zi+tu|$p+USeeY;Q4;=zSKdmjc%abF8SCN)xTkxb>`ruvbq;-)CT7i;%a-S_;7!5 z5;XzN(X@7^z$zDY$YiAN4JQLm&T9S!awwUhKectmK3{9iFM^feI=|xB9OR)On5`gK zOI(v2)N7LDri}NC+`9T+BrdF<+OkvGh&}`SB)6fiI~L5r7%Bcb`*Plz6qwwQPQI1h z(?>Wa4QZHE`U}4}(sp_2blX7Eris}mDu%KPHIK+D0)w{3^dD{~v?fLw%Gc~_1s09D z@RpP#*>Oj%uZBTx0@-1$!PaLSp^UEfUN_KN-PR^x-d?N7V4e8w;#c~4s6eLvKXA(( zCizCQ%bt2kgckEJJz9~FlZ!w#1fKsu@ay0(WXkJPy)TnTM1X!Y{b4HTI=~CRlTFjj zMM)23_SHYTpp%&_AF6UV^_8w6e)oFGHac zF>=)Rg6c7HLu-fs@EW`mA(}UwxlSZEQ6#rbuoq?X$(ylfI02E z%oE&jK`a?hNw;*BuBKJxu+uM|9r=&mVvZD@1Eq~ex9B#0WMrDp!Yu%IB{;6R%7~fK zD-ot~nK7Lo8dWqnSty@{D{W0yZ*9{(@wEoP@qEixiN;N2eyt>bM;+}s_rR$n+Z3eb z{yzBKc*9D#b$-LedB}md?XlNb-xEcNtpT|!P+ZkC<5rJZ5dA(!-km_B0#_)YAskO0 zsnEj+0FyoTrvrnLQYdwZRXe9^TeT=aS1)}iMrwFU8;+1u1`Aq~GJ=gXeYUcFQ3o5R zG(w?&;xmd1v8HeySn(PoTlAS}qXHUD*rkWB%FYa#%y((7Cr=@48D2Tv$9m}_ixptA zoCG`X+Wp<8rbdfJ&8=0lys8a|P}b2ATI?yLI~Pi5kAB=`5$ALffey4b|J3ym0&lbA z4AS3&G`j&O;D%j(iErLNQ%m=Pqs=F;0zul;KTeLQrsqlM1*B4gza4U}UM23MxRewvF|rq9Xv z{UPf7;GaSo4{P1sHa`tsltKe2h(XYCm?7|;AUr#Xih27$P#T7i8{%AT9QS~@0l^70 z8(p!2XJax_yHAhD8T2Pn0A^>9J6RTD)xWqYvnmmgoEyv3l#V7W;h(-V^k$1Hr#vXa zotQ&Q{~+L&5dQs8L+USP4fPirjRQ47v)oaK7q&X8QX(&@X+R~&V+>h_6zI?0-wV`S zSN-y_^)eHSr%fG`P*(&O=%fj5jb6vp5BS4FJbuK!-l?d6h@fhO_jTnLRXx<)2|n`^ zS%G}ZsOC-PChrL%mvT8=O60ACQvmmvNS_k&W=gfRU`VYDqP!>ThAu(zY>?r@_=QK! z@YWNMHViq4tZ!kt)|<;ip_4bcNo7M$C3XT}G9hf>`)8lW>|odwq|1xV7o@hmV3drW z9%sY=fm>1fnyQyT-c3gd>B?FErZ4>5rkRoQ7hj!tW+lMgrKEBAEfTE6v3Qlil9h~% zzEdSZOVj6SI@eqfl52kjCFp=3#ihXnSz=VU^(E6@iOkLMUlqFdS$L3OYL9UPOv#e6 zxofr9Zh#+>v58v}r!6;f1RLtzZyE+NXd8YCnEj_J) z4))*hDBOHyvbqK0R`2;z@M&WN_OCPbYAsvl;3DX4w1RKr7GX8fk@MS<%F1gIdy>_4 z^Qp|#>PJ^09EEXuni%RKlw3KbM%3ENkJB@KSOOXIyN)arkEEgfc~;J3L&^o)X7tya zsvjX>cf+ro7QuSB!2tk+ax2ar0sHprg4qVF!7z_Y)$kttwuZ{-+by5K`w|IRa0Gc& zzXP0t4TPP)z`|bkKAa8S)EXv_s>Qv8LK>oS=Az{kM&%~UtT9kKmLUTxYhiEqgyyAx z{uyvpzN$y2nEv;|@M?suxKSy+8VzTU=LJu=P}v(0nwM>H+n(WKyE3H}mGwTdvd>~P z0OA}Q5VX{^*AMq-Jf&tqdOX!&tW>Zt9c-2eLRuqEJk{x1HZ{UGo*YXF0q ztme}?f>iFCOx*0QGB%g`*?$&T+XU`n{;;5q+9SjC5y2{Rf2`1NXAJD#HzviIg#H0$ zHzB(%yk_%$4ffuOuZ_D(?6cgT`#d~Ir=S=RJtt9y7N!rW9C8)~7Pkj4N7CSMk#L&Q z;aB(k;TM_P1!}mJzGoW&?wpriFkh@&cFxZ2QaoCtNg`DM)Upg5w&kZ4i?W1c0SA$1S!vUsVu$!Au0Bamvc{O`3=0;h$VyaQzr6vds*0UH zVOY&3tA;@CXvbJB*$rY%oxe!g@9C}(`PvSkeVEIFB2l<9d z6E?TAwK@^0Id~yiv}>+Oh3@x|rr6A{jCXmbJbFS6T|RN&kKcTV?uUv=!J3QKjMwGs zW=K(I8>HsGhZ|yqx7aHLWY9^TSQ32=bA%gByP$YxpHW1aN3XD3Lu)R8citwEnPc0GYCd>YUbe!PA zp&hV!jC8+cIb@(Lt1904E~Sly4iBeD_Ou14veWS(2zdI61&KH+kYGcR@}nNm~A?`5o?&tBtnRzTE1a*V4GVMx0DnH5Ev z{0Th}d{`2uptwJvS{bj#_-;hKsGfvq`2TLT+*bzf``s{wwK+95T$Vn__m#dpAGFr4RPAcr5@<#$b%CCS= zLMfGKi2%Phjx%~=IEgu)UICLwBM%Zl&f|N4R&wsG>fO!(ZoczELjBc)>*iH>R9{6@ zUwhhP(EEDRrLnx&(BeDO`_TAV0RijJsPYW1jHI3=Mq?0IvOg(Q2{}2P$FB^ z-WV)Xj;c)@eUC|1Vyf9^!!PhhRXBPWvx1`b$WU!UO=Gs#B1C${{ z20#&NOz4o?DA;kso}E4A-iX|`x(1CHSxak8{y^ql?B80HIh+%sclJ;Fg|WD)VZPW|awtD(GOuk*o1ns;z) zeUE!5L79&~M9-8q5StvB@s#kY+KPW&aUME^yRvTcz2xq04S7NMos4#1o5Q7({`86& zcy^kHepFrCKFi0ZY>$`g}L3^GP88VeK@# zR2#FcEBVq%kf6{n6Bu$K$M?rNLFRLdst9(Cy;8>O>*X>f6z?JZ6!&{4e6IR7$a z(RchSiqJL(bk)oQC*YJ-%3aOm?t2P(ul|^bsua;B-zOkb3vqzMBC!%B04P(VVr??i zn;070%6NflWjd&}xwQ-Nv^iTQlwWj+!7~y@jw`6)8SVxe?R+M1bdaoACL&c(TxTKLORL38wOM z{kqf~mx=LJH@xqmzj;4?e$eE?9o5Nk;c;`v8zLH zB1B5}ZurmY>!89GKeE}s%rx3!mL5lZDW`w&o#mxXPUa{EpUhfFPwJ1uA0QDvB~x`2 zpQat-UbuK)yDCx#8yWF4fUk(rjvT#V*$l^jf+_lt)0k&`@nFs6Fchwn7G}-xoiH{c zWepO>1S?x-Y-Tp`vP%Ck7ooL;2UgTV7x0}W7C9Er9u#PXijmajhUcp;is9hk*(yC` zSPdO`smg#HR=!&kkNkCBxGg?Q3U7*m2E3ZWU#ZO3Lf9w&*nnFnPm;PPV4OLC(WJZn z=bK=sPL#Ej?w#p3a)-j;EKg`ju`>LSTJU=+B3WFw{A!2X0joWv0y*96RFc)IIH_Nr zp3?Icn8;;pbxAgI@%lzC?Q+X})^Y{7e(P)5Wr(=>tA4v;R0#{H`H_7{nPG2he7i4aIdR9J&?{-49I#JJP0XLeM@;E%;%&3MOc%$N$}l zUaK!BJKY`R3MWx_)6Z^H@vK3#fmRIcp`ctPi^2%VRTZ{-Lna zr`~3&h{6d=pCm)WCF}4bE0M?7E5HzzH^TtAA%lM|`FVz^^zRl`tK`F;L&Nhaqbd$} zP&9uem;%5DarySaEOpuj#)h(}qZg<}!JCd}Rs`vu`%XtYgu-^_qjrqhUQtC)m^WZS zMXztM_~Y}9II+(T>dxGPcM*FfY18zO(&tEeO5|P_6Zo$K_d3FXtGrZa>L34B__)EZ zj}~qHJMc!ZRL4NS>1S260Od7okCT^m;H+kd#*qG?ch{r@l{L@+GiJAIk#quV8Ie9( zK9+xD0nd2WI|17|J?s=FDp2m+Nz@>R#0duacyDWqE4Q?UpIcb&oUi-;AMb!x9P4Ae|AViLLOAq|x_i!KS`w`pKKG0o4=5g5-HlmHtUW}@AsDuZ}cl9qW?vgwaZ4}5b zl_zifOh4|xYTzLzpTIVkX#=%x%vc?IW`SM6p8!}T2g?PTmM&uYs|c=-`Z}8YxaShg zmyGi=?;A*YHa7I2GdxG&*dg-k+EX}Bw-Zw}+lO=ZS(p)GPCHmtf-K)P>{67+=eFPV zt(sbjBGZb@)#($LQS{Gfrer30V*ETDk6KUzvOB|P?|>MYL(?B27WTb63ILcj!^CBE zkT?)v)ywhDe4lD1uE0u9>yqDGb=zx|kSAAya-767Cjbzb`#6XpElS5ct^ z11G*Ggo$R$YS-EAofseZ331ArKbt15aIgp35nH}O(-Mr?S1Zjs#VW~w$SCF_to|?$}`~_Aa)M!ZDwiu5bI+%P4If%Cc zU3WyY(XMHKI#lCO2-=52m;ZvhK<4Gz0eMa}cAaYjBW?`?WW-}kzhWylWt zTiNu22S#m%_D}YI1b$zLppLvj{Z^mM?EMTwSiW7DJ%cM{_r(g3>U4&SPnIL9qep9* zftdc_MZ;LP*MCBUFP9$MA0q9FfB>x)3ZoD7HKgy4kR0=aCUU{wv6T{pGiQe8=i@1I zERLC`?%=|&0M)#P(eYBASZHDxa>n`2CEVWMoboP~B3gupsO(Q#6{i_qJ!n)T@4L~= z=H-@b=S%+9ckBnuDe}_k2>D}u37@?&3Or0fG_c1d7Ob9No(&fXlV3(=lxgj|&X-}y z9enp_xo2SXima;-yBy`Nt|>b7vQa>y7=1EHTmc$8tfB^*n$BJQsADt6s9vM@3gxe= zg?u;YWY7LinOEV|1-Oq(ZTVOS+bL!erCg_OKDhr(Z+tbhj@v511?WXw-A$l-NxAc%7*t&^Nf8!%Dn8aF5J&gTrUz23A7@$}DkEp9)tAc5wba$7uG>AxtbR!_$-7P87 z-O}CCjdYiUbTx%c{h|6rfpiL*0j&gj9C`!c^hxZY^Mh|z2IoiRwLOTp6m zDJNy(e7^9r@w#f`3P3sr&Qq-eVJ58$JB2lSQlm8P?17nl-P#gAD+ACp{WXH9{^(~@ zMuv5lkZ_OScP3B_xPm(m_SiF*DGXUHif;_dd`!n)2Ry*+c0=h+M0+FFxWGdW!jcQI z>INpsTX9*{Hitqu?H}^t|1fnt)fT>iCu&%~FRu81|NPI(F$_Y?>bkN!9*ZH-v&W*c z7yc;5%dLXSs-C8&35~aglj}{1fr1iq({<8f9bky37+O3NP;s&o*fadHAgO!$xZP1C4!Kr z82=wnd^uDmaAQco|}9UN~c6%Tg-o^&9=f(Rew{q zfnJMmg^FWR*(vc45KNPhLX)gdc%Us3yTW4wfDFhea8$?8wCB|xR$=}qtI zA&xn9Zl}&$hWjHrJ2JRylLG!OrE9)T95zAd zdDg21ItZx)t4&(-gKQfNW_L+hMf6j9N;Y`^DO8>Ltd$i!s@tnTl787o^;M^@qFcha z=-y#y^4+Z>J7fTacg(u@NTqI#wS6td?b(6qM$S_zGEsi2J{96EdBPtJh!!tiY5?+5 zVVA`Cjklwx@B=Q%xGay3=g5iOK&!|x-JT=;*z#GsY+&PW3XL{I@shPS*h`^Z=dx(8 z7^6ALadd*dSR~#c1uwO7?Duzb~X}d?%;R4J!`!xI0BV zsloa*_Kj$@{l5VoU(hjdMK~hRh|0JZHH#xK|6It!yuaN79)nm`iq<26rDegY{nPId z;a@pZl0)EfI|Q3{s(qHD&n)|#_sK$Kn!)?2iM`;!d!y?;Wk+2b$!S`Q#mw3T_vD*yzFo(@j2?`4X0)~E!{BmPk@m8B9zNoT=n%b)AN=!Au%9Y98ezWBEOMlRmEjFKUYKaEVidxC?;`$IkNmyKCLF* z@VMty22h;Hy%Wc|TY ziB|go`MP?xM?8Xh5zD6#qpD-S-V79EKhe%j@VZp!Qc3- z8H)fv1rot7fDx-sn*mZvq1=)SexCP3iYM!+p3E+&kja<58!aZRp@#QhTXp#g8ll7%nnwuY^>x#ShW`I80QOKK{$D~<^E3@NKW}&?N zFc1fj$X@y%LU%90dxt)ZS@UgG*t`6Oo_Rbby3?mO999?W*P zkYrm@UJW>#uE~W^9Pby+IhAYL3iE08;W}Jc(7KqPPpTqk6wwFe1Nu>Uw`Y=B6bC)Q zpYm2quj7@Jf)qaC5&A(GjkW@3HJd?hn8zu|Qc&f&)oH9d9knADpxV-fxnV4Tq#LPkE2u=~7qZ z8F8OP&azCWD6Y0zlV?fpZwRXnn4YI^#EnTcV_yfu2Am?ae?vT5U^Wclw;YFSEhn-^f-Gi-^O9?v#c!1(bTnJT#Q69Yq#3d)j zw8r&Q(d7w5vQpec{$oh0b#5$x5(gHj2g*-kh;1OThuz5j_!?x9P8G^qeH$|24g`Cy z2ed!2mzHiy=7cKNpMvd zCklN=)fdW5&Uz|$0I{lz7;P?E=aon116|blR?@I^jEG zV>u&qwB!=xES9lvy>lWJO*msv7{0F#@~0}6vYi9S7RH>e9Uy*VLpGNgwJ)yCM;|Fw zA^U)^g@ZTn2k`gF#xTXZq-3B@F{hnV&A94!=^+SPFjYh#vqS2tns2DO^0}U4Sd`|v zfcw{q@P6jfMe?cf>RWR;QKY4+mzMM^2-g@`sJO$ITQisK%EO3lM;5{TInaY7(4tQLw1I_V$2Z?CaYT!^TS27)_UHVyRK#sIeh2=@aHn=<3qf=-7%@kzn%C60l+ssfai5&C4E>zwaQs zo7Kkk>kS)lDHO&9SyAJz8@=*Ire3OM#JQ%#`?5U16lj0YS7`FCU4kn4q9;^e^!p~& zc)t5SK1{zF&(C!Y6gz%#%I;n~zFsWYYXfypC_OEjGBXIKHM#dG*u+1^Fci-R*)2>m zk^p15AeIS0YZ4H&ehRDU$7@n4d{Km$hs&!@RV@D*4kEj-vsN6*S|R8btUBM;_!OtA zsDB^+r$K4bFZ`4Ffq3R1x<4#YcsnFeOPoiBN1|~5%@1jo^OJ8YrDIBuh`#vdysRS*OR|#gVf@vvvaOnnKak zR^@kFiB5nIL>@FZ7DcF4;P}6kF13EXSRfOG1ed#hXu*fsvK^SCWZjTyyih*X=9Yh2DD ze4JN}$31IC`Uorjwo&J&Bjo#5-+;6UTzQm9ZOsAK z3j#rBNb4-px0kEG7{m4Lvd`(aD_>&)(G+KV`x0hG2j57f+$N(zMd!V5SGfdTh3~Ti zq=?0zYT8niM5P>p^*@e@?FpRrL>+&^?}VvGL`MM%V)+_qQ3{mztCOqfSYGd5;TsLo z=X8n-+M~OmJJXcaf;uq2%4)AM7!7 zfQpA0)aK5mc8&T@e>TIcB9{Y)vBpVh{=rSsR@!v<;F(SAY7-*rDzqT45*;$OX*XBu zfLpVi80Qp#CeJ(atGyE=`R$uCZpf;lP7|wA%crUuNu){w$q}s(b|Bn*ksN_|0RG5s zCs#Hr1dN2sml_+R6xp>co6X*VQi#pQaAUwEtxs4xuFn>6LO=YhsWCWU2{oojavbc0 z{y-hclUUuL)odaZ9E|nIGG(t!5A)ic0VvB^gw*hBW;-07Gk0tp>k%wi=kF4ypzc6! zQ83f#1^Vv)_YFw_*+u_s8qH)$ojK~*jc+P6g*e)BqzceBH&kn_#&9RFlsNKDIFzsb zdM!h@>+zL3#tFPGeVPLP$BOGeRCRu?jNP=#JxDW9^AdpWm<2=cYZ)f1qYJO^`C~z^ z%=~16D5&lFPZ%AsAW1f{+QJyiVXGC|o?^z6vuJkYC^_O1R-J`QsiCoO9k|wdr8uWt zL~H*G6$!vo2ry9WA;y;E!Z{ra&53`%Gkl#4p7$k`4{Te@*8PUGH?sDq=txleNjnl$ zT1*k#io%1p#Num6QQ}J%wn5jDn)qtK5tHctaUt08sSBX!MoC}hna^?@S%5R0R>WNO zDGD(~Tu%g_xOoprbPOH}Fw6*0bgO@1{Q$G+$^)VJMM@hDpN<-mTinUCP~iH{X`nO^ z1uh5P>()fhxgv*TpGA>vN?Mm zSiSLtcy!%LSWBD=fEO%Nvw5%ZRQ?OmNYWEmb6B-#_b3G=0qm#bk1q~_VC4h#NSJl= z{+HFbN5#=7T*ju?9fiXxl z7L`xVGwe|FeH`Y0xmv!eskRD3?-UiM`g_xcW|4x(?UO+X2iM)z$CIe&eiCLs}@b5{G@zwrh>gcf=3vA_(QnYH$OBx7T!v(Z5q>ZRt0{k;nx#t@8E-N^}$3ni{t` zUDp{L-%xI~x-&S^4_BG3P!IlR6eA$h)Jl}#3(#B3ZNhTcrygm%4Zc(E1pbh>TM>V8 zReT6%N&UD=vf>3rY&>-MkL>cf^`64(EVR_eKj+M$_h3=zef2@trZY}F;fa>y0F)Mh z?DF{POLS1)v&<%4@2mQXufe-yy@fb65{u8DgE+e_m%%b(pMfyXe@bES^c~cz0F2GU zt#@wy;=VoTARey*fGJ>ZX=g(~dH@r;GRX?_TS)d`N?D#1PtA7-V~&|k1+&}R+lDSf?g$6C3< zjH3DMITwT~1ks@AklqwXmZIwDN&tH{CBbcA5z>{ZOv;@1-r2Jie*Hhz&nXaXj=xr^ zGm$nf7b+uOHn6>Vm7f@00h*Nh4i~t{)-PJ}US%YS#%K&`Cm%)}R82F`CtFCPs}2l3 zY599)4nI$f$fkz3JKIN!^*}qUiXUDMbpy{q`%t(UMznxR&hccN!#xJg&6Kk|&)7{3 zuTXqxUI4fZptc04a#M>)#jQp00K?Wz?Y6v_M!#KJto4$^PK<--Vqa-bCNBE4`M4S5 z?mI#$rTkL{3hwRNbf<6l;N(wWO+y#N^TltE*E!Z-B)y6EISKu$r|*CR+>uA5~Whx{syCjb6eN@!Rx&JQHhE_G3uN5#B;_Klt^O34Hzgw24N3<;)#! z&A`lVf=37#R-)kOo&7ln`BxvK^jPJ`C1a$BqD>Mmx0L2K9`x#8lzTw}MZUmez}$}e z5Gys*P!))FSwy_~F`~1_E@~Ee$-JXBg_p0x9^zR{RCUM<&VXSC(X&OjFF{6xVocQOy|_0L z`<_7;B_5z{`l7|({Rk`}u?H!M-Mnp?!BI%yj`m|c$62m01JYgm4-nj(UuRC9Z}1~s zBw+-7)MkM<2LFVF`bvKw&~r*!<7BAZJP7$sr4nSvz&|hYeom~}iNHt$(2vwanWF_i zj@}`5w}#4+EQU%JtlG%kIYgKo(Ct+V|Jn!t(w~4CBs{1qtzju>(!A-CQzV2QY2jYkf zawxx9F?YWpa6&wZk|R-zzt|>5!ds3fE;X+$&bTFw_4`6Yg%bR@f8Bil@B5<9P!KdV z>HQrwGC2ydUupO;y*uHo%P`>wagbRc5q#I^s<#tJ4@rIB9L5;rv{0P>_CufEDn`_g zpNly*8V1Dfmri;P=q89%QRgj;;orw)F1aF#=s;6++tGtt$ZBIX;+MDgRoq)W?j^7+ z+FugDqd7bCo3u%FNT)3&Iq^JjdXU0zm(nUfjaQK=$~0-Gv^7maKIo6x-oCbIN_*Cq6BIa`%_T(FEqPnU{**6R@I(4SOLm;o+J!XC<)L#oTsHp+OY| z3|WfmI~x`Hfeh}NoF7@$+9=!)ib?(v6+;8s-URmi?%x^=5Yh~Mo14p^#ql1wC2dfn z|C`_NZ7a-)y^Fj_Y#7<6+4(EOwRTM5yQ2Z8ZqJW%zP8^_DPpyd0S*Ej8v{PbOv=dt z(#W}-xyQ4bji!}gAk>2*a1!0>vohUYdfHxyjnQb8! z+k2pP!K*1GbinbiF;AbAt{$ry|9Fd#Bbcu=G2f|_sX)Iji{W}|MYqi9DY0LGVri#I zD@+UB1_%`|Ma3OZJ{ONOZV1ct6aLiZ$snxguA*k3`ST^8=WKnP+uCB|eKmn15=Qu( zYrk>O;SNq>trfhF1`+QEK4jrV*SK+^k6#Rsn}{bxD-Egy?yvokfqZzUkAU-K2c@IW zgLE_%LrYaj?Ldp_!v2ojulEa6244u^HC~X-0q6|rL8j1Me)n~B-;>2d^kAa?B6Z9F z&rsC8CMwQA^@b^C1b<=yK|F-`eI0nv)<-)cFbIcDoOJ-fdwNzBvyF5sH^T7E_NaQ| zgkHqQY0R!p#qKWaKduvmA4r;PG%0P}76U5H5?!7NJFF@@lL9sX0y{5M$tDO`2Ah|~ zA>^&Sqf}GnlV2vUSsgsYN|1#0GW1^Dqk2O#G{-0ij{j)U+@y6w-Q`W%4PZSZ>bs?NYs zRyxsO=qHoEl(E@>qM`;Qe$JXNFj(b>=JRN_Fki3xjVtJAhGKmVGw%R#^W?O8)U5c* z_feEBWGcH+Cvqi}ufY9$gSeRMG`Fjv>iG0LN}cvn`^5H`tUs7fp6#!5r$dq90Ln5F zrdmUF;=c`j4L3-mA;x#kw^W1RR11BjZhJ7T>;pigu|BEN_wPQGeRs;bg|hD{do>>tD^_ z9`-Y^xJrjtHc@5Q|7ITjd9QkFZEfTCYz6QT4~o!sFdJ`Mrfk~Xh7NIhaM43)y1`+) z3$fk4zPZ`!?ScE)HBI{1MYTjSUxofhj%X`$$5n52Cf{e3T7}G$r}jdVB+DIvkq_^} zNJBb|^>82x=s75SQVRh+Y+!Nq85p)ja>(ap>pnl?AZ=+>wIpw1ixx}*fxm$M458F+ zftP$!;U{7OV!))je&jy^d{`+{AE_cfZD-jPj3e6Hrq)N;L|yhSV%~x>VivoTF$kC# z)O2KB*XH>2U-anr>UKjUzuwRhvy_;f4!IeBO+oq!Orw)fEJA(|z`OWK4w2KdFcr!u z9fFmYn(oG7WoQLd?|S$t+gIm+>X4U~Qlc@SgJSW#zNZQ{&8nOatqlE=ndpMU^J7zf|^x8{N-g{U2(%QM>XkP2^MvDFqo?_*zuqg4A2hieT2&Hy#tl_}U}^LeH!^cC6x<4)A7 zY54oH?aC>1>C1dU1{{ax1M_%3o^5s2pB)93@OJvk; zC)(JTKgC)FQchoiC4>WbQf7(Vw|u_Zt}PQBqfX8nITnGu^ag%q(cM@G2}XXGX*9Nz z(r5ZaCbQ_!t_UKqs`QO;d;!$Xd|&KDx=O`~SvOYbZxxkqD`8mMgCrRr@{Vy$OQQQN zUZ6i9T)_gvRdyB3>yLVpuQk%yw|=zvyyHQL;RCJ%*bx>KHSaHpBO^_;McM0&!0@w{ z0dE#07doGWs5wD%s3j^R&VS#bYT=ImR4zd{)$*>2i<&S(lNkc?f^KNJ^3aPEi~E$r z3UcJ9*2ux!bk>nu{TtWu7K7#&8t=;?V1S26$7GQXfGxNfEMB>#-tgtc+NeYZ;yW^e z=r2DGGSAY2pI70Bq>f=H(Tcz`YcRe+aaj^@Sh#7%Uk3i(AlbT-EmiJD#FJHt|0zD| zP}BmeLwmQ&$f2lG?#cJHs zYNBhnCpKSjCW}xv6wpa`6ufKiQCih|6HL=+c1llKWt(soUMdwA)df|#1`|}g2ADN& z@UD2+<-F)6Afsr?PHmur6Y;?&_{$Tlv`N^Gjg?c zXJ8+mjFsp0-b-VsD6gY!oT=|Ei>sdO`b%YX4GM>@8Yq~{7EP*fh7fGG1wm?=4^N6i z%F@UNya)6$WatAj19*YX*qo`Rf+4bb!BVj7qE~*AWH~%-i=u#JI84*P_8vEfL~!lG zPmff|H+#;zdZ;;1VtwL4(Mlq0@|*e9S-ql?fRuHB5$Gz76xs)LS5V9sjT2Dm6IacY`+lc8(lT#TQ19$jHEn)RzZV-W^}# zEceegf4Z3dHhUVTQ^H?S5%v~k&dXzM5<%Z5X|q*JSS4Yo!TyiOSd36pU(W)WUZD?n zMm%e*pDYanM?jDj$-7??>CZ5&h#<8feJ|X43&E4YJP%9Ux5_WrYU16~SXMyQ+Rb-b z1EKe4Pwskh;URkygOpw!5#E#o^c7xpVFLr-o> zkToNKmQHb0#&KZkJi|c6(kkozx{&$S6VDGWpk?)P_;pHbvn_ae{x*LD39Axz$R4nl zt61rN6|epL{TG1pL*1JrtmcHzaz{v}z0`ECYoqO%b;8YwGV2KlXY$XEQ8PRycx{^ zU4wFRU=WT!=42}uEcEdTk@V+e7GbXEH1-8RZ0E1Q`!!}FS zDk3P^h#Xb>ac}Ps|H17D460{$*0}Fq5`DTOpEFV8Q(C6H%fD$&?mWF$JcfDIC1|Y} zQpH%^*&%nQ;&Vn?m@af1cw)7loJXLMkJk??b|3Ol3Shnvu{;5Hl4NP z+`RW3b+F<4s4Ji`4CWVCaeO0+k{l#{n1uy+TE-dpHoz5Sp~(;A6*%Jl1oJvrgaGSJ z0EwI&VJ}lSi9`T)z+XtiJ;F_!Q#&?k3Rqosk*Qi4w8I}U=a_0kr938nZ4%K1E*X)T z)_8DuUXC{yPB=a(H?U`s3yE?pd=LR_y$LVWNEm~=TYiW;wWKIZQMS-)# z4mBLuV_6a12+w#w|9tyzJ?pWg3h5L@`9*bm-w(Fq_4;i{58Kyx(L5~_x1~FR<|hzO z9+~#xtoOruGp>F1WA_3mpIF;bbQC;tR%^&iqy<6>!C?Xk1p0f^=F9igjh5tmJCG&< z7S9*($w6|Ggfv{WFpp({+8YUv!|vy)os?YlAk#D;yLfYeYFU>tx;v$Gg4W$*s5i@D zD!6;pmp~l_gK=R3kU4Egz9b~uwx%U0$;{JY*5hZ=UZT-cLMfH~T957@J>cpumf%!|p?)Re1ip^h}AM#J1)b7J>Tn(#0)n(r& z>Udu(MSd?Az+;4f*Bv`HH_ZQ-Q%1bmG} z;o#n@=Up;m8{WnL9RZBj{!!$?1At5h5Xg)gUMhHXPsuR)h>0&us9^z9%ny?HE{bi} zWXJMwB|gQsv{YC2igR!y|3@!>@>r~qj+f1eP*M;$Q(}yBG*g49Z27AiJ|$jG&{tUp zafdn@)3a72(#nmlf0*TyL6p%+>me~Nn6+RGL5&J1^W8nw~ z=E6nnApH0x34fd{1Z>NZyDR0@o9`6!@&w+?Z578&-L74K0=MNHAT?xNTK`%jUg1rm z{R|PiR5w6hoH%g|!zl>cP0(LQ5%Lvjyvn)A`l;p8Ap6FOdv0!ktY(sOoB#UW^Imo4 zE6>`0$DjlrBd2guO8_BkV;iCJNecy$bm(i7DX47J`)y`M>JMgc@%V4fx7P@38wYRM z|BcR>tq)s^JdbF`yk`dN9{$Ssla0ZJJy@3~v++PY5`+IIu^{~dLv$oQnSo@XPEK@p9!#aq5_kcV#7k6PDgxt%{{FFSsslj3ORiVi2PJiZ6i>S zL=M~R$8W+(-V{?*;F|}sP9fitfKl$xPphvb8aVXB`ANN(jnRC0?jlU;>R)Aa z_aw%gOsgDwwWH0%J7)RBz7RJL^tWofjuI0&%O?iWl@l!1BvZyMQ9~F5K{|NK%5EV&Qv2;SNtJi%A>zZqmvxt7c+h!=qhru z8J1u%Jahi~JQY9e@eXeE>U-tbSaRErZD))TwQpCzko#Ka%@rG%OAAQM2G+G%$g0$6 z!&Ox@0G9kjX_TFF=g z7lM(>=W-{@9Y3Q7<|eFk*yX}=Q5J!M@#uXOg3V6PaqWM1!4JF(0T$lN^)^TpLf;H= zi}<|uPB;-3&>)Cbw7r$sUxetswvTUJ;0e*kW|~L-dFnfLxF57VUywh%TQT{7=E5@0 z=+;#u(<#6u^yc%83C9nJr$MNIkFU@If9Uw~>^S3yc1J73Y{C%cI9+N#{A_LxLmZx7;&4=O1zrpbcG@g1r2o$xeC;f@D=jDb{R93G(+Ay8NdzrS8Pw5 zQ(AGWOF8Ko6izduZ-4F3=O?si&C?A1NS?0Iv2_h`7vB}8#PWy)@s~Fxc}YF=iLc zOgBRQ;v>=e<2)d+`0p5gIgD?Icx*o?&KfDia-KO} z`L*wjrTOyjQ&hB^=K~#Rolz;vU8mrh{WlgL_x*VhLsms?VH+B{oB}`B1Aaj-eFtPk z4B%R5gt(vQgK{Qf(M=Jri3O{ihcskZ=|IblPJh{+<25szYy6R^k&FAlayRxM1`eGu zY;U8qd;0?if~p44PJ@`PwTwOTaS%)E2a?exL+n|Q*7Vt&(JTV8NW1W|uGm)vtU@^+ zMxn2;?GYFa+N@rg{RS|806gB8LK-&kHWY|sZV8og3g8r%1Do5Bi2GMHl0XE(zP@(8 z0)H*i)3|`OAC?_B^-c{%;GFt=C8v0*L9#}Hb7`mLVvRO>$ajX8-Qx1pZiN&ES;GK@ z0YM|5m~CT2gpi8Kp!i#fh1ON%qVHqDp`|fb!juTYS0Eh?Sy2dd7rai~{(-F<0IfVn zPNJAe6MoU1H=u(1&?9%46kvhpi4)duBp$?KXwkYwu&Z_vaHwo5ey+CgOr2%$+cDvps67@PC)wua>(vSZ2-p6 z1Yk}&!KQnGQwE(4c{ySL)(-Og=gYznSMkpXb%D=45P+?j)r^yPMfXJB%{w%AG z@QGgw`#}dG*_GTU3tj^3sfvX{TK8231&=h<#kfn-eAtP{SQf*+SRk#f z?moODz)Hbx^t5;4ccyQZ>BxWZG2XhCbNYLcpLYH6g--x@k|xlT*rxaTU-D%2DYnO9 zZ{W}f*5Gm*0LxgU7{T0^ZcodzpS}J#3)FRgMW^}&p1^+24@^+nV1p%j-I#3QG5M4kPI@>$`O#epj6S;g_sh2PfrTD;p`Q_Q6oQ-EVJ zfImR+%SD_7gin(d#|9HoD+<{A4TY(Z4Y?A5+;lA#DPY>nkg#`-Hh5pcg#J`YED!V^ zJNiVk3K^dP8{Si)mj;=KwlEhncV4ThxT>Uy8_{wV3IeoW1v{V*@#Gm&;Y*Cy82^w$ z5TbjmSG4|qXn(gFnB_jf2fB!2;6*%?PYa@La1{woL6Z85JQMdSEH%o2>S)Ovvcgt= z+PD1Q$}OCuLx$2++rNY9-3G|UKSqYX1;u`^D({(WY1h!ETU_Ci;k^(x#nt@D(+8k; z*O`82$HBbewCjG>uNf9u#hPxd@P~c(C4%UiuJXkhpq>Zpfdm1uh1fSWL35h&R-HcV zvy4SP8}*R=31D07i<|~_s%{t-?C7c8@9=IMPs{;_f4G-CMdla(p*G6pueycI0Huvf z(o~@piuZAM{*=Occ%KE)g&>RqV1=$d=mtb7obJcnWt1vJ@D*HbvskR|ZBvdOhJpN9 zz|RmF^fR0~{Eo|PTc)L7kVy4fk1E0;Dm3$5Q;sd_*07^ z7f~DPhOj|eA<}FtvIhhdQ&4Lcbi)455iBb&v~=#e*(lzIBn<85?<|4?OZItH zAjjn8k8A++4-9rnQByaMtqei)z|21V8fNbM&LvPA-*=cyB>{~ITeW4hu9@*7Jh=_g z1YE`vD&-_j`v`qGPP22aA!Y7H3#e)6Wb8Cc1gWG0CpsI6BeG9YlM^B@0w>jnwS@8Gk=uWzG*0PPZ^PL-_trKYOxC_ww^lvB z5$r#>F2r9qY<5a7LtV=rQhyu_| zzMz2lnzlshMCg3T=-}z`TCtMmRdO3BhvjG(wV17$SNG2s%xP7V!gi13WSIT?nttb; z3YX5QhvYEBmjC!|Z!JCF|F^%l0agj@B8z)aJb)ZHdt61soJgnmT3^xeK+-5-jOW0* z&TC-8uk@ymJ3ul&~^uwE@H;0G(rIKvi!ISk-f-LlN|ZKg(qa zt;hUxxkFw(ycE<5MBe^XT4djkbvog`knC^&?W(V(gYEstCFYkW+z{NgS7_dB>|~nw ziAL@ckM$??#>_ZYIgE>i>Hz}AVBT4fUMictqL;T_cB>-F;`&eQM&|UvrGJRi06e2S z0QJ@aFz*ELE)bRoI!%WarX>hPjm?%u^fXTo+UkG_op0qUQBG6f7Wa=--JAEYD8K(O z#)JJ7%A%^s&|T1qs{GNSsb)53l-i>1P^;#6u;AV>jF)ZV7J5gYyKh#V=qMKg za9+Ko>(w5s1kWdNGn21mC%6K)&+=}qzUotCq{G27gU6u!Aru0H6w_HY-?)6ZKf}rj z=luB4ig@iAyA90dSwYnNCU*bf2I^%$VjjM;-8awb5m|>YTvFCaYUL5$Cj_=-?tXg7ulcz?Z+bA2?;k0NhE^Bfzzd!=}*68j% z1Z2OF3yO1Cgun1pjKR^9gbR$J_~wJWbXSe4#kiG=`#iuXUZnew71w~rxY7JjC<^Ie z+1(x)y7Nk@lMqc`20Wxx$zB7sImt?WcTQOzo2QrHD34|XiWdj>IdAPaa5|D9Xt+DR z0mxZl>q3}OS{~)6{Yeg+-w^?8pX4f?2^!5_9cgw2$Xa&n7n4;QmGVQd8!mbyT1up( zxP$*77)HRkoZN=?tC?Chm1?9}Se_1(qVXX%8W8X%&C-&^q)mftRGY*zql>Tn{@WG2 z((*xch)s-|PeNXb;po=)FToVIfRg;A`@Cb8<;X$Nb8;NyL#+@Z>ym=}y{6y;9wbuH zAu>$k1JZbMjn&ihWNpe=4cI}1few;wM9qn+u*plAe92#Z<3mm!Zo%6K3>8)(Nb*b> zzdk0Rlu6X`lKLQ`JU;#l6%WH-PL?j31*qBsf~BHNws3uX4Wr=!8aN)z{FoQ%2>?dH zYg<(q9T%1eg@6w2pikJP=s}B%bt(QwmaENI!sh^#F`lUw&#FVq^dO^@Ha< z7Tt9FdefiR@!mj^VxDbbNB6wN>e@#XySh8Awq#DN-(cdAPyZ*H5~tV00F^V*skmdfwL`Zm~}sEUx~&NS)x>a?eR0Iv6LmP>QBor zY9@ekg%I#2$fz)W%PdkPv1ZxZYQ&#WDGG_UmjVA`r=C3`9M+b`r7`v#&WbD$I4qNe z{{WT?Z@eW*PkEOw;&QQ@NUmt)(s@ABz?BcR!iST#@>(QveT6=>fTn=KiO;H4kFfeY z%+1hhDzZw8qJnm(3|dD=|5>I(FOcCegvYy7@l%G(ko0bXIk>Yx_xAteLhQeXSF2qb@o(tNn}7> z6QrTSoFzrYs7(oNM(^19V%}9@hQ-WG$Y=1&^4IK}5b&3f0BD&HJFDdm`JTty*<;#e z&-tn_pLW^&L9iQY4Bd42l7Kvqcd38OZyK|=Y8FhBJaP)=j0)S9+79q`#iKlJ56-+A%ON+rO*;$JfFKs!#)xNf67i=7hV!8 zbd=#|42>4F-z+jO^Va~w#Q6Twzy8ABz|SuqBAlUGOvk`c(_K#vmFELwDCSG@cN)3t z!;wd>7nwx4AbqQL@B3G3)?0TJ`Z;B}{-=mMT!0r8b&dc6-eRaN|A3IkyGSHi~iz1ASotboEH@K83l?sF^ zUK~UU_#ioDXL}j6<7_(=QNQ*0|8(JgK)ZGTc`0K4x5lT2h$pI88nVzT77dPbj`@f3w}vU(gQ{#@dUCwK04ZG&6Xma5#DIBU19N}>ZGD+P7Z3ec9iJ!3 zo-tu@lw$A$xS-#8(@B#w1CBM1xp#$UY6cFwvZJ18eX}nB{dUI3r z*CMaS^)J;q@JTGRRb!g|pgv*Xs`*ANC$y>@rU$KpQu<}6-za6?!DeGF4@Tvoxf{%y zeLr#U(5KJBX&fU1V`R_^t9Ztg=bDlp9}v!owqG%)F6Zu6iWlcMt#PMVQe%e#_ooBy z;Wh9cqE7-2hkA+b-Y|v@z=ry%`8#oQ0^7$c1fAl@b7+iQ{?gPNR(Eh`r^C?T8o~7r zQ`}vca~GFd{O}U>r!%-d&0KGI%KLGT3*;jA9ejX}dQuZKtpkoeM1Nuc*VbGw(v?o# z)iQD@h9mN}_F_U7m>nntES6y8XYo7*Hb(|2A6NvgoC@bxeVZ`PcS z6>hu@&37NC(Jm7xkfd+h{xh7%zVlu7?e z?d@j%X-qR(%3*o0dBCx%Rqxqb*(xy|$0+Om1Bkj`XbpbEz`t>bhW1D|A{mbMaf||9 zJF+=8cxF)oJ`#Q7$ruylTPojBm%t#-1M4Cq*-U$MzXDEZIRpP8Ns8UZ?1fy?7*SI z0vIa%4H}nn)y`Hp1WwzU{%+QvCyE-G0g+8~dSeFKGoL?sX?gyTnByR>Av#Gl zo|^c4x}^_0QtCqR7o5$NfG$ez85D8&t`re*+MWo?94;9t+ilzf7_aIC7EslaRD8Tg z0zN~iABi+iPYVBAemiGbO*UjNf|z#QiTk6-F+srVJ}^I))0~$u;+GpqbO>M?#y_UK zVfIk&mvZ(SXUKHr`7~sdDufu)cANBXkA?IN;Or3!!ZoQ8@$yV#qc`PIe@SJC2OSEX z>B&HN_h^f22<1A)_w$Tb8`baQH!{T?|L|_)dn2ok6`leOCJanr?jmy9+u*^WenJbx zd&lS}YZe5k8?u3YjZE*!QO~F-y9H58t&0Jdy z+(@gsY|PM_8z9@7xp@5q35TQpo&)^s@_G%+!iPzrnkGCD>tBJgxsb2rH`WzD601lA zVnd5uGj>i@r=P)dB|TD`-snOe;)m7{&pL!@QI6i_9hjR(Aqr+uvjKUqtA1jFIyT1S z{Ssr|fW5Oo1{U^`eqedZ0%l2Kwrjz`vl3x0fHtR(@ZM z;(XDw%@u!-(d@hwQS$6tCrSBNFl;9bs)_a>$Tk5EGGmd)j9z$g^+Q42U)PFT$Bmfx zQ?FbjeE_?m!4-EVV8uN~#<&vY!_tLIveb>v7fbja6xa&Tm~GFyt)?9aHHXiU6S~!^ z#oD=Vt3QLGW+(0pZrW;VmcR_Y$Op-KBI6AWpFc<&RU!+8sWB1#yohUL_))K!$83bp z9eS8US|wv)n?ApqgMC+Tw;gHvPVej<>>$NJ2ict1AG;>ydt}MsiMr;A3L?c94XOkp z%|*|%Ok2K+Y8%pKKU}I7D`8=df2BO13JAyLpRfTW4VI(Gnc9Ln_CFsO5R?c!(h~2= zerlg0uaWWi|JpKph*9&0s3?LhD($g2Lm1Qv+3W05&knR&I|NirUO+`x_zS40riyGX z;bh!#+ZMxPVah#vE>mh61IA4BXDakvI_nCAd$>>TOX%|Ezp_OCjek@3ATx}@Tn-ZM zK%@@*I_P<3ze_F3mH*x*b)BcL4)GQ+{{4e~C{^gs;~Wd`>@V-Nxr3&lm6Ras0}L$s z-sK5JCP27i0>CRBV9fNkqLp&>HWra5m>v>26`_>0>)siCv57VF-Z>h^HqLqOlrvo% zt{f&#MC2hbz2e?o{D!mq)gfxh>}1}rY5g^R-M`lSC@51II{_n1uE@|Bz7@YrY58ol zJT#O-@-FBFA`)tKO=jT;*X`Dk`!vcI!OPPDL@YdD`mi9nRTh_s`X5nO!4?JAM3)pK zMY>bz?oJ6Q2?3FAknZl1?rv$2Mp8PZ8)>Aw8~K*q_5J?AeeS(8bLPyEHW*X1yZ;EPpFnvNL&ZuD<+q~Ic7vQRxFkr%qorf`_s6AZX)f+0fAR3Ku z^1==mW4K#|p-BzKKpgOtYmM=zL3_lk(I5U8Kmr$2PJRMI^_sR%_jO^WvjhL-e|-&K zzzN9oy&s+u=F0eQ>7(KX(=>C!=p;}Ag0L>!+)8t;d5x^}j<0B&vkJK1dkuoGgh=Qc z+jL!_c{28A_|9;?`WoJF7FtHJPqPLrL$7y65eW-Q*m+QgHuWGY70OwTV<~2QvR+_2NP}^}@#RFJF?bFjW0NM=M-0)GC=pQY zY!fp&SW4R7cVM@v>zxpBadC>^;r=ZLnaS!Gpk`KxydU%!B)4HlWIAdcqPQE+I&HwB7!$}u(FrThztXAZu<(%3DUS~1Nxcf zq~D1I2i>+Fk3KO+)7>gIH_?0t7o%W{+t>;oKHv|ug?`@};E<-StWWTJdfD15<8j_`@`7Q+h=iK5<4##Kg z!!(fo-5nv0ScRD|M|DL{__KUHyB?mml<4}L2AO39f-M`bnfid*PcBxWs#(J=q%h9E zlO6!`r@n7lC93y~A7N92ch;)cAuCaU6Ch#W>W5J9*e87f#(bhT;cCRM1ocVUn?V@Q zO*XyxC7?h1FH4VsdcLoaaScW2CkVAlx?#5pht?#lm)hcfg!kZcm}Kswg1OC)y;{!i z^JilPSa>+K7aVpXjIo}od`+=$4CtdR%ghw%HV+C+VB(7Wu?0ziR>MIlkiomwj6U^% zwd>;46!Wg1FqGr-fFZP$W zD9N4jg+l*anKE`0tY)4L41WdgPm)yw9Qkb#Pe)TwX&L%4xkmU;rXq`H2Iw>jYtGNk zKx|_W9Ki(BPS`4_S9dtNY*5qOz1Cl}u(yCB*v?C{2s0i|+6fl3(O6m)OF6o&TgV}v zIvOR$O?F1d0q(8QUzIBwA&|~oNV%$rqZ9~k z?l~PI{PCu$blA}QR1X^R1rp4?&-B2JH12T&UMdyL(Yx7gPAUaLXx_zqLBmplg9=ML&#_6A@X}cOh?=Wb3`MG=CtqgG4**tR z<|OfAF_QCN>t|3juI=LFa=2Q=qYjsr2)ni(po}|zfLug3_#%QoztBsHm)f`ChW=p7 zA@#+qySxJ*Pt;gsnpQ#zH@pcJ5%kGd$ zad@FK=hz115pfH(i$Y!W$&?0vq9hBUvK&CMlAVdvD9`Qp3gUX-uTj+6TAxw}Y3yJI zdkGkyPTKOHy0a`ngg$)H>$-1{sk1@ERj25qc53%x%9D0$m+^LQA|ZK$H>83u1Xy%` zeb3lp(MaW8!T>EL+=2pVjZ&=9GCBPq9Zc&&(Ec-4$JiwWU;ij67oN%At6+hNDpu?7 zxy-oZFE^&OU(pcW$_HejPRvx=elDH?vm)Z3wRnxXG*+NUz}-G>gWdDTYl96?L6q=n z*wC+#5TyCQ9$UEWv!Y2g^CV+*-VMLHN9Hl~`ot&XtzYkr{6Fkxz1HgjHpB@R6-DkQ zJ1Kg_YB26-ZWJYbJNBFSAtOv?!H@fb!fOl^IG*YLaL_UQMy?GzWan5eQ}GAtf6#YY zEEYP(f%Bhur!wj3FvoYgpJDc1W*|R}&m#R(%66Bcm{lCR*4(4m|N09-@FDpVtblA` z){~soPKvh@HgGCP5kmtorF(>rIj%mz%IjZUY(gql#y(Y+R-Bi~6z|Fo;&wq(L3p4z zN=^!zA{R=9+gFem^Ir9Lhx9c-Z+|amSl{6D!bZ@) z#?&vg6EM1wQk{l`sdk~|cJJWww1E_^r3`@FZpU8ma~p@)=A0rA{OWf7?pqbu z42zo#oHA>4^AQ>4*H!zvIfKj3b1SBx*iRJF!?#vsXAJNQx~CBurqoXyBm@g#e*JtE zGW+p&$)d&d?+@YtJ;b*Su>XpQy4;D9yPZvvPP7#n5AW$_Y+rsK1h${#zJso_|-U!y&(La-WL-dZSdPo zO$f}L$XS+=yiNdD32Zc%sbAp|IF(4mvoxfJjK(=O{u3vS_DZsbn(oLjHvj5xdzgPM zRpia*YbPIWVz}Jo6@jAug4Cyyl-^Ckhov~-4g1q7(cS=^f;oG&y=VAB8TTqru`;li z4~)|NI6+US*i&SP$*=XYaBGp-(O~`SGULs34am4@V~cJSle=L94RHS?IYfMzmRUlD z7?w~@Bx+EvW&ym#{OW0bEFnSd4`Qsr78m5&G!r7W!*nEJAGK)G54mrnbsBT|xUr+^ zL?RXvmtzmr)g3!W6U0A$0A_EHhF2%htE7|44X!niCccvlFl)qX%L;n;f(gvUb~BW} za=oLOJm-aR&bdgBdwl(53J!f2+txDL{SW>->z_E@*`vych7V{-UT60hJqxtK3G);!f#1iz6rB%+QWY-0#iBWTs`wMenS`+}3iFSk4_WL~)Oc<7x{`&zCB%)8 zaz|ccM(z`g#8jEqZ9soT~styxgKISWg&-7sBW|!V9ys+*;)x9 zH(J1lII^#(-bnc4c61`XBt0+OU+%W@s)9i8Q%tUK*URXEK;jd&Tvs`_-s zF@n`&u8VzEeqIJOH3%N+1|On#8b&mk&RzjEOK=f5(MGtb(Q^Shgy|uz0JHfLc_ClN zdAjL>L^gKU`8Xtl6c!*g5#n<+=TZ4Jb1PO4N8VlD49_{XWrJ4T{Cn1F9A<}!?12W~ zdnxYB>)d4|ST2KLLgPT#X?fFZJl4+CZ5NU-TnTW8J>k66pS8gx`pV>k;;JDRn;<{DihX!SARQdR2h9 zO-Fg})S)uQdkIw8c;m?XF{CBv8v#bjKHX)Ca!&pEt)y+sQX;Kb4_)lv{|r^Q4^$@5 z_tNat)LvUSuVkfW8_}gFOZ&_Q2B@Sd)`>pubHR9ww6PLR9!1G+DGd-Ow@Swxcf@!~ z$I{W+64`jB_J#iSi0V@&LX)APYJegDgTx2$^1ilI?lO~euTu2xPu~21M!az*Z5&%- z?E+@}BqyRfNOl2zsSUMIv zu^yMCTYC`SL>jvC&Og1QU(>A>fBm}|+-#jgyfWBKAAbFbGoI!?&sZn?s7P0~1WVJ) z_h~$&={#`a33|s#ToJew;2k#F_w--Ka;=8(cB1ZttS*MY$;EcBqJ{Ti)s63+Ks1X1 zFryZZdd8?W{)Nyjf{N<*9}CXLxMlZnSdBPAN*m~g>7}2(_Pwc|^Y}#Tj+~59`^{k< zq9XPnb(g(1GztBnfGmO1^HvBzRpjR5a~Gz#Yoqq(+vp(t7*lcxX6=xAi(|z{i3N3;BOupxz z**@xY6BVpbUuqQ)@Ezk!C3yUh5gPVDp+fbSiyReQ`duMA-ebQqw8!?*1QR zlJn2!_e(-PaoGQ7-flqe!Jz|PrQP*3>AH*+cWJ8sk}Dm>0EE^vL!}01MmAXjXd7ji zanGwPQ~JFBN!D^(bqK`NI39#-&I?pfg_{c9{&6`#2-u!9);e;a5K90`OCy>Fy3c26 zES@ptucMI`R}Sf9NN^c#OIF7SeHxWWh4kB2f?Y+^>>;v{G1i-nfq0JE$2E8vrN9}G z)Q1qpB{~+9E`_YPO~dr$fp1>~?Y=c6ilveIFlo_GTYB|A4Y~tK?;fYeZU)ACOAg?4b|crC*GOvq3NIxOiRU=!mC@CC9K>V!OwX1y3IlQ%*}p-DcxkkR1SQ5KlQp4kPLE_d!o5k#29`ac;9Dx-=SN%mi+^o!@iq1W z`v$!U;<1E2=IgQ}(g_*F>&}R_uIwAXp`$D$nT}JaF6C=XKp2CWEA(C9p+TI=gRxOR ze^;s|@pob6_td@#Hj_xC+JD`wP#y1*Kg7NshI;Q$wCWrbsgB8)9 zn<*nu39~E9JwoqbU%c9nL;6tJAawUOLd~i9rN+Ii2!A&=1tg9cTY|(Ts5XQ}XhrfK zYcUK9#%s8D6A5_qpX1mGh2x$E&!?w9xs;V;46NRf404S3U|1pSP4HQv?P$$LCBf0* zL^89T8@MX|8=hHHc8%d_h7fZUP!sf|Qx2~G`@89$S$qMn>1YebSm z-*W=(>;u+qgq{VH{hSyqhmC*m6Ud2EojTZ9#h?7 z=q0HQaok7@)9J+xH}4U?9!f`bN`_M1kJW3IqvX;a8D}X~4Znv%&{b3Vqnb;E99nla z`I;VDT&Gg&Z|Jt14^C5;5?`eC; zd`dc=B#3bYQzgpE?tg;E1F+SaBHEAHaY;7cPX^U{m*I*~szWYfB?MWiXX3bM^RQO8 zSxe7;xCcr{R!5?I!Q{ieD-vB66axC(inKrVOTICpmv+12=QCUl?+50uPtR-v-!Fwk z-S$Gxpa?nxti(h%u|&M&pOc|aa?o6@>TGKQexQp;cbK>!DciApvQaXdQFud=*PWmU z#@s%DvyXUg)9q#S&L>)kZ_wO^k#ACi5HkHub4pUXNZ01?0InrE^@GVV@jshSXN3<8n8luCZHNLFy7$P%;NW=A7{>UQL+F}glb092BhcQJ{nK= zr!;?!jhJ?}PmU!y3t8n-_+J%GQJr(m8a`WOK`e0rG4$`?%i8x}ggG_^xAkpBe@Mgn zL+?Z>dSuevI*;1Pw~k?pmiAVqphRslAcQzn^0|uq`HBRw4KEPJ%YOV8rxF}ki%~Y+ z#-ZjhOEedY4$=cvw5O;KBx~f}4&Guc&;D2#A8wHf8QzDDE`Vu3(9WKsnxG~%8s)xP zwUlxwZ^O&9{(ZvOEuJ|HM+&f1TdX-$Ais4yH`<@SU>ZdVk%;r)eSFZLTIji;*#@m; z29|e)K-g+*K_-G@>TEddE@YR+_s@}#J+cUxTkzvebuymB9^mhu3rm&lMQmU~oc)LU z^_`E?zR>Ig;%LxW=1T3pA-w7KsWK0%Vm$lTTu!@^+rp`yN|S;3{b<4cEQJNSQQv6TzH&SbA*OZOkXyfzzMVtw=Y*w)^3Q{1J^Qx zcxe%k-;Pvk^!jN)L8r^dbvo;Uc!Z+v0p^5-)*~0FjLia(`_|GHxf|)sEWcqwjC4wQ zEPkeIG@^zRb-NQ;4#x^6%dXL@bg(tYWo}XOcMDLIH037WF=FN0+_s6smigw1@-T&pJLEz8nsjY!gX?Q=*rTFT`S}ok^ZZF0Plz?n}H`)BD`f9e@ zO3@X!CONhjyc}h}AUda-n_aj=IsboQwsf8SL=JO>9lPvJBKBaI9B9 zXjVK-EW=jWfwc3@Fq&*R)NnLH8EXtXpqdw`ul?Lis0jKL{h=!vdX{^Nvz&Tc_PE?wl@wNK^-aMOZY?m~=cO@35c9kJyD4w`=wZ{gc@;WWhZMe-{Ch{jWC%>?#7t zdm_v3az}WAGiV+HsBJ7w>3YDd*H}+kvcJ1Q2Z2{xNaicErSjyte_Vx6dFB0P)R5N^Cq5p)T6o_Fw|E z?JG%3*yHtdCT+=st`5jvHgg)n7U>;h{Oy5Y3URQvpvO1A{~b${@)f4rHzg=T-ra54#Rrl}B1`Fcoe2NcDBx?&mC8zg@b@dTl{?8HUXV z13^5V*dLDnbw8VeK8D-Idj8B-i|Ks3KsS_hD>PS&Ljp)oV5~-5rFrvxxJwHU(}n;v zbdFDi2@B*dd=x6i2{s$HILtJRRnF}`#dTDtQMX1=^Hil+XniybHU~hbf6Mgrgzc3L zh^mRJ<)D-h_=}B(mu-Q|7IS!PRCnVH;mAorzd~e8qR~olmTk#*e;0pE^@&0T^E-G- zp=k7!$H5}@fr}zee8T`yi71m#zm1lOja1a~JJqVl_jv7srwLUi7ty*zf;2^gY;SKVzH^doJ-nD}1x{%2 zb8lEc?35mCry&MdL85_F3afwLh?9qqjhlN+3WA;Y-p>cb-^tCrGq2orzwKkc8d?YB zKxTM^>Gm;h7vKN(itDC~dr%xrKfFuCij^rU#JIi=_{+BdKlUWJqDZ&+0JXH~D&i7O zBZbj&S39}+B_I1u^Nz%J)zN<}fhjnK>@d<&9;}YvlS#gi6k>imwYPH)+G;60=FHLn ztK73=Y9Lgj#jO})`}bWHWK+Zy+zfm$fmDjvP$m4#@qOP{fY9tm072k;gVuV3 zWBv)~SKP2HNU{=CIUUZ1kI4LSKq9+vLJi)^k zBUAyB9`DH1lsIzvz1H=3uq1`_>th||6VLK{7J3wzfoStrguQBxI5Rr?@5=F*B3Ew< z6oF#r8Ivg39xvg>?_@xN{8eDl9tmjA&F6?O;`*lj}7b^@>QhA)|ns$2i?O zu?m0aRiMcv$fT~Byc_brsRz4@=%+U{nio-$6F&q2(kpc8k6j7c%9NgFdmnre$s3}45VGgO$D(j_g-wKQeY)uuL5=J z{s(;jFCUgHdlFka)lwqiHZ#*{Eys`Z*HlDDd}0ds!hguzJ&aPCcKTw-d?LfuA+>^N zF!1iNm!(oJQ>hzxuzK}NeokHgz(pJM9;A7sbEmeiiKO^g=<^X7$`QFPXUxD53*jVU zlSrBeLEXdV)L-lsxx*K3gVv^&kgs7DJNKd_N7G2cfIKFuFZ8hnH8YATGYtiGZb@+z z_tJ0mc@bcoVSFT*W*}-bl+Vt4_3fnk@*b-$DH%`lFSw6Nuw)tWA3(iIei$?FwK*Cv z+YxG@!z4bQ1Ow^>hZB<1+81}Y%;n_6^OFC{eyviNWpdxI@aP0Q> zyJ;)Ev?+X1LtH!w7cE3{fIEl$J53l*0P`*Y0Ns7T95~-_w6ena>4k!A;Qz?R_(W8xVd?2bknN)l?9679X-`x6Y=q)*6_({ zO2$3EB{|-0nsVlOr~fmqPf5uS&Fm%RT}Kd*T`e$`3ywjg)aH*rd|8dg=%6wjte*C0 z=WL}_jRXA@J^_j8vLL(}l|pR3dLkpcSn>4r#STqXDd!qASRY708D+bn)v8iSwcwxx z0To%!wcQ#V$Fg;ruC%z(a%n&<6QmE~Gst0i)w}auyjH%#c70HYd(FAsjQa5g zMCPsb>8b(#Fl$ovZ(^zsBg1`8oHF$RgBu?=+blH(4tAdG-K`Xa7f*8qPA8A=k50Qo^Nj-a^3XIh3RpB8*^+EwO*0=jziM1L@?qlJy`(w zt5VlhCf)t;?W*35!zTnSW**DC->CYO#LjCq^eq!l%hRame#!J-E1zQ~5(oE=(oeGN z41)-5*kS%x%@gxbf@y2MdY|}+ZVUm?q@owvzi*w0NXoDV#0)-~P5Q{bG)$)AM74y0 zcS+R_0|k(xXHmBku$?9h5f`hm&d4khZuk2(Oy$de3_t`W$RsB6$4A@qCtA1tBNQu{ z#U=Mvm_?94)_+RLYyfKvWBtdp_ta7f`)bv{5x2)o0@-o~7zTkRH#}Xsd)TVwuxWGL{#w<`PVqibnYCW~tG?hhAhY?LkFA1l0`AvS zOzpJWd~v4%DRxQzDfQNa8|Wso>qx~z;VmQmLf*cm`MRoJborhIk_sW5P$8dH46eOX ztgE^>)b;&QW6D1)^yR`1mHBH(r^4@Aglv*hMPh=C`>oZrpx+uB-Q#B&&bSneRQqqK z$k2pEE5-j`aHa!T7#S4kf&^q1?`+Ji;AgNpSt4#YR){>i%ac`J(}kRuydh z&U$Dq#CvB;Tk4cfV6bf#Us|belDwffsvJshp{Qvb6ouVIWqc&|0q|LAEm(U~=hJ3# zFrn3v?;D1F%KODTV{A2;L`E%L_pc9I0c55MNrcAC>BsJEdzb^rc_A_PM74-uO|^LZ z0Kyhc``1neT#qN1|ImWnw$q$AQNpD$3|s5%UKOCXd5^cBxZh%ne;sixn_tVB7x zBJjr~lzwvWNJETY06DAz`}KgFW;7ylZU4TosE#VmdiiC@P55AcGd(iP$yS%k#6dYX z**r=1HRVtE9ntmJ+i+AJ6!f~i4d1w2O3MzLM1clRAd~7rdHipO=EWQ*Yw1^ZErC)? z;E2Gp3Z)46If7xPABQI*`jzkS=J!Takf++13c+7p{dCRqwziO;=*kqtxrHHEe;;e>Za8E zP`Q%bF`?N6E8Ttn`UO1?P}mw$JpKTBkZ>>3rpr&^vMjHf2)zwh^%fH9WS;Y}v92y+ zdymZiFNk$jN-UIRL@#AI@xg9$Rp)Nxb-evi9C_7a@b|))`YZbYm#`-8afeubq zS+rFWBP&Ja&pnB;HBF0It<`yn<+<=R3gg=fXo*H0=$i!~sf}lJ)1D5p)2Y@zT6Ul1 zzfWyJXz-kDu9$f#y`aBoZl{M=^(IHlcnD4`L#&? z-ot^PeFP!9JmUKv zxDcb8`h0|F7#VZ!9QylgWIZnU7fYgHRA;YtpZ^3Y_29&Da}H6}Qv9x*yRVrWJ&qRO zU(*!-Rt{f|q0mRUEU^g-B}Wx2Npr*-(`rKNcjvtPs=8dj6a>X9lO1IwLVTcM73-H= zXCW$LWogr!M;x8>r%$S4JWdd*VCb1YDzbeL`NR?yN3_YE_ABpI=sTGuH?WFVaY>H6 z_ctXxUxg_j$2UK|EjkWE`mk4p$ae~(qFLJe^26WK-E`dQ$CfnLo9tnPyWu7xzy6Mf zChYUb(m8d-yTIGjh2B0Bi&}NbTHZPEbL5+Du{7M%Px2lxw((^E`H5}$xk>m#eidJ} zC*hp|j|+@yvJ)`Ue8=g)lcdmr7kK5O&#;}Af32zH3;vkQXuO<@T#Dw4eMUuCKTTIy z`u!L_cV)m8h;!tWX%nvlwSnI36WDDR@d|!W3x}a~Dm|R%y}?nFkf6WX`K;=;s<8l$ z=6-763>{vC%@Va=)nLmJMt8T-vP$3A?;EJ4A(#8^I#M4#1tSTr@95>Yrj%lQ0hlvs z7piGg9~@ZNtFSsgHZ@(n3T+XPhH2{v;ueX5>vQM?LDBXn2FtaLa|qmxaAGT zuSF%djyW4ib)AHCo6aj>8{MvCsQq3|=-3(Y#wbf>8R zrJB;XW_1%VZk~|mqFj&c1I&??4=I1vFY7t-&ECNsyoG$r?0B$c=s`iHX~x0dXZ`dK zlU)>_QwDqj56)wH0B9}V*Dw%wIJEEv2l^&cEn9(KgA|~$q1_C(@fCgh{IQy91btjSq@{~po0rRzoCWSqaM~^7tWIh>RK%Jg_HA3ekzH-YSTmLQ17w7!9sC*r%?EdzmL`wM6Cc0QEFO!E z^=>tRB^|8z_F2CO2@gu1V3x_l=a40jV0c_Z z-+M{ep4S%-^Z=+PyumMn+&VbehsuJ2-`;MEFpP=iyq(mq$_vJocbjAdLOk$9ZZ`NX zXg5Z*7CnYzGwRAvzCR9QOE{j`f*Tq>*pClD>$6t7pryDSc+rI6)3nWjA7qEgMXB@A z2VPLcOBJ`E1i11vd>+Zcf~Hu6UCdnszRerz;eK(B@sq$-WBcj&F2f)^CIN0aKF2!E z-^|c)Z0>b-E(p>r1|dz7x`v)0^xoN?zh^9X_{*djeGVlhARG1LKZ1HV`z}da?iy09 z5Fu8vN$Cw44){rQ#eI0Y{QG@y!^i3piGDWnQ^LLwp$0dI33Zq-_Auis=<}ny zGnqNBV>rq^5Z6yZah&c{vFJe2I0+mPZ-Ah!!&=0yZQ*S53~=Q zIpy+-u?fhSIThb~mrd01z~ZC_JCgXyBo%BaXQ~lum=A#gU6rd48JtBNVKkfN#yqKay30F5xEA(KYx5jlXa1^2rmf=NW<=(!YpS-O6$kB zcgSUq|5n54&=~;NEF93>YKRE@t?ONherPhcXk4^h=?L>H-T(UloC^Lk(-cCKa_jLx znw|doLipG0BYRB6y^KVDH@AMXk;@T?aIXWBXz0H{R@#(0`Rhw@DY#Zu^E%l53o~A!agoshY1sb+{ zFNfPuzUm_ZVa?O^aHHBPZMvwi#?HI16#*524(kA{YR=CS<)8gM?LhlFaIyi3&rb6s z?|7l^<*V-_^$Z>T!DCj$#^s`%Ab-V|{*KN)>17Zdp5$6VvQ|PH3AEO~>6tO2^A6AT zzMlnZ?L@|n21oAcwV|)|HTB=ps8V0C4K~4`ufn><+=M!Ap@mIWTp10~6$Bm^MpswO z$T*W;Plp=1fxc$nGsFW$Qqm%<0xUrH`ZcA2#QrkN*NQ>uv>;GUx!X)={rF{SWXo)x_l`FxX;sz&kZ{ka%WUp@%IigRWFR_!b2M@BM zSDyt>MN10{ZZynIVZ>7ZhEP(6Ib0j#2)i}Emx1E2)ylNZSXaF64$Gw(gx)m-;cX#R zzel&L8^a($m|)t*%>tj{SGeG2AIf*h8zl0jy5;*6p1U3}KBD7uE#NjVpQk?d=v>&< zK5c_yjR)uG3pt072&IrMsUfvx+379lI!*x8$(c#0VMQe8mfcfSZuekrDHhz+0G*E7 zb+gL@{ep}HgiRa*vx$k9owM*C%$5sZmeClh1(c!&B(8$Px!CVZfolL8(uS9#(H}{&0TL2p7J@J-*%XSKE{dY8oAdFr*lk205)<8-sol?nH<$b_II9;gC!6 z*xOnrYp3=1&@V%ZGfEC*)^_+ps5np>_ThOjxB;A?zq{AL)$kF-yxdEi@G3zr&_xG!Ykr9(bZ^}1>yG_;^H#h0b87wh%Z!|g(_{+(t80Wc;SHqt0REXFBzo>; zyS24O=^ERP*@_~yGaq-sd)WjQaT9m>d0S}$D%PDoR-F~{u{8f<2@o_|R#T)~Zt;_B zm{}~lFy*RLy?!`sOm7g|AKD+7S^=OxYc7p?STL9gmHhnr$~ju;&~lR6Iqhw^WF!Tt z1ZD!_e>5|xF{quuSDoW!rOAiamZZHXm*4l$M{FAoWz4QM3fNt<|#%tE`Lozi`RuBhN~shG?aT05vQoDKNo-7d}=|K?WiQd z_GclC#z7>{rD6MN6q&`zIJPtT3*x&!gP>+~v#ZlZ0QZwE%ED|i508y9vHsh9P%((+ zMIZ97gRh?&H!5z_p%ZJ*iyR}3OHwk{gp?B83YN*|?Uk0CDesI8ky2sINB6i&DI z_$&r^vR_LGzTZ2X!O{#OT}(`UTf43!AE`S?&LY}$LStYIT%QOU-){naimZI9gL$#8 z7s}{-+RDR>hyFg%*Kh~1x?{^E>>vY)$~7~|Y>D-Li5&96a;Id^ zwszM3U#;{r_184>r1!Wa#FCr#yz7+3oXhuT)CV3VC%f~7Fhm(p7qet$Ri|mL#(6^d z`ZW6%Y5kfwmGz4-rG<9t=2CAaF2Sz>tqqE#ql!r(me8TEvS`J=c`LuGB>c<123DZd z^M6y7fpfocczO9len`DO>NL6xl8?4QpRvnbD9*6>*HFx4$rhU|8ZR5V=19R5d*j^P zAg}|&7<`RTo!RHJisLda9lb0xe!zuG@`SWmptVZ3UUDPKEW|n(L8ZA6YmW+4-&*8K zf}Ak}A0HWA(z-m5yfy52vC73lkrAhA}GmFev3PXiM{5@$2v2(iI(*IKIIy6=N zKkGOFhji-qfbEH4zS=U(MiC!al?rAQDrpe1p$KeQCNJ5=?fdq!(Xrroo=%en8Vs=7 zh1h6WhkCCRDI|hCU1Zx5OXiIlTVMn(-92F3-wpX?5w$<54EVgl=rXb!cq$oKBDnSv zI?)ds65JyosEF#Tj)RF1-@gn6E*OzWMl1WDm>=@5Nhb&6Vo^LMaq8=t)dfLzc`d!+((k@b+HJ)_D#OONBaL{r0-THCUwMi&D%*PPmBnl2e&TTXS)AtuM*o#e zZ1QBnMUiz}YSHx^^6{G^8fiaXhw*NOh!7Y#MmD{Ldf1Qb2qhnK(ZSlrViWSl{TmTq zEgQ*ql56KAhu!>Y!tg)vPYNOl5IQAtRkuSOF1KAJ;;oES(hAN|c z&$stJuXK-aLgJ(U>kSO>Ml!d|O1p*f;FH@Vl`j=7NONICVPene`FN-%J!{9W~^4t2{Y}ipn9`xh=TAg`%b339cZY}99j^VL)-O4=WRc$zPt8M64FWe z*`N03+XIL%L9q5#&<&lu@NJ32o)7Ng9zgpf^FF~1`@xKYw?jBnxvx!kdcx`A6B#~9weY3#qtSk3V< ziiOP^x*qZV#F)nkH8BjAVYdN|@AosTvDV-37`U-Qb{ht6n#!!7@+cJ@afLIZ2QHR; z7_a#Y{6wpCqYT*wB!(D*VhH-_oK~l2uk+XS#P*t^OVk~Ii5ajikR4y}+bIV`M}OyK z@2{Iu61kcEl3@2OEVMW$AY~sYR#VAQ%R?7^C)IlHpvwc`XF4uf$}EA8c_|DKX)AQS1&+NbfHCitOP9z|9f0od=8Ta*Hy*`@>ujv9MvAx+5F2My(*dN25&McdeAa9W%>LdpNT9a;W)^r86qi z%XBAV%cbYpE}$OT63dabE$EfhNKk@8D7%Jc=;kn|wcQBAH+niK8D4PKaC) zPDFwD=(V=$*+8Gp#k!0z-0&R7=Aal)b8+KbSwaLZNy6!S2=(szvmt16lu95DJ!Tdk zpUbxPllldtpPyn(gi&*WXK(1v93=w=%+0J&`DQ0sH)qY}9qQhT`NAC=xF9#!l)saQBrI7$bT;+-}i;`^P@yMgz=p0sw5 zyVyB}S@kWIX*PUO5?jKvzJb9hi2VtSdl$FwnhzHKoPBg^qw1a>HSku5f|T-)T=Dqh zMJ?O8mAq^$wJ&~V%mphfAQ8V8%}={%pu>i|8;j8-KCgaCObJ8}RGPDXXZ*r%RAeT9{(et)u zCBse$!ef0h^gcD7GjztSILl-r4wnB2NQD*^y0UX+O~ zec~(Zuhf(elc5NA`*y?iDm8n?A(j1lKQpl%AfIy>^f@!hT61mSLgD_F(fdz``r^(W zsv>~HIuXVSb>;;9l&J9zi%+1mRtNw&9fB>gYGu>;lSQ@{J7uhYacrZ@y4Pe3S83kj zvIpm%7-UN#uadwPQ;q#Nu+XgG4Z$tI)DRT4(ZMD~n>=FNnxarQm;SGk4*(I(V>JeN z6A#kF`Z(gl$k$0&^M}|{51{XvMc2A%ij}zu$N19s?LaB492Y)4M1SRP;PCC*LefJ< zO304JjKI_&731H@+)Ud?qBaLnp*6}qz~7oh6TKLt)|m@!?Yt85;SIkl83t zb*qmfvr7<%Wdd?oW6s(M0$zFEvxdY5aW=Jatc2{w;HmLbR)en7x;9w_Qc|OAGyMHd zN4R7N==J#}o7j7bJ&y@@aY3Zw?)X^4A||E&@&{6t8`E2f5-v5s<291Fl3+wDQ5q-v z3yjn+6SGK~Y~_=lQ-&?0X~-7P!GDxkmg z0cqhs*Gsd(UTY2Eof?VL9=3tt7<|dYO-i3z>IB$pJzak~8^ek`u0-BVRf5*ze0ZIz z`_F5MJsu}D;xe4__@`>%(~ig6SC5h6KjwBp&7Vr?1N3hcLDbO z*ku}Oj}_s=zW>#;mpiO4C&DZ#&1A|_qz#qaqVqc&xkfN{cty#k*7k@W?*waA}(limV2$iMcSrK24vxEKlkI^#+ z8;F?C6g#ZvtGsfAoRtn~a@2dIdB|%h9uxbO z&OQ!w?WzXy@=L<5;;pQPQxv^U;y5%_bQ>!M_OEtW1!fr?wZLD!UBys=M&S9r z+*~({h9>eAnF2Ud3CarR!O>KwDA8}f3+a7^-PHG~NG|y)JOi-CMJl0{@XTZG%0Wat zl-UzLb2xqQE@bTBiK~uRMI`hX@7~MMBAvw@L9*(krqOctgWdy@#lQ?a>gq}(*}KOB z!4ve`*MfFpxmR>->B=Vuj^U#`(IbddjM0#8;&$-AOfc2fXiGZ6xs8LJaB)yI#W1+; z0;lL`zlp}aGRpN1s~N~ zx*bh&BIm-5RcvS1G_Sm&j3kx6^{i6(BOm?FTL|A^MZrI_Ye&mg7Z}l>MU20Lu_iM1 z-xA}(C=~?OT75o_KPa8>W8fjF5VqHqa?%+jzli5b_N@3iPK5xh|B{ew&xZ6E4B`DA zBKgRhq_|?(qdUn>Ee%G#i~Ul;xzT;#WKcNccRizRTW?46Q?u-I zg%DEr01@MSN@*xIu}D+FT0x!xt_5%T@#^~;;re}Rm5Dfs624WM8{o;$b%KQT>;XR3 zVIHUCj7+uhNnhDM;LSLBG(}~+{}!du^93uO>5awy;N-hj`6ozn>VwmrXgM&;tzaW)K{2V2xH&%g6DlTM zDsd>d!#CZdN(TVFS_Rx7oY1CU+-2g^zh5J7t5IEU`Xe3w_g>oj<+9>e5JvAO_(hcX zaxe##*`ZzpG7^X?;@1j9Z^nbs|N2))zL@(32fInS580etdn>#MkUeqG$+7#!uDSsP ztXaM$pTuGqs|dKfSd5 z#hhkubxI*=AftDj`@NrGr&w{ZR#El1E83Y>jT@4=j#x0lhCRq7%0lXXwS?Z}y0v~v9AOMP=6%UPM0>&3-E3AU+ ze)M$wz`N1)IKSux0=bTx!|50lLS;SNhgVyS>LV82ArilRzK31VmH*I9N)b=BIus)e zd;z=&h;mjt=p0-bn1w@4XmU_$-#p%UT%W)T_0fZ(v;NC@8gxYLO$)sH*6(bR3?{N zc~E8QI6IACfEKnSKYn-EH34J_KwTBwpd`rTZ@@|ZUV4il6(UVSNX@$1@R!c#=V(WZ z-Z>?`-G)~#=AEce>Tra1cm(`YQ=4NrkMS7JgM!(t@veqzw=Lo>A3wPma8oxSFhBuU2ZE1*kaN>) z(j_D8L#5gDqpGGgD>kqcEb|@suui`|{9TV)OT&yJ18MqiqvC%I(qeMYkM;^WCqrt} z^4cDu6J$xaHF;l}g!;IFb}8l*1pqXx#HbZCXG@$28lGIm_XDbR3ncdS?)D^!M7SxxUsR^kZd7fPk3}nz{j7lYvC-c>}6&`WS!%8B( z3Z1i0gLtgl!K3o`fFHfzunk~u6hfgn&THeVpg7&Yh&7YO04X$wVgugz}mF^)fdfn#W<2HWU1 zY-1#;gOPs$U zebGCVu>b4GaxJ)_OL$=T>4_$@yWbtd2Qb}4Q)1dTfZ0i0w${)_B&_0=SJ1-d`MK() zTdY8G(Fg=-x`8o87rDQ9PcCz2Eah#w(9JiN@fJML8kL)>h+!^|Aco!#aNcWqgFEs8 z)2uCE&z+rB_GsQ?-L8zS;ySyAWJTEjP#2KH5Vg*Mjm!Y!Y^eq;jZuELm!d6Gqj{r8 zvX_K0ZIQfeIBjf95tqUsk<5ww?F`)JvYG)RdHu&S>-XqxW{z=|Si7>YD5=nS6~Wmc zDK?;AciDr)p_sGZLws?{7&WsLQj>BIHxfNt$F`(YKRd`^2(=wcWhcc>8Y4fU-rVN$ z3sD3-s_120AwIdf!76GqCrA+OFT@k~t2tCe7uiV^mkowOdK!E{XE>p7_j%>4Bzlj@ zTC@^!LjV_BFAEDMu&`MsLS%IYLaYX=?M}WF{PgTVJcO_W3i3=5CbRs1_97bTSYQ8- zsHk06ndeI8cb-NhYwlP= zoZ-*qfVA59jerW3Y|f9&36tIY-u1^+a3OUc1#Bk3!>t0G?lJ^{2bwaoedqEeYM#wl z(-9&Ngg4eF-&7mzY>VN!(Jwu76kggpBKP5@bEu=0JcLo?0dqE7+x_*y$b-LKphUWZg8CA+s!~Cd*LP(9 z`URs|qJ#|CojOXZv+rp}HNQgew&1THS}RtI0i=li2vP^tO|i{7!y!%@?-iK)Tf`>Z z7wG{|jFG&?b-Y4|^pPZg(adcaq-#0?n!Hjtr>94}i{R=F|1*z5ka>7G{heCEw{Ciz zLYtTp^WziD+6(h~!W0;kuZe@x35Tud1a&innsOLK@Y&uxYZMj73EM7L9qG$KpJ5O4 z%d+I@`@ulH^`zcLR>$a4>|2967kJsM^7YWoqC_R;ldtN1*QItUB}*^IK@y5;HZ12x z6U026K<1%PO~YRu->X{r&q48w(I)Eshzbqlt0rTa- z%OO$OuEcjmc1;8HT#5a9H3u9f8MS=(^U2#M-~sR_ly?Y*{(&1N*1W`S?A~%~&ym98~ zf04*5s-Vv|@wI{L09NXyv6}hAZjIwhsI*5$BlKKE#dY*m-;F7O(X`7S+CFcY_O;bu%JwYP3_YRU zu*nC=3D~kvL6T~@K$0N9{pnq_p}mE|ObeiobO`LRqQs!uV`+t` zrCL_DQ-d}|T55HiAciXV5_(riM%@I};teZS>S0{8(%@tA7+!BjDaCE*k{~|vs=n$8 zv}L!pHpvmr%=;LNkBgZrYYwQVjFALl1Ur9kJ0LJG1{B6%yOGoXuDxqRiTRekTPMo5 z(fpw>5R{!~c(F#CGM9Qv@{k6wEb()$T)1sPLMe2D-XHO#f|#{RCI>j>&Zysv!2Niz zJ632+J=cdq?_qCXcGO9dTBKrw{oO57jsvhws2eKZxV;!ZFEII`6ftTdu&5tm#}fL`;~#qsgBz?k#eZTw#+kW6EyQ$ zbwS39OSWpvy8kN!(LH^MVp%x?d`-y>{=X6~F#xn#*f)j5o!0fpE$GR=FfIIt$C7i^ zAy>JhnttZSc^gU)yBuC9!ZMFon` z$qvso^HEZ0S-70oEN~&Auo{L))1@g+@BpXKAy{({*&r%Sp=9ZUMm!SWTr546*FI z_?xBcw)yuHlCzQetxl|W22H^5->8Rpz7Va6>c`i&Z}|jy80`eNgkhl% zn@L-tqxDd@^ZAG~hT$Ec?z&bH8@4;9V_m|o z1Qv@$%bdiQ3!%V|v(?*V3ZuvHWstd?a_~*i62bR{NdJ{>O}XXMCFDX#Xvn|>-9$_< zp=9pb?2HA-f?(hxFl z3Ag*yD{-@F&d$TrFD~@sx6DBKj!7YMLN((Y3a32mTv0qX_$DG21*v6%u&gR3v$^0$ z@apg<>i--RL~K;fF=uvU*L8^OrhW^)&2aeD=>+cWb}(&m>vm2xP@Tid|B7pXq6iP= z4q>p+1K-1W36T7rwhER&LgL&YV?xXOteESw{wN+OZ#R4ZwYc35CFVnPl-l}vwCb|d zT${dF|7ugR4S(V+-nG?7076%kkAm>c-aD@unB#$O!Tzh*Ork3nQ(9%CU^%W8J{|FS zB(eU+yCMyGa|$6b=ntL{x0wYqmq%)i<;kmqdBUiQ&9!V_8})~6)OO4d-2{CasAIlL zn#dhUFl+N;)ln9~YA&>LWqH8_KE6yS1GAY?czOH{( zmg#ZF=q2)K5%g2B3EM6sW4x&rQDjj7v6`JM;bPKd z5t6y4xyv*n;_X#zBf-zq>Xy3eQODx0u!djZ9ZSL8 z@Ds)BwaJG_QM>Q-$*DfjpUr$q9qO_%>y+$Ue#VkQLI@s6$b{6XfnJbPrjj>%ar$-l zl`~;=@hnIOa;M!vn`3#5DM-IEYv==i0(Z~D!Z+|CVn*j|>hciEJ-w;TL~HxZwU{%{ zi!{$Hgx)n&rg(j%LL<+w-c@F-CH*x_QN^0D4@w`ToF zj8FdWV<~DS{xhYBpnt#@qZ$k($uro)epjdr^oX5*_gmbV;nY~)L@yu%F85>+UFC-# z`2#QXU6VUwKimE-nW|V9=Y&Pk=eKXk7GD9`il^p0j4_an(xZeA6iI{m)K0`=uvaIIzbZqIMnxPCyt{OcBD$WH*+LWrA)3j_gZxia<)^ zJ8QfGkJ`%I%Wc%1{&57pViqg}H(=v9K6M zA){#V+A!YGfuolqqo8+LI9=i2oR)*ejFXPfv#oM$sGg|xOrpJuTO7&2cTg}ACq~Qj zxg~zsnUkf-P$Pc1x91n35XRwmXS1Qnz%Izo=aJvWNrGxKzGI;Q z5mCej8z`kS5~l&Vdkno#4Z1nzJ45@8X;ZL)9;cPsmknIw8~x+U(n>4;LO%xcjIG+> z6WLnsDFnBz2zLp82CaPMyRQw@8;7GR)q31g-aZ57=LH+s>30e-5k5;D;~~1&hqm}4 zNgRwzuP;o|*bI@rLK;`ez_y{a^wq0R`Gw)+^;WS~Rb zT}5~B;?rxTjPHj!h9*&H==ACsfj-BOac)iI=bt>Vtq#9B%99Re=7psofjlPEL z;)M)@5)1SCkN7B=Y@|_?V2`DZUyHVeR}{d3=lTw%6sY%0Guy@*>4AcdeuG29gJQ&3 z>CiWe+cVbzz=lzXyeB*;bYw-i98v>PT(3K*wP1(`#9xbc^#h=d|!FB$41AP@c-(hX5dc}>PUvsm~c-94sOWrHO%h1Js@*Rp*9L|0EeaYDi%2I~bwF_c8aBMSAdL?t!(pB~nz?P;*D zXzR?giX@OnQ@Y2pLoTk}dwazI3Fh}AeJ(;iyXr(GzdU?>d6!166orjf2&vNj^C;iUbqp&eb>ORSu7^LgtYpjbt=8NM&5zSI>W#NB^~nQYVeLBMs@4W~ z^p*O?5HhfWokwGSA_&@+Mx9Mr-#$mNfN)S0lmCdz)vCTBkSQO29wco#F(hOX4w5GD zIdw=Yc3ss}sk7}NkPkQgi1_@9U!04&51AK@Wv%dG< z3!?k_Z#?b>F_2KJxytlNC~EC{ z@PykaVBV(OFi5H0)z;i%iOc-+Co(yBGC!3EDGmd}296^+BKV4B1xM2Efbu>04R4gA zky6}bv_~-2O_l?C7S)Iw!k@dLneR~BVX|txiI*6^;)7+P3u7$ztEp%ygpO8yzM0c} zPN>^`0g30fyrRRk;wZtc7r$Qq*frbIM2SZ&(qaQBZJe!gJ*<8N9%8V61u4j5!$rfR z*1U>WLsm0`a2K22cUhy|T~wlr90)6()*%DHhY%%8JGE6&2})K*J;FS3ICq|pECppi z0klJ%tomuyy!MN{J|pTbe<;_v!@-9j11z>ursJc{DtJ5Tar9Q+4&O@gC49mgS&lY2 z5zPsAO5Ib-C-V3aeNPSRhXM8dc$c6FvF5GymI?Xt)xP^oL-ZFc8Wc#kD$n z?Y>s{p@uhF9L|!Qqjg>wwBhGY^p@M;;)6zsp(k>1#Uf4h5qTUOR%v+IRTFm27nGBIHvh3F5nw>N&05|X%MhIE>ssq9|KD1;B(y1E;#1me{^03M;|ZL7N+WRX~AX+)@Lx@wCGtK$@f!iB{mp< zIjyz9pxfetXjMP@bsvoj)rDVNA^%Mn(o(7Klfc`NST7f5N-6)wM{FbufTlFFA&AJ< zN-Qsu@;4{_cTE<7{%ZL_kA1&>rhNSdS_gO+PcRDubQ5qFrdKd(cSM zUUCjT1rb37>(6#f_2#|sRXa4rxkA^LdHkdh4Z#Q83SB@L8JiV1)yXu5fe$9;B^A7} zdM##s)U?B!PW43qEUh1oZuT&hg~SpzQR8JqK@6K-G~FD3+aNZMMvxb0BjhIhz&Byg zn>hxTxb~TbtbuwNA0Leb7B~OtCRR<^Q$%_Z>)WGBSI}qY-;jO4Rp12U8^6bK)4q%; zuKK^(f|Z4wV1>)EL*I9g6QC93z>7b36IHA8O(oaEgrKZovAd<;-Xp;Kiatw9S4{_as%9E1uR#7N%*L| z!a<{+D}rv1k$fi2cQ!*4YyNU2>Ocv|96i<0+a*9D-3&m=mBt|Vuc)PC4l#-}iYk47 z5~R@pt5`{9NPM;PCr~1&`OKi8N%A!g7WfcZ84nBP4Ug1VLz(su+6DP$ss!7&6P-Fujw&jB4uVW@ehK0R0q1a<8MV1?I#m zvZ2O0HIEY` zNy=_Q`-AThAf4gZl2aNOH&_Uv{V$GsJB$R9^3j1S8IR}yGZRf>>WCCg=l)4JhFK=i z5_Epvhefa731p$gifl;*b*k>F0n`&}5zaR68#vdB5jB>*rNqOWse=&iU$4&HGxv%ZvPJ1FgMSz1 zr@Uv0Y{UI^lXhw8fapxu4HRCTSYGb$M&M~L|9)I}rLS_NAcEgt`B+kj+|t#nn&I>S zhBtnBpo{1f=S2_;5*GfF+^BX`#GpKmRYVTD2r{UzzOX(7`I$spsWp3qBM-LM77E}T z*I6OX7M#>=R3{ri+(G0lC3 z>-w(OLxBbP$7g*f*U=~E5MLn<@)f+_hldAF>#{$b=N|qocP0L`o~#Jkae9}BL|4)) zY`x^fQFOAQ=uD>RK6LgBu}pNz6JCoKMlVmiPk+o`gt;-%;pQ|LNWwL+WWznz0>DpNBH4 z8Khr%!}gQKPNIOafd%SZ|M*hp`yTw@(66+U#g|&ICdGd*&^pez$W;LMJD@;!K!A5V z80W$J>CqpOriRE%A*cuXcQLF7g@Fb;@2>m=bz_TpDiAYl6(qF8hR9$e$su>)H+&m9 z{`b(9vmXuyd+1;;F>uP-K9GU`C6U(ItcF7jv)|*84GE$Tx?8db7Mf?F>p_~V6cZI? zBea*!+<~ zj>BkU%Q2N}!sRpTPI``FJ19vQFv(idq{`*th&Yb@{*J78Y;@T37bqllr$4=f0k<7` zOoBXNzJKb~8*XY9zr8AUV+nkSa|)(&eT)uVp@8gu@&kR1t9I<2MH}L-y5u7ZpTl6B zI2v>mU66T@RBL;b+Ent3*6Ypty?oN zmE_i_vf?qeh9*Xfw^S}s>VMLKfDL*-wn3X|)oT}~PAID2;w-7d&Q?hCtWQOxO7qAU zpwK9uuxL@a^{1}b@qIG-{=Zg>>#!%krLo(5b!E$4KG;UuKE5K2%c2^6#iGic=->Fp zT^1ewWMc=)>p#F-3WhdX*2~xkraoD=H4d$L7!muH3fx5?kk{)dJM{0J?`GnJQ^>am zf|TEGy$Ik(F~-a!D_^@n9{(cn;dillT;h5)7F9O;1s>Tn9!GJ#2mwM+eOc|)8CgUx9csTGsl72>~d{Z(XCr*Rp=SAY&dW`?@3 ze->qg8|mP6PW1hYe@VMPDQG7DE-R|YQe98Mp6ysu?st82ekh(rEch;tqm`l2KAOQ_ zuE+R3WRXq*tLs7nMalC)r`rt01A>&@FRI__d|RI=nQR9Z;))9(WM_!tJ`Y&UMT-96Rzuh-uQ&dMa-S12z%39_)b$+X868BKvc6&aQa5M03w!WASud9J%t zn+KtqaJY%uL1s)h4KQHEqw5huCUGqH;IGYJI}I{PEs(GVwIMwX0Dqm=K#hCAVayfo zk|VPqyO+kJq#GUsruIg`oGzE*2LN;)ui7_6#4Pw*>B^6aIIfg+x;Pi+(qoj{6>x8h zME5=b0|OMPj)&4-_8>IN59`zUEE@^Wv6_rZ)sSY9ArFu>D`Kb`1Nn&1+&69iw$QTqATNQg;pQP^U^`U(#7 zzjhX5ROC-M*1|uj<<_wv`b_v=Nhlx_bQ@^slaw6&tjb2%LUk7-1kKXi=274j-D@Jx z1wHQ^2JU$A0wveM->ZV2|aNQh;mqYE?b6qGO75VORV<+XuoRjp;kXcVj9(X4na1At45hBRJW( zapBJU_MSPj8q%$oNkL=yMcZoz4h0GZRZh#Mam@Iy*hm5)_K`MBtH)=Dem8>-5CJDBG_seGeW z4-PLbsY|=rlb|D>e%PX8QZ}G=>y5wC31{9HV*oS;=2im#_O)*PXbfu_`JHVeFMP`= z_V}?#=9(yjy0__n{LV4>HoB9`T@YCnnHQT{`Ypb)OmNh6CWCGx3qPTGo+OGu$*!1C zI$fo?u4S+mGDCFd`&}O`yko(fO~9*>vB=+=ELK_ZQNX6_?axm(L0kf_pb*+<{;s&a ztN2LvnS)I5@u%h)xzo`?Mr+@AtkP$zZGzmw6ki>1h4APR4YK$Nu~C*oZzqTf&aZJW}z+O#nvaGLt}wri-+ zG!lc~cctD=1aR9wx_-46m!GR@y8bQH>x+0aDc`U*r>N`bK5)ay;yZ|PS2_6cba-yM z|HzjsnVG%O`EpXKkvrvG2nsX;Ob6T^1e3v4ik;)SWm2hcWn7iLz|M8EH66Ow(0a!4 zg&bAt3$y@eU8_jzJ6wrr^mTGLQg0PzKi?{&u~`RQVhf`Ej{sB7oVlK(VIK;M_kvgU z6Tw5-mUj>dvkZ_WV;JIdp_qD7mmWVTl*Xx80MgMJBr@p#EwZ79c8XGmp_(5q7+z)%zZbj+;(bR(!)w&fn1ZqB|0a$0(`}@%pehhWv6-nf&$f#7M^Y1(3iOC*aNknI!8`x zEa%H@8u);XoqmQ|cKmsplC0CpW&F5(xdtLcKX!&VE6mUqwKh^BQmEcbS2}=if?IBCzOYc?sI{laZK9w`&xWraW$Av9)dlH z@?_|%dXTZ?8~r!uM@>^EEA|ShhS;p@A`0$59D+U(NMP+XVyUsfm;ml2%36oGyHEN2 zO460LYXZxS#QYbQRX7$zLZ!MF$Af|EFQ3TytU^%KpKJ|#-34%NuXuPYD4lrRO4ejJ z2iKTkefJ|6%CY425A1_y{`MaiVt(ib*Ggu&wDMS0vwVy-ud2UX?0&|S7nO@;y7;v$ zp%i)ihTXv*@Zg$3lCrwBr6gxzuK<1Vw!!I&+95wD9|s1Xp|+|xavtp71F}I66Wt>| zw)M;Ezxu^WBdmfBMutE%Rtu0sZS4ntk}1vO&UeZqJ3)30c%D4*5R$1}e+mElpCh7B zlE6+)9HvxU?<9=!A4(qx8t~OB6{rQFfWtc;S{Y7?-XW}oIvYm$Kix4^W4eTNktrRj zHgS&PVB8>UeGove@;uMRsq}ZnynuCOch`>=MiPz<;TTYY(C6@Sk9gTA=W$|PkSu3? zJk$Z$Vh%2<-s5W0Os?Yml9iTzjYcxSFO;>uAKngKq}?>xr8cs2%maYBaOfI{_hbKk zML;yCz2y%>YGA<$6l%LHgEL*!<|WYqzRIT=4Fph^mXF6FT52bNM-%z==-S}^x#X-0 zRuYJSr9ll*f=6(jafM0fq?+absri@O?YY1lI#m*P_}al2=1}w12%3kww}KV-aOML^ z|BoElwglrNs7>Cxcku&0IsM{I=N1)|!qU?nkxp!pwed70{m9-rlt6($2-}te3b&)y z`;UP#RvPjSK0)Q={tabAWHDg&6E)28-=<5mtJpCTLAL9R{Zt$WETnXmdDV~-(n$0x>QTZHHb!2gA@i*K=DsU1t~=sG`rxI8y;T(Jzq8T$ z?fkE(85tn_^CYhk0qz4i#o4)Ymj9`LbR#>+DHoDp@;(o|?0uWVmT_7$XIw&O<43Om zVMbB^{N?kW3@imU8L}va9PJ@-hC8(4Lvb4^vE>caHS^jW#I=}(7f=Xez9V=)MN^b< z!jfvADQ8JIr6gGv>8rHu={OK0y#A1hXlFlBDco;K9FLtZNs9VOj3)Cr!NH z*jpF_ZTDIH9@J>2_UG)m-L#k53RvkKiEg7Z^W&_Rg4@tt^%A_Hfb&#OuEG!GDz08z z&AE~}>Mpr|{l(`>s`|B>N=XES!pJ!6J=^%(7#}taH+n9&l+7d zrUQi27oONWuTVxhpH_4{(|V)!Gw66Y-aQlZ)@%Pt^!=t6`i8+iZwMw(xwyBzt<5r6 zl73i<%!K9BH(p#7m__Tz4Or?hsNEhzva!fwU z#va`1FHjsyu^KqVS=#8SeZhG$F>M!q5FJRa{0CK&plWfyJ<90FN16 zI5EFle*=>;g(P-<*zam6i&b0qznrU5ScivUW6-;)S$7`k&Byb$jcEd8p;HV36(9{2@%tQCikz#_0)1#E)X(9Ex{F;y;{M4-V;JI3s#k$xdQ!_3QrBMGWgWbG}R9 z=UHn<>%Ww_An|Tu3|bHqH=bR5zzy;|{l0J*Qek#`ub&!bM;z5K$5zn{*nE9I6J@5K z6JHeK1>`mMEqwmX{M{_xgUgoB<7@=;p5i0==}e907+W znw%$CTZIZAB<Pq{O6WZ9dm5e|+ZL5(s=reXJBuH(YVj z$&f4*59@ZRC8GBq8olz*9tfBX0FQ0(7?rgG=Hdv6P|Up}Wh4_i5z1HV+#>ng^|dK5kvtlOsk37n%}$$)$a9&6))#6s6Js=L?gf*m$kgZz%63J5F$r_eotPzLy?*$yaeqxkOR+;bwc184pQ zD|D7qJy0wLOYOpm&EO{fEYJtMOFL)x^lV=-^~ss#WiEbSHrg|H{bx z<7O+3L==dC5Tc0|?^DC6{oRe1olakZcGvg{uLjb#(S}OB>n9gKVqdZFU6{gp*eS2x zod1wxip(h77#D33A6L*<-D&~ti-N6R-kyyIUTH-d47_~R^DPY#LYj!fdwp4g#Sk%HVMEUibn;^PpMUJ2t z4!cjpyV2BT7!54wXHw@4irShw$%2DbdJzVHmp?-9eEvWa8xzS{ICSdLFuw)hR z4!gEkc`(rOb(y!9{f6fS>U8)X*Ii1M4MO_me+_RMAcvp+_EY;PZLAb~f0nK9+0@Qs zm~bLk?MpI_Ptx@57wnjXcjH4mv!-e&!NU;NRDL+dQ1pD~`k-J!;a6z__I<|;e@&f6 z7WL^ghqsH#9Z(RwKsp}tj(yZCE&5zBQ*2ix1f7HagSSc?VfmAG#a`sBZ&S=yM;*b=tmhb7y_3VQnAJ_Uzm>*rHY+mh{~D zzf^lzTj0)9DW(duR~=%(p`|Tmy+d{{Ble8}JiKu<+NQ>IUV=)=njl&~4s~BG zrb*)C=AB}G^SrqD2MD1?Z}$#MGfksq?b8I?EI>8XPSg*9#e3X}QM;+@KNrm&(px&5 zH0vG5`ItXl#782(hoyg^(vMTn#~Ct4`j3`y^L2-7$!F7z4ySSvAy^dwl4ob!ZaaCsYf7>BH8T zNa0>K=wW6p>nqtyc2D`sV{i$F{9LNtUEzTcbO@_r@o~D#erWGYdg#$ObsmWjrBBMuGu9Qbi__W>2Bok zoy6_zc~1j%z96lbI-p~aO%PiIhAR~ZKiC4kB3a#V@~3q=f%3ObmJ*vNFWPT#XTV|W z+I{7y1NrA^P3(0?pRK8ve)}_2WB{d!)2>NHDx3Gvb0_-n^InhL&OmIq@+nGoCK=t| z=5hgb<#m!6>`GX)lNDR`Ac{(0^1kwazM`!JEL*0zL-z4>BS7yg8Qpl7$YO&@7|o?oVAEKyn0E=NRw*(3{d3_8e*kiVF)JU zOWeGOF<^$$4=qXf?DjaAn|rA-vCi%1>kn1xuU+<0j~&&5(ifAw4x8$yh0Jh?zBQc$ zg<>TakX(Rd4HY08k+b8rLeDBGiubR_F(cC=`M$-S2SP-|9%L7dlZo9Yhc^ELawvoD z4Y`w_N3dw2$^)@RlfMXJ7_?~rXq2m#WMcR>h>4oyf_H;nS4;@}B*!bdDe$pJt&|@c zjlbZ{_6r@(rw6?z`YdO6oGBB6@gB1H(ejB~I8YHYC_Uff9CC16J=@!5Oyy)_6M1?T zV;g}o`!)Zv-$AR9AF*KEbp*v^^@3lg!HQZ3j1m@&aYNPMLJ~RGLBcg$QD(nFJ0jtp z&|hSCZd5_7dQ&@iyxnFM59B;7lY!a*7!@kkTEq0(PrV61lf3FaZ6BobGDf^xWX_9_5IwhmfN zU1Tb@=1zARfnhG#MCyNC*(H|>B~RhZ4|E`A78EACXFOlV2fr!PvvSFZTCZ@cqG;K9 z9CX5CXY)Zr$pRJsBMcrY0MzD{EW7QQ=gBaKxWOc*(xRp4!uiy=Cod-+w~H7w&2s~Z zGdO(;mG!^fjX|0$AdM(%Nz^9zF%bw-i@%DMKk=j^{XhKRb+vc*Q5@IId1s7sWZO}-p5E&yoBdn#7lsE~=m?c0sGsTG?Ip%{!CgRXBNodUDqtXf#3C;_wLodq%!OKMk9m{7CvO*@+NhJo16wWm2-Q?Qr+ zgqxi;lM%%shx_WcK-wo*6u|-T+%u~u$`^N*u0O>txYz2J$TsuW!J`lcfIlz$5=oJT z0}*|kd&PJSY56(voKO!j+|^sb9+idGSSuXY;<|3yT-^B3p;@}x=@3{>Ds=rDJ%k)gSY7qny@H> z9EyleQyE;UtX-l$0@z2P^Oyp)X z-DKc~05?(zGnj@kT<*w2SwVvaDSUXj-@@MZ7uZx#h4P=teg;N6kOr1H=nObs;}s@qf5h)&$&>V4t|9>ZBN7(uSOn(dgoClN7*)tEcXd=_@)7Yo{N88PnAtAYYgZyjrCUG@@G!*}tCP9)1`PhL3?vmqD}@!?1G|M;BwD|jfsV@%nP zh7S2f7Rf;`;E>{vUG|1TZlIXh(f~*B5cW7T%cOrp@8rr?e`tTHwQtVIS0nyBe)>{I zH|m4a$+a3}KB*o&&Kb^@6j{o%oikcl>Lw0%O`J7ka{;OiqLtqIw`YfP1c|es``O`B zVtJdHJolnC3FHT+Aow78Q&bU{NTUiYQ^LJV_&m^ULH-_>glpg&xO-ctM|Y5TzrwE~ z>CR(lJ92G=anD^md$yoB)jBIJv0CwOv0ns^UJT zV?06(WF72QeXeMl7fSYb1`2lx`g58pVT&7Ww{eC<8Z+dOwtlb)Lsz zLirNbu@}f258!6>tN0BMX5bhFH!sjIqu{RObuR1+p%$5|c4WxiXY?ZXNvpjZawVo6 zKDeN}G6_o`pj5u~4Rm|%FKO3#%9XNc8l4M&&d)@eE=JFsCZyK=6TV9am6>>22mH8G z|2Rz$bG$hjg0Gi1kC}$Zf%yor9k5KeOGTX{xX*nLN0=F3*GF2I~O_!$o!33b~3M@KwY)+B5nwKD1b~jHF8B zI;yvROPL3K4~aR33+nA=tpO_s1`W+D5wcvwN3fctAHZ4XJ%_Fple9v%CvQY5f?>#J zKDSJ~`kQ@?VC8?OB6mQaX`HC_6)%b-L#%waqcRbSE=gxrIy2|r&(D4JgWaw`6-P*h z-~#fR8Q;X{Y*Q5D+Ai;xr_5>RBXZxUfXBEP^5QTyCR^NQyZV_Zsb`)V6hiM_jnCk%=cC9}R) zC>LX<)l8BJjFEsK4?oEg8(hHT54`kvOItazY&7VOF|SdFVN&zghLzI|zu5hJ7qsNG zAB;jAXRCBAlV-8mE#MfH7^#iP7gxA#iuav?;QXn`(^mH6vX0}?9MpxDn0Ct0w06A- zP$X(7K3Ri@Z1b;~va}i`r_{p59{hu`Bi%>=Eph)JkGq|mcP-$m z!YqmZx&u-^8hx60X%p#2#ZIjpxF(%lkL5o|70MmG!2D^{oH?E8ksf!v6=I5j6`to_pe!GkBuT1plOdY>LPYRh6WrPtqxR=Q~Y=vPz>G zmZ^Z@2dHd>XUZN`$?vIbev^)!Q|2}-jI3diIAvg46vs%K76CES3$U5KPs8ae<-jBH zQ8(CVlueL*%xs4=`=?iFxC_Jsf5+Z9H3V+6yZS}rv&Rx76cx)3Gt~YfP4&B*h_7{j z09wPCPH8`v2hOzXqDvGC!QfQDPrVWavoApAI8)9?Oy0Kmt;+RBz;72AL9T{7X~<&8 zJ`lz`$B-1aBOxUGYl0HSG@6~L0(YD{YU{^SCsG!+#c*b#nBMMt+8kPl zZ@bnVevJt!7#5ivQ3AFoJ~2%GdLV|$%;y~2jJu7YL*sZG3LuX^s$hi%l6-|t2gKu* z9%1;N27RvMPy5=_6cpk1>?(vmt#;vVvpFx_Xs+xvdJiz=^_;=4Nh938uML-L7d8h# zFRrVn$YeGAzEnSCK=9b)XGYAi3*2@!#OTA%nrI?e0d-&%KEay@@F!76z5jeeko>1= zSi35giU;6U5`GD~4auO0mHTXt?%1PYw%30VFg2!Qm7iyAoxTxnZ(rl(up3EQ7roKB zATLXEw#Zh?7nAs0gmOi+1-+wwHeVIo)CTQ0@KOiep{LCBoW@9Hge@@eor`y+uIyXj z;{+?k(bj_0322X6KB1Irb(X@HSew(m;--yKeG3BK7)xKE|NTk25X7vny6y>5+-M~W zDFTzh7yh|fRXrb)lUX!THyKlT`P7g~gpl-JmwD{@Y1*HeF#w>9{zueRFhtdD(V@E( z38lNG8)@m32I*AkmhSFWK#(p$O1itdyQQU@H_Qy*`v>=)b9Sx0*V>W}ms}4_6da+Z zgZ^tj5fJ)?)+|HVO6L8G*kJB6D~;M@nMXdrsRM=BTji15hBcYoU@mWE7@AbtT&D*RJKe>EeeDQW#+B>h8sSSdN84CBNzR1h+NLe&CT_QB6ScqC1_a z^>_;Hn}#(rVV$rfz%q$ zOz{m6%n$1O4TSR*XF!ujtn~7d9?f^Z5oL-$9|d>szkt)`2fJ?>8lm|ahEdAJ(>a&# z*G#_ICGlYp_e~NKAU~SFEGR&eCk|bB^3z`!ORvp<7SDwR3x`^3w;sy+P)Hz-T{9nqiWQD_uFBiXI>AJAVsO*FTHO8IE1zXmJx;*mw%ae90E4)!u) zXT9LA8*LS9`Xk|rA{E(T=JdXJ-#`tU(zB6lbeJcjzWlp$y9x7yg@^xvqG*uL5=OG@ zgY_9F8cT&10D41esQ3LWxsbZ7ZpBva~huqjN4IFmQ_@-uy9yx>76xdk4<`v zn74LiG7SIqyM#cWv2Vl9H8ViSj~t#5*<)EG-Bl&a1KKcryw3U024(UV=F9`y-kn7$ ztBiRf@)@4b{)ME^C?!EEOyZKfwEKQo1iQ0tVUed;`(p#F3YRouMsrtEAbD2aWsi`W zQMuWEtZuGt;}|zdYH}yW3oGdAJ_5U!^uV+i4{W73V)J}EyKPzCFe`;=o-XhPcnIjA z5+Eu$ZrscGBkDZyacP9TzmMEX%iHJKRf=^KoaIy=r!8vL%Kk%>c+Dj5n*vFxgGARcOqXK#h&^Xc#(2j<|&wgR}A#qj|!w+c)ynK7U1<3tK5iBfo9m=@@t0lVgav{UxeMjc_jy3 zjZzh3A$f@+-!u+%IyE0rhw=*& z#BU&Y#WKn(tsucA-vgBN4H{~~h=wCNy?-UaoO^JiHvN8xA+RHQL@lYsHCNge1@q}X zGYVN#nll$Dar)DGQ6%+Tw!+3B2d?qdm6bM6Wsx23G&-;MW z1V4g7)f4n59!CJ-fSHXvF?P$}nkP9GZI~%3JnHQUFWn)eiH0-(q_M--Q0OUldjZW| ziO{4%aZ^VXUlaw3WevuPvKm)PdI^!GkugzxrsT)yC_v(y`W)QP-@ z_^XU-+&08|fkXm2sm@Kg)K>p{)!!~013tXM!W@dIlX$?HQB>{~GfgN3&qLHh9ahq% zm9&1g*J|_T0IUWowHO##NAJ1MAH&l2@=P?gI;Eu2C9Rz5gjEr7s1zU zUsRS|tPUp-THx!Xx!a}5p7X_I%vG=w+f zHjmKt4+w}i35cxbpOHKnC?~#h3V`4n%t|5EEF-O7f-WYareAorN<*U737-LJbUO{3 zepRVtA&)q*!#NSUDalsRPraeTDNDJJX~q=EQ2QT5@~yg7_;fAHV|BQ>mY4+@-mfRh z48hNRNg_q7X91REpw&UfAXl+-t#!zbse@!BlV!kNbYO`b8tn&qnH#7b06fOOdXcUI zR_*%PJ6L}OV4v3__K;gGqcTzc)Ls*yJk2^fT?QBu3Vb8ld1GTjaWsYFgK)gu2!k%I zuY&A2TH*4~A~PtCfa!j0cuM2VcvH-$RwF_P!&M06G(GjVpqJ{>9dcwJ+=bnvI7ii3 zeB<+P}Tmy<5GRDc!9G`={~_t8(8H|aV65wqFig#DMG(I=kS9M-DuVFjH8 zi`$QUNOek^c%jzLa>y&h1QTt=^6V>7x6aUO8|WPB#=Bl2E(?tB_!Q2dLCmK{w@^6<$YOtAAc9mYrNHlk%5qaip8MLe%L3Hh^`xNMyVg5q z>lwIl#7nmg4xj%Mw*WCyKp)1i6r5BN*~>G`?a!9Z!yNrlKU8D)r&TREM@4MpFk700 zowEhGDQqI-g8v01ShSkDx3$vkFYweBqg=^;w>^MhNMhh9wv<@M5fZ|6>;>IcuYkGP ze$!j^0UXeojGG_nE1}V_?6Nh3Fh%rI2VOw5mtdJ^zpb@)uxd!{IgZL8+s2xHm2PO) z?xIl8{uyo4*H{fl;@$q0+b&u}nNsd5DHf*L=L3ZcHhy<~kMLu;vp#2?{MLWSA`QrG z3c8&(I-sU52a@Jxw7uSFZQp-wX9z+T+3J&;-aRUdBoSw~@EaDjO0^0nK|rMYP+4c# zLC+zA2)CfLe%0F3e#O{*!a_G+t=^sl((ov#yUSg?tYVwOde?tef}-x$#VT&L{c4(& zMChlnQMXx4)j%tKn*P%VorRsw@;T=}_R80PIKDp0eN2?I-q;6m#s(VFC;whBE{BUZ z+vP)*a5y9^1%olYmPeckthYYs^fF^&6RPB=I|JR8%-dT|FA?-Rv~k}mx&e!H&LsHH zRm<#OtPu$>&Qs@o!&|N|rUO0mFDzooj;l7Gc3M4Ud3~TP4>Og}8W)g^{)b{^Ylinn zo&2Zw42@5-RWsM5fqyTdMmnOc(H#U^?)M$GHUB~0gg#M0uH3vi;)+t~eAw?5mcLxX z?P7FqJ1mvMf~|D@*@;>NtLF->jQwB*oU2KH1bKL?C6wp-EAhR;aS1hcw0NKfE?fg8 z6(%50L4$Z}tS$M_z)VMbxpVJD^RhY11WY>KcaG+fbqTt!=@q4bib!csg(l#G_{zO@WZq+UrC2jV~~`pmMEunFMDsyBuNi?n9=MP>N|@rMKAOZ zlx8J9QBKAl%9TJeP4mFZeRp+&pj0WzpHy6NpEMr^uYA3fOx|9z@G`9#)gT-n88xG) z;PcQmXKKoJ{7?cs2xQGt3=Vo<%qzbEU0eH=iVT0A+f)^jc6&3yz7D@uwr@d6T`Qrp9^d1* zC!7is=bIbPWg>9UaFPK)mr1Zy{GRMtFd zuJzP)3ez+j_K8)0^CNuCl%Q+p2S8P7Sj8LjA($1ko!4`sU5p855+AY{50JdIaQV@a%K;j48%)%F+8D+4o4RgxT$^c z*{wWGT+c@ArSA`pwvL79Zc%)RY*_G7vV0InSrcn+ldb{WB=q6H2M-xF!mETi%x*tq zFS$6AL`11O+2xwzAGlw&{Fj>+fP*henCI-@JacF#A&0VW>nY{T^5URv6~}QqzO$BY zv6T0eFGXA^^2_%nrkKEXEhH#kql=jlDIR1t80$$U#Ng%Pnn)T4`yjk<`9T-oS{7Yj z5AJ@;=G66MB>=rwtlF9M9HDOO&vwj=BcDoU@F$PwuAd~xy$Q!GeKIIINyTR!=8Gql z;OH9QSStpF90dAUVMong`DoWbyQy+s^^e%;vmjrL>?zh;2&g{U>3??i2d-g zBWzM)=Om@stWRPXNW_Q^u}(LAB*-;F*Ey6PfS zm^*UA{cj!X5)6d`DnU@FJuX(!_m5|Mjt{F@3#j_Z@U}4EW}4u>FS@gA(jY!r0CEau zLFD)<`W=L!j95kVgx}&`*t6-pIkZXq~&MgmyAsa(quT|GnkLqRO z$5z?)0EDJM4=0vAxD5#yb9sDuw!`Qrg*))P9UkZ?U>P618p3-UN4R0C*?EhvvR~GJ zF9(?iiL3T2HdU!M-Rqk&d+mMWN%Kk>T?n$kC6lxLK;0UYqWSRHxbT)DWC{)@+}NK1 zoqlr~@fx-P@IY8{ANDsPup5z&U@>pSFTOjkSiU=BI&iJX@g?m^L=4#1Lyv+0SvdkF z+-f`YdiGwZCA?x!gJw4;IZy$KF&5Bseq>g7LccP6r4s+I(@N_1GcRVF*VdrR;V#wF zJ6gpkWc>wEJA%V969R@ZiSUaC?{6jmXqT0L(EEn$WQhoHeb#ejE6TK^asKz5WWMVv z%j4tiPYW8ryu%gnjgZGzE{eu@xBhKz;mXiS+26Zs`3kNUz6#j&D6g~=22S2*&C+-H zOpQlGfkVzrQkl*UT2EvL@mOutei&IR_h3}&hD<c~qw*&QgbHT2jntAad zfKt9V{f2eCMn$-MGENKBYd$9bh8otU{x*05rSeKMJDp0F_L1ZnRVebfAG2ir^B~Nw z$fw0pfQ7*VCuyP46tSOBP|o6F1O&+EM1|q!6ww`dA*= zMv`{_^H=#`e^tjuGG33LNXGkV6E+_x2d2-jVfPeq%Hrmn1CR(}W*q!NR$qDV{A0K0 ziiDV{P_eU?wP7)0AWN=W4pdW}1-g|O#i{n{i}bwS%Ali6M(+ngbV>rQ+aQ||_f$R` zfTeS8;Lj-Lhz*8aW=0%~A4Z`4Areo455p?C;*~d1KX5wV?UU2&n-lI^@A^F{K$H_` zns-9Kp%hhhfF)lVXJfK^NqB3Z`0{zeiwKbDKCD1F!I}u)H;Bz}(U-GkO6rT^=`-p;%`nOCHb+!`^C^ml}*c7~r*?au} zY#}|BO+H^h$q-`w58fXNnedl{81I!oH}GmHv+9ApX61t+-o|)htbTlw@oY(lOx^2U z`Dd@$q)?!Z)-xCc&%o(EFI#@P40W!j_{%ck06)K^Ghh+eK>8hUj^{ZszMh}uh5mQX zS72vaO0ZL6m?ed>c5q=X5!iYMv4pBXUh}2dulC}XmkDzt=h&~D*#!?+5br=X%CWpK zF3f?+pBX@my&uy^k4EyQ8-nt9JM;6QB7U+k422gjUR;{nx+9q#=a0`&GVT%K;LY|m z20(Mmc(K3lX^N_8>t_JcBVVf9jn5F;wEse@MD1l_e~kfj6;I>A8sHS2jQJrf`HRZi z9=so@=`_W7v0-LUaTLBJN*VauH6yk_oFbVXVOdOc6IG?2%xmy3i?VgL3u&6VP4A~e z-kX~!W7z0sqZIpFVeXYKj*~q*Ta;{3w{@D_>fJ>Ome1LXtkXcPMNl?83Ce~QSSFRb)xD|$4jzgI;God2>3kLe6J#bZ`0hpH7iG(8`xDDop}ZiNfatg33YF~*RN?t+tTC?^sIXdrNaF1DYdaUQv=B9>w+_gV|KJ2{FBZR8IxAH6Pu3Ft-hm0P;bH< z&H7u3T8fF0fG-qR?<}$8j~d@mAU_H?dV#rO(Ei;9z?cZjm{`}RIU4%wQHq;+kLl7{ zGXg^p9~kOd?u}PH{o5tj#Kam2G6%}vc=%|9(YPB-@x&P!(LtG~LG1At$R58xvbd{p>j^?f1qk}td#&J`dYgfw2=MvCxT5!L^R@xqIOsC zE86)yvjj=EG%)G)^v))mZ-%}!zVQZN2DDz=12i#D&h8t!=G48T_H>8TX>Dn6Qw@}5 zCJ%vJWFY_KsZFB~ItsqLzvjG7cxH=3p0z4HzpwPr#f(68+FiK(w3R;Up3kE@!`u?? z>-!q2C5V;;iFZ&060Igi(b|pfRKe!o(qg2kh8WCJdwn@EjM&yGLuzj?hHzdTr`5d4 z5%>J@S`C%5#Adnv)V*&ebGXcuik_EXme$i}d;;G{Xo8X@MmHyxU1&{jL9EAKVwF`L z=tdAVwT7eY?dLI#-+oAVi|ZMmA(;)4_qdn3lZqMQqEW3LOB8rB6FS@T{cRU^+IxB3 zW`;j1K@L3LkDTJEVZ`$j-%!YstokN1SF3fM@5F%lEH zFHyQk92j-XI#bL-KNXbD1>FcqiCWmEDPk_} z@pZ_mtMQ>(Z;5+RwL$C9JipiW1M2C2TTMy+fShDp@pN1uwcR`R`<5V|!ZkHs%HPW% zC&|aVMLY+8Ev}`Zn9Z&gEK4IcOan1fXd3LjZ|+JI{2w^9{C#R!XwXoOt}C~BLcfF# zCeMmCn*v$twV9!HvB{#mWDmq{;DvtiKju|+iFkSj z@(hR?;-aJ5z%S=0(e9j>Cok8mGC|T~) zGJ87NkQ=c9-pJ>&8v|=lsR(?HP(8EjnwhZuSa;D)?Q~FwKX;%gJ>3ydR4>$k#bOO8 z8{R*YmwtnkMattT+V@++hF;sTiqQsif$YIom0Nj~L89MOM5T9G5&TxteV$`I*$nGH z^5ZN45w6;j)6R>*A)!Xn^}KsBF9qx3yz`H-Pu#(Nu(x3)`aGx;Xuq~}TA zG{N|GV&OpZzw-w9*$H5%74`y!TJzMQbICpb$JA-ut`!`;R3Q$GJ1~JLmD;t7uKH*03e-@7uLea$nr~NgpGA@_RNT2=;*p z`UX$VJWIyzd>d7wuU`UTo$qJPoLo!5zP>JEEER`N7}IjtVm_JEp%9jQ6GDM`%oYyF zUHV~d_&FH5aX`wipjW6DaS$VTD zj@taJdxzQlj6}KSNXXe6vHL}_TTU$>GVMil|C;VXLK!DtW-SeDv3?=+sB#F!0#nsG zB{9x&D-_a&p+y zL1dU=@G5y?JAOWBwxvqDNwujq|26cy7*}ccA#koiFDEnIBy}r1O#MYEvf*);r3?|W z73aJe0kH8}s;UiB8)C7=sv~G8RY4@0uuQR9Ff18OQQ6QsU{)0fNkSIEkepn>?g9JJ zZebh&FYC)Va!2XqM$ioPjzKQ@aQR?G{5dP10G6k6JhgL33OE5g_JZf;L>vsTmYezK zy(o5x@qx!k^VPCV&O2^Y_T!m?88{N5S$=J&044(ZU_3`PRH=KD5uw>b2Q7_?+2Xw* zEMNV@{}577aJad3iWynrOTINP8alFo|6;gKPVfJ87ArxL+>RtXtNUH@IO%d%sX`j4|R3k zx=c?^nD0`qGqnwUN$a0jB9{YOD2X6!r1oK4zJHnQ$e*de>j5n5-5TP7vgn#G&D3N0 zhJHZN=@stMCEp=R8@jcAz7*;57LJvmRBfT(p}W(?EPIqypw&B1$T>;Plc&ct=5*(m zSVg_$zbgH)dos$Dg-u zD?F$O@;3Xx#p39dmr_u6aOoP;cb?+enRob~NSi^lWX;BYnW?U_Y&)K0?u=avY{$79 zM+n;J#V%Xgd@K_7M%x1A%^yjo5-aKJHws-_^eSlK_*CW{82VmPJ`_8fHOsl=+UV02 z4)8ae4K}-xM&BMHB9djvifbU<-*B*zX4dVg?U~+hT^VUq4G_oj;CIR2fQ;0P2qudl zQTS^WxmrW}-UqmOWC3v?iyhCKq_{z)^@HSXU}~W$O@e)T?l-!^_Z8ge-helK2&fM$ zJr@+XT||hh8J4e(@yx=rr31x3;22%UW)}cpNocKS7HcY@hi42v@tE}DUKsxqhC=>Z zuq=5+2anZ#0l6eha8$9nzMmNckZiRszW5f;@qyr7n6x)2s`TKTwdw5gyxgxM2>Lpa zLP#7gL-7<?w?OG@-f~gqtjs6)11Is7Z@{<5@(6CDVVD$Vn*rF{C*3Y zkyXzq?R1Q6aYF_U=WOI@Z$vB`LIkn@U~@^UC&=?|N8k6yI~Iuxe(8xh*Uzl2+4K98JWLW64j6n%mMvEVXu2xdInIp+*8G1 zck)D{uz(9MY1&v6v)zsR7yih#7N#-o>WqGrYBn^A?zLg^u(AK%0JQ$uWc8tgm_5Up4Bss<0o5C9tj@oDnzeq1~X; zdljCF4PVav= zw3l|Z;6Ec#4X<)_or8mh^a-Pr^l*x?E=t-qb%{56=J~F8_R-vcz@Xn~Z|pnW@|eJ4 z+R#cs3Xxa-vQK$p-&6<5;Fg)ebJSY_MZKBd3qoAK@ctliI^QDnEFE3H?3|wfy$YJY z#IrM5zvU`m!c=Nw-PI)gr=OSJ-Lrov5K1o-R`lq}a7^qI!|}Xyk03oYSDPt0m}qmR zXZ7|{pVXjc>To3PFB--+tDU!!(HaRTa{H~U6N=7Hf!DtS5%&Z#3ulpqFujY$LWw0w zw8&eO%;1%slO~*eN}oJE;%gIAo6^q(Itl0z;tf?9k{$%zM9-aC*x_pQKD8{O@$UpM zv0a$ih6&^cIpvGJK@p#Ws4RX1)54C|SQIf4fU>?Mv@D^?2Hb)WY+j7N&E#ur$XtPI zEV+=ha2xayBSZeNNmcF4>1}k5vRtlA#!TEixuB0Qlvk<>&}7MA`=~!o()H;V)k^O< zq^;z|NfQ$1w%hV;ovwGttV12v%);03N7T{u^dJ2!4$C1762bRg-g)-kRJxRCjjzzC zCXu!@%;8CN*-oa;Y-4GwEg|M11U3&q4{AlMqrf5edfcy9f-t4EFhdC-_lD8&(!}$# zt-7RnUYQX(p@7nfPSCSnOP>~i*W(ZBM!Pf$X>nU%R)Ry*{$et^DCx1pPjYxb2kzy^4tfwFPRH=wCj%y@MCEJ=)F4M+Hc&pFD!jK{4O-`eQC*rx~H*SLNzK8&dyR&*zSQqal?r((e+$*)Ke9t^%xF@w^LN^w!IAj8A3020;YGO5sb!7=kOFmfbjNgR>gFpGfyC~*UtnH_zC z%^g7=lV+;vT0%kiDm^-!3EMWxwf>sb608DThB+9~c%@-~@u!94&hLVK)Ub&S;;g(i zO>@P+@1P>qg;Ue*Q=1V`ip&2JR>_&K5eb@SRewnZfYQ07xTd}kvpy?Lb z$m0>LQL<7MM9OB+!GPF@4(MGtHRRadEd(02w*+mC&oED0P_}D>B~JfMX)FY(2bo1r ziq}`y|A3n!_Ev$sP3FQF_)gKKuH47S>i$^j>hy`7g?b{W6ULc-I>G}RIkbApeJpz5o(-zqgcT6o!=v!v%9u>K!x zS_w8(y_n9z`xm-c8d~%c`-5v^yc)A-AVbZwKfkS%@$hVg?@K=qyrVC$uqp?S*a$ts z==H{Q!E~)ya08X{^3$tjth59Q-;H}W&4+8j!q6iLc|V|{mX396bD01pAK(g13D@E z$7MUjWcFh$FTCuYp{AM9t^91yqi@jj5@e|XY`^7M{;MD}K(Tb>)G_MZhVBKEo6bOS8n z4rl@yYh}o;-2h+C6@1Vq)fFW-9cd)*S@3=sx}T4Xt;hWB*HUYA*;KA$s}msS%4l#h(zZv?hB7@(TyE0cVUo1OyMjwUn!)IKl%KQYJbgyM*M`0(;M+(BqPr_rRUWem9;*;9{nQ0zY5E+<-XhZ_Q z-@tQY&fZCFHf6Sk|#`fF>bgADHXsuo`1|XsX=BjLy28z4o|so(AxB^Or&Cwi+{b`>jV}f)IZ~Y%}2NZP%8G`FM7ir zCp$yegh{^9b{t6Q>&ko!kbcw;{~dsYnh$iFUv9@rc6`cZqk3SMkS*DEH2^Vi)}jB+1i>ix(M87M$a=qDZ3Ru@nd zK|G**$fum7^Lf-?3Yo%4gCd{u1v7(6Lg{@ywF8k*C-TQDAIG7*mhi(NjZc97=aa0F zyv{wtq=~FvFMqD^oGyG~Y@e@uk?TZ-7H@R`k2?LNQFl>Z9d9aZUN3*g>kPMvL*|Xe zcxW8S^g!q&JoqoL?|{4(K}KcW(VMsn-7$m260@GaA1vcfWQ9{U*hGXb2i}YiKz*$?MN~EH>y6rpqG$l+ zoFg6B!#)5;eAXd2CitZrH;%-MV+a-Iq4QcBdJjItlI&kFU#9vZ&o~TQeVjnaA+gTs1&IV zw`ukXgw*NwWTh+Jomcx7&;|cuhDzh)Dpk)0?yUMj3XN9g=!UNlRy`RopcbsT7_hJZ zU{gE`MG}3Wdlfw*;EJYlb$aBjJ{@w*Dv=X4=zgOCI>y>`_HSpi@sk7 zB;EnzQE4B)5-{{8JEXqQBt6cDpB$5>ha$Ss@er0Ek9#gm&!0kR3p)93lEEQBuHE_N zi{CS`j3Hycc0nCT!4yTftE~d~uXrBNDVWzI{+e5t2H<>i1ErksSFQ%aXBDL-2Y0R= z^1T<2UYJqFb>}{g@_h`_wB9#kWh8T4b#Ge~5OndP=n?BNnvmdPd6VXI(gvzM2uay__=-{T{SS-F|U(8Vo7^nLH= z{VIBFU!i%2qv;i|m*e@=G1>S$j&{IctP_TX&wSwkK*eWIhRf%+#7Q|3c7H4U*?%wu zV2iZMIArpt?Fow}`0(FnG=S|RvhXmYDss-B{$56{E}RSvo0jwi=t9uguo*^7M9Sg5 z+zeV1D@@)!z)n0D0GA1r&00&1E@;Kmd8gRX>@5*)@1trZ%k_3F0^V3#k^rEz)KigH zJtG4H33Sx$H~gdFhx%Nv6VwET@*EQH*k-N%`-~CrXH>e9q_TH4BERr2Uzf(kGUAuW zUjUmaA%821Yyv|2Tjl%E!n;Pk7SDeW1n{J>v*>SS^WV<&lC`%TAN2#;xXsE`WiYP0 zle~1lsn`&D1AyHbwB>3m#(*6B^)WW}b*Z;0b3dB@aGjIJ@jmK*iiKbW*Ps+@c)&8P z1X(Tl+Ym|3ofu=m*c{s^7$4t~2pSYIEk@3igQxy*Ov?6xqpKTo7A<}D;%88FE{RkH zvo&n`xSA_3W>3595Ec7mzK15`Wzc)y-N-C)SHF3js59l8QL;OUin6q#k-iO-;JJCzr)Xk{Tq?SWfZ>Yv zmQYKkOsh_2c+^|feaN;g{1@;(p76XL@Y`hKrgHzI03S2;hU^$n-n?Zof&t!nO(PL_ zvra@``B##BDxDd|LsqOj=b3N35FYKUWCDBd_Xf87WikW8KL(+xxR4UJmE*hnn6xS6jC~N^y$674m@gfPjYEZoy>;m$huGrDVz3 zv19S1#*E(AY}5|WE-6go1NmB#6H-;;>%~jEWMo#yAfIvw1NH3@rv=5HhcD zJLR{Y=fwJwu!Q28d{T4|Q*&$sxx@C1M8uXwd@$Dwr^U-{38|uBbl`k&XHd|D8rl41 zLMCUM441i5^Tat8B^(eIe$us7Tz<;Cuatx&Gz8jEle=tXMNb!dTR9%{UBDDAk}`Gi z&r*I@q!)VgWR6*=VdL@;`p3mGs++%`C=x8mMkAEikidMNam6Yh)3N+m=*}Iglqxd- ziYx}lJ6M~K7+#z{qLk~Z}PVd z-{pm_4xyieOcayC4^0zmW{vQjUWOR~`xr)0R&X5zq|ZRb!5XI~>>!5gj4!YV@2xEL zBA75;#S-iDYWYLHuZ2JYkh8Kpp1+KHH~1|!%;A3gj9)Dx$h6n`Lml2r|GFs>AO{7c z(Eu*R9E5yj#O8EUH@FQ+5?_nsV<60!fN_(aeY~9(k8+1s1#Bx#9DHbS-f7RB0{zwu ziw81q#ZIAsehN-MJWlGw4<<3^3Dzjkk&;~s`9N72$ycfMYPCtku#3)q9tK&vI(a zDgiG(i#*6E6+YL;JsKm2yUfMK%=br0h3}zFFM$IJ`gO^pDj%-|jQdd>pb*Q_s9q=7 zvphtr%=e_4Hhxs`(-2;l`pZUerCfKs`6XB ztp;64G)!f-AyHD)q#6QJ0O!P>lVraPWEmptjAK$>ffTdQ@9~Cqk5HTGX@h@l34ki! zFWRFY&NqAofutbEsP8{dcXI>;VdtrR>uQsSe}pi`f4Fl&?64ANUz7%RO}JGepP--yrm3%* zKa~F7y^M9SlKVvStK&c51bN|!(kaZpGCM_IpgZJ#RInSGoxbE&hg=0R)E$CYefsal z=(fF;wbsD^hTD{Lz(5Jg^#QZa5~@C z-sJPE4=GO{u@a2Xn3N$Px#ubovHg5UYjgT}YRgZhQ3InA5jQ9;lmtX$s*?n%5K zFcdb19hGR7_49jWyU#_Tlw03>`_GE05{X|(>+&d2PJa%qEZA3a5N;>3B5;)eInTbc zOX1~MZBvF1BwyU*gg2zZlx^_)`;Mf3>pRc&***SO6vBW8q)9@L%oB@~ryp{I6ybmx zJ>p+=Nen8ivk3i5R_+95X$HcvMvY%?iPbB~$9+tr1@*U?Fq*Twoj}5|M zjTKBH%9$Z>$JS7fK)Bh`3;z4|r@%zA9A&plI=5=)!L%O zennSQ%^cz7s@FGkWtAUkr(jd@L96?x>jD!7kn1b+b~HQxwXtS>J~6vRJlr6L$G`mq z{hE(gt?${%tbt1LAg-?u2shaQsynS}{$tlk=#X7`!AGDVn@S6k1vtZmNSVJS z+4Fg|%J?Wc^Ro+bBl={o8L*|MFwW}_U>9^+E2nl=vU2rc(<-gr4G1;3A7Kg!rWErg z;)of|$D3c^geVU|txkV#X7`8=#*=mYz%;`NoXC8dDrB~K0t+VCsU7y!4#P)LYAk6# z(=DIRwFQHvei~${DUqSd&2v7KW}Q9MeO|V<(uO3xfPu@Vog=x#7b?Q`Qf#H|7&mXm4DCq5>>Ccgmj5C=^A98v9B~c{rq2V_@Zq;ui?p-1oIivLdvusc4F@;>0>LIVX~g2_-HF1-{OA)%#s-L)~#{ow78`>7)cDFm8RkSvW=`?;zo; zk$%yw809U#@dxf#ZN?`cN;da4b_@3266o{Mf*5DG{ zDZMc@Lc6qB8~@G}LLHJTrBz5I2MgUoh7S!HDkP}^smj>Io!Y&nO3fg|=MuCYQ9{4!3TvmEH4;`uR-nz7{tbj^HHy|K@9M&}Vq= z|NNv*ui@M-jPh=8*`~H!inA>kX5d= zry*U`_J14b%aQ*Uk%yujXLp&t?`{;D3ucG<0ZN=YL8_^7J8jm#RK3HDUMzC)V|yGy zZ2hUs8bTc8K2SmTk-@g!p*56Et+vuBXwDxSXg$9A>dTYsF8ff$W-=Dx9&S0;{4glu z)Eplkp7>mwLZ8>;4i_KpPPZDHwoa^g&{C!+JKDy(v$ab78`d*s@V@U^=5`h(`<9%n zyoZigWp7BCcFfW~dkO>l!nBT-a0(JjGe8d$vqKLzEb=AQxC z7q{!^%`#Gaqg25f4G_Z!Nh}gw|#>6!W9s zl|X#CbWz!zM^e0XncCXW-KC$ZCB>&&&$lM_WrT+3hu__wqMt#pZ{5&}=PeG_Sm+9R zD47iZB6aD*U}mJX1;yH-laAl9MM)sopu{_BHV5&wMa!o#y~Ds=?S|~@5n2U#R@Sp? zWxushlRs9rD43ZKPE$%Vs$h7fttZIe|1zZbW_xaQ7}+O7qv-9k0Qbn@yuR4#)UW2a zn1SD@pRH`tNZKS##rILE!`QLsF;al-ybt(~2~r_A+rKPckntr#1$L)Qgn{jU8>_O)d4EdtU27z-v3?evpo=aBYOrhykhm-^#0 zjhF{^tyf1_uElRd7i+O9f`y61c>oV@IT=N8GsPv6{b#GwUReT9g0R+VuMj?36{BbW zm7eSowHw+=^ENX~mSJViaY@@4WcCmfbP`ukC%FM~<2I+)DShj`of-&n@}dNwvModS zW(58%Mt?DqmalY6k9M9<_=q~BvDxCBLn1)|YufT-<@P!N@!H`;QM0AaMV9VQq3jP^ zN&{f-QFY#8u}Mlh)a-qHOfuuF=cSq=i@0Zk)0M%U(@c`G2!Z`TCqc3!Bu~sFK})qc zq*?SW62UlummYfNY1P8n&I{};iInh~YV&xV??I;l)p&G}uz#gq)~ThI=IqWkBvv~G zkIuKK@ugNV=2|RB*Z?z@pb824N^te|WbF$xm;I^@R3u4eNtwRcZ<1oSjB#8KX`#q1erVSM8FP73v1V`K|U z1acN5cxp_Dyoo-aoOf?#BN-NdtquJ%4Q+WSbv;W$rPXx>o&{x3<7XowvabE))!&lw zxg!5CzV+SwC~KLxTwkfctseoUgHJM;U%-y-r_Em2M>OrIzQhV$gA(-a z7n5jj7cR~G5zN({-bUpHt=EJ+qoDhWmLFMcOMh1E2(F33u?kT(bp_P0G%%|gj$M?0 z%sk10~U)Vr~!UFzzOP*6PCU zB}SB08f9}LY||N3@U()QeB=au)xk2UfNhuBke1E7l(VOd8MtEd2H>e`DOqFGBT+s| z%+=l_K2A|Ed}p!Fl=rODhtKQ#QVxKPW}(8eYeOY%Dl5h3HMHr(y#efYH)vf6(v2S+ z(;X#4M(9;QC-F7b*`-_uszh<`b@2cAy2`kyzo)x22q+zbGy($B-BL<-mvpCuNGx5_ z-7Os=-Q7qxNT(njN zIzS6JmcD8*$0ZgO!zvH#BSMX#JIxHQ3eo_;GRJxymk!Y21pz!5p|=F_wCeEnjrjlNGzV|id3@D59iG8c@AqlDGT!1UIn!~ zgR&J_K8T84H^7_KyU>oaFY9}0S>qbU;vc|!`l-l(0KV9Yp+z9zzcfJx@>MEu4(9e~ zlNZGP%~}{vUKfw2+Y|X%a#Hv(7~7x*s-IWU6f-<% zVa~G9Vsks>GEQykzSsT~VDVZi+jv$5^&%R^^s#l2C-U=pE#P;K1)H^^2SwBFlaW zEH@b>|0kTQf2ia3vB1$!NaPxtF)^_WN5NP*IWzFtIAxuk0IZNyVlw(N;yp%%Wzeg7 z0zv!Rg|Y8f?$D$~D1z?n&-YILN}Xy8=dc62M9;T2|9)-y3oUtfJp%OOT=-o{jG+^S zrNkkkEc204$76W`NI=!^F2%{j{>5E|MY888icLJs+yX7GVvsd)`vzOD{8_t(p~}EA zOnb=taa~UtJ5>kj9(ku}^bAK>2yN7A@QN%f#kucP{?)l!h{(pYyN}Rlo$`lejavmi z=%C3l#6+m}XyIj@^;()Eb~YJETt?>Pq9IBZqo+s5J#Nmd0mF2em$uy7OpRkhPwdKh z0Ih}P_I~V^tSSDi^5nv2I?@sHz?j2lUka-wOB8!yriKbhtTc+;jZq~hZ@f0%&BCW) z5oLK#N`(bz*{{5jgR*YBkU)kmQ%J5SqC-RXp!iS|Zo=$t4*L!q$VhK8)ku`HtFQG^LE)1VgQ?%yHoqQUz5f_jw|-QKg= zj_jem4Nh>TEa6nma~N7vmSgS|EgAL_t!wxPX5Ajwdto>{=56rHt*F^Zrbzf-Oegx^ z)4DHCh*0lA&XKRM(XN7Mktl&p7gDTn4hS?%uYjH-`0k4XTsuF;Un22{U5;I`3VhvH z^@4pA@=QzS7x4pZNXMh9T#a;sVX~1?ITck~q1V-8HyKk)SnyC=Es+6D|eg2Sa zMTY)Y)VyJZWoArhvZk6hR~WBLE5v8z7m~zRzsz7KDXP%V_5932$790fgbTapGk1xofq3Y)$H_!a871(?NB9q4{Se#~zy3U)1J=hPPZ0eOTgY$& z#@k<-UDHJd{pYio*TH=$MN&m9gXhL^!Mn3OZT8 z7C*`#wrhBL7jpvaQqt^ps4vu_hW9+wlr#}X(k7qvI1{HJ+O}bgslXsJ^LM_xze4wn zDMmqAKp=$)8<@+Vb1Bl{q|MWRm@u9IJ&Z@zEvp;My1|KEc%)!3u!+6^RHJ6GGvo1Ben(DEy+P$scu3p0h1>fSBogv+e)1e)}uV&JW9VARv zNnj*~_I(1E-5+HMIKXlJ70k%4@s$(q+wWQ*VsbhUKAf=FKuT%t6W7&Cvt%(>zRzsk z8@0l)#!%a!cd_F1exkm8ZI!%-YU$0Z%S)C+LUs`{rq}zu2yDj=NX77EK=us8nM=A% zHx2W$_yNaP?sg#3;rNe(QscygB9EB(+db__c_lVCSNRr zCN4DqzB-W>YD(+`Z(fyhE)!|}sdRfGDhSOV0b`9o{t#e=2L5Z0_TV2q`YxqMm)sZu z8SDQJ>Yv%6FaluKZO*90Cx|>q_@wvaPW%7%0+p;f);}$O>3DXK?#IFjO=1}#2q&0| zesie4`=2q19!EAg-UpL|5)&~0nAhEIumKzGEFCkXCtrKG8I!&?0I6XCU;r?|yrE8) z#^kmyF!Ih%pXKx^>wKL`@5ACQ@#{PLod}xR{K~Xq*uuB}I`TGm>@!z|omCO0Ur2H( zn#)4ZwWhfY^bmC5Ly%picOLCMpmd4@Jr=Z*CWt5MnjnYpKg2S?t{v?5hz`{tFlIBp z*HBG>bRYxo>HMG9Qcsi)71<;F!Kq4?;JavbU$00F6nx&2U$bBe8VR@U8y=8nUF0_T z5?SVO)_1h}D`Dy+o1i!1$XCgl;!7j6yo$~B*bhGTk|KAQGlbq4zsG>D&RML^4_mA3 zv4d?c`rlP_IO@mFVCT;iqke*}u(KgQp}?Y@o29W}ru5{YUgbR_4xBSA8qUY}KVA@y zAjGQ@6jA1Y4uSYQ&Y+fD-j%Hp(-=>3<3fUT7!d9Ux1W7F7{^8z^AmK4$6|#71XhR$ zauZ4jj5@^^?8e?3A`J+BQQ8IL|6akZR)9YxZ*k|Z??DKEC=joeBA|y@{l1>&V*Zj< z5g|d;+=#hQQ0y`{ZOV#n!G`y9@Mj@E5RW7ljE>&%3U_zLOKH*cwium$J(l2~9 z5_UaV-CsbAJIJf6gWmlMnBquH`KSCtH z*t=_%jty}xbeF5$uRSENDzwFiZTzWj<9=vf>u=#R(eI$g5!X=JPzPuJb_WmXV=pO| z7vS0tv=Lx39K|6sXF*sn(jW>|PFf(EYasL4$RB=9;meonKEa#NLuh~xA+W7!u2O`) z8#L@v)t{~-3b#Hy34RpFp@Qm~*Sr)$TfB!>=+&&E2MjRxPpObxwkLu7_#P3yvVpaG zE=KujT-3@O(@1Gq6Rw=U_!y|s&M8u=F7+YXoF^&tAz9STswc1a&+12u$bR2lyF-Pq zS^uF;1IV*ji0x3`j?DZ`&DO9qT{&(*DzQHB_$;z$x+N!@RN!ipG2LfoI$cY2Zt;em z)cDI;ELm@vEB5b>KF7;3j(j6qEO+uL?_PTyA_89{qBIYHC!lpZVI5AE6WWvAV%iLo zHXkfQxhssuuA~&3?LkSEhh}8W;AradP2G0MimIf8M`dK_ySHQveQG~gRjxm}<|Di1 zG`b3MeceHNKA==aN>mDxBHtP@NjYri9(2J4`L7`qExY@NCrJX)u$|=66b&tZa36wd zM|<`t-=2#PYZU%MRdrS!Gsln5xA-L(Q&mka&w`S>1f_%R!LZ_%pqtH%qIsnGTI1n} z;jKsC_wo0l;MDYm?lSF#0h|JV>rQw1!%Fp~>&O>qdnGI}+I15}a?tYuZf+s2}IgzSu4@$K*0QY@P+*zErc zAS_^yMKZx?v+rgQ%;daGLOFG6Ou9jlxdLV_h+C@QpLOJH`WOy`NUDEmmp~<7h1lt? zzFnD{#Pm*rq7+&hPo7-c5o})(RoAQX&?R5#erdP>P=U3>a_^kQ8R?(A32vI;_3~J< z;*u+~II4Mdj}Yg4?El0cfshcQLO7O>j|_*^UZyfJUF6QMnv@Bt^SWb5S+|nCBqx+* z(EZDLj(8OHuhSUHS{P{EU8V;R42R)o;B-`ZG+h7TIaWUYyQGXRgHz6mGlagX&nOs? zU_bFff*>d3thcZhQCNWVrUIwoM0=`83E-^=Rew){AieRKS?XSo;y5ej`sj#7qiO>+ zE*^+_1opQRNx9vJ)QKEd|D`AfeUfNz7w94E2W%~)!xa<1<^tfl5&2zamJ5Y?WjxN> zJzmqb3>S@pGWE^O75;Yf97SKQ=Regyl%H574S!T$K=J&BP~tkBha9msqw@i@q7>u=D>!+%Ut=@r0R!tv7561=x9 z!<`f%^#qZNk3(Lp!Z1sqF!Hk0YYv2RL8b|c900H97WQs^Vi)!s3$ZT-bz0M~5`7<@ z;}sv2fn4qCA()N~rI+^o<%%}%)PjI=BdK44eBR6hMnpo+RnG&6I!{K=hQ-E6d(k|c zidA%=R@E1{S}QTgpT-Ppz9Z<3>g0aNj?n}*1YRtRE09z}~9A)%;TN_W)1_%8IMDcwSgG%C=b zEC)gZu`yWS>7ExAA`RIe=567mRuzq7Lueo%V3)Xl)Qhi}J?wdt?X^<`BBq_*i`>cc zEY_VL2qjy#9RT>TafQxM*tx6EcNy|-N%(z0O0mNS`m|#);mHHq94RemGQ$tPAFo?C zuKxV1dp(}^0skP}tTNdhYjDjY3n{|ft(bwh^xI2YPo5a~@m-k}x2N7j9?n+{h3n); zMd?02cZ$mnoelCl*cs9Q>5_Vg_K4|-WI&!cqxWvE2OCKN=mtsFdWf)ojprKTujexC zcR#r=Ik75c~H?Eq% ztpK=4Md)jdjkA?0)%nEq0=4vDq+-Jy|94&^DhaT}Q`nW`W)txk<~EUf<|Qu7$r6cs zcF!Eyh6d5lndaI*F%^dp1J{3PWJ*x9$PM;6~6sVf_^(l6YVN9ynmEchW zx;znmt9cr#hR^j$R{rd5xsr5qP}~f>aZ@=!wG#Kp%~8bMTAa!v!e-(}*xVk;5XR=EKSFL+U*$Ou$H{APs_6!nd4(5OpeC~# zYEp#>m*&U9^-hug%%TtBX${)c*;?zc3YHQ^$5sy`N#}tZt}jdsZxW|7uaJ_I95X?^ zcuf6osB8OIG!{7{(4_groH~TD4ZXvA0}hA3nbMqCfwX2Jv$Y)&k0cb?`z3XXPp&_h zhM)h9%gY%Z^!RiH0})tTYMNpHp%JOwyJ5htB-f35+1>dT`Y76+Pg;bpq|CZah-zEE(H?oL_ z2Wo78OtFFBM^Wj-5pCRIsn6*%9Ifm(m+0|TENKh;JzgZb-~a1Jpi}!s(Ret7_HRb~ z6FsEu3izOdPnVkR!vmxGLS?3rMdu1OuMPJ1u4;JHzBbBA1PKMu8=D^6i&TVdE1~`1 z?&7C#!Nc}_Q9$Iq8Sd4j-bKkAXt5cz;VBq`SqF73W?yD|`Q>hIOocwq+(* ziNW+*&mZK?=~SsooUh`D>N}RPVP#4=Z-*-6$}jR|k>2RAO67<`3&jAixAINm?jfVb z-hTgf_n!JSd#-xsD2SXaBt{ihuz-UJ`1NP1$|MoUwnz;KT3f_>n#JjQM=V)P^V{zv zHn|gZU+|Qe`xC>^gV#)F*_Y8Tz>rD+d|{OJ_yzqI=VZdrGlm5f?z9>PqvH1{X1=k~ z2bc)237`gY3o($fX3LpytXaiA$}+$YHw$@LZSi67A)=;Fp8Xghs_*(od!ABkVlM9R z<)8)1|In86>e%=iAU*72wKmwG?a!BDI59X|)>zh{;18iZ!vy8|dVA?GO=q&5N-JUY zVMg2qQSNy5b*iUohjAJL358uvF8WsQ@0NA z)(vDWoA2JRia*?z{?g7X-k6;O%;HX=3N!-b%?M%tTq_J;IJjV_Xa`3fR-^^@b?bK< zT3FASwUdLS!b`ix%_LhWW4zYx;0y#Qf^@ewjk)LK!{UrrUa?6uK&LJ+9KkWZVInNW zJgF4h?&0}$OWO;zU6X55Fd>&w9~Mc=O)Vt0hosr{GyH=RCwbtLu$47a;f%5HjQcx4 z3Xmzn%-#nxs`Ir22Gz;HxW#6!r2_1An<8S3Foo;cN4gwxM5%5qy0%EHz2!JciM=+__+RNrXHrBKFac%2jgSGQo4aU19zxX5MT3&>6T?7q2JG+=}1MEAiWRds1{u_c)KBvgq zSvU|xzxru6^NWE{VB+(|rdco_r}#+!$UyjpRHaCNo+aADmrb3+ltO7-O;$~ics|*= zvSj>gDV>i`M{ty7dA%c`|N2Q0h^6e4>agx}9AxoMzczWrZI@lu?`sA6DbMETUSV^3b8~_*rJJpog@ozXgXe9kxpp-t`@ziuzm;HM;AkMb}Z9Lwpb&huoDTz zTsUAWb+P>XH~g4)8_v&s{W3Ft2@%`07IFs1(-zK`ER?HioiPEXHoJ-u9m?ELOd({w zwG!j1=SAjyL__gMYQUNnCgMwuv!cm*0eQ?@|3E_FhtvTUz)1zU%0Og1E{*4q|25Be z2T}&RMm>*e^1Y1_2z)+z&DDM|bx+w>{xiWZ!u-c`bjpRChYQSd_e=-^)+8U-*G?`* znW%_O7%^FV`@l_V0L>qwzQ`>ZuT*1MHd(&6#QfrmhjA>c8>Fc2Uuqc_iADNY>C3f| zUA($okZi!DtkLKs@rg$AnRF^nr&^|DPy5mL7o_kE7U+xy#}8VA>qU6IHR&2JR+i}-LHtwQSWow5mT0u@nCN#lDo8t^fj3sg2lRQlz%a!*)r1?2QiIfSPSz75sqeP<}RR03REH@ z2HY3W7dLEeJ?R=Fe=1AQLXeMdUcHG3xeL3pOiuM`4*aNls$QY=i z1cn~Gt&?yIKM&<1SF?Jg)~j{D^$g?;_QqZUO+nijDM)E&-%;-SXHP49YZ&Pp{GF9n z5PxgQ{ed#UB)fALqz42ZuayFu2dM{H=IO7S%rmpCSyp=d{E2U@1K>n|jwQ+|Ygdoo zjDG1s7xTk0qVCr3!=1ze#?6JKtJv7}Jhu}iLm_PD6(cidU7C|!X`hwY;K9?7puefQr=o`j&k;Y}G z&o)r{RPfCthl4G&K|STSl*{3YzLg1b@f<8zRH*Tj`B$9b)xHLHKZgXrV8S7QkY={y zqneygEV#I}6HR9Wcl2;*A@=gSPxLEt*?1ocaDR;#acnX@OEaSCO`Se*aT(QZwDIcG zdWF?SDuOun2=PT90B4A+OpIehb8E34nv#xw^@n|J7(!5MBzFYwOMPpTg!Zl5zuslv z%w@+AWzigeQ}^V1BE@3JIy_uIAmLMLQ2y?1fWdMF zE)dYRuy(`j*KiZZ@NV#*sD3K*o>6BYf`D>`rbmN#p8X)0g?g;%WPwA-?fXI5U*Y~s z%`ZEc>D0<1y25SX55eJdl>5S_MyQLdd$j7=zQE~}dD96dbl$-uno!TGkiW;EyJy>B z@{Js+w~uG6y)gH%y>LM@=B+i-@r$-W_qAHa9eq8R4C=CeqB_U9?hQQcqYFYT^J!by zQz)(w19_|&gNv?5#guGE>q25UjPswxRY{1yCFSN>cP$U8;f_W)>i!sH5B_>=np1$d z`uS%p?`#Jg5-m~WToQ945Sp8v!EFS`%KOycIYqT5c->1GojfTSUB!tCz_{Poc#gvf+vI| zqqou@#gw;(UjJ7CBHIFg!G)voFzeix3N$+Pr+f+Z9FxmGydht3s4E*F@qR#2X<%XJ z*(B0(E)(z!@|v%&?gh|$PbH8pq9R2PN2lGyo}=q#R_PI+zb63HRI%E^VUTquT8?$i z2y@ePU@=#d@mr2M8=gkKeV8=lnkfU4$%9lS!5bOkz|JMeNwC`8Ub2MGb;UHw$?S7f@8eFYD1*4TRc{)>g|H8;wsnH?)B#742*KaS0D8;# z?AHkX?S=-?I_Rt3)8crQQw(~u6^5jk97+OYCMF#@>%WqY1%kMn#%&w_6WA0U0=xU% z4?B1_&c5+?6u{B944Cr-&b)V!W@95<2bHrcS+suAQv}#oRhBPR2)3YCq5h0(C260F3lpp6>DFCrqgYjNnUf%#Ri$b#eGUrG;Ml!G9fd4E zrWcQ;Cp3M#GJh|~p6q*(*7yD)#HVctbvRGOI%+b(^~bPtVqirE;BxQ97)iJ6KzmNK*&X4Wc^uM>WEXea6$K`!oGaZ`>lFy;SML=a8>KT z>D7raE>U|6I!^6=o~nrpwOsMBI_X?u;@zA0rcZNxhx(eg^gwcGF0BeS4-(9Rc{8P{ zqOeoS_O`1g%UDOb6^K5!!u8jxdT!s>Om{oRim#Qo=KYwV7VX)Qg@9GFxDlcn-YZ{Y z#adP*Fi|&gN|nQ(6Fov0LXWme`mdv@C-D;&i3GR8`t+S9;pps}`{`ZcAg8`w1=|A! zP$~@(FjxiO1jhN-CJ!5-3SQo0ml>PMe3*&bbR}?U(q)xt$VnZ0*Hgug}Qt3hPqs=z}06^tkQ{2(i$Au&KwU;lrycv0l-OrtL!jJdalp$yI^- z5|J*;(!(nUNu_iGHkCC@?RMzbFbJn7EtxRC4BjH*4jHz4&6}ItJ9f~q>g~C`5cvRq zO3?mLeijPa^+H#!DC@(HlKffx1diI-;=!gmcOSOdp{5LEp`d}_M`)@8@mDm{O*OG8 z*mj{MH1P&iBiol`h0b6W(}^$H?c*CPk9UBWtgy|bi$qsg@DE9UjWTn6vs*uHN1L{$y$dt$2;Dnc6m?mrU1n{hh z6LmpjFC#eij`l6=ls3Y(Z7zS{Wx?>_e1H8f1|rZX`_C-Kn~g|l?9|pN7jMf?p*ZGg z9~`hURP5PwlUTEzc7}|N_{sB9*7#W-*fJ$FfinNWd?#JNL-FZFvP_p2pHYJ{M)6_( z{tJeikZ^svhRI^GO5yAR$nxLEX1GEKI#m-s&X59C>2ilggDv_oEu~t4;Nr`!X7?2L zJ;xUYN1PV9k6(#*b-d3IUsao0afWRGZof3#*CLIJ%Qko(Ejwc9KBq7uEf&eVw_r1E zAq-9T9fP^ez4AON9&Pg@|B?S8=>#`N=0NZ5vspvrsOVMXD~;X>sEL?>zev^?3fb3B zb$mdH7BqF1qXX(M5@v7XGRw;Iu!`PZgEbOnm)k-lOHUPnyc4*L-lEI3&%w`X-enm3X+#8)t^CQ^mF!n?;RkK^J=nNx%w z7A`=YrkVIz4SA4!Nvp>BE_YgR~XJ;LX%z{mp~8;vfLQY|JH#o`EykpuaErpQ;3j>OkpBoBY^-u?!E7h7@G| zxmCiMIsy`wl`IROgd%L=sLO9NL>i^*t3R%rqri?LxHjjwXcWs6VIYkJrZ+xx*=$GB zV<{0J;9wNVM3*W#rtz&~y7TmQTLyXPyZagoRUno~9wg?%v ztDs-U2_LifT(HA8?m$u&5%3vSkuJQqINpv-Get5Rtny}8FQJIrf+g}O*(tM`U{%82@it_VPji~SPp3}%dhJ}Y1{Pm zq3T2{w&3P3LnR*Vq4M2M%7ww^0*O+I9sQ;=$Qh1FKipd2J&_uWE^**Sn1VXUD zvO;ocvvz_H_>kY<)W;Vo`sPXOMLK>RPB6+HVH zg%Q1m_#g89Qc~ngZTgU=ClJpA%LYEi=yJWwSYm+8Gfnz6c*|bRWp;%kNLxv8f1~`Z zgOf(uXeJs>CN2Jv!ENKy7tuk{s-%|c*XOVweQ%Z3;BbehWpRZbMSJ?3oM}wYofpBGe*z1+mHJh&sVbMPg&vq)whxMlOrwffuJjg`}Hum!BSYCm< zSHWAEZz0T6OE9JB`>Jk=Smn|SlY}{|^HuAOG%ODP z6Zq}H>?RW&3+70gXRmNd}O$0`xgLShuG@b1Ox%I?sIF6+M-0ge7gbR+gZ ze~Q>zF)rdGefyQ55+mvs8q%oCpi>s*XATQ#t@hNg!HG^0}@Hh4UFc3 z(*T-I(z9@oO_ivCffQOyJ$gC^4QH<4a7H>wOORVvcOTUF<=5{k z1%_ymf;gxbr=nIcl42GH7FklK!2z&StxK?>v{SP~XEg+!vyXSQCJKc>Cg;H2r9uD9+!hP&|tXTr&3Rs$7N zX&q=|9uX3~Bf2^$DK!9J>g`f{1*$pI$4P)!A#Sj)s;kd@qcrHbM+HQ{k+r{LFsx9l zCt8jfKOP7DuC}q~{1OHEJ^Pn}6y>NFR+K>Rm@kVNu#WjaABk)}e;>5^Pp2Qh{a~-D zDDj;#!ge#gd-62CTwoK&;K})D_D7Zw#a|Wviq$^F^;Ol2Y|&+cD$wGR`wJAeR|E_N z#F_D5mt}SFby|^tVX484T3;ulc^w1L<^lIciaR(bGLA&)--Rr*weQvhr>KW(?}Nkp zSu0k?LdJX{Fbo#_x7vT!D`Qz#V!yvvatXIYy6Am3u&v|@`u`crYF|MxqXPspzDkPx zFh-nF$N>MgFK?c1px>CRv zZ+3S+6jMkBJP`MxE!}$A<+C?@_%u>j+0~?jpud+ZfRz}qAJD%ZB}|Q?v;=b@8T}<{ z`n-b}#6l~!mov!;C5;Ne3CHbdFx8mQBHPzV2WjdvQZCQ0@X9jkTSwli2|Hn29_Mk-{+^AvFT*-zmw+I+5(!bEGM zB?gPzPw`6^hR-G`qLEZmi9(&LPcI3U7yOc?Btp8nsc1VNDigrjq|CDT@Rt)3o0YmvBgmt_U2tmKKDsWwgtwRN7qLZLD^uOz_xc@T?;Hu^2xw@(+}4NV}g;)=OX+n=DlO zbvbU3rI*J|4NiK0Ze9t$NB~?iYJao|G<~sXHjiG?x@|?ZhW$HXoxx%^D5q{ST0rdb zzsukUe-d#xC|WUTTP#W3lm*+MC;|NZEDYQg9ZBIsJ# zf3vFvvz`?V1J{BXCmm%qn-tet(NlVg{`XV4uLMiwH36{1JDWr>vnaA(D0z0N-+v_H zQ$bOa=`RxSNMwr;Yis}apV0Fz_;tb`wu}gPq{VH}Yl*+xeQh0#FF^JQ(zJ{{zmguy+${WkxG6FedUl4A!Zp-(3+<5|eS}n%UD}!d0DTVq^l#4d zXx~XSSye~`L+*k@)5wE&{L<4Y1B+jFKzsM}Qa2Y`wBr6ktyWMMuiWVc{92om>&Z7J z9Fmf!^Y&6P#|#)}lnQ_Ra6o#uG|Ms5X#5#|k&3Q^62B!7D#U)cafX+u$ zvD4Fhn}v16Ps=-_ROl}n>_{yuaNOSddoy~H!awKgs3xOz>C^H^_pe(6Rqt+S8u>)K zL>SR;XcLS+QCsGqU%i=D`UPw3_&$#J*FH!u83ZmZK?MrH1Q_E|;la7MuAo(0cS~!E zrz~rR5UT}&fwotu;0(6^2R)2G^ljDfg*L61`CkDw6%IYcPi^SKY<$I&Y2F{W=76qS_uaYw+1C=8hWRR){k z!gv22%365F#k-^a{l}=3{Vy|O7{gWFSR_In_{j&>R@;Zn=U3;A8_@y zms|<&?{ddyO5Lo+g9uz|8jZIt-OMEi0MZ{X$y&YO*63d3QCZ_^R zFO9!(nwf)H^~F69VjF=65nus&u8!A2hz0 z@w(pKWblrr4e9GRhDK9l@F5Q3iix+8_Z(3-Fr$7824`h`ZvA5l29%%FSWZ@06>$R1 z10zDFV#X#GQ7WGRrIsnnht%t1Eq7~HmYY={c#nUh^imW!s@H=r({%1cN6L0PVZpt>NTM zbeXY?SKVv7pP=A61dPNoZb?_9{cTG;xkE1AeZrV-B^y+Oh)2ZH#v3_~t_y-T40af* zr%(+uc`QQHVLSTFY+;h_bySjRiX{YhN%w5Oy5qdo)>3j4p_3)v8l>ZgawOJ5!`Amv zOI&lqbT&VRR;z`dvu@9?$()LU=tU$bBi>4*(=LAE_oM)vvG@b+ z8?=Veg@KwUrF&_aioEQ)skA=Fs*FzIM-m;GsJQ-IIvsy`(Knz|z1ffa2pR23CYu7S z@4a*>Mu?E7pxJ9ZksZhqCPM9(E!vwh-A+5bQ)xWp?b>W3K9EBQ16EKn0VQr|Gvsh8 zO9!|;0zP>vn1U$|TY0}&wE&|qQlMRf6~p*2xb6b(OhCCf^C!(ru0nete^tX{W=G`I+h?_ z@n0}>WD(vz+*80+_K!f!451p_b4eP@0s?D5yGCn*t?okUD(gGY(w!y2apoIoU@KEz zOp)^(>hqJdH4Q*Xf%dL0W`r$6F3y?7ynP{whHx`cQ&Ooj&2M28 zr_rL%Y{`KSg&`&i%`s|%A^~rM`bdg~#K~@c0IpCjRxgs#Y=oB1{zF(|;A6z z`y_q`lXs7?G;91ZmL5-De{&*V`h2sad+kf58Jg2IxC{fP+4(%2xl&j-6MQT88UBvH zB4Q1spM~mf{{4HDT$jSiKqsnh_Z!uyv7Ii6fDy4MP{4k303Q!Pj4TYKuj(4y#@%J^ z?Kj zmCKu{13Q?j7vr?8Ffq3%+}T%MYEMdG1`{uBM7oH>;}$K(L6n_ETV(KCwc@ zh|!eJNKrz%oh|Vqs}>Oksb8x`37_wCc^2?$ml_jbNSdfx*H8b)W0HV_sQ{?A3pYt4 zzH0?H4`XpW6rROf9lU>Fw+JR%X2^T!m%h7D4Pu9I^CFNN1?nqCW1OR1%#rilV*hk3 z$CDE1PHfAf{Z-$)8(*<~3F47Kd&&&RR>jY>qS?eN?l`aCcxR*fT02{wu%9@X5s;PA zhCzcVH^f)$56h}6v|4D+|BLLf7}UOJT{z)_1k?2zr`J{C_37KX6qn0>i3plA*Yyyr zc@OvddLn)KZ`?y-rx-yxKarAR0+&a@I`0KwchPUqy7fcBIzjA~N+ez3X8tgrcBCpJtX-R1!W%zI1C~Gg|R(ahWhS!2+!Zd*_Yk;4mAB6 z`nsw`kR^*nCeZ>MOuH-kt_ zXm%s{0~t<}LT*Re`y^1@DA={lJ;J`GEnuAgt;|EPaoBH?vO__lZ0Ja+VP zecfZVIu>$?~2d?p#mBQI|h&q(asH=d*GLC(;r=&pgAVDh8I#(Ifr*;#`Y-2}=j zds8*W%h=+;jf7S8y5pIO9{xgBBu>#QC(>~xdq65GPXAM6u56g0Tm)(w`h1h@o za4-%RT0EjMIH>i5wFKoHdWdKUoq%AebD0f;6M0Xz*X8%p+7y33T>*^!m3NMXKRFBq zi+NvHD@35ooCuRpKBa_NS>dIP7q7R7H~T&`f7%*y<9{*db(H#}`R{MF;iztZz(1?n z7dRt=H@>yGUKgEj0I%UDjgy}Fxu7c@J5*m=z>CTT_VDs^23 z#1_Q&HaC}(3+)eKAT_8jq`nKqs;A%Aq~0NEMDmLnXQZ?c z#LIa|Z^pE#sX_0@gu^KGZ=OB{^%RVF`+J;7t7dwA2i{S}OpJcvs`=KZ21UGoE6R5H z6jd3uD(r@QRgtZL)ZRX?BV3e$q*x2?GsY0|ty-CUo%vujc7B`FZJ?Bl9|& zHmZ75{>Xesh@ALOB`g_o8z)M8=*od2S>7TolVxr;V@6>gr5uf%kZVZd`v4shsD}V7YbNRy?M?R#wZ;U;o86>NJK^O3 z@KprE?-h>9hsVfo$3|atv_?hA&i;flxfi|mO%(ET)Rq{&YH9NTBzxoE5whLOt47~v zhCEVV3&LU;l&h*~kV@q7pLmr2X`0(&mS!l(9K(>a%JhiyGC4R0HTpi*!3_2uDZy)z z&`D>4;4x+sidHJ;|ba!z#>37BctUUne3k!<-19&aB2pj@xKtB;D^6BB`(7BEW?^DFCp)J zT_$>WEyQh}s(vo=e=FeclPMpbf>VUjvza~261t0MWT>q_Bn-O@>K}A#V&qLXEfBPf ze=%$Kg_&Z&b1wTE*6m>`rQ01MXHeaLkCPkxIE56+w%DJqTPqOPEexDbi*PqX6j6D< z1eZZ}OI9G@PQy%$^NAkSy1v!DmzD#T?u^YYo@DJum4sS1@2j=pEcRLejHNV~ZLv07~tCTo>`w_My8tiJhY zP5{y80^SpTG*ikV#E_vJZzTlYQ4F(xAf)AvcR#--mPP!cX#1*Nh$28bv-YND4F5#? zV@pVL%e)#=be6n)^?>-vt1Z!_&rjWZB9Jg^HHQ)NZe(#&}h3abg|(S zBax2(bsY{+e}#ucCx zMzT)sXZr*dU}p8yOvH*p9JqA)Y+?R(hrcl;*Gkku|CF=aM`#a$&_$a?qT|V6*huBG zdGa@;+-=`XMg8C6pp}hN*mw~d5w?5x^h`yzor>X%o%y&fwgpS@IVLdpDNMVH=WwT= zZc&0{_a7}4un)G>@fmwGO<$oC&o=w5UlQ+=OiLOTz$TKGO1TFUTQ?p)$_mIn9T8N% zc>f$i^a25IN!1KPcRa(}q-A!MQBlUsKe!WjbatA`*?Mjx`_$zDE+-lNK39~RQYvqd z@Q96R42uwI>l$unN*{(+l|TQN3f*hGI{64TqhhZ|367e9_5E2?1q2KW;xnSmLEx0I zAZ{nyTAgHHsK|U`*s-Wzvc_KnIv?@SINs9f$)GnyAZZM5|FB1&d+$t3id4lZ7iGc2 z=gZFq{09>t<||HYd?Cm%vg;{rEJWCumWO_0dT8{;w5T_R4-`xxi@z1XH?fOJ0vC4E z8}aKqN==;iU!FJut}M8we1*Lbkei{H&$HNS-ah7jRqP_Yg!!p7x`_V*Q>@=*jW&WNusiDfIayzSo8g9dtZ(^NsLM1q5;g76+Bm%!%+ zSx=u1n%?qX>0inQG9kJ(%Ac`7*1>WvCPvI{yUOp!uH+kzp(9e zR@(K}Gasrc?s_Sm^iD7iKSAjuF-S0d=MNJk_nSw{`M$U$VRX7lsrS<{ID+ib7%uzn z@Sf>Lo#PscvZPzo6OK+m#N+O0#8dMOg8~xaI`~keqbiZJLod`@5*=>dzrRo3)lXmn z-qUnA+I4J=JEat)iB10CK{^vg^rxw%iAPm6YE|*l1SsCC{XNCi$cFBpBVQ1&7tMfG(kw+`V_{1!4sE(-6PwOsa&Ea+wHYfY0=V?bU zF^T*NKRnuB^Z6xQo#}V?X1OY60l9Za-IV}j2A_Kpn5j{Vwo%clNLrZ~hUSTVgwU6m zc7bRkqg-p>j%BSp=0Kzgxc7PrY$0raSMJNq35AEk$c8?LNGWZ;IR&rhTP@%kM%b^f z4JV^ZMo>VL=;$yDKzy25X*uN{$X?c9ClJh+ty4#Nc>67k6S1ObN!9~PuReU24fw!u zC@0|ZL;mK&)w>k$uT}b4Ev7r$N|I*$-+z7?vi7-n%1wPWApFt6Sh#vH5l3@{Uz8b8 zdG5DiBo(+6Qn-i4vMjEEvuA&!w!QsJw#2zx7Ah)!MRGsgwAvzEg{a_bmk2<=nY#70 zY{`?RLF}tdU0qH`JQhN^TKrx_K8}}v6RXYn3o)Hy~O<3}jr-3-oz z98*#?07i)my+t*zTE{kU?yoy?!H?oLZlm{o@ry_U%kKoLX9RM&!R-P9Pg%N1mJpBy z$Oo0!j@6P$vM@aDE8>Lv!IS*&W4*Vcq35%*)Q(zcU>jEOI)uY z2+LxDaau3vkZ)j~50iv^)7BPu7@8d4_cVWee`q@x^ZN@5Ez5*_mKchoHvTudDLE}^ zM+JDicmTY@NkC1>8D_4k>Gt8JtTmsJ-dWq^6z(snar!N;V3K$!g_Q^X7+&3sY$j@k znAxtKwe79yku6I*h7hgf;G4YFr2?;OZ-M1J*{_o5hOCDlp0-9RIJ9$gFG^jNGzyb2 z1)rHEg%Fs-x+J(Yh9yd3{hl=gO?iJ0R(XLk^B2h)(QA&ifJ}wmYf5rxx3hepkax%m zPYcxJ105I@PnS-@=%94~%d{)aY=LDRW+L-HtjYI_aCQ(PFXF3wGM~>d!ivavI-TQXiuY(H5J%AlGEFpCK~pl; z#_wFKIFfh^6#M9FJ>e;!7ESjC)CO$It)(Y~L^gNmA`L)w{&WpdC$O#*lAyfq#C#@v{Ck zoWeQSP7mzS1gn1m_CYNH!Sdy}0a)in1`=w8bTbjrux?A2;O60Gzs%F~ZUw~bwQjABEO(^n9xR7kslrLr(2|t|BlKU)>M{MRj##6&FZ!w{-Q5VS&=0l^I z2qY*hCn^@F(fpS(WMK#=Hn6_6$-OI<`tL;|zJthrq2se_TT&afg(_X5F7vLESqfM! zP&Cc>`{yEDY@kKO%$w@2C5i}LX(e0;LjKDWVD>l1ShG_J{=Iqh#OCej<;SVP=-}*8 z-6T~xg5`ih5M-So;=cVxM_On(*!QmNM^OG)uKARMz8wj28E!}|2Za3Z1DVAEE)X@~ z!(27hV<;vc+)mU4n!Et%W1!{Sv?!d;uR_6mViOl(Jj%9HLZy4gymt$>`!e;8;w~HN z3bm?f0kAx=>eshLf9Ab1;Ss0D(c6Aio-)>BkfwL=kP3F66gj`p)h4rsLNba?knD!_ z_*DRz9~uIG)JAQb=6Ib%;&l#j1nwdPy84`-pop&X=f2w4jf!u|$rmf|D5yYs=%gMC zLi2i3S2ZrZ{_OHWQ@h%3j5VyYU-cV--P=OK^z#QkqO}^X`Lr5ZEYwt`DWq$W*at*0w<=p>~i0K zd$GphJAY=OYBm6Q=_M#RjkN*LN{g3cR5&J*`)y3v(e{n%f1vP`KCf?%TYWWm!6$>Lh3A z6zXZL!c@F|z(RptGw_R)dmdwO$}*U`z^V>Pr#JcTcYH_UyY>&4ON@22S{i{o$P)NL z^g{2tigmvonPGv{eIONiLJE~qyQMYC8A@BGkei~!JGI|8OoIeOH;D;S~UP*bwcW)k9hI|7Wa zbq=SC#%BB>IL{dTAayF;)MrH1*Y^sIjD+X1nrzyM>nQdcPm>v-eiYDAy*mbx$Su+P z#0jqqH0U1B;mNa`cEGrJPr~rUul#8P%D!_gru;q9xmQvU>Dt@Z-?tN%X8Yhw3ms@W zH-2IaY?l?6Ui=kmz_R$iq`P70;`65OJt4+J}4se9Glxr}+ccV7gJ{y?zB~#M;T$N?8*TZGDf5 z^}G#Nkb2)TXqREaV451fzb)uz#7Zk7u8TV@&cFr?503FFgXiCO%%k|p&I6vVezkQ2 zv70t{)|0-S?`48Y*?y@rQSO59&(mNHF36u8&|@u%nzRjc1x>`fuhJk%6>AjM1VKT4 zJZ_7SkkKt|gC%3EzV-O4LXPuid1;+^=M-4yA5MX~|norku(DfIY}Un1bui)LB;F*06(vOLP(Pepj)h8zu@! zi-THoG(kvE-iG2f7X8}K=J?MS^>gb{&#-`AP{jSdl%^-A#tAJp8l zdR^dF8P3OnFG(?%>01~bXU1IuOB=_g?^WMF>d4g)%ZkCBtbD+6DJ3M1b#&jlPUfw% zbE=z1!V0YLx!CJX=BL*t0rAmK`bVpvFmr9K@C`N5HoTG8lKd~mW&P$xc^Lr+1d;mL zy!-w(L&9e6O`qls#*E?@tp;m|e;47VpC`n7)J)g@8jiX*$REAbvPK%b>-Qnm&Ga!7 zaSzxkB~#dQm$>@5EVW8OQt*KRi)`$%>heqqeuL7p$8qxm#J{hC-UHUF&}*rjr&c#S zf5^IxCGZ~y=Bx+k5X3cCXkR>tGukEUM&>$g`;rVFx1I-feTzd4H+kRw$xi1DAA*zG zgu3t$&csu9&ce8Jy~S)y1QKp2eFfw@zlHiZyQJUKBp*ppTgPK8l9&>k|2_SkK$#EJ z2!8q?Lgiq3$FljoEF#%P`|1}=llrl;r&br1 zf&(s^U_ZB$dtA+WNgUyt4HUB`Hl6;;GP?K35(4Wu@qvpDaP%zMO_uvJ!n#P5!*bBn zmUTbP_`UXBJJ0XQ02wFEAJKvTQC*&3m!ehDH;~bHd5wLGb=T`cG2G=j0ooY78er-8 zx1p5F?ihb@avm@LTyS)F2-1Y_(K4E=ZX)u6!ILjAbxbba^6_Vn%l34bk5(&E^sQte z7jW;;+7)-$7A_hT*0#V*-KQ1~#dbLr!Z&zj^~B0w%PU$S#CR(xVRLt_E>hwPPGDdH}K8L$QokGP}~U#n9EKR3mgbwydLp+lo~R5#auj8{rA z@91I6n!n-*pp9@;;^!K!j5Ppydjg>JN{rPRQ`5SyFh1?<2@EY= z@onAvOPIgQ-O~_oB=Z4&)F+`bU+{zQ8PN%Z2BTHp;%svPk|gn#B!nkGfu=y;a!~{W zYh_bBfxW3lI$Lmyb{>+;LmNM~eZgPJr^tTG?P3j#vBKB#yk@?kDnbr2zXeQ}NPw)y zw)KloJAGETcDP2%Wg$$Iexa;i6S|F#%IU>UvS^fni-*7v-K!d$%rlrfY4@>9-p`pzT_wM2ToAl~Ud#V83b+Nd8RkXQSzD-(UQq%v9_`DGCzs zLcy1zjN5Vi^Rl9lN3Y0PzBVy{!VMh+gH|Qhv*eH8v=i|oLQ!Jt! zen0Hmzn3S48pU&pmFhKolBU6d@#5gMW4gzLeFuCHh5a)fcLR&pw}pdd(tn+Caab?; zqyh;+FsSx*TUsTB?sruZpz1aC|ZUpu?R;(;P&c4B;lXG z%D9aWLoqa^-=mzo-w|(K02*!F9^Wh0AghuukVU<#gqWAj85*%$ zO@YWO5T<@EfCpj}Q6Qrb(8z073@PXN4$ce2wOox>Pi9P=C5sXHazn)*Pn$BD#VPSi&z6~|EcJ|_K}1V{;fRu-kQMySB%Y3 z8A}NdukF$A!bb!-Oya7O*0|0kfElGn72#BWaX{HN{4OVtTMkmQu{r?PY&g7Je~y?_ zpB!(}sD8cZh1zbK0mZS5=3+!6TdCsMJ~-d*M)QXbGBk9EW)OlW&)#>a`@gN#eLCl; zsgJ%Pnc1lkEmxiFeZ9lkZ&2R9BweYHPVM^0U&de7i*7J1bbHB-%`4V7VQzm|HeKMa zANU^)n*llo!rnA3y!VJ;Z3+XP;l7`CZPs=D4LEi5L9-UY3Yxn*xQ^Wg?s|)jxoMh) zL^4v+P+|0JZ?Vi-A@g<*Vz^1yYW_b&X|TCjrb-4uRfqU(d?z#tb9w(xREF)F(WBGx z7Uro`&D(9xUcYd?aEZ`+1w6(R=A~}}Xc<6O<>LT7gDq)pj_C0P^9BHERL z9#niDC;!c-Q79gKHDt_a#;9woB!Iy==?R0$U7FceT%+Mrw>~*(8SRRh8 z`lcyWRN=3DCuWJ)nNEE&7o?j&rs-+y6AdiC_V&QOMiIq^9{%6T7H;Gg3>l&7FnF*| zH_b54yhCEGHFeO-aBUNYD0grTVikY`LC0xdTu8welz?j)t+BcE3?^@&NW>C`RVbee7`% z2xL8_A$_0+S?Vj&J3=Na^pe6t+k2zWm7d0EIRUZ@O<8H=&2uh^vw?YOUuG+|zrDPv z&vxTpL2&OGh#}vUj?clv zLc6#QHBX4Ah03nEqdf}vAR2vK0BBEQXhJ`}iTJ;?EE?K)@s157k;8yD@Yi;E2o%d% zSduW;qx*#{y^Bkl@#FJK7bE@QseY}wrqKTJZ%Qq-O$=;@Abzt5>^Eft<^3~?M+Lat zukj6RRTzTNx01nW^kawT3OcEN2xrjpO|i6>BfG@i^M*;mgp=xk%=WYFCq2c(^%gl^!dYjg3-G=to@}7D zNYN%qwZgs`6xV>Dib*iooRMp$$wjJ)!o8BlBjB_?WGs3H3~ovT^U`+Qm&X=Xb6-ZuSGU5= zT7$NP+@bl8Uis#G1h1Kd7^SfIDun>Z%OJo)8&>m!m9uB{o46Q+C5Cq^9d|sks`

    H5&PynumSHiwCn7sB~?UgdMKKMQ*A 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

    9%2}AVGM8_G>>7j|keKr&>bYCbK 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%0AFOicBSinzu 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

    59=zZQvnOxV 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

    fMN`*^~sT_L?ac54zD8fm2!!rW%Qh&RX3EyKM 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

    LnDllW`4;31J{7oXV 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 literal 2771810 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