Name

Data::Table::Text - Write data in tabular text format.

Synopsis

  use Data::Table::Text;

# Print a table:

  my $d =
   [[qq(a), qq(b\nbb), qq(c\ncc\nccc\n)],
    [qq(1), qq(1\n22), qq(1\n22\n333\n)],
   ];

  my $t = formatTable($d, [qw(A BB CCC)]);

  ok $t eq <<END;
     A  BB  CCC
  1  a  b   c
        bb  cc
            ccc
  2  1   1    1
        22   22
            333
  END

# Print a table containing tables and make it into a report:

  my $D = [[qq(See the\ntable\nopposite), $t],
           [qq(Or\nthis\none),            $t],
          ];


  my $T = formatTable($D, [qw(Description Table)], head=><<END);
  Table of Tables.

  Table has NNNN rows each of which contains a table.
  END

  ok $T eq <<END;
  Table of Tables.

  Table has 2 rows each of which contains a table.


     Description  Table
  1  See the         A  BB  CCC
     table        1  a  b   c
     opposite           bb  cc
                            ccc
                  2  1   1    1
                        22   22
                            333
  2  Or              A  BB  CCC
     this         1  a  b   c
     one                bb  cc
                            ccc
                  2  1   1    1
                        22   22
                            333
  END

# Print an array of arrays:

  my $aa = formatTable
   ([[qw(A   B   C  )],
     [qw(AA  BB  CC )],
     [qw(AAA BBB CCC)],
     [qw(1   22  333)]],
     [qw (aa  bb  cc)]);

  ok $aa eq <<END;
     aa   bb   cc
  1  A    B    C
  2  AA   BB   CC
  3  AAA  BBB  CCC
  4    1   22  333
  END

# Print an array of hashes:

  my $ah = formatTable
   ([{aa=> "A",   bb => "B",   cc => "C" },
     {aa=> "AA",  bb => "BB",  cc => "CC" },
     {aa=> "AAA", bb => "BBB", cc => "CCC" },
     {aa=> 1,     bb => 22,    cc => 333 }]);

  ok $ah eq <<END;
     aa   bb   cc
  1  A    B    C
  2  AA   BB   CC
  3  AAA  BBB  CCC
  4    1   22  333
  END

# Print a hash of arrays:

  my $ha = formatTable
   ({""     => ["aa",  "bb",  "cc"],
     "1"    => ["A",   "B",   "C"],
     "22"   => ["AA",  "BB",  "CC"],
     "333"  => ["AAA", "BBB", "CCC"],
     "4444" => [1,      22,    333]},
     [qw(Key A B C)]
     );

  ok $ha eq <<END;
  Key   A    B    C
        aa   bb   cc
     1  A    B    C
    22  AA   BB   CC
   333  AAA  BBB  CCC
  4444    1   22  333
  END

# Print a hash of hashes:

  my $hh = formatTable
   ({a    => {aa=>"A",   bb=>"B",   cc=>"C" },
     aa   => {aa=>"AA",  bb=>"BB",  cc=>"CC" },
     aaa  => {aa=>"AAA", bb=>"BBB", cc=>"CCC" },
     aaaa => {aa=>1,     bb=>22,    cc=>333 }});

  ok $hh eq <<END;
        aa   bb   cc
  a     A    B    C
  aa    AA   BB   CC
  aaa   AAA  BBB  CCC
  aaaa    1   22  333
  END

# Print an array of scalars:

  my $a = formatTable(["a", "bb", "ccc", 4], [q(#), q(Col)]);

  ok $a eq <<END;
  #  Col
  0  a
  1  bb
  2  ccc
  3    4
  END

# Print a hash of scalars:

  my $h = formatTable({aa=>"AAAA", bb=>"BBBB", cc=>"333"}, [qw(Key Title)]);

  ok $h eq <<END;
  Key  Title
  aa   AAAA
  bb   BBBB
  cc     333
  END

Description

Write data in tabular text format.

Version 20191106.

The following sections describe the methods in each functional area of this module. For an alphabetic listing of all methods by name see Index.

Immediately useful methods

These methods are the ones most likely to be of immediate use to anyone using this module for the first time:

clearFolder

Remove all the files and folders under and including the specified folder as long as the number of files to be removed is less than the specified limit. Sometimes the folder can be emptied but not removed - perhaps because it a link, in this case a message is produced unless suppressed by the optional $nomsg parameter.

dateTimeStamp

Year-monthNumber-day at hours:minute:seconds

filePathExt

Create a file name from an array of file name components the last of which is an extension. Identical to fpe.

fn

Remove path and extension from file name.

formatHtmlTable

Format an array of arrays of scalars as an html table using the %options described in formatTableCheckKeys.

formatTable

Format various $data structures as a table with titles as specified by $columnTitles: either a reference to an array of column titles or a string each line of which contains the column title as the first word with the rest of the line describing that column.

Optionally create a report from the table using the report %options described in formatTableCheckKeys

genHash

Return a $blessed hash with the specified $attributes accessible via lvalue method method calls. updateDocumentation will generate documentation at "Hash Definitions" for the hash defined by the call to genHash if the call is laid out as in the example below.

newProcessStarter

Create a new process starter with which to start parallel processes up to a specified $maximumNumberOfProcesses maximum number of parallel processes at a time, wait for all the started processes to finish and then optionally retrieve their saved results as an array from the folder named by $transferArea.

readFile

Read a file containing unicode in utf8.

searchDirectoryTreesForMatchingFiles

Search the specified directory trees for the files (not folders) that match the specified extensions. The argument list should include at least one path name to be useful. If no file extension is supplied then all the files below the specified paths are returned. Arguments wrapped in [] will be unwrapped.

sumAbsAndRel

Combine zero or more absolute and relative file names starting at the current working folder to get an absolute file name.

writeFile

Write a unicode utf8 string to a new file that does not already exist after creating a path to the file if necessary and return the name of the file on success else confess if a problem occurred or the file already exists.

xxx

Execute a shell command optionally checking its response. The command to execute is specified as one or more strings which are joined together after removing any new lines. Optionally the last string can be a regular expression that is used to test any non blank output generated by the execution of the command: if the regular expression fails the command and the command output are printed, else it is suppressed as being uninteresting. If such a regular expression is not supplied then the command and its non blank output lines are always printed.

xxxr

Execute a bash command $cmd on the server whose ip address is located in awsIp using the optional $userid supplied or the one listed in .ssh/config by default.

Time stamps

Date and timestamps as used in logs of long running commands.

dateTimeStamp()

Year-monthNumber-day at hours:minute:seconds

Example:

  ok 𝗱𝗮𝘁𝗲𝗧𝗶𝗺𝗲𝗦𝘁𝗮𝗺𝗽     =~ m(\A\d{4}-\d\d-\d\d at \d\d:\d\d:\d\d\Z), q(dts);

dateTimeStampName()

Date time stamp without white space.

Example:

  ok 𝗱𝗮𝘁𝗲𝗧𝗶𝗺𝗲𝗦𝘁𝗮𝗺𝗽𝗡𝗮𝗺𝗲 =~ m(\A_on_\d{4}_\d\d_\d\d_at_\d\d_\d\d_\d\d\Z);

dateStamp()

Year-monthName-day

Example:

  ok 𝗱𝗮𝘁𝗲𝗦𝘁𝗮𝗺𝗽         =~ m(\A\d{4}-\w{3}-\d\d\Z);

versionCode()

YYYYmmdd-HHMMSS

Example:

  ok 𝘃𝗲𝗿𝘀𝗶𝗼𝗻𝗖𝗼𝗱𝗲       =~ m(\A\d{8}-\d{6}\Z);

versionCodeDashed()

YYYY-mm-dd-HH:MM:SS

Example:

  ok 𝘃𝗲𝗿𝘀𝗶𝗼𝗻𝗖𝗼𝗱𝗲𝗗𝗮𝘀𝗵𝗲𝗱 =~ m(\A\d{4}-\d\d-\d\d-\d\d:\d\d:\d\d\Z);

timeStamp()

hours:minute:seconds

Example:

  ok 𝘁𝗶𝗺𝗲𝗦𝘁𝗮𝗺𝗽         =~ m(\A\d\d:\d\d:\d\d\Z);

microSecondsSinceEpoch()

Micro seconds since unix epoch.

Example:

  ok 𝗺𝗶𝗰𝗿𝗼𝗦𝗲𝗰𝗼𝗻𝗱𝘀𝗦𝗶𝗻𝗰𝗲𝗘𝗽𝗼𝗰𝗵 > 47*365*24*60*60*1e6;

Command execution

Various ways of processing commands and writing results.

fff($$@)

Confess a message with a line position and a file that Geany will jump to if clicked on.

     Parameter  Description
  1  $line      Line
  2  $file      File
  3  @m         Messages

Example:

  𝗳𝗳𝗳 __LINE__, __FILE__, "Hello world";

lll(@)

Log messages including the project name if available. This method is not merged as we need to retain its prototype.

     Parameter  Description
  1  @m         Messages

Example:

  𝗹𝗹𝗹 "Hello world";

xxx(@)

Execute a shell command optionally checking its response. The command to execute is specified as one or more strings which are joined together after removing any new lines. Optionally the last string can be a regular expression that is used to test any non blank output generated by the execution of the command: if the regular expression fails the command and the command output are printed, else it is suppressed as being uninteresting. If such a regular expression is not supplied then the command and its non blank output lines are always printed.

     Parameter  Description
  1  @cmd       Command to execute followed by an optional regular expression to test the results

Example:

   {ok 𝘅𝘅𝘅("echo aaa")       =~ /aaa/;

xxxr($$)

Execute a bash command $cmd on the server whose ip address is located in awsIp using the optional $userid supplied or the one listed in .ssh/config by default.

     Parameter  Description
  1  $cmd       Command string
  2  $userid    Userid on remote system

Example:

  if (0)
   {ok 𝘅𝘅𝘅𝗿(q(pwd), q(phil));
   }

yyy($)

Execute a block of shell commands line by line after removing comments - stop if there is a non zero return code from any command.

     Parameter  Description
  1  $cmd       Commands to execute separated by new lines

Example:

    ok !𝘆𝘆𝘆 <<END;
  echo aaa
  echo bbb
  END

zzz($$$$)

Execute lines of commands after replacing new lines with && then check that the pipeline execution results in a return code of zero and that the execution results match the optional regular expression if one has been supplied; confess() to an error if either check fails. To execute remotely, add "ssh ... 'echo start" as the first line and "echo end'" as the last line with the commands to be executed on the lines in between.

     Parameter    Description
  1  $cmd         Commands to execute - one per line with no trailing &&
  2  $success     Optional regular expression to check for acceptable results
  3  $returnCode  Optional regular expression to check the acceptable return codes
  4  $message     Message of explanation if any of the checks fail

Example:

  ok 𝘇𝘇𝘇(<<END, qr(aaa\s*bbb)s);
  echo aaa
  echo bbb
  END

parseCommandLineArguments(&$$)

Classify the specified array of words referred to by $args into positional and keyword parameters, call the specified sub with a reference to an array of positional parameters followed by a reference to a hash of keywords and their values then return the value returned by this sub. The keywords names will be validated if $valid is either a reference to an array of valid keywords names or a hash of valid keyword names => textual descriptions. Confess with a table of valid keywords definitions if the $valid keywords are specified and an invalid one is presented.

     Parameter  Description
  1  $sub       Sub to call
  2  $args      List of arguments to parse
  3  $valid     Optional list of valid parameters else all parameters will be accepted

Example:

    my $r = 𝗽𝗮𝗿𝘀𝗲𝗖𝗼𝗺𝗺𝗮𝗻𝗱𝗟𝗶𝗻𝗲𝗔𝗿𝗴𝘂𝗺𝗲𝗻𝘁𝘀 {[@_]}

     [qw( aaa bbb -c --dd --eee=EEEE -f=F), q(--gg=g g), q(--hh=h h)];

    is_deeply $r,

      [["aaa", "bbb"],

       {c=>undef, dd=>undef, eee=>"EEEE", f=>"F", gg=>"g g", hh=>"h h"},

      ];

call(&@)

Call the specified sub in a separate process, wait for it to complete, copy back the named our variables, free the memory used.

     Parameter  Description
  1  $sub       Sub to call
  2  @our       Our variable names with preceding sigils to copy back

Example:

   {our $a = q(1);

Files and paths

Operations on files and paths.

Statistics

Information about each file.

fileSize($)

Get the size of a file.

     Parameter  Description
  1  $file      File name

Example:

    my $f = writeFile("zzz.data", "aaa");

    ok 𝗳𝗶𝗹𝗲𝗦𝗶𝘇𝗲($f) == 3;

fileLargestSize(@)

Return the largest file

     Parameter  Description
  1  @files     File names

Example:

  if (1) {
    my $d = temporaryFolder;
    my @f = map {owf(fpe($d, $_, q(txt)), 'X' x ($_ ** 2 % 11))} 1..9;

    my $f = 𝗳𝗶𝗹𝗲𝗟𝗮𝗿𝗴𝗲𝘀𝘁𝗦𝗶𝘇𝗲(@f);
    ok fn($f) eq '3', 'aaa';

    my $b = folderSize($d);
    ok $b > 0, 'bbb';

    my $c = processFilesInParallel(
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12);

    ok 108 == $c, 'cc11';

    my $C = processSizesInParallel
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, map {[fileSize($_), $_]} (@f) x 12;

    ok 108 == $C, 'cc2';

    my $J = processJavaFilesInParallel
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12;

    ok 108 == $J, 'cc3';

    clearFolder($d, 12);
   }

folderSize($)

Get the number of bytes in a folder

     Parameter  Description
  1  $folder    Folder name

Example:

  if (1) {
    my $d = temporaryFolder;
    my @f = map {owf(fpe($d, $_, q(txt)), 'X' x ($_ ** 2 % 11))} 1..9;

    my $f = fileLargestSize(@f);
    ok fn($f) eq '3', 'aaa';

    my $b = 𝗳𝗼𝗹𝗱𝗲𝗿𝗦𝗶𝘇𝗲($d);
    ok $b > 0, 'bbb';

    my $c = processFilesInParallel(
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12);

    ok 108 == $c, 'cc11';

    my $C = processSizesInParallel
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, map {[fileSize($_), $_]} (@f) x 12;

    ok 108 == $C, 'cc2';

    my $J = processJavaFilesInParallel
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12;

    ok 108 == $J, 'cc3';

    clearFolder($d, 12);
   }

fileMd5Sum($)

Get the Md5 sum for a file or string

     Parameter  Description
  1  $file      File or string

Example:

    𝗳𝗶𝗹𝗲𝗠𝗱𝟱𝗦𝘂𝗺(q(/etc/hosts));

  if (1) {
    ok 𝗳𝗶𝗹𝗲𝗠𝗱𝟱𝗦𝘂𝗺(join '', 1..100)     eq
       q(ef69caaaeea9c17120821a9eb6c7f1de);

    ok guidFromString(join '', 1..100) eq
       q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de);

    ok guidFromMd5(𝗳𝗶𝗹𝗲𝗠𝗱𝟱𝗦𝘂𝗺(join('', 1..100))) eq
       q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de);

    ok md5FromGuid(q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de)) eq
                        q(ef69caaaeea9c17120821a9eb6c7f1de);
  }

  if (1)
   {ok arraySum   (1..10) ==  55;
    ok arrayProduct(1..5) == 120;
    is_deeply[arrayTimes(2, 1..5)], [qw(2 4 6 8 10)];
   }

guidFromMd5($)

Create a guid from an md5 hash.

     Parameter  Description
  1  $m         Md5 hash

Example:

  if (1) {
    ok fileMd5Sum(join '', 1..100)     eq
       q(ef69caaaeea9c17120821a9eb6c7f1de);

    ok guidFromString(join '', 1..100) eq
       q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de);

    ok 𝗴𝘂𝗶𝗱𝗙𝗿𝗼𝗺𝗠𝗱𝟱(fileMd5Sum(join('', 1..100))) eq
       q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de);

    ok md5FromGuid(q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de)) eq
                        q(ef69caaaeea9c17120821a9eb6c7f1de);
  }

  if (1)
   {ok arraySum   (1..10) ==  55;
    ok arrayProduct(1..5) == 120;
    is_deeply[arrayTimes(2, 1..5)], [qw(2 4 6 8 10)];
   }

md5FromGuid($)

Recover an md5 sum from a guid.

     Parameter  Description
  1  $G         Guid

Example:

  if (1) {
    ok fileMd5Sum(join '', 1..100)     eq
       q(ef69caaaeea9c17120821a9eb6c7f1de);

    ok guidFromString(join '', 1..100) eq
       q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de);

    ok guidFromMd5(fileMd5Sum(join('', 1..100))) eq
       q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de);

    ok 𝗺𝗱𝟱𝗙𝗿𝗼𝗺𝗚𝘂𝗶𝗱(q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de)) eq
                        q(ef69caaaeea9c17120821a9eb6c7f1de);
  }

  if (1)
   {ok arraySum   (1..10) ==  55;
    ok arrayProduct(1..5) == 120;
    is_deeply[arrayTimes(2, 1..5)], [qw(2 4 6 8 10)];
   }

guidFromString($)

Create a guid from a file or string via an md5 hash.

     Parameter  Description
  1  $string    File name or string

Example:

  if (1) {
    ok fileMd5Sum(join '', 1..100)     eq
       q(ef69caaaeea9c17120821a9eb6c7f1de);

    ok 𝗴𝘂𝗶𝗱𝗙𝗿𝗼𝗺𝗦𝘁𝗿𝗶𝗻𝗴(join '', 1..100) eq
       q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de);

    ok guidFromMd5(fileMd5Sum(join('', 1..100))) eq
       q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de);

    ok md5FromGuid(q(GUID-ef69caaa-eea9-c171-2082-1a9eb6c7f1de)) eq
                        q(ef69caaaeea9c17120821a9eb6c7f1de);
  }

  if (1)
   {ok arraySum   (1..10) ==  55;
    ok arrayProduct(1..5) == 120;
    is_deeply[arrayTimes(2, 1..5)], [qw(2 4 6 8 10)];
   }

fileModTime($)

Get the modified time of a file in seconds since the epoch.

     Parameter  Description
  1  $file      File name

Example:

  ok 𝗳𝗶𝗹𝗲𝗠𝗼𝗱𝗧𝗶𝗺𝗲($0) =~ m(\A\d+\Z)s;

fileOutOfDate(&$@)

Calls the specified sub once for each source file that is missing, then calls the sub for the target if there were any missing files or if the target is older than any of the non missing source files or if the target does not exist. The file name is passed to the sub each time in $_. Returns the files to be remade in the order they should be made.

     Parameter  Description
  1  $make      Make with this sub
  2  $target    Target file
  3  @source    Source files

Example:

  if (0) {
    my @Files = qw(a b c);
    my @files = (@Files, qw(d));
    writeFile($_, $_), sleep 1 for @Files;

    my $a = '';
    my @a = 𝗳𝗶𝗹𝗲𝗢𝘂𝘁𝗢𝗳𝗗𝗮𝘁𝗲 {$a .= $_} q(a), @files;
    ok $a eq 'da';
    is_deeply [@a], [qw(d a)];

    my $b = '';
    my @b = 𝗳𝗶𝗹𝗲𝗢𝘂𝘁𝗢𝗳𝗗𝗮𝘁𝗲 {$b .= $_} q(b), @files;
    ok $b eq 'db';
    is_deeply [@b], [qw(d b)];

    my $c = '';
    my @c = 𝗳𝗶𝗹𝗲𝗢𝘂𝘁𝗢𝗳𝗗𝗮𝘁𝗲 {$c .= $_} q(c), @files;
    ok $c eq 'dc';
    is_deeply [@c], [qw(d c)];

    my $d = '';
    my @d = 𝗳𝗶𝗹𝗲𝗢𝘂𝘁𝗢𝗳𝗗𝗮𝘁𝗲 {$d .= $_} q(d), @files;
    ok $d eq 'd';
    is_deeply [@d], [qw(d)];

    my @A = 𝗳𝗶𝗹𝗲𝗢𝘂𝘁𝗢𝗳𝗗𝗮𝘁𝗲 {} q(a), @Files;
    my @B = 𝗳𝗶𝗹𝗲𝗢𝘂𝘁𝗢𝗳𝗗𝗮𝘁𝗲 {} q(b), @Files;
    my @C = 𝗳𝗶𝗹𝗲𝗢𝘂𝘁𝗢𝗳𝗗𝗮𝘁𝗲 {} q(c), @Files;
    is_deeply [@A], [qw(a)];
    is_deeply [@B], [qw(b)];
    is_deeply [@C], [];
    unlink for @Files;
   }

firstFileThatExists(@)

Returns the name of the first file that exists or undef if none of the named files exist.

     Parameter  Description
  1  @files     Files to check

Example:

    my $d = temporaryFolder;

    ok $d eq 𝗳𝗶𝗿𝘀𝘁𝗙𝗶𝗹𝗲𝗧𝗵𝗮𝘁𝗘𝘅𝗶𝘀𝘁𝘀("$d/$d", $d);

fileInWindowsFormat($)

Convert a unix file name to windows format

     Parameter  Description
  1  $file      File

Example:

  if (1)
   {ok 𝗳𝗶𝗹𝗲𝗜𝗻𝗪𝗶𝗻𝗱𝗼𝘄𝘀𝗙𝗼𝗿𝗺𝗮𝘁(fpd(qw(/a b c d))) eq q(\a\b\c\d\\);
   }

Components

File names and components.

Fusion

Create file names from file name components.

filePath(@)

Create a file name from an array of file name components. If all the components are blank then a blank file name is returned. Identical to fpf.

     Parameter  Description
  1  @file      File name components

Example:

  if (1) {
    ok 𝗳𝗶𝗹𝗲𝗣𝗮𝘁𝗵   (qw(/aaa bbb ccc ddd.eee)) eq "/aaa/bbb/ccc/ddd.eee";
    ok filePathDir(qw(/aaa bbb ccc ddd))     eq "/aaa/bbb/ccc/ddd/";
    ok filePathDir('', qw(aaa))              eq "aaa/";
    ok filePathDir('')                       eq "";
    ok filePathExt(qw(aaa xxx))              eq "aaa.xxx";
    ok filePathExt(qw(aaa bbb xxx))          eq "aaa/bbb.xxx";

    ok fpd        (qw(/aaa bbb ccc ddd))     eq "/aaa/bbb/ccc/ddd/";
    ok fpf        (qw(/aaa bbb ccc ddd.eee)) eq "/aaa/bbb/ccc/ddd.eee";
    ok fpe        (qw(aaa bbb xxx))          eq "aaa/bbb.xxx";
   }

fpf is a synonym for filePath.

filePathDir(@)

Create a directory name from an array of file name components. If all the components are blank then a blank file name is returned. Identical to fpd.

     Parameter  Description
  1  @file      Directory name components

Example:

  if (1) {
    ok filePath   (qw(/aaa bbb ccc ddd.eee)) eq "/aaa/bbb/ccc/ddd.eee";
    ok 𝗳𝗶𝗹𝗲𝗣𝗮𝘁𝗵𝗗𝗶𝗿(qw(/aaa bbb ccc ddd))     eq "/aaa/bbb/ccc/ddd/";
    ok 𝗳𝗶𝗹𝗲𝗣𝗮𝘁𝗵𝗗𝗶𝗿('', qw(aaa))              eq "aaa/";
    ok 𝗳𝗶𝗹𝗲𝗣𝗮𝘁𝗵𝗗𝗶𝗿('')                       eq "";
    ok filePathExt(qw(aaa xxx))              eq "aaa.xxx";
    ok filePathExt(qw(aaa bbb xxx))          eq "aaa/bbb.xxx";

    ok fpd        (qw(/aaa bbb ccc ddd))     eq "/aaa/bbb/ccc/ddd/";
    ok fpf        (qw(/aaa bbb ccc ddd.eee)) eq "/aaa/bbb/ccc/ddd.eee";
    ok fpe        (qw(aaa bbb xxx))          eq "aaa/bbb.xxx";
   }

fpd is a synonym for filePathDir.

filePathExt(@)

Create a file name from an array of file name components the last of which is an extension. Identical to fpe.

     Parameter  Description
  1  @File      File name components and extension

Example:

  if (1) {
    ok filePath   (qw(/aaa bbb ccc ddd.eee)) eq "/aaa/bbb/ccc/ddd.eee";
    ok filePathDir(qw(/aaa bbb ccc ddd))     eq "/aaa/bbb/ccc/ddd/";
    ok filePathDir('', qw(aaa))              eq "aaa/";
    ok filePathDir('')                       eq "";
    ok 𝗳𝗶𝗹𝗲𝗣𝗮𝘁𝗵𝗘𝘅𝘁(qw(aaa xxx))              eq "aaa.xxx";
    ok 𝗳𝗶𝗹𝗲𝗣𝗮𝘁𝗵𝗘𝘅𝘁(qw(aaa bbb xxx))          eq "aaa/bbb.xxx";

    ok fpd        (qw(/aaa bbb ccc ddd))     eq "/aaa/bbb/ccc/ddd/";
    ok fpf        (qw(/aaa bbb ccc ddd.eee)) eq "/aaa/bbb/ccc/ddd.eee";
    ok fpe        (qw(aaa bbb xxx))          eq "aaa/bbb.xxx";
   }

fpe is a synonym for filePathExt.

Fission

Get file name components from file names.

fp($)

Get path from file name.

     Parameter  Description
  1  $file      File name

Example:

  ok 𝗳𝗽 (q(a/b/c.d.e))  eq q(a/b/);

fpn($)

Remove extension from file name.

     Parameter  Description
  1  $file      File name

Example:

  ok 𝗳𝗽𝗻(q(a/b/c.d.e))  eq q(a/b/c.d);

fn($)

Remove path and extension from file name.

     Parameter  Description
  1  $file      File name

Example:

  ok 𝗳𝗻 (q(a/b/c.d.e))  eq q(c.d);

fne($)

Remove path from file name.

     Parameter  Description
  1  $file      File name

Example:

  ok 𝗳𝗻𝗲(q(a/b/c.d.e))  eq q(c.d.e);

fe($)

Get extension of file name.

     Parameter  Description
  1  $file      File name

Example:

  ok 𝗳𝗲 (q(a/b/c.d.e))  eq q(e);

checkFile($)

Return the name of the specified file if it exists, else confess the maximum extent of the path that does exist.

     Parameter  Description
  1  $file      File to check

Example:

    my $d = filePath   (my @d = qw(a b c d));

    my $f = filePathExt(qw(a b c d e x));

    my $F = filePathExt(qw(a b c e d));

    createEmptyFile($f);

    ok  eval{𝗰𝗵𝗲𝗰𝗸𝗙𝗶𝗹𝗲($d)};

    ok  eval{𝗰𝗵𝗲𝗰𝗸𝗙𝗶𝗹𝗲($f)};

quoteFile($)

Quote a file name.

     Parameter  Description
  1  $file      File name

Example:

  ok 𝗾𝘂𝗼𝘁𝗲𝗙𝗶𝗹𝗲(fpe(qw(a "b" c))) eq q("a/\"b\".c");

removeFilePrefix($@)

Removes a file prefix from an array of files.

     Parameter  Description
  1  $prefix    File prefix
  2  @files     Array of file names

Example:

  is_deeply [qw(a b)], [&𝗿𝗲𝗺𝗼𝘃𝗲𝗙𝗶𝗹𝗲𝗣𝗿𝗲𝗳𝗶𝘅(qw(a/ a/a a/b))];

  is_deeply [qw(b)],   [&𝗿𝗲𝗺𝗼𝘃𝗲𝗙𝗶𝗹𝗲𝗣𝗿𝗲𝗳𝗶𝘅("a/", "a/b")];

swapFilePrefix($$$)

Swaps the start of a file name from a $known name to a $new one if the file does in fact start with the $known name otherwise returns the original file name. The $new prefix is optional, if not supplied the $known prefix is removed.

     Parameter  Description
  1  $file      File name
  2  $known     Existing prefix
  3  $new       Optional new prefix defaults to q()

Example:

  ok 𝘀𝘄𝗮𝗽𝗙𝗶𝗹𝗲𝗣𝗿𝗲𝗳𝗶𝘅(q(/aaa/bbb.txt), q(/aaa/), q(/AAA/)) eq q(/AAA/bbb.txt);

setFileExtension($$)

Set the extension of a file to a specified value. Removes the extension if no extension is specified.

     Parameter   Description
  1  $file       File name
  2  $extension  Optional new extension

Example:

  ok 𝘀𝗲𝘁𝗙𝗶𝗹𝗲𝗘𝘅𝘁𝗲𝗻𝘀𝗶𝗼𝗻(q(.c),     q(d)) eq q(.d);

  ok 𝘀𝗲𝘁𝗙𝗶𝗹𝗲𝗘𝘅𝘁𝗲𝗻𝘀𝗶𝗼𝗻(q(b.c),    q(d)) eq q(b.d);

  ok 𝘀𝗲𝘁𝗙𝗶𝗹𝗲𝗘𝘅𝘁𝗲𝗻𝘀𝗶𝗼𝗻(q(/a/b.c), q(d)) eq q(/a/b.d);

swapFolderPrefix($$$)

Swaps a starting folder of a file name from a known name to a new one if the file does in fact start with the known name and the known name and new name are folders else return the file as is.

     Parameter  Description
  1  $file      File name
  2  $known     Existing prefix
  3  $new       New prefix

Example:

  if (1) {
    my $g = fpd(qw(a b c d));
    my $h = fpd(qw(a b cc dd));
    my $i = fpe($g, qw(aaa txt));

    my $j = 𝘀𝘄𝗮𝗽𝗙𝗼𝗹𝗱𝗲𝗿𝗣𝗿𝗲𝗳𝗶𝘅($i, $g, $h);
    ok $j =~ m(a/b/cc/dd/)s;
   }

fullyQualifiedFile($$)

Return whether a file is fully qualified or not

     Parameter  Description
  1  $file      File name to test
  2  $start     Optional start

Example:

  ok  𝗳𝘂𝗹𝗹𝘆𝗤𝘂𝗮𝗹𝗶𝗳𝗶𝗲𝗱𝗙𝗶𝗹𝗲(q(/a/b/c.d));

  ok  𝗳𝘂𝗹𝗹𝘆𝗤𝘂𝗮𝗹𝗶𝗳𝗶𝗲𝗱𝗙𝗶𝗹𝗲(q(/a/b/c.d), q(/a/b));

  ok !𝗳𝘂𝗹𝗹𝘆𝗤𝘂𝗮𝗹𝗶𝗳𝗶𝗲𝗱𝗙𝗶𝗹𝗲(q(/a/b/c.d), q(/a/c));

  ok !𝗳𝘂𝗹𝗹𝘆𝗤𝘂𝗮𝗹𝗶𝗳𝗶𝗲𝗱𝗙𝗶𝗹𝗲(q(c.d));

fullyQualifyFile($)

Return the fully qualified name of a file

     Parameter  Description
  1  $file      File name

Example:

  if (0)
   {ok 𝗳𝘂𝗹𝗹𝘆𝗤𝘂𝗮𝗹𝗶𝗳𝘆𝗙𝗶𝗹𝗲(q(perl/cpan)) eq q(/home/phil/perl/cpan/);
   }

removeDuplicatePrefixes($)

Remove duplicated leading path components from a file name.

     Parameter  Description
  1  $file      File name

