var [const] MsgHash=Import.lib("zklMsgHash");
var [const] gotEm=Atomic.Int();	// global signal for all threads

const THREADS=9,   // how we will split task, THREADS<=26
      CHR_a="a".toAsc();

fcn crack(c,n,hashes){	// thread
   sha256:=MsgHash.SHA256; // the SHA-256 hash method, byte bucket
   bytes,hash := Data(),Data().howza(0); // byte buckets to reduce garbage production
   firstLtrs:=(c+CHR_a).walker(n);
   ltrs:=CHR_a.walker;	// iterator starting at 97/"a"
   foreach a,b,c,d,e in (firstLtrs,ltrs(26),ltrs(26),ltrs(26),ltrs(26)){
      if(not hashes2go) return(); // all cracked, stop, not really needed
      bytes.clear(a,b,c,d,e);     // recycle Data, faster than creating Strings
      sha256(bytes,1,hash);	  // put hash in hash
      if(hashes.holds(hash)){
         println(bytes.text," --> ",hash.pump(String,"%02x".fmt));
	 hashes2go.dec();	// I cracked one, let mom thread know
      }
   }
}


ParseIP(Address){
	return InStr(A_LoopField, ".") ? IPv4(Address) : IPv6(Address)
}

IPv4(Address){
	for i, v in StrSplit(Address, "."){
		x := StrSplit(v, ":")
		num .= SubStr("00" . Format("{:X}", x.1), -1)
		port := x.2 ? x.2 : ""
	}
	return [num, port]
}

IPv6(Address){
	for i, v in StrSplit(Address, "]")
		if i = 1
			for j, x in StrSplit(LTrim(v, "[:"), ":")
				num .= x = "" ? "00000000" : SubStr("0000" x, -3)
		else
			port := LTrim(v, ":")
	return [SubStr("00000000000000000000000000000000" num, -31), port]
}


#include <string.h>
#include <memory.h>

static unsigned int _parseDecimal ( const char** pchCursor )
{
    unsigned int nVal = 0;
    char chNow;
    while ( chNow = **pchCursor, chNow >= '0' && chNow <= '9' )
    {
        //shift digit in
        nVal *= 10;
        nVal += chNow - '0';

        ++*pchCursor;
    }
    return nVal;
}

static unsigned int _parseHex ( const char** pchCursor )
{
    unsigned int nVal = 0;
    char chNow;
    while ( chNow = **pchCursor & 0x5f, //(collapses case, but mutilates digits)
            (chNow >= ('0'&0x5f) && chNow <= ('9'&0x5f)) ||
            (chNow >= 'A' && chNow <= 'F')
            )
    {
        unsigned char nybbleValue;
        chNow -= 0x10;  //scootch digital values down; hex now offset by x31
        nybbleValue = ( chNow > 9 ? chNow - (0x31-0x0a) : chNow );
        //shift nybble in
        nVal <<= 4;
        nVal += nybbleValue;

        ++*pchCursor;
    }
    return nVal;
}

