diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/socat/Makefile | 20 | ||||
-rw-r--r-- | net/socat/distinfo | 6 | ||||
-rw-r--r-- | net/socat/files/patch-socat-maxfds | 442 | ||||
-rw-r--r-- | net/socat/files/patch-socat-servicenames | 31 | ||||
-rw-r--r-- | net/socat/files/socat.in | 25 |
5 files changed, 37 insertions, 487 deletions
diff --git a/net/socat/Makefile b/net/socat/Makefile index b8f70d8b8e55..cfb3d79ee741 100644 --- a/net/socat/Makefile +++ b/net/socat/Makefile @@ -1,24 +1,22 @@ -# ex:ts=8 # Ports collection makefile for: socat -# Date created: May 14, 2002 -# Whom: ijliao +# Date created: May 14, 2002 +# Whom: ijliao # # $FreeBSD$ # PORTNAME= socat -PORTVERSION= 1.6.0.0 -PORTREVISION= 1 -CATEGORIES= net -MASTER_SITES= http://www.dest-unreach.org/socat/download/ +PORTVERSION= 1.7.0.0 +CATEGORIES= net ipv6 +MASTER_SITES= http://www.dest-unreach.org/socat/download/ \ + CRITICAL -MAINTAINER= ports@FreeBSD.org +MAINTAINER= ehaupt@FreeBSD.org COMMENT= Multipurpose relay and more -#WRKSRC= ${WRKDIR}/${PORTNAME}-${PORTVERSION:R:R} -USE_BZIP2= yes - GNU_CONFIGURE= yes +USE_BZIP2= yes +USE_RC_SUBR= socat MAN1= socat.1 diff --git a/net/socat/distinfo b/net/socat/distinfo index 7efe8a9c73ac..7868cc802219 100644 --- a/net/socat/distinfo +++ b/net/socat/distinfo @@ -1,3 +1,3 @@ -MD5 (socat-1.6.0.0.tar.bz2) = 810135eb1c3e892b1577735b7deca8ef -SHA256 (socat-1.6.0.0.tar.bz2) = 157090b94ab616eac5598bc246c7a3f8c5867ecbdf31c7c2c1c364c7bf8a01c8 -SIZE (socat-1.6.0.0.tar.bz2) = 343285 +MD5 (socat-1.7.0.0.tar.bz2) = be5f942c44dafefa58365e9dc3ada81f +SHA256 (socat-1.7.0.0.tar.bz2) = 827c8ccd508ad12c999208d42867ec8334e39a425d3984eda78a34449d414f25 +SIZE (socat-1.7.0.0.tar.bz2) = 418842 diff --git a/net/socat/files/patch-socat-maxfds b/net/socat/files/patch-socat-maxfds deleted file mode 100644 index 424a5942ea27..000000000000 --- a/net/socat/files/patch-socat-maxfds +++ /dev/null @@ -1,442 +0,0 @@ -diff -r -N -U 3 socat-1.6.0.0/procan.c socat-1.6.0.0+maxfds/procan.c ---- procan.c.orig 2006-12-28 08:25:01.000000000 +0100 -+++ procan.c 2007-04-05 12:41:26.000000000 +0200 -@@ -161,6 +161,10 @@ - #endif - } - -+ /* C defines */ -+ fprintf(outfile, "#define FD_SETSIZE %u\n", FD_SETSIZE); -+ fprintf(outfile, "#define FOPEN_MAX %u\n", FOPEN_MAX); -+ - /* file descriptors */ - - /* what was this for?? */ -diff -r -N -U 3 socat-1.6.0.0/socat.c socat-1.6.0.0+maxfds/socat.c ---- socat.c.orig 2007-03-06 22:03:28.000000000 +0100 -+++ socat.c 2007-03-31 22:24:37.000000000 +0200 -@@ -642,8 +642,8 @@ - returns >0 if child died and left data - */ - int childleftdata(xiofile_t *xfd) { -- fd_set in, out, expt; -- int retval; -+ fd_set *in = NULL, *out = NULL, *expt = NULL; -+ int max, retval; - /* have to check if a child process died before, but left read data */ - if (XIO_READABLE(xfd) && - (XIO_RDSTREAM(xfd)->howtoend == END_KILL || -@@ -652,25 +652,59 @@ - XIO_RDSTREAM(xfd)->para.exec.pid == 0) { - struct timeval time0 = { 0,0 }; - -- FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); -+#ifndef howmany -+#define howmany(x, y) (((x) + ((y) - 1)) / (y)) -+#endif -+ -+#ifndef NFDBITS -+# ifndef HAVE_FDS_BITS -+# define NFDBITS (sizeof(__fd_mask) * 8) -+# else -+# define NFDBITS (sizeof(fd_mask) * 8) -+# endif -+#endif -+ -+#ifndef HAVE_FDS_BITS -+# define FD_MASK_SIZE (sizeof(__fd_mask)) -+#else -+# define FD_MASK_SIZE (sizeof(fd_mask)) -+#endif -+ -+ max = XIO_GETRDFD(xfd); -+ in = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE); -+ out = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE); -+ expt = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE); -+ if (in == NULL || out == NULL || expt == NULL) { -+ Error2("select(%d): %s", max+1, strerror(errno)); -+ if (in != NULL) -+ free(in); -+ if (out != NULL) -+ free(out); -+ if (expt != NULL) -+ free(expt); -+ return -1; -+ } - if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) { -- FD_SET(XIO_GETRDFD(xfd), &in); -+ FD_SET(XIO_GETRDFD(xfd), in); - /*0 FD_SET(XIO_GETRDFD(xfd), &expt);*/ - } - do { -- retval = Select(FOPEN_MAX, &in, &out, &expt, &time0); -+ retval = Select(max+1, in, out, expt, &time0); - } while (retval < 0 && errno == EINTR); - - if (retval < 0) { - #if HAVE_FDS_BITS - Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s", -- FOPEN_MAX, in.fds_bits[0], out.fds_bits[0], -- expt.fds_bits[0], strerror(errno)); -+ max+1, in->fds_bits[0], out->fds_bits[0], -+ expt->fds_bits[0], strerror(errno)); - #else - Error5("select(%d, &0x%lx, &0x%lx, &0x%lx, {0}): %s", -- FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0], -- expt.__fds_bits[0], strerror(errno)); -+ max+1, in->__fds_bits[0], out->__fds_bits[0], -+ expt->__fds_bits[0], strerror(errno)); - #endif -+ free(in); -+ free(out); -+ free(expt); - return -1; - } else if (retval == 0) { - Info("terminated child did not leave data for us"); -@@ -679,6 +713,9 @@ - closing = MAX(closing, 1); - } - } -+ free(in); -+ free(out); -+ free(expt); - return 0; - } - -@@ -694,14 +731,34 @@ - and their options are set/applied - returns -1 on error or 0 on success */ - int _socat(void) { -- fd_set in, out, expt; -- int retval; -+ fd_set *in, *out, *expt; -+ int max, retval; - unsigned char *buff; - ssize_t bytes1, bytes2; - int polling = 0; /* handling ignoreeof */ - int wasaction = 1; /* last select was active, do NOT sleep before next */ - struct timeval total_timeout; /* the actual total timeout timer */ - -+#ifndef MAX -+# define MAX(x, y) (((y) > (x)) ? (y) : (x)) -+#endif -+ -+ max = MAX( -+ MAX(XIO_GETRDFD(sock1), XIO_GETWRFD(sock1)), -+ MAX(XIO_GETRDFD(sock2), XIO_GETWRFD(sock2))); -+ in = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE); -+ out = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE); -+ expt = (fd_set *)Calloc(howmany(max+1, NFDBITS), FD_MASK_SIZE); -+ if (in == NULL || out == NULL || expt == NULL) { -+ Error2("select(%d): %s", max+1, strerror(errno)); -+ if (in != NULL) -+ free(in); -+ if (out != NULL) -+ free(out); -+ if (expt != NULL) -+ free(expt); -+ return -1; -+ } - #if WITH_FILAN - if (socat_opts.debug) { - int fdi, fdo; -@@ -733,7 +790,7 @@ - - /* when converting nl to crnl, size might double */ - buff = Malloc(2*socat_opts.bufsiz+1); -- if (buff == NULL) return -1; -+ if (buff == NULL) { free(in); free(out); free(expt); return -1; } - - if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') { - Info("switching to syslog"); -@@ -772,6 +829,9 @@ - if (total_timeout.tv_sec < 0 || - total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) { - Notice("inactivity timeout triggered"); -+ free(in); -+ free(out); -+ free(expt); - return 0; - } - } -@@ -803,7 +863,9 @@ - - do { - int _errno; -- FD_ZERO(&in); FD_ZERO(&out); FD_ZERO(&expt); -+ memset(in, 0, howmany(max+1, NFDBITS) * FD_MASK_SIZE); -+ memset(out, 0, howmany(max+1, NFDBITS) * FD_MASK_SIZE); -+ memset(expt, 0, howmany(max+1, NFDBITS) * FD_MASK_SIZE); - - childleftdata(sock1); - childleftdata(sock2); -@@ -819,23 +881,23 @@ - !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) && - !socat_opts.righttoleft) { - if (!mayrd1) { -- FD_SET(XIO_GETRDFD(sock1), &in); -+ FD_SET(XIO_GETRDFD(sock1), in); - } - if (!maywr2) { -- FD_SET(XIO_GETWRFD(sock2), &out); -+ FD_SET(XIO_GETWRFD(sock2), out); - } - } - if (XIO_READABLE(sock2) && - !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) && - !socat_opts.lefttoright) { - if (!mayrd2) { -- FD_SET(XIO_GETRDFD(sock2), &in); -+ FD_SET(XIO_GETRDFD(sock2), in); - } - if (!maywr1) { -- FD_SET(XIO_GETWRFD(sock1), &out); -+ FD_SET(XIO_GETWRFD(sock1), out); - } - } -- retval = Select(FOPEN_MAX, &in, &out, &expt, to); -+ retval = Select(max+1, in, out, expt, to); - _errno = errno; - if (retval < 0 && errno == EINTR) { - Info1("select(): %s", strerror(errno)); -@@ -851,15 +913,18 @@ - if (retval < 0) { - #if HAVE_FDS_BITS - Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s", -- FOPEN_MAX, in.fds_bits[0], out.fds_bits[0], -- expt.fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0, -+ max+1, in->fds_bits[0], out->fds_bits[0], -+ expt->fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0, - strerror(errno)); - #else - Error7("select(%d, &0x%lx, &0x%lx, &0x%lx, %s%lu): %s", -- FOPEN_MAX, in.__fds_bits[0], out.__fds_bits[0], -- expt.__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0, -+ max+1, in->__fds_bits[0], out->__fds_bits[0], -+ expt->__fds_bits[0], to?"&":"NULL/", to?to->tv_sec:0, - strerror(errno)); - #endif -+ free(in); -+ free(out); -+ free(expt); - return -1; - } else if (retval == 0) { - Info2("select timed out (no data within %ld.%06ld seconds)", -@@ -872,6 +937,9 @@ - socat_opts.total_timeout.tv_usec != 0) { - /* there was a total inactivity timeout */ - Notice("inactivity timeout triggered"); -+ free(in); -+ free(out); -+ free(expt); - return 0; - } - -@@ -884,17 +952,17 @@ - } - - if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 && -- FD_ISSET(XIO_GETRDFD(sock1), &in)) { -+ FD_ISSET(XIO_GETRDFD(sock1), in)) { - mayrd1 = true; - } - if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 && -- FD_ISSET(XIO_GETRDFD(sock2), &in)) { -+ FD_ISSET(XIO_GETRDFD(sock2), in)) { - mayrd2 = true; - } -- if (XIO_GETWRFD(sock1) >= 0 && FD_ISSET(XIO_GETWRFD(sock1), &out)) { -+ if (XIO_GETWRFD(sock1) >= 0 && FD_ISSET(XIO_GETWRFD(sock1), out)) { - maywr1 = true; - } -- if (XIO_GETWRFD(sock2) >= 0 && FD_ISSET(XIO_GETWRFD(sock2), &out)) { -+ if (XIO_GETWRFD(sock2) >= 0 && FD_ISSET(XIO_GETWRFD(sock2), out)) { - maywr2 = true; - } - -@@ -989,6 +1057,10 @@ - xioclose(sock1); - xioclose(sock2); - -+ free(in); -+ free(out); -+ free(expt); -+ - return 0; - } - -diff -r -N -U 3 socat-1.6.0.0/test.sh socat-1.6.0.0+maxfds/test.sh ---- test.sh.orig 2007-03-06 22:06:20.000000000 +0100 -+++ test.sh 2007-04-06 10:16:30.000000000 +0200 -@@ -1425,7 +1425,8 @@ - local arg1="$3"; [ -z "$arg1" ] && arg1="-" - local arg2="$4"; [ -z "$arg2" ] && arg2="echo" - local opts="$5" -- local T="$6"; [ -z "$T" ] && T=0 -+ local redir="$6" -+ local T="$7"; [ -z "$T" ] && T=0 - local tf="$td/test$N.stdout" - local te="$td/test$N.stderr" - local tdiff="$td/test$N.diff" -@@ -1435,14 +1436,16 @@ - $PRINTF "test $F_n %s... " $num "$title" - #echo "$da" |$cmd >"$tf" 2>"$te" - #set -vx -- (echo "$da"; sleep $T) |$SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" & -+# (echo "$da"; sleep $T) |($SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te"; echo $? >"$td/test$N.rc") & -+# echo eval $SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" $redir -+ (echo "$da"; sleep $T) |(eval $SOCAT $opts "$arg1" "$arg2" >"$tf" 2>"$te" $redir; echo $? >"$td/test$N.rc") & - export rc1=$! - #sleep 5 && kill $rc1 2>/dev/null & - # rc2=$! - wait $rc1 - # kill $rc2 2>/dev/null --#set +vx -- if [ "$?" != 0 ]; then -+set +vx -+ if [ "$(cat "$td/test$N.rc")" != 0 ]; then - $PRINTF "$FAILED: $SOCAT:\n" - echo "$SOCAT $opts $arg1 $arg2" - cat "$te" -@@ -4129,7 +4132,7 @@ - case "$TESTS" in - *%functions%*|*%$NAME%*) - TEST="$NAME: inheritance of stdout to single exec with socketpair" --testecho "$N" "$TEST" "-!!exec:cat" "" "$opts" 1 -+testecho "$N" "$TEST" "-!!exec:cat" "" "$opts" "" 1 - esac - N=$((N+1)) - -@@ -4137,7 +4140,7 @@ - case "$TESTS" in - *%functions%*|*%$NAME%*) - TEST="$NAME: inheritance of stdout to single exec with pipe" --testecho "$N" "$TEST" "-!!exec:cat,pipes" "" "$opts" 1 -+testecho "$N" "$TEST" "-!!exec:cat,pipes" "" "$opts" "" 1 - esac - N=$((N+1)) - -@@ -4149,7 +4152,7 @@ - $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N - numCANT=$((numCANT+1)) - else --testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" 1 -+testecho "$N" "$TEST" "-!!exec:cat,pty,raw" "" "$opts" "" 1 - fi - esac - N=$((N+1)) -@@ -4178,7 +4181,7 @@ - $PRINTF "test $F_n $TEST... ${YELLOW}PTY not available${NORMAL}\n" $N - numCANT=$((numCANT+1)) - else --testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" $MISCDELAY -+testecho "$N" "$TEST" "exec:cat,pty,raw!!-" "" "$opts" "" $MISCDELAY - fi - esac - N=$((N+1)) -@@ -5662,7 +5665,7 @@ - case "$TESTS" in - *%parse%*|*%functions%*|*%$NAME%*) - TEST="$NAME: does lexical analysis work sensibly (exec)" --testecho "$N" "$TEST" "" "exec:'$SOCAT - exec:$CAT,pipes'" "$opts" 1 -+testecho "$N" "$TEST" "" "exec:'$SOCAT - exec:$CAT,pipes'" "$opts" "" 1 - esac - N=$((N+1)) - -@@ -5670,7 +5673,7 @@ - case "$TESTS" in - *%parse%*|*%functions%*|*%$NAME%*) - TEST="$NAME: does lexical analysis work sensibly (system)" --testecho "$N" "$TEST" "" "system:\"$SOCAT - exec:$CAT,pipes\"" "$opts" 1 -+testecho "$N" "$TEST" "" "system:\"$SOCAT - exec:$CAT,pipes\"" "$opts" "" 1 - esac - N=$((N+1)) - -@@ -7737,6 +7740,81 @@ - esac - N=$((N+1)) - -+ -+# test: up to socat 1.6.0.0, the highest file descriptor supported in socats -+# transfer engine was FOPEN_MAX-1; this usually worked fine but would fail when -+# socat was invoked with many file descriptors already opened. socat would -+# just hang in the select() call. Daniel Lucq found this problem and provided a -+# patch that replaced the FOPEN_MAX limit: this patch not only allows FDs to be -+# up to NFDBITS-1, but should work even when the processes maximum number of -+# open files is increased with ulimit -n. -+# FOPEN_MAX on different OS's: -+# OS FOPEN_ ulimit ulimit FD_ -+# MAX -H -n -S -n SETSIZE -+# Linux 2.6: 16 1024 1024 1024 -+# HP-UX 11.11: 60 2048 2048 2048 -+# FreeBSD: 20 11095 11095 1024 -+# Cygwin: 20 unlimit 256 64 -+# AIX: 32767 65534 65534 -+NAME=EXCEED_FOPEN_MAX -+case "$TESTS" in -+*%functions%*|*%maxfds%*|*%$NAME%*) -+TEST="$NAME: more than FOPEN_MAX FDs in use" -+# this test opens a number of FDs before socat is invoked. socat will have to -+# allocate higher FD numbers and thus hang if it cannot handle them. -+REDIR= -+FOPEN_MAX=$($PROCAN |grep '^#define FOPEN_MAX' |awk '{print($3);}') -+OPEN_FILES=$FOPEN_MAX # more than the highest FOPEN_MAX -+i=3; while [ "$i" -lt "$OPEN_FILES" ]; do -+ REDIR="$REDIR $i>&2" -+ i=$((i+1)) -+done -+#echo $REDIR -+#testecho "$N" "$TEST" "" "pipe" "$opts -T 3" "" 1 -+#set -vx -+testecho "$N" "$TEST" "" "pipe" "$opts -T 1" "$REDIR" 1 -+#set +vx -+esac -+N=$((N+1)) -+ -+OPEN_FILES="$(ulimit -n)" -+NAME=EXCEED_FD_SETSIZE -+case "$TESTS" in -+*%functions%*|*%maxfds%*|*%root%*|*%$NAME%*) -+TEST="$NAME: more than FD_SETSIZE FDs in use" -+# this test opens a number of FDs before socat is invoked. This number exceeds -+# the size of the fd_set type proposed for use with select(). socat will have -+# to allocate space for a larger record and will hang or crash if it cannot -+# handle this. -+# ulimit -n must be above FD_SETSIZE which might require root -+REDIR= -+FD_SETSIZE=$($PROCAN |grep '^#define FD_SETSIZE' |awk '{print($3);}') -+OPEN_FILES=$(($FD_SETSIZE+2)) # more than the highest FD_SETSIZE -+while true; do # just go once; so we can break inside -+ if [ $(ulimit -S -n) -lt $OPEN_FILES ]; then -+ # if it increases, -H must be first -+ if [ $(ulimit -H -n) -lt $OPEN_FILES ]; then -+ if ! ulimit -H -n $((OPEN_FILES)); then -+ $PRINTF "test $F_n $TEST... ${YELLOW}must be root${NORMAL}\n" $N -+ numCANT=$((numCANT+1)) -+ break; -+ fi -+ fi -+ ulimit -S -n $((OPEN_FILES)) -+ fi -+ i=3; while [ "$i" -lt "$FD_SETSIZE" ]; do -+ REDIR="$REDIR $i>&2" -+ i=$((i+1)) -+ done -+ testecho "$N" "$TEST" "" "pipe" "$opts -T 1" "$REDIR" 1 -+ set +vx -+break -+done -+;; -+esac -+N=$((N+1)) -+ -+ - echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed" - - if [ "$numFAIL" -gt 0 ]; then -diff -r -N -U 3 socat-1.6.0.0/VERSION socat-1.6.0.0+maxfds/VERSION ---- VERSION.orig 2007-03-06 21:58:44.000000000 +0100 -+++ VERSION 2007-04-06 23:20:11.000000000 +0200 -@@ -1 +1 @@ --"1.6.0.0" -+"1.6.0.0_1" diff --git a/net/socat/files/patch-socat-servicenames b/net/socat/files/patch-socat-servicenames deleted file mode 100644 index f00d72c743af..000000000000 --- a/net/socat/files/patch-socat-servicenames +++ /dev/null @@ -1,31 +0,0 @@ ---- xio-ip.c.orig Wed Mar 7 08:08:02 2007 -+++ xio-ip.c Fri Apr 27 17:10:02 2007 -@@ -144,7 +144,7 @@ - with NIS), so we handle this specially */ - if (service && isdigit(service[0]&0xff)) { - char *extra; -- port = strtoul(service, &extra, 0); -+ port = htons(strtoul(service, &extra, 0)); - if (*extra != '\0') { - Warn2("xiogetaddrinfo(, \"%s\", ...): extra trailing data \"%s\"", - service, extra); -@@ -396,15 +396,16 @@ - - #if WITH_TCP || WITH_UDP - if (service) { -- port = parseport(service, family); -+ port = parseport(service, protocol); -+ - } - if (port >= 0) { - switch (family) { - #if WITH_IP4 -- case PF_INET: sau->ip4.sin_port = htons(port); break; -+ case PF_INET: sau->ip4.sin_port = port; break; - #endif /* WITH_IP4 */ - #if WITH_IP6 -- case PF_INET6: sau->ip6.sin6_port = htons(port); break; -+ case PF_INET6: sau->ip6.sin6_port = port; break; - #endif /* WITH_IP6 */ - } - } diff --git a/net/socat/files/socat.in b/net/socat/files/socat.in new file mode 100644 index 000000000000..b3cd35c02e10 --- /dev/null +++ b/net/socat/files/socat.in @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Author: Emanuel Haupt <ehaupt@FreeBSD.org> +# +# $FreeBSD$ +# + +# PROVIDE: socat +# REQUIRE: LOGIN +# KEYWORD: shutdown + +. %%RC_SUBR%% + +name="socat" +rcvar=${name}_enable + +command=%%PREFIX%%/bin/${name} +command_args="&" + +load_rc_config $name + +: ${socat_enable="NO"} +: ${socat_flags=""} + +run_rc_command "$1" |