Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
U
unique-xids
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
uplex-varnish
unique-xids
Commits
40761260
Commit
40761260
authored
Feb 15, 2012
by
Poul-Henning Kamp
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Push worker->busyobj change up through ESI
parent
5d4e2cee
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
62 additions
and
68 deletions
+62
-68
cache_esi.h
bin/varnishd/cache/cache_esi.h
+3
-3
cache_esi_fetch.c
bin/varnishd/cache/cache_esi_fetch.c
+38
-41
cache_esi_parse.c
bin/varnishd/cache/cache_esi_parse.c
+21
-24
No files found.
bin/varnishd/cache/cache_esi.h
View file @
40761260
...
...
@@ -39,10 +39,10 @@
#define VEC_S8 (0x60 + 8)
#define VEC_INCL 'I'
typedef
ssize_t
vep_callback_t
(
struct
worker
*
w
,
ssize_t
l
,
enum
vgz_flag
flg
);
typedef
ssize_t
vep_callback_t
(
struct
busyobj
*
,
ssize_t
l
,
enum
vgz_flag
flg
);
void
VEP_Init
(
struct
worker
*
w
,
vep_callback_t
*
cb
);
void
VEP_Init
(
struct
busyobj
*
,
vep_callback_t
*
cb
);
void
VEP_Parse
(
const
struct
busyobj
*
,
const
char
*
p
,
size_t
l
);
struct
vsb
*
VEP_Finish
(
const
struct
worker
*
w
);
struct
vsb
*
VEP_Finish
(
struct
busyobj
*
);
bin/varnishd/cache/cache_esi_fetch.c
View file @
40761260
...
...
@@ -84,26 +84,26 @@ vef_read(struct http_conn *htc, void *buf, ssize_t buflen,
*/
static
int
vfp_esi_bytes_uu
(
struct
worker
*
wrk
,
const
struct
vef_priv
*
vef
,
vfp_esi_bytes_uu
(
struct
busyobj
*
bo
,
const
struct
vef_priv
*
vef
,
struct
http_conn
*
htc
,
ssize_t
bytes
)
{
ssize_t
wl
;
struct
storage
*
st
;
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER
_MAGIC
);
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ
_MAGIC
);
CHECK_OBJ_NOTNULL
(
vef
,
VEF_MAGIC
);
while
(
bytes
>
0
)
{
st
=
FetchStorage
(
wrk
->
busyobj
,
0
);
st
=
FetchStorage
(
bo
,
0
);
if
(
st
==
NULL
)
return
(
-
1
);
wl
=
vef_read
(
htc
,
st
->
ptr
+
st
->
len
,
st
->
space
-
st
->
len
,
bytes
);
if
(
wl
<=
0
)
return
(
wl
);
VEP_Parse
(
wrk
->
busyobj
,
(
const
char
*
)
st
->
ptr
+
st
->
len
,
wl
);
VEP_Parse
(
bo
,
(
const
char
*
)
st
->
ptr
+
st
->
len
,
wl
);
st
->
len
+=
wl
;
wrk
->
busyobj
->
fetch_obj
->
len
+=
wl
;
bo
->
fetch_obj
->
len
+=
wl
;
bytes
-=
wl
;
}
return
(
1
);
...
...
@@ -114,7 +114,7 @@ vfp_esi_bytes_uu(struct worker *wrk, const struct vef_priv *vef,
*/
static
int
vfp_esi_bytes_gu
(
struct
worker
*
wrk
,
const
struct
vef_priv
*
vef
,
vfp_esi_bytes_gu
(
struct
busyobj
*
bo
,
const
struct
vef_priv
*
vef
,
struct
http_conn
*
htc
,
ssize_t
bytes
)
{
struct
vgz
*
vg
;
...
...
@@ -123,9 +123,9 @@ vfp_esi_bytes_gu(struct worker *wrk, const struct vef_priv *vef,
size_t
dl
;
const
void
*
dp
;
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER
_MAGIC
);
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ
_MAGIC
);
CHECK_OBJ_NOTNULL
(
vef
,
VEF_MAGIC
);
vg
=
wrk
->
busyobj
->
vgz_rx
;
vg
=
bo
->
vgz_rx
;
while
(
bytes
>
0
)
{
if
(
VGZ_IbufEmpty
(
vg
)
&&
bytes
>
0
)
{
...
...
@@ -135,12 +135,12 @@ vfp_esi_bytes_gu(struct worker *wrk, const struct vef_priv *vef,
VGZ_Ibuf
(
vg
,
vef
->
ibuf
,
wl
);
bytes
-=
wl
;
}
if
(
VGZ_ObufStorage
(
wrk
->
busyobj
,
vg
))
if
(
VGZ_ObufStorage
(
bo
,
vg
))
return
(
-
1
);
i
=
VGZ_Gunzip
(
vg
,
&
dp
,
&
dl
);
xxxassert
(
i
==
VGZ_OK
||
i
==
VGZ_END
);
VEP_Parse
(
wrk
->
busyobj
,
dp
,
dl
);
wrk
->
busyobj
->
fetch_obj
->
len
+=
dl
;
VEP_Parse
(
bo
,
dp
,
dl
);
bo
->
fetch_obj
->
len
+=
dl
;
}
return
(
1
);
}
...
...
@@ -161,13 +161,13 @@ vfp_esi_bytes_gu(struct worker *wrk, const struct vef_priv *vef,
*/
static
int
vfp_vep_inject
(
const
struct
worker
*
wrk
,
struct
vef_priv
*
vef
,
ssize_t
wl
)
vfp_vep_inject
(
const
struct
busyobj
*
bo
,
struct
vef_priv
*
vef
,
ssize_t
wl
)
{
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER
_MAGIC
);
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ
_MAGIC
);
CHECK_OBJ_NOTNULL
(
vef
,
VEF_MAGIC
);
VEP_Parse
(
wrk
->
busyobj
,
vef
->
ibuf_i
,
wl
);
VEP_Parse
(
bo
,
vef
->
ibuf_i
,
wl
);
vef
->
ibuf_i
+=
wl
;
assert
(
vef
->
ibuf_o
>=
vef
->
ibuf
&&
vef
->
ibuf_o
<=
vef
->
ibuf_i
);
if
(
vef
->
error
)
{
...
...
@@ -183,16 +183,15 @@ vfp_vep_inject(const struct worker *wrk, struct vef_priv *vef, ssize_t wl)
}
static
ssize_t
vfp_vep_callback
(
struct
worker
*
wrk
,
ssize_t
l
,
enum
vgz_flag
flg
)
vfp_vep_callback
(
struct
busyobj
*
bo
,
ssize_t
l
,
enum
vgz_flag
flg
)
{
struct
vef_priv
*
vef
;
size_t
dl
;
const
void
*
dp
;
int
i
;
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER_MAGIC
);
CHECK_OBJ_NOTNULL
(
wrk
->
busyobj
,
BUSYOBJ_MAGIC
);
vef
=
wrk
->
busyobj
->
vef_priv
;
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ_MAGIC
);
vef
=
bo
->
vef_priv
;
CHECK_OBJ_NOTNULL
(
vef
,
VEF_MAGIC
);
assert
(
l
>=
0
);
...
...
@@ -211,14 +210,14 @@ vfp_vep_callback(struct worker *wrk, ssize_t l, enum vgz_flag flg)
VGZ_Ibuf
(
vef
->
vgz
,
vef
->
ibuf_o
,
l
);
do
{
if
(
VGZ_ObufStorage
(
wrk
->
busyobj
,
vef
->
vgz
))
{
if
(
VGZ_ObufStorage
(
bo
,
vef
->
vgz
))
{
vef
->
error
=
ENOMEM
;
vef
->
tot
+=
l
;
return
(
vef
->
tot
);
}
i
=
VGZ_Gzip
(
vef
->
vgz
,
&
dp
,
&
dl
,
flg
);
vef
->
tot
+=
dl
;
wrk
->
busyobj
->
fetch_obj
->
len
+=
dl
;
bo
->
fetch_obj
->
len
+=
dl
;
}
while
(
!
VGZ_IbufEmpty
(
vef
->
vgz
)
||
(
flg
!=
VGZ_NORMAL
&&
VGZ_ObufFull
(
vef
->
vgz
)));
assert
(
VGZ_IbufEmpty
(
vef
->
vgz
));
...
...
@@ -235,14 +234,13 @@ vfp_vep_callback(struct worker *wrk, ssize_t l, enum vgz_flag flg)
*/
static
int
vfp_esi_bytes_ug
(
const
struct
worker
*
wrk
,
struct
vef_priv
*
vef
,
vfp_esi_bytes_ug
(
const
struct
busyobj
*
bo
,
struct
vef_priv
*
vef
,
struct
http_conn
*
htc
,
ssize_t
bytes
)
{
ssize_t
wl
;
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER_MAGIC
);
CHECK_OBJ_NOTNULL
(
vef
,
VEF_MAGIC
);
CHECK_OBJ_NOTNULL
(
wrk
->
busyobj
,
BUSYOBJ_MAGIC
);
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ_MAGIC
);
while
(
bytes
>
0
)
{
wl
=
vef
->
ibuf_sz
-
(
vef
->
ibuf_i
-
vef
->
ibuf
);
...
...
@@ -250,7 +248,7 @@ vfp_esi_bytes_ug(const struct worker *wrk, struct vef_priv *vef,
if
(
wl
<=
0
)
return
(
wl
);
bytes
-=
wl
;
if
(
vfp_vep_inject
(
wrk
,
vef
,
wl
))
if
(
vfp_vep_inject
(
bo
,
vef
,
wl
))
return
(
-
1
);
}
return
(
1
);
...
...
@@ -261,7 +259,7 @@ vfp_esi_bytes_ug(const struct worker *wrk, struct vef_priv *vef,
*/
static
int
vfp_esi_bytes_gg
(
const
struct
worker
*
wrk
,
struct
vef_priv
*
vef
,
vfp_esi_bytes_gg
(
const
struct
busyobj
*
bo
,
struct
vef_priv
*
vef
,
struct
http_conn
*
htc
,
size_t
bytes
)
{
ssize_t
wl
;
...
...
@@ -269,9 +267,8 @@ vfp_esi_bytes_gg(const struct worker *wrk, struct vef_priv *vef,
const
void
*
dp
;
int
i
;
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER_MAGIC
);
CHECK_OBJ_NOTNULL
(
vef
,
VEF_MAGIC
);
CHECK_OBJ_NOTNULL
(
wrk
->
busyobj
,
BUSYOBJ_MAGIC
);
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ_MAGIC
);
while
(
bytes
>
0
)
{
wl
=
vef_read
(
htc
,
vef
->
ibuf2
,
vef
->
ibuf2_sz
,
bytes
);
...
...
@@ -279,16 +276,16 @@ vfp_esi_bytes_gg(const struct worker *wrk, struct vef_priv *vef,
return
(
wl
);
bytes
-=
wl
;
VGZ_Ibuf
(
wrk
->
busyobj
->
vgz_rx
,
vef
->
ibuf2
,
wl
);
VGZ_Ibuf
(
bo
->
vgz_rx
,
vef
->
ibuf2
,
wl
);
do
{
wl
=
vef
->
ibuf_sz
-
(
vef
->
ibuf_i
-
vef
->
ibuf
);
VGZ_Obuf
(
wrk
->
busyobj
->
vgz_rx
,
vef
->
ibuf_i
,
wl
);
i
=
VGZ_Gunzip
(
wrk
->
busyobj
->
vgz_rx
,
&
dp
,
&
dl
);
VGZ_Obuf
(
bo
->
vgz_rx
,
vef
->
ibuf_i
,
wl
);
i
=
VGZ_Gunzip
(
bo
->
vgz_rx
,
&
dp
,
&
dl
);
/* XXX: check i */
assert
(
i
>=
VGZ_OK
);
if
(
dl
>
0
&&
vfp_vep_inject
(
wrk
,
vef
,
dl
))
if
(
dl
>
0
&&
vfp_vep_inject
(
bo
,
vef
,
dl
))
return
(
-
1
);
}
while
(
!
VGZ_IbufEmpty
(
wrk
->
busyobj
->
vgz_rx
));
}
while
(
!
VGZ_IbufEmpty
(
bo
->
vgz_rx
));
}
return
(
1
);
}
...
...
@@ -314,20 +311,20 @@ vfp_esi_begin(struct worker *wrk, size_t estimate)
AZ
(
bo
->
vgz_rx
);
if
(
bo
->
is_gzip
&&
bo
->
do_gunzip
)
{
bo
->
vgz_rx
=
VGZ_NewUngzip
(
wrk
->
vsl
,
"U F E"
);
VEP_Init
(
wrk
,
NULL
);
VEP_Init
(
bo
,
NULL
);
vef
->
ibuf_sz
=
cache_param
->
gzip_buffer
;
}
else
if
(
bo
->
is_gunzip
&&
bo
->
do_gzip
)
{
vef
->
vgz
=
VGZ_NewGzip
(
wrk
->
vsl
,
"G F E"
);
VEP_Init
(
wrk
,
vfp_vep_callback
);
VEP_Init
(
bo
,
vfp_vep_callback
);
vef
->
ibuf_sz
=
cache_param
->
gzip_buffer
;
}
else
if
(
bo
->
is_gzip
)
{
bo
->
vgz_rx
=
VGZ_NewUngzip
(
wrk
->
vsl
,
"U F E"
);
vef
->
vgz
=
VGZ_NewGzip
(
wrk
->
vsl
,
"G F E"
);
VEP_Init
(
wrk
,
vfp_vep_callback
);
VEP_Init
(
bo
,
vfp_vep_callback
);
vef
->
ibuf_sz
=
cache_param
->
gzip_buffer
;
vef
->
ibuf2_sz
=
cache_param
->
gzip_buffer
;
}
else
{
VEP_Init
(
wrk
,
NULL
);
VEP_Init
(
bo
,
NULL
);
}
if
(
vef
->
ibuf_sz
>
0
)
{
vef
->
ibuf
=
calloc
(
1L
,
vef
->
ibuf_sz
);
...
...
@@ -359,13 +356,13 @@ vfp_esi_bytes(struct worker *wrk, struct http_conn *htc, ssize_t bytes)
AN
(
bo
->
vep
);
assert
(
&
bo
->
htc
==
htc
);
if
(
bo
->
is_gzip
&&
bo
->
do_gunzip
)
i
=
vfp_esi_bytes_gu
(
wrk
,
vef
,
htc
,
bytes
);
i
=
vfp_esi_bytes_gu
(
bo
,
vef
,
htc
,
bytes
);
else
if
(
bo
->
is_gunzip
&&
bo
->
do_gzip
)
i
=
vfp_esi_bytes_ug
(
wrk
,
vef
,
htc
,
bytes
);
i
=
vfp_esi_bytes_ug
(
bo
,
vef
,
htc
,
bytes
);
else
if
(
bo
->
is_gzip
)
i
=
vfp_esi_bytes_gg
(
wrk
,
vef
,
htc
,
bytes
);
i
=
vfp_esi_bytes_gg
(
bo
,
vef
,
htc
,
bytes
);
else
i
=
vfp_esi_bytes_uu
(
wrk
,
vef
,
htc
,
bytes
);
i
=
vfp_esi_bytes_uu
(
bo
,
vef
,
htc
,
bytes
);
AN
(
bo
->
vep
);
return
(
i
);
}
...
...
@@ -389,7 +386,7 @@ vfp_esi_end(struct worker *wrk)
if
(
bo
->
vgz_rx
!=
NULL
&&
VGZ_Destroy
(
&
bo
->
vgz_rx
)
!=
VGZ_END
)
retval
=
FetchError
(
bo
,
"Gunzip+ESI Failed at the very end"
);
vsb
=
VEP_Finish
(
wrk
);
vsb
=
VEP_Finish
(
bo
);
if
(
vsb
!=
NULL
)
{
if
(
!
retval
)
{
...
...
bin/varnishd/cache/cache_esi_parse.c
View file @
40761260
...
...
@@ -60,7 +60,6 @@ struct vep_state {
#define VEP_MAGIC 0x55cb9b82
struct
vsb
*
vsb
;
struct
worker
*
wrk
;
struct
busyobj
*
bo
;
int
dogzip
;
vep_callback_t
*
cb
;
...
...
@@ -329,7 +328,7 @@ vep_mark_common(struct vep_state *vep, const char *p, enum vep_mark mark)
*/
if
(
vep
->
last_mark
!=
mark
&&
(
vep
->
o_wait
>
0
||
vep
->
startup
))
{
lcb
=
vep
->
cb
(
vep
->
wrk
,
0
,
lcb
=
vep
->
cb
(
vep
->
bo
,
0
,
mark
==
VERBATIM
?
VGZ_RESET
:
VGZ_ALIGN
);
if
(
lcb
-
vep
->
o_last
>
0
)
vep_emit_common
(
vep
,
lcb
-
vep
->
o_last
,
vep
->
last_mark
);
...
...
@@ -339,7 +338,7 @@ vep_mark_common(struct vep_state *vep, const char *p, enum vep_mark mark)
/* Transfer pending bytes CRC into active mode CRC */
if
(
vep
->
o_pending
)
{
(
void
)
vep
->
cb
(
vep
->
wrk
,
vep
->
o_pending
,
VGZ_NORMAL
);
(
void
)
vep
->
cb
(
vep
->
bo
,
vep
->
o_pending
,
VGZ_NORMAL
);
if
(
vep
->
o_crc
==
0
)
{
vep
->
crc
=
vep
->
crcp
;
vep
->
o_crc
=
vep
->
o_pending
;
...
...
@@ -363,7 +362,7 @@ vep_mark_common(struct vep_state *vep, const char *p, enum vep_mark mark)
vep
->
o_wait
+=
l
;
vep
->
last_mark
=
mark
;
(
void
)
vep
->
cb
(
vep
->
wrk
,
l
,
VGZ_NORMAL
);
(
void
)
vep
->
cb
(
vep
->
bo
,
l
,
VGZ_NORMAL
);
}
static
void
...
...
@@ -500,7 +499,7 @@ vep_do_include(struct vep_state *vep, enum dowhat what)
VSB_printf
(
vep
->
vsb
,
"%c"
,
0
);
}
else
{
VSB_printf
(
vep
->
vsb
,
"%c"
,
0
);
url
=
vep
->
wrk
->
busyobj
->
bereq
->
hd
[
HTTP_HDR_URL
];
url
=
vep
->
bo
->
bereq
->
hd
[
HTTP_HDR_URL
];
/* Look for the last / before a '?' */
h
=
NULL
;
for
(
q
=
url
.
b
;
q
<
url
.
e
&&
*
q
!=
'?'
;
q
++
)
...
...
@@ -979,14 +978,14 @@ VEP_Parse(const struct busyobj *bo, const char *p, size_t l)
*/
static
ssize_t
__match_proto__
()
vep_default_cb
(
struct
worker
*
wrk
,
ssize_t
l
,
enum
vgz_flag
flg
)
vep_default_cb
(
struct
busyobj
*
bo
,
ssize_t
l
,
enum
vgz_flag
flg
)
{
struct
vep_state
*
vep
;
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER_MAGIC
);
CHECK_OBJ_NOTNULL
(
wrk
->
busyobj
,
BUSYOBJ_MAGIC
);
vep
=
wrk
->
busyobj
->
vep
;
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ_MAGIC
);
vep
=
bo
->
vep
;
CHECK_OBJ_NOTNULL
(
vep
,
VEP_MAGIC
);
assert
(
vep
->
bo
==
bo
);
(
void
)
flg
;
vep
->
cb_x
+=
l
;
return
(
vep
->
cb_x
);
...
...
@@ -996,23 +995,21 @@ vep_default_cb(struct worker *wrk, ssize_t l, enum vgz_flag flg)
*/
void
VEP_Init
(
struct
worker
*
wrk
,
vep_callback_t
*
cb
)
VEP_Init
(
struct
busyobj
*
bo
,
vep_callback_t
*
cb
)
{
struct
vep_state
*
vep
;
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER_MAGIC
);
CHECK_OBJ_NOTNULL
(
wrk
->
busyobj
,
BUSYOBJ_MAGIC
);
AZ
(
wrk
->
busyobj
->
vep
);
vep
=
(
void
*
)
WS_Alloc
(
wrk
->
busyobj
->
ws
,
sizeof
*
vep
);
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ_MAGIC
);
AZ
(
bo
->
vep
);
vep
=
(
void
*
)
WS_Alloc
(
bo
->
ws
,
sizeof
*
vep
);
AN
(
vep
);
memset
(
vep
,
0
,
sizeof
*
vep
);
vep
->
magic
=
VEP_MAGIC
;
vep
->
wrk
=
wrk
;
vep
->
bo
=
wrk
->
busyobj
;
vep
->
bo
=
bo
;
vep
->
vsb
=
VSB_new_auto
();
AN
(
vep
->
vsb
);
wrk
->
busyobj
->
vep
=
vep
;
bo
->
vep
=
vep
;
if
(
cb
!=
NULL
)
{
vep
->
dogzip
=
1
;
...
...
@@ -1043,25 +1040,25 @@ VEP_Init(struct worker *wrk, vep_callback_t *cb)
*/
struct
vsb
*
VEP_Finish
(
const
struct
worker
*
wrk
)
VEP_Finish
(
struct
busyobj
*
bo
)
{
struct
vep_state
*
vep
;
ssize_t
l
,
lcb
;
CHECK_OBJ_NOTNULL
(
wrk
,
WORKER_MAGIC
);
CHECK_OBJ_NOTNULL
(
wrk
->
busyobj
,
BUSYOBJ_MAGIC
);
vep
=
wrk
->
busyobj
->
vep
;
CHECK_OBJ_NOTNULL
(
bo
,
BUSYOBJ_MAGIC
);
vep
=
bo
->
vep
;
CHECK_OBJ_NOTNULL
(
vep
,
VEP_MAGIC
);
assert
(
vep
->
bo
==
bo
);
if
(
vep
->
o_pending
)
vep_mark_common
(
vep
,
vep
->
ver_p
,
vep
->
last_mark
);
if
(
vep
->
o_wait
>
0
)
{
lcb
=
vep
->
cb
(
vep
->
wrk
,
0
,
VGZ_ALIGN
);
lcb
=
vep
->
cb
(
vep
->
bo
,
0
,
VGZ_ALIGN
);
vep_emit_common
(
vep
,
lcb
-
vep
->
o_last
,
vep
->
last_mark
);
}
(
void
)
vep
->
cb
(
vep
->
wrk
,
0
,
VGZ_FINISH
);
(
void
)
vep
->
cb
(
vep
->
bo
,
0
,
VGZ_FINISH
);
wrk
->
busyobj
->
vep
=
NULL
;
bo
->
vep
=
NULL
;
AZ
(
VSB_finish
(
vep
->
vsb
));
l
=
VSB_len
(
vep
->
vsb
);
if
(
vep
->
esi_found
&&
l
>
0
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment