mirror of
https://github.com/urbit/shrub.git
synced 2024-12-01 06:35:32 +03:00
Merge branch 'cc-release' into ccr-fast-boot
This commit is contained in:
commit
704abb09ca
@ -9,9 +9,9 @@ node_js:
|
||||
# email: false
|
||||
|
||||
before_install:
|
||||
# try to get pill early, so configuration errors will be quickly caught
|
||||
#
|
||||
# try to get pill early, so configuration errors will be quickly caught
|
||||
- cd .travis
|
||||
- bash check-trailing-whitespace.sh
|
||||
- bash get-brass-pill.sh
|
||||
- cd ..
|
||||
- wget https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip
|
||||
|
15
.travis/check-trailing-whitespace.sh
Executable file
15
.travis/check-trailing-whitespace.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
whitespace=$(
|
||||
find .. -path ../.git -prune -o \
|
||||
-path ../subprojects -prune -o \
|
||||
-type f \
|
||||
-exec egrep -l " +$" {} ';' \
|
||||
)
|
||||
|
||||
if [ -n "$whitespace" ]
|
||||
then
|
||||
echo 'found trailing whitespace in:';
|
||||
echo $whitespace;
|
||||
exit 1;
|
||||
fi
|
@ -66,6 +66,7 @@
|
||||
u3_noun u3wc_rep(u3_noun);
|
||||
u3_noun u3wc_rev(u3_noun);
|
||||
u3_noun u3wc_rip(u3_noun);
|
||||
u3_noun u3wc_ripn(u3_noun);
|
||||
u3_noun u3wc_rsh(u3_noun);
|
||||
u3_noun u3wc_swp(u3_noun);
|
||||
u3_noun u3wc_sqt(u3_noun);
|
||||
|
@ -697,6 +697,7 @@
|
||||
u3_pier** tab_u; // lord table
|
||||
uv_pipe_t cmd_u; // command socket
|
||||
u3_moor* cli_u; // connected clients
|
||||
uv_timer_t tim_u; // gc timer
|
||||
} u3_king;
|
||||
|
||||
# define u3L u3_Host.lup_u // global event loop
|
||||
@ -1293,6 +1294,11 @@
|
||||
void
|
||||
u3_pier_sway(c3_l tab_l, u3_noun tax);
|
||||
|
||||
/* u3_pier_mark(): mark all Loom allocations in all u3_pier structs.
|
||||
*/
|
||||
c3_w
|
||||
u3_pier_mark(FILE* fil_u);
|
||||
|
||||
/* u3_dawn_come(): mine a comet
|
||||
*/
|
||||
u3_noun
|
||||
@ -1307,3 +1313,8 @@
|
||||
*/
|
||||
void
|
||||
u3_king_commence();
|
||||
|
||||
/* u3_king_grab(): gc the kingdom
|
||||
*/
|
||||
void
|
||||
u3_king_grab(void* vod_p);
|
||||
|
154
jets/c/rip.c
154
jets/c/rip.c
@ -1,92 +1,86 @@
|
||||
/* j/3/rip.c
|
||||
**
|
||||
*/
|
||||
#include "all.h"
|
||||
|
||||
u3_noun u3qc_rip(u3_atom bloq, u3_atom b) {
|
||||
if ( !_(u3a_is_cat(bloq)) || (bloq >= 32) ) {
|
||||
return u3m_bail(c3__fail);
|
||||
}
|
||||
|
||||
/* functions
|
||||
*/
|
||||
u3_noun
|
||||
u3qc_rip(u3_atom a,
|
||||
u3_atom b)
|
||||
{
|
||||
if ( !_(u3a_is_cat(a)) || (a >= 32) ) {
|
||||
c3_g bloq_g = bloq;
|
||||
|
||||
/*
|
||||
This is a fast-path for the case where all the resulting blocks will
|
||||
fit in 31-bit direct atoms.
|
||||
*/
|
||||
if ( bloq_g < 5 ) { // produce direct atoms
|
||||
u3_noun acc = u3_nul;
|
||||
|
||||
c3_w met_w = u3r_met(bloq_g, b); // num blocks in atom
|
||||
c3_w nbits_w = 1 << bloq_g; // block size in bits
|
||||
c3_w bmask_w = (1 << nbits_w) - 1; // result mask
|
||||
|
||||
for ( c3_w i_w = 0; i_w < met_w; i_w++ ) { // `i_w` is block index
|
||||
c3_w nex_w = i_w + 1; // next block
|
||||
c3_w pat_w = met_w - nex_w; // blks left after this
|
||||
c3_w bit_w = pat_w << bloq_g; // bits left after this
|
||||
c3_w wor_w = bit_w >> 5; // wrds left after this
|
||||
c3_w sif_w = bit_w & 31; // bits left in word
|
||||
c3_w src_w = u3r_word(wor_w, b); // find word by index
|
||||
c3_w rip_w = (src_w >> sif_w) & bmask_w; // get item from word
|
||||
|
||||
acc = u3nc(rip_w, acc);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
u3_noun acc = u3_nul;
|
||||
c3_w met_w = u3r_met(bloq_g, b);
|
||||
c3_w len_w = u3r_met(5, b);
|
||||
c3_g san_g = (bloq_g - 5);
|
||||
c3_w san_w = 1 << san_g;
|
||||
c3_w dif_w = (met_w << san_g) - len_w;
|
||||
c3_w tub_w = ((dif_w == 0) ? san_w : (san_w - dif_w));
|
||||
|
||||
for ( c3_w i_w = 0; i_w < met_w; i_w++ ) {
|
||||
c3_w pat_w = (met_w - (i_w + 1));
|
||||
c3_w wut_w = (pat_w << san_g);
|
||||
c3_w sap_w = ((0 == i_w) ? tub_w : san_w);
|
||||
c3_w* sal_w = u3a_slab(sap_w);
|
||||
|
||||
if ( 0 == sal_w ) {
|
||||
return u3m_bail(c3__fail);
|
||||
}
|
||||
else {
|
||||
u3_noun pir = u3_nul;
|
||||
c3_g a_g = a;
|
||||
c3_w i_w;
|
||||
|
||||
if ( a_g < 5 ) {
|
||||
c3_w met_w = u3r_met(a_g, b);
|
||||
c3_w mek_w = ((1 << (1 << a_g)) - 1);
|
||||
c3_w j_w;
|
||||
u3_atom rip;
|
||||
|
||||
for ( i_w = 0; i_w < met_w; i_w++ ) {
|
||||
c3_w pat_w = (met_w - (i_w + 1));
|
||||
c3_w bit_w = (pat_w << a_g);
|
||||
c3_w wor_w = (bit_w >> 5);
|
||||
c3_w sif_w = (bit_w & 31);
|
||||
c3_w src_w = u3r_word(wor_w, b);
|
||||
c3_w rip_w = ((src_w >> sif_w) & mek_w);
|
||||
|
||||
pir = u3nc(rip_w, pir);
|
||||
}
|
||||
return pir;
|
||||
}
|
||||
else {
|
||||
c3_w met_w = u3r_met(a_g, b);
|
||||
c3_w len_w = u3r_met(5, b);
|
||||
c3_g san_g = (a_g - 5);
|
||||
c3_w san_w = 1 << san_g;
|
||||
c3_w dif_w = (met_w << san_g) - len_w;
|
||||
c3_w tub_w = ((dif_w == 0) ? san_w : (san_w - dif_w));
|
||||
|
||||
for ( i_w = 0; i_w < met_w; i_w++ ) {
|
||||
c3_w pat_w = (met_w - (i_w + 1));
|
||||
c3_w wut_w = (pat_w << san_g);
|
||||
c3_w sap_w = ((0 == i_w) ? tub_w : san_w);
|
||||
c3_w* sal_w = u3a_slab(sap_w);
|
||||
|
||||
if ( 0 == sal_w ) {
|
||||
return u3m_bail(c3__fail);
|
||||
} else {
|
||||
c3_w j_w;
|
||||
u3_atom rip;
|
||||
|
||||
for ( j_w = 0; j_w < sap_w; j_w++ ) {
|
||||
sal_w[j_w] = u3r_word(wut_w + j_w, b);
|
||||
}
|
||||
|
||||
rip = u3a_malt(sal_w);
|
||||
pir = u3nc(rip, pir);
|
||||
}
|
||||
len_w -= san_w;
|
||||
}
|
||||
}
|
||||
return pir;
|
||||
for ( j_w = 0; j_w < sap_w; j_w++ ) {
|
||||
sal_w[j_w] = u3r_word(wut_w + j_w, b);
|
||||
}
|
||||
}
|
||||
u3_noun
|
||||
u3wc_rip(u3_noun cor)
|
||||
{
|
||||
u3_noun a, b;
|
||||
|
||||
if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
|
||||
(c3n == u3ud(a)) ||
|
||||
(c3n == u3ud(b)) )
|
||||
{
|
||||
return u3m_bail(c3__exit);
|
||||
} else {
|
||||
return u3qc_rip(a, b);
|
||||
}
|
||||
rip = u3a_malt(sal_w);
|
||||
acc = u3nc(rip, acc);
|
||||
len_w -= san_w;
|
||||
}
|
||||
u3_noun
|
||||
u3kc_rip(u3_atom a,
|
||||
u3_atom b)
|
||||
{
|
||||
u3_noun res = u3qc_rip(a, b);
|
||||
|
||||
u3z(a); u3z(b);
|
||||
return res;
|
||||
return acc;
|
||||
}
|
||||
|
||||
u3_noun u3wc_rip(u3_noun cor) {
|
||||
u3_noun a, b;
|
||||
|
||||
if ( (c3n == u3r_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0)) ||
|
||||
(c3n == u3ud(a)) ||
|
||||
(c3n == u3ud(b))
|
||||
) {
|
||||
return u3m_bail(c3__exit);
|
||||
}
|
||||
|
||||
return u3qc_rip(a, b);
|
||||
}
|
||||
|
||||
u3_noun u3kc_rip(u3_atom a, u3_atom b) {
|
||||
u3_noun res = u3qc_rip(a, b);
|
||||
u3z(a); u3z(b);
|
||||
return res;
|
||||
}
|
||||
|
100
jets/c/ripn.c
Normal file
100
jets/c/ripn.c
Normal file
@ -0,0 +1,100 @@
|
||||
#include "all.h"
|
||||
|
||||
/*
|
||||
Get the lowest `n` bits of a word `w` using a bitmask.
|
||||
*/
|
||||
#define TAKEBITS(n,w) \
|
||||
((n)==32) ? (w) : \
|
||||
((n)==0) ? 0 : \
|
||||
((w) & ((1 << (n)) - 1))
|
||||
|
||||
/*
|
||||
Divide, rounding up.
|
||||
*/
|
||||
#define DIVCEIL(x,y) \
|
||||
(x==0) ? 0 : \
|
||||
1 + ((x - 1) / y);
|
||||
|
||||
/*
|
||||
`ripn` breaks `atom` into a list of blocks, of bit-width `bits`. The
|
||||
resulting list will be least-significant block first.
|
||||
|
||||
XX TODO This only handles cases where the bit-width is <= 32.
|
||||
|
||||
For each block we produce, we need to grab the relevant words inside
|
||||
`atom`, so we first compute their indicies.
|
||||
|
||||
`ins_idx` is the word-index of the least-significant word we
|
||||
care about, and `sig_idx` is the word after that.
|
||||
|
||||
Next we grab those words (`ins_word` and `sig_word`) from the atom
|
||||
using `u3r_word`. Note that `sig_idx` might be out-of-bounds for the
|
||||
underlying array of `atom`, but `u3r_word` returns 0 in that case,
|
||||
which is exatly what we want.
|
||||
|
||||
Now, we need to grab the relevant bits out of both words, and combine
|
||||
them. `bits_rem_in_ins_word` is the number of remaining (insignificant)
|
||||
bits in `ins_word`, `nbits_ins` is the number of bits we want from the
|
||||
less-significant word, and `nbits_sig` from the more-significant one.
|
||||
|
||||
Take the least significant `nbits_sig` bits from `sig_word`, and take
|
||||
the slice we care about from `ins_word`. In order to take that slice,
|
||||
we drop `bits_rem_in_ins_word` insignificant bits, and then take the
|
||||
`nbits_sig` most-significant bits.
|
||||
|
||||
Last, we slice out those bits from the two words, combine them into
|
||||
one word, and cons them onto the front of the result.
|
||||
*/
|
||||
u3_noun u3qc_ripn(u3_atom bits, u3_atom atom) {
|
||||
if ( !_(u3a_is_cat(bits) || bits==0 || bits>31) ) {
|
||||
return u3m_bail(c3__fail);
|
||||
}
|
||||
|
||||
c3_w bit_width = u3r_met(0, atom);
|
||||
c3_w num_blocks = DIVCEIL(bit_width, bits);
|
||||
|
||||
u3_noun res = u3_nul;
|
||||
|
||||
for ( c3_w blk = 0; blk < num_blocks; blk++ ) {
|
||||
c3_w next_blk = blk + 1;
|
||||
c3_w blks_rem = num_blocks - next_blk;
|
||||
c3_w bits_rem = blks_rem * bits;
|
||||
c3_w ins_idx = bits_rem / 32;
|
||||
c3_w sig_idx = ins_idx + 1;
|
||||
|
||||
c3_w bits_rem_in_ins_word = bits_rem % 32;
|
||||
|
||||
c3_w ins_word = u3r_word(ins_idx, atom);
|
||||
c3_w sig_word = u3r_word(sig_idx, atom);
|
||||
c3_w nbits_ins = c3_min(bits, 32 - bits_rem_in_ins_word);
|
||||
c3_w nbits_sig = bits - nbits_ins;
|
||||
|
||||
c3_w ins_word_bits = TAKEBITS(nbits_ins, ins_word >> bits_rem_in_ins_word);
|
||||
c3_w sig_word_bits = TAKEBITS(nbits_sig, sig_word);
|
||||
|
||||
c3_w item = ins_word_bits | (sig_word_bits << nbits_ins);
|
||||
|
||||
res = u3nc(item, res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u3_noun u3wc_ripn(u3_noun cor) {
|
||||
u3_noun bits, atom;
|
||||
|
||||
if ( (c3n == u3r_mean(cor, u3x_sam_2, &bits, u3x_sam_3, &atom, 0)) ||
|
||||
(c3n == u3ud(bits)) ||
|
||||
(c3n == u3ud(atom)) )
|
||||
{
|
||||
return u3m_bail(c3__exit);
|
||||
}
|
||||
|
||||
return u3qc_ripn(bits, atom);
|
||||
}
|
||||
|
||||
u3_noun u3kc_ripn(u3_atom bits, u3_atom atom) {
|
||||
u3_noun res = u3qc_ripn(bits, atom);
|
||||
u3z(bits), u3z(atom);
|
||||
return res;
|
||||
}
|
21
jets/tree.c
21
jets/tree.c
@ -1,5 +1,18 @@
|
||||
/* j/tree.c
|
||||
/*
|
||||
To generate the hashes, take the sha256 of the jammed battery. For example:
|
||||
|
||||
```
|
||||
> `@ux`(shax (jam -:ripn))
|
||||
0x2759.a693.1e9e.f9a5.2c8e.ee43.1088.43d9.4d39.32a6.b04f.86cb.6ba1.5553.4329.3a28
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
```
|
||||
2759a6931e9ef9a52c8eee43108843d94d3932a6b04f86cb6ba1555343293a28
|
||||
```
|
||||
*/
|
||||
|
||||
#include "all.h"
|
||||
|
||||
static u3j_harm _141_hex_aes_ecba_en_a[] = {{".2", u3wea_ecba_en}, {}};
|
||||
@ -1473,6 +1486,11 @@ static c3_c* _141_two_rip_ha[] = {
|
||||
"e8e0b834aded0d2738bcf38a93bf373d412a51e0cee7f274277a6393e634a65e",
|
||||
0
|
||||
};
|
||||
static u3j_harm _141_two_ripn_a[] = {{".2", u3wc_ripn, c3y}, {}};
|
||||
static c3_c* _141_two_ripn_ha[] = {
|
||||
"2759a6931e9ef9a52c8eee43108843d94d3932a6b04f86cb6ba1555343293a28",
|
||||
0
|
||||
};
|
||||
static u3j_harm _141_two_rsh_a[] = {{".2", u3wc_rsh, c3y}, {}};
|
||||
static c3_c* _141_two_rsh_ha[] = {
|
||||
"a401145b4c11ec8d17a729fe30f06c295865ffed1b970b0a788f0fec1ed0a703",
|
||||
@ -1710,6 +1728,7 @@ static u3j_core _141_two_d[] =
|
||||
{ "rep", 7, _141_two_rep_a, 0, _141_two_rep_ha },
|
||||
{ "rev", 7, _141_two_rev_a, 0, _141_two_rev_ha },
|
||||
{ "rip", 7, _141_two_rip_a, 0, _141_two_rip_ha },
|
||||
{ "ripn", 7, _141_two_ripn_a, 0, _141_two_ripn_ha },
|
||||
{ "rsh", 7, _141_two_rsh_a, 0, _141_two_rsh_ha },
|
||||
{ "swp", 7, _141_two_swp_a, 0, _141_two_swp_ha },
|
||||
{ "rub", 7, _141_two_rub_a, 0, _141_two_rub_ha },
|
||||
|
@ -73,6 +73,7 @@ jets_c_src = [
|
||||
'jets/c/rep.c',
|
||||
'jets/c/rev.c',
|
||||
'jets/c/rip.c',
|
||||
'jets/c/ripn.c',
|
||||
'jets/c/rsh.c',
|
||||
'jets/c/swp.c',
|
||||
'jets/c/sqt.c'
|
||||
|
@ -109,6 +109,7 @@ u3v_lite(u3_noun pil)
|
||||
pro = u3k(u3r_at(7, cor));
|
||||
|
||||
u3z(cor);
|
||||
u3z(arv);
|
||||
return pro;
|
||||
}
|
||||
|
||||
|
44
vere/king.c
44
vere/king.c
@ -375,14 +375,16 @@ _king_bail(u3_moor *vod_p, const c3_c *err_c)
|
||||
{
|
||||
u3_moor *free_p;
|
||||
fprintf(stderr, "_king_bail: %s\r\n", err_c);
|
||||
|
||||
if ( vod_p == 0 ) {
|
||||
free_p = u3K.cli_u;
|
||||
u3K.cli_u = u3K.cli_u->nex_u;
|
||||
u3a_free(free_p);
|
||||
} else {
|
||||
c3_free(free_p);
|
||||
}
|
||||
else {
|
||||
free_p = vod_p->nex_u;
|
||||
vod_p->nex_u = vod_p->nex_u->nex_u;
|
||||
u3a_free(free_p);
|
||||
c3_free(free_p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,14 +394,17 @@ void
|
||||
_king_socket_connect(uv_stream_t *sock, int status)
|
||||
{
|
||||
u3_moor *mor_u;
|
||||
|
||||
if ( u3K.cli_u == 0 ) {
|
||||
u3K.cli_u = u3a_malloc(sizeof(u3_moor));
|
||||
u3K.cli_u = c3_malloc(sizeof(u3_moor));
|
||||
mor_u = u3K.cli_u;
|
||||
mor_u->vod_p = 0;
|
||||
mor_u->nex_u = 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (mor_u = u3K.cli_u; mor_u->nex_u; mor_u = mor_u->nex_u);
|
||||
mor_u->nex_u = u3a_malloc(sizeof(u3_moor));
|
||||
|
||||
mor_u->nex_u = c3_malloc(sizeof(u3_moor));
|
||||
mor_u->nex_u->vod_p = mor_u;
|
||||
mor_u = mor_u->nex_u;
|
||||
mor_u->nex_u = 0;
|
||||
@ -781,8 +786,6 @@ u3_king_commence()
|
||||
//
|
||||
sag_w = u3C.wag_w;
|
||||
u3C.wag_w |= u3o_hashless;
|
||||
u3C.wag_w &= ~u3o_debug_ram;
|
||||
u3C.wag_w &= ~u3o_check_corrupt;
|
||||
|
||||
u3m_boot_pier();
|
||||
{
|
||||
@ -810,6 +813,8 @@ u3_king_commence()
|
||||
u3K.soc_c = strdup(buf_c);
|
||||
}
|
||||
|
||||
uv_timer_init(u3L, &u3K.tim_u);
|
||||
|
||||
uv_pipe_init(u3L, &u3K.cmd_u, 0);
|
||||
uv_pipe_bind(&u3K.cmd_u, u3K.soc_c);
|
||||
uv_listen((uv_stream_t *)&u3K.cmd_u, 128, _king_socket_connect);
|
||||
@ -822,3 +827,26 @@ u3_king_commence()
|
||||
_king_loop_exit();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* u3_king_grab(): gc the kingdom
|
||||
*/
|
||||
void
|
||||
u3_king_grab(void* vod_p)
|
||||
{
|
||||
// XX fix leaks and enable
|
||||
//
|
||||
#if 0
|
||||
c3_w man_w = 0, pir_w = 0;
|
||||
FILE* fil_u = stderr;
|
||||
|
||||
c3_assert( u3R == &(u3H->rod_u) );
|
||||
|
||||
fprintf(fil_u, "measuring king:\r\n");
|
||||
|
||||
man_w = u3m_mark(fil_u);
|
||||
pir_w = u3_pier_mark(fil_u);
|
||||
|
||||
u3a_print_memory(fil_u, "total marked", man_w + pir_w);
|
||||
u3a_print_memory(fil_u, "sweep", u3a_sweep());
|
||||
#endif
|
||||
}
|
||||
|
34
vere/pier.c
34
vere/pier.c
@ -2219,3 +2219,37 @@ u3_pier_stay(c3_w wag_w, u3_noun pax)
|
||||
|
||||
u3z(pax);
|
||||
}
|
||||
|
||||
/* u3_pier_mark(): mark all Loom allocations in all u3_pier structs.
|
||||
*/
|
||||
c3_w
|
||||
u3_pier_mark(FILE* fil_u)
|
||||
{
|
||||
c3_w len_w = u3K.len_w;
|
||||
c3_w tot_w = 0;
|
||||
u3_pier* pir_u;
|
||||
|
||||
while ( 0 < len_w ) {
|
||||
pir_u = u3K.tab_u[--len_w];
|
||||
fprintf(stderr, "pier: %u\r\n", len_w);
|
||||
|
||||
tot_w += u3a_maid(fil_u, " boot event", u3a_mark_noun(pir_u->bot));
|
||||
|
||||
{
|
||||
u3_writ* wit_u = pir_u->ent_u;
|
||||
c3_w wit_w = 0;
|
||||
|
||||
while ( 0 != wit_u ) {
|
||||
wit_w += u3a_mark_noun(wit_u->job);
|
||||
wit_w += u3a_mark_noun(wit_u->now);
|
||||
wit_w += u3a_mark_noun(wit_u->mat);
|
||||
wit_w += u3a_mark_noun(wit_u->act);
|
||||
wit_u = wit_u->nex_u;
|
||||
}
|
||||
|
||||
tot_w += u3a_maid(fil_u, " writs", wit_w);
|
||||
}
|
||||
}
|
||||
|
||||
return tot_w;
|
||||
}
|
||||
|
@ -131,9 +131,12 @@ _reck_kick_term(u3_pier* pir_u, u3_noun pox, c3_l tid_l, u3_noun fav)
|
||||
|
||||
case c3__mass: p_fav = u3t(fav);
|
||||
{
|
||||
// XX GC the full king state
|
||||
u3z(pox); u3z(fav);
|
||||
|
||||
// gc the kingdom
|
||||
//
|
||||
u3z(pox); u3z(fav); return c3y;
|
||||
uv_timer_start(&u3K.tim_u, (uv_timer_cb)u3_king_grab, 0, 0);
|
||||
return c3y;
|
||||
} break;
|
||||
}
|
||||
c3_assert(!"not reached"); return 0;
|
||||
|
@ -408,6 +408,8 @@ _serf_sure(u3_noun ovo, u3_noun vir, u3_noun cor)
|
||||
}
|
||||
}
|
||||
|
||||
// XX this runs on replay too
|
||||
//
|
||||
_serf_grab(sac, ovo, vir);
|
||||
_serf_send_complete(vir);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user