Example:

  ok q(a/b.c) eq 𝗿𝗲𝗺𝗼𝘃𝗲𝗗𝘂𝗽𝗹𝗶𝗰𝗮𝘁𝗲𝗣𝗿𝗲𝗳𝗶𝘅𝗲𝘀("a/a/b.c");

  ok q(a/b.c) eq 𝗿𝗲𝗺𝗼𝘃𝗲𝗗𝘂𝗽𝗹𝗶𝗰𝗮𝘁𝗲𝗣𝗿𝗲𝗳𝗶𝘅𝗲𝘀("a/b.c");

  ok q(b.c) eq 𝗿𝗲𝗺𝗼𝘃𝗲𝗗𝘂𝗽𝗹𝗶𝗰𝗮𝘁𝗲𝗣𝗿𝗲𝗳𝗶𝘅𝗲𝘀("b.c");

Position

Position in the file system.

currentDirectory()

Get the current working directory.

Example:

    𝗰𝘂𝗿𝗿𝗲𝗻𝘁𝗗𝗶𝗿𝗲𝗰𝘁𝗼𝗿𝘆;

currentDirectoryAbove()

The path to the folder above the current working folder.

Example:

    𝗰𝘂𝗿𝗿𝗲𝗻𝘁𝗗𝗶𝗿𝗲𝗰𝘁𝗼𝗿𝘆𝗔𝗯𝗼𝘃𝗲;

parseFileName($)

Parse a file name into (path, name, extension) considering .. to be always part of the path ans using undef to mark missing components. This differs from (fp, fn, fe) which return q() for missing components and do not interpret . or .. as anything special

     Parameter  Description
  1  $file      File name to parse

Example:

  if (1)
   {is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "/home/phil/test.data"], ["/home/phil/", "test", "data"];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "/home/phil/test"],      ["/home/phil/", "test"];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "phil/test.data"],       ["phil/",       "test", "data"];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "phil/test"],            ["phil/",       "test"];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "test.data"],            [undef,         "test", "data"];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "phil/"],                [qw(phil/)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "/phil"],                [qw(/ phil)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "/"],                    [qw(/)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "/var/www/html/translations/"], [qw(/var/www/html/translations/)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "a.b/c.d.e"],            [qw(a.b/ c.d e)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "./a.b"],                [qw(./ a b)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲 "./../../a.b"],          [qw(./../../ a b)];
   }

fullFileName()

Full name of a file.

Example:

    𝗳𝘂𝗹𝗹𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲(fpe(qw(a txt)));

absFromAbsPlusRel($$)

Create an absolute file from an absolute file and a relative file.

     Parameter  Description
  1  $a         Absolute file name
  2  $f         Relative file name

Example:

  ok "/home/la/perl/aaa.pl"   eq 𝗮𝗯𝘀𝗙𝗿𝗼𝗺𝗔𝗯𝘀𝗣𝗹𝘂𝘀𝗥𝗲𝗹("/home/la/perl/bbb",      "aaa.pl");

  ok "/home/la/perl/aaa.pl"   eq 𝗮𝗯𝘀𝗙𝗿𝗼𝗺𝗔𝗯𝘀𝗣𝗹𝘂𝘀𝗥𝗲𝗹("/home/il/perl/bbb.pl",   "../../la/perl/aaa.pl");

relFromAbsAgainstAbs($$)

Derive a relative file name for the first absolute file name relative to the second absolute file name.

     Parameter  Description
  1  $f         Absolute file to be made relative
  2  $a         Absolute file name to make relative to.

Example:

  ok "bbb.pl"                 eq 𝗿𝗲𝗹𝗙𝗿𝗼𝗺𝗔𝗯𝘀𝗔𝗴𝗮𝗶𝗻𝘀𝘁𝗔𝗯𝘀("/home/la/perl/bbb.pl", "/home/la/perl/aaa.pl");

  ok "../perl/bbb.pl"         eq 𝗿𝗲𝗹𝗙𝗿𝗼𝗺𝗔𝗯𝘀𝗔𝗴𝗮𝗶𝗻𝘀𝘁𝗔𝗯𝘀("/home/la/perl/bbb.pl", "/home/la/java/aaa.jv");

absFile($)

Return undef if the file is a relative file or b<$file> if the file is an absolute file name

     Parameter  Description
  1  $file      File to test

Example:

  ok "/aaa/"                  eq 𝗮𝗯𝘀𝗙𝗶𝗹𝗲(qw(/aaa/));

sumAbsAndRel(@)

Combine zero or more absolute and relative file names starting at the current working folder to get an absolute file name.

     Parameter  Description
  1  @f         Absolute and relative file names

Example:

  ok "/aaa/bbb/ccc/ddd.txt"   eq 𝘀𝘂𝗺𝗔𝗯𝘀𝗔𝗻𝗱𝗥𝗲𝗹(qw(/aaa/AAA/ ../bbb/bbb/BBB/ ../../ccc/ddd.txt));

Temporary

Temporary files and folders

temporaryFile()

Create a temporary file that will automatically be unlinked during END processing.

Example:

    my $f = 𝘁𝗲𝗺𝗽𝗼𝗿𝗮𝗿𝘆𝗙𝗶𝗹𝗲;

temporaryFolder()

Create a temporary folder that will automatically be rmdired during END processing.

Example:

    my $D = 𝘁𝗲𝗺𝗽𝗼𝗿𝗮𝗿𝘆𝗙𝗼𝗹𝗱𝗲𝗿;

temporaryDirectory is a synonym for temporaryFolder.

Find

Find files and folders below a folder.

findFiles($$)

Find all the files under a folder and optionally filter the selected files with a regular expression.

     Parameter  Description
  1  $dir       Folder to start the search with
  2  $filter    Optional regular expression to filter files

Example:

    my $D = temporaryFolder;

    my $d = fpd($D, q(ddd));

    my @f = map {createEmptyFile(fpe($d, $_, qw(txt)))} qw(a b c);

    is_deeply [sort map {fne $_} 𝗳𝗶𝗻𝗱𝗙𝗶𝗹𝗲𝘀($d, qr(txt\Z))], [qw(a.txt b.txt c.txt)];

findDirs($$)

Find all the folders under a folder and optionally filter the selected folders with a regular expression.

     Parameter  Description
  1  $dir       Folder to start the search with
  2  $filter    Optional regular expression to filter files

Example:

    my $D = temporaryFolder;

    my $d = fpd($D, q(ddd));

    my @f = map {createEmptyFile(fpe($d, $_, qw(txt)))} qw(a b c);

    is_deeply [𝗳𝗶𝗻𝗱𝗗𝗶𝗿𝘀($D)], [$D, $d];

fileList($)

Files that match a given search pattern handed to bsd_glob.

     Parameter  Description
  1  $pattern   Search pattern

Example:

    my $D = temporaryFolder;

    my $d = fpd($D, q(ddd));

    my @f = map {createEmptyFile(fpe($d, $_, qw(txt)))} qw(a b c);

    is_deeply [sort map {fne $_} 𝗳𝗶𝗹𝗲𝗟𝗶𝘀𝘁("$d/*.txt")],

              ["a.txt", "b.txt", "c.txt"];

searchDirectoryTreesForMatchingFiles(@)

Search the specified directory trees for the files (not folders) that match the specified extensions. The argument list should include at least one path name to be useful. If no file extension is supplied then all the files below the specified paths are returned. Arguments wrapped in [] will be unwrapped.

     Parameter              Description
  1  @FoldersandExtensions  Mixture of folder names and extensions

Example:

    my $D = temporaryFolder;

    my $d = fpd($D, q(ddd));

    my @f = map {createEmptyFile(fpe($d, $_, qw(txt)))} qw(a b c);

    is_deeply [sort map {fne $_} 𝘀𝗲𝗮𝗿𝗰𝗵𝗗𝗶𝗿𝗲𝗰𝘁𝗼𝗿𝘆𝗧𝗿𝗲𝗲𝘀𝗙𝗼𝗿𝗠𝗮𝘁𝗰𝗵𝗶𝗻𝗴𝗙𝗶𝗹𝗲𝘀($d)],

              ["a.txt", "b.txt", "c.txt"];

countFileExtensions(@)

Return a hash which counts the file extensions in and below the specified directories

     Parameter  Description
  1  @folders   Folders to search

Example:

    𝗰𝗼𝘂𝗻𝘁𝗙𝗶𝗹𝗲𝗘𝘅𝘁𝗲𝗻𝘀𝗶𝗼𝗻𝘀(q(/home/phil/perl/));

countFileTypes($@)

Return a hash which counts, in parallel, the results of applying the file command to each file under the specified directories.

     Parameter                  Description
  1  $maximumNumberOfProcesses  Maximum number of processes to run in parallel
  2  @folders                   Folders to search

Example:

    𝗰𝗼𝘂𝗻𝘁𝗙𝗶𝗹𝗲𝗧𝘆𝗽𝗲𝘀(4, q(/home/phil/perl/));

matchPath($)

Given an absolute path find out how much of the path actually exists.

     Parameter  Description
  1  $file      File name

Example:

    my $d = filePath   (my @d = qw(a b c d));

    ok 𝗺𝗮𝘁𝗰𝗵𝗣𝗮𝘁𝗵($d) eq $d;

findFileWithExtension($@)

Find the first extension from the specified extensions that produces a file that exists when appended to the specified file.

     Parameter  Description
  1  $file      File name minus extensions
  2  @ext       Possible extensions

Example:

    my $f = createEmptyFile(fpe(my $d = temporaryFolder, qw(a jpg)));

    my $F = 𝗳𝗶𝗻𝗱𝗙𝗶𝗹𝗲𝗪𝗶𝘁𝗵𝗘𝘅𝘁𝗲𝗻𝘀𝗶𝗼𝗻(fpf($d, q(a)), qw(txt data jpg));

    ok $F eq "jpg";

clearFolder($$$)

Remove all the files and folders under and including the specified folder as long as the number of files to be removed is less than the specified limit. Sometimes the folder can be emptied but not removed - perhaps because it a link, in this case a message is produced unless suppressed by the optional $nomsg parameter.

     Parameter    Description
  1  $folder      Folder
  2  $limitCount  Maximum number of files to remove to limit damage
  3  $noMsg       No message if the folder cannot be completely removed.

Example:

    my $D = temporaryFolder;

    my $d = fpd($D, q(ddd));

    my @f = map {createEmptyFile(fpe($d, $_, qw(txt)))} qw(a b c);

    𝗰𝗹𝗲𝗮𝗿𝗙𝗼𝗹𝗱𝗲𝗿($D, 5);

    ok !-e $_ for @f;

    ok !-d $D;

Read and write files

Read and write strings from and to files creating paths as needed.

readFile($)

Read a file containing unicode in utf8.

     Parameter  Description
  1  $file      Name of file to read

Example:

    my $f = writeFile(undef, "aaa");

    my $s = 𝗿𝗲𝗮𝗱𝗙𝗶𝗹𝗲($f);

    ok $s eq "aaa";

    appendFile($f, "bbb");

    my $S = 𝗿𝗲𝗮𝗱𝗙𝗶𝗹𝗲($f);

    ok $S eq "aaabbb";

  if (1) {
    my $f =  writeFile(undef, q(aaaa));
    ok 𝗿𝗲𝗮𝗱𝗙𝗶𝗹𝗲($f) eq q(aaaa);
    eval{writeFile($f, q(bbbb))};
    ok $@ =~ m(\AFile already exists)s;
    ok 𝗿𝗲𝗮𝗱𝗙𝗶𝗹𝗲($f) eq q(aaaa);
    overWriteFile($f,  q(bbbb));
    ok 𝗿𝗲𝗮𝗱𝗙𝗶𝗹𝗲($f) eq q(bbbb);
    unlink $f;
   }

evalFile($)

Read a file containing unicode in utf8, evaluate it, confess to any errors and then return any result with lvalue method methods to access each hash element - an improvement on do which silently ignores any errors.

     Parameter  Description
  1  $file      File to read

Example:

  if (1) {
    my $f = dumpFile(undef, {a=>1, b=>2});
    my $d = 𝗲𝘃𝗮𝗹𝗙𝗶𝗹𝗲($f);
    ok $d->a == 1;
    ok $d->b == 2;
    unlink $f;
   }

evalGZipFile($)

Read a file containing compressed utf8, evaluate it, confess to any errors or return any result. This is much slower than using Storable but does use much smaller files, see also: dumpGZipFile.

     Parameter  Description
  1  $file      File to read

Example:

  if (1) {
    my $d = [1, 2, 3=>{a=>4, b=>5}];
    my $file = dumpGZipFile(q(zzz.zip), $d);
    ok -e $file;
    my $D = 𝗲𝘃𝗮𝗹𝗚𝗭𝗶𝗽𝗙𝗶𝗹𝗲($file);
    is_deeply $d, $D;
    unlink $file;
   }

retrieveFile($)

Retrieve a file created via Storable. This is much faster than evalFile but the stored data is not easily modified.

     Parameter  Description
  1  $file      File to read

Example:

  if (1) {
    my $f = storeFile(undef, my $d = [qw(aaa bbb ccc)]);
    my $s = 𝗿𝗲𝘁𝗿𝗶𝗲𝘃𝗲𝗙𝗶𝗹𝗲($f);
    is_deeply $s, $d;
    unlink $f;
   }

readBinaryFile($)

Read binary file - a file whose contents are not to be interpreted as unicode.

     Parameter  Description
  1  $file      File to read

Example:

    my $f = writeBinaryFile(undef, 0xff x 8);

    my $s = 𝗿𝗲𝗮𝗱𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲($f);

    ok $s eq 0xff x 8;

readGZipFile($)

Read the specified $file, containing compressed utf8, through gzip

     Parameter  Description
  1  $file      File to read.

Example:

  if (1) {
    my $s = '𝝰'x1e3;
    my $file = writeGZipFile(q(zzz.zip), $s);
    ok -e $file;
    my $S = 𝗿𝗲𝗮𝗱𝗚𝗭𝗶𝗽𝗙𝗶𝗹𝗲($file);
    ok $s eq $S;
    ok length($s) == length($S);
    unlink $file;
   }

makePath($)

Make the path for the specified file name or folder.

     Parameter  Description
  1  $file      File

Example:

    my $d = fpd(my $D = temporaryDirectory, qw(a));

    my $f = fpe($d, qw(bbb txt));

    ok !-d $d;

    𝗺𝗮𝗸𝗲𝗣𝗮𝘁𝗵($f);

    ok -d $d;

overWriteFile($$)