//Parse a textual IPv4 or IPv6 address, optionally with port, into a binary
//array (for the address, in network order), and an optionally provided port.
//Also, indicate which of those forms (4 or 6) was parsed.  Return true on
//success.  ppszText must be a nul-terminated ASCII string.  It will be
//updated to point to the character which terminated parsing (so you can carry
//on with other things.  abyAddr must be 16 bytes.  You can provide NULL for
//abyAddr, nPort, bIsIPv6, if you are not interested in any of those
//informations.  If we request port, but there is no port part, then nPort will
//be set to 0.  There may be no whitespace leading or internal (though this may
//be used to terminate a successful parse.
//Note:  the binary address and integer port are in network order.
int ParseIPv4OrIPv6 ( const char** ppszText,
        unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
{
    unsigned char* abyAddrLocal;
    unsigned char abyDummyAddr[16];

    //find first colon, dot, and open bracket
    const char* pchColon = strchr ( *ppszText, ':' );
    const char* pchDot = strchr ( *ppszText, '.' );
    const char* pchOpenBracket = strchr ( *ppszText, '[' );
    const char* pchCloseBracket = NULL;

    //we'll consider this to (probably) be IPv6 if we find an open
    //bracket, or an absence of dots, or if there is a colon, and it
    //precedes any dots that may or may not be there
    int bIsIPv6local = NULL != pchOpenBracket || NULL == pchDot ||
            ( NULL != pchColon && ( NULL == pchDot || pchColon < pchDot ) );
    //OK, now do a little further sanity check our initial guess...
    if ( bIsIPv6local )
    {
        //if open bracket, then must have close bracket that follows somewhere
        pchCloseBracket = strchr ( *ppszText, ']' );
        if ( NULL != pchOpenBracket && ( NULL == pchCloseBracket ||
                pchCloseBracket < pchOpenBracket ) )
            return 0;
    }
    else    //probably ipv4
    {
        //dots must exist, and precede any colons
        if ( NULL == pchDot || ( NULL != pchColon && pchColon < pchDot ) )
            return 0;
    }

    //we figured out this much so far....
    if ( NULL != pbIsIPv6 )
        *pbIsIPv6 = bIsIPv6local;

    //especially for IPv6 (where we will be decompressing and validating)
    //we really need to have a working buffer even if the caller didn't
    //care about the results.
    abyAddrLocal = abyAddr; //prefer to use the caller's
    if ( NULL == abyAddrLocal ) //but use a dummy if we must
        abyAddrLocal = abyDummyAddr;

    //OK, there should be no correctly formed strings which are miscategorized,
    //and now any format errors will be found out as we continue parsing
    //according to plan.
    if ( ! bIsIPv6local )   //try to parse as IPv4
    {
        //4 dotted quad decimal; optional port if there is a colon
        //since there are just 4, and because the last one can be terminated
        //differently, I'm just going to unroll any potential loop.
        unsigned char* pbyAddrCursor = abyAddrLocal;
        unsigned int nVal;
        const char* pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           //get first val
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )    //must be in range and followed by dot and nonempty
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;  //stick it in addr
        ++(*ppszText);  //past the dot

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           //get second val
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;
        ++(*ppszText);  //past the dot

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           //get third val
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;
        ++(*ppszText);  //past the dot

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           //get fourth val
        if ( nVal > 255 || pszTextBefore == *ppszText ) //(we can terminate this one in several ways)
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;

        if ( ':' == **ppszText && NULL != pnPort )  //have port part, and we want it
        {
            unsigned short usPortNetwork;   //save value in network order
            ++(*ppszText);  //past the colon
            pszTextBefore = *ppszText;
            nVal =_parseDecimal ( ppszText );
            if ( nVal > 65535 || pszTextBefore == *ppszText )
                return 0;
            ((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
            ((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
            *pnPort = usPortNetwork;
            return 1;
        }
        else    //finished just with ip address
        {
            if ( NULL != pnPort )
                *pnPort = 0;    //indicate we have no port part
            return 1;
        }
    }
    else    //try to parse as IPv6
    {
        unsigned char* pbyAddrCursor;
        unsigned char* pbyZerosLoc;
        int bIPv4Detected;
        int nIdx;
        //up to 8 16-bit hex quantities, separated by colons, with at most one
        //empty quantity, acting as a stretchy run of zeroes.  optional port
        //if there are brackets followed by colon and decimal port number.
        //A further form allows an ipv4 dotted quad instead of the last two
        //16-bit quantities, but only if in the ipv4 space ::ffff:x:x .
        if ( NULL != pchOpenBracket )   //start past the open bracket, if it exists
            *ppszText = pchOpenBracket + 1;
        pbyAddrCursor = abyAddrLocal;
        pbyZerosLoc = NULL; //if we find a 'zero compression' location
        bIPv4Detected = 0;
        for ( nIdx = 0; nIdx < 8; ++nIdx )  //we've got up to 8 of these, so we will use a loop
        {
            const char* pszTextBefore = *ppszText;
            unsigned nVal =_parseHex ( ppszText );      //get value; these are hex
            if ( pszTextBefore == *ppszText )   //if empty, we are zero compressing; note the loc
            {
                if ( NULL != pbyZerosLoc )  //there can be only one!
                {
                    //unless it's a terminal empty field, then this is OK, it just means we're done with the host part
                    if ( pbyZerosLoc == pbyAddrCursor )
                    {
                        --nIdx;
                        break;
                    }
                    return 0;   //otherwise, it's a format error
                }
                if ( ':' != **ppszText )    //empty field can only be via :
                    return 0;
                if ( 0 == nIdx )    //leading zero compression requires an extra peek, and adjustment
                {
                    ++(*ppszText);
                    if ( ':' != **ppszText )
                        return 0;
                }

                pbyZerosLoc = pbyAddrCursor;
                ++(*ppszText);
            }
            else
            {
                if ( '.' == **ppszText )    //special case of ipv4 convenience notation
                {
                    //who knows how to parse ipv4?  we do!
                    const char* pszTextlocal = pszTextBefore;   //back it up
                    unsigned char abyAddrlocal[16];
                    int bIsIPv6local;
                    int bParseResultlocal = ParseIPv4OrIPv6 ( &pszTextlocal, abyAddrlocal, NULL, &bIsIPv6local );
                    *ppszText = pszTextlocal;   //success or fail, remember the terminating char
                    if ( ! bParseResultlocal || bIsIPv6local )  //must parse and must be ipv4
                        return 0;
                    //transfer addrlocal into the present location
                    *(pbyAddrCursor++) = abyAddrlocal[0];
                    *(pbyAddrCursor++) = abyAddrlocal[1];
                    *(pbyAddrCursor++) = abyAddrlocal[2];
                    *(pbyAddrCursor++) = abyAddrlocal[3];
                    ++nIdx; //pretend like we took another short, since the ipv4 effectively is two shorts
                    bIPv4Detected = 1;  //remember how we got here for further validation later
                    break;  //totally done with address
                }

                if ( nVal > 65535 ) //must be 16 bit quantity
                    return 0;
                *(pbyAddrCursor++) = nVal >> 8;     //transfer in network order
                *(pbyAddrCursor++) = nVal & 0xff;
                if ( ':' == **ppszText )    //typical case inside; carry on
                {
                    ++(*ppszText);
                }
                else    //some other terminating character; done with this parsing parts
                {
                    break;
                }
            }
        }

        //handle any zero compression we found
        if ( NULL != pbyZerosLoc )
        {
            int nHead = (int)( pbyZerosLoc - abyAddrLocal );    //how much before zero compression
            int nTail = nIdx * 2 - (int)( pbyZerosLoc - abyAddrLocal ); //how much after zero compression
            int nZeros = 16 - nTail - nHead;        //how much zeros
            memmove ( &abyAddrLocal[16-nTail], pbyZerosLoc, nTail );    //scootch stuff down
            memset ( pbyZerosLoc, 0, nZeros );      //clear the compressed zeros
        }

        //validation of ipv4 subspace ::ffff:x.x
        if ( bIPv4Detected )
        {
            static const unsigned char abyPfx[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
            if ( 0 != memcmp ( abyAddrLocal, abyPfx, sizeof(abyPfx) ) )
                return 0;
        }

        //close bracket
        if ( NULL != pchOpenBracket )
        {
            if ( ']' != **ppszText )
                return 0;
            ++(*ppszText);
        }

        if ( ':' == **ppszText && NULL != pnPort )  //have port part, and we want it
        {
            const char* pszTextBefore;
            unsigned int nVal;
            unsigned short usPortNetwork;   //save value in network order
            ++(*ppszText);  //past the colon
            pszTextBefore = *ppszText;
            pszTextBefore = *ppszText;
            nVal =_parseDecimal ( ppszText );
            if ( nVal > 65535 || pszTextBefore == *ppszText )
                return 0;
            ((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
            ((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
            *pnPort = usPortNetwork;
            return 1;
        }
        else    //finished just with ip address
        {
            if ( NULL != pnPort )
                *pnPort = 0;    //indicate we have no port part
            return 1;
        }
    }

}

//simple version if we want don't care about knowing how much we ate
int ParseIPv4OrIPv6_2 ( const char* pszText,
        unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
{
    const char* pszTextLocal = pszText;
    return ParseIPv4OrIPv6 ( &pszTextLocal, abyAddr, pnPort, pbIsIPv6);
}


#include <boost/asio/ip/address.hpp>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <limits>
#include <string>

using boost::asio::ip::address;
using boost::asio::ip::address_v4;
using boost::asio::ip::address_v6;
using boost::asio::ip::make_address;
using boost::asio::ip::make_address_v4;
using boost::asio::ip::make_address_v6;

template<typename uint>
bool parse_int(const std::string& str, int base, uint& n) {
    try {
        size_t pos = 0;
        unsigned long u = stoul(str, &pos, base);
        if (pos != str.length() || u > std::numeric_limits<uint>::max())
            return false;
        n = static_cast<uint>(u);
        return true;
    } catch (const std::exception& ex) {
        return false;
    }
}

//
// Parse an IP address and port from the given input string.
//
// Throws an exception if the input is not valid.
//
// Valid formats are:
// [ipv6_address]:port
// ipv4_address:port
// ipv4_address
// ipv6_address
//
void parse_ip_address_and_port(const std::string& input, address& addr, uint16_t& port) {
    size_t pos = input.rfind(':');
    if (pos != std::string::npos && pos > 1 && pos + 1 < input.length()
        && parse_int(input.substr(pos + 1), 10, port) && port > 0) {
        if (input[0] == '[' && input[pos - 1] == ']') {
            // square brackets so can only be an IPv6 address
            addr = make_address_v6(input.substr(1, pos - 2));
            return;
        } else {
            try {
                // IPv4 address + port?
                addr = make_address_v4(input.substr(0, pos));
                return;
            } catch (const std::exception& ex) {
                // nope, might be an IPv6 address
            }
        }
    }
    port = 0;
    addr = make_address(input);
}

void print_address_and_port(const address& addr, uint16_t port) {
    std::cout << std::hex << std::uppercase << std::setfill('0');
    if (addr.is_v4()) {
        address_v4 addr4 = addr.to_v4();
        std::cout << "address family: IPv4\n";
        std::cout << "address number: " << std::setw(8) << addr4.to_uint() << '\n';
    } else if (addr.is_v6()) {
        address_v6 addr6 = addr.to_v6();
        address_v6::bytes_type bytes(addr6.to_bytes());
        std::cout << "address family: IPv6\n";
        std::cout << "address number: ";
        for (unsigned char byte : bytes)
            std::cout << std::setw(2) << static_cast<unsigned int>(byte);
        std::cout << '\n';
    }
    if (port != 0)
        std::cout << "port: " << std::dec << port << '\n';
    else
        std::cout << "port not specified\n";
}

void test(const std::string& input) {
    std::cout << "input: " << input << '\n';
    try {
        address addr;
        uint16_t port = 0;
        parse_ip_address_and_port(input, addr, port);
        print_address_and_port(addr, port);
    } catch (const std::exception& ex) {
        std::cout << "parsing failed\n";
    }
    std::cout << '\n';
}

int main(int argc, char** argv) {
    test("127.0.0.1");
    test("127.0.0.1:80");
    test("::ffff:127.0.0.1");
    test("::1");
    test("[::1]:80");
    test("1::80");
    test("2605:2700:0:3::4713:93e3");
    test("[2605:2700:0:3::4713:93e3]:80");
    return 0;
}


// Parse IP addresses: Nigel Galloway. May 29th., 2021
open System.Text.RegularExpressions
type ipv6= Complete |Composite |Compressed |CompressedComposite
let ip4n,ip6i,ip6g,ip6e,ip6l=let n,g="[0-9a-fA-F]{1,4}","(25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?[0-9])" in (
  sprintf "^(%s)\.(%s)\.(%s)\.(%s)$" g g g g, sprintf "^(%s):(%s):(%s):(%s):(%s):(%s):(%s):(%s)$" n n n n n n n n,
  sprintf "^((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?(^|%s)::(%s|$)(:(%s))?(:(%s))?(:(%s))?(:(%s))?(:(%s))?(:(%s))?$" n n n n n n n n n n n n n n,
  sprintf "^(%s):(%s):(%s):(%s):(%s):(%s):(%s)\.(%s)\.(%s)\.(%s)$" n n n n n n g g g g,
  sprintf "^((%s):)?((%s):)?((%s):)?((%s):)?(^|%s)::((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?(%s)\.(%s)\.(%s)\.(%s)$" n n n n n n n n n n g g g g)
let mn,mi,mg,me,ml=[2;4;6;8;10;12;13], [14..2..26], [2;4;6;8;9], [11..2..19], [20..5..35]
let     fN(n:Match) g=g|>List.filter(fun(g:int)->n.Groups.[g].Length>0)
let     fI n (g:Match)=n|>List.fold(fun Σ (n:int)->(Σ<<<16)+((int>>bigint)(sprintf "0x%s" g.Groups.[n].Value)))0I
let rec fG n g=let a="0123456789abcdef" in match bigint.DivRem(n,16I) with (n,r) when n=0I->a.[int r]::g|>Array.ofList|>System.String |(n,r)->fG n (a.[int r]::g)
let     fE(m:Match) n g=(fN m n,fN m g)
let     fL n (g:Match)=n|>List.fold(fun Σ (n:int)->(Σ<<<8)+int(g.Groups.[n].Value))0
let (|IP4 |_|) n=let g=Regex.Match(n,ip4n) in if g.Success then Some(fL [1..5..16] g) else None
let (|IP6n|_|) i=let g=Regex.Match(i,ip6i) in if g.Success then Some(fI [1..8] g) else None
let (|IP6i|_|) g=let g=Regex.Match(g,ip6g) in if g.Success then let n,l=fE g mn mi in (if n.Length+l.Length<8 then Some(((fI n g)<<<((8-n.Length)*16))+(fI l g)) else None) else None
let (|IP6g|_|) e=let g=Regex.Match(e,ip6e) in if g.Success then Some(((fI [1..6] g)<<<32)+bigint(fL [7..5..22] g)) else None
let (|IP6e|_|) l=let g=Regex.Match(l,ip6l) in if g.Success then let n,l=fE g mg me in (if n.Length+l.Length<6 then Some(((fI n g)<<<((8-n.Length)*16))+((fI l g)<<<32)+bigint(fL ml g)) else None) else None
let (|IP6l|_|) n=match n with IP6n n->Some(Complete,fG n []) |IP6i n->Some(Compressed,fG n []) |IP6g n->Some(Composite,fG n []) |IP6e n->Some(CompressedComposite,fG n []) |_->None
let (|IP4p|_|) n=let g=Regex.Match(n,"^(.+):(\d{1,4})$") in if g.Success then match g.Groups.[1].Value with IP4 n->Some(n,int g.Groups.[2].Value) |_->None else None
let (|IP6p|_|) n=let g=Regex.Match(n,"^\[(.+)\]:(\d{1,4})$") in if g.Success then match g.Groups.[1].Value with IP6l n->Some(n,int g.Groups.[2].Value) |_->None else None
let pIP n=match n with IP6p((t,g),p)->printfn "%s is a %A IPv6 address value 0x%s using port %d" n t g p
                      |IP4 g->printfn "%s is an IPv4 address value %0x" n g
                      |IP6l(t,g)->printfn "%s is a %A IPv6 address value 0x%s" n t g
                      |IP4p(g,p)->printfn "%s is an IPv4 address value %0x using port %d" n g p
                      |_->printfn "%s not matched" n

["127.0.0.1";"127.0.0.1:80";"2605:2700:0:3::4713:93e3";"::1";"[::1]:80";"2605:2700:0:3::4713:93e3";"[2605:2700:0:3::4713:93e3]:80";
  "::ffff:127.0.0.1";"1:2:3:4:5:6:7:8";"1:2:3:4:5:6:7:8:9";"1:2:3:4:5:6:127.0.0.1"]|>List.iter pIP


package main

import (
	"encoding/hex"
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"
)

// parseIPPort parses an IP with an optional port, returning an IP and a port (or nil
// if no port was present in the given address).
func parseIPPort(address string) (net.IP, *uint64, error) {
	ip := net.ParseIP(address)
	if ip != nil {
		return ip, nil, nil
	}

	host, portStr, err := net.SplitHostPort(address)
	if err != nil {
		return nil, nil, fmt.Errorf("splithostport failed: %w", err)
	}

	port, err := strconv.ParseUint(portStr, 10, 16)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to parse port: %w", err)
	}

	ip = net.ParseIP(host)
	if ip == nil {
		return nil, nil, fmt.Errorf("failed to parse ip address")
	}

	return ip, &port, nil
}

func ipVersion(ip net.IP) int {
	if ip.To4() == nil {
		return 6
	}

	return 4
}

func main() {
	testCases := []string{
		"127.0.0.1",
		"127.0.0.1:80",
		"::1",
		"[::1]:443",
		"2605:2700:0:3::4713:93e3",
		"[2605:2700:0:3::4713:93e3]:80",
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)

	writeTSV := func(w io.Writer, args ...interface{}) {
		fmt.Fprintf(w, strings.Repeat("%s\t", len(args)), args...)
		fmt.Fprintf(w, "\n")
	}

	writeTSV(w, "Input", "Address", "Space", "Port")

	for _, addr := range testCases {
		ip, port, err := parseIPPort(addr)
		if err != nil {
			panic(err)
		}

		portStr := "n/a"
		if port != nil {
			portStr = fmt.Sprint(*port)
		}

		ipVersion := fmt.Sprintf("IPv%d", ipVersion(ip))

		writeTSV(w, addr, hex.EncodeToString(ip), ipVersion, portStr)
	}

	w.Flush()
}


import Data.List (isInfixOf)
import Numeric (showHex)
import Data.Char (isDigit)

data IPChunk = IPv6Chunk String | IPv4Chunk (String, String) |
    IPv6WithPort [IPChunk] String | IPv6NoPort [IPChunk] |
    IPv4WithPort IPChunk String | IPv4NoPort IPChunk |
    IPInvalid | IPZeroSection | IPUndefinedWithPort String |
    IPUndefinedNoPort

instance Show IPChunk where
    show (IPv6Chunk a) = a
    show (IPv4Chunk (a,b)) = a ++ b
    show (IPv6WithPort a p) = "IPv6 " ++ concatMap show a ++ " port " ++ p
    show (IPv6NoPort a) = "IPv6 " ++ concatMap show a ++ " no port"
    show (IPv4WithPort a p) = "IPv4 " ++ show a ++ " port " ++ p
    show (IPv4NoPort a) = "IPv4 " ++ show a
    show IPInvalid = "Invalid IP address"

isIPInvalid IPInvalid = True
isIPInvalid _ = False

isIPZeroSection IPZeroSection = True
isIPZeroSection _ = False

splitOn _ [] = []
splitOn x xs = let (a, b) = break (== x) xs in a : splitOn x (drop 1 b)

count x = length . filter (== x)

between a b x = x >= a && x <= b

none f = all (not . f)

parse1 [] = IPInvalid
parse1 "::" = IPUndefinedNoPort
parse1 ('[':':':':':']':':':ps) = if portIsValid ps then IPUndefinedWithPort ps else IPInvalid
parse1 ('[':xs) = if "]:" `isInfixOf` xs
    then let (a, b) = break (== ']') xs in
            if tail b == ":" then IPInvalid else IPv6WithPort (map chunk (splitOn ':' a)) (drop 2 b)
    else IPInvalid
parse1 xs
    | count ':' xs <= 1 && count '.' xs == 3 =
        let (a, b) = break (== ':') xs in case b of
                "" -> IPv4NoPort (chunk a)
                (':':ps) -> IPv4WithPort (chunk a) ps
                _ -> IPInvalid
    | count ':' xs > 1 && count '.' xs <= 3 =
        IPv6NoPort (map chunk (splitOn ':' xs))

chunk [] = IPZeroSection
chunk xs
    | '.' `elem` xs = case splitOn '.' xs of
        [a,b,c,d] -> let [e,f,g,h] = map read [a,b,c,d]
                     in if all (between 0 255) [e,f,g,h]
                            then let [i,j,k,l] = map (\n -> fill 2 $ showHex n "") [e,f,g,h]
                                 in IPv4Chunk (i ++ j, k ++ l)
                            else IPInvalid
    | ':' `notElem` xs && between 1 4 (length xs) && all (`elem` "0123456789abcdef") xs = IPv6Chunk (fill 4 xs)
    | otherwise = IPInvalid

fill n xs = replicate (n - length xs) '0' ++ xs

parse2 IPInvalid = IPInvalid
parse2 (IPUndefinedWithPort p) = IPv6WithPort (replicate 8 zeroChunk) p
parse2 IPUndefinedNoPort = IPv6NoPort (replicate 8 zeroChunk)
parse2 a = case a of
    IPv6WithPort xs p -> if none isIPInvalid xs && portIsValid p
        then let ys = complete xs
             in  if countChunks ys == 8
                     then IPv6WithPort ys p
                     else IPInvalid
        else IPInvalid
    IPv6NoPort xs -> if none isIPInvalid xs
        then let ys = complete xs
             in  if countChunks ys == 8
                     then IPv6NoPort ys
                     else IPInvalid
        else IPInvalid
    IPv4WithPort (IPv4Chunk a) p -> if portIsValid p
        then IPv4WithPort (IPv4Chunk a) p
        else IPInvalid
    IPv4NoPort (IPv4Chunk a) -> IPv4NoPort (IPv4Chunk a)
    _ -> IPInvalid

zeroChunk = IPv6Chunk "0000"

portIsValid a = all isDigit a && between 0 65535 (read a)

complete xs = case break isIPZeroSection xs of
    (_, [IPZeroSection]) -> []
    (ys, []) -> ys
    ([], (IPZeroSection:IPZeroSection:ys)) -> if any isIPZeroSection ys || countChunks ys > 7
        then []
        else replicate (8 - countChunks ys) zeroChunk ++ ys
    (ys, (IPZeroSection:zs)) -> if any isIPZeroSection zs || countChunks ys + countChunks zs > 7
        then []
        else ys ++ replicate (8 - countChunks ys - countChunks zs) zeroChunk ++ zs
    _ -> []

countChunks xs = foldl f 0 xs
    where f n (IPv4Chunk _) = n + 2
          f n (IPv6Chunk _) = n + 1

ip = parse2 . parse1

main = mapM_ (putStrLn . show . ip)
    ["127.0.0.1",                                  -- loop back
     "127.0.0.1:80",                               -- loop back +port
     "::1",                                        -- loop back
     "[::1]:80",                                   -- loop back +port
     "2605:2700:0:3::4713:93e3",                   -- Rosetta Code
     "[2605:2700:0:3::4713:93e3]:80"]              -- Rosetta Code


link printf, hexcvt

procedure main()
   L := ["192.168.0.1",                                # private
         "127.0.0.1",                                  # loop back
         "127.0.0.1:80",                               # loop back +port
         "2001:db8:85a3:0:0:8a2e:370:7334",            # doc, IPv6 for 555-1234
         "2001:db8:85a3::8a2e:370:7334",               # doc
         "::1",                                        # loop back
         "[::1]:80",                                   # loop back +port
         "::",                                         # unspecified
         "::ffff:192.168.0.1",                         # transition
         "2605:2700:0:3::4713:93e3",                   # RC
         "[2605:2700:0:3::4713:93e3]:80",              # RC
         "::ffff:71.19.147.227",                       # RC transition
         "[::ffff:71.19.147.227]:80",                  # RC transition  +port
         "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443", # doc +port
         "256.0.0.0",                                  # invalid
         "g::1"]                                       # invalid

   every x := !L do {
      if x ?  (ip := ipmatch(), port := portmatch(), pos(0)) then {
         if i := IPv4decode(ip) then
            printf("%s is the IPv4 address = x'%s'",x,i)
         else if i := IPv6decode(ip) then
               printf("%s is the IPv6 address = x'%s'",x,i)
         else {
            printf("%s is not a valid IP address\n",x)
            next
            }
         if \port then printf(" port=%s\n",port) else printf("\n")
         }
      else printf("%s is not an IP address\n",x)
      }
end

procedure ipmatch()                                #: match an ip v4/v6 address
static c4,c6
initial {
   c4 := &digits ++ '.'
   c6 := &digits ++ 'abcdef:'
   }
   suspend (="[" || ( (="::ffff:" || tab(many(c4))) | tab(many(c6)) ) || ="]") |
           ( ="::ffff:" || tab(many(c4))) |  tab(many(c6|c4))
end

procedure portmatch()                              #: match a port number
   return (=":",0 < (65536 > tab(many(&digits)))) | &null
end

procedure IPv4decode(s)                            #: match IPv4 to hex string
   s ? ( ip  := (0 <= (256 > tab(many(&digits)))), ip *:= 256, =".",
         ip +:= (0 <= (256 > tab(many(&digits)))), ip *:= 256, =".",
         ip +:= (0 <= (256 > tab(many(&digits)))), ip *:= 256, =".",
         ip +:= (0 <= (256 > tab(many(&digits)))),
         return right(hexstring(ip,,&lcase),8) )
end

procedure IPv6decode(s)                            #: IPv6 to hex string
   s ?:=  2(="[", tab(-1), ="]")                         # remove any []
   if find(".",s) then                                   # transitional
      s ? ( tab(many(':0')), ="ffff:",
            return right("ffff" || IPv4decode(tab(0)),32,"0") )
   else {
      h := t := ""
      s ? {
         while x := tab(find(":")) do {                  # head
            if *x <= 4 then h ||:= right(x,4,"0")
            if ="::" then break
            else move(1)
            }
         while x := tab(find(":")|0) do {                # tail
            if *x <= 4 then t ||:= right(x,4,"0")
            move(1) | break
            }
         if x := h || repl("0",32-(*h+*t)) || t then     # and insides
            return x
         }
      }
end


import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ParseIPAddress {

    public static void main(String[] args) {
        String [] tests = new String[] {"192.168.0.1", "127.0.0.1", "256.0.0.1", "127.0.0.1:80", "::1", "[::1]:80", "[32e::12f]:80", "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80", "2001:db8:85a3:0:0:8a2e:370:7334"};
        System.out.printf("%-40s %-32s   %s%n", "Test Case", "Hex Address", "Port");
        for ( String ip : tests ) {
            try {
                String [] parsed = parseIP(ip);
                System.out.printf("%-40s %-32s   %s%n", ip, parsed[0], parsed[1]);
            }
            catch (IllegalArgumentException e) {
                System.out.printf("%-40s Invalid address:  %s%n", ip, e.getMessage());
            }
        }
    }

    private static final Pattern IPV4_PAT = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)(?::(\\d+)){0,1}$");
    private static final Pattern IPV6_DOUBL_COL_PAT = Pattern.compile("^\\[{0,1}([0-9a-f:]*)::([0-9a-f:]*)(?:\\]:(\\d+)){0,1}$");
    private static String ipv6Pattern;
    static {
        ipv6Pattern = "^\\[{0,1}";
        for ( int i = 1 ; i <= 7 ; i ++ ) {
            ipv6Pattern += "([0-9a-f]+):";
        }
        ipv6Pattern += "([0-9a-f]+)(?:\\]:(\\d+)){0,1}$";
    }
    private static final Pattern IPV6_PAT = Pattern.compile(ipv6Pattern);

    private static String[] parseIP(String ip) {
        String hex = "";
        String port = "";

        //  IPV4
        Matcher ipv4Matcher = IPV4_PAT.matcher(ip);
        if ( ipv4Matcher.matches() ) {
            for ( int i = 1 ; i <= 4 ; i++ ) {
                hex += toHex4(ipv4Matcher.group(i));
            }
            if ( ipv4Matcher.group(5) != null ) {
                port = ipv4Matcher.group(5);
            }
            return new String[] {hex, port};
        }

        //  IPV6, double colon
        Matcher ipv6DoubleColonMatcher = IPV6_DOUBL_COL_PAT.matcher(ip);
        if ( ipv6DoubleColonMatcher.matches() ) {
            String p1 = ipv6DoubleColonMatcher.group(1);
            if ( p1.isEmpty() ) {
                p1 = "0";
            }
            String p2 = ipv6DoubleColonMatcher.group(2);
            if ( p2.isEmpty() ) {
                p2 = "0";
            }
            ip =  p1 + getZero(8 - numCount(p1) - numCount(p2)) + p2;
            if ( ipv6DoubleColonMatcher.group(3) != null ) {
                ip = "[" + ip + "]:" + ipv6DoubleColonMatcher.group(3);
            }
        }

        //  IPV6
        Matcher ipv6Matcher = IPV6_PAT.matcher(ip);
        if ( ipv6Matcher.matches() ) {
            for ( int i = 1 ; i <= 8 ; i++ ) {
                hex += String.format("%4s", toHex6(ipv6Matcher.group(i))).replace(" ", "0");
            }
            if ( ipv6Matcher.group(9) != null ) {
                port = ipv6Matcher.group(9);
            }
            return new String[] {hex, port};
        }

        throw new IllegalArgumentException("ERROR 103: Unknown address: " + ip);
    }

    private static int numCount(String s) {
        return s.split(":").length;
    }

    private static String getZero(int count) {
        StringBuilder sb = new StringBuilder();
        sb.append(":");
        while ( count > 0 ) {
            sb.append("0:");
            count--;
        }
        return sb.toString();
    }

    private static String toHex4(String s) {
        int val = Integer.parseInt(s);
        if ( val < 0 || val > 255 ) {
            throw new IllegalArgumentException("ERROR 101:  Invalid value : " + s);
        }
        return String.format("%2s", Integer.toHexString(val)).replace(" ", "0");
    }

    private static String toHex6(String s) {
        int val = Integer.parseInt(s, 16);
        if ( val < 0 || val > 65536 ) {
            throw new IllegalArgumentException("ERROR 102:  Invalid hex value : " + s);
        }
        return s;
    }

}


const testdata = ["127.0.0.1", "127.0.0.1:80", "::1", "[::1]:80",
                  "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80",
                  "::ffff:192.168.173.22", "[::ffff:192.168.173.22]:80",
                  "1::", "[1::]:80", "::", "[::]:80"]

maybev4(ip) = search(ip, '.') > 0 && length(matchall(r":", ip)) < 2
maybev6(ip) = length(matchall(r":", ip)) > 1

function parseip(ip)
    if (mat = match(r"^\[([:.\da-fA-F]+)\]:(\d+)$", ip))!= nothing ||
       (mat = match(r"^([\d.]+)[:/](\d+)$", ip)) != nothing
        port = mat.captures[2]
        ip = mat.captures[1]
    else
        port = "none"
    end
    if maybev4(ip)
        println("Processing ip v4 $ip")
        iphex = hex(Int(Base.IPv4(ip)))
        addresspace = "IPv4"
    elseif maybev6(ip)
        println("Processing ip v6 $ip")
        iphex = hex(UInt128(Base.IPv6(ip)))
        addresspace = "IPv6"
    else
        throw("Bad IP address argument $ip")
    end
    iphex, addresspace, port
end

for ip in testdata
    hx, add, por = parseip(ip)
    println("For input $ip, IP in hex is $hx, address space $add, port $por.")
end


// version 1.1.3

import java.math.BigInteger

enum class AddressSpace { IPv4, IPv6, Invalid }

data class IPAddressComponents(
    val address: BigInteger,
    val addressSpace: AddressSpace,
    val port: Int  // -1 denotes 'not specified'
)

val INVALID = IPAddressComponents(BigInteger.ZERO, AddressSpace.Invalid, 0)

fun ipAddressParse(ipAddress: String): IPAddressComponents {
    var addressSpace = AddressSpace.IPv4
    var ipa = ipAddress.toLowerCase()
    var port = -1
    var trans = false

    if (ipa.startsWith("::ffff:") && '.' in ipa) {
        addressSpace = AddressSpace.IPv6
        trans = true
        ipa = ipa.drop(7)
    }
    else if (ipa.startsWith("[::ffff:") && '.' in ipa) {
        addressSpace = AddressSpace.IPv6
        trans = true
        ipa = ipa.drop(8).replace("]", "")
    }
    val octets = ipa.split('.').reversed().toTypedArray()
    var address = BigInteger.ZERO
    if (octets.size == 4) {
        val split = octets[0].split(':')
        if (split.size == 2) {
            val temp = split[1].toIntOrNull()
            if (temp == null || temp !in 0..65535) return INVALID
            port = temp
            octets[0] = split[0]
        }

        for (i in 0..3) {
            val num = octets[i].toLongOrNull()
            if (num == null || num !in 0..255) return INVALID
            val bigNum = BigInteger.valueOf(num)
            address = address.or(bigNum.shiftLeft(i * 8))
        }

        if (trans) address += BigInteger("ffff00000000", 16)
    }
    else if (octets.size == 1) {
        addressSpace = AddressSpace.IPv6
        if (ipa[0] == '[') {
            ipa = ipa.drop(1)
            val split = ipa.split("]:")
            if (split.size != 2) return INVALID
            val temp = split[1].toIntOrNull()
            if (temp == null || temp !in 0..65535) return INVALID
            port = temp
            ipa = ipa.dropLast(2 + split[1].length)
        }
        val hextets = ipa.split(':').reversed().toMutableList()
        val len = hextets.size

        if (ipa.startsWith("::"))
            hextets[len - 1] = "0"
        else if (ipa.endsWith("::"))
            hextets[0] = "0"

        if (ipa == "::") hextets[1] = "0"
        if (len > 8 || (len == 8 && hextets.any { it == "" }) || hextets.count { it == "" } > 1)
            return INVALID
        if (len < 8) {
            var insertions = 8 - len
            for (i in 0..7) {
                if (hextets[i] == "") {
                    hextets[i] = "0"
                    while (insertions-- > 0) hextets.add(i, "0")
                    break
                }
            }
        }
        for (j in 0..7) {
            val num = hextets[j].toLongOrNull(16)
            if (num == null || num !in 0x0..0xFFFF) return INVALID
            val bigNum = BigInteger.valueOf(num)
            address = address.or(bigNum.shiftLeft(j * 16))
        }
    }
    else return INVALID

    return IPAddressComponents(address, addressSpace, port)
}

fun main(args: Array<String>) {
    val ipas = listOf(
        "127.0.0.1",
        "127.0.0.1:80",
        "::1",
        "[::1]:80",
        "2605:2700:0:3::4713:93e3",
        "[2605:2700:0:3::4713:93e3]:80",
        "::ffff:192.168.173.22",
        "[::ffff:192.168.173.22]:80",
        "1::",
        "::",
        "256.0.0.0",
        "::ffff:127.0.0.0.1"
    )
    for (ipa in ipas) {
        val (address, addressSpace, port) = ipAddressParse(ipa)
        println("IP address    : $ipa")
        println("Address       : ${"%X".format(address)}")
        println("Address Space : $addressSpace")
        println("Port          : ${if (port == -1) "not specified" else port.toString()}")
        println()
    }
}


import net, sequtils, strscans, strutils

const NoPort = -1

func parseIpAddressAndPort(str: string): tuple[ipAddr: IpAddress; port: int] =
  var ipString: string
  var port: int
  if str.scanf("[$+]:$i", ipString, port):
    # IP v6 address with port.
    return (ipString.parseIpAddress(), port)
  if '.' in str and str.scanf("$+:$i", ipString, port):
    # IP v4 address with port.
    return (ipString.parseIpAddress(), port)
  # IP address without port.
  result = (str.parseIpAddress(), NoPort)

const Inputs = ["127.0.0.1", "127.0.0.1:80",
                "::1", "[::1]:80",
                "2605:2700:0:3::4713:93e3",
                "[2605:2700:0:3::4713:93e3]:80"]

# Room to reserve to display the input.
const InputSize = Inputs.mapIt(it.len).foldl(max(a, b)) + 2

echo "Input".alignLeft(InputSize), "Address".align(32), "  Space", "  Port"

for input in Inputs:
  try:
    let (ipAddress, port) = input.parseIpAddressAndPort()
    let portStr = if port == NoPort: "" else: $port
    case ipAddress.family
    of IPv6:
      echo input.alignLeft(InputSize),
           ipAddress.address_v6.map(toHex).join().align(32),
           "IP v6".align(7),
           portStr.align(6)
    of IPv4:
      echo input.alignLeft(InputSize),
           ipAddress.address_v4.map(toHex).join().align(32),
           "IP v4".align(7),
           portStr.align(6)

  except ValueError:
    echo "Invalid IP address: ", input


with javascript_semantics
function parse_ip(string txt)
    sequence r
    integer dot = find('.',txt),
            colon = find(':',txt),
            openbr = find('[',txt),
            closebr = find(']',txt)
    if (colon=5 and txt[1..4] = "http")
    or (colon=6 and txt[1..5] = "https") then
        txt = trim(txt[colon+1..$],"/")
        return parse_ip(txt)
    end if
    bool ipv6 = openbr or dot=0 or (colon and colon<dot)
    if ipv6 then
        sequence res = repeat(0,8)
        if openbr then
            if openbr!=1 or closebr<openbr then return 0 end if
            r = scanf(txt[closebr+1..$],":%d")
            if length(r)!=1 then return 0 end if
            atom port = r[1][1]
            if port<0 or port>65535 then return 0 end if
            res &= port
            txt = txt[2..closebr-1]
        end if
        if dot then
            colon = rfind(':',txt)
            if colon>dot then return 0 end if
            object r4 = parse_ip(txt[colon+1..$])
            if not sequence(r4) or length(r4)!=4 then return 0 end if
            res[7] = r4[1]*#100+r4[2]
            res[8] = r4[3]*#100+r4[4]
            txt = txt[1..colon-1+(txt[colon-1]=':')]
            dot = 2
        end if
        sequence r8 = {}
        integer ip = 0
        while length(txt) do
            colon = find(':',txt)
            if colon=1 then
                if ip then return 0 end if
                ip = length(r8)+1
                txt = txt[2+(length(r8)=0)..$]
            else
                r = scanf(txt[1..colon-1],"%x")
                if length(r)!=1 then return 0 end if
                atom r11 = r[1][1]
                if r11<0 or r11>#FFFF then return 0 end if
                r8 &= r11
                if colon=0 then exit end if
                txt = txt[colon+1..$]
            end if
        end while
        if ip then
            if length(r8)>=(8-dot) then return 0 end if
            r8[ip..ip-1] = repeat(0,(8-dot)-length(r8))
        else
            if length(r8)!=8-dot then return 0 end if
        end if
        res[1..8-dot] = r8
        return res
    end if
    -- ipv4:
    if dot=0 or (colon and colon<dot) then return 0 end if
    string d4 = substitute(txt[1..colon-1],'.',' ')
    r = scanf(d4,"%d %d %d %d")
    if length(r)!=1 then return 0 end if
    r = r[1]
    for i=1 to length(r) do
        if r[i]<0 or r[i]>255 then return 0 end if
    end for
    if colon then
        sequence r2 = scanf(txt[colon+1..$],"%d")
        if length(r2)!=1 then return 0 end if
        atom port = r2[1][1]
        if port<0 or port>65535 then return 0 end if
        r &= port
    end if
    return r
end function

constant tests = {{"127.0.0.1",{127,0,0,1}},
                  {"127.0.0.1:80",{127,0,0,1,80}},
                  {"::1",{0,0,0,0,0,0,0,1}},
                  {"[::1]:80",{0,0,0,0,0,0,0,1,80}},
                  {"2605:2700:0:3::4713:93e3",{#2605,#2700,0,3,0,0,#4713,#93e3}},
                  {"[2605:2700:0:3::4713:93e3]:80",{#2605,#2700,0,3,0,0,#4713,#93e3,80}},
                  {"::ffff:192.168.173.22",{0,0,0,0,0,#ffff,#c0a8,#ad16}},
                  {"[::ffff:192.168.173.22]:80",{0,0,0,0,0,#ffff,#c0a8,#ad16,80}},
                  {"1::",{1,0,0,0,0,0,0,0}},
                  {"[1::]:80",{1,0,0,0,0,0,0,0,80}},
                  {"::",{0,0,0,0,0,0,0,0}},
                  {"[::]:80",{0,0,0,0,0,0,0,0,80}},
                  {"192.168.0.1",{192,168,0,1}},
                  {"2001:db8:85a3:0:0:8a2e:370:7334",{#2001,#db8,#85a3,0,0,#8a2e,#370,#7334}},
                  {"2001:db8:85a3::8a2e:370:7334",{#2001,#db8,#85a3,0,0,#8a2e,#370,#7334}},
                  {"[2001:db8:85a3:8d3:1319:8a2e:370:7334]:443",{#2001,#db8,#85a3,#8d3,#1319,#8a2e,#370,#7334,443}},
                  {"256.0.0.0",0},
                  {"g::1",0},
                  {"::ffff:127.0.0.0.1",0},
                  {"a::b::1",0},
                  {"0000",0},
                  {"0000:0000",0},
                  {"0000:0000:0000:0000:0000:0000:0000:0000",{0,0,0,0,0,0,0,0}},
                  {"0000:0000:0000::0000:0000",{0,0,0,0,0,0,0,0}},
                  {"0000::0000::0000:0000",0},
                  {"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",{#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff}},
                  {"ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff",0},
                  {"fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",{#fff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff}},
                  {"fff:ffff:0:ffff:ffff:ffff:ffff:ffff",{#fff,#ffff,0,#ffff,#ffff,#ffff,#ffff,#ffff}},
                  {"2001:0db8:0:0:0:0:1428:57ab",{#2001,#0db8,0,0,0,0,#1428,#57ab}},
                  {"2001:0db8::1428:57ab",{#2001,#0db8,0,0,0,0,#1428,#57ab}},
                  {"2001:0db8:0:0:8d3:0:0:0",{#2001,#0db8,0,0,#8d3,0,0,0}},
                  {"2001:0db8:0:0:8d3::",{#2001,#0db8,0,0,#8d3,0,0,0}},
                  {"2001:0db8::8d3:0:0:0",{#2001,#0db8,0,0,#8d3,0,0,0}},
                  {"http://127.0.0.1/",{127,0,0,1}},
                  {"https://127.0.0.1/",{127,0,0,1}},
                  {"http:",0},
                  {"http:/2001:db8:3:4::127.0.2.0",{#2001,#db8,3,4,0,0,#7F00,#200}},
                  {"::192.168.0.1",{0,0,0,0,0,0,#C0A8,1}},
                  {"::ffff:0:255.255.255.255",{0,0,0,0,#ffff,0,#ffff,#ffff}},
                  {"",0},
                  {"ffffffffffffffffffffffffffffffff::",0},
                  {"[1::]:9999999999999999999999999999",0},
                  {"I think that's enough tests for now",0}}

for i=1 to length(tests) do
    {string ip, object expected} = tests[i]
    object actual = parse_ip(ip)
    if actual!=expected then
        ?{ip,actual,expected}
        ?9/0
    end if
    string addr
    if actual=0 then
        addr = "**not a valid ip address**"
    else
        if remainder(length(actual),2) then
            actual[$] = sprintf(", port %d",actual[$])
        else
            actual = append(actual,"")
        end if
        if length(actual)=5 then
            addr = sprintf("ivp4 address: %02x%02x%02x%02x%s",actual)
        elsif length(actual)=9 then
            addr = sprintf("ivp6 address: %04x%04x%04x%04x%04x%04x%04x%04x%s",actual)
        else
            ?9/0
        end if
    end if
    printf(1,"%45s %s\n",{ip,addr})
end for


# Return a cons pair of address and port: (address . port)
(de ipAddress (Adr)
   (use (@A @B @C @D @Port)
      (cond
         ((match '("[" @A "]" ":" @Port) Adr)
            (adrIPv6 (split @A ":") @Port) )
         ((match '("[" @A "]") Adr)
            (adrIPv6 (split @A ":")) )
         ((match '(@A ":" @B ":" @C) Adr)
            (adrIPv6 (cons @A @B (split @C ":"))) )
         ((match '(@A "." @B "." @C "." @D ":" @Port) Adr)
            (adrIPv4 (list @A @B @C @D) @Port) )
         ((match '(@A "." @B "." @C "." @D) Adr)
            (adrIPv4 (list @A @B @C @D)) )
         (T (quit "Bad IP address" (pack Adr))) ) ) )

(de adrIPv4 (Lst Port)
   (cons
      (sum >> (-24 -16 -8 0) (mapcar format Lst))
      (format Port) ) )

(de adrIPv6 (Lst Port)
   (cons
      (sum >>
         (-112 -96 -80 -64 -48 -32 -16 0)
         (mapcan
            '((X)
               (if X
                  (cons (hex X))
                  (need (- 9 (length Lst)) 0) ) )  # Handle '::'
            (cons (or (car Lst) "0") (cdr Lst)) ) )
      (format Port) ) )


*process or(!) source xref attributes macro options;
 /*********************************************************************
 * Program to parse an IP address into -->   IPv4 or IPv6 format
 * 28.05.2013 Walter Pachl translated from REXX version 3
 *                         x2d was the hard part :-)
 *********************************************************************/
 ip: proc options(main);
 Dcl ipa   char(50) Var;
 Dcl ipi   char(50) Var;
 Dcl ipax  char(50) Var Init('');
 Dcl ipad  char(50) Var Init('');
 Dcl space char(4);
 Dcl port  char(5) Var;
 dcl head Char(132) Var;
 head='       input IP address                 hex IP address   '!!
      '                 decimal IP address            space  port';
 Put Edit(head)(Skip,a);
 Put Edit(copies('_',30),
          copies('_',32),
          copies('_',39),
          copies('_', 5),
          copies('_', 5))
         (Skip,6(a,x(1)));

 call expand('127.0.0.1');
 call expand('127.0.0.1:80');
 call expand('2605:2700:0:3::4713:93e3');
 call expand('[2605:2700:0:3::4713:93e3]:80');
 call expand('::1');
 call expand('[::1]:80');

 expand: procedure(s);
 Dcl s Char(50) Var;
 ipi=s;
 ipa=s;
 If index(ipa,'.')>0 Then
   Call expand_ipv4;
 Else
   Call expand_ipv6;
 ipad=x2d(ipax);
 Put Edit(left(ipi,30),right(ipax,32),right(ipad,39),
          right(space,5),right(port,5))
         (Skip,6(a,x(1)));
 End;

 expand_ipv4: Proc;
 Dcl a(4) Char(3) Var;
 Dcl (pp,j) Bin Fixed(31);
 space='IPv4';
 pp=index(ipa,':');
 If pp>0 Then Do;
   port=substr(ipa,pp+1);
   ipa=left(ipa,pp-1);
   End;
 Else
   Port='';
 Call parse((ipa),'.',a);
 ipax='';
 do j=1 To 4;
   ipax=ipax!!a(j);
   end;
 End;

 expand_ipv6: Proc;
 Dcl a(8) Char(4) Var;
 Dcl (s,o1,o2) Char(50) Var Init('');
 Dcl (i,ii,pp,j,n) Bin Fixed(31) Init(0);
 space='IPv6';
 pp=index(ipa,']:');
 If pp>0 Then Do;
   port=substr(ipa,pp+2);
   ipa=substr(ipa,2,pp-2);
   End;
 Else
   Port='';
 s=ipa;
 j=0;
 Do i=1 To 8 While(s>'');
   pp=index(s,':');
   dcl temp Char(6) Var;
   If pp>1 Then
     temp=left(s,pp-1);
   Else
     temp=s;
   temp=right(temp,4,'0');
   Select(pp);
     When(0) Do;
       a(i)=temp;
       s='';
       End;
     When(1) Do;
       a(i)='----';
       ii=i;
       s=substr(s,pp+1);
       If left(s,1)=':' Then
         s=substr(s,2);
       End;
     Otherwise Do;
       a(i)=temp;
       s=substr(s,pp+1);
       End;
     End;
   End;
 n=i-1;
 o1='';
 o2='';
 Do i=1 To n;
   If i=ii Then Do;
     o1=o1!!'----';
     Do j=1 To 9-n;
       o2=o2!!'0000';
       End;
     End;
   Else Do;
     o1=o1!!right(a(i),4,'0');
     o2=o2!!right(a(i),4,'0');
     End;
   End;
  ipax=o2;
 End;

 parse: Proc(s,c,a);
 Dcl s Char(50) Var;
 Dcl c Char( 1);
 Dcl a(*) Char(*) Var;
 Dcl (i,p) Bin Fixed(31);
 a='';
 Do i=1 By 1 While(length(s)>0);
   p=index(s,c);
   If p>0 Then Do;
     a(i)=left(s,p-1);
     s=substr(s,p+1);
     End;
   Else Do;
     a(i)=s;
     s='';
     End;
   End;
  End;

 /*
 underscore: Proc(s) Returns(char(132) Var);
 Dcl s Char(*);
 Dcl r Char(length(s)) Var Init('');
 Dcl i Bin Fixed(31);
 Dcl us Bit(1) Init('0'b);
 Do i=1 To length(s)-1;
   If substr(s,i,1)>' ' Then Do;
     r=r!!'_';
     us='1'b;
     End;
   Else Do;
     If substr(s,i+1,1)>' ' & us Then
       r=r!!'_';
     Else Do;
       r=r!!' ';
       us='0'b;
       End;
     End;
   End;
 If substr(s,length(s),1)>' ' Then
   r=r!!'_';
 Return(r);
 End;

 center: Proc(s,l) Returns(char(50) Var);
 Dcl s char(50) Var;
 Dcl (l,b) Bin Fixed(31);
 b=(l-length(s))/2;
 Return(left(copies(' ',b)!!s,l));
 End;
 */
 copies: Proc(c,n) Returns(char(50) Var);
 Dcl c char(50) Var;
 Dcl n Bin Fixed(31);
 Return(repeat(c,n-1));
 End;

 c2d: Procedure(s) Returns(Char(50) Var);
 Dcl s Char(*) Var;
 Dcl d Pic'99';
 Dcl (v,part,result,old) Char(100) Var;
 Dcl i Bin Fixed(31);
 result='0';
 v='1';

 Do i=length(s) To 1 By -1;
   d=c2d(substr(s,i,1));
   part=longmult((v),(d));
   result=longadd((result),(part));
   v=longmult((v),'16');
   End;
 Do While(left(result,1)='0');
   result=substr(result,2);
   End;
 Return(result);
 /*
 dbg: Proc(txt);
 Dcl txt Char(*);
 Put Skip list(txt);
 End;
 */
 x2d: Procedure(c) Returns(Char(2));
 Dcl c Char(1);
 Dcl res Char(2);
 Select(c);
   When('a','A') res='10';
   When('b','B') res='11';
   When('c','C') res='12';
   When('d','D') res='13';
   When('e','E') res='14';
   When('f','F') res='15';
   Otherwise res='0'!!c;
   End;
 Return(res);
 End;

 longmult: Procedure(as,bs) Returns(Char(1000) Var);
 /* REXX **************************************************************
 * Multiply(as,bs) -> as*bs
 *********************************************************************/
 Dcl (as,bs) Char(*);
 Dcl (a(1000),b(1000),r(1000)) Pic'9';
 Dcl (p,s) Pic'99';
 Dcl (al,bl) Bin Fixed(31);
 Dcl (i,ai,bi,ri,rim) Bin Fixed(31);
 Dcl res Char(1000) Var Init((1000)'0');
 al=length(as); Do ai=al To 1 By -1; a(ai)=substr(as,al-ai+1,1); End;
 bl=length(bs); Do bi=bl To 1 By -1; b(bi)=substr(bs,bl-bi+1,1); End;
 r=0;
 rim=0;
 Do bi=1 To bl;
   Do ai=1 To al;
     ri=ai+bi-1;
     p=a(ai)*b(bi);
     Do i=ri by 1 Until(p=0);
       s=r(i)+p;
       r(i)=mod(s,10);
       p=s/10;
       End;
     rim=max(rim,i);
     End;
   End;
 res='';
 Do i=1 To rim;
   res=r(i)!!res;
   End;
 Return(res);
 End;

 longadd: proc(as,bs) Returns(Char(100) Var);
 Dcl (as,bs) Char(*) Var;
 Dcl cs Char(100) Var Init('');
 Dcl (al,bl,cl,i) Bin Fixed(31);
 Dcl a(100) Pic'9' Init((100)0);
 Dcl b(100) Pic'9' Init((100)0);
 Dcl c(100) Pic'9' Init((100)0);
 Dcl temp Pic'99';
 al=length(as);
 bl=length(bs);
 Do i=1 To al; a(i)=substr(as,al-i+1,1); End;
 Do i=1 To bl; b(i)=substr(bs,bl-i+1,1); End;
 cl=max(al,bl)+1;
 Do i=1 To cl;
   temp=a(i)+b(i)+c(i);
   c(i)=mod(temp,10);
   c(i+1)=c(i+1)+temp/10;
   End;
 Do i=1 To cl;
   cs=c(i)!!cs;
   End;
 Return(cs);
 End;
 End;

 end;


V date = Time(2020, 2, 3)
print(‘First 15 palindrome dates after 2020-02-02 are:’)
V count = 0
L count < 15
   V date_formatted = date.format(‘YYYYMMDD’)
   I date_formatted == reversed(date_formatted)
      print(‘date = ’date.format(‘YYYY-MM-DD’))
      count++
   date += TimeDelta(days' 1)


function Get-IpAddress
{
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $InputObject
    )

    Begin
    {
        function Get-Address ([string]$Address)
        {
            if ($Address.IndexOf(".") -ne -1)
            {
                $Address, $port = $Address.Split(":")

                [PSCustomObject]@{
                    IPAddress = [System.Net.IPAddress]$Address
                    Port      = $port
                }
            }
            else
            {
                if ($Address.IndexOf("[") -ne -1)
                {
                    [PSCustomObject]@{
                        IPAddress = [System.Net.IPAddress]$Address
                        Port      = ($Address.Split("]")[-1]).TrimStart(":")
                    }
                }
                else
                {
                    [PSCustomObject]@{
                        IPAddress = [System.Net.IPAddress]$Address
                        Port      = $null
                    }
                }
            }
        }
    }
    Process
    {
        $InputObject | ForEach-Object {
            $address = Get-Address $_
            $bytes = ([System.Net.IPAddress]$address.IPAddress).GetAddressBytes()
            [Array]::Reverse($bytes)
            $i = 0
            $bytes | ForEach-Object -Begin   {[bigint]$decimalIP = 0} `
                                    -Process {$decimalIP += [bigint]$_ * [bigint]::Pow(256, $i); $i++} `
                                    -End     {[PSCustomObject]@{
                                                  Address = $address.IPAddress
                                                  Port    = $address.Port
                                                  Hex     = "0x$($decimalIP.ToString('x'))"}
                                             }
        }
    }
}


TYPE Date=[
  INT year
  BYTE month
  BYTE day]

BYTE FUNC IsLeapYear(INT y)
  IF y MOD 100=0 THEN
    IF y MOD 400=0 THEN
      RETURN (1)
    ELSE
      RETURN (0)
    FI
  FI

  IF y MOD 4=0 THEN
    RETURN (1)
  FI
RETURN (0)

BYTE FUNC GetMaxDay(INT y BYTE m)
  BYTE ARRAY MaxDay=[31 28 31 30 31 30 31 31 30 31 30 31]

  IF m=2 AND IsLeapYear(y)=1 THEN
    RETURN (29)
  FI
RETURN (MaxDay(m-1))

PROC NextDay(Date POINTER d)
  BYTE maxD

  d.day==+1
  maxD=GetMaxDay(d.year,d.month)
  IF d.day>maxD THEN
    d.day=1
    d.month==+1
    IF d.month>12 THEN
      d.month=1
      d.year==+1
    FI
  FI
RETURN

BYTE FUNC IsPalindrome(Date POINTER d)
  INT y

  y=d.year
  IF y/1000#d.day MOD 10 THEN
    RETURN (0)
  FI
  y==MOD 1000
  IF y/100#d.day/10 THEN
    RETURN (0)
  FI
  y==MOD 100
  IF y/10#d.month MOD 10 THEN
    RETURN (0)
  FI
  y==MOD 10
  IF y#d.month/10 THEN
    RETURN (0)
  FI
RETURN (1)

PROC PrintB2(BYTE x)
  IF x<10 THEN
    Put('0)
  FI
  PrintB(x)
RETURN

PROC PrintDateShort(Date POINTER d)
  PrintI(d.year) Put('-)
  PrintB2(d.month) Put('-)
  PrintB2(d.day)
RETURN

PROC Main()
  BYTE count
  Date d

  count=0
  d.year=2020 d.month=2 d.day=3
  WHILE count<15
  DO
    IF IsPalindrome(d) THEN
      PrintDateShort(d) PutE()
      count==+1
    FI
    NextDay(d)
  OD
RETURN


BEGIN # print future palindromic dates                                           #
    # a palindromic date must be of the form demn-nm-ed                          #
    # returns a string representation of n with at least 2 digits                #
    PROC two digits = ( INT n )STRING:
         BEGIN
             STRING result := whole( ABS n, 0 );
             IF ( UPB result - LWB result ) + 1 < 2 THEN "0" +=: result FI;
             IF n < 0 THEN "-" +=: result FI;
             result
         END # two digits # ;
    # possible years for a palindromic date                                      #
    []INT mn     = (  1, 10, 11, 20, 21, 30, 40, 50, 60, 70, 80, 90 );
    # months corresponding to the year for for a palindromic date                #
    []INT nm     = ( 10,  1, 11,  2, 12,  3,  4,  5,  6,  7,  8,  9 );
    # possible centuaries for a palindromic date                                 #
    []INT de     = ( 10, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50
                   , 51, 52, 60, 61, 62, 70, 71, 72, 80, 81, 82, 90, 91, 92
                   );
    # days corresponding to the centuary for a palindromic date                  #
    []INT ed     = (  1, 11, 21, 31,  2, 12, 22,  3, 13, 23,  4, 14, 24,  5
                   , 15, 25,  6, 16, 26,  7, 17, 27,  8, 18, 28,  9, 19, 29
                   );
    # max days per month ( february handled specifically in code )               #
    []INT max dd = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
    # current date in local time (Algol 68G extension)                           #
    []INT date   = local time;
    INT   yy now = local time[ 1 ] MOD  100;
    INT   cc now = local time[ 1 ] OVER 100;
    INT dates to print := 15; # maximum number of dates to print                 #
    FOR c pos FROM LWB de TO UPB de WHILE dates to print > 0 DO
        INT cc = de[ c pos ];
        INT dd = ed[ c pos ];
        FOR y pos FROM LWB nm TO UPB nm WHILE dates to print > 0 DO
            INT mm = nm[ y pos ];
            INT yy = mn[ y pos ];
            IF cc > cc now OR ( cc = cc now AND yy > yy now ) THEN
                # have a possible future date                                    #
                IF dd <= max dd[ mm ]
                OR ( mm = 2 AND dd = 29 AND yy MOD 4 = 0 )
                THEN
                    # have a valid future date                                   #
                    # no need to test yy = 0 as dd = 0 is impossible             #
                    dates to print -:= 1;
                    print( ( two digits( cc )
                           , two digits( yy )
                           , "-"
                           , two digits( mm )
                           , "-"
                           , two digits( dd )
                           , newline
                           )
                         )
                FI
            FI
        OD
    OD
END


from ipaddress import ip_address
from urllib.parse import urlparse

tests = [
    "127.0.0.1",
    "127.0.0.1:80",
    "::1",
    "[::1]:80",
    "::192.168.0.1",
    "2605:2700:0:3::4713:93e3",
    "[2605:2700:0:3::4713:93e3]:80" ]

def parse_ip_port(netloc):
    try:
        ip = ip_address(netloc)
        port = None
    except ValueError:
        parsed = urlparse('//{}'.format(netloc))
        ip = ip_address(parsed.hostname)
        port = parsed.port
    return ip, port

for address in tests:
    ip, port = parse_ip_port(address)
    hex_ip = {4:'{:08X}', 6:'{:032X}'}[ip.version].format(int(ip))
    print("{:39s}  {:>32s}  IPv{}  port={}".format(
        str(ip), hex_ip, ip.version, port ))


#lang racket

(require net/private/ip)

(define (bytes->hex bs)
  (string-append* (map (λ(n) (~r n #:base 16 #:min-width 2 #:pad-string "0"))
                       (bytes->list bs))))

(define (parse-ip str)
  (define-values [ipstr portstr]
    (match str
      [(regexp #rx"^([0-9.]+):([0-9]+)$" (list _ i p)) (values i p)]
      [(regexp #rx"^\\[([0-9a-fA-F:]+)\\]:([0-9]+)$" (list _ i p)) (values i p)]
      [_ (values str "")]))
  (define ip (make-ip-address ipstr))
  (define 4? (ipv4? ip))
  (define hex (bytes->hex ((if 4? ipv4-bytes ipv6-bytes) ip)))
  (displayln (~a (~a str #:min-width 30)
                 " "
                 (~a hex #:min-width 32 #:align 'right)
                 " ipv" (if 4? "4" "6") " " portstr)))

(for-each parse-ip
          '("127.0.0.1"
            "127.0.0.1:80"
            "::1"
            "[::1]:80"
            "2605:2700:0:3::4713:93e3"
            "[2605:2700:0:3::4713:93e3]:80"))


with Ada.Text_IO;
with Ada.Calendar.Formatting;
with Ada.Calendar.Arithmetic;

procedure Palindrome_Dates is
   Desired_Count : constant := 15;
   Start_Date    : constant String := "2020-01-01 00:00:00";

   use Ada.Calendar;

   function Is_Palindrome_Date (Date : Time) return Boolean is
      Image : String renames Formatting.Image (Date);
   begin
      return
        Image (1) = Image (10) and
        Image (2) = Image (9)  and
        Image (3) = Image (7)  and
        Image (4) = Image (6);
   end Is_Palindrome_Date;

   Date  : Ada.Calendar.Time := Formatting.Value (Start_Date);
   Count : Natural := 0;

   use type Ada.Calendar.Arithmetic.Day_Count;
begin
   loop
      if Is_Palindrome_Date (Date) then
         Ada.Text_IO.Put_Line (Formatting.Image (Date) (1 .. 10));
         Count := Count + 1;
      end if;
      exit when Count = Desired_Count;
      Date := Date + 1;
   end loop;
end Palindrome_Dates;


on palindromeDates(startYear, targetNumber)
    script o
        property output : {}
    end script

    set counter to 0
    set y to startYear
    repeat until ((counter = targetNumber) or (y > 9999))
        -- Derive a month number from the last two digits of the current year number. It's valid if it's in the range 1 to 12.
        set m to y mod 10 * 10 + y mod 100 div 10
        if ((m > 0) and (m < 13)) then
            -- Derive a day number from the first two digits of the year number.
            set d to y div 100 mod 10 * 10 + y div 1000
            -- It's valid if it's between 1 and 28. Otherwise, if it's between 29 and 31, check that it fits the month and year.
            -- In fact though, it'll only ever be 2 or 12 in the period containing the 15 palindromic dates after 2020.
            if ((d > 0) and ¬
                ((d < 29) ¬
                    or ((d < 31) and ((m is not 2) or ((d is 29) and (y mod 4 is 0) and ((y mod 100 > 0) or (y mod 400 is 0))))) ¬
                    or ((d is 31) and (m is not in {2, 4, 9, 6, 11})))) then
                -- If the figures represent a valid date, add a yyyy-mm-dd format text to the end of the output list.
                tell ((100000000 + y * 10000 + m * 100 + d) as text) to ¬
                    set end of o's output to text 2 thru 5 & ("-" & text 6 thru 7) & ("-" & text 8 thru 9)
                set counter to counter + 1
            end if
        end if
        set y to y + 1
    end repeat

    return o's output
end palindromeDates

palindromeDates(2021, 15)


date := 20200202
counter := 0

while (counter < 15) {
    date += 1, days
    date := SubStr(date, 1, 8)
    if (date = reverse(date))
    {
        FormatTime, fdate, % date, yyyy-MM-dd
        output .= fdate "`n"
        counter++
    }
}

MsgBox, 262144, , % output
return

reverse(n){
    for i, v in StrSplit(n)
        output := v output
    return output
}


# syntax: GAWK -f PALINDROME_DATES.AWK
BEGIN {
    show = 15
    year_b = 2020
    year_e = 9999
    split("31,28,31,30,31,30,31,31,30,31,30,31",daynum_array,",") # days per month in non leap year
    for (y=year_b; y<=year_e; y++) {
      daynum_array[2] = (y % 400 == 0 || (y % 4 == 0 && y % 100)) ? 29 : 28
      for (m=1; m<=12; m++) {
        for (d=1; d<=daynum_array[m]; d++) {
          ymd = sprintf("%04d%02d%02d",y,m,d)
          if (substr(ymd,1,1) == substr(ymd,8,1)) { # speed up
            if (ymd == reverse(ymd)) {
              arr[++n] = ymd
            }
          }
        }
      }
    }
    printf("%04d0101-%04d1231=%d years, %d palindromes, showing first and last %d\n",year_b,year_e,year_e-year_b+1,n,show)
    printf("YYYYMMDD YYYYMMDD\n")
    for (i=1; i<=show; i++) {
      printf("%s %s\n",arr[i],arr[n-show+i])
    }
    exit(0)
}
function reverse(str,  i,rts) {
    for (i=length(str); i>=1; i--) {
      rts = rts substr(str,i,1)
    }
    return(rts)
}


/*REXX program parses an  IP address  into  ──►  IPv4  or  IPv6 format,  optional pport.*/
_= "_";    say center('input IP address'   , 30),
               center('hex IP address'     , 32),
               center('decimal IP address' , 39)         "space  port"
           say copies(_, 30)   copies(_, 32)   copies(_, 39)   copies(_, 5)   copies(_, 5)
call IP_parse  127.0.0.1                         /*this simple  IP  doesn't need quotes.*/
call IP_parse '127.0.0.1:80'
call IP_parse '::1'
call IP_parse '[::1]:80'
call IP_parse '2605:2700:0:3::4713:93e3'
call IP_parse '[2605:2700:0:3::4713:93e3]:80'
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
IP_parse:  procedure;  parse arg a .;       hx=;              @.=;       numeric digits 50
           dot= pos(., a)\==0                    /*see if there is a dot present in IP. */

           if dot then do;   parse var   a    @.1  '.'  @.2  "."  @.3  '.'  @.4  ":"  port
                                            do j=1  for 4;    hx= hx  ||  d2x(@.j, 2)
                                            end   /*j*/
                       end
                  else do;   parse var  a  pureA  ']:'  port
                       _= space( translate( pureA, , '[]'), 0)        /*remove brackets.*/
                       parse var _ x '::' y
                                            do L=1  until x==''       /*get  left side. */
                                            parse var  x  @.L  ':'  x
                                            end   /*L*/
                       y= reverse(y)
                                            do r=8  by -1             /*get right side. */
                                            parse var  y  z  ':'  y;   if z=='' then leave
                                            @.r= reverse(z)
                                            end   /*r*/

                            do k=1  for 8;  hx=hx  ||  right( word(@.k 0, 1), 4, 0)
                            end   /*k*/
                       end

           say left(a,30) right(hx,32) right(x2d(hx),39) ' IPv' || (6-2*dot) right(port,5)
           return


dateTest$ = ""
total = 0

PRINT "Siguientes 15 fechas palindr¢micas al 2020-02-02:"
FOR anno = 2021 TO 9999
    dateTest$ = LTRIM$(STR$(anno))
    FOR mes = 1 TO 12
        IF mes < 10 THEN dateTest$ = dateTest$ + "0"
        dateTest$ = dateTest$ + LTRIM$(STR$(mes))
        FOR dia = 1 TO 31
            IF mes = 2 AND dia > 28 THEN EXIT FOR
            IF (mes = 4 OR mes = 6 OR mes = 9 OR mes = 11) AND dia > 30 THEN EXIT FOR
            IF dia < 10 THEN dateTest$ = dateTest$ + "0"
            dateTest$ = dateTest$ + LTRIM$(STR$(dia))
            FOR Pal = 1 TO 4
                IF MID$(dateTest$, Pal, 1) <> MID$(dateTest$, 9 - Pal, 1) THEN EXIT FOR
            NEXT Pal
            IF Pal = 5 THEN
               total = total + 1
               IF total <= 15 THEN PRINT LEFT$(dateTest$, 4); "-"; MID$(dateTest$, 5, 2); "-"; RIGHT$(dateTest$, 2)
            END IF
            IF total > 15 THEN
               EXIT FOR: EXIT FOR: EXIT FOR
            END IF
            dateTest$ = LEFT$(dateTest$, 6)
        NEXT dia
        dateTest$ = LEFT$(dateTest$, 4)
    NEXT mes
    dateTest$ = ""
NEXT anno
END


      INSTALL @lib$ + "DATELIB"
      DIM B% 8
      TestDate%=FN_today
      REPEAT
        $B%=FN_date$(TestDate%, "yyyyMMdd")
        FOR I%=0 TO 3
          IF ?(B% + I%) <> ?(B% + 7 - I%) EXIT FOR
        NEXT
        IF I%=4 PRINT FN_date$(TestDate%, "yyyy-MM-dd")
        TestDate%+=1
      UNTIL VPOS=15
      END


#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

bool is_palindrome(const char* str) {
    size_t n = strlen(str);
    for (size_t i = 0; i + 1 < n; ++i, --n) {
        if (str[i] != str[n - 1])
            return false;
    }
    return true;
}

int main() {
    time_t timestamp = time(0);
    const int seconds_per_day = 24*60*60;
    int count = 15;
    char str[32];
    printf("Next %d palindrome dates:\n", count);
    for (; count > 0; timestamp += seconds_per_day) {
        struct tm* ptr = gmtime(&timestamp);
        strftime(str, sizeof(str), "%Y%m%d", ptr);
        if (is_palindrome(str)) {
            strftime(str, sizeof(str), "%F", ptr);
            printf("%s\n", str);
            --count;
        }
    }
    return 0;
}


using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    static void Main()
    {
        foreach (var date in PalindromicDates(2021).Take(15)) WriteLine(date.ToString("yyyy-MM-dd"));
    }

    public static IEnumerable<DateTime> PalindromicDates(int startYear) {
        for (int y = startYear; ; y++) {
            int m = Reverse(y % 100);
            int d = Reverse(y / 100);
            if (IsValidDate(y, m, d, out var date)) yield return date;
        }

        int Reverse(int x) => x % 10 * 10 + x / 10;
        bool IsValidDate(int y, int m, int d, out DateTime date) => DateTime.TryParse($"{y}-{m}-{d}", out date);
    }
}


require 'ipaddr'

TESTCASES = ["127.0.0.1",                "127.0.0.1:80",
                "::1",                      "[::1]:80",
                "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80"]

output = [%w(String Address Port Family Hex),
          %w(------ ------- ---- ------ ---)]

def output_table(rows)
  widths = []
  rows.each {|row| row.each_with_index {|col, i| widths[i] = [widths[i].to_i, col.to_s.length].max }}
  format = widths.map {|size| "%#{size}s"}.join("\t")
  rows.each {|row| puts format % row}
end

TESTCASES.each do |str|
  case str  # handle port; IPAddr does not.
  when /\A\[(?<address> .* )\]:(?<port> \d+ )\z/x      # string like "[::1]:80"
    address, port = $~[:address], $~[:port]
  when /\A(?<address> [^:]+ ):(?<port> \d+ )\z/x       # string like "127.0.0.1:80"
    address, port = $~[:address], $~[:port]
  else                                                 # string with no port number
    address, port = str, nil
  end

  ip_addr = IPAddr.new(address)
  family = "IPv4" if ip_addr.ipv4?
  family = "IPv6" if ip_addr.ipv6?

  output << [str, ip_addr.to_s, port.to_s, family, ip_addr.to_i.to_s(16)]
end

output_table(output)


#include <iostream>
#include <string>
#include <boost/date_time/gregorian/gregorian.hpp>

bool is_palindrome(const std::string& str) {
    for (size_t i = 0, j = str.size(); i + 1 < j; ++i, --j) {
        if (str[i] != str[j - 1])
            return false;
    }
    return true;
}

int main() {
    using boost::gregorian::date;
    using boost::gregorian::day_clock;
    using boost::gregorian::date_duration;

    date today(day_clock::local_day());
    date_duration day(1);
    int count = 15;
    std::cout << "Next " << count << " palindrome dates:\n";
    for (; count > 0; today += day) {
        if (is_palindrome(to_iso_string(today))) {
            std::cout << to_iso_extended_string(today) << '\n';
            --count;
        }
    }
    return 0;
}


(defn valid-date? [[y m d]]
  (and (<= 1 m 12)
       (<= 1 d 31)))

(defn date-str [[y m d]]
  (format "%4d-%02d-%02d" y m d))

(defn yr->date [y]
  (let [[_ m d] (re-find #"(..)(..)" (apply str (reverse (str y))))]
    [y (Long. m) (Long. d)]))

(defn palindrome-dates [start-yr n]
  (->> (iterate inc start-yr)
       (map yr->date)
       (filter valid-date?)
       (map date-str)
       (take n)))


use std::{
    net::{IpAddr, SocketAddr},
    str::FromStr,
};

#[derive(Clone, Debug)]
struct Addr {
    addr: IpAddr,
    port: Option<u16>,
}

impl std::fmt::Display for Addr {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let ipv = if self.addr.is_ipv4() { "4" } else { "6" };

        let hex = match self.addr {
            IpAddr::V4(addr) => u32::from(addr) as u128,
            IpAddr::V6(addr) => u128::from(addr),
        };

        match self.port {
            Some(p) => write!(
                f,
                "address: {}, port: {}, hex: {:x} (IPv{})",
                self.addr, p, hex, ipv
            ),

            None => write!(
                f,
                "address: {}, port: N/A, hex: {:x} (IPv{}) ",
                self.addr, hex, ipv
            ),
        }
    }
}

impl FromStr for Addr {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(addr) = s.parse::<IpAddr>() {
            Ok(Self { addr, port: None })
        } else if let Ok(sock) = s.parse::<SocketAddr>() {
            Ok(Self {
                addr: sock.ip(),
                port: Some(sock.port()),
            })
        } else {
            Err(())
        }
    }
}

fn print_addr(s: &str) {
    match s.parse::<Addr>() {
        Ok(addr) => println!("{}: {}", s, addr),
        _ => println!("{} not a valid address", s),
    }
}

fn main() {
    [
        "127.0.0.1",
        "127.0.0.1:80",
        "::1",
        "[::1]:80",
        "2605:2700:0:3::4713:93e3",
        "[2605:2700:0:3::4713:93e3]:80",
    ]
    .iter()
    .cloned()
    .for_each(print_addr);
}


object IPparser extends App {

  /*
  Parse an IP (v4/v6) Address

  This software can parse all ipv4/ipv6 address text representations
  of IP Address in common usage against the IEF RFC 5952 specification.

  The results of the parse are:
  - The parts of the text are valid representations. This is indicated in the list by a ✔ or ✘.
  - The intended version; 4 or 6.
  - Compliance with RFC 5952 in respect with double colons Compressed zeroes expansion ('::') and lower case letters.
  - Hexadecimal representation of the intended IP address.
  - If part in the text the port number which is optional.
  - The used text string search pattern.

  As much of the information is produced if there are invalid parts in the remark field.
  */

  def myCases = Map(
    "http:"                                      -> IPInvalidAddressComponents(remark = "No match at all: 'http:'."),
    "http://"                                    -> IPInvalidAddressComponents(remark = "No match at all: 'http://'."),
    "http:// "                                   -> IPInvalidAddressComponents(remark = "No match at all: 'http:// '."),
    "http://127.0.0.1/"                          -> ResultContainer(4, BigInt("7F000001", 16)),
    "http://127.0.0.1:80/"                       -> ResultContainer(4, BigInt("7F000001", 16), Some(80)),
    "http://127.0.0.1:65536" ->
      IPInvalidAddressComponents(4, BigInt("7F000001", 16), Some(65536), remark = "Port number out of range."),
    "http://192.168.0.1"                         -> ResultContainer(4, BigInt("C0A80001", 16)),
    "http:/1::"                                  -> ResultContainer(6, BigInt("10000000000000000000000000000", 16)),
    "http:/2001:0db8:0:0:0:0:1428:57ab/"         -> ResultContainer(6, BigInt("20010db80000000000000000142857ab", 16)),
    "2001:0db8:0:0:8d3:0:0:0"                    -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
    "2001:db8:0:0:8d3::"                         -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
    "http:/2001:db8:3:4::192.0.2.33"                   -> ResultContainer(6, BigInt("20010db80003000400000000c0000221", 16)),
    "2001:db8:85a3:0:0:8a2e:370:7334"            -> ResultContainer(6, BigInt("20010db885a3000000008a2e03707334", 16)),
    "2001:db8::1428:57ab"                        -> ResultContainer(6, BigInt("20010db80000000000000000142857ab", 16)),
    "2001:db8::8d3:0:0:0"                        -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
    "256.0.0.0"                                  -> IPInvalidAddressComponents(4, remark = "Invalid octets."),
    "2605:2700:0:3::4713:93e3"                   -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16)),
    "::"                                         -> ResultContainer(6, BigInt("00000000000000000000000000000000", 16)),
    "1::8"                                       -> ResultContainer(6, BigInt("00010000000000000000000000000008", 16)),
    "::1"                                        -> ResultContainer(6, BigInt("00000000000000000000000000000001", 16)),
    "::192.168.0.1"                              -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16)),
    "::255.255.255.255"                          -> ResultContainer(6, BigInt("000000000000000000000000ffffffff", 16)),
    "http:/[::255.255.255.255]:65536" ->
      IPInvalidAddressComponents(6, BigInt("000000000000000000000000ffffffff", 16), Some(65536), remark = "Port number out of range."),
    "::2:3:4:5:6:7:8"                            -> ResultContainer(6, BigInt("00000002000300040005000600070008", 16), strictRFC5952 = false),
    "::8"                                        -> ResultContainer(6, BigInt("00000000000000000000000000000008", 16)),
    "::c0a8:1"                                   -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16)),
    "::ffff:0:255.255.255.255"                   -> ResultContainer(6, BigInt("0000000000000000ffff0000ffffffff", 16)),
    "::ffff:127.0.0.0.1"                         -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':127.0.0.0.1'."),
    "::ffff:127.0.0.1"                           -> ResultContainer(6, BigInt("00000000000000000000ffff7f000001", 16)),
    "::ffff:192.168.0.1"                         -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16)),
    "::ffff:192.168.173.22"                      -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16)),
    "::ffff:255.255.255.255"                     -> ResultContainer(6, BigInt("00000000000000000000ffffffffffff", 16)),
    "::ffff:71.19.147.227"                       -> ResultContainer(6, BigInt("00000000000000000000ffff471393e3", 16)),
    "1:2:3:4:5:6:7::"                            -> ResultContainer(6, BigInt("00010002000300040005000600070000", 16), strictRFC5952 = false),
    "8000:2:3:4:5:6:7::"                         -> ResultContainer(6, BigInt("80000002000300040005000600070000", 16), strictRFC5952 = false),
    "1:2:3:4:5:6::8"                             -> ResultContainer(6, BigInt("00010002000300040005000600000008", 16), strictRFC5952 = false),
    "1:2:3:4:5::8"                               -> ResultContainer(6, BigInt("00010002000300040005000000000008", 16)),
    "1::7:8"                                     -> ResultContainer(6, BigInt("00010000000000000000000000070008", 16)),
    "a::b::1"                                    -> IPInvalidAddressComponents(remark = "Noise found: 'a::b::1'."),
    "fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"     -> ResultContainer(6, BigInt("0fffffffffffffffffffffffffffffff", 16)),
    "FFFF:ffff:ffff:ffff:ffff:ffff:ffff:ffff"    -> ResultContainer(6, BigInt("ffffffffffffffffffffffffffffffff", 16), strictRFC5952 = false),
    "ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff"    -> IPInvalidAddressComponents(remark = "No match at all: 'ffff:ffff:ffff:fffg…'."),
    "g::1"                                       -> IPInvalidAddressComponents(6, remark ="Invalid input 'g::1'."),
    "[g::1]:192.0.2.33"                          -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':192.0.2.33'."),
    "1:2:3:4:5:6:7:8"                            -> ResultContainer(6, BigInt("00010002000300040005000600070008", 16)),
    "1:2:3:4:5::7:8"                             -> ResultContainer(6, BigInt("00010002000300040005000000070008", 16), strictRFC5952 = false),
    "1:2:3:4::6:7:8"                             -> ResultContainer(6, BigInt("00010002000300040000000600070008", 16), strictRFC5952 = false),
    "1:2:3:4::8"                                 -> ResultContainer(6, BigInt("00010002000300040000000000000008", 16)),
    "1:2:3::5:6:7:8"                             -> ResultContainer(6, BigInt("00010002000300000005000600070008", 16), strictRFC5952 = false),
    "1:2:3::8"                                   -> ResultContainer(6, BigInt("00010002000300000000000000000008", 16)),
    "1:2::4:5:6:7:8"                             -> ResultContainer(6, BigInt("00010002000000040005000600070008", 16), strictRFC5952 = false),
    "1:2::8"                                     -> ResultContainer(6, BigInt("00010002000000000000000000000008", 16)),
    "1::3:4:5:6:7:8"                             -> ResultContainer(6, BigInt("00010000000300040005000600070008", 16), strictRFC5952 = false),
    "1::4:5:6:7:8"                               -> ResultContainer(6, BigInt("00010000000000040005000600070008", 16)),
    "1::5:6:7:8"                                 -> ResultContainer(6, BigInt("00010000000000000005000600070008", 16)),
    "[1::6:7:8]"                                 -> ResultContainer(6, BigInt("0010000000000000000000600070008", 16)),
    "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"    -> ResultContainer(6, BigInt("ffffffffffffffffffffffffffffffff", 16)),
    "64:ff9b::192.0.2.33"                        -> ResultContainer(6, BigInt("0064ff9b0000000000000000c0000221", 16)),
    "64:ff9b::256.0.2.33" ->
      IPInvalidAddressComponents(6, BigInt("0064ff9b000000000000000000000000", 16), remark = "Invalid octets."),
    "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443" -> ResultContainer(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(443)),
    "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:100000" ->
      IPInvalidAddressComponents(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(100000), remark = "Port number out of range."),
    "[2605:2700:0:3::4713:93e3]:80"              -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16), Some(80)),
    "[::ffff:192.168.0.1]:22"                    -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16), Some(22)),
    "[::ffff:192.168.173.22]:80"                 -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16), Some(80)),
    "[::ffff:71.19.147.227]:80"                  -> ResultContainer(6, BigInt("00000000000000000000FFFF471393E3", 16), Some(80)),
    "2001:0DB8:0:0:0:0:1428:57AB"                -> ResultContainer(6, BigInt("20010DB80000000000000000142857AB", 16), strictRFC5952 = false),
    "2001:0DB8:0:0:8D3:0:0:0"                    -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
    "2001:DB8:0:0:8D3::"                         -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
    "2001:DB8:3:4::192.0.2.33"                   -> ResultContainer(6, BigInt("20010DB80003000400000000C0000221", 16), strictRFC5952 = false),
    "2001:DB8:85A3:0:0:8A2E:370:7334"            -> ResultContainer(6, BigInt("20010DB885A3000000008A2E03707334", 16), strictRFC5952 = false),
    "2001:DB8::1428:57AB"                        -> ResultContainer(6, BigInt("20010DB80000000000000000142857AB", 16), strictRFC5952 = false),
    "2001:DB8::8D3:0:0:0"                        -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
    "2605:2700:0:3::4713:93E3"                   -> ResultContainer(6, BigInt("260527000000000300000000471393E3", 16), strictRFC5952 = false),
    "::192.168.0.1"                              -> ResultContainer(6, BigInt("000000000000000000000000C0A80001", 16)),
    "::255.255.255.255"                          -> ResultContainer(6, BigInt("000000000000000000000000FFFFFFFF", 16)),
    "::C0A8:1"                                   -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16), strictRFC5952 = false),
    "::FFFF:0:255.255.255.255"                   -> ResultContainer(6, BigInt("0000000000000000FFFF0000FFFFFFFF", 16), strictRFC5952 = false),
    "::FFFF:127.0.0.0.1"                         -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':127.0.0.0.1'."),
    "::FFFF:127.0.0.1"                           -> ResultContainer(6, BigInt("00000000000000000000FFFF7F000001", 16), strictRFC5952 = false),
    "::FFFF:192.168.0.1"                         -> ResultContainer(6, BigInt("00000000000000000000FFFFC0A80001", 16), strictRFC5952 = false),
    "::FFFF:192.168.173.22"                      -> ResultContainer(6, BigInt("00000000000000000000FFFFC0A8AD16", 16), strictRFC5952 = false),
    "::FFFF:255.255.255.255"                     -> ResultContainer(6, BigInt("00000000000000000000FFFFFFFFFFFF", 16), strictRFC5952 = false),
    "::FFFF:71.19.147.227"                       -> ResultContainer(6, BigInt("00000000000000000000FFFF471393E3", 16), strictRFC5952 = false),
    "[1::]:80"                                   -> ResultContainer(6, BigInt("00010000000000000000000000000000", 16), Some(80)),
    "[2001:DB8:85A3:8D3:1319:8A2E:370:7348]:443" -> ResultContainer(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(443), strictRFC5952 = false),
    "[2605:2700:0:3::4713:93E3]:80"              -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16), Some(80), strictRFC5952 = false),
    "[::1]:80"                                   -> ResultContainer(6, BigInt("00000000000000000000000000000001", 16), Some(80)),
    "[::1]:65536" ->
      IPInvalidAddressComponents(6, BigInt("00000000000000000000000000000001", 16), Some(65536), remark = "Port number out of range."),
    "[::]:80"                                    -> ResultContainer(6, BigInt("00000000000000000000000000000000", 16), Some(80)),
    "[::FFFF:192.168.0.1]:22"                    -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16), Some(22), strictRFC5952 = false),
    "[::FFFF:192.168.173.22]:80"                 -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16), Some(80), strictRFC5952 = false),
    "[::FFFF:71.19.147.227]:80"                  -> ResultContainer(6, BigInt("00000000000000000000ffff471393e3", 16), Some(80), strictRFC5952 = false),
    "A::B::1"                                    -> IPInvalidAddressComponents(remark = "Noise found: 'A::B::1'."),
    "FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"     -> ResultContainer(6, BigInt("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16), strictRFC5952 = false),
    "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"    -> ResultContainer(6, BigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16), strictRFC5952 = false),
    "FFFF:FFFF:FFFF:FFFG:FFFF:FFFF:FFFF:FFFF"    -> IPInvalidAddressComponents(remark = "No match at all: 'FFFF:FFFF:FFFF:FFFG…'."),
    "G::1"                                       -> IPInvalidAddressComponents(6, remark = "Invalid input 'G::1'."),
    "64:FF9B::192.0.2.33"                        -> ResultContainer(6, BigInt("0064FF9B0000000000000000C0000221", 16), strictRFC5952 = false),
    "64:FF9B::256.0.2.33" -> IPInvalidAddressComponents(6, BigInt("0064FF9B000000000000000000000000", 16), remark = "Invalid octets.")
    )

  def IPInvalidAddressComponents(version: Int = 0,
                                 address: BigInt = BigInt(0),
                                 port: Option[Int] = None,
                                 valid: Boolean = false,
                                 remark: String = "",
                                 strict: Boolean = false) = ResultContainer(version, address, port, valid, remark, strict)

  case class ResultContainer(version: Int,
                             address: BigInt,
                             port: Option[Int] = None,
                             valid: Boolean = true,
                             remark: String = "",
                             strictRFC5952: Boolean = true)

  class IpAddress(val originalString: String) {

    import IpAddress._

    val (usedPattern, result: ResultContainer) = originalString match {
      case trapPattern() => (trapPattern, IPInvalidAddressComponents(remark = s"Noise found: '${shortener(originalString)}'."))
      case allIpV6PortedPatternsCompiled(adr, port) => parseIpV6(adr, Option(port).map(_.toInt))
      case allIpV6UnspecPortPatternsCompiled(adr) => parseIpV6(adr)
      case ipV4PortSpecCompiled(adr, port) => (ipV4PortSpecCompiled, parseIpV4(adr, Option(port).map(_.toInt)))
      case _ => ("Exhausted of all matches.", IPInvalidAddressComponents(remark = s"No match at all: '${shortener(originalString, 19)}'."))
    }

    override def toString: String = {
      def hexAddr = if (result.version == 6) f"${result.address}%#034x" else f"${result.address}%#010x"

      def validInd = if (result.valid) '\u2714' else '\u2718'

      def rfc5952 = if (result.strictRFC5952) "comply" else "broken"

      def version = result.version match {
        case 0 => "   ?"
        case 4 => "IPv4"
        case 6 => "IPv6"
      }

      def surround(s: String) = if (result.valid) s" $s " else s"($s)"

      def port = if (result.port.isDefined) surround(result.port.get.toString) else if (result.valid) " " else "? "

      def hexAddrField = f"${if (result.valid || result.address != 0) surround(hexAddr) else "? "}%36s "

      f"${shortener(originalString, 45)}%46s $version $validInd $rfc5952 $hexAddrField $port%8s ${result.remark}%-40s $usedPattern"
    }

    def shortener(s: String, maxlength: Int = 12): String = {
      val size = s.length()
      s.substring(0, math.min(size, maxlength)) + (if (size > maxlength) "…" else "")
    }

    private def parseIpV6(ipAddress: String, port: Option[Int] = None): (String, ResultContainer) = {

      def colonedStringToBigInt(colonedString: String): (BigInt, Int) = {
        // Compressed zeroes expansion
        val ar = if (colonedString contains "::") colonedString.split("::", 2) else Array("", colonedString)
        val (left, right) = (ar.head.split(':').filterNot(_.isEmpty), ar(1).split(':').filterNot(_.isEmpty))
        val sixteenBitExpansions = 8 - (right.length + left.length)

        ((left ++ Seq.fill(sixteenBitExpansions)("0") ++ right)
          .map(BigInt(_, 16).toLong).map(BigInt(_)).reduceLeft((acc, i) => (acc << 16) | i),
          sixteenBitExpansions)
      }

      def parseEmbeddedV4(seg: String, ip4Seg: String, usedRegEx: String): (String, ResultContainer) = {
        val (ip4, ip6Parser, test) =
          (parseIpV4(ip4Seg), colonedStringToBigInt(seg.replaceFirst(ipV4Regex("3"), "0:0")), portNumberTest(port))

        (usedRegEx, ResultContainer(originalString, 6, ip4.address + ip6Parser._1, port,
          ip4.valid && test.isEmpty, ip4.remark + test, ip4.valid && test.isEmpty))
      }

      if (!ipAddress.forall((('A' to 'F') ++ ('a' to 'f') ++ ('0' to '9') ++ Vector(':', '.')).contains(_)))
        ("[^:.[0-9][A-F][a-f]]", IPInvalidAddressComponents(6, remark = s"Invalid input '${shortener(ipAddress)}'."))
      else
        ipAddress match {
          case pattern10Compiled(seg, ip4Seg) => parseEmbeddedV4(seg, ip4Seg, pattern10Compiled.toString())
          case pattern11Compiled(seg, ip4Seg) => parseEmbeddedV4(seg, ip4Seg, pattern11Compiled.toString())
          case ip6PatternsRawCompiled(seg, _*) =>
            val (ip6Parser, test) = (colonedStringToBigInt(seg), portNumberTest(port))

            (ip6PatternsRawCompiled.toString(),
              ResultContainer(ipAddress, 6, ip6Parser._1, port,
                valid = test.isEmpty, test, strictRFC5952 = ip6Parser._2 != 1 && test.isEmpty))
          case _ => ("V6 match exhausted.", IPInvalidAddressComponents(6, remark = "V6 address puntation error."))
        }
    } // parseIpV6

    private def parseIpV4(sIP: String, port: Option[Int] = None): ResultContainer = {

      def wordsToNum(words: Array[Long]): Long = words.reduceLeft((acc, i) => (acc << 8) | i)

      if (sIP.head.isDigit && sIP.matches(ipV4Regex("3"))) {
        val octets = sIP.split('.').map(_.toLong)
        if (octets.forall(_ < 256)) {
          val portNumberOK = portNumberTest(port)
          ResultContainer(4, BigInt(wordsToNum(octets)), port, portNumberOK.isEmpty, portNumberOK, portNumberOK.isEmpty)
        } else IPInvalidAddressComponents(4, remark = "Invalid octets.")
      }
      else IPInvalidAddressComponents(4, remark = s"Address puntation error: '${shortener(sIP)}'.")
    }

    private def portNumberTest(port: Option[Int]) = if (port.isEmpty || port.get < math.pow(2, 16)) "" else "Port number out of range."
  } // IpAddress

  object IpAddress {
    val (ip6PatternsRawCompiled, pattern11Compiled) = (ipV6Patterns.mkString("(", "|", ")").r, embeddedV4patterns()(1).r)
    val (trapPattern, pattern10Compiled) = (""".*?(?:(?:\w*:{2,}?){2,}?\w)|(?:\[?)""".r, embeddedV4patterns().head.r)
    val allIpV6PortedPatternsCompiled = ("""[^\\.]*?\[(""" + allIpV6 +""")\](?::(\d{1,6}))?[^\.:]*?""").r
    val allIpV6UnspecPortPatternsCompiled = (""".*?(""" + allIpV6 +""")[^\.:]*?""").r
    val ipV4PortSpecCompiled = s".*?([:.\\]]?${ipV4Regex()})(?::(\\d{1,6}))?.*?".r

    // Make a regex pattern with non-capturing groups by the disabling the capturing group syntax (?:).
    def allIpV6 = (embeddedV4patterns("(?:") ++ ipV6Patterns).map(s => "(?:" + s.drop(1)).mkString("|")

    def ipV6Patterns = {
      def ipV6SegRegWC = """\w{1,4}"""

      Seq(
        s"((?::(?:(?::$ipV6SegRegex){1,7}|:)))",
        s"((?:$ipV6SegRegWC:(?::$ipV6SegRegex){1,6}))",
        s"((?:$ipV6SegRegex:){1,2}(?::$ipV6SegRegex){1,5})",
        s"((?:$ipV6SegRegex:){1,3}(?::$ipV6SegRegex){1,4})",
        s"((?:$ipV6SegRegex:){1,4}(?::$ipV6SegRegex){1,3})",
        s"((?:$ipV6SegRegex:){1,5}(?::$ipV6SegRegex){1,2})",
        s"((?:$ipV6SegRegex:){1,6}:$ipV6SegRegex)",
        s"((?:$ipV6SegRegex:){1,7}:)",
        s"((?:$ipV6SegRegex:){7}$ipV6SegRegex)"
      )
    }

    private def embeddedV4patterns(nonCapturePrefix: String = "(") =
      Seq(s"(::(?:(?:FFFF|ffff)(?::0{1,4}){0,1}:){0,1}$nonCapturePrefix${ipV4Regex("3")}))",
        s"((?:$ipV6SegRegex:){1,4}:$nonCapturePrefix${ipV4Regex("3")}))")

    private def ipV6SegRegex = """[\dA-Fa-f]{1,4}"""

    private def ipV4Regex(octets: String = "3,") = s"(?:\\d{1,3}\\.){$octets}\\d{1,3}"
  }

  object ResultContainer {
    def apply(orginalString: String, version: Int,
              address: BigInt, port: Option[Int],
              valid: Boolean, remark: String,
              strictRFC5952: Boolean): ResultContainer =
    // To comply with strictRFC5952 all alpha character must be lowercase too.
      this (version, address, port, valid, remark, strictRFC5952 && !orginalString.exists(_.isUpper))
  }

  {
    val headline = Seq(f"${"IP addresses to be parsed. "}%46s", "Ver.", f"${"S"}%1s", "RFC5952",
      f"${"Hexadecimal IP address"}%34s", f"${"Port "}%10s", f"${" Remark"}%-40s", f"${" Effective RegEx"}%-40s")

    println(headline.mkString("|") + "\n" + headline.map(s => "-" * s.length).mkString("+"))

    val cases: Set[IpAddress] = myCases.keySet.map(new IpAddress(_))

    println(cases.toList.sortBy(s => (s.originalString.length, s.originalString)).mkString("\n"))
    logInfo(s"Concluding: ${myCases.size} cases processed, ${cases.count(_.result.valid)} valid ✔ and ${cases.count(!_.result.valid)} invalid ✘.")
    logInfo("Successfully completed without errors.")

    def logInfo(info: String) {
      println(f"[Info][${System.currentTimeMillis() - executionStart}%5d ms]" + info)
    }
  }

} // IPparser cloc.exe : 235 loc


// palindrome_dates.fsx
open System

let is_palindrome_date =
    let date_string (date: DateTime) = date.ToString "yyyyMMdd"
    let is_palindrome s =
        let rev_string = Seq.rev >> Seq.map string >> String.concat ""
        s = rev_string s
    date_string >> is_palindrome

let palindrome_dates =
    let rec loop date =
        seq {
            if is_palindrome_date date
            then
                yield date
                yield! loop (date.AddDays 1.0)
            else
                yield! loop (date.AddDays 1.0)
        }
    loop DateTime.Now

let print_date =
    let iso_string (date: DateTime) = date.ToString "yyyy-MM-dd"
    iso_string >> printfn "%s"

palindrome_dates
|> Seq.take 15
|> Seq.iter print_date


USING: calendar calendar.format io kernel lists lists.lazy
sequences sets ;

: palindrome-dates ( -- list )
    2020 2 2 <date> [ 1 days time+ ] lfrom-by
    [ timestamp>ymd ] lmap-lazy
    [ "-" without dup reverse = ] lfilter ;

15 palindrome-dates ltake [ print ] leach


Dim As String dateTest = ""
Dim As Integer Pal =0, total = 0
Print "Siguientes 15 fechas palindr¢micas al 2020-02-02:"
For anno As Integer = 2021 To 9999
    dateTest = Ltrim(Str(anno))
    For mes As Integer = 1 To 12
        If mes < 10 Then dateTest = dateTest + "0"
        dateTest += Ltrim(Str(mes))
        For dia As Integer = 1 To 31
            If mes = 2 And dia > 28 Then Exit For
            If (mes = 4 Or mes = 6 Or mes = 9 Or mes = 11) And dia > 30 Then Exit For
            If dia < 10 Then dateTest += "0"
            dateTest = dateTest + Ltrim(Str(dia))
            For Pal = 1 To 4
                If Mid(dateTest, Pal, 1) <> Mid(dateTest, 9 - Pal, 1) Then Exit For
            Next Pal
            If Pal = 5 Then
                total += 1
                If total <= 15 Then Print Left(dateTest,4);"-";Mid(dateTest,5,2);"-";Right(dateTest,2)
            End If
            if total > 15 then Exit For : Exit For : Exit For
            dateTest = Left(dateTest, 6)
        Next dia
        dateTest = Left(dateTest, 4)
    Next mes
    dateTest = ""
Next anno
Sleep


package require Tcl 8.5
package require ip

proc parseIP {address} {
    set result {}
    set family [ip::version $address]
    set port -1
    if {$family == -1} {
    if {[regexp {^\[(.*)\]:(\d+)$} $address -> address port]} {
        dict set result port $port
        set family [ip::version $address]
        if {$family != 6} {
        return -code error "bad address"
        }
    } elseif {[regexp {^(.*):(\d+)$} $address -> address port]} {
        dict set result port $port
        set family [ip::version $address]
        if {$family != 4} {
        return -code error "bad address"
        }
    } else {
        return -code error "bad address"
    }
    }
    # Only possible error in ports is to be too large an integer
    if {$port > 65535} {
    return -code error "bad port"
    }
    dict set result family $family
    if {$family == 4} {
    # IPv4 normalized form is dotted quad, but toInteger helps
    dict set result addr [format %x [ip::toInteger $address]]
    } else {
    # IPv6 normalized form is colin-separated hex
    dict set result addr [string map {: ""} [ip::normalize $address]]
    }
    # Return the descriptor dictionary
    return $result
}


package main

import (
    "fmt"
    "time"
)

func reverse(s string) string {
    chars := []rune(s)
    for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
        chars[i], chars[j] = chars[j], chars[i]
    }
    return string(chars)
}

func main() {
    const (
        layout  = "20060102"
        layout2 = "2006-01-02"
    )
    fmt.Println("The next 15 palindromic dates in yyyymmdd format after 20200202 are:")
    date := time.Date(2020, 2, 2, 0, 0, 0, 0, time.UTC)
    count := 0
    for count < 15 {
        date = date.AddDate(0, 0, 1)
        s := date.Format(layout)
        r := reverse(s)
        if r == s {
            fmt.Println(date.Format(layout2))
            count++
        }
    }
}