{"id":5866,"date":"2013-10-18T04:30:36","date_gmt":"2013-10-18T08:30:36","guid":{"rendered":"http:\/\/g33kinfo.com\/info\/?p=5866"},"modified":"2013-10-18T04:30:36","modified_gmt":"2013-10-18T08:30:36","slug":"prettyping-sh","status":"publish","type":"post","link":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/","title":{"rendered":"prettyping.sh"},"content":{"rendered":"<p>From <a href=\"http:\/\/my.opera.com\/CrazyTerabyte\/blog\/2013\/10\/18\/prettyping-sh-a-better-ui-for-watching-ping-responses\" target=\"_blank\" rel=\"noopener noreferrer\">CrazyTerabyte Blog<\/a><\/p>\n<p>prettyping.sh &#8211; A better UI for watching ping responses<\/p>\n<p>Do you run ping tool very often? Do you find yourself squeezing your eyes to see if a packet has been lost? Do you want to have a better view of the latency and of the lost packets over time? Then you need <a href=\"http:\/\/bitbucket.org\/denilsonsa\/small_scripts\/src\/tip\/prettyping.sh\" target=\"_blank\" rel=\"noopener noreferrer\">prettyping.sh<\/a>, a wrapper around the standard ping tool with the objective to make the output prettier, by making it colorful, more compact, and easier to read. How? Look at the following animated GIF (being played at 4\u00d7 the actual speed): <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/files.myopera.com\/CrazyTerabyte\/blog\/prettyping-4x.gif\" width=\"484\" height=\"329\" class=\"aligncenter\" \/><\/p>\n<p><!--more--><\/p>\n<p>Download it from from my small_scripts repository at bitbucket.org (<a href=\"http:\/\/bitbucket.org\/denilsonsa\/small_scripts\/src\/tip\/prettyping.sh\" target=\"_blank\" rel=\"noopener noreferrer\">direct link<\/a>).<\/p>\n<p><strong>A bit of history<\/strong><\/p>\n<p>prettyping.sh was originally written in January of 2008, while I was working at Vialink. I noticed that, very often, we were looking at the output of the ping tool to measure the quality of network links, by looking at a combination of packet loss ratio and latency. However, the standard ping output is too verbose, making it hard to have a quick glance at latency. Not just that, but missing\/lost packets are not reported at all. Finally, the statistics of the run are only printed at the very end, after ping finishes running. This helpful piece of information should be available all the time.<\/p>\n<p>I observed a common use-case, a common pattern in our daily work, and I noticed that our workflow could have been improved by having better tools. And so I built a better tool. (By the way, this paragraph describes something I do ALL the time.)<\/p>\n<p>Thus prettyping.sh was born. And it received essentially no updates after 2008. But recently I discovered the spark shell script in github, which made me want to implement a similar output in prettyping. So, in the last few days, I&#8217;ve been implementing many features I wanted to implement for a long time, in addition to the spark-like output.<\/p>\n<p><strong>Requirements<\/strong><\/p>\n<ul>\n<li>bash (tested on 4.20, should work on versions as old as 2008)<\/li>\n<li>gawk (GNU awk, tested on 4.0.1, should work on versions as old as 2008)<\/li>\n<li>ping (from iputils, or any other version that prints essentially the same output)<\/li>\n<\/ul>\n<p><strong>Features<\/strong><\/p>\n<ol>\n<li>Detects missing\/lost packets and marks them at the output.<\/li>\n<li>Shows live statistics, updated after each response is received.<\/li>\n<li>Two sets of statistics are calculated: one for the most recent <n> responses, and another for all responses since the start of the script.<\/n><\/li>\n<li>Correctly handles &#8220;unknown&#8221; lines, such as error messages, without messing up the output.<\/li>\n<li>Detects repeated messages and avoids printing them repeatedly.<\/li>\n<li>Fast startup, very few and lightweight dependencies (usually faster than running a Python script).<\/li>\n<li>No installation required, just run the script from anywhere (and make sure you have the 3 dependencies, most Linux distros already have them).<\/li>\n<li>Sane defaults, auto-detects terminal width (but does not detect when the terminal is resized), auto-detects if the output is a terminal. Basically, just run the script and don&#8217;t worry about the options until you need to.<\/li>\n<li>Options not recognized by prettyping are passed to the ping tool. As a wrapper, you can use the most common ping parameters in prettyping as well.<\/li>\n<li>The output can be redirected to a file (using shell redirection or pipeline). In such mode, prettyping will avoid using cursor-control escape codes.<\/li>\n<li>Colorful output (can be disabled by command-line option).<\/li>\n<li>Graphical output of the latency using unicode characters (can be disabled by command-line option).<\/li>\n<li>Intuitive output.<\/li>\n<li>It looks pretty!<\/li>\n<\/ol>\n<p><strong>Quick Install<\/strong><br \/>\n<code><br \/>\nwget https:\/\/bitbucket.org\/denilsonsa\/small_scripts\/raw\/0c59d14ca5f1aac01447e28d81f5d5c433976348\/prettyping.sh<br \/>\nchmod +x prettyping.sh<br \/>\n.\/prettyping.sh google.com<br \/>\n<\/code><\/p>\n<p><strong>Code<\/strong><br \/>\n<code><br \/>\n#!\/bin\/bash<br \/>\n#<br \/>\n# Written by Denilson Figueiredo de S\u00e1 <denilsonsa @gmail.com><br \/>\n# MIT license<br \/>\n#<br \/>\n# Requirements:<br \/>\n# * bash (tested on 4.20, should work on older versions too)<br \/>\n# * gawk (GNU awk, tested on 4.0.1, should work on older versions too)<br \/>\n# * ping (from iputils)<\/p>\n<p># TODO: Detect the following kind of message and avoid printing it repeatedly.<br \/>\n# From 192.168.1.11: icmp_seq=4 Destination Host Unreachable<br \/>\n#<br \/>\n# TODO: print the destination (also) at the bottom bar. Useful after leaving<br \/>\n# the script running for quite some time.<br \/>\n#<br \/>\n# TODO: Implement audible ping.<br \/>\n#<br \/>\n# TODO: Autodetect the width of printf numbers, so they will always line up correctly.<br \/>\n#<br \/>\n# TODO: Test the behavior of this script upon receiving out-of-order packets, like these:<br \/>\n#   http:\/\/www.blug.linux.no\/rfc1149\/pinglogg.txt<br \/>\n#<br \/>\n# TODO? How will prettyping behave if it receives a duplicate response?<\/p>\n<p>print_help() {<br \/>\n        cat < < EOF\nUsage: $MYNAME [prettyping parameters] <standard ping parameters><\/p>\n<p>This script is a wrapper around the system's \"ping\" tool. It will substitute<br \/>\neach ping response line by a colored character, giving a very compact overview<br \/>\nof the ping responses.<\/p>\n<p>prettyping parameters:<br \/>\n  --[no]color      Enable\/disable color output. (default: enabled)<br \/>\n  --[no]multicolor Enable\/disable multi-color unicode output. Has no effect if<br \/>\n                     either color or unicode is disabled. (default: enabled)<br \/>\n  --[no]unicode    Enable\/disable unicode characters. (default: enabled)<br \/>\n  --[no]terminal   Force the output designed to a terminal. (default: auto)<br \/>\n  --last <n>       Use the last \"n\" pings at the statistics line. (default: 60)<br \/>\n  --columns <\/n><n>    Override auto-detection of terminal dimensions.<br \/>\n  --lines <\/n><n>      Override auto-detection of terminal dimensions.<br \/>\n  --rttmin <\/n><n>     Minimum RTT represented in the unicode graph. (default: auto)<br \/>\n  --rttmax <\/n><n>     Maximum RTT represented in the unicode graph. (default: auto)<\/p>\n<p>ping parameters handled by prettyping:<br \/>\n  -a  Audible ping is not implemented yet.<br \/>\n  -f  Flood mode is not allowed in prettyping.<br \/>\n  -q  Quiet output is not allowed in prettyping.<br \/>\n  -R  Record route mode is not allowed in prettyping.<br \/>\n  -v  Verbose output seems to be the default mode in ping.<\/p>\n<p>Tested with Linux ping tool from \"iputils\" package:<br \/>\nhttp:\/\/www.linuxfoundation.org\/collaborate\/workgroups\/networking\/iputils<br \/>\nEOF<br \/>\n}<\/p>\n<p># Thanks to people at #bash who pointed me at<br \/>\n# http:\/\/bash-hackers.org\/wiki\/doku.php\/scripting\/posparams<br \/>\nparse_arguments() {<br \/>\n        USE_COLOR=1<br \/>\n        USE_MULTICOLOR=1<br \/>\n        USE_UNICODE=1<\/p>\n<p>        if [ -t 1 ]; then<br \/>\n                IS_TERMINAL=1<br \/>\n        else<br \/>\n                IS_TERMINAL=0<br \/>\n        fi<\/p>\n<p>        LAST_N=60<br \/>\n        OVERRIDE_COLUMNS=0<br \/>\n        OVERRIDE_LINES=0<br \/>\n        RTT_MIN=auto<br \/>\n        RTT_MAX=auto<\/p>\n<p>        PING_PARAMS=( )<\/p>\n<p>        while [[ $# != 0 ]] ; do<br \/>\n                case \"$1\" in<br \/>\n                        -h | -help | --help )<br \/>\n                                print_help<br \/>\n                                exit<br \/>\n                                ;;<\/p>\n<p>                        # Forbidden ping parameters within prettyping:<br \/>\n                        -f )<br \/>\n                                echo \"${MYNAME}: You can't use the -f (flood) option.\"<br \/>\n                                exit 1<br \/>\n                                ;;<br \/>\n                        -R )<br \/>\n                                # -R prints extra information at each ping response.<br \/>\n                                echo \"${MYNAME}: You can't use the -R (record route) option.\"<br \/>\n                                exit 1<br \/>\n                                ;;<br \/>\n                        -q )<br \/>\n                                echo \"${MYNAME}: You can't use the -q (quiet) option.\"<br \/>\n                                exit 1<br \/>\n                                ;;<br \/>\n                        -v )<br \/>\n                                # -v enables verbose output. However, it seems the output with<br \/>\n                                # or without this option is the same. Anyway, prettyping will<br \/>\n                                # strip this parameter.<br \/>\n                                ;;<br \/>\n                        # Note:<br \/>\n                        #  Small values for -s parameter prevents ping from being able to<br \/>\n                        #  calculate RTT.<\/p>\n<p>                        # New parameters:<br \/>\n                        -a )<br \/>\n                                # TODO: Implement audible ping for responses or for missing packets<br \/>\n                                ;;<\/p>\n<p>                        -color        | --color        ) USE_COLOR=1 ;;<br \/>\n                        -nocolor      | --nocolor      ) USE_COLOR=0 ;;<br \/>\n                        -multicolor   | --multicolor   ) USE_MULTICOLOR=1 ;;<br \/>\n                        -nomulticolor | --nomulticolor ) USE_MULTICOLOR=0 ;;<br \/>\n                        -unicode      | --unicode      ) USE_UNICODE=1 ;;<br \/>\n                        -nounicode    | --nounicode    ) USE_UNICODE=0 ;;<br \/>\n                        -terminal     | --terminal     ) IS_TERMINAL=1 ;;<br \/>\n                        -noterminal   | --noterminal   ) IS_TERMINAL=0 ;;<\/p>\n<p>                        #TODO: Check if these parameters are numbers.<br \/>\n                        -last    | --last    ) LAST_N=\"$2\"           ; shift ;;<br \/>\n                        -columns | --columns ) OVERRIDE_COLUMNS=\"$2\" ; shift ;;<br \/>\n                        -lines   | --lines   ) OVERRIDE_LINES=\"$2\"   ; shift ;;<br \/>\n                        -rttmin  | --rttmin  ) RTT_MIN=\"$2\"          ; shift ;;<br \/>\n                        -rttmax  | --rttmax  ) RTT_MAX=\"$2\"          ; shift ;;<\/p>\n<p>                        * )<br \/>\n                                PING_PARAMS+=(\"$1\")<br \/>\n                                ;;<br \/>\n                esac<br \/>\n                shift<br \/>\n        done<\/p>\n<p>        if [[ \"${RTT_MIN}\" -gt 0 && \"${RTT_MAX}\" -gt 0 && \"${RTT_MIN}\" -ge \"${RTT_MAX}\" ]] ; then<br \/>\n                echo \"${MYNAME}: Invalid --rttmin and -rttmax values.\"<br \/>\n                exit 1<br \/>\n        fi<\/p>\n<p>        if [[ \"${#PING_PARAMS[@]}\" = 0 ]] ; then<br \/>\n                echo \"${MYNAME}: Missing parameters, use --help for instructions.\"<br \/>\n                exit 1<br \/>\n        fi<br \/>\n}<\/p>\n<p>MYNAME=`basename \"$0\"`<br \/>\nparse_arguments \"$@\"<\/p>\n<p>export LC_ALL=C<\/p>\n<p># Warning! Ugly code ahead!<br \/>\n# The code is so ugly that the comments explaining it are<br \/>\n# bigger than the code itself!<br \/>\n#<br \/>\n# Suppose this:<br \/>\n#<br \/>\n#   cmd_a | cmd_b &<br \/>\n#<br \/>\n# I need the PID of cmd_a. How can I get it?<br \/>\n# In bash, $! will give me the PID of cmd_b.<br \/>\n#<br \/>\n# So, I came up with this ugly solution: open a subshell, like this:<br \/>\n#<br \/>\n# (<br \/>\n#       cmd_a &<br \/>\n#       echo \"This is the PID I want $!\"<br \/>\n#       wait<br \/>\n# ) | cmd_b<\/p>\n<p># Ignore Ctrl+C here.<br \/>\n# If I don't do this, this shell script is killed before<br \/>\n# ping and gawk can finish their work.<br \/>\ntrap '' 2<\/p>\n<p># Now the ugly code.<br \/>\n(<br \/>\n        ping \"${PING_PARAMS[@]}\" &<br \/>\n        # Commented out, because it looks like this line is not needed<br \/>\n        #trap \"kill -2 $! ; exit 1\" 2  # Catch Ctrl+C here<br \/>\n        wait<br \/>\n) 2>&1 | gawk '<br \/>\n# Weird that awk does not come with abs(), so I need to implement it.<br \/>\nfunction abs(x) {<br \/>\n        return ( (x < 0) ? -x : x )\n}\n\n# Ditto for ceiling function.\nfunction ceil(x) {\n        return (x == int(x)) ? x : int(x) + 1\n}\n\n# Currently, this function is called once, at the beginning of this\n# script, but it is also possible to call this more than once, to\n# handle window size changes while this program is running.\n#\n# Local variables MUST be declared in argument list, else they are\n# seen as global. Ugly, but that is how awk works.\nfunction get_terminal_size(SIZE,SIZEA) {\n        if( HAS_STTY ) {\n                if( (STTY_CMD | getline SIZE) == 1 ) {\n                        split(SIZE, SIZEA, \" \")\n                        LINES   = SIZEA[1]\n                        COLUMNS = SIZEA[2]\n                } else {\n                        HAS_STTY = 0\n                }\n                close(STTY_CMD)\n        }\n        if ( int('\"${OVERRIDE_COLUMNS}\"') ) { COLUMNS = int('\"${OVERRIDE_COLUMNS}\"') }\n        if ( int('\"${OVERRIDE_LINES}\"')   ) { LINES   = int('\"${OVERRIDE_LINES}\"')   }\n}\n\n############################################################\n# Functions related to cursor handling\n\n# Function called whenever a non-dotted line is printed.\n#\n# It will move the cursor to the line next to the statistics and\n# restore the default color.\nfunction other_line_is_printed() {\n        if( IS_PRINTING_DOTS ) {\n                if( '\"${IS_TERMINAL}\"' ) {\n                        printf( ESC_DEFAULT ESC_NEXTLINE ESC_NEXTLINE \"\\n\" )\n                } else {\n                        printf( ESC_DEFAULT \"\\n\" )\n                        print_statistics_bar()\n                }\n        }\n        IS_PRINTING_DOTS = 0\n        CURR_COL = 0\n}\n\n# Function called whenever a non-dotted line is repeated.\nfunction other_line_is_repeated() {\n        if (other_line_times < 2) {\n                return\n        }\n        if( '\"${IS_TERMINAL}\"' ) {\n                printf( ESC_DEFAULT ESC_ERASELINE \"\\r\" )\n        }\n        printf( \"Last message repeated %d times.\", other_line_times )\n        if( ! '\"${IS_TERMINAL}\"' ) {\n                printf( \"\\n\" )\n        }\n}\n\n# Prints the newlines required for the live statistics.\n#\n# I need to print some newlines and then return the cursor back to its position\n# to make sure the terminal will scroll.\n#\n# If the output is not a terminal, break lines on every LAST_N dots.\nfunction print_newlines_if_needed() {\n        if( '\"${IS_TERMINAL}\"' ) {\n                # COLUMNS-1 because I want to avoid bugs with the cursor at the last column\n                if( CURR_COL >= COLUMNS-1 ) {<br \/>\n                        CURR_COL = 0<br \/>\n                }<br \/>\n                if( CURR_COL == 0 ) {<br \/>\n                        if( IS_PRINTING_DOTS ) {<br \/>\n                                printf( \"\\n\" )<br \/>\n                        }<br \/>\n                        #printf( \"\\n\" \"\\n\" ESC_PREVLINE ESC_PREVLINE ESC_ERASELINE )<br \/>\n                        printf( ESC_DEFAULT \"\\n\" \"\\n\" ESC_CURSORUP ESC_CURSORUP ESC_ERASELINE )<br \/>\n                }<br \/>\n        } else {<br \/>\n                if( CURR_COL >= LAST_N ) {<br \/>\n                        CURR_COL = 0<br \/>\n                        printf( ESC_DEFAULT \"\\n\" )<br \/>\n                        print_statistics_bar()<br \/>\n                }<br \/>\n        }<br \/>\n        CURR_COL++<br \/>\n        IS_PRINTING_DOTS = 1<br \/>\n}<\/p>\n<p>############################################################<br \/>\n# Functions related to the data structure of \"Last N\" statistics.<\/p>\n<p># Clears the data structure.<br \/>\nfunction clear(d) {<br \/>\n        d[\"index\"] = 0  # The next position to store a value<br \/>\n        d[\"size\"]  = 0  # The array size, goes up to LAST_N<br \/>\n}<\/p>\n<p># This function stores the value to the passed data structure.<br \/>\n# The data structure holds at most LAST_N values. When it is full,<br \/>\n# a new value overwrite the oldest one.<br \/>\nfunction store(d, value) {<br \/>\n        d[d[\"index\"]] = value<br \/>\n        d[\"index\"]++<br \/>\n        if( d[\"index\"] >= d[\"size\"] ) {<br \/>\n                if( d[\"size\"] < LAST_N ) {\n                        d[\"size\"]++\n                } else {\n                        d[\"index\"] = 0\n                }\n        }\n}\n\n############################################################\n# Functions related to processing the received response\n\nfunction process_rtt(rtt) {\n        # Overall statistics\n        last_rtt = rtt\n        total_rtt += rtt\n        if( last_seq == 0 ) {\n                min_rtt = max_rtt = rtt\n        } else {\n                if( rtt < min_rtt ) min_rtt = rtt\n                if( rtt > max_rtt ) max_rtt = rtt<br \/>\n        }<\/p>\n<p>        # \"Last N\" statistics<br \/>\n        store(lastn_rtt,rtt)<br \/>\n}<\/p>\n<p>############################################################<br \/>\n# Functions related to printing the fancy ping response<\/p>\n<p># block_index is just a local variable.<br \/>\nfunction print_response_legend(i) {<br \/>\n        if( '\"${USE_UNICODE}\"' ) {<br \/>\n                printf( BLOCK[0] ESC_DEFAULT \"%4d \", 0)<br \/>\n                for( i=1 ; i<block_len ; i++ ) {\n                        printf( BLOCK[i] ESC_DEFAULT \"%4d \",\n                                BLOCK_RTT_MIN + ceil((i-1) * BLOCK_RTT_RANGE \/ (BLOCK_LEN - 2)) )\n                }\n                printf( \"\\n\" )\n        }\n\n        # Useful code for debugging.\n        #for( i=0 ; i<=BLOCK_RTT_MAX ; i++ ) {\n        #       print_received_response(i)\n        #       printf( ESC_DEFAULT \"%4d\\n\", i )\n        #}\n}\n\n# block_index is just a local variable.\nfunction print_received_response(rtt, block_index) {\n        if( '\"${USE_UNICODE}\"' ) {\n                if( rtt < BLOCK_RTT_MIN ) {\n                        block_index = 0\n                } else if( rtt >= BLOCK_RTT_MAX ) {<br \/>\n                        block_index = BLOCK_LEN - 1<br \/>\n                } else {<br \/>\n                        block_index = 1 + int((rtt - BLOCK_RTT_MIN) * (BLOCK_LEN - 2) \/ BLOCK_RTT_RANGE)<br \/>\n                }<br \/>\n                printf( BLOCK[block_index] )<br \/>\n        } else {<br \/>\n                printf( ESC_GREEN \".\" )<br \/>\n        }<br \/>\n}<\/p>\n<p>function print_missing_response(rtt) {<br \/>\n        printf( ESC_RED \"!\" )<br \/>\n}<\/p>\n<p>############################################################<br \/>\n# Functions related to printing statistics<\/p>\n<p>function print_overall() {<br \/>\n        if( '\"${IS_TERMINAL}\"' ) {<br \/>\n                printf( \"%2d\/%3d (%2d%%) lost; %4.0f\/\" ESC_BOLD \"%4.0f\" ESC_DEFAULT \"\/%4.0fms; last: \" ESC_BOLD \"%4.0f\" ESC_DEFAULT \"ms\",<br \/>\n                        lost,<br \/>\n                        lost+received,<br \/>\n                        (lost*100\/(lost+received)),<br \/>\n                        min_rtt,<br \/>\n                        (total_rtt\/received),<br \/>\n                        max_rtt,<br \/>\n                        last_rtt )<br \/>\n        } else {<br \/>\n                printf( \"%2d\/%3d (%2d%%) lost; %4.0f\/\" ESC_BOLD \"%4.0f\" ESC_DEFAULT \"\/%4.0fms\",<br \/>\n                        lost,<br \/>\n                        lost+received,<br \/>\n                        (lost*100\/(lost+received)),<br \/>\n                        min_rtt,<br \/>\n                        (total_rtt\/received),<br \/>\n                        max_rtt )<br \/>\n        }<br \/>\n}<\/p>\n<p>function print_last_n(i, sum, min, avg, max, diffs) {<br \/>\n        # Calculate and print the lost packets statistics<br \/>\n        sum = 0<br \/>\n        for( i=0 ; i<lastn_lost [\"size\"] ; i++ ) {\n                sum += lastn_lost[i]\n        }\n        printf( \"%2d\/%3d (%2d%%) lost; \",\n                sum,\n                lastn_lost[\"size\"],\n                sum*100\/lastn_lost[\"size\"] )\n\n        # Calculate the min\/avg\/max rtt times\n        sum = diffs = 0\n        min = max = lastn_rtt[0]\n        for( i=0 ; i<lastn_rtt[\"size\"] ; i++ ) {\n                sum += lastn_rtt[i]\n                if( lastn_rtt[i] < min ) min = lastn_rtt[i]\n                if( lastn_rtt[i] > max ) max = lastn_rtt[i]<br \/>\n        }<br \/>\n        avg = sum\/lastn_rtt[\"size\"]<\/p>\n<p>        # Calculate mdev (mean absolute deviation)<br \/>\n        for( i=0 ; i<lastn_rtt [\"size\"] ; i++ ) {\n                diffs += abs(lastn_rtt[i] - avg)\n        }\n        diffs \/= lastn_rtt[\"size\"]\n\n        # Print the rtt statistics\n        printf( \"%4.0f\/\" ESC_BOLD \"%4.0f\" ESC_DEFAULT \"\/%4.0f\/%4.0fms (last %d)\",\n                min,\n                avg,\n                max,\n                diffs,\n                lastn_rtt[\"size\"] )\n}\n\nfunction print_statistics_bar() {\n        if( '\"${IS_TERMINAL}\"' ) {\n                printf( ESC_SAVEPOS ESC_DEFAULT )\n\n                printf( ESC_NEXTLINE ESC_ERASELINE )\n                print_overall()\n                printf( ESC_NEXTLINE ESC_ERASELINE )\n                print_last_n()\n\n                printf( ESC_UNSAVEPOS )\n        } else {\n                print_overall()\n                printf( \"\\n\" )\n                print_last_n()\n                printf( \"\\n\" )\n        }\n}\n\n############################################################\n# Initializations\nBEGIN {\n        # Easy way to get each value from ping output\n        FS = \"=\"\n\n        ############################################################\n        # General internal variables\n\n        # This is needed to keep track of lost packets\n        last_seq = 0\n\n        # The previously printed non-ping-response line\n        other_line = \"\"\n        other_line_times = 0\n\n        # Variables to keep the screen clean\n        IS_PRINTING_DOTS = 0\n        CURR_COL = 0\n\n        ############################################################\n        # Variables related to \"overall\" statistics\n        received = 0\n        lost = 0\n        total_rtt = 0\n        min_rtt = 0\n        max_rtt = 0\n        last_rtt = 0\n\n        ############################################################\n        # Variables related to \"last N\" statistics\n        LAST_N = int('\"${LAST_N}\"')\n\n        # Data structures for the \"last N\" statistics\n        clear(lastn_lost)\n        clear(lastn_rtt)\n\n        ############################################################\n        # Terminal height and width \n\n        # These are sane defaults, in case we cannot query the actual terminal size\n        LINES    = 24\n        COLUMNS  = 80\n\n        # Auto-detecting the terminal size\n        HAS_STTY = 1\n        STTY_CMD = \"stty size --file=\/dev\/tty 2> \/dev\/null\"<br \/>\n        get_terminal_size()<br \/>\n        if( '\"${IS_TERMINAL}\"' && COLUMNS < = 50 ) {\n                print \"Warning: terminal width is too small.\"\n        }\n\n        ############################################################\n        # ANSI escape codes\n\n        # Color escape codes.\n        # Fortunately, awk defaults any unassigned variable to an empty string.\n        if( '\"${USE_COLOR}\"' ) {\n                ESC_DEFAULT = \"\\033[0m\"\n                ESC_BOLD    = \"\\033[1m\"\n                #ESC_BLACK   = \"\\033[0;30m\"\n                #ESC_GRAY    = \"\\033[1;30m\"\n                ESC_RED     = \"\\033[0;31m\"\n                ESC_GREEN   = \"\\033[0;32m\"\n                ESC_YELLOW  = \"\\033[0;33m\"\n                ESC_BLUE    = \"\\033[0;34m\"\n                ESC_MAGENTA = \"\\033[0;35m\"\n                ESC_CYAN    = \"\\033[0;36m\"\n                ESC_WHITE   = \"\\033[0;37m\"\n                ESC_YELLOW_ON_GREEN = \"\\033[42;33m\"\n                ESC_RED_ON_YELLOW   = \"\\033[43;31m\"\n        }\n        # Other escape codes, see:\n        # http:\/\/en.wikipedia.org\/wiki\/ANSI_escape_code\n        # http:\/\/invisible-island.net\/xterm\/ctlseqs\/ctlseqs.html\n        ESC_NEXTLINE   = \"\\n\"\n        ESC_CURSORUP   = \"\\033[A\"\n        ESC_SCROLLUP   = \"\\033[S\"\n        ESC_SCROLLDOWN = \"\\033[T\"\n        ESC_ERASELINE  = \"\\033[2K\"\n        ESC_SAVEPOS    = \"\\0337\"\n        ESC_UNSAVEPOS  = \"\\0338\"\n\n        # I am avoiding these escapes as they are not listed in:\n        # http:\/\/vt100.net\/docs\/vt100-ug\/chapter3.html\n        #ESC_PREVLINE   = \"\\033[F\"\n        #ESC_SAVEPOS    = \"\\033[s\"\n        #ESC_UNSAVEPOS  = \"\\033[u\"\n\n        # I am avoiding this to improve compatibility with (older versions of) tmux\n        #ESC_NEXTLINE   = \"\\033[E\"\n\n        ############################################################\n        # Unicode characters (based on https:\/\/github.com\/holman\/spark )\n        if( '\"${USE_UNICODE}\"' ) {\n                BLOCK[ 0] = ESC_GREEN \"?\"\n                BLOCK[ 1] = ESC_GREEN \"?\"\n                BLOCK[ 2] = ESC_GREEN \"?\"\n                BLOCK[ 3] = ESC_GREEN \"?\"\n                BLOCK[ 4] = ESC_GREEN \"?\"\n                BLOCK[ 5] = ESC_GREEN \"?\"\n                BLOCK[ 6] = ESC_GREEN \"?\"\n                BLOCK[ 7] = ESC_GREEN \"?\"\n                BLOCK[ 8] = ESC_YELLOW_ON_GREEN \"?\"\n                BLOCK[ 9] = ESC_YELLOW_ON_GREEN \"?\"\n                BLOCK[10] = ESC_YELLOW_ON_GREEN \"?\"\n                BLOCK[11] = ESC_YELLOW_ON_GREEN \"?\"\n                BLOCK[12] = ESC_YELLOW_ON_GREEN \"?\"\n                BLOCK[13] = ESC_YELLOW_ON_GREEN \"?\"\n                BLOCK[14] = ESC_YELLOW_ON_GREEN \"?\"\n                BLOCK[15] = ESC_YELLOW_ON_GREEN \"?\"\n                BLOCK[16] = ESC_RED_ON_YELLOW \"?\"\n                BLOCK[17] = ESC_RED_ON_YELLOW \"?\"\n                BLOCK[18] = ESC_RED_ON_YELLOW \"?\"\n                BLOCK[19] = ESC_RED_ON_YELLOW \"?\"\n                BLOCK[20] = ESC_RED_ON_YELLOW \"?\"\n                BLOCK[21] = ESC_RED_ON_YELLOW \"?\"\n                BLOCK[22] = ESC_RED_ON_YELLOW \"?\"\n                BLOCK[23] = ESC_RED_ON_YELLOW \"?\"\n                if( '\"${USE_MULTICOLOR}\"' &#038;&#038; '\"${USE_COLOR}\"' ) {\n                        # Multi-color version:\n                        BLOCK_LEN = 24\n                        BLOCK_RTT_MIN = 10\n                        BLOCK_RTT_MAX = 230\n                } else {\n                        # Simple version:\n                        BLOCK_LEN = 8\n                        BLOCK_RTT_MIN = 25\n                        BLOCK_RTT_MAX = 175\n                }\n\n                if( int('\"${RTT_MIN}\"') > 0 && int('\"${RTT_MAX}\"') > 0 ) {<br \/>\n                        BLOCK_RTT_MIN = int('\"${RTT_MIN}\"')<br \/>\n                        BLOCK_RTT_MAX = int('\"${RTT_MAX}\"')<br \/>\n                } else if( int('\"${RTT_MIN}\"') > 0 ) {<br \/>\n                        BLOCK_RTT_MIN = int('\"${RTT_MIN}\"')<br \/>\n                        BLOCK_RTT_MAX = BLOCK_RTT_MIN * (BLOCK_LEN - 1)<br \/>\n                } else if( int('\"${RTT_MAX}\"') > 0 ) {<br \/>\n                        BLOCK_RTT_MAX = int('\"${RTT_MAX}\"')<br \/>\n                        BLOCK_RTT_MIN = int(BLOCK_RTT_MAX \/ (BLOCK_LEN - 1))<br \/>\n                }<\/p>\n<p>                BLOCK_RTT_RANGE = BLOCK_RTT_MAX - BLOCK_RTT_MIN<br \/>\n                print_response_legend()<br \/>\n        }<br \/>\n}<\/p>\n<p>############################################################<br \/>\n# Main loop<br \/>\n{<br \/>\n        # Sample line:<br \/>\n        # 64 bytes from 8.8.8.8: icmp_seq=1 ttl=49 time=184 ms<br \/>\n        if( $0 ~ \/^[0-9]+ bytes from .*: icmp_[rs]eq=[0-9]+ ttl=[0-9]+ time=[0-9.]+ *ms\/ ) {<br \/>\n                if( other_line_times >= 2 ) {<br \/>\n                        if( '\"${IS_TERMINAL}\"' ) {<br \/>\n                                printf( \"\\n\" )<br \/>\n                        } else {<br \/>\n                                other_line_is_repeated()<br \/>\n                        }<br \/>\n                }<br \/>\n                other_line = \"\"<br \/>\n                other_line_times = 0<\/p>\n<p>                # $1 = useless prefix string<br \/>\n                # $2 = icmp_seq<br \/>\n                # $3 = ttl<br \/>\n                # $4 = time<\/p>\n<p>                # This must be called before incrementing the last_seq variable!<br \/>\n                rtt = int($4)<br \/>\n                process_rtt(rtt)<\/p>\n<p>                seq = int($2)<\/p>\n<p>                while( last_seq < seq - 1 ) {\n                        # Lost a packet\n                        print_newlines_if_needed()\n                        print_missing_response()\n\n                        last_seq++\n                        lost++\n                        store(lastn_lost, 1)\n                }\n\n                # Received a packet\n                print_newlines_if_needed()\n                print_received_response(rtt)\n\n                last_seq++\n                received++\n                store(lastn_lost, 0)\n\n                if( '\"${IS_TERMINAL}\"' ) {\n                        print_statistics_bar()\n                }\n        } else if ( $0 == \"\" ) {\n                # Do nothing on blank lines.\n        } else {\n                other_line_is_printed()\n                if ( $0 == other_line ) {\n                        other_line_times++\n                        if( '\"${IS_TERMINAL}\"' ) {\n                                other_line_is_repeated()\n                        }\n                } else {\n                        other_line = $0\n                        other_line_times = 1\n                        printf( \"%s\\n\", $0 )\n                }\n        }\n\n        # Not needed when the output is a terminal, but does not hurt either.\n        fflush()\n}'<\/code><\/lastn_rtt><\/lastn_lost><\/block_len><\/n><\/denilsonsa><\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>From CrazyTerabyte Blog prettyping.sh &#8211; A better UI for watching ping responses Do you run ping tool very often? Do you find yourself squeezing your eyes to see if a packet has been lost? Do you want to have a better view of the latency and of the lost packets over time? Then you need&#8230; <\/p>\n<div class=\"read-more navbutton\"><a href=\"https:\/\/g33kinfo.com\/info\/prettyping-sh\/\">Read More<i class=\"fa fa-angle-double-right\"><\/i><\/a><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"class_list":["post-5866","post","type-post","status-publish","format-standard","hentry","category-info"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>prettyping.sh - Linux Shtuff<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/g33kinfo.com\/info\/prettyping-sh\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"prettyping.sh - Linux Shtuff\" \/>\n<meta property=\"og:description\" content=\"From CrazyTerabyte Blog prettyping.sh &#8211; A better UI for watching ping responses Do you run ping tool very often? Do you find yourself squeezing your eyes to see if a packet has been lost? Do you want to have a better view of the latency and of the lost packets over time? Then you need... Read More\" \/>\n<meta property=\"og:url\" content=\"https:\/\/g33kinfo.com\/info\/prettyping-sh\/\" \/>\n<meta property=\"og:site_name\" content=\"Linux Shtuff\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/fb.me\/g33kinf0\" \/>\n<meta property=\"article:author\" content=\"https:\/\/fb.me\/g33kinf0\" \/>\n<meta property=\"article:published_time\" content=\"2013-10-18T08:30:36+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/files.myopera.com\/CrazyTerabyte\/blog\/prettyping-4x.gif\" \/>\n<meta name=\"author\" content=\"g33kadmin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/drsinger1111\" \/>\n<meta name=\"twitter:site\" content=\"@drsinger1111\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/\"},\"author\":{\"name\":\"g33kadmin\",\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/#\\\/schema\\\/person\\\/c022e4c40b13ea1b678e6f020756f547\"},\"headline\":\"prettyping.sh\",\"datePublished\":\"2013-10-18T08:30:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/\"},\"wordCount\":576,\"publisher\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/#\\\/schema\\\/person\\\/c022e4c40b13ea1b678e6f020756f547\"},\"image\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/files.myopera.com\\\/CrazyTerabyte\\\/blog\\\/prettyping-4x.gif\",\"articleSection\":[\"General Info\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/\",\"url\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/\",\"name\":\"prettyping.sh - Linux Shtuff\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/files.myopera.com\\\/CrazyTerabyte\\\/blog\\\/prettyping-4x.gif\",\"datePublished\":\"2013-10-18T08:30:36+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/#primaryimage\",\"url\":\"http:\\\/\\\/files.myopera.com\\\/CrazyTerabyte\\\/blog\\\/prettyping-4x.gif\",\"contentUrl\":\"http:\\\/\\\/files.myopera.com\\\/CrazyTerabyte\\\/blog\\\/prettyping-4x.gif\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/prettyping-sh\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"prettyping.sh\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/#website\",\"url\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/\",\"name\":\"Linux Shtuff\",\"description\":\"Because I have CRS Syndrome...\",\"publisher\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/#\\\/schema\\\/person\\\/c022e4c40b13ea1b678e6f020756f547\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/#\\\/schema\\\/person\\\/c022e4c40b13ea1b678e6f020756f547\",\"name\":\"g33kadmin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/wp-content\\\/uploads\\\/2022\\\/07\\\/minion-researchA.gif\",\"url\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/wp-content\\\/uploads\\\/2022\\\/07\\\/minion-researchA.gif\",\"contentUrl\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/wp-content\\\/uploads\\\/2022\\\/07\\\/minion-researchA.gif\",\"width\":512,\"height\":512,\"caption\":\"g33kadmin\"},\"logo\":{\"@id\":\"https:\\\/\\\/g33kinfo.com\\\/info\\\/wp-content\\\/uploads\\\/2022\\\/07\\\/minion-researchA.gif\"},\"description\":\"I am a g33k, Linux blogger, developer, student and Tech Writer for Liquidweb.com\\\/kb. My passion for all things tech drives my hunt for all the coolz. I often need a vacation after I get back from vacation....\",\"sameAs\":[\"https:\\\/\\\/thelinuxreport.com\",\"https:\\\/\\\/fb.me\\\/g33kinf0\",\"https:\\\/\\\/x.com\\\/https:\\\/\\\/twitter.com\\\/drsinger1111\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"prettyping.sh - Linux Shtuff","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/","og_locale":"en_US","og_type":"article","og_title":"prettyping.sh - Linux Shtuff","og_description":"From CrazyTerabyte Blog prettyping.sh &#8211; A better UI for watching ping responses Do you run ping tool very often? Do you find yourself squeezing your eyes to see if a packet has been lost? Do you want to have a better view of the latency and of the lost packets over time? Then you need... Read More","og_url":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/","og_site_name":"Linux Shtuff","article_publisher":"https:\/\/fb.me\/g33kinf0","article_author":"https:\/\/fb.me\/g33kinf0","article_published_time":"2013-10-18T08:30:36+00:00","og_image":[{"url":"http:\/\/files.myopera.com\/CrazyTerabyte\/blog\/prettyping-4x.gif","type":"","width":"","height":""}],"author":"g33kadmin","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/drsinger1111","twitter_site":"@drsinger1111","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/#article","isPartOf":{"@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/"},"author":{"name":"g33kadmin","@id":"https:\/\/g33kinfo.com\/info\/#\/schema\/person\/c022e4c40b13ea1b678e6f020756f547"},"headline":"prettyping.sh","datePublished":"2013-10-18T08:30:36+00:00","mainEntityOfPage":{"@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/"},"wordCount":576,"publisher":{"@id":"https:\/\/g33kinfo.com\/info\/#\/schema\/person\/c022e4c40b13ea1b678e6f020756f547"},"image":{"@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/#primaryimage"},"thumbnailUrl":"http:\/\/files.myopera.com\/CrazyTerabyte\/blog\/prettyping-4x.gif","articleSection":["General Info"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/","url":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/","name":"prettyping.sh - Linux Shtuff","isPartOf":{"@id":"https:\/\/g33kinfo.com\/info\/#website"},"primaryImageOfPage":{"@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/#primaryimage"},"image":{"@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/#primaryimage"},"thumbnailUrl":"http:\/\/files.myopera.com\/CrazyTerabyte\/blog\/prettyping-4x.gif","datePublished":"2013-10-18T08:30:36+00:00","breadcrumb":{"@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/g33kinfo.com\/info\/prettyping-sh\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/#primaryimage","url":"http:\/\/files.myopera.com\/CrazyTerabyte\/blog\/prettyping-4x.gif","contentUrl":"http:\/\/files.myopera.com\/CrazyTerabyte\/blog\/prettyping-4x.gif"},{"@type":"BreadcrumbList","@id":"https:\/\/g33kinfo.com\/info\/prettyping-sh\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/g33kinfo.com\/info\/"},{"@type":"ListItem","position":2,"name":"prettyping.sh"}]},{"@type":"WebSite","@id":"https:\/\/g33kinfo.com\/info\/#website","url":"https:\/\/g33kinfo.com\/info\/","name":"Linux Shtuff","description":"Because I have CRS Syndrome...","publisher":{"@id":"https:\/\/g33kinfo.com\/info\/#\/schema\/person\/c022e4c40b13ea1b678e6f020756f547"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/g33kinfo.com\/info\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/g33kinfo.com\/info\/#\/schema\/person\/c022e4c40b13ea1b678e6f020756f547","name":"g33kadmin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/g33kinfo.com\/info\/wp-content\/uploads\/2022\/07\/minion-researchA.gif","url":"https:\/\/g33kinfo.com\/info\/wp-content\/uploads\/2022\/07\/minion-researchA.gif","contentUrl":"https:\/\/g33kinfo.com\/info\/wp-content\/uploads\/2022\/07\/minion-researchA.gif","width":512,"height":512,"caption":"g33kadmin"},"logo":{"@id":"https:\/\/g33kinfo.com\/info\/wp-content\/uploads\/2022\/07\/minion-researchA.gif"},"description":"I am a g33k, Linux blogger, developer, student and Tech Writer for Liquidweb.com\/kb. My passion for all things tech drives my hunt for all the coolz. I often need a vacation after I get back from vacation....","sameAs":["https:\/\/thelinuxreport.com","https:\/\/fb.me\/g33kinf0","https:\/\/x.com\/https:\/\/twitter.com\/drsinger1111"]}]}},"_links":{"self":[{"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/posts\/5866","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/comments?post=5866"}],"version-history":[{"count":0,"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/posts\/5866\/revisions"}],"wp:attachment":[{"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/media?parent=5866"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/categories?post=5866"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/g33kinfo.com\/info\/wp-json\/wp\/v2\/tags?post=5866"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}