Write a unicode utf8 string to a file after creating a path to the file if necessary and return the name of the file on success else confess. If the file already exists it is overwritten. {my ($file, $string) = @_; # File to write to or undef for a temporary file, unicode string to write

     Parameter  Description
  1  $file      File to write to or B<undef> for a temporary file
  2  $string    Unicode string to write

Example:

  if (1) {
    my $f =  writeFile(undef, q(aaaa));
    ok readFile($f) eq q(aaaa);
    eval{writeFile($f, q(bbbb))};
    ok $@ =~ m(\AFile already exists)s;
    ok readFile($f) eq q(aaaa);
    𝗼𝘃𝗲𝗿𝗪𝗿𝗶𝘁𝗲𝗙𝗶𝗹𝗲($f,  q(bbbb));
    ok readFile($f) eq q(bbbb);
    unlink $f;
   }

owf is a synonym for overWriteFile.

writeFile($$)

Write a unicode utf8 string to a new file that does not already exist after creating a path to the file if necessary and return the name of the file on success else confess if a problem occurred or the file already exists.

     Parameter  Description
  1  $file      New file to write to or B<undef> for a temporary file
  2  $string    String to write

Example:

    my $f = 𝘄𝗿𝗶𝘁𝗲𝗙𝗶𝗹𝗲(undef, "aaa");

    my $s = readFile($f);

    ok $s eq "aaa";

    appendFile($f, "bbb");

    my $S = readFile($f);

    ok $S eq "aaabbb";

  if (1) {
    my $f =  𝘄𝗿𝗶𝘁𝗲𝗙𝗶𝗹𝗲(undef, q(aaaa));
    ok readFile($f) eq q(aaaa);
    eval{𝘄𝗿𝗶𝘁𝗲𝗙𝗶𝗹𝗲($f, q(bbbb))};
    ok $@ =~ m(\AFile already exists)s;
    ok readFile($f) eq q(aaaa);
    overWriteFile($f,  q(bbbb));
    ok readFile($f) eq q(bbbb);
    unlink $f;
   }

overWriteBinaryFile($$)

Write a binary string to a file after creating a path to the file if necessary and return the name of the file on success else confess. If the file already exists it is overwritten.

     Parameter  Description
  1  $file      File to write to or B<undef> for a temporary file
  2  $string    Unicode string to write

Example:

  if (1)
   {vec(my $a, 0, 8) = 254;
    vec(my $b, 0, 8) = 255;
    ok dump($a) eq dump("FE");
    ok dump($b) eq dump("FF");
    ok length($a) == 1;
    ok length($b) == 1;

    my $s = $a.$a.$b.$b;
    ok length($s) == 4;

    my $f = eval {writeFile(undef, $s)};
    ok fileSize($f) == 8;

    eval {writeBinaryFile($f, $s)};
    ok $@ =~ m(Binary file already exists:)s;

    eval {𝗼𝘃𝗲𝗿𝗪𝗿𝗶𝘁𝗲𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲($f, $s)};
    ok !$@;
    ok fileSize($f) == 4;

    ok $s eq eval {readBinaryFile($f)};

    copyBinaryFile($f, my $F = temporaryFile);
    ok $s eq readBinaryFile($F);
    unlink $f, $F;
   }

writeBinaryFile($$)

Write a binary string to a new file that does not already exist after creating a path to the file if necessary and return the name of the file on success else confess if a problem occurred or the file does already exist.

     Parameter  Description
  1  $file      New file to write to or B<undef> for a temporary file
  2  $string    String to write

Example:

    my $f = 𝘄𝗿𝗶𝘁𝗲𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲(undef, 0xff x 8);

    my $s = readBinaryFile($f);

    ok $s eq 0xff x 8;

  if (1)
   {vec(my $a, 0, 8) = 254;
    vec(my $b, 0, 8) = 255;
    ok dump($a) eq dump("FE");
    ok dump($b) eq dump("FF");
    ok length($a) == 1;
    ok length($b) == 1;

    my $s = $a.$a.$b.$b;
    ok length($s) == 4;

    my $f = eval {writeFile(undef, $s)};
    ok fileSize($f) == 8;

    eval {𝘄𝗿𝗶𝘁𝗲𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲($f, $s)};
    ok $@ =~ m(Binary file already exists:)s;

    eval {overWriteBinaryFile($f, $s)};
    ok !$@;
    ok fileSize($f) == 4;

    ok $s eq eval {readBinaryFile($f)};

    copyBinaryFile($f, my $F = temporaryFile);
    ok $s eq readBinaryFile($F);
    unlink $f, $F;
   }

dumpFile($$)

Dump a data structure to a file

     Parameter  Description
  1  $file      File to write to or B<undef> for a temporary file
  2  $struct    Address of data structure to write

Example:

  if (1) {
    my $f = 𝗱𝘂𝗺𝗽𝗙𝗶𝗹𝗲(undef, my $d = [qw(aaa bbb ccc)]);
    my $s = evalFile($f);
    is_deeply $s, $d;
    unlink $f;
   }

storeFile($$)

Store a data structure to a file via Storable. This is much faster than dumpFile but the stored results are not easily modified.

     Parameter  Description
  1  $file      File to write to or B<undef> for a temporary file
  2  $struct    Address of data structure to write

Example:

  if (1) {
    my $f = 𝘀𝘁𝗼𝗿𝗲𝗙𝗶𝗹𝗲(undef, my $d = [qw(aaa bbb ccc)]);
    my $s = retrieveFile($f);
    is_deeply $s, $d;
    unlink $f;
   }

writeGZipFile($$)

Write a unicode utf8 string through gzip to a file.

     Parameter  Description
  1  $file      File to write to
  2  $string    String to write

Example:

  if (1) {
    my $s = '𝝰'x1e3;
    my $file = 𝘄𝗿𝗶𝘁𝗲𝗚𝗭𝗶𝗽𝗙𝗶𝗹𝗲(q(zzz.zip), $s);
    ok -e $file;
    my $S = readGZipFile($file);
    ok $s eq $S;
    ok length($s) == length($S);
    unlink $file;
   }

dumpGZipFile($$)

Write a data structure through gzip to a file. This technique produces files that are a lot more compact files than those produced by Storable, but the execution time is much longer. See also: evalGZipFile.

     Parameter  Description
  1  $file      File to write
  2  $data      Reference to data

Example:

  if (1) {
    my $d = [1, 2, 3=>{a=>4, b=>5}];
    my $file = 𝗱𝘂𝗺𝗽𝗚𝗭𝗶𝗽𝗙𝗶𝗹𝗲(q(zzz.zip), $d);
    ok -e $file;
    my $D = evalGZipFile($file);
    is_deeply $d, $D;
    unlink $file;
   }

writeFiles($$$)

Write the values of a hash into files identified by the key of each value using overWriteFile optionally swapping the prefix of each file from $old to $new

     Parameter  Description
  1  $hash      Hash of key value pairs representing files and data
  2  $old       Optional old prefix
  3  $new       New prefix

Example:

  if (1) {
    my $h =
     {"aaa/1.txt"=>"1111",
      "aaa/2.txt"=>"2222",
     };
    clearFolder(q(aaa), 3);
    clearFolder(q(bbb), 3);
    𝘄𝗿𝗶𝘁𝗲𝗙𝗶𝗹𝗲𝘀($h);
    my $a = readFiles(q(aaa));
    is_deeply $h, $a;
    copyFolder(q(aaa), q(bbb));
    my $b = readFiles(q(bbb));
    is_deeply [sort values %$a],[sort values %$b];

    copyFile(q(aaa/1.txt), q(aaa/2.txt));
    my $A = readFiles(q(aaa));
    is_deeply(values %$A);

    clearFolder(q(aaa), 3);
    clearFolder(q(bbb), 3);
   }

readFiles(@)

Read all the files in the specified @folders into a hash

     Parameter  Description
  1  @folders   Folders to read

Example:

  if (1) {
    my $h =
     {"aaa/1.txt"=>"1111",
      "aaa/2.txt"=>"2222",
     };
    clearFolder(q(aaa), 3);
    clearFolder(q(bbb), 3);
    writeFiles($h);
    my $a = 𝗿𝗲𝗮𝗱𝗙𝗶𝗹𝗲𝘀(q(aaa));
    is_deeply $h, $a;
    copyFolder(q(aaa), q(bbb));
    my $b = 𝗿𝗲𝗮𝗱𝗙𝗶𝗹𝗲𝘀(q(bbb));
    is_deeply [sort values %$a],[sort values %$b];

    copyFile(q(aaa/1.txt), q(aaa/2.txt));
    my $A = 𝗿𝗲𝗮𝗱𝗙𝗶𝗹𝗲𝘀(q(aaa));
    is_deeply(values %$A);

    clearFolder(q(aaa), 3);
    clearFolder(q(bbb), 3);
   }

appendFile($$)

Append a unicode utf8 string to a file, possibly creating the file and the path to the file if necessary and return the name of the file on success else confess. The file being appended to is locked first with https://perldoc.perl.org/functions/flock.html to allow multiple processes to append linearly to the same file.

     Parameter  Description
  1  $file      File to append to
  2  $string    String to append

Example:

    my $f = writeFile(undef, "aaa");

    my $s = readFile($f);

    ok $s eq "aaa";

    𝗮𝗽𝗽𝗲𝗻𝗱𝗙𝗶𝗹𝗲($f, "bbb");

    my $S = readFile($f);

    ok $S eq "aaabbb";

createEmptyFile($)

Create an empty file - writeFile complains if no data is written to the file - and return the name of the file on success else confess.

     Parameter  Description
  1  $file      File to create or B<undef> for a temporary file

Example:

    my $D = temporaryFolder;

    my $d = fpd($D, q(ddd));

    my @f = map {𝗰𝗿𝗲𝗮𝘁𝗲𝗘𝗺𝗽𝘁𝘆𝗙𝗶𝗹𝗲(fpe($d, $_, qw(txt)))} qw(a b c);

    is_deeply [sort map {fne $_} findFiles($d, qr(txt\Z))], [qw(a.txt b.txt c.txt)];

setPermissionsForFile($$)

Set the permissions for the named file

     Parameter     Description
  1  $file         File
  2  $permissions  Permissions settings per chmod

Example:

  if (1)
   {my $f = temporaryFile();
    𝘀𝗲𝘁𝗣𝗲𝗿𝗺𝗶𝘀𝘀𝗶𝗼𝗻𝘀𝗙𝗼𝗿𝗙𝗶𝗹𝗲($f, q(ugo=r));
    my $a = qx(ls -la $f);
    ok $a =~ m(-r--r--r--)s;
    𝘀𝗲𝘁𝗣𝗲𝗿𝗺𝗶𝘀𝘀𝗶𝗼𝗻𝘀𝗙𝗼𝗿𝗙𝗶𝗹𝗲($f, q(u=rwx));
    my $b = qx(ls -la $f);
    ok $b =~ m(-rwxr--r--)s;
   }

numberOfLinesInFile($)

The number of lines in a file

     Parameter  Description
  1  $file      File

Example:

    my $f = writeFile(undef, "a
b
");

    ok 𝗻𝘂𝗺𝗯𝗲𝗿𝗢𝗳𝗟𝗶𝗻𝗲𝘀𝗜𝗻𝗙𝗶𝗹𝗲($f) == 2;

Copy

Copy files and folders. The \Acopy.*Md5Normalized.*\Z methods can be used to ensure that files have collision proof names that collapse duplicate content even when copied to another folder.

copyFile($$)

Copy the $source file encoded in utf8 to the specified $target file in and return $target.

     Parameter  Description
  1  $source    Source file
  2  $target    Target file

Example:

  if (1) {
    my $h =
     {"aaa/1.txt"=>"1111",
      "aaa/2.txt"=>"2222",
     };
    clearFolder(q(aaa), 3);
    clearFolder(q(bbb), 3);
    writeFiles($h);
    my $a = readFiles(q(aaa));
    is_deeply $h, $a;
    copyFolder(q(aaa), q(bbb));
    my $b = readFiles(q(bbb));
    is_deeply [sort values %$a],[sort values %$b];

    𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲(q(aaa/1.txt), q(aaa/2.txt));
    my $A = readFiles(q(aaa));
    is_deeply(values %$A);

    clearFolder(q(aaa), 3);
    clearFolder(q(bbb), 3);
   }

copyFileToFolder($$)

Copy the file named in $source to the specified $targetFolder/ or if $targetFolder/ is in fact a file into the folder containing this file and return the target file name. Confesses instead of copying if the target already exists.

     Parameter      Description
  1  $source        Source file
  2  $targetFolder  Target folder

Example:

  if (1) {
    my $sd = temporaryFolder;
    my $td = temporaryFolder;
    my $sf = writeFile fpe($sd, qw(test data)), q(aaaa);
    my $tf = 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗧𝗼𝗙𝗼𝗹𝗱𝗲𝗿($sf, $td);
    ok readFile($tf) eq q(aaaa);
    ok fp ($tf) eq $td;
    ok fne($tf) eq q(test.data);
   }

nameFromString($%)

Create a readable name from an arbitrary string of text.

     Parameter  Description
  1  $string    String
  2  %options   Options

Example:

  if (1) {
  ok q(help) eq 𝗻𝗮𝗺𝗲𝗙𝗿𝗼𝗺𝗦𝘁𝗿𝗶𝗻𝗴(q(!@#$%^help___<>?><?>));
  ok q(bm_The_skyscraper_analogy) eq 𝗻𝗮𝗺𝗲𝗙𝗿𝗼𝗺𝗦𝘁𝗿𝗶𝗻𝗴(<<END);
  <bookmap id="b1">
  <title>The skyscraper analogy</title>
  </bookmap>
  END

  ok q(bm_The_skyscraper_analogy_An_exciting_tale_of_two_skyscrapers_that_meet_in_downtown_Houston)
     eq 𝗻𝗮𝗺𝗲𝗙𝗿𝗼𝗺𝗦𝘁𝗿𝗶𝗻𝗴(<<END);
  <bookmap id="b1">
  <title>The skyscraper analogy</title>
  An exciting tale of two skyscrapers that meet in downtown Houston
  <concept><html>
  </bookmap>
  END

  ok q(bm_the_skyscraper_analogy) eq nameFromStringRestrictedToTitle(<<END);
  <bookmap id="b1">
  <title>The skyscraper analogy</title>
  An exciting tale of two skyscrapers that meet in downtown Houston
  <concept><html>
  </bookmap>
  END
   }

nameFromStringRestrictedToTitle($%)

Create a readable name from a string of text that might contain a title tag - fall back to nameFromString if that is not possible.

     Parameter  Description
  1  $string    String
  2  %options   Options

Example:

  if (1) {
  ok q(help) eq nameFromString(q(!@#$%^help___<>?><?>));
  ok q(bm_The_skyscraper_analogy) eq nameFromString(<<END);
  <bookmap id="b1">
  <title>The skyscraper analogy</title>
  </bookmap>
  END

  ok q(bm_The_skyscraper_analogy_An_exciting_tale_of_two_skyscrapers_that_meet_in_downtown_Houston)
     eq nameFromString(<<END);
  <bookmap id="b1">
  <title>The skyscraper analogy</title>
  An exciting tale of two skyscrapers that meet in downtown Houston
  <concept><html>
  </bookmap>
  END

  ok q(bm_the_skyscraper_analogy) eq 𝗻𝗮𝗺𝗲𝗙𝗿𝗼𝗺𝗦𝘁𝗿𝗶𝗻𝗴𝗥𝗲𝘀𝘁𝗿𝗶𝗰𝘁𝗲𝗱𝗧𝗼𝗧𝗶𝘁𝗹𝗲(<<END);
  <bookmap id="b1">
  <title>The skyscraper analogy</title>
  An exciting tale of two skyscrapers that meet in downtown Houston
  <concept><html>
  </bookmap>
  END
   }

uniqueNameFromFile($)

Create a unique name from a file name and the md5 sum of its content

     Parameter  Description
  1  $source    Source file

Example:

  if (1) {
    my $f = owf(q(test.txt), join "", 1..100);
    ok 𝘂𝗻𝗶𝗾𝘂𝗲𝗡𝗮𝗺𝗲𝗙𝗿𝗼𝗺𝗙𝗶𝗹𝗲($f) eq q(test_ef69caaaeea9c17120821a9eb6c7f1de.txt);
    unlink $f;
   }

nameFromFolder($)

Create a name from the last folder in the path of a file name. Return undef if the file does not have a path.

     Parameter  Description
  1  $file      File name

Example:

  if (1) {
  ok 𝗻𝗮𝗺𝗲𝗙𝗿𝗼𝗺𝗙𝗼𝗹𝗱𝗲𝗿(fpe(qw( a b c d e))) eq q(c);
   }

copyFileMd5Normalized($$)

Normalize the name of the specified $source file to the md5 sum of its content, retaining its current extension, while placing the original file name in a companion file if the companion file does not already exist. If no $target folder is supplied the file is renamed to its normalized form in situ, otherwise it is copied to the target folder and renamed there. A companion file for the $source file is created by removing the extension of the normalized file and writing the original $source file name to it unless such a file already exists as we assume that it contains the 'original' original name of the $source file. If the $source file is copied to a new location then the companion file is copied as well to maintain the link back to the original name of the file.

     Parameter  Description
  1  $source    Source file
  2  $Target    Target folder or a file in the target folder

Example:

  if (0) {
    my $dir = temporaryFolder;
    my $a = fpe($dir, qw(a a jpg));
    my $b = fpe($dir, qw(b a jpg));
    my $c = fpe($dir, qw(c a jpg));

    my $content = join '', 1..1e3;

    my $A = copyFileMd5NormalizedCreate($a, $content, q(jpg), $a);
    ok readFile($A) eq $content;
    ok $A eq 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($A);

    my $B = 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($A, $b);
    ok readFile($B) eq $content;
    ok $B eq 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($B);

    my $C = 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($B, $c);
    ok readFile($C) eq $content;
    ok $C eq 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($C);

    ok fne($A) eq fne($_) for $B, $C;
    ok readFile($_) eq $content for $A, $B, $C;
    ok copyFileMd5NormalizedGetCompanionContent($_) eq $a for $A, $B, $C;

    ok 6 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($A);
    ok 4 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($B);
    ok 2 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($C);
    ok 0 == searchDirectoryTreesForMatchingFiles($dir);

    clearFolder($dir, 10);
    ok 0 == searchDirectoryTreesForMatchingFiles($dir);
   }

copyFileMd5NormalizedName($$@)

Name a file using the GB Standard

     Parameter   Description
  1  $content    Content
  2  $extension  Extension
  3  %options    Options

Example:

  if (0) {
    ok 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱𝗡𝗮𝗺𝗲(<<END, q(txt)) eq
  <p>Hello<b>World</b></p>
  END
  q(Hello_World_6ba23858c1b4811660896c324acac6fa.txt);
   }

copyFileMd5NormalizedCreate($$$$@)

Create a file in the specified $folder whose name is constructed from the md5 sum of the specified $content, whose content is $content, whose extension is $extension and which has a companion file with the same name minus the extension which contains the specified $companionContent. Such a file can be copied multiple times by copyFileMd5Normalized regardless of the other files in the target folders.

     Parameter          Description
  1  $Folder            Target folder or a file in that folder
  2  $content           Content of the file
  3  $extension         File extension
  4  $companionContent  Contents of the companion file
  5  %options           Options.

Example:

  if (0) {
    my $dir = temporaryFolder;
    my $a = fpe($dir, qw(a a jpg));
    my $b = fpe($dir, qw(b a jpg));
    my $c = fpe($dir, qw(c a jpg));

    my $content = join '', 1..1e3;

    my $A = 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱𝗖𝗿𝗲𝗮𝘁𝗲($a, $content, q(jpg), $a);
    ok readFile($A) eq $content;
    ok $A eq copyFileMd5Normalized($A);

    my $B = copyFileMd5Normalized($A, $b);
    ok readFile($B) eq $content;
    ok $B eq copyFileMd5Normalized($B);

    my $C = copyFileMd5Normalized($B, $c);
    ok readFile($C) eq $content;
    ok $C eq copyFileMd5Normalized($C);

    ok fne($A) eq fne($_) for $B, $C;
    ok readFile($_) eq $content for $A, $B, $C;
    ok copyFileMd5NormalizedGetCompanionContent($_) eq $a for $A, $B, $C;

    ok 6 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($A);
    ok 4 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($B);
    ok 2 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($C);
    ok 0 == searchDirectoryTreesForMatchingFiles($dir);

    clearFolder($dir, 10);
    ok 0 == searchDirectoryTreesForMatchingFiles($dir);
   }

copyFileMd5NormalizedGetCompanionContent($)

Return the content of the companion file to the specified $source file after it has been normalized via copyFileMd5Normalized or copyFileMd5NormalizedCreate or return undef if the corresponding companion file does not exist.

     Parameter  Description
  1  $source    Source file.

Example:

  if (0) {
    my $dir = temporaryFolder;
    my $a = fpe($dir, qw(a a jpg));
    my $b = fpe($dir, qw(b a jpg));
    my $c = fpe($dir, qw(c a jpg));

    my $content = join '', 1..1e3;

    my $A = copyFileMd5NormalizedCreate($a, $content, q(jpg), $a);
    ok readFile($A) eq $content;
    ok $A eq copyFileMd5Normalized($A);

    my $B = copyFileMd5Normalized($A, $b);
    ok readFile($B) eq $content;
    ok $B eq copyFileMd5Normalized($B);

    my $C = copyFileMd5Normalized($B, $c);
    ok readFile($C) eq $content;
    ok $C eq copyFileMd5Normalized($C);

    ok fne($A) eq fne($_) for $B, $C;
    ok readFile($_) eq $content for $A, $B, $C;
    ok 𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱𝗚𝗲𝘁𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗖𝗼𝗻𝘁𝗲𝗻𝘁($_) eq $a for $A, $B, $C;

    ok 6 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($A);
    ok 4 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($B);
    ok 2 == searchDirectoryTreesForMatchingFiles($dir);
    copyFileMd5NormalizedDelete($C);
    ok 0 == searchDirectoryTreesForMatchingFiles($dir);

    clearFolder($dir, 10);
    ok 0 == searchDirectoryTreesForMatchingFiles($dir);
   }

copyFileMd5NormalizedDelete($)

Delete a normalized and its companion file

     Parameter  Description
  1  $file      File

Example:

  if (0) {
    my $dir = temporaryFolder;
    my $a = fpe($dir, qw(a a jpg));
    my $b = fpe($dir, qw(b a jpg));
    my $c = fpe($dir, qw(c a jpg));

    my $content = join '', 1..1e3;

    my $A = copyFileMd5NormalizedCreate($a, $content, q(jpg), $a);
    ok readFile($A) eq $content;
    ok $A eq copyFileMd5Normalized($A);

    my $B = copyFileMd5Normalized($A, $b);
    ok readFile($B) eq $content;
    ok $B eq copyFileMd5Normalized($B);

    my $C = copyFileMd5Normalized($B, $c);
    ok readFile($C) eq $content;
    ok $C eq copyFileMd5Normalized($C);

    ok fne($A) eq fne($_) for $B, $C;
    ok readFile($_) eq $content for $A, $B, $C;
    ok copyFileMd5NormalizedGetCompanionContent($_) eq $a for $A, $B, $C;

    ok 6 == searchDirectoryTreesForMatchingFiles($dir);
    𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱𝗗𝗲𝗹𝗲𝘁𝗲($A);
    ok 4 == searchDirectoryTreesForMatchingFiles($dir);
    𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱𝗗𝗲𝗹𝗲𝘁𝗲($B);
    ok 2 == searchDirectoryTreesForMatchingFiles($dir);
    𝗰𝗼𝗽𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱𝗗𝗲𝗹𝗲𝘁𝗲($C);
    ok 0 == searchDirectoryTreesForMatchingFiles($dir);

    clearFolder($dir, 10);
    ok 0 == searchDirectoryTreesForMatchingFiles($dir);
   }

copyBinaryFile($$)

Copy a binary file and return the target name,

     Parameter  Description
  1  $source    Source file
  2  $target    Target file

Example:

  if (1)
   {vec(my $a, 0, 8) = 254;
    vec(my $b, 0, 8) = 255;
    ok dump($a) eq dump("FE");
    ok dump($b) eq dump("FF");
    ok length($a) == 1;
    ok length($b) == 1;

    my $s = $a.$a.$b.$b;
    ok length($s) == 4;

    my $f = eval {writeFile(undef, $s)};
    ok fileSize($f) == 8;

    eval {writeBinaryFile($f, $s)};
    ok $@ =~ m(Binary file already exists:)s;

    eval {overWriteBinaryFile($f, $s)};
    ok !$@;
    ok fileSize($f) == 4;

    ok $s eq eval {readBinaryFile($f)};

    𝗰𝗼𝗽𝘆𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲($f, my $F = temporaryFile);
    ok $s eq readBinaryFile($F);
    unlink $f, $F;
   }

copyBinaryFileMd5Normalized($$)

Normalize the name of the specified $source file to the md5 sum of its content, retaining its current extension, while placing the original file name in a companion file if the companion file does not already exist. If no $target folder is supplied the file is renamed to its normalized form in situ, otherwise it is copied to the target folder and renamed there. A companion file for the $source file is created by removing the extension of the normalized file and writing the original $source file name to it unless such a file already exists as we assume that it contains the 'original' original name of the $source file. If the $source file is copied to a new location then the companion file is copied as well to maintain the link back to the original name of the file.

     Parameter  Description
  1  $source    Source file
  2  $Target    Target folder or a file in the target folder

Example:

  if (0) {
    my $dir = temporaryFolder;
    my $a = fpe($dir, qw(a a jpg));
    my $b = fpe($dir, qw(b a jpg));
    my $c = fpe($dir, qw(c a jpg));

    my $content = join '', 1..1e3;

    my $A = copyBinaryFileMd5NormalizedCreate($a, $content, q(jpg), $a);
    ok readBinaryFile($A) eq $content;
    ok $A eq 𝗰𝗼𝗽𝘆𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($A);

    my $B = 𝗰𝗼𝗽𝘆𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($A, $b);
    ok readBinaryFile($B) eq $content;
    ok $B eq 𝗰𝗼𝗽𝘆𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($B);

    my $C = 𝗰𝗼𝗽𝘆𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($B, $c);
    ok readBinaryFile($C) eq $content;
    ok $C eq 𝗰𝗼𝗽𝘆𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱($C);

    ok fne($A) eq fne($_) for $B, $C;
    ok readBinaryFile($_) eq $content for $A, $B, $C;
    ok copyBinaryFileMd5NormalizedGetCompanionContent($_) eq $a for $A, $B, $C;

    ok 6 == searchDirectoryTreesForMatchingFiles($dir);
    clearFolder($dir, 10);
   }

copyBinaryFileMd5NormalizedCreate($$$$)

Create a file in the specified $folder whose name is constructed from the md5 sum of the specified $content, whose content is $content, whose extension is $extension and which has a companion file with the same name minus the extension which contains the specified $companionContent. Such a file can be copied multiple times by copyBinaryFileMd5Normalized regardless of the other files in the target folders while retaining the original name information.

     Parameter          Description
  1  $Folder            Target folder or a file in that folder
  2  $content           Content of the file
  3  $extension         File extension
  4  $companionContent  Optional content of the companion file.

Example:

  if (0) {
    my $dir = temporaryFolder;
    my $a = fpe($dir, qw(a a jpg));
    my $b = fpe($dir, qw(b a jpg));
    my $c = fpe($dir, qw(c a jpg));

    my $content = join '', 1..1e3;

    my $A = 𝗰𝗼𝗽𝘆𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱𝗖𝗿𝗲𝗮𝘁𝗲($a, $content, q(jpg), $a);
    ok readBinaryFile($A) eq $content;
    ok $A eq copyBinaryFileMd5Normalized($A);

    my $B = copyBinaryFileMd5Normalized($A, $b);
    ok readBinaryFile($B) eq $content;
    ok $B eq copyBinaryFileMd5Normalized($B);

    my $C = copyBinaryFileMd5Normalized($B, $c);
    ok readBinaryFile($C) eq $content;
    ok $C eq copyBinaryFileMd5Normalized($C);

    ok fne($A) eq fne($_) for $B, $C;
    ok readBinaryFile($_) eq $content for $A, $B, $C;
    ok copyBinaryFileMd5NormalizedGetCompanionContent($_) eq $a for $A, $B, $C;

    ok 6 == searchDirectoryTreesForMatchingFiles($dir);
    clearFolder($dir, 10);
   }

copyBinaryFileMd5NormalizedGetCompanionContent($)

Return the original name of the specified $source file after it has been normalized via copyBinaryFileMd5Normalized or copyBinaryFileMd5NormalizedCreate or return undef if the corresponding companion file does not exist.

     Parameter  Description
  1  $source    Source file.

Example:

  if (0) {
    my $dir = temporaryFolder;
    my $a = fpe($dir, qw(a a jpg));
    my $b = fpe($dir, qw(b a jpg));
    my $c = fpe($dir, qw(c a jpg));

    my $content = join '', 1..1e3;

    my $A = copyBinaryFileMd5NormalizedCreate($a, $content, q(jpg), $a);
    ok readBinaryFile($A) eq $content;
    ok $A eq copyBinaryFileMd5Normalized($A);

    my $B = copyBinaryFileMd5Normalized($A, $b);
    ok readBinaryFile($B) eq $content;
    ok $B eq copyBinaryFileMd5Normalized($B);

    my $C = copyBinaryFileMd5Normalized($B, $c);
    ok readBinaryFile($C) eq $content;
    ok $C eq copyBinaryFileMd5Normalized($C);

    ok fne($A) eq fne($_) for $B, $C;
    ok readBinaryFile($_) eq $content for $A, $B, $C;
    ok 𝗰𝗼𝗽𝘆𝗕𝗶𝗻𝗮𝗿𝘆𝗙𝗶𝗹𝗲𝗠𝗱𝟱𝗡𝗼𝗿𝗺𝗮𝗹𝗶𝘇𝗲𝗱𝗚𝗲𝘁𝗖𝗼𝗺𝗽𝗮𝗻𝗶𝗼𝗻𝗖𝗼𝗻𝘁𝗲𝗻𝘁($_) eq $a for $A, $B, $C;

    ok 6 == searchDirectoryTreesForMatchingFiles($dir);
    clearFolder($dir, 10);
   }

copyFolder($$)

Copy a folder

     Parameter  Description
  1  $source    Source file
  2  $target    Target file

Example:

  if (1) {
    my $h =
     {"aaa/1.txt"=>"1111",
      "aaa/2.txt"=>"2222",
     };
    clearFolder(q(aaa), 3);
    clearFolder(q(bbb), 3);
    writeFiles($h);
    my $a = readFiles(q(aaa));
    is_deeply $h, $a;
    𝗰𝗼𝗽𝘆𝗙𝗼𝗹𝗱𝗲𝗿(q(aaa), q(bbb));
    my $b = readFiles(q(bbb));
    is_deeply [sort values %$a],[sort values %$b];

    copyFile(q(aaa/1.txt), q(aaa/2.txt));
    my $A = readFiles(q(aaa));
    is_deeply(values %$A);

    clearFolder(q(aaa), 3);
    clearFolder(q(bbb), 3);
   }

copyFolderToRemote($$)

Copy the specified local $Source folder to the corresponding remote folder on the server whose address is returned by awsIp using either the optional $userid or the default userid supplied by .ssh/config

     Parameter  Description
  1  $Source    Source file
  2  $userid    Userid on server

Example:

  if (0)
   {𝗰𝗼𝗽𝘆𝗙𝗼𝗹𝗱𝗲𝗿𝗧𝗼𝗥𝗲𝗺𝗼𝘁𝗲(q(/home/phil/perl/cpan/), q(phil));
   }

copyFolderFromRemote($$)

Copy to the specified local $Source folder the corresponding remote folder on the server whose address is returned by awsIp using either the optional $userid or the default userid supplied by .ssh/config

     Parameter  Description
  1  $Source    Source file
  2  $userid    Userid on server

Example:

    𝗰𝗼𝗽𝘆𝗙𝗼𝗹𝗱𝗲𝗿𝗙𝗿𝗼𝗺𝗥𝗲𝗺𝗼𝘁𝗲(q(/home/phil/tests/));

Testing

Methods to assist with testing

removeFilePathsFromStructure($)

Remove all file paths from a specified $structure to make said $structure testable with is_deeply().

     Parameter   Description
  1  $structure  Data structure reference

Example:

  if (1)
   {my $d = {"/home/aaa/bbb.txt"=>1, "ccc/ddd.txt"=>2, "eee.txt"=>3};
    my $D = 𝗿𝗲𝗺𝗼𝘃𝗲𝗙𝗶𝗹𝗲𝗣𝗮𝘁𝗵𝘀𝗙𝗿𝗼𝗺𝗦𝘁𝗿𝘂𝗰𝘁𝘂𝗿𝗲($d);

    is_deeply 𝗿𝗲𝗺𝗼𝘃𝗲𝗙𝗶𝗹𝗲𝗣𝗮𝘁𝗵𝘀𝗙𝗿𝗼𝗺𝗦𝘁𝗿𝘂𝗰𝘁𝘂𝗿𝗲($d),
     {"bbb.txt"=>1, "ddd.txt"=>2, "eee.txt"=>3};

    ok writeStructureTest($d, q($d)) eq <<'END';
    is_deeply 𝗿𝗲𝗺𝗼𝘃𝗲𝗙𝗶𝗹𝗲𝗣𝗮𝘁𝗵𝘀𝗙𝗿𝗼𝗺𝗦𝘁𝗿𝘂𝗰𝘁𝘂𝗿𝗲($d),
     { "bbb.txt" => 1, "ddd.txt" => 2, "eee.txt" => 3 };
  END
   }

writeStructureTest($$)

Write a test for a data $structure with file names in it.

     Parameter   Description
  1  $structure  Data structure reference
  2  $expr       Expression

Example:

  if (1)
   {my $d = {"/home/aaa/bbb.txt"=>1, "ccc/ddd.txt"=>2, "eee.txt"=>3};
    my $D = removeFilePathsFromStructure($d);

    is_deeply removeFilePathsFromStructure($d),
     {"bbb.txt"=>1, "ddd.txt"=>2, "eee.txt"=>3};

    ok 𝘄𝗿𝗶𝘁𝗲𝗦𝘁𝗿𝘂𝗰𝘁𝘂𝗿𝗲𝗧𝗲𝘀𝘁($d, q($d)) eq <<'END';
    is_deeply removeFilePathsFromStructure($d),
     { "bbb.txt" => 1, "ddd.txt" => 2, "eee.txt" => 3 };
  END
   }

Images

Image operations.

imageSize($)

Return (width, height) of an image obtained via Imagemagick.

     Parameter  Description
  1  $image     File containing image

Example:

    my ($width, $height) = 𝗶𝗺𝗮𝗴𝗲𝗦𝗶𝘇𝗲(fpe(qw(a image jpg)));

convertImageToJpx($$$$)

Convert an image to jpx format using Imagemagick applying an optional scaling if required.

     Parameter  Description
  1  $Source    Source file
  2  $target    Target folder (as multiple files will be created)
  3  $Size      Optional size of each tile - defaults to 256
  4  $Tiles     Optional limit in either direction on the number of tiles

Example:

    𝗰𝗼𝗻𝘃𝗲𝗿𝘁𝗜𝗺𝗮𝗴𝗲𝗧𝗼𝗝𝗽𝘅(fpe(qw(a image jpg)), fpe(qw(a image jpg)), 256);

convertDocxToFodt($$)

Convert a docx file to fodt using unoconv which must not be running elsewhere at the time. Unoconv can be installed via:

  sudo apt install sharutils unoconv

Parameters:

     Parameter    Description
  1  $inputFile   Input file
  2  $outputFile  Output file

Example:

    𝗰𝗼𝗻𝘃𝗲𝗿𝘁𝗗𝗼𝗰𝘅𝗧𝗼𝗙𝗼𝗱𝘁(fpe(qw(a docx)), fpe(qw(a fodt)));

cutOutImagesInFodtFile($$$)

Cut out the images embedded in a fodt file, perhaps produced via convertDocxToFodt, placing them in the specified folder and replacing them in the source file with:

  <image href="$imageFile" outputclass="imageType">.

This conversion requires that you have both Imagemagick and unoconv installed on your system:

    sudo apt install sharutils  imagemagick unoconv

Parameters:

     Parameter      Description
  1  $inputFile     Input file
  2  $outputFolder  Output folder for images
  3  $imagePrefix   A prefix to be added to image file names

Example:

    𝗰𝘂𝘁𝗢𝘂𝘁𝗜𝗺𝗮𝗴𝗲𝘀𝗜𝗻𝗙𝗼𝗱𝘁𝗙𝗶𝗹𝗲(fpe(qw(source fodt)), fpd(qw(images)), q(image));

Encoding and Decoding

Encode and decode using Json and Mime.

encodeJson($)

Encode Perl to Json.

     Parameter  Description
  1  $string    Data to encode

Example:

    my $A = 𝗲𝗻𝗰𝗼𝗱𝗲𝗝𝘀𝗼𝗻(my $a = {a=>1,b=>2, c=>[1..2]});

    my $b = decodeJson($A);

    is_deeply $a, $b;

decodeJson($)

Decode Perl from Json.

     Parameter  Description
  1  $string    Data to decode

Example:

    my $A = encodeJson(my $a = {a=>1,b=>2, c=>[1..2]});

    my $b = 𝗱𝗲𝗰𝗼𝗱𝗲𝗝𝘀𝗼𝗻($A);

    is_deeply $a, $b;

encodeBase64($)

Encode an ascii string in base 64.

     Parameter  Description
  1  $string    String to encode

Example:

    my $A = 𝗲𝗻𝗰𝗼𝗱𝗲𝗕𝗮𝘀𝗲𝟲𝟰(my $a = "Hello World" x 10);

    my $b = decodeBase64($A);

    ok $a eq $b;

decodeBase64($)

Decode an ascii string in base 64.

     Parameter  Description
  1  $string    String to decode

Example:

    my $A = encodeBase64(my $a = "Hello World" x 10);

    my $b = 𝗱𝗲𝗰𝗼𝗱𝗲𝗕𝗮𝘀𝗲𝟲𝟰($A);

    ok $a eq $b;

convertUnicodeToXml($)

Convert a string with unicode points that are not directly representable in ascii into string that replaces these points with their representation on Xml making the string usable in Xml documents.

     Parameter  Description
  1  $s         String to convert

Example:

  ok 𝗰𝗼𝗻𝘃𝗲𝗿𝘁𝗨𝗻𝗶𝗰𝗼𝗱𝗲𝗧𝗼𝗫𝗺𝗹('setenta e três') eq q(setenta e tr&#234;s);

asciiToHexString($)

Encode an ascii string as a string of hexadecimal digits.

     Parameter  Description
  1  $ascii     Ascii string

Example:

  if (1) {
    ok 𝗮𝘀𝗰𝗶𝗶𝗧𝗼𝗛𝗲𝘅𝗦𝘁𝗿𝗶𝗻𝗴("Hello World!") eq                  "48656c6c6f20576f726c6421";
    ok                  "Hello World!"  eq hexToAsciiString("48656c6c6f20576f726c6421");
   }

hexToAsciiString($)

Decode a string of hexadecimal digits as an ascii string.

     Parameter  Description
  1  $hex       Hexadecimal string

Example:

  if (1) {
    ok asciiToHexString("Hello World!") eq                  "48656c6c6f20576f726c6421";
    ok                  "Hello World!"  eq 𝗵𝗲𝘅𝗧𝗼𝗔𝘀𝗰𝗶𝗶𝗦𝘁𝗿𝗶𝗻𝗴("48656c6c6f20576f726c6421");
   }

wwwEncode($)

Percent encode a url per: https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters

     Parameter  Description
  1  $string    String

Example:

  if (1) {
    ok 𝘄𝘄𝘄𝗘𝗻𝗰𝗼𝗱𝗲(q(a  {b} <c>)) eq q(a%20%20%7bb%7d%20%3cc%3e);
    ok 𝘄𝘄𝘄𝗘𝗻𝗰𝗼𝗱𝗲(q(../))        eq q(%2e%2e/);
    ok wwwDecode(𝘄𝘄𝘄𝗘𝗻𝗰𝗼𝗱𝗲 $_) eq $_ for q(a  {b} <c>), q(a  b|c),
      q(%), q(%%), q(%%.%%);
   }

  sub 𝘄𝘄𝘄𝗘𝗻𝗰𝗼𝗱𝗲($)
   {my ($string) = @_;                                                            # String
    join '', map {$translatePercentEncoding{$_}//$_} split //, $string
   }

wwwDecode($)

Percent decode a url per: https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters

     Parameter  Description
  1  $string    String

Example:

  if (1) {
    ok wwwEncode(q(a  {b} <c>)) eq q(a%20%20%7bb%7d%20%3cc%3e);
    ok wwwEncode(q(../))        eq q(%2e%2e/);
    ok 𝘄𝘄𝘄𝗗𝗲𝗰𝗼𝗱𝗲(wwwEncode $_) eq $_ for q(a  {b} <c>), q(a  b|c),
      q(%), q(%%), q(%%.%%);
   }

  sub 𝘄𝘄𝘄𝗗𝗲𝗰𝗼𝗱𝗲($)
   {my ($string) = @_;                                                            # String
    my $r = '';
    my @s = split //, $string;
    while(@s)
     {my $c = shift @s;
      if ($c eq q(%) and @s >= 2)
       {$c .= shift(@s).shift(@s);
        $r .= $TranslatePercentEncoding{$c}//$c;
       }
      else
       {$r .= $c;
       }
     }
    $r =~ s(%0d0a) (
)gs;                                                        # Awkward characters that appear in urls
    $r =~ s(\+)     ( )gs;
    $r
   }

Numbers

Numeric operations,

powerOfTwo($)

Test whether a number is a power of two, return the power if it is else undef.

     Parameter  Description
  1  $n         Number to check

Example:

  ok  𝗽𝗼𝘄𝗲𝗿𝗢𝗳𝗧𝘄𝗼(1) == 0;

  ok  𝗽𝗼𝘄𝗲𝗿𝗢𝗳𝗧𝘄𝗼(2) == 1;

  ok !𝗽𝗼𝘄𝗲𝗿𝗢𝗳𝗧𝘄𝗼(3);

  ok  𝗽𝗼𝘄𝗲𝗿𝗢𝗳𝗧𝘄𝗼(4) == 2;

containingPowerOfTwo($)

Find log two of the lowest power of two greater than or equal to a number.

     Parameter  Description
  1  $n         Number to check

Example:

  ok  𝗰𝗼𝗻𝘁𝗮𝗶𝗻𝗶𝗻𝗴𝗣𝗼𝘄𝗲𝗿𝗢𝗳𝗧𝘄𝗼(1) == 0;

  ok  𝗰𝗼𝗻𝘁𝗮𝗶𝗻𝗶𝗻𝗴𝗣𝗼𝘄𝗲𝗿𝗢𝗳𝗧𝘄𝗼(2) == 1;

  ok  𝗰𝗼𝗻𝘁𝗮𝗶𝗻𝗶𝗻𝗴𝗣𝗼𝘄𝗲𝗿𝗢𝗳𝗧𝘄𝗼(3) == 2;

  ok  𝗰𝗼𝗻𝘁𝗮𝗶𝗻𝗶𝗻𝗴𝗣𝗼𝘄𝗲𝗿𝗢𝗳𝗧𝘄𝗼(4) == 2;

Sets

Set operations.

mergeHashesBySummingValues(@)

Merge the specified hashes by summing their values

     Parameter  Description
  1  @h         List of hashes to be summed

Example:

  if (1) {
    is_deeply +{a=>1, b=>2, c=>3},
      𝗺𝗲𝗿𝗴𝗲𝗛𝗮𝘀𝗵𝗲𝘀𝗕𝘆𝗦𝘂𝗺𝗺𝗶𝗻𝗴𝗩𝗮𝗹𝘂𝗲𝘀
        +{a=>1,b=>1, c=>1}, +{b=>1,c=>1}, +{c=>1};
   }

invertHashOfHashes(@)

Invert a hash of hashes: given {a}{b} = c return {b}{c} = c

     Parameter  Description
  1  $h         Hash of hashes

Example:

  if (1) {
    my $h =  {a=>{A=>q(aA), B=>q(aB)}, b=>{A=>q(bA), B=>q(bB)}};
    my $g =  {A=>{a=>q(aA), b=>q(bA)}, B=>{a=>q(aB), b=>q(bB)}};

    is_deeply 𝗶𝗻𝘃𝗲𝗿𝘁𝗛𝗮𝘀𝗵𝗢𝗳𝗛𝗮𝘀𝗵𝗲𝘀($h), $g;
    is_deeply 𝗶𝗻𝘃𝗲𝗿𝘁𝗛𝗮𝘀𝗵𝗢𝗳𝗛𝗮𝘀𝗵𝗲𝘀($g), $h;
   }

unionOfHashKeys(@)

Form the union of the keys of the specified hashes as one hash whose keys represent the union.

     Parameter  Description
  1  @h         List of hashes to be united

Example:

  if (1)
   {is_deeply  𝘂𝗻𝗶𝗼𝗻𝗢𝗳𝗛𝗮𝘀𝗵𝗞𝗲𝘆𝘀
     ({a=>1,b=>2}, {b=>1,c=>1}, {c=>2}),
      {a=>1, b=>2, c=>2};

    is_deeply  intersectionOfHashKeys
     ({a=>1,b=>2},{b=>1,c=>1},{b=>3,c=>2}),
      {b=>1};
   }

intersectionOfHashKeys(@)

Form the intersection of the keys of the specified hashes as one hash whose keys represent the intersection.

     Parameter  Description
  1  @h         List of hashes to be intersected

Example:

  if (1)
   {is_deeply  unionOfHashKeys
     ({a=>1,b=>2}, {b=>1,c=>1}, {c=>2}),
      {a=>1, b=>2, c=>2};

    is_deeply  𝗶𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻𝗢𝗳𝗛𝗮𝘀𝗵𝗞𝗲𝘆𝘀
     ({a=>1,b=>2},{b=>1,c=>1},{b=>3,c=>2}),
      {b=>1};
   }

unionOfHashesAsArrays(@)

Form the union of the specified hashes as one hash whose values are a array of corresponding values from each hash

     Parameter  Description
  1  @h         List of hashes to be united

Example:

  if (1)
   {is_deeply  𝘂𝗻𝗶𝗼𝗻𝗢𝗳𝗛𝗮𝘀𝗵𝗲𝘀𝗔𝘀𝗔𝗿𝗿𝗮𝘆𝘀
     ({a=>1,b=>2}, {b=>1,c=>1}, {c=>2}),
      {a=>[1], b=>[2,1], c=>[undef,1,2]};

    is_deeply  intersectionOfHashesAsArrays
     ({a=>1,b=>2},{b=>1,c=>1},{b=>3,c=>2}),
      {b=>[2,1,3]};
   }

intersectionOfHashesAsArrays(@)

Form the intersection of the specified hashes as one hash whose values are an array of corresponding values from each hash

     Parameter  Description
  1  @h         List of hashes to be intersected

Example:

  if (1)
   {is_deeply  unionOfHashesAsArrays
     ({a=>1,b=>2}, {b=>1,c=>1}, {c=>2}),
      {a=>[1], b=>[2,1], c=>[undef,1,2]};

    is_deeply  𝗶𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻𝗢𝗳𝗛𝗮𝘀𝗵𝗲𝘀𝗔𝘀𝗔𝗿𝗿𝗮𝘆𝘀
     ({a=>1,b=>2},{b=>1,c=>1},{b=>3,c=>2}),
      {b=>[2,1,3]};
   }

setUnion(@)

Union of sets represented as arrays of strings and/or the keys of hashes

     Parameter  Description
  1  @s         Array of arrays of strings and/or hashes

Example:

  if (1) {
    is_deeply [qw(a b c)],     [𝘀𝗲𝘁𝗨𝗻𝗶𝗼𝗻(qw(a b c a a b b b))];
    is_deeply [qw(a b c d e)], [𝘀𝗲𝘁𝗨𝗻𝗶𝗼𝗻 {a=>1, b=>2, e=>3}, [qw(c d e)], qw(e)];
   }

setIntersection(@)

Intersection of sets represented as arrays of strings and/or the keys of hashes

     Parameter  Description
  1  @s         Array of arrays of strings and/or hashes

Example:

  if (1) {
    is_deeply [qw(a b c)], [𝘀𝗲𝘁𝗜𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻[qw(e f g a b c )],[qw(a A b B c C)]];
    is_deeply [qw(e)],   [𝘀𝗲𝘁𝗜𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻 {a=>1, b=>2, e=>3}, [qw(c d e)], qw(e)];
   }

setIntersectionOverUnion(@)

Returns the size of the intersection over the size of the union of one or more sets represented as arrays and/or hashes

     Parameter  Description
  1  @s         Array of arrays of strings and/or hashes

Example:

  if (1) {
    my $f = 𝘀𝗲𝘁𝗜𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻𝗢𝘃𝗲𝗿𝗨𝗻𝗶𝗼𝗻 {a=>1, b=>2, e=>3}, [qw(c d e)], qw(e);
    ok $f > 0.199999 && $f < 2.00001;
   }

setPartitionOnIntersectionOverUnion($@)

Partition a set of sets so that within each partition the setIntersectionOverUnion of any two sets in the partition is never less than the specified $confidence**2

     Parameter    Description
  1  $confidence  Minimum setIntersectionOverUnion
  2  @sets        Array of arrays of strings and/or hashes representing sets

Example:

  if (1) {
    is_deeply [𝘀𝗲𝘁𝗣𝗮𝗿𝘁𝗶𝘁𝗶𝗼𝗻𝗢𝗻𝗜𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻𝗢𝘃𝗲𝗿𝗨𝗻𝗶𝗼𝗻
     (0.80,
       [qw(a A   b c d e)],
       [qw(a A B b c d e)],
       [qw(a A B C b c d)],
     )],
    [[["A", "B", "a".."e"],
      ["A",      "a".."e"]],
     [["A".."C", "a".."d"]],
    ];
  }




  if (1) {
  is_deeply [setPartitionOnIntersectionOverUnionOfSetsOfWords
     (0.80,
       [qw(a A   b c d e)],
       [qw(a A B b c d e)],
       [qw(a A B C b c d)],
     )],
   [[["a", "A", "B", "C", "b", "c", "d"]],
    [["a", "A", "B", "b" .. "e"], ["a", "A", "b" .. "e"]],
   ];
   }

setPartitionOnIntersectionOverUnionOfSetsOfWords($@)

Partition a set of sets of words so that within each partition the setIntersectionOverUnion of any two sets of words in the partition is never less than the specified $confidence**2

     Parameter    Description
  1  $confidence  Minimum setIntersectionOverUnion
  2  @sets        Array of arrays of strings and/or hashes representing sets

Example:

  if (1) {
  is_deeply [𝘀𝗲𝘁𝗣𝗮𝗿𝘁𝗶𝘁𝗶𝗼𝗻𝗢𝗻𝗜𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻𝗢𝘃𝗲𝗿𝗨𝗻𝗶𝗼𝗻𝗢𝗳𝗦𝗲𝘁𝘀𝗢𝗳𝗪𝗼𝗿𝗱𝘀
     (0.80,
       [qw(a A   b c d e)],
       [qw(a A B b c d e)],
       [qw(a A B C b c d)],
     )],
   [[["a", "A", "B", "C", "b", "c", "d"]],
    [["a", "A", "B", "b" .. "e"], ["a", "A", "b" .. "e"]],
   ];
   }

setPartitionOnIntersectionOverUnionOfStringSets($@)

Partition a set of sets, each set represented by a string containing words and punctuation, each word possibly capitalized, so that within each partition the setPartitionOnIntersectionOverUnionOfSetsOfWords of any two sets of words in the partition is never less than the specified $confidence**2

     Parameter    Description
  1  $confidence  Minimum setIntersectionOverUnion
  2  @strings     Sets represented by strings

Example:

  if (1) {
  is_deeply [𝘀𝗲𝘁𝗣𝗮𝗿𝘁𝗶𝘁𝗶𝗼𝗻𝗢𝗻𝗜𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻𝗢𝘃𝗲𝗿𝗨𝗻𝗶𝗼𝗻𝗢𝗳𝗦𝘁𝗿𝗶𝗻𝗴𝗦𝗲𝘁𝘀
     (0.80,
       q(The Emu            are seen here sometimes.),
       q(The Emu, Gnu       are seen here sometimes.),
       q(The Emu, Gnu, Colt are seen here.),
     )],
   [["The Emu, Gnu, Colt are seen here."],
    ["The Emu, Gnu       are seen here sometimes.",
     "The Emu            are seen here sometimes.",
    ]];
   }

setPartitionOnIntersectionOverUnionOfHashStringSets($$)

Partition a set of sets represented by a hash, each hash value being a string containing words and punctuation, each word possibly capitalized, so that within each partition the setPartitionOnIntersectionOverUnionOfSetsOfWords of any two sets of words in the partition is never less than the specified $confidence**2 and the partition entries are the hash keys of the string sets.

     Parameter    Description
  1  $confidence  Minimum setIntersectionOverUnion
  2  $hashSet     Sets represented by the hash value strings

Example:

  if (1) {
    is_deeply [𝘀𝗲𝘁𝗣𝗮𝗿𝘁𝗶𝘁𝗶𝗼𝗻𝗢𝗻𝗜𝗻𝘁𝗲𝗿𝘀𝗲𝗰𝘁𝗶𝗼𝗻𝗢𝘃𝗲𝗿𝗨𝗻𝗶𝗼𝗻𝗢𝗳𝗛𝗮𝘀𝗵𝗦𝘁𝗿𝗶𝗻𝗴𝗦𝗲𝘁𝘀
     (0.80,
       {e  =>q(The Emu            are seen here sometimes.),
        eg =>q(The Emu, Gnu       are seen here sometimes.),
        egc=>q(The Emu, Gnu, Colt are seen here.),
       }
     )],
   [["e", "eg"], ["egc"]];
   }

contains($@)

Returns the indices at which an item matches elements of the specified array. If the item is a regular expression then it is matched as one, else it is a number it is matched as a number, else as a string.

     Parameter  Description
  1  $item      Item
  2  @array     Array

Example:

  is_deeply [1],       [𝗰𝗼𝗻𝘁𝗮𝗶𝗻𝘀(1,0..1)];

  is_deeply [1,3],     [𝗰𝗼𝗻𝘁𝗮𝗶𝗻𝘀(1, qw(0 1 0 1 0 0))];

  is_deeply [0, 5],    [𝗰𝗼𝗻𝘁𝗮𝗶𝗻𝘀('a', qw(a b c d e a b c d e))];

  is_deeply [0, 1, 5], [𝗰𝗼𝗻𝘁𝗮𝗶𝗻𝘀(qr(a+), qw(a baa c d e aa b c d e))];

countOccurencesInString($$)

Returns the number of times the first string occurs in the second string

     Parameter   Description
  1  $inString   String to search in
  2  $searchFor  String to search for.

Example:

  if (1)
   {ok 𝗰𝗼𝘂𝗻𝘁𝗢𝗰𝗰𝘂𝗿𝗲𝗻𝗰𝗲𝘀𝗜𝗻𝗦𝘁𝗿𝗶𝗻𝗴(q(a<b>c<b><b>d), q(<b>)) == 3;
   }

partitionStringsOnPrefixBySize()

Partition a hash of strings and associated sizes into partitions with either a maximum size $maxSize or only one element; the hash %Sizes consisting of a mapping {string=>size}; with each partition being named with the shortest string prefix that identifies just the strings in that partition. Returns a list of {prefix=>size}... describing each partition.

Example:

  if (1)
   {my $ps = \&𝗽𝗮𝗿𝘁𝗶𝘁𝗶𝗼𝗻𝗦𝘁𝗿𝗶𝗻𝗴𝘀𝗢𝗻𝗣𝗿𝗲𝗳𝗶𝘅𝗕𝘆𝗦𝗶𝘇𝗲;

    is_deeply {&$ps(1)}, {};
    is_deeply {&$ps(1, 1=>0)},      {q()=>0};
    is_deeply {&$ps(1, 1=>1)},      {q()=>1};
    is_deeply {&$ps(1, 1=>2)},      {1=>2};
    is_deeply {&$ps(1, 1=>1,2=>1)}, {1=>1,2=>1};
    is_deeply {&$ps(2, 11=>1,12=>1, 21=>1,22=>1)}, {1=>2, 2=>2};
    is_deeply {&$ps(2, 111=>1,112=>1,113=>1, 121=>1,122=>1,123=>1, 131=>1,132=>1,133=>1)}, { 111 => 1, 112 => 1, 113 => 1, 121 => 1, 122 => 1, 123 => 1, 131 => 1, 132 => 1, 133 => 1 };

    for(3..8)
     {is_deeply {&$ps($_, 111=>1,112=>1,113=>1, 121=>1,122=>1,123=>1, 131=>1,132=>1,133=>1)}, { 11 => 3, 12 => 3, 13 => 3 };
     }

    is_deeply {&$ps(9, 111=>1,112=>1,113=>1, 121=>1,122=>1,123=>1, 131=>1,132=>1,133=>1)}, { q()=> 9};
    is_deeply {&$ps(3, 111=>1,112=>1,113=>1, 121=>1,122=>1,123=>1, 131=>1,132=>1,133=>2)}, { 11 => 3, 12 => 3, 131 => 1, 132 => 1, 133 => 2 };
    is_deeply {&$ps(4, 111=>1,112=>1,113=>1, 121=>1,122=>1,123=>1, 131=>1,132=>1,133=>2)}, { 11 => 3, 12 => 3, 13 => 4 };

   }

Minima and Maxima

Find the smallest and largest elements of arrays.

min(@)

Find the minimum number in a list confessing to any ill defined values.

     Parameter  Description
  1  @m         Numbers

Example:

  ok 𝗺𝗶𝗻(1) == 1;

  ok 𝗺𝗶𝗻(5,4,2,3) == 2;

indexOfMin(@)

Find the index of the minimum number in a list confessing to any ill defined values.

     Parameter  Description
  1  @m         Numbers

Example:

    ok 𝗶𝗻𝗱𝗲𝘅𝗢𝗳𝗠𝗶𝗻(qw(2 3 1 2)) == 2;

max(@)

Find the maximum number in a list confessing to any ill defined values.

     Parameter  Description
  1  @m         Numbers

Example:

  ok !𝗺𝗮𝘅;

  ok 𝗺𝗮𝘅(1) == 1;

  ok 𝗺𝗮𝘅(1,4,2,3) == 4;

indexOfMax(@)

Find the index of the maximum number in a list confessing to any ill defined values.

     Parameter  Description
  1  @m         Numbers

Example:

   {ok 𝗶𝗻𝗱𝗲𝘅𝗢𝗳𝗠𝗮𝘅(qw(2 3 1 2)) == 1;

arraySum(@)

Find the sum of any strings that look like numbers in an array

     Parameter  Description
  1  @a         Array to sum

Example:

   {ok 𝗮𝗿𝗿𝗮𝘆𝗦𝘂𝗺   (1..10) ==  55;

arrayProduct(@)

Find the product of any strings that look like numbers in an array

     Parameter  Description
  1  @a         Array to multiply

Example:

    ok 𝗮𝗿𝗿𝗮𝘆𝗣𝗿𝗼𝗱𝘂𝗰𝘁(1..5) == 120;

arrayTimes($@)

Multiply the second and subsequent parameters by the first parameter and return as an array

     Parameter    Description
  1  $multiplier  Multiplier
  2  @a           Array to multiply and return

Example:

    is_deeply[𝗮𝗿𝗿𝗮𝘆𝗧𝗶𝗺𝗲𝘀(2, 1..5)], [qw(2 4 6 8 10)];

Format

Format data structures as tables.

maximumLineLength($)

Find the longest line in a string

     Parameter  Description
  1  $string    String of lines of text

Example:

  ok 3 == 𝗺𝗮𝘅𝗶𝗺𝘂𝗺𝗟𝗶𝗻𝗲𝗟𝗲𝗻𝗴𝘁𝗵(<<END);
  a
  bb
  ccc
  END

formatTableBasic($)

Tabularize an array of arrays of text.

     Parameter  Description
  1  $data      Reference to an array of arrays of data to be formatted as a table.

Example:

  if (1) {
    my $d = [[qw(a 1)], [qw(bb 22)], [qw(ccc 333)], [qw(dddd 4444)]];
    ok 𝗳𝗼𝗿𝗺𝗮𝘁𝗧𝗮𝗯𝗹𝗲𝗕𝗮𝘀𝗶𝗰($d) eq <<END, q(ftb);
  a        1
  bb      22
  ccc    333
  dddd  4444
  END
    }

  if (0) {
    my %pids;
    sub{startProcess {} %pids, 1; ok 1 >= keys %pids}->() for 1..8;
    waitForAllStartedProcessesToFinish(%pids);
    ok !keys(%pids)
   }

formatTable($$%)

Format various $data structures as a table with titles as specified by $columnTitles: either a reference to an array of column titles or a string each line of which contains the column title as the first word with the rest of the line describing that column.

Optionally create a report from the table using the report %options described in formatTableCheckKeys

     Parameter      Description
  1  $data          Data to be formatted
  2  $columnTitles  Optional reference to an array of titles or string of column descriptions
  3  @options       Options

Example:

  ok 𝗳𝗼𝗿𝗺𝗮𝘁𝗧𝗮𝗯𝗹𝗲

   ([[qw(A    B    C    D   )],

     [qw(AA   BB   CC   DD  )],

     [qw(AAA  BBB  CCC  DDD )],

     [qw(AAAA BBBB CCCC DDDD)],

     [qw(1    22   333  4444)]], [qw(aa bb cc)]) eq <<END;
     aa    bb    cc
  1  A     B     C     D
  2  AA    BB    CC    DD
  3  AAA   BBB   CCC   DDD
  4  AAAA  BBBB  CCCC  DDDD
  5     1    22   333  4444
  END

  ok 𝗳𝗼𝗿𝗺𝗮𝘁𝗧𝗮𝗯𝗹𝗲

   ([[qw(1     B   C)],

     [qw(22    BB  CC)],

     [qw(333   BBB CCC)],

     [qw(4444  22  333)]], [qw(aa bb cc)]) eq <<END;
     aa    bb   cc
  1     1  B    C
  2    22  BB   CC
  3   333  BBB  CCC
  4  4444   22  333
  END

  ok 𝗳𝗼𝗿𝗺𝗮𝘁𝗧𝗮𝗯𝗹𝗲

   ([{aa=>'A',   bb=>'B',   cc=>'C'},

     {aa=>'AA',  bb=>'BB',  cc=>'CC'},

     {aa=>'AAA', bb=>'BBB', cc=>'CCC'},

     {aa=>'1',   bb=>'22',  cc=>'333'}

     ]) eq <<END;
     aa   bb   cc
  1  A    B    C
  2  AA   BB   CC
  3  AAA  BBB  CCC
  4    1   22  333
  END

  ok 𝗳𝗼𝗿𝗺𝗮𝘁𝗧𝗮𝗯𝗹𝗲

   ({''=>[qw(aa bb cc)],

      1=>[qw(A B C)],

      22=>[qw(AA BB CC)],

      333=>[qw(AAA BBB CCC)],

      4444=>[qw(1 22 333)]}) eq <<END;
        aa   bb   cc
     1  A    B    C
    22  AA   BB   CC
   333  AAA  BBB  CCC
  4444    1   22  333
  END

  ok 𝗳𝗼𝗿𝗺𝗮𝘁𝗧𝗮𝗯𝗹𝗲

   ({1=>{aa=>'A', bb=>'B', cc=>'C'},

     22=>{aa=>'AA', bb=>'BB', cc=>'CC'},

     333=>{aa=>'AAA', bb=>'BBB', cc=>'CCC'},

     4444=>{aa=>'1', bb=>'22', cc=>'333'}}) eq <<END;
        aa   bb   cc
     1  A    B    C
    22  AA   BB   CC
   333  AAA  BBB  CCC
  4444    1   22  333
  END

  ok 𝗳𝗼𝗿𝗺𝗮𝘁𝗧𝗮𝗯𝗹𝗲({aa=>'A', bb=>'B', cc=>'C'}, [qw(aaaa bbbb)]) eq <<END;
  aaaa  bbbb
  aa    A
  bb    B
  cc    C
  END

  if (1) {
    my $file = fpe(qw(report txt));                                               # Create a report
    my $t = 𝗳𝗼𝗿𝗺𝗮𝘁𝗧𝗮𝗯𝗹𝗲
     ([["a",undef], [undef, "b0ac"]],                                           # Data - please replace 0a with a new line
      [undef, "BC"],                                                              # Column titles
      file=>$file,                                                                # Output file
      head=><<END);                                                               # Header
  Sample report.

  Table has NNNN rows.
  END
    ok -e $file;
    ok readFile($file) eq $t;
    unlink $file;
    ok nws($t) eq nws(<<END);
  Sample report.

  Table has 2 rows.

  This file: report.txt

        BC
  1  a
  2     b
        c
  END
   }

formattedTablesReport(@)

Report of all the reports created. The optional parameters are the same as for formatTable

     Parameter  Description
  1  @options   Options

Example:

  if (1) {
    @formatTables = ();

    for my $m(2..8)
     {formatTable([map {[$_, $_*$m]} 1..$m], [q(Single), qq(* $m)],
        title=>qq(Multiply by $m));
     }

    ok nws(𝗳𝗼𝗿𝗺𝗮𝘁𝘁𝗲𝗱𝗧𝗮𝗯𝗹𝗲𝘀𝗥𝗲𝗽𝗼𝗿𝘁) eq nws(<<END);
     Rows  Title          File
  1     2  Multiply by 2
  2     3  Multiply by 3
  3     4  Multiply by 4
  4     5  Multiply by 5
  5     6  Multiply by 6
  6     7  Multiply by 7
  7     8  Multiply by 8
  END
   }

summarizeColumn($$)

Count the number of unique instances of each value a column in a table assumes.

     Parameter  Description
  1  $data      Table == array of arrays
  2  $column    Column number to summarize.

Example:

  if (1) {
    is_deeply
     [𝘀𝘂𝗺𝗺𝗮𝗿𝗶𝘇𝗲𝗖𝗼𝗹𝘂𝗺𝗻([map {[$_]} qw(A B D B C D C D A C D C B B D)], 0)],
     [[5, "D"], [4, "B"], [4, "C"], [2, "A"]];

    ok nws(formatTable
     ([map {[split m//, $_]} qw(AA CB CD BC DC DD CD AD AA DC CD CC BB BB BD)],
      [qw(Col-1 Col-2)],
       summarize=>1)) eq nws(<<'END');

  Summary_of_column                - Count of unique values found in each column                     Use the Geany flick capability by placing your cursor on the first word
  Comma_Separated_Values_of_column - Comma separated list of the unique values found in each column  of these lines and pressing control + down arrow to see each sub report.

      Col-1  Col-2
   1  A      A
   2  C      B
   3  C      D
   4  B      C
   5  D      C
   6  D      D
   7  C      D
   8  A      D
   9  A      A
  10  D      C
  11  C      D
  12  C      C
  13  B      B
  14  B      B
  15  B      D

  Summary_of_column_Col-1
     Count  Col-1
  1      5  C
  2      4  B
  3      3  A
  4      3  D

  Comma_Separated_Values_of_column_Col-1: "A","B","C","D"

  Summary_of_column_Col-2
     Count  Col-2
  1      6  D
  2      4  C
  3      3  B
  4      2  A

  Comma_Separated_Values_of_column_Col-2: "A","B","C","D"
  END
   }

keyCount($$)

Count keys down to the specified level.

     Parameter  Description
  1  $maxDepth  Maximum depth to count to
  2  $ref       Reference to an array or a hash

Example:

    my $a = [[1..3],       {map{$_=>1} 1..3}];

    my $h = {a=>[1..3], b=>{map{$_=>1} 1..3}};

    ok 𝗸𝗲𝘆𝗖𝗼𝘂𝗻𝘁(2, $a) == 6;

    ok 𝗸𝗲𝘆𝗖𝗼𝘂𝗻𝘁(2, $h) == 6;

formatHtmlTable($%)

Format an array of arrays of scalars as an html table using the %options described in formatTableCheckKeys.

     Parameter  Description
  1  $data      Data to be formatted
  2  %options   Options

Example:

  if (1)
   {my $t = 𝗳𝗼𝗿𝗺𝗮𝘁𝗛𝘁𝗺𝗹𝗧𝗮𝗯𝗹𝗲
     ([
        [qw(1 a)],
        [qw(2 b)],
      ],
     title  => q(Sample html table),
     head   => q(Head NNNN rows),
     foot   => q(Footer),
     columns=> <<END,
  source The source number
  target The target letter
  END
     );

    my $T = <<'END';
  <h1>Sample html table</h1>

  <p>Head 2 rows</p>

  <p><table borders="0" cellpadding="10" cellspacing="5">

  <tr><th><span title="The source number">source</span><th><span title="The target letter">target</span>
  <tr><td>1<td>a
  <tr><td>2<td>b
  </table></p>

  <p><pre>
  source  The source number
  target  The target letter

  </pre></p>

  <p>Footer</p>

  <span class="options" style="display: none">{
    columns => "source The source number
target The target letter
",
    foot    => "Footer",
    head    => "Head NNNN rows",
    rows    => 2,
    title   => "Sample html table",
  }</span>
  END

    ok "$t
" eq $T;
   }

formatHtmlTablesIndex($$$)

Create an index of html files for use use as an initial page of Xref results

     Parameter  Description
  1  $reports   Reports folder
  2  $title     Title of report of reports
  3  $url       $url to get files

Example:

  if (1)
   {my $reports = temporaryFolder;

    my $b = formatHtmlAndTextTables
     ($reports, $reports, q(/cgi-bin/getFile.pl?), q(/a/),
       [[qw(1 /a/a)],
        [qw(2 /a/b)],
       ],
     title   => q(Bad files),
     head    => q(Head NNNN rows),
     foot    => q(Footer),
     file    => q(bad.html),
     facet   => q(files), aspectColor => "red",
     columns => <<END,
  source The source number
  target The target letter
  END
     );

    my $g = formatHtmlAndTextTables
     ($reports, $reports, q(/cgi-bin/getFile.pl?file=), q(/a/),
       [[qw(1 /a/a1)],
        [qw(2 /a/b2)],
        [qw(3 /a/b3)],
       ],
     title   => q(Good files),
     head    => q(Head NNNN rows),
     foot    => q(Footer),
     file    => q(good.html),
     facet   => q(files), aspectColor => "green",
     columns => <<END,
  source The source number
  target The target letter
  END
     );

    my $result = 𝗳𝗼𝗿𝗺𝗮𝘁𝗛𝘁𝗺𝗹𝗧𝗮𝗯𝗹𝗲𝘀𝗜𝗻𝗱𝗲𝘅($reports, q(TITLE), q(/cgi-bin/getFile.pl?file=));
    ok $result =~ m(green.*>3<.*>Good files);
    ok $result =~ m(red.*>2<.*>Bad files);
   }

formatHtmlAndTextTables($$$$$%)

Create text and html versions of a tabular report

     Parameter    Description
  1  $reports     Folder to contain text reports
  2  $html        Folder to contain html reports
  3  $getFile     Url to get files
  4  $filePrefix  File prefix to be removed from file entries or array of file prefixes
  5  $data        Data
  6  %options     Options

Example:

  if (1)
   {my $reports = temporaryFolder;

    my $b = 𝗳𝗼𝗿𝗺𝗮𝘁𝗛𝘁𝗺𝗹𝗔𝗻𝗱𝗧𝗲𝘅𝘁𝗧𝗮𝗯𝗹𝗲𝘀
     ($reports, $reports, q(/cgi-bin/getFile.pl?), q(/a/),
       [[qw(1 /a/a)],
        [qw(2 /a/b)],
       ],
     title   => q(Bad files),
     head    => q(Head NNNN rows),
     foot    => q(Footer),
     file    => q(bad.html),
     facet   => q(files), aspectColor => "red",
     columns => <<END,
  source The source number
  target The target letter
  END
     );

    my $g = 𝗳𝗼𝗿𝗺𝗮𝘁𝗛𝘁𝗺𝗹𝗔𝗻𝗱𝗧𝗲𝘅𝘁𝗧𝗮𝗯𝗹𝗲𝘀
     ($reports, $reports, q(/cgi-bin/getFile.pl?file=), q(/a/),
       [[qw(1 /a/a1)],
        [qw(2 /a/b2)],
        [qw(3 /a/b3)],
       ],
     title   => q(Good files),
     head    => q(Head NNNN rows),
     foot    => q(Footer),
     file    => q(good.html),
     facet   => q(files), aspectColor => "green",
     columns => <<END,
  source The source number
  target The target letter
  END
     );

    my $result = formatHtmlTablesIndex($reports, q(TITLE), q(/cgi-bin/getFile.pl?file=));
    ok $result =~ m(green.*>3<.*>Good files);
    ok $result =~ m(red.*>2<.*>Bad files);
   }

Lines

Load data structures from lines.

loadArrayFromLines($)

Load an array from lines of text in a string.

     Parameter  Description
  1  $string    The string of lines from which to create an array

Example:

    my $s = 𝗹𝗼𝗮𝗱𝗔𝗿𝗿𝗮𝘆𝗙𝗿𝗼𝗺𝗟𝗶𝗻𝗲𝘀 <<END;
  a a
  b b
  END

    is_deeply $s, [q(a a), q(b b)];

    ok formatTable($s) eq <<END;
  0  a a
  1  b b
  END

loadHashFromLines($)

Load a hash: first word of each line is the key and the rest is the value.

     Parameter  Description
  1  $string    The string of lines from which to create a hash

Example:

    my $s = 𝗹𝗼𝗮𝗱𝗛𝗮𝘀𝗵𝗙𝗿𝗼𝗺𝗟𝗶𝗻𝗲𝘀 <<END;
  a 10 11 12
  b 20 21 22
  END

    is_deeply $s, {a => q(10 11 12), b =>q(20 21 22)};

    ok formatTable($s) eq <<END;
  a  10 11 12
  b  20 21 22
  END

loadArrayArrayFromLines($)

Load an array of arrays from lines of text: each line is an array of words.

     Parameter  Description
  1  $string    The string of lines from which to create an array of arrays

Example:

    my $s = 𝗹𝗼𝗮𝗱𝗔𝗿𝗿𝗮𝘆𝗔𝗿𝗿𝗮𝘆𝗙𝗿𝗼𝗺𝗟𝗶𝗻𝗲𝘀 <<END;
  A B C
  AA BB CC
  END

    is_deeply $s, [[qw(A B C)], [qw(AA BB CC)]];

    ok formatTable($s) eq <<END;
  1  A   B   C
  2  AA  BB  CC
  END

loadHashArrayFromLines($)

Load a hash of arrays from lines of text: the first word of each line is the key, the remaining words are the array contents.

     Parameter  Description
  1  $string    The string of lines from which to create a hash of arrays

Example:

    my $s = 𝗹𝗼𝗮𝗱𝗛𝗮𝘀𝗵𝗔𝗿𝗿𝗮𝘆𝗙𝗿𝗼𝗺𝗟𝗶𝗻𝗲𝘀 <<END;
  a A B C
  b AA BB CC
  END

    is_deeply $s, {a =>[qw(A B C)], b => [qw(AA BB CC)] };

    ok formatTable($s) eq <<END;
  a  A   B   C
  b  AA  BB  CC
  END

loadArrayHashFromLines($)

Load an array of hashes from lines of text: each line is a hash of words.

     Parameter  Description
  1  $string    The string of lines from which to create an array of arrays

Example:

    my $s = 𝗹𝗼𝗮𝗱𝗔𝗿𝗿𝗮𝘆𝗛𝗮𝘀𝗵𝗙𝗿𝗼𝗺𝗟𝗶𝗻𝗲𝘀 <<END;
  A 1 B 2
  AA 11 BB 22
  END

    is_deeply $s, [{A=>1, B=>2}, {AA=>11, BB=>22}];

    ok formatTable($s) eq <<END;
     A  AA  B  BB
  1  1      2
  2     11     22
  END

loadHashHashFromLines($)

Load a hash of hashes from lines of text: the first word of each line is the key, the remaining words are the sub hash contents.

     Parameter  Description
  1  $string    The string of lines from which to create a hash of arrays

Example:

    my $s = 𝗹𝗼𝗮𝗱𝗛𝗮𝘀𝗵𝗛𝗮𝘀𝗵𝗙𝗿𝗼𝗺𝗟𝗶𝗻𝗲𝘀 <<END;
  a A 1 B 2
  b AA 11 BB 22
  END

    is_deeply $s, {a=>{A=>1, B=>2}, b=>{AA=>11, BB=>22}};

    ok formatTable($s) eq <<END;
     A  AA  B  BB
  a  1      2
  b     11     22
  END

checkKeys($$)

Check the keys in a hash conform to those $permitted.

     Parameter   Description
  1  $hash       The hash to test
  2  $permitted  A hash of the permitted keys and their meanings

Example:

    eval q{𝗰𝗵𝗲𝗰𝗸𝗞𝗲𝘆𝘀({a=>1, b=>2, d=>3}, {a=>1, b=>2, c=>3})};

    ok nws($@) =~ m(\AInvalid options chosen: d Permitted.+?: a 1 b 2 c 3);

LVALUE methods

Replace $a->{value} = $b with $a->value = $b which reduces the amount of typing required, is easier to read and provides a hard check that {value} is spelled correctly.

genLValueScalarMethods(@)

Generate lvalue method scalar methods in the current package, A method whose value has not yet been set will return a new scalar with value undef. Suffixing X to the scalar name will confess if a value has not been set.

     Parameter  Description
  1  @names     List of method names

Example:

    package Scalars;

    my $a = bless{};

    Data::Table::Text::𝗴𝗲𝗻𝗟𝗩𝗮𝗹𝘂𝗲𝗦𝗰𝗮𝗹𝗮𝗿𝗠𝗲𝘁𝗵𝗼𝗱𝘀(qw(aa bb cc));

    $a->aa = 'aa';

    Test::More::ok  $a->aa eq 'aa';

    Test::More::ok !$a->bb;

    Test::More::ok  $a->bbX eq q();

    $a->aa = undef;

    Test::More::ok !$a->aa;

addLValueScalarMethods(@)

Generate lvalue method scalar methods in the current package if they do not already exist. A method whose value has not yet been set will return a new scalar with value undef. Suffixing X to the scalar name will confess if a value has not been set.

     Parameter  Description
  1  @names     List of method names

Example:

    my $class = "Data::Table::Text::Test";

    my $a = bless{}, $class;

    𝗮𝗱𝗱𝗟𝗩𝗮𝗹𝘂𝗲𝗦𝗰𝗮𝗹𝗮𝗿𝗠𝗲𝘁𝗵𝗼𝗱𝘀(qq(${class}::$_)) for qw(aa bb aa bb);

    $a->aa = 'aa';

    ok  $a->aa eq 'aa';

    ok !$a->bb;

    ok  $a->bbX eq q();

    $a->aa = undef;

    ok !$a->aa;

genLValueScalarMethodsWithDefaultValues(@)

Generate lvalue method scalar methods with default values in the current package. A reference to a method whose value has not yet been set will return a scalar whose value is the name of the method.

     Parameter  Description
  1  @names     List of method names

Example:

    package ScalarsWithDefaults;

    my $a = bless{};

    Data::Table::Text::𝗴𝗲𝗻𝗟𝗩𝗮𝗹𝘂𝗲𝗦𝗰𝗮𝗹𝗮𝗿𝗠𝗲𝘁𝗵𝗼𝗱𝘀𝗪𝗶𝘁𝗵𝗗𝗲𝗳𝗮𝘂𝗹𝘁𝗩𝗮𝗹𝘂𝗲𝘀(qw(aa bb cc));

    Test::More::ok $a->aa eq 'aa';

genLValueArrayMethods(@)

Generate lvalue method array methods in the current package. A reference to a method that has no yet been set will return a reference to an empty array.

     Parameter  Description
  1  @names     List of method names

Example:

    package Arrays;

    my $a = bless{};

    Data::Table::Text::𝗴𝗲𝗻𝗟𝗩𝗮𝗹𝘂𝗲𝗔𝗿𝗿𝗮𝘆𝗠𝗲𝘁𝗵𝗼𝗱𝘀(qw(aa bb cc));

    $a->aa->[1] = 'aa';

    Test::More::ok $a->aa->[1] eq 'aa';

genLValueHashMethods(@)

Generate lvalue method hash methods in the current package. A reference to a method that has no yet been set will return a reference to an empty hash.

     Parameter  Description
  1  @names     Method names

Example:

    package Hashes;

    my $a = bless{};

    Data::Table::Text::𝗴𝗲𝗻𝗟𝗩𝗮𝗹𝘂𝗲𝗛𝗮𝘀𝗵𝗠𝗲𝘁𝗵𝗼𝗱𝘀(qw(aa bb cc));

    $a->aa->{a} = 'aa';

    Test::More::ok $a->aa->{a} eq 'aa';

genHash($%)

Return a $blessed hash with the specified $attributes accessible via lvalue method method calls. updateDocumentation will generate documentation at "Hash Definitions" for the hash defined by the call to genHash if the call is laid out as in the example below.

     Parameter    Description
  1  $bless       Package name
  2  %attributes  Hash of attribute names and values

Example:

  if (1) {
    my $o = 𝗴𝗲𝗻𝗛𝗮𝘀𝗵(q(TestHash),                                                  # Definition of a blessed hash.
        a=>q(aa),                                                                 # Definition of attribute aa.
        b=>q(bb),                                                                 # Definition of attribute bb.
       );
    ok $o->a eq q(aa);
    is_deeply $o, {a=>"aa", b=>"bb"};
    my $p = 𝗴𝗲𝗻𝗛𝗮𝘀𝗵(q(TestHash),
      c=>q(cc),                                                                   # Definition of attribute cc.
     );
    ok $p->c eq q(cc);
    ok $p->a =  q(aa);
    ok $p->a eq q(aa);
    is_deeply $p, {a=>"aa", c=>"cc"};

    loadHash($p, a=>11, b=>22);                                                   # Load the hash
    is_deeply $p, {a=>11, b=>22, c=>"cc"};

    my $r = eval {loadHash($p, d=>44)};                                           # Try to load the hash
    ok $@ =~ m(Cannot load attribute: d);
   }

loadHash($%)

Load the specified blessed $hash generated with genHash with %attributes. Confess to any unknown attribute names.

     Parameter    Description
  1  $hash        Hash
  2  %attributes  Hash of attribute names and values to be loaded

Example:

  if (1) {
    my $o = genHash(q(TestHash),                                                  # Definition of a blessed hash.
        a=>q(aa),                                                                 # Definition of attribute aa.
        b=>q(bb),                                                                 # Definition of attribute bb.
       );
    ok $o->a eq q(aa);
    is_deeply $o, {a=>"aa", b=>"bb"};
    my $p = genHash(q(TestHash),
      c=>q(cc),                                                                   # Definition of attribute cc.
     );
    ok $p->c eq q(cc);
    ok $p->a =  q(aa);
    ok $p->a eq q(aa);
    is_deeply $p, {a=>"aa", c=>"cc"};

    𝗹𝗼𝗮𝗱𝗛𝗮𝘀𝗵($p, a=>11, b=>22);                                                   # Load the hash
    is_deeply $p, {a=>11, b=>22, c=>"cc"};

    my $r = eval {𝗹𝗼𝗮𝗱𝗛𝗮𝘀𝗵($p, d=>44)};                                           # Try to load the hash
    ok $@ =~ m(Cannot load attribute: d);
   }

reloadHashes($)

Ensures that all the hashes within a tower of data structures have LValue methods to get and set their current keys.

     Parameter  Description
  1  $d         Data structure

Example:

  if (1)
   {my $a = bless [bless {aaa=>42}, "AAAA"], "BBBB";
    eval {$a->[0]->aaa};
    ok $@ =~ m(\ACan.t locate object method .aaa. via package .AAAA.);
    𝗿𝗲𝗹𝗼𝗮𝗱𝗛𝗮𝘀𝗵𝗲𝘀($a);
    ok $a->[0]->aaa == 42;
   }

  if (1)
   {my $a = bless [bless {ccc=>42}, "CCCC"], "DDDD";
    eval {$a->[0]->ccc};
    ok $@ =~ m(\ACan.t locate object method .ccc. via package .CCCC.);
    𝗿𝗲𝗹𝗼𝗮𝗱𝗛𝗮𝘀𝗵𝗲𝘀($a);
    ok $a->[0]->ccc == 42;
   }

setPackageSearchOrder($@)

Set a package search order for methods requested in the current package via AUTOLOAD.

     Parameter  Description
  1  $set       Package to set
  2  @search    Package names in search order.

Example:

  if (1)
   {if (1)
     {package AAAA;

      sub aaaa{q(AAAAaaaa)}
      sub bbbb{q(AAAAbbbb)}
      sub cccc{q(AAAAcccc)}
     }
    if (1)
     {package BBBB;

      sub aaaa{q(BBBBaaaa)}
      sub bbbb{q(BBBBbbbb)}
      sub dddd{q(BBBBdddd)}
     }
    if (1)
     {package CCCC;

      sub aaaa{q(CCCCaaaa)}
      sub dddd{q(CCCCdddd)}
      sub eeee{q(CCCCeeee)}
     }

    𝘀𝗲𝘁𝗣𝗮𝗰𝗸𝗮𝗴𝗲𝗦𝗲𝗮𝗿𝗰𝗵𝗢𝗿𝗱𝗲𝗿(__PACKAGE__, qw(CCCC BBBB AAAA));

    ok &aaaa eq q(CCCCaaaa);
    ok &bbbb eq q(BBBBbbbb);
    ok &cccc eq q(AAAAcccc);

    ok &aaaa eq q(CCCCaaaa);
    ok &bbbb eq q(BBBBbbbb);
    ok &cccc eq q(AAAAcccc);

    ok &dddd eq q(CCCCdddd);
    ok &eeee eq q(CCCCeeee);

    𝘀𝗲𝘁𝗣𝗮𝗰𝗸𝗮𝗴𝗲𝗦𝗲𝗮𝗿𝗰𝗵𝗢𝗿𝗱𝗲𝗿(__PACKAGE__, qw(AAAA BBBB CCCC));

    ok &aaaa eq q(AAAAaaaa);
    ok &bbbb eq q(AAAAbbbb);
    ok &cccc eq q(AAAAcccc);

    ok &aaaa eq q(AAAAaaaa);
    ok &bbbb eq q(AAAAbbbb);
    ok &cccc eq q(AAAAcccc);

    ok &dddd eq q(BBBBdddd);
    ok &eeee eq q(CCCCeeee);
   }

isSubInPackage($$)

Test whether the specified $package contains the subroutine <$sub>.

     Parameter  Description
  1  $package   Package name
  2  $sub       Subroutine name

Example:

  if (1)
   {sub AAAA::Call {q(AAAA)}

    sub BBBB::Call {q(BBBB)}
    sub BBBB::call {q(bbbb)}

    if (1)
     {package BBBB;
      use Test::More;
      *ok = *Test::More::ok;
      *𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲 = *Data::Table::Text::𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲;
      ok  𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲(q(AAAA), q(Call));
      ok !𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲(q(AAAA), q(call));
      ok  𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲(q(BBBB), q(Call));
      ok  𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲(q(BBBB), q(call));
      ok Call eq q(BBBB);
      ok call eq q(bbbb);
      &Data::Table::Text::overrideMethods(qw(AAAA BBBB Call call));
      *𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲 = *Data::Table::Text::𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲;
      ok  𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲(q(AAAA), q(Call));
      ok  𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲(q(AAAA), q(call));
      ok  𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲(q(BBBB), q(Call));
      ok  𝗶𝘀𝗦𝘂𝗯𝗜𝗻𝗣𝗮𝗰𝗸𝗮𝗴𝗲(q(BBBB), q(call));
      ok Call eq q(AAAA);
      ok call eq q(bbbb);
      package AAAA;
      use Test::More;
      *ok = *Test::More::ok;
      ok  Call eq q(AAAA);
      ok &call eq q(bbbb);
     }
   }

overrideMethods($$@)

For each method, if it exists in package $from then export it to package $to replacing any existing method in $to, otherwise export the method from package $to to package $from in order to merge the behavior of the $from and $to packages with respect to the named methods with duplicates resolved if favour of package $from.

     Parameter  Description
  1  $from      Name of package from which to import methods
  2  $to        Package into which to import the methods
  3  @methods   List of methods to try importing.

Example:

  if (1)
   {sub AAAA::Call {q(AAAA)}

    sub BBBB::Call {q(BBBB)}
    sub BBBB::call {q(bbbb)}

    if (1)
     {package BBBB;
      use Test::More;
      *ok = *Test::More::ok;
      *isSubInPackage = *Data::Table::Text::isSubInPackage;
      ok  isSubInPackage(q(AAAA), q(Call));
      ok !isSubInPackage(q(AAAA), q(call));
      ok  isSubInPackage(q(BBBB), q(Call));
      ok  isSubInPackage(q(BBBB), q(call));
      ok Call eq q(BBBB);
      ok call eq q(bbbb);
      &Data::Table::Text::𝗼𝘃𝗲𝗿𝗿𝗶𝗱𝗲𝗠𝗲𝘁𝗵𝗼𝗱𝘀(qw(AAAA BBBB Call call));
      *isSubInPackage = *Data::Table::Text::isSubInPackage;
      ok  isSubInPackage(q(AAAA), q(Call));
      ok  isSubInPackage(q(AAAA), q(call));
      ok  isSubInPackage(q(BBBB), q(Call));
      ok  isSubInPackage(q(BBBB), q(call));
      ok Call eq q(AAAA);
      ok call eq q(bbbb);
      package AAAA;
      use Test::More;
      *ok = *Test::More::ok;
      ok  Call eq q(AAAA);
      ok &call eq q(bbbb);
     }
   }

This is a static method and so should be invoked as:

  Data::Table::Text::overrideMethods

overrideAndReabsorbMethods(@)

Override methods down the list of @packages then reabsorb any unused methods back up the list of packages so that all the packages have the same methods as the last package with methods from packages mentioned earlier overriding methods from packages mentioned later. The methods to override and reabsorb are listed by the sub overridableMethods in the last package in the packages list. Confess to any errors.

     Parameter  Description
  1  @packages  List of packages

Example:

    ok 𝗼𝘃𝗲𝗿𝗿𝗶𝗱𝗲𝗔𝗻𝗱𝗥𝗲𝗮𝗯𝘀𝗼𝗿𝗯𝗠𝗲𝘁𝗵𝗼𝗱𝘀(qw(main Edit::Xml Data::Edit::Xml));

This is a static method and so should be invoked as:

  Data::Table::Text::overrideAndReabsorbMethods

assertPackageRefs($@)

Confirm that the specified references are to the specified package

     Parameter  Description
  1  $package   Package
  2  @refs      References

Example:

  if (1) {
    eval q{𝗮𝘀𝘀𝗲𝗿𝘁𝗣𝗮𝗰𝗸𝗮𝗴𝗲𝗥𝗲𝗳𝘀(q(bbb), bless {}, q(aaa))};
    ok $@ =~ m(\AWanted reference to bbb, but got aaa);
   }

assertRef(@)

Confirm that the specified references are to the package into which this routine has been exported.

     Parameter  Description
  1  @refs      References

Example:

  if (1) {
    eval q{𝗮𝘀𝘀𝗲𝗿𝘁𝗥𝗲𝗳(bless {}, q(aaa))};
    ok $@ =~ m(\AWanted reference to Data::Table::Text, but got aaa);
   }

arrayToHash(@)

Create a hash from an array

     Parameter  Description
  1  @array     Array

Example:

  is_deeply 𝗮𝗿𝗿𝗮𝘆𝗧𝗼𝗛𝗮𝘀𝗵(qw(a b c)), {a=>1, b=>1, c=>1};

flattenArrayAndHashValues(@)

Flatten an array of scalars, array and hash references to make an array of scalars by flattening the array references and hash values.

     Parameter  Description
  1  @array     Array to flatten

Example:

  is_deeply [1..5], [𝗳𝗹𝗮𝘁𝘁𝗲𝗻𝗔𝗿𝗿𝗮𝘆𝗔𝗻𝗱𝗛𝗮𝘀𝗵𝗩𝗮𝗹𝘂𝗲𝘀([1], [[2]], {a=>3, b=>[4, [5]]})], 'ggg';

Strings

Actions on strings.

indentString($$)

Indent lines contained in a string or formatted table by the specified string.

     Parameter  Description
  1  $string    The string of lines to indent
  2  $indent    The indenting string

Example:

  if (1) {
    my $t = [qw(aa bb cc)];
    my $d = [[qw(A B C)], [qw(AA BB CC)], [qw(AAA BBB CCC)],  [qw(1 22 333)]];
    my $s = 𝗶𝗻𝗱𝗲𝗻𝘁𝗦𝘁𝗿𝗶𝗻𝗴(formatTable($d), '  ')."
";

    ok $s eq <<END;
    1  A    B    C
    2  AA   BB   CC
    3  AAA  BBB  CCC
    4    1   22  333
  END
   }

replaceStringWithString($$$)

Replace all instances in $string of $source with $target

     Parameter  Description
  1  $string    String in which to replace substrings
  2  $source    The string to be replaced
  3  $target    The replacement string

Example:

  ok 𝗿𝗲𝗽𝗹𝗮𝗰𝗲𝗦𝘁𝗿𝗶𝗻𝗴𝗪𝗶𝘁𝗵𝗦𝘁𝗿𝗶𝗻𝗴(q(abababZ), q(ab), q(c)) eq q(cccZ), 'eee';

formatString($$)

Format the specified $string so it can be displayed in $width columns.

     Parameter  Description
  1  $string    The string of text to format
  2  $width     The formatted width.

Example:

  ok 𝗳𝗼𝗿𝗺𝗮𝘁𝗦𝘁𝗿𝗶𝗻𝗴(<<END, 16) eq  <<END, 'fff';
  Now is the time for all
  good men to come to the rescue
  of the ailing B<party>.
  END

isBlank($)

Test whether a string is blank.

     Parameter  Description
  1  $string    String

Example:

  ok 𝗶𝘀𝗕𝗹𝗮𝗻𝗸("");

  ok 𝗶𝘀𝗕𝗹𝗮𝗻𝗸("
 ");

trim($)

Remove any white space from the front and end of a string.

     Parameter  Description
  1  $string    String

Example:

  ok 𝘁𝗿𝗶𝗺(" a b ") eq join ' ', qw(a b);

pad($$$)

Pad the specified $string to a multiple of the specified $length with blanks or the specified padding character to a multiple of a specified length.

     Parameter  Description
  1  $string    String
  2  $length    Tab width
  3  $padding   Padding string

Example:

  ok  𝗽𝗮𝗱('abc  ', 2).'='       eq "abc =";

  ok  𝗽𝗮𝗱('abc  ', 3).'='       eq "abc=";

  ok  𝗽𝗮𝗱('abc  ', 4, q(.)).'=' eq "abc.=";

firstNChars($$)

First N characters of a string.

     Parameter  Description
  1  $string    String
  2  $length    Length

Example:

  ok 𝗳𝗶𝗿𝘀𝘁𝗡𝗖𝗵𝗮𝗿𝘀(q(abc), 2) eq q(ab);

  ok 𝗳𝗶𝗿𝘀𝘁𝗡𝗖𝗵𝗮𝗿𝘀(q(abc), 4) eq q(abc);

nws($$)

Normalize white space in a string to make comparisons easier. Leading and trailing white space is removed; blocks of white space in the interior are reduced to a single space. In effect: this puts everything on one long line with never more than one space at a time. Optionally a maximum length is applied to the normalized string.

     Parameter  Description
  1  $string    String to normalize
  2  $length    Maximum length of result

Example:

  ok 𝗻𝘄𝘀(qq(a  b    c)) eq q(a b c);

deduplicateSequentialWordsInString($)

Remove sequentially duplicate words in a string

     Parameter  Description
  1  $s         String to deduplicate

Example:

  if (1) {
    ok 𝗱𝗲𝗱𝘂𝗽𝗹𝗶𝗰𝗮𝘁𝗲𝗦𝗲𝗾𝘂𝗲𝗻𝘁𝗶𝗮𝗹𝗪𝗼𝗿𝗱𝘀𝗜𝗻𝗦𝘁𝗿𝗶𝗻𝗴(<<END) eq qq(\(aa \[bb \-cc dd ee
);
  (aa [bb bb -cc cc dd dd dd dd ee ee ee ee
  END
   }

detagString($)

Remove html or xml tags from a string

     Parameter  Description
  1  $string    String to detag

Example:

  ok 𝗱𝗲𝘁𝗮𝗴𝗦𝘁𝗿𝗶𝗻𝗴(q(<a><a href="aaaa">a </a><a/>b </a>c)) eq q(a b c), 'hhh';

parseIntoWordsAndStrings($$)

Parse a $string into words and quoted strings with an optional $limit on the number of words and strings to parse out

     Parameter  Description
  1  $string    String
  2  $limit     Optional limit

Example:

  if (1)
   {is_deeply
     [𝗽𝗮𝗿𝘀𝗲𝗜𝗻𝘁𝗼𝗪𝗼𝗿𝗱𝘀𝗔𝗻𝗱𝗦𝘁𝗿𝗶𝗻𝗴𝘀
       (q( aa12! a"b "aa !! ++ bb" '  ', '"', "'", ' '. "" ''.))
     ],
     ["aa12!",  "a\"b", "aa !! ++ bb", "  ", ",", "\"",
      ",",  "'",  ",",  " ",  ".",  "",  ""
     ];
   }

stringsAreNotEqual($$)

Return the common start followed by the two non equal tails of two non equal strings or an empty list if the strings are equal.

     Parameter  Description
  1  $a         First string
  2  $b         Second string

Example:

  if (1) {
    ok        !𝘀𝘁𝗿𝗶𝗻𝗴𝘀𝗔𝗿𝗲𝗡𝗼𝘁𝗘𝗾𝘂𝗮𝗹(q(abc), q(abc));
    ok         𝘀𝘁𝗿𝗶𝗻𝗴𝘀𝗔𝗿𝗲𝗡𝗼𝘁𝗘𝗾𝘂𝗮𝗹(q(abc), q(abd));
    is_deeply [𝘀𝘁𝗿𝗶𝗻𝗴𝘀𝗔𝗿𝗲𝗡𝗼𝘁𝗘𝗾𝘂𝗮𝗹(q(abc), q(abd))], [qw(ab c d)];
    is_deeply [𝘀𝘁𝗿𝗶𝗻𝗴𝘀𝗔𝗿𝗲𝗡𝗼𝘁𝗘𝗾𝘂𝗮𝗹(q(ab),  q(abd))], [q(ab), '', q(d)];
   }

printQw(@)

Print an array of words in qw() format.

     Parameter  Description
  1  @words     Array of words

Example:

  ok 𝗽𝗿𝗶𝗻𝘁𝗤𝘄(qw(a b c)) eq q(qw(a b c));

numberOfLinesInString($)

The number of lines in a string.

     Parameter  Description
  1  $string    String

Example:

    ok 𝗻𝘂𝗺𝗯𝗲𝗿𝗢𝗳𝗟𝗶𝗻𝗲𝘀𝗜𝗻𝗦𝘁𝗿𝗶𝗻𝗴("a
b
") == 2;

javaPackage($)

Extract the package name from a java string or file.

     Parameter  Description
  1  $java      Java file if it exists else the string of java

Example:

    overWriteFile($f, <<END);
  // Test
  package com.xyz;
  END

    ok 𝗷𝗮𝘃𝗮𝗣𝗮𝗰𝗸𝗮𝗴𝗲($f)           eq "com.xyz";

javaPackageAsFileName($)

Extract the package name from a java string or file and convert it to a file name.

     Parameter  Description
  1  $java      Java file if it exists else the string of java

Example:

    overWriteFile($f, <<END);
  // Test
  package com.xyz;
  END

    ok 𝗷𝗮𝘃𝗮𝗣𝗮𝗰𝗸𝗮𝗴𝗲𝗔𝘀𝗙𝗶𝗹𝗲𝗡𝗮𝗺𝗲($f) eq "com/xyz";

perlPackage($)

Extract the package name from a perl string or file.

     Parameter  Description
  1  $perl      Perl file if it exists else the string of perl

Example:

    overWriteFile($f, <<END);
  package a::b;
  END

    ok 𝗽𝗲𝗿𝗹𝗣𝗮𝗰𝗸𝗮𝗴𝗲($f)           eq "a::b";

javaScriptExports($)

Extract the Javascript functions marked for export in a file or string. Functions are marked for export by placing function in column 1 followed by //E on the same line. The end of the exported function is located by }

     Parameter      Description
  1  $fileOrString  File or string

Example:

  if (1) {
    ok 𝗷𝗮𝘃𝗮𝗦𝗰𝗿𝗶𝗽𝘁𝗘𝘅𝗽𝗼𝗿𝘁𝘀(<<END) eq <<END;
  function aaa()            //E
   {console.log('aaa');
   }

chooseStringAtRandom(@)

Choose a string at random from the list of @strings supplied.

     Parameter  Description
  1  @strings   Strings to chose from

Example:

  ok q(a) eq 𝗰𝗵𝗼𝗼𝘀𝗲𝗦𝘁𝗿𝗶𝗻𝗴𝗔𝘁𝗥𝗮𝗻𝗱𝗼𝗺(qw(a a a a));

Unicode

Translate ascii alphanumerics in strings to various Unicode blocks.

boldString($)

Convert alphanumerics in a string to bold.

     Parameter  Description
  1  $string    String to convert

Example:

  ok 𝗯𝗼𝗹𝗱𝗦𝘁𝗿𝗶𝗻𝗴(q(zZ)) eq q(𝘇𝗭);

boldStringUndo($)

Undo alphanumerics in a string to bold.

     Parameter  Description
  1  $string    String to convert

Example:

  if (1)
   {my $n = 1234567890;
    ok 𝗯𝗼𝗹𝗱𝗦𝘁𝗿𝗶𝗻𝗴𝗨𝗻𝗱𝗼            (boldString($n))             == $n;
    ok enclosedStringUndo        (enclosedString($n))         == $n;
    ok enclosedReversedStringUndo(enclosedReversedString($n)) == $n;
    ok superScriptStringUndo     (superScriptString($n))      == $n;
    ok subScriptStringUndo       (subScriptString($n))        == $n;
   }

enclosedString($)

Convert alphanumerics in a string to enclosed alphanumerics.

     Parameter  Description
  1  $string    String to convert

Example:

  ok 𝗲𝗻𝗰𝗹𝗼𝘀𝗲𝗱𝗦𝘁𝗿𝗶𝗻𝗴(q(hello world 1234)) eq q(ⓗⓔⓛⓛⓞ ⓦⓞⓡⓛⓓ ①②③④);

enclosedStringUndo($)

Undo alphanumerics in a string to enclosed alphanumerics.

     Parameter  Description
  1  $string    String to convert

Example:

  if (1)
   {my $n = 1234567890;
    ok boldStringUndo            (boldString($n))             == $n;
    ok 𝗲𝗻𝗰𝗹𝗼𝘀𝗲𝗱𝗦𝘁𝗿𝗶𝗻𝗴𝗨𝗻𝗱𝗼        (enclosedString($n))         == $n;
    ok enclosedReversedStringUndo(enclosedReversedString($n)) == $n;
    ok superScriptStringUndo     (superScriptString($n))      == $n;
    ok subScriptStringUndo       (subScriptString($n))        == $n;
   }

enclosedReversedString($)

Convert alphanumerics in a string to enclosed reversed alphanumerics.

     Parameter  Description
  1  $string    String to convert

Example:

  ok 𝗲𝗻𝗰𝗹𝗼𝘀𝗲𝗱𝗥𝗲𝘃𝗲𝗿𝘀𝗲𝗱𝗦𝘁𝗿𝗶𝗻𝗴(q(hello world 1234)) eq q(🅗🅔🅛🅛🅞 🅦🅞🅡🅛🅓 ➊➋➌➍);

enclosedReversedStringUndo($)

Undo alphanumerics in a string to enclosed reversed alphanumerics.

     Parameter  Description
  1  $string    String to convert

Example:

  if (1)
   {my $n = 1234567890;
    ok boldStringUndo            (boldString($n))             == $n;
    ok enclosedStringUndo        (enclosedString($n))         == $n;
    ok 𝗲𝗻𝗰𝗹𝗼𝘀𝗲𝗱𝗥𝗲𝘃𝗲𝗿𝘀𝗲𝗱𝗦𝘁𝗿𝗶𝗻𝗴𝗨𝗻𝗱𝗼(enclosedReversedString($n)) == $n;
    ok superScriptStringUndo     (superScriptString($n))      == $n;
    ok subScriptStringUndo       (subScriptString($n))        == $n;
   }

superScriptString($)

Convert alphanumerics in a string to super scripts

     Parameter  Description
  1  $string    String to convert

Example:

  ok 𝘀𝘂𝗽𝗲𝗿𝗦𝗰𝗿𝗶𝗽𝘁𝗦𝘁𝗿𝗶𝗻𝗴(1234567890) eq q(¹²³⁴⁵⁶⁷⁸⁹⁰);

superScriptStringUndo($)

Undo alphanumerics in a string to super scripts

     Parameter  Description
  1  $string    String to convert

Example:

  if (1)
   {my $n = 1234567890;
    ok boldStringUndo            (boldString($n))             == $n;
    ok enclosedStringUndo        (enclosedString($n))         == $n;
    ok enclosedReversedStringUndo(enclosedReversedString($n)) == $n;
    ok 𝘀𝘂𝗽𝗲𝗿𝗦𝗰𝗿𝗶𝗽𝘁𝗦𝘁𝗿𝗶𝗻𝗴𝗨𝗻𝗱𝗼     (superScriptString($n))      == $n;
    ok subScriptStringUndo       (subScriptString($n))        == $n;
   }

subScriptString($)

Convert alphanumerics in a string to sub scripts

     Parameter  Description
  1  $string    String to convert

Example:

  ok 𝘀𝘂𝗯𝗦𝗰𝗿𝗶𝗽𝘁𝗦𝘁𝗿𝗶𝗻𝗴(1234567890)   eq q(₁₂₃₄₅₆₇₈₉₀);

subScriptStringUndo($)

Undo alphanumerics in a string to sub scripts

     Parameter  Description
  1  $string    String to convert

Example:

  if (1)
   {my $n = 1234567890;
    ok boldStringUndo            (boldString($n))             == $n;
    ok enclosedStringUndo        (enclosedString($n))         == $n;
    ok enclosedReversedStringUndo(enclosedReversedString($n)) == $n;
    ok superScriptStringUndo     (superScriptString($n))      == $n;
    ok 𝘀𝘂𝗯𝗦𝗰𝗿𝗶𝗽𝘁𝗦𝘁𝗿𝗶𝗻𝗴𝗨𝗻𝗱𝗼       (subScriptString($n))        == $n;
   }

isFileUtf8($)

Return the file name quoted if its contents are in utf8 else return undef

     Parameter  Description
  1  $file      File to test

Example:

  if (0) {
    my $f = writeFile(undef, "aaa");
    ok 𝗶𝘀𝗙𝗶𝗹𝗲𝗨𝘁𝗳𝟴 $f;
   }

Unix domain communications

Send messages between processes via a unix domain socket.

newUdsrServer(@)

Create a communications server - a means to communicate between processes on the same machine via Udsr::read and Udsr::write.

     Parameter  Description
  1  @parms     Attributes per L<Udsr Definition|/Udsr Definition>

Example:

  if (1) {
    my $N = 20;
    my $s = 𝗻𝗲𝘄𝗨𝗱𝘀𝗿𝗦𝗲𝗿𝘃𝗲𝗿(serverAction=>sub
     {my ($u) = @_;
      my $r = $u->read;
      $u->write(qq(Hello from server $r));
     });

    my $p = newProcessStarter(min(100, $N));                                      # Run some clients
    for my $i(1..$N)
     {$p->start(sub
       {my $count = 0;
        for my $j(1..$N)
         {my $c = newUdsrClient;
          my $m = qq(Hello from client $i x $j);
          $c->write($m);
          my $r = $c->read;
          ++$count if $r eq qq(Hello from server $m);
         }
        [$count]
       });
     }

    my $count;
    for my $r($p->finish)                                                         # Consolidate results
     {my ($c) = @$r;
      $count += $c;
     }

    ok $count == $N*$N;                                                           # Check results and kill
    $s->kill;
   }

newUdsrClient(@)

Create a new communications client - a means to communicate between processes on the same machine via Udsr::read and Udsr::write.

     Parameter  Description
  1  @parms     Attributes per L<Udsr Definition|/Udsr Definition>

Example:

  if (1) {
    my $N = 20;
    my $s = newUdsrServer(serverAction=>sub
     {my ($u) = @_;
      my $r = $u->read;
      $u->write(qq(Hello from server $r));
     });

    my $p = newProcessStarter(min(100, $N));                                      # Run some clients
    for my $i(1..$N)
     {$p->start(sub
       {my $count = 0;
        for my $j(1..$N)
         {my $c = 𝗻𝗲𝘄𝗨𝗱𝘀𝗿𝗖𝗹𝗶𝗲𝗻𝘁;
          my $m = qq(Hello from client $i x $j);
          $c->write($m);
          my $r = $c->read;
          ++$count if $r eq qq(Hello from server $m);
         }
        [$count]
       });
     }

    my $count;
    for my $r($p->finish)                                                         # Consolidate results
     {my ($c) = @$r;
      $count += $c;
     }

    ok $count == $N*$N;                                                           # Check results and kill
    $s->kill;
   }

Udsr::write($$)

Write a communications message to the newUdsrServer or the newUdsrClient.

     Parameter  Description
  1  $u         Communicator
  2  $msg       Message

Example:

  if (1) {
    my $N = 20;
    my $s = newUdsrServer(serverAction=>sub
     {my ($u) = @_;
      my $r = $u->read;
      $u->write(qq(Hello from server $r));
     });

    my $p = newProcessStarter(min(100, $N));                                      # Run some clients
    for my $i(1..$N)
     {$p->start(sub
       {my $count = 0;
        for my $j(1..$N)
         {my $c = newUdsrClient;
          my $m = qq(Hello from client $i x $j);
          $c->write($m);
          my $r = $c->read;
          ++$count if $r eq qq(Hello from server $m);
         }
        [$count]
       });
     }

    my $count;
    for my $r($p->finish)                                                         # Consolidate results
     {my ($c) = @$r;
      $count += $c;
     }

    ok $count == $N*$N;                                                           # Check results and kill
    $s->kill;
   }

Udsr::read($)

Read a message from the newUdsrServer or the newUdsrClient.

     Parameter  Description
  1  $u         Communicator

Example:

  if (1) {
    my $N = 20;
    my $s = newUdsrServer(serverAction=>sub
     {my ($u) = @_;
      my $r = $u->read;
      $u->write(qq(Hello from server $r));
     });

    my $p = newProcessStarter(min(100, $N));                                      # Run some clients
    for my $i(1..$N)
     {$p->start(sub
       {my $count = 0;
        for my $j(1..$N)
         {my $c = newUdsrClient;
          my $m = qq(Hello from client $i x $j);
          $c->write($m);
          my $r = $c->read;
          ++$count if $r eq qq(Hello from server $m);
         }
        [$count]
       });
     }

    my $count;
    for my $r($p->finish)                                                         # Consolidate results
     {my ($c) = @$r;
      $count += $c;
     }

    ok $count == $N*$N;                                                           # Check results and kill
    $s->kill;
   }

Udsr::kill($)

Kill a communications server.

     Parameter  Description
  1  $u         Communicator

Example:

  if (1) {
    my $N = 20;
    my $s = newUdsrServer(serverAction=>sub
     {my ($u) = @_;
      my $r = $u->read;
      $u->write(qq(Hello from server $r));
     });

    my $p = newProcessStarter(min(100, $N));                                      # Run some clients
    for my $i(1..$N)
     {$p->start(sub
       {my $count = 0;
        for my $j(1..$N)
         {my $c = newUdsrClient;
          my $m = qq(Hello from client $i x $j);
          $c->write($m);
          my $r = $c->read;
          ++$count if $r eq qq(Hello from server $m);
         }
        [$count]
       });
     }

    my $count;
    for my $r($p->finish)                                                         # Consolidate results
     {my ($c) = @$r;
      $count += $c;
     }

    ok $count == $N*$N;                                                           # Check results and kill
    $s->kill;
   }

Udsr::webUser($$$)

Create a systemd installed server that processes http requests using a specified userid. The systemd and CGI files plus an installation script are written to the specified folder after it has been cleared and installed on the server unless $noInstall is true. The serverAction string contains the code to be executed by the server: the contained sub genResponse($hash) will be called with a hash of the CGI variables, it should return the response to be sent back to the client. Returns the installation script file name.

     Parameter   Description
  1  $u          Communicator
  2  $folder     Folder to contain server code
  3  $noInstall  Do not install if true optionally

Example:

  if (0)
   {my $fold = fpd(qw(/home phil zzz));                                           # Folder to contain server code
    my $name = q(test);                                                           # Service
    my $user = q(phil);                                                           # User

    my $udsr = newUdsr                                                            # Create a Udsr parameter list
     (serviceName => $name,
      serviceUser => $user,
      socketPath  => qq(/home/phil/$name.socket),
      serverAction=> <<'END'
  my $user = userId;
  my $list = qx(ls -l);
  my $dtts = dateTimeStamp;
  return <<END2;
  Content-type: text/html

  <h1>Hello World to you $user on $dtts!</h1>

  <pre>
  $list
  </pre>
  END2
  END
     );

    𝗨𝗱𝘀𝗿::𝘄𝗲𝗯𝗨𝘀𝗲𝗿($udsr, $fold);                                                  # Create and install web service interface
    my $ip = awsIp;
    say STDERR qx(curl http://$ip/cgi-bin/$name/client.pl);                       # Enable port 80 on AWS first)
   }

Cloud Cover

Useful for operating across the cloud.

makeDieConfess()

Force die to confess where the death occurred

Example:

    𝗺𝗮𝗸𝗲𝗗𝗶𝗲𝗖𝗼𝗻𝗳𝗲𝘀𝘀

awsMetaData($)

Get an item of meta data for the AWS server we are currently running on if we are running on an AWS server else return a blank string.

     Parameter  Description
  1  $item      Meta data field

Example:

    ok 𝗮𝘄𝘀𝗠𝗲𝘁𝗮𝗗𝗮𝘁𝗮(q(instance-id))    eq q(i-06a4b221b30bf7a37);

awsCurrentIp()

Get the ip address of the AWS server we are currently running on if we are running on an AWS server else return a blank string.

Example:

  if (0) {
    𝗮𝘄𝘀𝗖𝘂𝗿𝗿𝗲𝗻𝘁𝗜𝗽;
    confirmHasCommandLineCommand(q(find));
   }

    ok 𝗮𝘄𝘀𝗖𝘂𝗿𝗿𝗲𝗻𝘁𝗜𝗽                   eq q(31.41.59.26);

awsCurrentInstanceId()

Get the server instance id of the AWS server we are currently running on if we are running on an AWS server else return a blank string.

Example:

    ok 𝗮𝘄𝘀𝗖𝘂𝗿𝗿𝗲𝗻𝘁𝗜𝗻𝘀𝘁𝗮𝗻𝗰𝗲𝗜𝗱           eq q(i-06a4b221b30bf7a37);

awsCurrentRegion()

Get the server region of the AWS server we are currently running on if we are running on an AWS server else return a blank string.

Example:

    ok 𝗮𝘄𝘀𝗖𝘂𝗿𝗿𝗲𝗻𝘁𝗥𝗲𝗴𝗶𝗼𝗻               eq q(us-east-2);

awsCurrentInstanceType()

Get the instance type of the AWS server if we are running on an AWS server else return a blank string.

Example:

    ok 𝗮𝘄𝘀𝗖𝘂𝗿𝗿𝗲𝗻𝘁𝗜𝗻𝘀𝘁𝗮𝗻𝗰𝗲𝗧𝘆𝗽𝗲         eq q(r4.4xlarge);

awsCurrentPublicIp4()

Get the instance type of the AWS server if we are running on an AWS server else return a blank string.

Example:

    ok 𝗮𝘄𝘀𝗖𝘂𝗿𝗿𝗲𝗻𝘁𝗣𝘂𝗯𝗹𝗶𝗰𝗜𝗽𝟰            eq q(18.19.20.21);

awsEc2DescribeInstances($%)

Describe the AWS instances running in a $region.

     Parameter  Description
  1  $region    Region name
  2  %options   Options

Example:

  if (0) {
    my $r = 𝗮𝘄𝘀𝗘𝗰𝟮𝗗𝗲𝘀𝗰𝗿𝗶𝗯𝗲𝗜𝗻𝘀𝘁𝗮𝗻𝗰𝗲𝘀(q(us-east-2), profile=>q(fmc));
    my %i = awsEc2DescribeInstancesGetIPAddresses($r);
    is_deeply \%i, { "i-068a7176ba9140057" => { "18.221.162.39" => 1 } };
   }

awsEc2DescribeInstancesGetIPAddresses($)

Get the IP addresses in the data returned by describe instances

     Parameter  Description
  1  $d         Description

Example:

  if (0) {
    my $r = awsEc2DescribeInstances(q(us-east-2), profile=>q(fmc));
    my %i = 𝗮𝘄𝘀𝗘𝗰𝟮𝗗𝗲𝘀𝗰𝗿𝗶𝗯𝗲𝗜𝗻𝘀𝘁𝗮𝗻𝗰𝗲𝘀𝗚𝗲𝘁𝗜𝗣𝗔𝗱𝗱𝗿𝗲𝘀𝘀𝗲𝘀($r);
    is_deeply \%i, { "i-068a7176ba9140057" => { "18.221.162.39" => 1 } };
   }

awsEc2CreateImage($%)

Create an image snap shot with the specified $name of the AWS server we are currently running on if we are running on an AWS server else return false. It is safe to shut down the instance immediately after initiating the snap shot - the snap continues even though the instance has terminated.

     Parameter  Description
  1  $name      Image name
  2  $profile   Optional aws cli profile

Example:

       𝗮𝘄𝘀𝗘𝗰𝟮𝗖𝗿𝗲𝗮𝘁𝗲𝗜𝗺𝗮𝗴𝗲(q(099 Gold));

confirmHasCommandLineCommand($)

Check that the specified b<$cmd> is present on the current system.

     Parameter  Description
  1  $cmd       Command to check for

Example:

  if (0) {
    awsCurrentIp;
    𝗰𝗼𝗻𝗳𝗶𝗿𝗺𝗛𝗮𝘀𝗖𝗼𝗺𝗺𝗮𝗻𝗱𝗟𝗶𝗻𝗲𝗖𝗼𝗺𝗺𝗮𝗻𝗱(q(find));
   }

numberOfCpus($)

Number of cpus scaled by an optional factor - but only if you have nproc. If you do not have nproc but do have a convenient way for determining the number of cpus on your system please let me know.

     Parameter  Description
  1  $scale     Scale factor

Example:

  ok 𝗻𝘂𝗺𝗯𝗲𝗿𝗢𝗳𝗖𝗽𝘂𝘀(8) >= 8, 'ddd';

ipAddressViaArp($)

Get the ip address of a server on the local network by hostname via arp

     Parameter  Description
  1  $hostName  Host name

Example:

    𝗶𝗽𝗔𝗱𝗱𝗿𝗲𝘀𝘀𝗩𝗶𝗮𝗔𝗿𝗽(q(secarias));

parseS3BucketAndFolderName($)

Parse an S3 bucket/folder name into a bucket and a folder name removing any initial s3://.

     Parameter  Description
  1  $name      Bucket/folder name

Example:

  if (1)
   {is_deeply [𝗽𝗮𝗿𝘀𝗲𝗦𝟯𝗕𝘂𝗰𝗸𝗲𝘁𝗔𝗻𝗱𝗙𝗼𝗹𝗱𝗲𝗿𝗡𝗮𝗺𝗲(q(s3://bbbb/ffff/dddd/))], [qw(bbbb ffff/dddd/)], q(iii);
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗦𝟯𝗕𝘂𝗰𝗸𝗲𝘁𝗔𝗻𝗱𝗙𝗼𝗹𝗱𝗲𝗿𝗡𝗮𝗺𝗲(q(s3://bbbb/))],           [qw(bbbb), q()];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗦𝟯𝗕𝘂𝗰𝗸𝗲𝘁𝗔𝗻𝗱𝗙𝗼𝗹𝗱𝗲𝗿𝗡𝗮𝗺𝗲(q(     bbbb/))],           [qw(bbbb), q()];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗦𝟯𝗕𝘂𝗰𝗸𝗲𝘁𝗔𝗻𝗱𝗙𝗼𝗹𝗱𝗲𝗿𝗡𝗮𝗺𝗲(q(     bbbb))],            [qw(bbbb), q()];
   }

saveCodeToS3($$$$$)

Save source code every $saveCodeEvery seconds by zipping folder $folder to zip file $zipFileName then saving this zip file in the specified S3 $bucket using any additional S3 parameters in $S3Parms.

     Parameter       Description
  1  $saveCodeEvery  Save every seconds
  2  $folder         Folder to save
  3  $zipFileName    Zip file name
  4  $bucket         Bucket/key
  5  $S3Parms        Additional S3 parameters like profile or region as a string

Example:

    𝘀𝗮𝘃𝗲𝗖𝗼𝗱𝗲𝗧𝗼𝗦𝟯(1200, q(.), q(projectName), q(bucket/folder), q(--quiet));

addCertificate($)

Add a certificate to the current ssh session.

     Parameter  Description
  1  $file      File containing certificate

Example:

    𝗮𝗱𝗱𝗖𝗲𝗿𝘁𝗶𝗳𝗶𝗰𝗮𝘁𝗲(fpf(qw(.ssh cert)));

hostName()

The name of the host we are running on.

Example:

    𝗵𝗼𝘀𝘁𝗡𝗮𝗺𝗲;

userId($)

Get or confirm the userid we are currently running under.

     Parameter  Description
  1  $user      Userid to confirm

Example:

    𝘂𝘀𝗲𝗿𝗜𝗱;

awsTranslateText($$$$)

Translate $text from English to a specified $language using AWS Translate with the specified global $options and return the translated string. Translations are cached in the specified $cacheFolder for reuse were feasible.

     Parameter     Description
  1  $string       String to translate
  2  $language     Language code
  3  $cacheFolder  Cache folder
  4  $Options      Aws global options string

Example:

    ok 𝗮𝘄𝘀𝗧𝗿𝗮𝗻𝘀𝗹𝗮𝘁𝗲𝗧𝗲𝘅𝘁("Hello", "it", ".translations/") eq q(Ciao);

S3

Treat S3 as a file system

s3ListFilesAndSizes($%)

Return {file=>size} for all the files in a specified $folderOrFile on S3 using the specified %options if any.

     Parameter      Description
  1  $folderOrFile  Source on S3 - which will be truncated to a folder name
  2  %options       Options

Example:

  if (0) {
    my %options = (profile => q(fmc));

    say STDERR dump({𝘀𝟯𝗟𝗶𝘀𝘁𝗙𝗶𝗹𝗲𝘀𝗔𝗻𝗱𝗦𝗶𝘇𝗲𝘀(q(s3://salesforce.dita/originals4/images), %options)});

    is_deeply
     {𝘀𝟯𝗟𝗶𝘀𝘁𝗙𝗶𝗹𝗲𝘀𝗔𝗻𝗱𝗦𝗶𝘇𝗲𝘀(q(s3://salesforce.dita/originals4/images), %options)
     },
     {"s3://salesforce.dita/originals4/images/business_plan_sections.png" => [
                                                                             "originals4/images/business_plan_sections.png",
                                                                             112525,
                                                                             "2019-08-13",
                                                                             "20:01:10",
                                                                           ],
      "s3://salesforce.dita/originals4/images/non-referenced.png"         => [
                                                                             "originals4/images/non-referenced.png",
                                                                             19076,
                                                                             "2019-08-20",
                                                                             "01:25:04",
                                                                           ],
     };

    my $data = q(0123456789);
    my $file = q(s3://salesforce.dita/zzz/111.txt);

    if (1)
     {       s3WriteString($file, $data, %options);
      my $r = s3ReadString($file,        %options);
      ok $r eq $data;
     }

    if (1)
     {my @r = s3FileExists($file, %options);
      ok $r[0] eq "zzz/111.txt";
      ok $r[1] ==  10;
     }

    if (1)
     {my $d = $data x 2;
      my $f = writeFile(undef, $d);

      s3WriteFile($file, $f, %options);
      unlink $f;
      s3ReadFile ($file, $f, %options);
      ok readFile($f) eq $d;
      unlink $f;
     }
   }

s3FileExists($%)

Return (name, size, date, time) for a $file that exists on S3 else () using the specified %options if any.

     Parameter  Description
  1  $file      File on S3 - which will be truncated to a folder name
  2  %options   Options

Example:

  if (0) {
    my %options = (profile => q(fmc));

    say STDERR dump({s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)});

    is_deeply
     {s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)
     },
     {"s3://salesforce.dita/originals4/images/business_plan_sections.png" => [
                                                                             "originals4/images/business_plan_sections.png",
                                                                             112525,
                                                                             "2019-08-13",
                                                                             "20:01:10",
                                                                           ],
      "s3://salesforce.dita/originals4/images/non-referenced.png"         => [
                                                                             "originals4/images/non-referenced.png",
                                                                             19076,
                                                                             "2019-08-20",
                                                                             "01:25:04",
                                                                           ],
     };

    my $data = q(0123456789);
    my $file = q(s3://salesforce.dita/zzz/111.txt);

    if (1)
     {       s3WriteString($file, $data, %options);
      my $r = s3ReadString($file,        %options);
      ok $r eq $data;
     }

    if (1)
     {my @r = 𝘀𝟯𝗙𝗶𝗹𝗲𝗘𝘅𝗶𝘀𝘁𝘀($file, %options);
      ok $r[0] eq "zzz/111.txt";
      ok $r[1] ==  10;
     }

    if (1)
     {my $d = $data x 2;
      my $f = writeFile(undef, $d);

      s3WriteFile($file, $f, %options);
      unlink $f;
      s3ReadFile ($file, $f, %options);
      ok readFile($f) eq $d;
      unlink $f;
     }
   }

s3WriteFile($$%)

Write to a file $fileS3 on S3 the contents of a local file $fileLocal using the specified %options if any. $fileLocal will be removed if %options contains a key cleanUp with a true value.

     Parameter   Description
  1  $fileS3     File to write to on S3
  2  $fileLocal  String to write into file
  3  %options    Options

Example:

  if (0) {
    my %options = (profile => q(fmc));

    say STDERR dump({s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)});

    is_deeply
     {s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)
     },
     {"s3://salesforce.dita/originals4/images/business_plan_sections.png" => [
                                                                             "originals4/images/business_plan_sections.png",
                                                                             112525,
                                                                             "2019-08-13",
                                                                             "20:01:10",
                                                                           ],
      "s3://salesforce.dita/originals4/images/non-referenced.png"         => [
                                                                             "originals4/images/non-referenced.png",
                                                                             19076,
                                                                             "2019-08-20",
                                                                             "01:25:04",
                                                                           ],
     };

    my $data = q(0123456789);
    my $file = q(s3://salesforce.dita/zzz/111.txt);

    if (1)
     {       s3WriteString($file, $data, %options);
      my $r = s3ReadString($file,        %options);
      ok $r eq $data;
     }

    if (1)
     {my @r = s3FileExists($file, %options);
      ok $r[0] eq "zzz/111.txt";
      ok $r[1] ==  10;
     }

    if (1)
     {my $d = $data x 2;
      my $f = writeFile(undef, $d);

      𝘀𝟯𝗪𝗿𝗶𝘁𝗲𝗙𝗶𝗹𝗲($file, $f, %options);
      unlink $f;
      s3ReadFile ($file, $f, %options);
      ok readFile($f) eq $d;
      unlink $f;
     }
   }

s3WriteString($$%)

Write to a $file on S3 the contents of $string using the specified %options if any.

     Parameter  Description
  1  $file      File to write to on S3
  2  $string    String to write into file
  3  %options   Options

Example:

  if (0) {
    my %options = (profile => q(fmc));

    say STDERR dump({s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)});

    is_deeply
     {s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)
     },
     {"s3://salesforce.dita/originals4/images/business_plan_sections.png" => [
                                                                             "originals4/images/business_plan_sections.png",
                                                                             112525,
                                                                             "2019-08-13",
                                                                             "20:01:10",
                                                                           ],
      "s3://salesforce.dita/originals4/images/non-referenced.png"         => [
                                                                             "originals4/images/non-referenced.png",
                                                                             19076,
                                                                             "2019-08-20",
                                                                             "01:25:04",
                                                                           ],
     };

    my $data = q(0123456789);
    my $file = q(s3://salesforce.dita/zzz/111.txt);

    if (1)
     {       𝘀𝟯𝗪𝗿𝗶𝘁𝗲𝗦𝘁𝗿𝗶𝗻𝗴($file, $data, %options);
      my $r = s3ReadString($file,        %options);
      ok $r eq $data;
     }

    if (1)
     {my @r = s3FileExists($file, %options);
      ok $r[0] eq "zzz/111.txt";
      ok $r[1] ==  10;
     }

    if (1)
     {my $d = $data x 2;
      my $f = writeFile(undef, $d);

      s3WriteFile($file, $f, %options);
      unlink $f;
      s3ReadFile ($file, $f, %options);
      ok readFile($f) eq $d;
      unlink $f;
     }
   }

s3ReadFile($$%)

Read from a $file on S3 and write the contents to a local file $local using the specified %options if any. Any pre existing version of the local file $local will be deleted. Returns whether the local file exists after completion of the download.

     Parameter  Description
  1  $file      File to read from on S3
  2  $local     Local file to write to
  3  %options   Options

Example:

  if (0) {
    my %options = (profile => q(fmc));

    say STDERR dump({s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)});

    is_deeply
     {s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)
     },
     {"s3://salesforce.dita/originals4/images/business_plan_sections.png" => [
                                                                             "originals4/images/business_plan_sections.png",
                                                                             112525,
                                                                             "2019-08-13",
                                                                             "20:01:10",
                                                                           ],
      "s3://salesforce.dita/originals4/images/non-referenced.png"         => [
                                                                             "originals4/images/non-referenced.png",
                                                                             19076,
                                                                             "2019-08-20",
                                                                             "01:25:04",
                                                                           ],
     };

    my $data = q(0123456789);
    my $file = q(s3://salesforce.dita/zzz/111.txt);

    if (1)
     {       s3WriteString($file, $data, %options);
      my $r = s3ReadString($file,        %options);
      ok $r eq $data;
     }

    if (1)
     {my @r = s3FileExists($file, %options);
      ok $r[0] eq "zzz/111.txt";
      ok $r[1] ==  10;
     }

    if (1)
     {my $d = $data x 2;
      my $f = writeFile(undef, $d);

      s3WriteFile($file, $f, %options);
      unlink $f;
      𝘀𝟯𝗥𝗲𝗮𝗱𝗙𝗶𝗹𝗲 ($file, $f, %options);
      ok readFile($f) eq $d;
      unlink $f;
     }
   }

s3ReadString($%)

Read from a $file on S3 and return the contents as a string using specified %options if any. Any pre existing version of $local will be deleted. Returns whether the local file exists after completion of the download.

     Parameter  Description
  1  $file      File to read from on S3
  2  %options   Options

Example:

  if (0) {
    my %options = (profile => q(fmc));

    say STDERR dump({s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)});

    is_deeply
     {s3ListFilesAndSizes(q(s3://salesforce.dita/originals4/images), %options)
     },
     {"s3://salesforce.dita/originals4/images/business_plan_sections.png" => [
                                                                             "originals4/images/business_plan_sections.png",
                                                                             112525,
                                                                             "2019-08-13",
                                                                             "20:01:10",
                                                                           ],
      "s3://salesforce.dita/originals4/images/non-referenced.png"         => [
                                                                             "originals4/images/non-referenced.png",
                                                                             19076,
                                                                             "2019-08-20",
                                                                             "01:25:04",
                                                                           ],
     };

    my $data = q(0123456789);
    my $file = q(s3://salesforce.dita/zzz/111.txt);

    if (1)
     {       s3WriteString($file, $data, %options);
      my $r = 𝘀𝟯𝗥𝗲𝗮𝗱𝗦𝘁𝗿𝗶𝗻𝗴($file,        %options);
      ok $r eq $data;
     }

    if (1)
     {my @r = s3FileExists($file, %options);
      ok $r[0] eq "zzz/111.txt";
      ok $r[1] ==  10;
     }

    if (1)
     {my $d = $data x 2;
      my $f = writeFile(undef, $d);

      s3WriteFile($file, $f, %options);
      unlink $f;
      s3ReadFile ($file, $f, %options);
      ok readFile($f) eq $d;
      unlink $f;
     }
   }

GitHub

Simple interactions with GitHub - for more complex interactions please use GitHub::Crud.

downloadGitHubPublicRepo($$)

Get the contents of a public repo on GitHub and place them in a temporary folder whose name is returned to the caller or confess if no such repo exists.

     Parameter  Description
  1  $user      GitHub user
  2  $repo      GitHub repo

Example:

       𝗱𝗼𝘄𝗻𝗹𝗼𝗮𝗱𝗚𝗶𝘁𝗛𝘂𝗯𝗣𝘂𝗯𝗹𝗶𝗰𝗥𝗲𝗽𝗼(q(philiprbrenan), q(psr));

downloadGitHubPublicRepoFile($$$)

Get the contents of a $user $repo $file from a public repo on GitHub and return them as a string.

     Parameter  Description
  1  $user      GitHub user
  2  $repo      GitHub repository
  3  $file      File name in repository

Example:

  if (0) {
    ok &𝗱𝗼𝘄𝗻𝗹𝗼𝗮𝗱𝗚𝗶𝘁𝗛𝘂𝗯𝗣𝘂𝗯𝗹𝗶𝗰𝗥𝗲𝗽𝗼𝗙𝗶𝗹𝗲(qw(philiprbrenan pleaseChangeDita index.html));
   }

Processes

Start processes, wait for them to terminate and retrieve their results

startProcess(&\%$)

Start new processes while the number of child processes recorded in %$pids is less than the specified $maximum. Use waitForAllStartedProcessesToFinish to wait for all these processes to finish.

     Parameter  Description
  1  $sub       Sub to start
  2  $pids      Hash in which to record the process ids
  3  $maximum   Maximum number of processes to run at a time

Example:

  if (0) {
    my %pids;
    sub{𝘀𝘁𝗮𝗿𝘁𝗣𝗿𝗼𝗰𝗲𝘀𝘀 {} %pids, 1; ok 1 >= keys %pids}->() for 1..8;
    waitForAllStartedProcessesToFinish(%pids);
    ok !keys(%pids)
   }

waitForAllStartedProcessesToFinish(\%)

Wait until all the processes started by startProcess have finished.

     Parameter  Description
  1  $pids      Hash of started process ids

Example:

  if (0) {
    my %pids;
    sub{startProcess {} %pids, 1; ok 1 >= keys %pids}->() for 1..8;
    𝘄𝗮𝗶𝘁𝗙𝗼𝗿𝗔𝗹𝗹𝗦𝘁𝗮𝗿𝘁𝗲𝗱𝗣𝗿𝗼𝗰𝗲𝘀𝘀𝗲𝘀𝗧𝗼𝗙𝗶𝗻𝗶𝘀𝗵(%pids);
    ok !keys(%pids)
   }

newProcessStarter($%)

Create a new process starter with which to start parallel processes up to a specified $maximumNumberOfProcesses maximum number of parallel processes at a time, wait for all the started processes to finish and then optionally retrieve their saved results as an array from the folder named by $transferArea.

     Parameter                  Description
  1  $maximumNumberOfProcesses  Maximum number of processes to start
  2  %options                   Options

Example:

  if (1)
   {my $N = 100;
    my $l = q(logFile.txt);
    unlink $l;
    my $s = 𝗻𝗲𝘄𝗣𝗿𝗼𝗰𝗲𝘀𝘀𝗦𝘁𝗮𝗿𝘁𝗲𝗿(4);
       $s->processingTitle   = q(Test processes);
       $s->totalToBeStarted  = $N;
       $s->processingLogFile = $l;

    for my $i(1..$N)
     {Data::Table::Text::Starter::start($s, sub{$i*$i});
     }

    is_deeply
     [sort {$a <=> $b} Data::Table::Text::Starter::finish($s)],
     [map {$_**2} 1..$N];

    ok readFile($l) =~ m(Finished $N processes for: Test processes)s;
    clearFolder($s->transferArea, 1e3);
    unlink $l;
   }

Data::Table::Text::Starter::start($$)

Start a new process to run the specified $sub.

     Parameter  Description
  1  $starter   Starter
  2  $sub       Sub to be run.

Example:

  if (1)
   {my $N = 100;
    my $l = q(logFile.txt);
    unlink $l;
    my $s = newProcessStarter(4);
       $s->processingTitle   = q(Test processes);
       $s->totalToBeStarted  = $N;
       $s->processingLogFile = $l;

    for my $i(1..$N)
     {𝗗𝗮𝘁𝗮::𝗧𝗮𝗯𝗹𝗲::𝗧𝗲𝘅𝘁::𝗦𝘁𝗮𝗿𝘁𝗲𝗿::𝘀𝘁𝗮𝗿𝘁($s, sub{$i*$i});
     }

    is_deeply
     [sort {$a <=> $b} Data::Table::Text::Starter::finish($s)],
     [map {$_**2} 1..$N];

    ok readFile($l) =~ m(Finished $N processes for: Test processes)s;
    clearFolder($s->transferArea, 1e3);
    unlink $l;
   }

Data::Table::Text::Starter::finish($)

Wait for all started processes to finish and return their results as an array.

     Parameter  Description
  1  $starter   Starter

Example:

  if (1)
   {my $N = 100;
    my $l = q(logFile.txt);
    unlink $l;
    my $s = newProcessStarter(4);
       $s->processingTitle   = q(Test processes);
       $s->totalToBeStarted  = $N;
       $s->processingLogFile = $l;

    for my $i(1..$N)
     {Data::Table::Text::Starter::start($s, sub{$i*$i});
     }

    is_deeply
     [sort {$a <=> $b} 𝗗𝗮𝘁𝗮::𝗧𝗮𝗯𝗹𝗲::𝗧𝗲𝘅𝘁::𝗦𝘁𝗮𝗿𝘁𝗲𝗿::𝗳𝗶𝗻𝗶𝘀𝗵($s)],
     [map {$_**2} 1..$N];

    ok readFile($l) =~ m(Finished $N processes for: Test processes)s;
    clearFolder($s->transferArea, 1e3);
    unlink $l;
   }

squareArray(@)

Create a two dimensional square array from a one dimensional linear array.

     Parameter  Description
  1  @array     Array

Example:

  if (1) {
    is_deeply [𝘀𝗾𝘂𝗮𝗿𝗲𝗔𝗿𝗿𝗮𝘆 @{[1..4]} ], [[1, 2], [3, 4]];
    is_deeply [𝘀𝗾𝘂𝗮𝗿𝗲𝗔𝗿𝗿𝗮𝘆 @{[1..22]}],
     [[1 .. 5], [6 .. 10], [11 .. 15], [16 .. 20], [21, 22]];

    is_deeply [1..$_], [deSquareArray 𝘀𝗾𝘂𝗮𝗿𝗲𝗔𝗿𝗿𝗮𝘆 @{[1..$_]}] for 1..22;
    ok $_ == countSquareArray         𝘀𝗾𝘂𝗮𝗿𝗲𝗔𝗿𝗿𝗮𝘆 @{[1..$_]}  for 222;
   }

deSquareArray(@)

Create a one dimensional array from a two dimensional array of arrays

     Parameter  Description
  1  @square    Array of arrays

Example:

  if (1) {
    is_deeply [squareArray @{[1..4]} ], [[1, 2], [3, 4]];
    is_deeply [squareArray @{[1..22]}],
     [[1 .. 5], [6 .. 10], [11 .. 15], [16 .. 20], [21, 22]];

    is_deeply [1..$_], [𝗱𝗲𝗦𝗾𝘂𝗮𝗿𝗲𝗔𝗿𝗿𝗮𝘆 squareArray @{[1..$_]}] for 1..22;
    ok $_ == countSquareArray         squareArray @{[1..$_]}  for 222;
   }

runInParallel($$$@)

Process each element of @array in square root parallel with a maximum $maximumNumberOfProcesses processes using sub &$parallel to process an element and then call sub &$results to process all the results returned by &$parallel. &$parallel receives an element from @array. &$results receives an array of all the results returned by &$parallel.

     Parameter                  Description
  1  $maximumNumberOfProcesses  Maximum number of processes
  2  $parallel                  Parallel sub
  3  $results                   Results sub
  4  @array                     Array of items to process

Example:

  if (1) {
    my @N = 1..100;
    my $N = 100;
    my $R = 0; $R += $_*$_ for 1..$N;

    ok 338350 == $R;

    ok $R == runInSquareRootParallel
       (4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );

    ok $R == 𝗿𝘂𝗻𝗜𝗻𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹
       (4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );

    for my $sqrtMode(0..1)
     {ok $R == processInParallel
       ($sqrtMode, 4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );
     }
   }

runInSquareRootParallel($$$@)

Process each element of @array in square root parallel with a maximum $maximumNumberOfProcesses processes using sub &$parallel to process an element and then call sub &$results to process all the results returned by &$parallel. &$parallel receives an element from @array. &$results receives an array of all the results returned by &$parallel.

     Parameter                  Description
  1  $maximumNumberOfProcesses  Maximum number of processes
  2  $parallel                  Parallel sub
  3  $results                   Results sub
  4  @array                     Array of items to process

Example:

  if (1) {
    my @N = 1..100;
    my $N = 100;
    my $R = 0; $R += $_*$_ for 1..$N;

    ok 338350 == $R;

    ok $R == 𝗿𝘂𝗻𝗜𝗻𝗦𝗾𝘂𝗮𝗿𝗲𝗥𝗼𝗼𝘁𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹
       (4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );

    ok $R == runInParallel
       (4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );

    for my $sqrtMode(0..1)
     {ok $R == processInParallel
       ($sqrtMode, 4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );
     }
   }

processInParallel($$$$@)

Depending on $sqrtMode process elements in parallel or square root parallel with a maximum of $maximumNumberOfProcesses processes; process each element with sub $parallel and the results of processing all elements with $results where the elements are taken from @array. &$parallel receives an element from @array. &$results receives an array of all the results returned by &$parallel.

     Parameter                  Description
  1  $sqrtMode                  Square root parallel if true
  2  $maximumNumberOfProcesses  Maximum number of processes
  3  $parallel                  Parallel sub
  4  $results                   Results sub
  5  @array                     Array of items to process

Example:

  if (1) {
    my @N = 1..100;
    my $N = 100;
    my $R = 0; $R += $_*$_ for 1..$N;

    ok 338350 == $R;

    ok $R == runInSquareRootParallel
       (4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );

    ok $R == runInParallel
       (4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );

    for my $sqrtMode(0..1)
     {ok $R == 𝗽𝗿𝗼𝗰𝗲𝘀𝘀𝗜𝗻𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹
       ($sqrtMode, 4,
        sub {my ($p) = @_; $p * $p},
        sub {my $p = 0; $p += $_ for @_; $p},
        @{[1..$N]}
       );
     }
   }

processSizesInParallel($$@)

Process items of known size in parallel using (8 * the number of CPUs) processes with the process each item is assigned to depending on the size of the item so that each process is loaded with approximately the same number of bytes of data in total from the items it processes.

Each item is processed by sub $parallel and the results of processing all items is processed by $results where the items are taken from @sizes. Each &$parallel() receives an item from @files. &$results() receives an array of all the results returned by &$parallel().

     Parameter  Description
  1  $parallel  Parallel sub
  2  $results   Results sub
  3  @sizes     Array of [size; item] to process by size

Example:

  if (1) {
    my $d = temporaryFolder;
    my @f = map {owf(fpe($d, $_, q(txt)), 'X' x ($_ ** 2 % 11))} 1..9;

    my $f = fileLargestSize(@f);
    ok fn($f) eq '3', 'aaa';

    my $b = folderSize($d);
    ok $b > 0, 'bbb';

    my $c = processFilesInParallel(
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12);

    ok 108 == $c, 'cc11';

    my $C = 𝗽𝗿𝗼𝗰𝗲𝘀𝘀𝗦𝗶𝘇𝗲𝘀𝗜𝗻𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, map {[fileSize($_), $_]} (@f) x 12;

    ok 108 == $C, 'cc2';

    my $J = processJavaFilesInParallel
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12;

    ok 108 == $J, 'cc3';

    clearFolder($d, 12);
   }

processFilesInParallel($$@)

Process files in parallel using (8 * the number of CPUs) processes with the process each file is assigned to depending on the size of the file so that each process is loaded with approximately the same number of bytes of data in total from the files it processes.

Each file is processed by sub $parallel and the results of processing all files is processed by $results where the files are taken from @files. Each &$parallel receives a file from @files. &$results receives an array of all the results returned by &$parallel.

     Parameter  Description
  1  $parallel  Parallel sub
  2  $results   Results sub
  3  @files     Array of files to process by size

Example:

  if (1) {
    my $d = temporaryFolder;
    my @f = map {owf(fpe($d, $_, q(txt)), 'X' x ($_ ** 2 % 11))} 1..9;

    my $f = fileLargestSize(@f);
    ok fn($f) eq '3', 'aaa';

    my $b = folderSize($d);
    ok $b > 0, 'bbb';

    my $c = 𝗽𝗿𝗼𝗰𝗲𝘀𝘀𝗙𝗶𝗹𝗲𝘀𝗜𝗻𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹(
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12);

    ok 108 == $c, 'cc11';

    my $C = processSizesInParallel
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, map {[fileSize($_), $_]} (@f) x 12;

    ok 108 == $C, 'cc2';

    my $J = processJavaFilesInParallel
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12;

    ok 108 == $J, 'cc3';

    clearFolder($d, 12);
   }

processJavaFilesInParallel($$@)

Process java files of known size in parallel using (the number of CPUs) processes with the process each item is assigned to depending on the size of the java item so that each process is loaded with approximately the same number of bytes of data in total from the java files it processes.

Each java item is processed by sub $parallel and the results of processing all java files is processed by $results where the java files are taken from @sizes. Each &$parallel() receives a java item from @files. &$results() receives an array of all the results returned by &$parallel().

     Parameter  Description
  1  $parallel  Parallel sub
  2  $results   Results sub
  3  @files     Array of [size; java item] to process by size

Example:

  if (1) {
    my $d = temporaryFolder;
    my @f = map {owf(fpe($d, $_, q(txt)), 'X' x ($_ ** 2 % 11))} 1..9;

    my $f = fileLargestSize(@f);
    ok fn($f) eq '3', 'aaa';

    my $b = folderSize($d);
    ok $b > 0, 'bbb';

    my $c = processFilesInParallel(
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12);

    ok 108 == $c, 'cc11';

    my $C = processSizesInParallel
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, map {[fileSize($_), $_]} (@f) x 12;

    ok 108 == $C, 'cc2';

    my $J = 𝗽𝗿𝗼𝗰𝗲𝘀𝘀𝗝𝗮𝘃𝗮𝗙𝗶𝗹𝗲𝘀𝗜𝗻𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹
      sub
       {my ($file) = @_;
        [&fileSize($file), $file]
       },
      sub
       {scalar @_;
       }, (@f) x 12;

    ok 108 == $J, 'cc3';

    clearFolder($d, 12);
   }

syncFromS3InParallel($$$$$)

Download from S3 by using "aws s3 sync --exclude '*' --include '...'" in parallel to sync collections of two or more files no greater then $maxSize or single files greater than $maxSize from the $source folder on S3 to the local folder $target using the specified $Profile and $options - then execute the entire command again without the --exclude and --include options in series which might now run faster due to the prior downloads.

     Parameter  Description
  1  $maxSize   The maximum collection size
  2  $source    The source folder on S3
  3  $target    The target folder locally
  4  $Profile   Aws cli profile
  5  $options   Aws cli options

Example:

  if (0)
   {𝘀𝘆𝗻𝗰𝗙𝗿𝗼𝗺𝗦𝟯𝗜𝗻𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹 1e5,
      q(xxx/originals3/),
      q(/home/phil/xxx/),
      q(phil), q(--quiet);

    syncToS3InParallel 1e5,
      q(/home/phil/xxx/),
      q(xxx/originals3/),
      q(phil), q(--quiet);
   }

syncToS3InParallel($$$$$)

Upload to S3 by using "aws s3 sync --exclude '*' --include '...'" in parallel to sync collections of two or more files no greater then $maxSize or single files greater than $maxSize from the $source folder locally to the target folder $target on S3 using the specified $Profile and $options - then execute the entire command again without the --exclude and --include options in series which might now run faster due to the prior uploads.

     Parameter  Description
  1  $maxSize   The maximum collection size
  2  $source    The target folder locally
  3  $target    The source folder on S3
  4  $Profile   Aws cli profile
  5  $options   Aws cli options

Example:

  if (0)
   {syncFromS3InParallel 1e5,
      q(xxx/originals3/),
      q(/home/phil/xxx/),
      q(phil), q(--quiet);

    𝘀𝘆𝗻𝗰𝗧𝗼𝗦𝟯𝗜𝗻𝗣𝗮𝗿𝗮𝗹𝗹𝗲𝗹 1e5,
      q(/home/phil/xxx/),
      q(xxx/originals3/),
      q(phil), q(--quiet);
   }

childPids($)

Recursively find the pids of all the sub processes of a $process and all their sub processes and so on returning the specified pid and all its child pids as a list.

     Parameter  Description
  1  $p         Process

Example:

  if (0) {
    is_deeply [𝗰𝗵𝗶𝗹𝗱𝗣𝗶𝗱𝘀(2702)], [2702..2705];
   }

newServiceIncarnation($$)

Create a new service incarnation to record the start up of a new instance of a service and return the description as a Data::Exchange::Service Definition hash.

     Parameter  Description
  1  $service   Service name
  2  $file      Optional details file

Example:

  if (1)
   {my $s = 𝗻𝗲𝘄𝗦𝗲𝗿𝘃𝗶𝗰𝗲𝗜𝗻𝗰𝗮𝗿𝗻𝗮𝘁𝗶𝗼𝗻("aaa", q(bbb.txt));
    is_deeply $s->check, $s;
    my $t = 𝗻𝗲𝘄𝗦𝗲𝗿𝘃𝗶𝗰𝗲𝗜𝗻𝗰𝗮𝗿𝗻𝗮𝘁𝗶𝗼𝗻("aaa", q(bbb.txt));
    is_deeply $t->check, $t;
    ok $t->start >= $s->start+1;
    ok !$s->check(1);
    unlink q(bbb.txt);
   }

Data::Exchange::Service::check($$)

Check that we are the current incarnation of the named service with details obtained from newServiceIncarnation. If the optional $continue flag has been set then return the service details if this is the current service incarnation else undef. Otherwise if the $continue flag is false confess unless this is the current service incarnation thus bringing the earlier version of this service to an abrupt end.

     Parameter  Description
  1  $service   Current service details
  2  $continue  Return result if B<$continue> is true else confess if the service has been replaced

Example:

  if (1)
   {my $s = newServiceIncarnation("aaa", q(bbb.txt));
    is_deeply $s->check, $s;
    my $t = newServiceIncarnation("aaa", q(bbb.txt));
    is_deeply $t->check, $t;
    ok $t->start >= $s->start+1;
    ok !$s->check(1);
    unlink q(bbb.txt);
   }

Documentation

Extract, format and update documentation for a perl module.

parseDitaRef($$$)

Parse a dita reference into its components optionally supplying a base file name for the file component and the topic id of the current topic as the default for the topicId if not present.

     Parameter  Description
  1  $ref       Reference to parse
  2  $File      Default absolute file
  3  $TopicId   Default topic id

Example:

  if (1) {
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(a#b/c))], [qw(a b c)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(a#./c))], [q(a), q(), q(c)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(a#/c))],  [q(a), q(), q(c)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(a#c))],   [q(a), q(), q(c)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(#b/c))],  [q(),  qw(b c)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(#b))],    [q(),  q(), q(b)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(#./c))],  [q(),  q(), q(c)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(#/c))],   [q(),  q(), q(c)];
    is_deeply [𝗽𝗮𝗿𝘀𝗲𝗗𝗶𝘁𝗮𝗥𝗲𝗳(q(#c))],    [q(),  q(), q(c)];
   }

parseXmlDocType($)

Parse an Xml DOCTYPE and return a hash indicating its components

     Parameter  Description
  1  $string    String containing a DOCTYPE

Example:

  if (1)
   {is_deeply
      𝗽𝗮𝗿𝘀𝗲𝗫𝗺𝗹𝗗𝗼𝗰𝗧𝘆𝗽𝗲
        (q(<!DOCTYPE reference PUBLIC "-//OASIS//DTD DITA Reference//EN" "reference.dtd">)),
        {localDtd => "reference.dtd",
         public   => 1,
         publicId => "-//OASIS//DTD DITA Reference//EN",
         root     => "reference",
        };

    is_deeply
      𝗽𝗮𝗿𝘀𝗲𝗫𝗺𝗹𝗗𝗼𝗰𝗧𝘆𝗽𝗲
       (qq(<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE concept PUBLIC \"-//OASIS//DTD DITA Task//EN\" \"concept.dtd\" []>
<concept id=\"c2\">
  <title id=\"title\">Jumping Through Hops</title>
  <conbody>
    <section>
      <title/>
      <xref  format=\"dita\" href=\"act1.dita#c1/title\">All Timing Codes Begin Here</xref>
      <note  conref=\"act2.dita#c2/title\"/>
      <xref  format=\"dita\" href=\"9999#c1/title\"/>
      <xref  format=\"dita\" href=\"guid-000#guid-000/title\"/>
      <xref  format=\"dita\" href=\"guid-001#guid-001/title guid-000#guid-000/title\"/>
      <xref  format=\"dita\" href=\"guid-000#guid-000/title2\"/>
      <xref  format=\"dita\" href=\"guid-000#c1/title2\"/>
      <xref  format=\"dita\" href=\"guid-999#c1/title2\"/>
      <xref  href=\"http://\"/>
      <image href=\"act2.png\"/>
      <link href=\"guid-000\"/>
      <link href=\"guid-999\"/>
      <link href=\"act1.dita\"/>
      <link href=\"act9999.dita\"/>
      <p conref=\"9999.dita\"/>
      <p conref=\"bookmap.ditamap\"/>
      <p conref=\"bookmap2.ditamap\"/>
    </section>
    <required-cleanup>PLEX18</required-cleanup>
  </conbody>
</concept>
<!--linted: 2018-Nov-23 -->
)),
       {localDtd => "concept.dtd",
        public   => 1,
        publicId => "-//OASIS//DTD DITA Task//EN",
        root     => "concept",
       };
   }

reportSettings($$)

Report the current values of parameterless subs in a $sourceFile that match \Asub\s+(\w+)\s*\{ and optionally write the report to $reportFile. Return the text of the report.

     Parameter    Description
  1  $sourceFile  Source file
  2  $reportFile  Optional report file

Example:

  𝗿𝗲𝗽𝗼𝗿𝘁𝗦𝗲𝘁𝘁𝗶𝗻𝗴𝘀($0);

reportAttributes($)

Report the attributes present in a $sourceFile

     Parameter    Description
  1  $sourceFile  Source file

Example:

  if (0) {
    my $d = temporaryFile;

    my $f = writeFile(undef, <<'END'.<<END2);
  #!perl -I/home/phil/perl/cpan/DataTableText/lib/
  use Data::Table::Text qw(reportAttributeSettings);
  sub attribute {1}                                                               # An attribute
  sub replaceable($)                                                              #r A replaceable method
   {
   }

reportAttributeSettings($)

Report the current values of the attribute methods in the calling file and optionally write the report to $reportFile. Return the text of the report.

     Parameter    Description
  1  $reportFile  Optional report file

Example:

  if (0) {
    my $d = temporaryFile;

    my $f = writeFile(undef, <<'END'.<<END2);
  #!perl -I/home/phil/perl/cpan/DataTableText/lib/
  use Data::Table::Text qw(𝗿𝗲𝗽𝗼𝗿𝘁𝗔𝘁𝘁𝗿𝗶𝗯𝘂𝘁𝗲𝗦𝗲𝘁𝘁𝗶𝗻𝗴𝘀);
  sub attribute {1}                                                               # An attribute
  sub replaceable($)                                                              #r A replaceable method
   {
   }

reportReplacableMethods($)

Report the replaceable methods marked with #r in a $sourceFile

     Parameter    Description
  1  $sourceFile  Source file

Example:

  if (0) {
    my $d = temporaryFile;

    my $f = writeFile(undef, <<'END'.<<END2);
  #!perl -I/home/phil/perl/cpan/DataTableText/lib/
  use Data::Table::Text qw(reportAttributeSettings);
  sub attribute {1}                                                               # An attribute
  sub replaceable($)                                                              #r A replaceable method
   {
   }

  sub 𝗿𝗲𝗽𝗼𝗿𝘁𝗥𝗲𝗽𝗹𝗮𝗰𝗮𝗯𝗹𝗲𝗠𝗲𝘁𝗵𝗼𝗱𝘀($)
   {my ($sourceFile) = @_;                                                        # Source file
    my $s = readFile($sourceFile);
    my %s;
    for my $l(split /
/, $s)                                                     # Find the attribute subs
     {if ($l =~ m(\Asub\s*(\w+).*?#\w*r\w*\s+(.*)\Z))
       {$s{$1} = $2;
       }
     }
    \%s
   }

reportExportableMethods($)

Report the exportable methods marked with #e in a $sourceFile

     Parameter    Description
  1  $sourceFile  Source file

Example:

  if (0) {
    my $d = temporaryFile;

    my $f = writeFile(undef, <<'END'.<<END2);
  #!perl -I/home/phil/perl/cpan/DataTableText/lib/
  use Data::Table::Text qw(reportAttributeSettings);
  sub attribute {1}                                                               # An attribute
  sub replaceable($)                                                              #r A replaceable method
   {
   }

htmlToc($@)

Generate a table of contents for some html.

     Parameter  Description
  1  $replace   Sub-string within the html to be replaced with the toc
  2  $html      String of html

Example:

  ok nws(𝗵𝘁𝗺𝗹𝗧𝗼𝗰("XXXX", <<END)), '𝗵𝘁𝗺𝗹𝗧𝗼𝗰'
  <h1 id="1" otherprops="1">Chapter 1</h1>
    <h2 id="11" otherprops="11">Section 1</h1>
  <h1 id="2" otherprops="2">Chapter 2</h1>
  XXXX
  END

    eq nws(<<END);
  <h1 id="1" otherprops="1">Chapter 1</h1>
    <h2 id="11" otherprops="11">Section 1</h1>
  <h1 id="2" otherprops="2">Chapter 2</h1>
  <table cellspacing=10 border=0>
  <tr><td>&nbsp;
  <tr><td align=right>1<td>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#1">Chapter 1</a>
  <tr><td align=right>2<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#11">Section 1</a>
  <tr><td>&nbsp;
  <tr><td align=right>3<td>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#2">Chapter 2</a>
  </table>
  END

expandWellKnownUrlsInPerlFormat($)

Expand short url names found in a string in the format L<url-name> using the Perl POD syntax

     Parameter  Description
  1  $string    String containing url names to expand

Example:

  if (1) {
    ok expandWellKnownUrlsInDitaFormat(q(L[github])) eq
      q(<xref scope="external" format="html" href="https://github.com">GitHub</xref>);

    ok expandWellKnownUrlsInHtmlFormat(q(L[github])) eq
      q(<a format="html" href="https://github.com">GitHub</a>);

    ok 𝗲𝘅𝗽𝗮𝗻𝗱𝗪𝗲𝗹𝗹𝗞𝗻𝗼𝘄𝗻𝗨𝗿𝗹𝘀𝗜𝗻𝗣𝗲𝗿𝗹𝗙𝗼𝗿𝗺𝗮𝘁(q(L<GitHub|https://github.com>)) eq
      q(L<GitHub|https://github.com>);

    ok 𝗲𝘅𝗽𝗮𝗻𝗱𝗪𝗲𝗹𝗹𝗞𝗻𝗼𝘄𝗻𝗨𝗿𝗹𝘀𝗜𝗻𝗣𝗲𝗿𝗹𝗙𝗼𝗿𝗺𝗮𝘁(q(github))    eq q(github);

    ok expandWellKnownUrlsInHtmlFromPerl(q(L<GitHub|https://github.com>)) eq
      q(<a format="html" href="https://github.com">GitHub</a>);
   }

expandWellKnownUrlsInHtmlFormat($)

Expand short url names found in a string in the format L[url-name] using the html a tag.

     Parameter  Description
  1  $string    String containing url names to expand

Example:

  if (1) {
    ok expandWellKnownUrlsInDitaFormat(q(L[github])) eq
      q(<xref scope="external" format="html" href="https://github.com">GitHub</xref>);

    ok 𝗲𝘅𝗽𝗮𝗻𝗱𝗪𝗲𝗹𝗹𝗞𝗻𝗼𝘄𝗻𝗨𝗿𝗹𝘀𝗜𝗻𝗛𝘁𝗺𝗹𝗙𝗼𝗿𝗺𝗮𝘁(q(L[github])) eq
      q(<a format="html" href="https://github.com">GitHub</a>);

    ok expandWellKnownUrlsInPerlFormat(q(L<GitHub|https://github.com>)) eq
      q(L<GitHub|https://github.com>);

    ok expandWellKnownUrlsInPerlFormat(q(github))    eq q(github);

    ok expandWellKnownUrlsInHtmlFromPerl(q(L<GitHub|https://github.com>)) eq
      q(<a format="html" href="https://github.com">GitHub</a>);
   }

expandWellKnownUrlsInHtmlFromPerl($)

Expand short url names found in a string in the format L[url-name] using the html a tag.

     Parameter  Description
  1  $string    String containing url names to expand

Example:

  if (1) {
    ok expandWellKnownUrlsInDitaFormat(q(L[github])) eq
      q(<xref scope="external" format="html" href="https://github.com">GitHub</xref>);

    ok expandWellKnownUrlsInHtmlFormat(q(L[github])) eq
      q(<a format="html" href="https://github.com">GitHub</a>);

    ok expandWellKnownUrlsInPerlFormat(q(L<GitHub|https://github.com>)) eq
      q(L<GitHub|https://github.com>);

    ok expandWellKnownUrlsInPerlFormat(q(github))    eq q(github);

    ok 𝗲𝘅𝗽𝗮𝗻𝗱𝗪𝗲𝗹𝗹𝗞𝗻𝗼𝘄𝗻𝗨𝗿𝗹𝘀𝗜𝗻𝗛𝘁𝗺𝗹𝗙𝗿𝗼𝗺𝗣𝗲𝗿𝗹(q(L<GitHub|https://github.com>)) eq
      q(<a format="html" href="https://github.com">GitHub</a>);
   }

expandWellKnownUrlsInDitaFormat($)

Expand short url names found in a string in the format L[url-name] in the L[Dita] xrefformat.

     Parameter  Description
  1  $string    String containing url names to expand

Example:

  if (1) {
    ok 𝗲𝘅𝗽𝗮𝗻𝗱𝗪𝗲𝗹𝗹𝗞𝗻𝗼𝘄𝗻𝗨𝗿𝗹𝘀𝗜𝗻𝗗𝗶𝘁𝗮𝗙𝗼𝗿𝗺𝗮𝘁(q(L[github])) eq
      q(<xref scope="external" format="html" href="https://github.com">GitHub</xref>);

    ok expandWellKnownUrlsInHtmlFormat(q(L[github])) eq
      q(<a format="html" href="https://github.com">GitHub</a>);

    ok expandWellKnownUrlsInPerlFormat(q(L<GitHub|https://github.com>)) eq
      q(L<GitHub|https://github.com>);

    ok expandWellKnownUrlsInPerlFormat(q(github))    eq q(github);

    ok expandWellKnownUrlsInHtmlFromPerl(q(L<GitHub|https://github.com>)) eq
      q(<a format="html" href="https://github.com">GitHub</a>);
   }

expandNewLinesInDocumentation($)

Expand new lines in documentation, specifically for new line and

 for two new lines.

     Parameter  Description
  1  $s         String to be expanded

Example:

  if (1) {
  ok 𝗲𝘅𝗽𝗮𝗻𝗱𝗡𝗲𝘄𝗟𝗶𝗻𝗲𝘀𝗜𝗻𝗗𝗼𝗰𝘂𝗺𝗲𝗻𝘁𝗮𝘁𝗶𝗼𝗻(q(a

  b
  c
)) eq <<END;
  a

    b
    c
  END
   }

updateDocumentation($)

Update documentation for a Perl module from the comments in its source code. Comments between the lines marked with:

  #Dn title # description

and:

  #D

where n is either 1, 2 or 3 indicating the heading level of the section and the # is in column 1.

Methods are formatted as:

  sub name(signature)      #FLAGS comment describing method
   {my ($parameters) = @_; # comments for each parameter separated by commas.

FLAGS can be chosen from:

I

method of interest to new users

P

private method

r

optionally replaceable method

R

required replaceable method

S

static method

X

die rather than received a returned undef result

Other flags will be handed to the method extractDocumentationFlags(flags to process, method name) found in the file being documented, this method should return [the additional documentation for the method, the code to implement the flag].

Text following 'Example:' in the comment (if present) will be placed after the parameters list as an example. Lines containing comments consisting of '#T'.methodName will also be aggregated and displayed as examples for that method.

Lines formatted as:

  BEGIN{*source=*target}

starting in column 1 will define a synonym for a method.

Lines formatted as:

  #C emailAddress text

will be aggregated in the acknowledgments section at the end of the documentation.

The character sequence \n in the comment will be expanded to one new line, \m to two new lines and L<$_>,L<confess>,L<die>,L<eval>,L<lvalueMethod> to links to the perl documentation.

Search for '#D1': in https://metacpan.org/source/PRBRENAN/Data-Table-Text-20180810/lib/Data/Table/Text.pm to see more examples of such documentation in action - although it is quite difficult to see as it looks just like normal comments placed in the code.

Parameters:

     Parameter    Description
  1  $perlModule  Optional file name with caller's file being the default

Example:

   {my $s = 𝘂𝗽𝗱𝗮𝘁𝗲𝗗𝗼𝗰𝘂𝗺𝗲𝗻𝘁𝗮𝘁𝗶𝗼𝗻(<<'END' =~ s(#) (#)gsr =~ s(~) ()gsr);
  package Sample::Module;

  #D1 Samples                                                                      # Sample methods.

  sub sample($@)                                                                  #R Documentation for the:  sample() method.  See also L<Data::Table::Text::sample2|/Data::Table::Text::sample2>. #Tsample
   {my ($node, @context) = @_;                                                    # Node, optional context
    1
   }

  ~BEGIN{*smpl=*sample}

  sub Data::Table::Text::sample2(\&@)                                             #PS Documentation for the sample2() method.
   {my ($sub, @context) = @_;                                                     # Sub to call, context.
    1
   }

  ok sample(undef, qw(a b c)) == 1;                                               #Tsample

  if (1)                                                                          #Tsample
   {ok sample(q(a), qw(a b c))  == 2;
    ok sample(undef, qw(a b c)) == 1;
   }

  ok sample(<<END2)) == 1;                                                        #Tsample
  sample data
  END2

    ok $s =~ m'=head2 sample28\$\@29';

Data::Exchange::Service Definition

Service details.

Output fields

file - The file in which the service start details is being recorded.

service - The name of the service.

start - The time this service was started time plus a minor hack to simplify testing.

Data::Table::Text::Starter Definition

Process starter definition.

Input fields

processingLogFile - Optional: name of a file to which process start and end information should be appended

processingTitle - Optional: title describing the processing being performed.

totalToBeStarted - Optionally: the total number of processes to be started - if this is supplied then an estimate of the finish time for this processing is printed to the log file every time a process starts or finishes.

Output fields

autoRemoveTransferArea - If true then automatically clear the transfer area at the end of processing.

maximumNumberOfProcesses - The maximum number of processes to start in parallel at one time. If this limit is exceeded, the start of subsequent processes will be delayed until processes started earlier have finished.

pids - A hash of pids representing processes started but not yet completed.

processFinishTime - {pid} == time the process finished.

processStartTime - {pid} == time the process was started.

processingLogFileHandle - Handle for log file if a log file was supplied

resultsArray - Consolidated array of results.

startTime - Start time

transferArea - The name of the folder in which files transferring results from the child to the parent process will be stored.

TestHash Definition

Definition of a blessed hash.

Output fields

a - Definition of attribute aa.

b - Definition of attribute bb.

Udsr Definition

Package name

Input fields

headerLength - Length of fixed header which carries the length of the following message

serverAction - Server action sub, which receives a communicator every time a client creates a new connection. If this server is going to be started by systemd as a service with the specified serverName then this is the a actual text of the code that will be installed as a CGI script and run in response to an incoming transaction in a separate process with the userid set to serviceUser. It receives the text of the http request from the browser as parameter 1 and should return the text to be sent back to the browser.

serviceName - Service name for install by systemd

serviceUser - Userid for service

socketPath - Socket file

Output fields

client - Client socket and connection socket

serverPid - Server pid which can be used to kill the server via kill q(kill), $pid

Attributes

The following is a list of all the attributes in this package. A method coded with the same name in your package will over ride the method of the same name in this package and thus provide your value for the attribute in place of the default value supplied for this attribute by this package.

Replaceable Attribute List

nameFromStringMaximumLength

nameFromStringMaximumLength

Maximum length of a name generated from a string

Private Methods

denormalizeFolderName($)

Remove any trailing folder separator from a folder name component.

     Parameter  Description
  1  $name      Name

renormalizeFolderName($)

Normalize a folder name component by adding a trailing separator.

     Parameter  Description
  1  $name      Name

trackFiles($@)

Track the existence of files.

     Parameter  Description
  1  $label     Label
  2  @files     Files

printFullFileName()

Print a file name on a separate line with escaping so it can be used easily from the command line.

absFromAbsPlusRel2($$)

Create an absolute file from an absolute file and a relative file.

     Parameter  Description
  1  $a         Absolute file name
  2  $f         Relative file name

findAllFilesAndFolders($)

Find all the files and folders under a folder.

     Parameter  Description
  1  $dir       Folder to start the search with

readUtf16File($)

Read a file containing unicode in utf-16 format.

     Parameter  Description
  1  $file      Name of file to read

binModeAllUtf8()

Set STDOUT and STDERR to accept utf8 without complaint.

Example:

    𝗯𝗶𝗻𝗠𝗼𝗱𝗲𝗔𝗹𝗹𝗨𝘁𝗳𝟴;

convertImageToJpx690($$$$)

Convert an image to jpx format using versions of Imagemagick version 6.9.0 and above with optional image reduction.

     Parameter  Description
  1  $Source    Source file
  2  $target    Target folder (as multiple files will be created)
  3  $Size      Optional size of each tile - defaults to 256
  4  $Tiles     Optional limit on the number of tiles in either dimension

setCombination(@)

Count the elements in sets represented as arrays of strings and/or the keys of hashes

     Parameter  Description
  1  @s         Array of arrays of strings and/or hashes

formatTableMultiLine($$)

Tabularize text that has new lines in it.

     Parameter   Description
  1  $data       Reference to an array of arrays of data to be formatted as a table
  2  $separator  Optional line separator to use instead of new line for each row.

formatTableClearUpLeft($)

Blank identical column values up and left

     Parameter  Description
  1  $data      Array of arrays

formatTableAA($$%)

Tabularize an array of arrays.

     Parameter  Description
  1  $data      Data to be formatted
  2  $title     Reference to an array of titles
  3  %options   Options

Example:

  if (1) {
   ok formatTable
    ([[1,1,1],[1,1,2],[1,2,2],[1,2,3]], [], clearUpLeft=>1) eq <<END;             # Clear matching columns

  1  1  1  1
  2        2
  3     2  2
  4        3
  END
   }

formatTableHA($$)

Tabularize a hash of arrays.

     Parameter  Description
  1  $data      Data to be formatted
  2  $title     Optional titles

formatTableAH($)

Tabularize an array of hashes.

     Parameter  Description
  1  $data      Data to be formatted

formatTableHH($)

Tabularize a hash of hashes.

     Parameter  Description
  1  $data      Data to be formatted

formatTableA($$)

Tabularize an array.

     Parameter  Description
  1  $data      Data to be formatted
  2  $title     Optional title

formatTableH($$)

Tabularize a hash.

     Parameter  Description
  1  $data      Data to be formatted
  2  $title     Optional title

formatTableCheckKeys()

Options available for formatting tables

reloadHashes2($$)

Ensures that all the hashes within a tower of data structures have LValue methods to get and set their current keys.

     Parameter  Description
  1  $d         Data structure
  2  $progress  Progress

showHashes2($$$)

Create a map of all the keys within all the hashes within a tower of data structures.

     Parameter  Description
  1  $d         Data structure
  2  $keys      Keys found
  3  $progress  Progress

showHashes($)

Create a map of all the keys within all the hashes within a tower of data structures.

     Parameter  Description
  1  $d         Data structure

newUdsr(@)

Create a communicator - a means to communicate between processes on the same machine via Udsr::read and Udsr::write.

     Parameter  Description
  1  @parms     Attributes per L<Udsr Definition|/Udsr Definition>

awsIp()

Get ip address of server at aws

awsProfile(%)

Create a profile keyword from the specified %options

     Parameter  Description
  1  %options   Options

saveSourceToS3($$)

Save source code.

     Parameter               Description
  1  $aws                    Aws target file and keywords
  2  $saveIntervalInSeconds  Save internal

s3Profile(%)

Return an S3 profile keyword from an S3 option set

     Parameter  Description
  1  %options   Options

Data::Table::Text::Starter::logEntry($$)

Create a log entry showing progress and eta.

     Parameter  Description
  1  $starter   Starter
  2  $finish    0 - start; 1 - finish

Data::Table::Text::Starter::averageProcessTime($)

Average elapsed time spent by each process

     Parameter  Description
  1  $starter   Starter

Data::Table::Text::Starter::say($@)

Write to the log file if it is available.

     Parameter  Description
  1  $starter   Starter
  2  @message   Text to write to log file.

Data::Table::Text::Starter::waitOne($)

Wait for at least one process to finish and consolidate its results.

     Parameter  Description
  1  $starter   Starter

countSquareArray(@)

Count the number of elements in a square array

     Parameter  Description
  1  @square    Array of arrays

processSizesInParallelN($$$@)

Process items of known size in parallel using the specified number $N processes with the process each file is assigned to depending on the size of the file so that each process is loaded with approximately the same number of bytes of data in total from the files it processes.

Each file is processed by sub $parallel and the results of processing all files is processed by $results where the files are taken from @files. Each &$parallel receives a file from @files. &$results receives an array of all the results returned by &$parallel.

     Parameter  Description
  1  $N         Number of processes
  2  $parallel  Parallel sub
  3  $results   Results sub
  4  @Sizes     Array of [size; item] to process by size

wellKnownUrls()

Short names for some well known urls

extractTest($)

Remove example markers from test code.

     Parameter  Description
  1  $string    String containing test line

docUserFlags($$$$)

Generate documentation for a method by calling the extractDocumentationFlags method in the package being documented, passing it the flags for a method and the name of the method. The called method should return the documentation to be inserted for the named method.

     Parameter    Description
  1  $flags       Flags
  2  $perlModule  File containing documentation
  3  $package     Package containing documentation
  4  $name        Name of method to be processed

updatePerlModuleDocumentation($)

Update the documentation in a perl file and show said documentation in a web browser.

     Parameter    Description
  1  $perlModule  File containing the code of the perl module

Synonyms

fpd is a synonym for filePathDir - Create a directory name from an array of file name components.

fpe is a synonym for filePathExt - Create a file name from an array of file name components the last of which is an extension.

fpf is a synonym for filePath - Create a file name from an array of file name components.

owf is a synonym for overWriteFile - Write a unicode utf8 string to a file after creating a path to the file if necessary and return the name of the file on success else confess.

temporaryDirectory is a synonym for temporaryFolder - Create a temporary folder that will automatically be rmdired during END processing.

Index

1 absFile - Return undef if the file is a relative file or b<$file> if the file is an absolute file name

2 absFromAbsPlusRel - Create an absolute file from an absolute file and a relative file.

3 absFromAbsPlusRel2 - Create an absolute file from an absolute file and a relative file.

4 addCertificate - Add a certificate to the current ssh session.

5 addLValueScalarMethods - Generate lvalue method scalar methods in the current package if they do not already exist.

6 appendFile - Append a unicode utf8 string to a file, possibly creating the file and the path to the file if necessary and return the name of the file on success else confess.

7 arrayProduct - Find the product of any strings that look like numbers in an array

8 arraySum - Find the sum of any strings that look like numbers in an array

9 arrayTimes - Multiply the second and subsequent parameters by the first parameter and return as an array

10 arrayToHash - Create a hash from an array

11 asciiToHexString - Encode an ascii string as a string of hexadecimal digits.

12 assertPackageRefs - Confirm that the specified references are to the specified package

13 assertRef - Confirm that the specified references are to the package into which this routine has been exported.

14 awsCurrentInstanceId - Get the server instance id of the AWS server we are currently running on if we are running on an AWS server else return a blank string.

15 awsCurrentInstanceType - Get the instance type of the AWS server if we are running on an AWS server else return a blank string.

16 awsCurrentIp - Get the ip address of the AWS server we are currently running on if we are running on an AWS server else return a blank string.

17 awsCurrentPublicIp4 - Get the instance type of the AWS server if we are running on an AWS server else return a blank string.

18 awsCurrentRegion - Get the server region of the AWS server we are currently running on if we are running on an AWS server else return a blank string.

19 awsEc2CreateImage - Create an image snap shot with the specified $name of the AWS server we are currently running on if we are running on an AWS server else return false.

20 awsEc2DescribeInstances - Describe the AWS instances running in a $region.

21 awsEc2DescribeInstancesGetIPAddresses - Get the IP addresses in the data returned by describe instances

22 awsIp - Get ip address of server at aws

23 awsMetaData - Get an item of meta data for the AWS server we are currently running on if we are running on an AWS server else return a blank string.

24 awsProfile - Create a profile keyword from the specified %options

25 awsTranslateText - Translate $text from English to a specified $language using AWS Translate with the specified global $options and return the translated string.

26 binModeAllUtf8 - Set STDOUT and STDERR to accept utf8 without complaint.

27 boldString - Convert alphanumerics in a string to bold.

28 boldStringUndo - Undo alphanumerics in a string to bold.

29 call - Call the specified sub in a separate process, wait for it to complete, copy back the named our variables, free the memory used.

30 checkFile - Return the name of the specified file if it exists, else confess the maximum extent of the path that does exist.

31 checkKeys - Check the keys in a hash conform to those $permitted.

32 childPids - Recursively find the pids of all the sub processes of a $process and all their sub processes and so on returning the specified pid and all its child pids as a list.

33 chooseStringAtRandom - Choose a string at random from the list of @strings supplied.

34 clearFolder - Remove all the files and folders under and including the specified folder as long as the number of files to be removed is less than the specified limit.

35 confirmHasCommandLineCommand - Check that the specified b<$cmd> is present on the current system.

36 containingPowerOfTwo - Find log two of the lowest power of two greater than or equal to a number.

37 contains - Returns the indices at which an item matches elements of the specified array.

38 convertDocxToFodt - Convert a docx file to fodt using unoconv which must not be running elsewhere at the time.

39 convertImageToJpx - Convert an image to jpx format using Imagemagick applying an optional scaling if required.

40 convertImageToJpx690 - Convert an image to jpx format using versions of Imagemagick version 6.

41 convertUnicodeToXml - Convert a string with unicode points that are not directly representable in ascii into string that replaces these points with their representation on Xml making the string usable in Xml documents.

42 copyBinaryFile - Copy a binary file and return the target name,

43 copyBinaryFileMd5Normalized - Normalize the name of the specified $source file to the md5 sum of its content, retaining its current extension, while placing the original file name in a companion file if the companion file does not already exist.

44 copyBinaryFileMd5NormalizedCreate - Create a file in the specified $folder whose name is constructed from the md5 sum of the specified $content, whose content is $content, whose extension is $extension and which has a companion file with the same name minus the extension which contains the specified $companionContent.

45 copyBinaryFileMd5NormalizedGetCompanionContent - Return the original name of the specified $source file after it has been normalized via copyBinaryFileMd5Normalized or copyBinaryFileMd5NormalizedCreate or return undef if the corresponding companion file does not exist.

46 copyFile - Copy the $source file encoded in utf8 to the specified $target file in and return $target.

47 copyFileMd5Normalized - Normalize the name of the specified $source file to the md5 sum of its content, retaining its current extension, while placing the original file name in a companion file if the companion file does not already exist.

48 copyFileMd5NormalizedCreate - Create a file in the specified $folder whose name is constructed from the md5 sum of the specified $content, whose content is $content, whose extension is $extension and which has a companion file with the same name minus the extension which contains the specified $companionContent.

49 copyFileMd5NormalizedDelete - Delete a normalized and its companion file

50 copyFileMd5NormalizedGetCompanionContent - Return the content of the companion file to the specified $source file after it has been normalized via copyFileMd5Normalized or copyFileMd5NormalizedCreate or return undef if the corresponding companion file does not exist.

51 copyFileMd5NormalizedName - Name a file using the GB Standard

52 copyFileToFolder - Copy the file named in $source to the specified $targetFolder/ or if $targetFolder/ is in fact a file into the folder containing this file and return the target file name.

53 copyFolder - Copy a folder

54 copyFolderFromRemote - Copy to the specified local $Source folder the corresponding remote folder on the server whose address is returned by awsIp using either the optional $userid or the default userid supplied by .

55 copyFolderToRemote - Copy the specified local $Source folder to the corresponding remote folder on the server whose address is returned by awsIp using either the optional $userid or the default userid supplied by .

56 countFileExtensions - Return a hash which counts the file extensions in and below the specified directories

57 countFileTypes - Return a hash which counts, in parallel, the results of applying the file command to each file under the specified directories.

58 countOccurencesInString - Returns the number of times the first string occurs in the second string

59 countSquareArray - Count the number of elements in a square array

60 createEmptyFile - Create an empty file - writeFile complains if no data is written to the file - and return the name of the file on success else confess.

61 currentDirectory - Get the current working directory.

62 currentDirectoryAbove - The path to the folder above the current working folder.

63 cutOutImagesInFodtFile - Cut out the images embedded in a fodt file, perhaps produced via convertDocxToFodt, placing them in the specified folder and replacing them in the source file with:

  <image href="$imageFile" outputclass="imageType">.

64 Data::Exchange::Service::check - Check that we are the current incarnation of the named service with details obtained from newServiceIncarnation.

65 Data::Table::Text::Starter::averageProcessTime - Average elapsed time spent by each process

66 Data::Table::Text::Starter::finish - Wait for all started processes to finish and return their results as an array.

67 Data::Table::Text::Starter::logEntry - Create a log entry showing progress and eta.

68 Data::Table::Text::Starter::say - Write to the log file if it is available.

69 Data::Table::Text::Starter::start - Start a new process to run the specified $sub.

70 Data::Table::Text::Starter::waitOne - Wait for at least one process to finish and consolidate its results.

71 dateStamp - Year-monthName-day

72 dateTimeStamp - Year-monthNumber-day at hours:minute:seconds

73 dateTimeStampName - Date time stamp without white space.

74 decodeBase64 - Decode an ascii string in base 64.

75 decodeJson - Decode Perl from Json.

76 deduplicateSequentialWordsInString - Remove sequentially duplicate words in a string

77 denormalizeFolderName - Remove any trailing folder separator from a folder name component.

78 deSquareArray - Create a one dimensional array from a two dimensional array of arrays

79 detagString - Remove html or xml tags from a string

80 docUserFlags - Generate documentation for a method by calling the extractDocumentationFlags method in the package being documented, passing it the flags for a method and the name of the method.

81 downloadGitHubPublicRepo - Get the contents of a public repo on GitHub and place them in a temporary folder whose name is returned to the caller or confess if no such repo exists.

82 downloadGitHubPublicRepoFile - Get the contents of a $user $repo $file from a public repo on GitHub and return them as a string.

83 dumpFile - Dump a data structure to a file

84 dumpGZipFile - Write a data structure through gzip to a file.

85 enclosedReversedString - Convert alphanumerics in a string to enclosed reversed alphanumerics.

86 enclosedReversedStringUndo - Undo alphanumerics in a string to enclosed reversed alphanumerics.

87 enclosedString - Convert alphanumerics in a string to enclosed alphanumerics.

88 enclosedStringUndo - Undo alphanumerics in a string to enclosed alphanumerics.

89 encodeBase64 - Encode an ascii string in base 64.

90 encodeJson - Encode Perl to Json.

91 evalFile - Read a file containing unicode in utf8, evaluate it, confess to any errors and then return any result with lvalue method methods to access each hash element - an improvement on do which silently ignores any errors.

92 evalGZipFile - Read a file containing compressed utf8, evaluate it, confess to any errors or return any result.

93 expandNewLinesInDocumentation - Expand new lines in documentation, specifically for new line and

 for two new lines.

94 expandWellKnownUrlsInDitaFormat - Expand short url names found in a string in the format L[url-name] in the L[Dita] xrefformat.

95 expandWellKnownUrlsInHtmlFormat - Expand short url names found in a string in the format L[url-name] using the html a tag.

96 expandWellKnownUrlsInHtmlFromPerl - Expand short url names found in a string in the format L[url-name] using the html a tag.

97 expandWellKnownUrlsInPerlFormat - Expand short url names found in a string in the format L<url-name> using the Perl POD syntax

98 extractTest - Remove example markers from test code.

99 fe - Get extension of file name.

100 fff - Confess a message with a line position and a file that Geany will jump to if clicked on.

101 fileInWindowsFormat - Convert a unix file name to windows format

102 fileLargestSize - Return the largest file

103 fileList - Files that match a given search pattern handed to bsd_glob.

104 fileMd5Sum - Get the Md5 sum for a file or string

105 fileModTime - Get the modified time of a file in seconds since the epoch.

106 fileOutOfDate - Calls the specified sub once for each source file that is missing, then calls the sub for the target if there were any missing files or if the target is older than any of the non missing source files or if the target does not exist.

107 filePath - Create a file name from an array of file name components.

108 filePathDir - Create a directory name from an array of file name components.

109 filePathExt - Create a file name from an array of file name components the last of which is an extension.

110 fileSize - Get the size of a file.

111 findAllFilesAndFolders - Find all the files and folders under a folder.

112 findDirs - Find all the folders under a folder and optionally filter the selected folders with a regular expression.

113 findFiles - Find all the files under a folder and optionally filter the selected files with a regular expression.

114 findFileWithExtension - Find the first extension from the specified extensions that produces a file that exists when appended to the specified file.

115 firstFileThatExists - Returns the name of the first file that exists or undef if none of the named files exist.

116 firstNChars - First N characters of a string.

117 flattenArrayAndHashValues - Flatten an array of scalars, array and hash references to make an array of scalars by flattening the array references and hash values.

118 fn - Remove path and extension from file name.

119 fne - Remove path from file name.

120 folderSize - Get the number of bytes in a folder

121 formatHtmlAndTextTables - Create text and html versions of a tabular report

122 formatHtmlTable - Format an array of arrays of scalars as an html table using the %options described in formatTableCheckKeys.

123 formatHtmlTablesIndex - Create an index of html files for use use as an initial page of Xref results

124 formatString - Format the specified $string so it can be displayed in $width columns.

125 formatTable - Format various $data structures as a table with titles as specified by $columnTitles: either a reference to an array of column titles or a string each line of which contains the column title as the first word with the rest of the line describing that column.

126 formatTableA - Tabularize an array.

127 formatTableAA - Tabularize an array of arrays.

128 formatTableAH - Tabularize an array of hashes.

129 formatTableBasic - Tabularize an array of arrays of text.

130 formatTableCheckKeys - Options available for formatting tables

131 formatTableClearUpLeft - Blank identical column values up and left

132 formatTableH - Tabularize a hash.

133 formatTableHA - Tabularize a hash of arrays.

134 formatTableHH - Tabularize a hash of hashes.

135 formatTableMultiLine - Tabularize text that has new lines in it.

136 formattedTablesReport - Report of all the reports created.

137 fp - Get path from file name.

138 fpn - Remove extension from file name.

139 fullFileName - Full name of a file.

140 fullyQualifiedFile - Return whether a file is fully qualified or not

141 fullyQualifyFile - Return the fully qualified name of a file

142 genHash - Return a $blessed hash with the specified $attributes accessible via lvalue method method calls.

143 genLValueArrayMethods - Generate lvalue method array methods in the current package.

144 genLValueHashMethods - Generate lvalue method hash methods in the current package.

145 genLValueScalarMethods - Generate lvalue method scalar methods in the current package, A method whose value has not yet been set will return a new scalar with value undef.

146 genLValueScalarMethodsWithDefaultValues - Generate lvalue method scalar methods with default values in the current package.

147 guidFromMd5 - Create a guid from an md5 hash.

148 guidFromString - Create a guid from a file or string via an md5 hash.

149 hexToAsciiString - Decode a string of hexadecimal digits as an ascii string.

150 hostName - The name of the host we are running on.

151 htmlToc - Generate a table of contents for some html.

152 imageSize - Return (width, height) of an image obtained via Imagemagick.

153 indentString - Indent lines contained in a string or formatted table by the specified string.

154 indexOfMax - Find the index of the maximum number in a list confessing to any ill defined values.

155 indexOfMin - Find the index of the minimum number in a list confessing to any ill defined values.

156 intersectionOfHashesAsArrays - Form the intersection of the specified hashes as one hash whose values are an array of corresponding values from each hash

157 intersectionOfHashKeys - Form the intersection of the keys of the specified hashes as one hash whose keys represent the intersection.

158 invertHashOfHashes - Invert a hash of hashes: given {a}{b} = c return {b}{c} = c

159 ipAddressViaArp - Get the ip address of a server on the local network by hostname via arp

160 isBlank - Test whether a string is blank.

161 isFileUtf8 - Return the file name quoted if its contents are in utf8 else return undef

162 isSubInPackage - Test whether the specified $package contains the subroutine <$sub>.

163 javaPackage - Extract the package name from a java string or file.

164 javaPackageAsFileName - Extract the package name from a java string or file and convert it to a file name.

165 javaScriptExports - Extract the Javascript functions marked for export in a file or string.

166 keyCount - Count keys down to the specified level.

167 lll - Log messages including the project name if available.

168 loadArrayArrayFromLines - Load an array of arrays from lines of text: each line is an array of words.

169 loadArrayFromLines - Load an array from lines of text in a string.

170 loadArrayHashFromLines - Load an array of hashes from lines of text: each line is a hash of words.

171 loadHash - Load the specified blessed $hash generated with genHash with %attributes.

172 loadHashArrayFromLines - Load a hash of arrays from lines of text: the first word of each line is the key, the remaining words are the array contents.

173 loadHashFromLines - Load a hash: first word of each line is the key and the rest is the value.

174 loadHashHashFromLines - Load a hash of hashes from lines of text: the first word of each line is the key, the remaining words are the sub hash contents.

175 makeDieConfess - Force die to confess where the death occurred

176 makePath - Make the path for the specified file name or folder.

177 matchPath - Given an absolute path find out how much of the path actually exists.

178 max - Find the maximum number in a list confessing to any ill defined values.

179 maximumLineLength - Find the longest line in a string

180 md5FromGuid - Recover an md5 sum from a guid.

181 mergeHashesBySummingValues - Merge the specified hashes by summing their values

182 microSecondsSinceEpoch - Micro seconds since unix epoch.

183 min - Find the minimum number in a list confessing to any ill defined values.

184 nameFromFolder - Create a name from the last folder in the path of a file name.

185 nameFromString - Create a readable name from an arbitrary string of text.

186 nameFromStringRestrictedToTitle - Create a readable name from a string of text that might contain a title tag - fall back to nameFromString if that is not possible.

187 newProcessStarter - Create a new process starter with which to start parallel processes up to a specified $maximumNumberOfProcesses maximum number of parallel processes at a time, wait for all the started processes to finish and then optionally retrieve their saved results as an array from the folder named by $transferArea.

188 newServiceIncarnation - Create a new service incarnation to record the start up of a new instance of a service and return the description as a Data::Exchange::Service Definition hash.

189 newUdsr - Create a communicator - a means to communicate between processes on the same machine via Udsr::read and Udsr::write.

190 newUdsrClient - Create a new communications client - a means to communicate between processes on the same machine via Udsr::read and Udsr::write.

191 newUdsrServer - Create a communications server - a means to communicate between processes on the same machine via Udsr::read and Udsr::write.

192 numberOfCpus - Number of cpus scaled by an optional factor - but only if you have nproc.

193 numberOfLinesInFile - The number of lines in a file

194 numberOfLinesInString - The number of lines in a string.

195 nws - Normalize white space in a string to make comparisons easier.

196 overrideAndReabsorbMethods - Override methods down the list of @packages then reabsorb any unused methods back up the list of packages so that all the packages have the same methods as the last package with methods from packages mentioned earlier overriding methods from packages mentioned later.

197 overrideMethods - For each method, if it exists in package $from then export it to package $to replacing any existing method in $to, otherwise export the method from package $to to package $from in order to merge the behavior of the $from and $to packages with respect to the named methods with duplicates resolved if favour of package $from.

198 overWriteBinaryFile - Write a binary string to a file after creating a path to the file if necessary and return the name of the file on success else confess.

199 overWriteFile - Write a unicode utf8 string to a file after creating a path to the file if necessary and return the name of the file on success else confess.

200 pad - Pad the specified $string to a multiple of the specified $length with blanks or the specified padding character to a multiple of a specified length.

201 parseCommandLineArguments - Classify the specified array of words referred to by $args into positional and keyword parameters, call the specified sub with a reference to an array of positional parameters followed by a reference to a hash of keywords and their values then return the value returned by this sub.

202 parseDitaRef - Parse a dita reference into its components optionally supplying a base file name for the file component and the topic id of the current topic as the default for the topicId if not present.

203 parseFileName - Parse a file name into (path, name, extension) considering .

204 parseIntoWordsAndStrings - Parse a $string into words and quoted strings with an optional $limit on the number of words and strings to parse out

205 parseS3BucketAndFolderName - Parse an S3 bucket/folder name into a bucket and a folder name removing any initial s3://.

206 parseXmlDocType - Parse an Xml DOCTYPE and return a hash indicating its components

207 partitionStringsOnPrefixBySize - Partition a hash of strings and associated sizes into partitions with either a maximum size $maxSize or only one element; the hash %Sizes consisting of a mapping {string=>size}; with each partition being named with the shortest string prefix that identifies just the strings in that partition.

208 perlPackage - Extract the package name from a perl string or file.

209 powerOfTwo - Test whether a number is a power of two, return the power if it is else undef.

210 printFullFileName - Print a file name on a separate line with escaping so it can be used easily from the command line.

211 printQw - Print an array of words in qw() format.

212 processFilesInParallel - Process files in parallel using (8 * the number of CPUs) processes with the process each file is assigned to depending on the size of the file so that each process is loaded with approximately the same number of bytes of data in total from the files it processes.

213 processInParallel - Depending on $sqrtMode process elements in parallel or square root parallel with a maximum of $maximumNumberOfProcesses processes; process each element with sub $parallel and the results of processing all elements with $results where the elements are taken from @array.

214 processJavaFilesInParallel - Process java files of known size in parallel using (the number of CPUs) processes with the process each item is assigned to depending on the size of the java item so that each process is loaded with approximately the same number of bytes of data in total from the java files it processes.

215 processSizesInParallel - Process items of known size in parallel using (8 * the number of CPUs) processes with the process each item is assigned to depending on the size of the item so that each process is loaded with approximately the same number of bytes of data in total from the items it processes.

216 processSizesInParallelN - Process items of known size in parallel using the specified number $N processes with the process each file is assigned to depending on the size of the file so that each process is loaded with approximately the same number of bytes of data in total from the files it processes.

217 quoteFile - Quote a file name.

218 readBinaryFile - Read binary file - a file whose contents are not to be interpreted as unicode.

219 readFile - Read a file containing unicode in utf8.

220 readFiles - Read all the files in the specified @folders into a hash

221 readGZipFile - Read the specified $file, containing compressed utf8, through gzip

222 readUtf16File - Read a file containing unicode in utf-16 format.

223 relFromAbsAgainstAbs - Derive a relative file name for the first absolute file name relative to the second absolute file name.

224 reloadHashes - Ensures that all the hashes within a tower of data structures have LValue methods to get and set their current keys.

225 reloadHashes2 - Ensures that all the hashes within a tower of data structures have LValue methods to get and set their current keys.

226 removeDuplicatePrefixes - Remove duplicated leading path components from a file name.

227 removeFilePathsFromStructure - Remove all file paths from a specified $structure to make said $structure testable with is_deeply().

228 removeFilePrefix - Removes a file prefix from an array of files.

229 renormalizeFolderName - Normalize a folder name component by adding a trailing separator.

230 replaceStringWithString - Replace all instances in $string of $source with $target

231 reportAttributes - Report the attributes present in a $sourceFile

232 reportAttributeSettings - Report the current values of the attribute methods in the calling file and optionally write the report to $reportFile.

233 reportExportableMethods - Report the exportable methods marked with #e in a $sourceFile

234 reportReplacableMethods - Report the replaceable methods marked with #r in a $sourceFile

235 reportSettings - Report the current values of parameterless subs in a $sourceFile that match \Asub\s+(\w+)\s*\{ and optionally write the report to $reportFile.

236 retrieveFile - Retrieve a file created via Storable.

237 runInParallel - Process each element of @array in square root parallel with a maximum $maximumNumberOfProcesses processes using sub &$parallel to process an element and then call sub &$results to process all the results returned by &$parallel.

238 runInSquareRootParallel - Process each element of @array in square root parallel with a maximum $maximumNumberOfProcesses processes using sub &$parallel to process an element and then call sub &$results to process all the results returned by &$parallel.

239 s3FileExists - Return (name, size, date, time) for a $file that exists on S3 else () using the specified %options if any.

240 s3ListFilesAndSizes - Return {file=>size} for all the files in a specified $folderOrFile on S3 using the specified %options if any.

241 s3Profile - Return an S3 profile keyword from an S3 option set

242 s3ReadFile - Read from a $file on S3 and write the contents to a local file $local using the specified %options if any.

243 s3ReadString - Read from a $file on S3 and return the contents as a string using specified %options if any.

244 s3WriteFile - Write to a file $fileS3 on S3 the contents of a local file $fileLocal using the specified %options if any.

245 s3WriteString - Write to a $file on S3 the contents of $string using the specified %options if any.

246 saveCodeToS3 - Save source code every $saveCodeEvery seconds by zipping folder $folder to zip file $zipFileName then saving this zip file in the specified S3 $bucket using any additional S3 parameters in $S3Parms.

247 saveSourceToS3 - Save source code.

248 searchDirectoryTreesForMatchingFiles - Search the specified directory trees for the files (not folders) that match the specified extensions.

249 setCombination - Count the elements in sets represented as arrays of strings and/or the keys of hashes

250 setFileExtension - Set the extension of a file to a specified value.

251 setIntersection - Intersection of sets represented as arrays of strings and/or the keys of hashes

252 setIntersectionOverUnion - Returns the size of the intersection over the size of the union of one or more sets represented as arrays and/or hashes

253 setPackageSearchOrder - Set a package search order for methods requested in the current package via AUTOLOAD.

254 setPartitionOnIntersectionOverUnion - Partition a set of sets so that within each partition the setIntersectionOverUnion of any two sets in the partition is never less than the specified $confidence**2

255 setPartitionOnIntersectionOverUnionOfHashStringSets - Partition a set of sets represented by a hash, each hash value being a string containing words and punctuation, each word possibly capitalized, so that within each partition the setPartitionOnIntersectionOverUnionOfSetsOfWords of any two sets of words in the partition is never less than the specified $confidence**2 and the partition entries are the hash keys of the string sets.

256 setPartitionOnIntersectionOverUnionOfSetsOfWords - Partition a set of sets of words so that within each partition the setIntersectionOverUnion of any two sets of words in the partition is never less than the specified $confidence**2

257 setPartitionOnIntersectionOverUnionOfStringSets - Partition a set of sets, each set represented by a string containing words and punctuation, each word possibly capitalized, so that within each partition the setPartitionOnIntersectionOverUnionOfSetsOfWords of any two sets of words in the partition is never less than the specified $confidence**2

258 setPermissionsForFile - Set the permissions for the named file

259 setUnion - Union of sets represented as arrays of strings and/or the keys of hashes

260 showHashes - Create a map of all the keys within all the hashes within a tower of data structures.

261 showHashes2 - Create a map of all the keys within all the hashes within a tower of data structures.

262 squareArray - Create a two dimensional square array from a one dimensional linear array.

263 startProcess - Start new processes while the number of child processes recorded in %$pids is less than the specified $maximum.

264 storeFile - Store a data structure to a file via Storable.

265 stringsAreNotEqual - Return the common start followed by the two non equal tails of two non equal strings or an empty list if the strings are equal.

266 subScriptString - Convert alphanumerics in a string to sub scripts

267 subScriptStringUndo - Undo alphanumerics in a string to sub scripts

268 sumAbsAndRel - Combine zero or more absolute and relative file names starting at the current working folder to get an absolute file name.

269 summarizeColumn - Count the number of unique instances of each value a column in a table assumes.

270 superScriptString - Convert alphanumerics in a string to super scripts

271 superScriptStringUndo - Undo alphanumerics in a string to super scripts

272 swapFilePrefix - Swaps the start of a file name from a $known name to a $new one if the file does in fact start with the $known name otherwise returns the original file name.

273 swapFolderPrefix - Swaps a starting folder of a file name from a known name to a new one if the file does in fact start with the known name and the known name and new name are folders else return the file as is.

274 syncFromS3InParallel - Download from S3 by using "aws s3 sync --exclude '*' --include '.

275 syncToS3InParallel - Upload to S3 by using "aws s3 sync --exclude '*' --include '.

276 temporaryFile - Create a temporary file that will automatically be unlinked during END processing.

277 temporaryFolder - Create a temporary folder that will automatically be rmdired during END processing.

278 timeStamp - hours:minute:seconds

279 trackFiles - Track the existence of files.

280 trim - Remove any white space from the front and end of a string.

281 Udsr::kill - Kill a communications server.

282 Udsr::read - Read a message from the newUdsrServer or the newUdsrClient.

283 Udsr::webUser - Create a systemd installed server that processes http requests using a specified userid.

284 Udsr::write - Write a communications message to the newUdsrServer or the newUdsrClient.

285 unionOfHashesAsArrays - Form the union of the specified hashes as one hash whose values are a array of corresponding values from each hash

286 unionOfHashKeys - Form the union of the keys of the specified hashes as one hash whose keys represent the union.

287 uniqueNameFromFile - Create a unique name from a file name and the md5 sum of its content

288 updateDocumentation - Update documentation for a Perl module from the comments in its source code.

289 updatePerlModuleDocumentation - Update the documentation in a perl file and show said documentation in a web browser.

290 userId - Get or confirm the userid we are currently running under.

291 versionCode - YYYYmmdd-HHMMSS

292 versionCodeDashed - YYYY-mm-dd-HH:MM:SS

293 waitForAllStartedProcessesToFinish - Wait until all the processes started by startProcess have finished.

294 wellKnownUrls - Short names for some well known urls

295 writeBinaryFile - Write a binary string to a new file that does not already exist after creating a path to the file if necessary and return the name of the file on success else confess if a problem occurred or the file does already exist.

296 writeFile - Write a unicode utf8 string to a new file that does not already exist after creating a path to the file if necessary and return the name of the file on success else confess if a problem occurred or the file already exists.

297 writeFiles - Write the values of a hash into files identified by the key of each value using overWriteFile optionally swapping the prefix of each file from $old to $new

298 writeGZipFile - Write a unicode utf8 string through gzip to a file.

299 writeStructureTest - Write a test for a data $structure with file names in it.

300 wwwDecode - Percent decode a url per: https://en.

301 wwwEncode - Percent encode a url per: https://en.

302 xxx - Execute a shell command optionally checking its response.

303 xxxr - Execute a bash command $cmd on the server whose ip address is located in awsIp using the optional $userid supplied or the one listed in .

304 yyy - Execute a block of shell commands line by line after removing comments - stop if there is a non zero return code from any command.

305 zzz - Execute lines of commands after replacing new lines with && then check that the pipeline execution results in a return code of zero and that the execution results match the optional regular expression if one has been supplied; confess() to an error if either check fails.

Installation

This module is written in 100% Pure Perl and, thus, it is easy to read, comprehend, use, modify and install via cpan:

  sudo cpan install Data::Table::Text

Author

philiprbrenan@gmail.com

http://www.appaapps.com

Copyright

Copyright (c) 2016-2019 Philip R Brenan.

This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.

Acknowledgements

Thanks to the following people for their help with this module:

mim@cpan.org

Testing on windows