Este material didáctico corresponde al último tema del Curso Fundamental de Posgrado ofrecido en el marco de los Programas de Posgrado en Ciencias Bioquímicas y Ciencias Biomédicas de la Universidad Nacional Autómoma de México (UNAM), semestre 2020-1, e impartido en el Centro de Ciencias Genómicas (CCG), Cuernavaca, Morelos, México.
El material docente del curso_perl4bioinfo lo distribuyo públicamente a través de este repositorio GitHub bajo la Licencia No Comercial Creative Commons 4.0
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 Licencse
CC BY-NC 4.0 license
Si tienes instalado git en tu computadora, puedes clonar el repositorio con el comando:
git clone https://github.com/vinuesa/curso_perl4bioinfo.gitPuedes instalar \(git\) fácilmente en Ubuntu usando:
sudo apt install git
Alternativamente, puedes descargar el archivo master.zip
sudo apt install perldoc cpanminus bioperl libstatistics-descriptive-perl libstatistics-distributions-perl
Estos módulos están en el directorio \(lib\) del repositorio GitHub.
sudo apt install muscle clustalo fasttree phyml
Estos binarios (Linux, 64bit) están en el directorio \(bin\) del repositorio GitHub.
Perl usa paquetes para particionar o dividir en compartimentos el espacio global de identificadores, es decir, de los nombres de variables, subrutinas, descriptores de archivos y formatos.
Cuando ejecutamos un script de Perl, todas las variables y nombres de subrutinas o descriptores de archivos (file handles) están definidos en el paquete principal, llamado package main.
Cada identificador global tiene de hecho dos partes: su nombre de paquete y su identificador. Estas dos “piezas” están separadas la una de la otra por un doble doble-punto ::
Así por ejemplo, la variable \(stats::x* es la variable global *\)x, que reside en el paquete \(stats\).
\(main::x* es la variable *\)x definida en el paquete \(main\). Ambas variables son completamente independientes.
De manera muy simple, podríamos definir a un módulo como la unidad de re-uso y distribución de código en Perl. Más formalmente, se trata de un paquete definido en un archivo que lleva el mismo nombre del paquete y tiene la terminación \(.pm\), es decir, algo como NombrePaquete.pm
Los módulos contienen funciones relacionadas y están diseñados para ser usados por programas que llaman a dichos módulos, o incluso otros módulos que llaman a las funciones contenidas en diversos módulos externos.
Cada módulo tiene una interfaz pública, que permite el acceso a las funciones y variables definidas en ellos. Llamamos clases a los módulos con interfaz dirigida a objetos. Como tales, son paquetes
Imagina que tenemos dos programas independientes y decidimos crear un tercero que combina las mejores características de ambos.
Al copiar y pegar funciones y variables de ambos en el nuevo, nos damos cuenta que comparten nombres, como la variable escalar $contador y el arreglo \(@misGenomas\).
Si no se modifican sus nombres, habrá colisión (interferencia) entre las variables.
La solución son los paquetes, que particionan el espacio global de identificadores.
Asignando las variables, subrutinas y descriptores de archivos de cada programa fuente a un paquete diferente, podremos usarlos sin problemas desde un tercer programa que los llama con su nombre completamente calificado, es decir, incluyendo el nombre del paquete.
los paquetes evitan colisiones entre nombres importados a programas de Perl, permitiendo así importar las funcionalidades ofrecidas por diferentes módulos a un mismo programa de Perl.
Los módulos a su vez nos ayudan a agrupar variables y funciones relacionadas en archivos individuales, facilitando así a la organización (modularización) del código, favoreciendo el re-uso de funciones (o métodos).
Este miniprograma ilustra el concepto de paquetes como divisores del espacio de nombres para evitar colisiones entre símbolos.
#!/usr/bin/env perl
# programa: paquetes1.pl
# El concepto de paquetes como divisores del espacio de nombres para evitar colisiones entre simbolos
# estamos en el paquete principal "main"
$secuencia = 'MVLLIATG';
# declaramos un nuevo paquete y declaramos una variable en dicho paquete
package Seq1;
$secuencia = 'AAAAAAAA';
# declaramos un segundo paquete y declaramos una variable en dicho paquete
package Seq2;
$secuencia = 'CCCCCCCC';
# regresamos al paquete main e imprimimos los valores de las 3 variables escalares secuencia
package main;
# imprimimos las secuencias, usando las variables completamente calificadas
print "\n\tmain es: $secuencia"
."\n\tSeq1 es: $Seq1::secuencia"
."\n\tSeq2 es: $Seq2::secuencia\n\n";
##
## main es: MVLLIATG
## Seq1 es: AAAAAAAA
## Seq2 es: CCCCCCCC
Veamos ahora cómo importar al script \(paquetes2.pl\) símbolos (variables) guardados en los archivos extermos Seq1.pm y Seq2.pm, cada uno de los cuales representa un módulo distinto (paquete guardado en un archivo).
## # contents of Seq1.pm
## package Seq1;
## $secuencia = 'AAAAAAAA';
##
## 1;
## ------------------------------------------------------------
## # contents of Seq2.pm
## package Seq2;
## $secuencia = 'CCCCCCCC';
##
## 1;
Como ven, cada archivo inicia con la definición de un paquete con el mismo nombre que el archivo.
Además, los archivos \(*.pm\) terminan con una línea que contiene ‘1;’ Es decir, terminan con un valor verdadero.
La clave está en:
Estos paquetes estan guardados en los archivos Seq1.pm y Seq2.pm, y por tanto representan modulos (aunque todavia muy primitivos y poco funcionales, …)
Ustedes tendrán que editar use lib ‘/path/to/lib’; para que apunte al directorio en el que han guardado los archivos *.pm.
#!/usr/bin/env perl
use strict;
use warnings;
my $host = `hostname`;
# programa: paquetes2.pl
# El concepto de paquetes como divisores del espacio de nombres para evitar colisiones entre simbolos.
# Importanmos simbolos desde dos paquetes externos usando la directiva 'use paquete;'.
# Estos paquetes estan guardados en los archivos Seq1.pm y Seq2.pm, y por tanto representan modulos
# (aunque todavia muy primitivos y poco funcionales, ...)
if ($host eq "alisio")
{
use lib qw(/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code);
}
else
{
# >>> EDITEN ESTA LINEA PARA APUNTAR AL PATH CORRECTO
# EN EL QUE SE ENCUENTRAN LOS ARCHIVOS '*pm' <<<
use lib qw(/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code);
}
use Seq1;
use Seq2;
my $secuencia = 'MVLLIATG';
# imprimimos los valores de las 3 variables escalares secuencia
print "\n\tmain es: $secuencia"
."\n\tSeq1 es: $Seq1::secuencia"
."\n\tSeq2 es: $Seq2::secuencia\n\n";
##
## main es: MVLLIATG
## Seq1 es: AAAAAAAA
## Seq2 es: CCCCCCCC
El módulo es la unidad de reciclado de código en Perl. Para acceder a su funcionalidad, el módulo debe “exportar” funciones y variables, mientras que el script que quiere hacer uso de ella debe importar dichos símbolos.
Las directivas use y require cargan el módulo en tu programa, pero tienen un efecto o semántica diferentes.
¿Qué significa ésto?
Por ello, una vez importado, el programa que llama al módulo no require ya usar el path completo para acceder al archivo *pm. Asímismo, un símbolo importado con \(use\), ya no require del uso del nombre completamente cualificado del paquete. Es decir, podemos usar las variables y subrutinas importadas como si fueran parte del paquete del script que las importa.
En esta sesión del curso vamos a ir escribiendo progresivamente el módulo \(PhyloTools\) y el script \(run\_phyloTools.pl\).
Con ellos podremos hacer un análisis filogenético completo, incluyendo el alineamiento múltiple de secuencias, la estima filogenética bajo máxima verosimilitud, usando diferentes algoritmos y modelos, e incluso evaluar el ajuste de diversos modelos a los datos, usando tanto pruebas de razones de versomilitud (LRTs) como pruebas basadas en el contenido de información de Akaike (AIC).
Iremos construyendo dicho módulo y scipt paso a paso, explicando en el camino los componentes de un módulo.
Para empezar, descarguen y exploren los programas run_muscle.pl, \(run\_aligners.pl\), así como los módulos asociados \(PhyloTools1.pm\) y \(PhyloTools2.pm\)
La principal diferencia entre estos módulos radica en que el primero de ellos no exporta las subrutinas, mientras que el segundo sí lo hace.
Por ello, en \(run\_muscle.pl\) necesitamos llamar a la función de \(PhyloTools1.pm\) usando la declaración completa \(PhyloTools1::run\_muscle\).
En \(run\_aligners.pl\) podemos simplemente llamar a la subrutina \(run\_muscle\), ya que es exportada por \(PhyloTools2.pm\) gracias al uso del módulo Exporter, que viene con Perl.
Veamos los detalles:
## # >>> Contents of PhyloTools1.pm <<< #
## # Pablo Vinuesa, http://www.ccg.unam.mx/~vinuesa
## # 2018 CCG-UNAM, Mexico,
## # Modulo de ejemplo del curso "Introduccion a la programacion en Perl para bioinformatica"
##
## package PhyloTools;
## use strict;
## use warnings;
##
## use File::Basename;
## use Carp;
##
## my $muscle_bin = '/usr/bin/muscle';
##
## my @binaries = ($muscle_bin);
##
## foreach my $bin (@binaries)
## {
## check_is_installed($bin);
## }
## #--------------------------------------------------------------------------------------
## #---------------------------------- SUBROUTINES ---------------------------------------
## #--------------------------------------------------------------------------------------
##
## sub check_is_installed
## {
## my @binaries = @_;
## foreach my $bin (@binaries)
## {
## if( ! -x "$bin")
## {
## croak "\n#ERROR! $bin is not installed. Please install or check path setting\n\tExiting now!\n";
## }
## }
## }
## #--------------------------------------------------------------------------------------
##
## sub run_muscle
## {
## my($infile, $clean, $verbosity) = @_;
##
## my $filename = basename($infile);
## my( $file_basename, $file_ext) = split(/\./,$filename);
##
## my $tmpfile1 = $file_basename . "_tmp1.mus";
## my $tmpfile2 = $file_basename . "_tmp2.mus";
## my $outfile = $file_basename . "_musAln.$file_ext";
##
## # run muscle with x2 refinement rounds after the primary alignment; note, -stable is not available anymore in muscle 3.8.31
## print "# sub run_muscle is running $muscle_bin < $infile > $tmpfile1 -quiet ...\n" if $verbosity ;
## system(" $muscle_bin < $infile > $tmpfile1 -quiet ");
## system(" $muscle_bin < $tmpfile1 > $tmpfile2 -refine -quiet ");
## system(" $muscle_bin < $tmpfile2 > $outfile -refine -quiet ");
##
## # clean file
## if($clean==1)
## {
## print "# will remove tmp files $tmpfile1, $tmpfile2\n" if $verbosity ;
## unlink $tmpfile1, $tmpfile2;
## }
##
## # check the output file is there
## if(! -s $outfile)
## {
## print "# ERROR; outfile $outfile is empty\n";
## return;
## }
## else
## {
## print "# run_muscle() returned aligned outfile $outfile\n";
## return $outfile;
## }
## }
## #--------------------------------------------------------------------------------------
##
## 1;
## # >>> Contents of run_muscle.pl <<< #
## #!/usr/bin/env perl
##
## # 1. load modules and pragmas
## use strict;
## use warnings;
## use Carp;
## use Cwd;
## use File::Basename;
##
## my $cwd = getcwd;
## my $host = `hostname`;
##
## # >>> Note the use of a BEGIN{ } block, to set the path in @INC at compile time!
## if ($host eq "Tenerife")
## {
## # BEGIN { unshift @INC, '/export/data/dbox/Dropbox/Cursos/perl4bioinfo/my_code' ;}
## use lib qw(/export/data/dbox/Dropbox/Cursos/perl4bioinfo/my_code) ;
## }
## else
## {
## # >>> EDIT THIS LINE TO SET THE CORRECT PATH TO THE *pm FILES <<<
## # BEGIN { unshift @INC, '/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code' ;}
## use lib qw(/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code) ;
## }
##
## use PhyloTools1;
##
## my $VERSION = 0.2; # v0.2_16Oct2018
## my $progname = basename($0);
##
## print_help() unless @ARGV;
##
## my $fasta_file = shift @ARGV;
##
## croak "\n# ERROR: no fasta file $fasta_file in dir $cwd!\n\n" if ! -s $fasta_file;
##
## # run muscle
## print "# will run muscle to align file: $fasta_file\n";
## PhyloTools::run_muscle($fasta_file, 1);
##
## #-----------------------------------------------------------
## sub print_help
## {
## print <<"EOF";
##
## USAGE:
## $progname version $VERSION requires a fasta file name as a single argument on the command line
##
## AIM:
## will run muscle to align the provided fasta file
##
## CWD:
## $cwd
##
## EOF
## exit 0
## }
NOTAS:
Si lo llamamos sin argumentos, el script imprime la ayuda sobre cómo usarlo, desde la función \(print\_help\), mostrada arriba.
/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code/run_muscle.pl
##
## USAGE:
## run_muscle.pl version 0.2 requires a fasta file name as a single argument on the command line
##
## AIM:
## will run muscle to align the provided fasta file
##
## CWD:
## /home/vinuesa/Cursos/perl4bioinfo
##
Ahora que sabemos que tenemos que pasar una extensión de archivo FASTA, volvamos a llamarlo:
script_dir=/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code/
$script_dir/run_muscle.pl GDP_12_prokEuc.faa
## # will run muscle to align file: GDP_12_prokEuc.faa
## # run_muscle() returned aligned outfile GDP_12_prokEuc_musAln.faa
Como comentábamos arriba, \(PhyloTools1.pm\) no exporta las subrutinas, mientras que \(PhyloTools2.pm\) sí lo hace, gracias al uso del módulo core \(Exporter\), tal y como se ve en la cabecera del archivo \(PhyloTools2.pm\), mostrada seguidamente:
head -15 /home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code/PhyloTools2.pm
## # Pablo Vinuesa, http://www.ccg.unam.mx/~vinuesa
## # 2018 CCG/UNAM, Mexico,
## # Modulo de ejemplo del curso "Introduccion a la programacion en Perl para bioinformatica"
## # el codigo y tutorial estan disponibles en: https://github.com/vinuesa/curso_perl4bioinfo
##
## package PhyloTools2;
## use strict;
## use warnings;
##
## our $VERSION = '0.2'; # v0.2 17 Nov. 2018
## our(@ISA, @EXPORT); # our($VAR1, @ARR1 ...) are package global symbols!
## use Exporter;
##
## @ISA = qw(Exporter); # activamos el proceso de exportacion
## @EXPORT = qw( run_muscle run_clustalo); # exportamos automaticamente las subrutinas indicadas
Un módulo puede hacer disponibles variables y funciones a otros módulos o scripts mediante un proceso denominado exportación, un proceso que se inicia llamando a \(import\).
El módulo core \(Exporter\) implementa un método \(import\) estándar para módulos, que permite exportar símbolos desde un módulo. \(Exporter\) utiliza las variables globales \(@EXPORT\_OK\) y \(@EXPORT\), que contienen una lista de símbolos para exportar, cuando sean requeridos.
Basados en la documentación de \(Exporter\), que podemos consultar con el comando \(perldoc\ Exporter\), vemos que:
package YourModule; require Exporter; # load the Exporter module from @INC @ISA = qw(Exporter); # use YourModule implicitly calls the method YourModule->import() @EXPORT_OK = qw(munge frobnicate); # symbols to export on request by calling script
y en el script que llama al módulo escribimos:
use YourModule qw(frobnicate); # import listed symbols; implicitly calls the method YourModule->import() frobnicate($left, $right) # calls YourModule::frobnicate()
Veamos la cabecera de nuestro script \(run\_aligners.pl\), que contiene las directivas:
head -30 /home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code/run_aligners.pl
## #!/usr/bin/env perl
##
## use strict;
## use warnings;
##
## use File::Basename;
## use Cwd;
## use Carp;
##
## my $cwd = cwd();
## my $hostname = '';
##
## if ($hostname eq "Tenerife")
## {
## # BEGIN { unshift @INC, '/export/data/dbox/Dropbox/Cursos/perl4bioinfo/my_code' ;}
## use lib qw(/export/data/dbox/Dropbox/Cursos/perl4bioinfo/my_code) ;
## }
## else
## {
## # >>> EDIT THIS LINE TO SET THE CORRECT PATH TO THE *pm FILES <<<
## # BEGIN { unshift @INC, '/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code' ;}
## use lib '/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code' ;
## }
##
## use PhyloTools2; # use PhyloTools2 qw(run_clustalo run_muscle); # <<< if using @EXPORT_OK()
##
## my $VERSION = 0.3; # v0.3_22Oct2018
## my $progname = basename($0);
##
## print_help() unless @ARGV;
Gracias a ello, en \(run\_aligners.pl\) la llamada a la función se hace directamente:
... if( $alignment_algorithm eq "muscle") { my $mus_aln = run_muscle($fasta_file, 1); # <== llamada directas a la sub } else { my $cluo_aln = run_clustalo($fasta_file); # <== llamada directas a la sub } ...
Corramos el script sin argumentos para ver la ayuda:
/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code/run_aligners.pl
##
## USAGE:
## run_aligners.pl version 0.3 requires 2 arguments:
##
## - Required
## 1. A fasta file name
##
## - Optional
## 2. an alignment algorithm name <clustalo|muscle>
##
## AIM:
## will run clustalo or muscle to align the input fasta file
##
## CWD:
## /home/vinuesa/Cursos/perl4bioinfo
##
Ahora con argumentos:
/home/vinuesa/Dropbox/Cursos/perl4bioinfo/my_code/run_aligners.pl GDP_12_prokEuc.faa
## # &run_clustalo is running /usr/local/bin/clustalo -i GDP_12_prokEuc.faa -o GDP_12_prokEuc_cluoAln.faa --force
## # &run_clustalo returned aligned outfile GDP_12_prokEuc_cluoAln.faa
Es importante resaltar que la interfaz de usuario del módulo \(miModulo.pm\) puede:
@EXPORT(&myFunc1 $VAR1);
@EXPORT_OK(&myFunc1 $VAR1);
use miModulo qw(&myFunc1 $VAR1);
. Entonces podemos simplemente usar \(myFunc()\)El método \(import\) heredado del paquete \(Exporter\) implícitamente llamado cuando el script principal usa \(use\ myModule\), busca variables globales en \(myModule\).
Por tanto, para poder exportar variables desde un módulo, éstas tienen que ser globales. Dado que usamos el pragma \(use\ strict;\), necesitamos declarar a las variables globales con \(our\).
package PackageName; use strict; use warnings; our(@ISA, @EXPORT, $VERSION); use Exporter; $VERSION = '0.01'; @ISA = qw(Exporter); @EXPORT = qw(sub1 sub2 …); sub sub1 { # tu código } sub sub2 { # tu código } 1; # recuerda que el módulo debe terminar retornando un valor verdadero!
Un módulo no está completo si no tiene documentación.
En general, toda la documentación de Perl se escribe en formato POD (Plain Old Documentation). Se trata de un lenguaje de marcado que permite incluir bloques de documentación en un script o módulo de perl y su lectura desde la línea de comandos usando el programa \(perldoc\).
Cuando el intérprete \(perl\) encuentra un signo = al inicio de una linea, tal como =head1, cambia al modo de procesamiento de POD, hasta que encuentra una línea que inicia con =cut.
Para compilar el código, perl ignora estos bloques (como muchos programadores …).
Aprende a usar \(POD\) estudiando \(perldoc\ perlpod\) (y \(perldoc\ perlpodspec\))
¿Dónde busca Perl los módulos instalados en el sistema?
El compilar Perl, se pasa una lista de directorios, que es sistema-específica, en la que se van a guardar los módulos estándar que se distribuyen con Perl, así como módulo instalados con poderes de superusuario.
La lista de esos directorios la exporta Perl al arreglo \(@INC\)
Para ver los detalles de configuración de la compilación del intérprete \(perl\), usa la siguiente línea, que incluye, al final de la copiosa salida, los directorios que se incluyen en el arreglo \(@INC\).
perl -V | tail -10; # imprime sólo las últimas líneas de la copiosa salida
## @INC:
## /etc/perl
## /usr/local/lib/x86_64-linux-gnu/perl/5.26.1
## /usr/local/share/perl/5.26.1
## /usr/lib/x86_64-linux-gnu/perl5/5.26
## /usr/share/perl5
## /usr/lib/x86_64-linux-gnu/perl/5.26
## /usr/share/perl/5.26
## /usr/local/lib/site_perl
## /usr/lib/x86_64-linux-gnu/perl-base
Cualquier módulo instalado en dichos directorios será accesible desde cualquier script que se corra en el sistema al invocar la directiva \(use\ module\)
Perl viene con una gran cantidad de módulos pre-instalados y listos para ser usados. Por ejemplo, la mayor parte de los > 66MB de la distribución v.5.26.1 corresponde a módulos, concretamente 893!
Puedes usar el módulo \(Module::CoreList\) para ver o contar los módulos que vienen con cada distribución.
¿Sabes qué versión de Perl estás corriendo?
perl -v; # imprime la versión de Perl
##
## This is perl 5, version 26, subversion 1 (v5.26.1) built for x86_64-linux-gnu-thread-multi
## (with 67 registered patches, see perl -V for more detail)
##
## Copyright 1987-2017, Larry Wall
##
## Perl may be copied only under the terms of either the Artistic License or the
## GNU General Public License, which may be found in the Perl 5 source kit.
##
## Complete documentation for Perl, including FAQ lists, should be found on
## this system using "man perl" or "perldoc perl". If you have access to the
## Internet, point your browser at http://www.perl.org/, the Perl Home Page.
¿Sabes qué versión del kernel Linux estás corriendo y qué distribución?
uname -a; # imprime la versión del kernel de Linux
echo '-----------------------------------------------------------------------'
lsb_release -a # imprime detalles de la distribución de Linux
## Linux alisio 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:11 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
## -----------------------------------------------------------------------
## No LSB modules are available.
## Distributor ID: Ubuntu
## Description: Ubuntu 18.04.3 LTS
## Release: 18.04
## Codename: bionic
Ejecuta este one-liner, para ver el número de \(módulos core\) en tu distirbución de Perl.
perl -MModule::CoreList -e 'print join "\n", Module::CoreList->find_modules(qr/.*/), "\n"' | wc -l
## 893
Es decir, Ubuntu 18.04.1 LTS corre Perl v5.26.1, con 893 módulos core.
Además de estos módulos de la distribución estándar, los programadores de Perl pueden usar cualquiera de los >> 100,000 módulos existentes en CPAN (Comprehensive Perl Archive Network).
En conjunto, estos módulos permiten al programador de Perl escribir con gran facilidad programas para todo tipo de aplicaciones, desde programación Web y de bases de datos a estadística, graficado y bioinformática, por mencionar sólo algunas de las áreas relevantes para este curso.
Veremos cómo buscar módulos en CPAN y su instalación un poco más adelante. Ahora nos enfocaremos a explorar algunos módulos de la distribución estándar, aprendiendo a manejar \(perldoc\) y a usar módulos con interfaz funcional y dirigida a objetos.
\(perldoc\) es un programa muy útil para explorar la copiosa documentación que viene con Perl y cada uno de sus módulos. Veamos algunos ejemplos:
y muchos, muchos más …
#!/usr/bin/env perl
use File::Basename;
$fullname = '/home/user/bin/my_perl_script.pl';
@suffixlist = qw(pl pm);
($name,$path,$suffix) = fileparse($fullname,@suffixlist);
$name = fileparse($fullname,@suffixlist);
$basename = basename($fullname,@suffixlist);
$dirname = dirname($fullname);
print "$name | $basename | $dirname | $suffix\n"
## my_perl_script. | my_perl_script. | /home/user/bin | pl
El módulo \(File::Basename\) detecta sobre qué tipo de sistema está corriendo, parseando correctamente los delimitadores de directorio, bien sean tipo UNIX ‘/’ o tipo Windows ‘\’, permitiendo escribir código portable, que corre bien en cualquier tipo de sistema operativo.
A medida que nuestro código se hace más complejo y necesitamos pasarle más parámetros, hacerlo como argumentos posicionales en la línea de comandos se hace cada vez más problemático.
Con el módulo base \(Getopt::Std\) podemos pasar fácilmente switches y parámetros como se muestra la sección de SYNOPSIS de la ayuda del módulo, la cual imprimimos con ‘\(perldoc\ Getopt::Std\)’:
use Getopt::Std; # -o & -i are boolean flags, -f takes an argument. Values in %opts getopts('oif:', \%opts);
Veamos como ejemplo el script \(LRT\_calculator.pl\). Si lo llamamos sin argumentos, imprime la ayuda:
. ./set_script_dir_by_hostname
$script_dir/LRT_calculator.pl
##
## LRT_calculator.pl vers. 0.1 usage [options]:
## -h this help message
## -l lnL0 (required)
## -L lnL1 (required)
## -d df (required)
## -a alpha (optional, default:0.05)
##
## AIM:
## LRT_calculator.pl uses as input the -lnL scores of a pair of nested H1 and H0 models
## to calculate the corresponding LRT statistic [LRT = 2(lnL H1 - lnL H0)],
## and compute its significance at a user-defined alpha (critical value).
##
## USAGE EXAMPLE:
## LRT_calculator.pl -l -19955.541 -L -19953.1245 -d 3
## LRT_calculator.pl -l -19955.541 -L -19950.1245 -d 3
##
Veamos ahora las líneas clave del script que hacen uso de \(Getop::Std\)
my $a = 0.05; # set default alpha my (%opts,$lnL0,$lnL1,$df); getopts('l:L:d:a:h', \%opts); if(($opts{'h'})||(scalar(keys(%opts))==0)) { print_help(); } if(defined($opts{'h'})){ print_help(); } if(defined($opts{'l'})){ $lnL0 = $opts{'l'}; } else{ die "ERROR: no lnL score for the null hypothesis (lnL0) provided\n\n"; } if(defined($opts{'L'})){ $lnL1 = $opts{'L'}; } else{ die "ERROR: no lnL score for the alternate hypothesis (lnL1) provided\n\n"; } if(defined($opts{'d'})){ $df = $opts{'d'}; } else{ die "ERROR: no degrees of freedom (df) provided\n\n"; } if(defined($opts{'a'})){ $a = $opts{'a'}; }
Y para finalizar, corramos el script:
. ./set_script_dir_by_hostname
$script_dir/LRT_calculator.pl -l -19955.541 -L -19950.1245 -d 4
## LRT_calculator.pl v.0.1 running with the following parameters:
##
## lnL0=-19955.541, lnL1=-19950.1245, df=4, q=0.05
##
##
## LRT=10.8329999999987 | Chi-squared-crit-val (df=4; q=0.05) = 9.4877 | p-val=0.028506
##
## >>> Significant ChiSq test! pchisq(0.028506) < alpha(0.05); LRT(10.8329999999987) > crit.val(9.4877) ==> reject the null model!
Noten que el órden de los parámetros no importa
. ./set_script_dir_by_hostname
$script_dir/LRT_calculator.pl -d 5 -L -19950.1245 -l -19955.541 -a 0.01
## LRT_calculator.pl v.0.1 running with the following parameters:
##
## lnL0=-19955.541, lnL1=-19950.1245, df=5, q=0.01
##
##
## LRT=10.8329999999987 | Chi-squared-crit-val (df=5; q=0.01) = 15.086 | p-val=0.054794
##
## >>>Non-significant ChiSq test! pchisq(0.054794) > alpha(0.01); LRT(10.8329999999987) <= crit.val(15.086) ==> cannot reject the null model!
Vimos arriba que la distribución estándar de Perl trae muchos módulos. Pero existen mucho más. CPAN es el repositorio público de módulos de Perl. Lo accesan en https://www.cpan.org/.
Welcome to CPAN
The Comprehensive Perl Archive Network (CPAN) currently has 184,975 Perl modules
in 40,530 distributions, written by 13,870 authors, mirrored on 255 servers.
...
¡No dejen de visitralo! Es un repositorio GIGANTESCO! Tiene mucha información y código: 184,975 Perl modules!!! Todos los lenguajes modernos tienen sus repositorios. Pero CPAN posiblemente sea el más grande.
Uno de los lemas de Perl es el de “no reinventar la rueda”. Un programador avanzado de Perl, además de dominar la sintaxis del lenguaje y conocer sus idiomas, tiene un conocimiento amplio de CPAN, haciendo uso extensivo de los recursos allí disponibles. Será realmente difícil que no encuentres un módulo en CPAN para ayudarte en resolver tus proyectos de programación.
Para buscar módulos en CPAN, lo mejor es usar uno de los buscadores especializados como Search-CPAN! Visita http://search.cpan.org/.
En este buscador pueden buscar por nombre de módulo o autor.
Una lista de “top-CPAN-authors” pueden verla aquí: http://thegestalt.org/simon/perl/wholecpan.html
Por ejemplo, hagan una búsqueda con el término Statistics para ver qué módulos encuentran.
Si bien ya habíamos corrido \(LRT\_calculator.pl\), no habiamos visto las líneas de llamada al módulo.
use Statistics::Distributions; sub LRT_significance_calculator { my ( $lnL0, $lnL1, $df, $a ) = @_; my $LRT = 2*( $lnL1 - $lnL0 ); my $qchisq=Statistics::Distributions::chisqrdistr($df,$a); my $pchisq=Statistics::Distributions::chisqrprob($df,$LRT); print STDOUT "\n\tLRT=$LRT | Chi-squared-crit-val (df=$df; q=$a) = $qchisq | p-val=$pchisq\n\n"; return($LRT,$pchisq,$qchisq); }
my ($LRT,$pchisq,$qchisq)=LRT_significance_calculator($lnL0, $lnL1, $df, $a); if ($pchisq <= $a){ print ">>> Significant ChiSq test! pchisq($pchisq) < alpha($a); LRT($LRT) > crit.val($qchisq) ==> reject the null model! \n\n"} else{ print ">>>Non-significant ChiSq test! pchisq($pchisq) > alpha($a); LRT($LRT) <= crit.val($qchisq) ==> cannot reject the null model!\n\n"}
Sencillo ¿veradad?. Revisen arriba, en la sección “2.4.2 Getopt::StdGetopt::Std - Process single-character switches with switch clustering” ejemplos de llamada al script \(LRT\_calculator.pl\).
Veamos ahora cómo insatalar módulos de CPAN. Tenemos varias opciones para ello. Sólo revisaremos algunas de ellas, en base a nuestros permisos y necesidades. Veamos algunos escenarios. Como ejemplo, veamos opciones para instalar el módulo \(Statistics::Distributions\) usado por el script \(LRT\_calculator.pl\) arriba mencionado.
Aquí tenemos nuevamente varias opiciones.
apt-cache search Statistics::Distributions
sudo apt install libstatistics-descriptive-perl
Si bien esta alternativa posiblemente no instalará la última versión de algunos módulos, sí permitirá que el sistema operativo automáticamente actualize el módulo, cuando una n nueva versión aparezca en el repositorio de Debian o Ubuntu, facilitando mucho el mantenimiento de múltiples módulos en el sistema. Es la vía que recomiendo.
Cuando trabajamos en un servidor, generalmente no tenemos permisos de administrador, por lo que no podemos usar la opción indicada arriba. En ese escenario, podemos:
Veamos este segundo escenario. Vamos a instalar \(Statistics::Distributions\) que podemos encontrar aquí: https://metacpan.org/pod/Statistics::Distributions#AVAILABILITY
mkdir -p $HOME/CPAN/downloads cd $HOME/CPAN/downloads wget –c https://cpan.metacpan.org/authors/id/M/MI/MIKEK/Statistics-Distributions-1.02.tar.gz tar –xvzf Statistics-Distributions-1.02.tar.gz cd Statistics-Distributions-1.02 # Si no tienes poderes de administrador, instala el módulo en un directorio al que tengas acceso, por ejemplo: perl Makefile.PL INSTALL_BASE = $HOME/CPAN/ make make test make install
Algunas distribuciones usan un archivo \(Build.PL\) para instalar módulos. El procedimiento es equivalente:
perl Buil.PL --install_base = $HOME/CPAN/ perl Build Perl Build test Perl Build install
Una opción muy conveniente (mi favorita) para manejar módulos es mediante el módulo \(cpanm\) CPANminus, que puedes descargar desde aquí: https://cpan.metacpan.org/authors/id/M/MI/MIYAGAWA/App-cpanminus-1.7044.tar.gz. No es parte aún de la distribución estándar, pero es un módulo muy popular y útil.
En sistemas Linux/Debian puedes instalarlo en tu máquina con:
sudo apt install cpanm
Una vez instalado, explora la documentación con \(perldoc\ cpanm\)
Muestro la sección de SYNOPSIS
NAME
cpanm - get, unpack build and install modules from CPAN
SYNOPSIS
cpanm Test::More # install Test::More
cpanm MIYAGAWA/Plack-0.99_05.tar.gz # full distribution path
cpanm http://example.org/LDS/CGI.pm-3.20.tar.gz # install from URL
cpanm ~/dists/MyCompany-Enterprise-1.00.tar.gz # install from a local file
cpanm --interactive Task::Kensho # Configure interactively
cpanm . # install from local directory
cpanm --installdeps . # install all the deps for the current directory
cpanm -L extlib Plack # install Plack and all non-core deps into extlib
cpanm --mirror http://cpan.cpantesters.org/ DBI # use the fast-syncing mirror
cpanm --from https://cpan.metacpan.org/ Plack # use only the HTTPS mirror
Instalemos ahora el módulo \(Statistics::Descriptive\) usando \(cpanm\)
cpanm -i Statistics::Descriptive cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib)
Si no corremos como superusuario (\(su\) o \(sudo\)) \(cpanm\) instala módulos en ~/perl5.
Si instalamos módulos como superusuario (\(su\) o \(sudo\)), éstos se instalan en uno de los directorios del arreglo especial \(@INC\), que contiene todas las rutas a directorios establecidos durante la compilación de \(perl\) para albergar módulos.
Podemos ver el contenido de @INC con el siguiente 1liner de Perl:
perl –e ‘print join “\n”, @INC’
ó tecleando \(perl -V\)
Si no tenemos derechos de administrador y hemos instalado el módulo en un directorio en nuestro \(\$HOME\) como ~/lib ó ~/CPAN/, este directorio no estará incluido en el arreglo \(@INC\).
Para que un script pueda encontrarlo, necesitamos indicar la ruta de acceso mediante una de las siguientes estrategias:
# asumiendo que usas el shell Bash, añade esta línea a tu archivo ~/.bashrc o ~/.bash_profile export PERL5LIB=$HOME/CPAN
Usando esta última estrategia, se garantiza que Perl siempre va a encontrar módulos instalados desde CPAN en un directorio personal. Es por tanto más portable y conveniente que la opción 1 (\(use\ lib\)).
Podemos listar y explorar los módulos instalados por el usuario (independientes de la distribución estándar) usando cualquiera de las sigientes opciones.
perldoc instmodsh
Pueden explorar el código del módulo con un editor de texto como \(vi\), el editor por excelencia en Linux
vi $(which instmodsh)
Veamos su documentación:
perldoc ExtUtils::Installed
Corramos un \(perl\ 1-liner\) llamando al módulo \(ExtUtils::Installed\) para ver la lista de módulos
perl -MExtUtils::Installed -e 'my ($inst) = ExtUtils::Installed->new( skip_cwd => 1 ); my (@modules) = $inst->modules(); print join "\n", @modules, "\n";'
## Algorithm::Combinatorics
## Algorithm::Munkres
## Alien::Build
## Alien::Libxml2
## Array::Compare
## B::Hooks::EndOfScope
## B::Hooks::OP::Check
## Bio
## Bio::EUtilities
## Bio::Phylo
## CPAN::Meta::Check
## Cache::LRU
## Canary::Stability
## Capture::Tiny
## Class::AutoClass
## Class::Data::Inheritable
## Class::Inspector
## Class::Load
## Class::Load::XS
## Class::Measure
## Class::Method::Modifiers
## Class::Singleton
## Class::Tiny
## Class::XSAccessor
## Clone
## Const::Fast
## Convert::BinHex
## Convert::Binary::C
## Crypt::RC4
## DBD::SQLite
## DBI
## DBIx::Connector
## DIME::Tools
## Data
## Data::OptList
## Data::Perl
## Data::TemporaryBag
## Data::UUID
## DateTime
## DateTime::Format::W3CDTF
## DateTime::Locale
## DateTime::TimeZone
## Devel::Caller
## Devel::CheckLib
## Devel::Cycle
## Devel::GlobalDestruction
## Devel::Hide
## Devel::LexAlias
## Devel::OverloadInfo
## Devel::StackTrace
## Digest::Perl::MD5
## Dist::CheckConflicts
## Encode
## Error
## Eval::Closure
## Exception::Class
## ExtUtils::Config
## ExtUtils::Depends
## ExtUtils::Helpers
## ExtUtils::InstallPaths
## ExtUtils::PkgConfig
## FFI::CheckLib
## File::ShareDir
## File::ShareDir::Install
## File::Slurp
## File::Slurp::Tiny
## File::Which
## File::chdir
## File::pushd
## Font::TTF
## GIS::Distance
## GIS::Distance::Fast
## Geo::Distance
## Getopt::Simple
## Graph
## HTML-TableExtract
## HTTP::Message
## Hash::AutoHash
## Hash::AutoHash::Args
## Hash::FieldHash
## IO::CaptureOutput
## IO::SessionData
## IO::Stringy
## IPC::Run3
## IRI
## Importer
## Inline
## Inline::C
## JSON
## JSON::XS
## List::MoreUtils
## List::MoreUtils::XS
## List::Util
## Log::Log4perl
## MIME::Charset
## MIME::Tools
## MRO::Compat
## Math::CDF
## Math::Derivative
## Math::Random
## Math::Spline
## Math::Utils
## Mock::Config
## Module::Build
## Module::Build::Tiny
## Module::Implementation
## Module::Pluggable
## Module::Runtime
## Module::Runtime::Conflicts
## Moo
## MooX::HandlesVia
## MooX::Types::MooseLike
## Moose
## MooseX::ArrayRef
## Net::HTTP
## OLE::Storage_Lite
## PDF::API2
## Package::DeprecationManager
## Package::Stash
## Package::Stash::XS
## PadWalker
## Params::Util
## Params::ValidationCompiler
## Parse::RecDescent
## Path::Tiny
## Pegex
## Perl
## Perl::Tidy
## PostScript::Metrics
## Ref::Util
## Ref::Util::XS
## Regexp::Util
## Role::Tiny
## SOAP::Lite
## SUPER
## SVG
## SVG::Graph
## SWF::File
## Scope::Guard
## Set::Scalar
## Sort::Naturally
## Sort::Versions
## Specio
## Spiffy
## Spreadsheet::ParseExcel
## Statistics::Descriptive
## Statistics::Distributions
## Storable
## Sub::Exporter
## Sub::Exporter::Progressive
## Sub::Identify
## Sub::Info
## Sub::Install
## Sub::Quote
## Sub::Uplevel
## Task::Weaken
## Term::Size::Any
## Term::Size::Perl
## Term::Table
## Test2::Plugin::NoWarnings
## Test2::Suite
## Test::Base
## Test::CleanNamespaces
## Test::Deep
## Test::Differences
## Test::Exception
## Test::FailWarnings
## Test::Fatal
## Test::File::ShareDir
## Test::LeakTrace
## Test::Memory::Cycle
## Test::MockModule
## Test::MockObject
## Test::MockRandom
## Test::Most
## Test::Needs
## Test::NoWarnings
## Test::Number::Delta
## Test::Output
## Test::Pod
## Test::Pod::Content
## Test::Requires
## Test::RequiresInternet
## Test::Simple
## Test::Warn
## Test::Warnings
## Test::Without::Module
## Test::XML
## Test::YAML
## Text::Aligner
## Text::CSV_XS
## Text::Diff
## Text::Table
## Tie::Hash::MultiValue
## Tie::ToObject
## Tree::DAG_Node
## Type::Tie
## Type::Tiny
## Type::Tiny::XS
## Types::Serialiser
## UNIVERSAL::can
## UNIVERSAL::isa
## Unicode::LineBreak
## Unicode::UTF8
## Variable::Magic
## XML::CommonNS
## XML::DOM
## XML::Filter::BufferText
## XML::LibXML
## XML::Namespace
## XML::NamespaceFactory
## XML::Parser::Lite
## XML::RegExp
## XML::SAX
## XML::SAX::Writer
## XML::SemanticDiff
## XML::Simple
## XML::Twig
## XML::Writer
## XML::XML2JSON
## XML::XPath
## YAML
## YAML::LibYAML
## YAML::Syck
## bareword::filehandles
## common::sense
## indirect
## libwww::perl
## libxml-perl
## multidimensional
## namespace::autoclean
## namespace::clean
## strictures
perldoc perllocal
## stty: 'entrada estándar': Función ioctl no apropiada para el dispositivo
## [1mWed Jun 19 16:03:43 2019: "Module" Algorithm::Munkres[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.08"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:04:04 2019: "Module" Bio::Phylo[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: v2.0.1"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:04:10 2019: "Module" YAML::Syck[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.31"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:04:10 2019: "Module" XML::XML2JSON[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.06"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:04:14 2019: "Module" Data::TemporaryBag[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.09"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:04:14 2019: "Module" SWF::File[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.42"
##
## * "EXE_FILES: dumpswf.plx"
##
## [1mWed Jun 19 16:04:21 2019: "Module" SVG[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.84"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:04:28 2019: "Module" Algorithm::Combinatorics[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.27"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:04:32 2019: "Module" Test::Requires[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.10"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:04:32 2019: "Module" Cache::LRU[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.04"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:05:26 2019: "Module" DBI[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.642"
##
## * "EXE_FILES: dbilogstrip dbiprof dbiproxy"
##
## [1mWed Jun 19 16:06:06 2019: "Module" DBD::SQLite[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.62"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:06:41 2019: "Module" Sub::Identify[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.14"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:06:44 2019: "Module" Test::Warnings[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.026"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:06:48 2019: "Module" Data::UUID[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.224"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:06:55 2019: "Module" Test::Fatal[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.014"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:06:57 2019: "Module" Class::Method::Modifiers[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.12"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:06:59 2019: "Module" Sub::Exporter::Progressive[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.001013"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:00 2019: "Module" Devel::GlobalDestruction[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.14"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:04 2019: "Module" Role::Tiny[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.000006"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:06 2019: "Module" Sub::Quote[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.006003"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:09 2019: "Module" Moo[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.003004"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:12 2019: "Module" ExtUtils::Depends[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.8000"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:16 2019: "Module" Test::Number::Delta[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.06"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:17 2019: "Module" B::Hooks::OP::Check[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.22"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:17 2019: "Module" bareword::filehandles[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.007"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:20 2019: "Module" indirect[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.38"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:22 2019: "Module" multidimensional[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.014"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:22 2019: "Module" strictures[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.000006"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:26 2019: "Module" Class::XSAccessor[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.19"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:32 2019: "Module" Test::Deep[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.128"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:48 2019: "Module" Capture::Tiny[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.48"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:49 2019: "Module" Test::Output[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.031"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:50 2019: "Module" Data::Perl[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.002009"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:52 2019: "Module" MooX::Types::MooseLike[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.29"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:55 2019: "Module" Sub::Uplevel[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.2800"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:56 2019: "Module" Test::Exception[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.43"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:07:57 2019: "Module" MooX::HandlesVia[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.001008"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:09 2019: "Module" Type::Tiny[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.004004"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:11 2019: "Module" Type::Tiny::XS[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.014"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:12 2019: "Module" Type::Tie[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.014"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:18 2019: "Module" Test::LeakTrace[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.16"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:20 2019: "Module" Regexp::Util[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.005"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:23 2019: "Module" Ref::Util::XS[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.117"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:26 2019: "Module" Devel::StackTrace[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.04"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:30 2019: "Module" PadWalker[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.3"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:30 2019: "Module" Devel::Caller[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.06"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:31 2019: "Module" Devel::LexAlias[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.05"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:31 2019: "Module" IRI[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.009"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:54 2019: "Module" JSON[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 4.02"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:08:57 2019: "Module" Canary::Stability[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2013"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:14:16 2019: "Module" common::sense[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 3.74"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:14:17 2019: "Module" Types::Serialiser[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.0"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:14:19 2019: "Module" JSON::XS[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 4.02"
##
## * "EXE_FILES: bin/json_xs"
##
## [1mWed Jun 19 16:14:50 2019: "Module" Log::Log4perl[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.49"
##
## * "EXE_FILES: eg/l4p-tmpl"
##
## [1mWed Jun 19 16:14:54 2019: "Module" Dist::CheckConflicts[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.11"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:14:56 2019: "Module" CPAN::Meta::Check[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.014"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:02 2019: "Module" Params::Util[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.07"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:04 2019: "Module" Sub::Install[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.928"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:04 2019: "Module" Data::OptList[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.110"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:05 2019: "Module" Module::Implementation[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.09"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:08 2019: "Module" Package::Stash[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.38"
##
## * "EXE_FILES: bin/package-stash-conflicts"
##
## [1mWed Jun 19 16:15:10 2019: "Module" Package::Stash::XS[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.29"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:13 2019: "Module" Test::Needs[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.002006"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:14 2019: "Module" Class::Load[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.25"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:16 2019: "Module" Class::Load::XS[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.10"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:18 2019: "Module" MRO::Compat[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.13"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:18 2019: "Module" Devel::OverloadInfo[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.005"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:20 2019: "Module" Eval::Closure[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.14"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:34 2019: "Module" Perl::Tidy[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 20190601"
##
## * "EXE_FILES: bin/perltidy"
##
## [1mWed Jun 19 16:15:35 2019: "Module" Module::Runtime::Conflicts[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.003"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:38 2019: "Module" Package::DeprecationManager[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.17"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:39 2019: "Module" Sub::Exporter[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.987"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:41 2019: "Module" File::pushd[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.016"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:46 2019: "Module" Variable::Magic[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.62"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:47 2019: "Module" B::Hooks::EndOfScope[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.24"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:48 2019: "Module" namespace::clean[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.27"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:15:49 2019: "Module" Test::CleanNamespaces[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.24"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:16:45 2019: "Module" Moose[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.2011"
##
## * "EXE_FILES: bin/moose-outdated"
##
## [1mWed Jun 19 16:16:47 2019: "Module" MooseX::ArrayRef[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.005"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:16:49 2019: "Module" Set::Scalar[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.29"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:16:55 2019: "Module" Test::Without::Module[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.20"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:17:00 2019: "Module" Text::Diff[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.45"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:17:01 2019: "Module" Test::Differences[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.67"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:17:18 2019: "Module" Text::CSV_XS[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.39"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:17:36 2019: "Module" Encode[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 3.01"
##
## * "EXE_FILES: bin/enc2xs bin/encguess bin/piconv"
##
## [1mWed Jun 19 16:17:41 2019: "Module" XML::NamespaceFactory[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.02"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:17:43 2019: "Module" XML::Namespace[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.02"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:17 2019: "Module" File::ShareDir::Install[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.13"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:21 2019: "Module" Class::Inspector[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.34"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:22 2019: "Module" File::ShareDir[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.116"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:35 2019: "Module" List::MoreUtils::XS[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.428"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:43 2019: "Module" List::MoreUtils[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.428"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:46 2019: "Module" Class::Data::Inheritable[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.08"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:46 2019: "Module" Exception::Class[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.44"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:52 2019: "Module" Specio[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.43"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:55 2019: "Module" Ref::Util[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.204"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:18:56 2019: "Module" IPC::Run3[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.048"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:15 2019: "Module" Test::Simple[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.302164"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:17 2019: "Module" Importer[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.025"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:22 2019: "Module" Module::Pluggable[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 5.2"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:23 2019: "Module" Scope::Guard[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.21"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:24 2019: "Module" Sub::Info[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.002"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:25 2019: "Module" Term::Table[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.013"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:29 2019: "Module" MIME::Charset[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.012.2"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:34 2019: "Module" Unicode::LineBreak[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2019.001"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:38 2019: "Module" Devel::Hide[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.0010"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:39 2019: "Module" Term::Size::Perl[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.031"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:39 2019: "Module" Term::Size::Any[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.002"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:51 2019: "Module" Test2::Suite[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.000122"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:52 2019: "Module" Test2::Plugin::NoWarnings[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.07"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:54 2019: "Module" Params::ValidationCompiler[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.30"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:58 2019: "Module" Class::Tiny[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.006"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:19:59 2019: "Module" Test::FailWarnings[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.008"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:02 2019: "Module" Path::Tiny[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.108"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:06 2019: "Module" Unicode::UTF8[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.62"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:07 2019: "Module" Test::MockRandom[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.01"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:09 2019: "Module" Test::File::ShareDir[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.001002"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:11 2019: "Module" namespace::autoclean[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.28"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:28 2019: "Module" DateTime::Locale[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.24"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:31 2019: "Module" Class::Singleton[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.5"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:33 2019: "Module" DateTime::TimeZone[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.35"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:44 2019: "Module" DateTime[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.51"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:45 2019: "Module" DateTime::Format::W3CDTF[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.07"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:20:56 2019: "Module" Spiffy[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.46"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:02 2019: "Module" Test::Base[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.89"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:02 2019: "Module" Test::YAML[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.07"
##
## * "EXE_FILES: bin/test-yaml"
##
## [1mWed Jun 19 16:21:08 2019: "Module" YAML[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.29"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:18 2019: "Module" Test::Pod[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.52"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:22 2019: "Module" ExtUtils::Config[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.008"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:23 2019: "Module" ExtUtils::Helpers[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.026"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:24 2019: "Module" ExtUtils::InstallPaths[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.012"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:51 2019: "Module" Font::TTF[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.06"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:55 2019: "Module" Devel::Cycle[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.12"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:21:56 2019: "Module" Test::Memory::Cycle[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.06"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:22:01 2019: "Module" PDF::API2[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.033"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:22:03 2019: "Module" Math::Random[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.72"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:22:06 2019: "Module" Math::CDF[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.1"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:22:10 2019: "Module" ExtUtils::PkgConfig[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.16"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:22:20 2019: "Module" Tie::Hash::MultiValue[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.05"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:22:22 2019: "Module" Tie::ToObject[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.03"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:22:30 2019: "Module" IO::Stringy[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.111"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:22:35 2019: "Module" Clone[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.41"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:23:05 2019: "Module" Convert::Binary::C[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.78"
##
## * "EXE_FILES: bin/ccconfig"
##
## [1mWed Jun 19 16:23:10 2019: "Module" Data[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.14"
##
## * "EXE_FILES: scripts/stag-autoschema.pl scripts/stag-db.pl
## scripts/stag-diff.pl scripts/stag-drawtree.pl scripts/stag-filter.pl
## scripts/stag-findsubtree.pl scripts/stag-flatten.pl
## scripts/stag-grep.pl scripts/stag-handle.pl
## scripts/stag-itext2simple.pl scripts/stag-itext2simple.pl
## scripts/stag-itext2sxpr.pl scripts/stag-itext2xml.pl
## scripts/stag-join.pl scripts/stag-merge.pl scripts/stag-mogrify.pl
## scripts/stag-parse.pl scripts/stag-query.pl scripts/stag-splitter.pl
## scripts/stag-view.pl scripts/stag-xml2itext.pl"
##
## [1mWed Jun 19 16:23:19 2019: "Module" IO::CaptureOutput[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.1104"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:23:20 2019: "Module" Mock::Config[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.03"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:23:22 2019: "Module" Devel::CheckLib[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.13"
##
## * "EXE_FILES: bin/use-devel-checklib"
##
## [1mWed Jun 19 16:23:41 2019: "Module" Graph[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.9704"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:23:46 2019: "Module" HTML-TableExtract[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.15"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:23:51 2019: "Module" HTTP::Message[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 6.18"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:23:55 2019: "Module" Net::HTTP[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 6.19"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:23:58 2019: "Module" Test::RequiresInternet[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.05"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:14 2019: "Module" libwww::perl[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 6.39"
##
## * "EXE_FILES: bin/lwp-download bin/lwp-dump bin/lwp-mirror
## bin/lwp-request"
##
## [1mWed Jun 19 16:24:16 2019: "Module" PostScript::Metrics[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.06"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:22 2019: "Module" List::Util[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.50"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:25 2019: "Module" IO::SessionData[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.03"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:27 2019: "Module" Task::Weaken[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.06"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:30 2019: "Module" Test::Warn[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.36"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:32 2019: "Module" XML::Parser::Lite[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.722"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:37 2019: "Module" SOAP::Lite[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.27"
##
## * "EXE_FILES: bin/SOAPsh.pl bin/stubmaker.pl"
##
## [1mWed Jun 19 16:24:47 2019: "Module" XML::XPath[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.44"
##
## * "EXE_FILES: examples/xpath"
##
## [1mWed Jun 19 16:24:50 2019: "Module" XML::Filter::BufferText[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.01"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:50 2019: "Module" XML::SAX::Writer[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.57"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:54 2019: "Module" UNIVERSAL::can[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.20140328"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:55 2019: "Module" UNIVERSAL::isa[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.20171012"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:24:56 2019: "Module" Test::MockObject[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.20180705"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:25:02 2019: "Module" MIME::Tools[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 5.509"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:25:08 2019: "Module" File::Slurp[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 9999.27"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:25:11 2019: "Module" Test::Most[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.35"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:25:12 2019: "Module" Convert::BinHex[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.125"
##
## * "EXE_FILES: bin/binhex.pl bin/debinhex.pl"
##
## [1mWed Jun 19 16:25:13 2019: "Module" DIME::Tools[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.04"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:31:41 2019: "Module" Sort::Naturally[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.03"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:31:45 2019: "Module" Crypt::RC4[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.02"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:31:47 2019: "Module" Digest::Perl::MD5[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.9"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:31:48 2019: "Module" OLE::Storage_Lite[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.19"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:31:52 2019: "Module" Spreadsheet::ParseExcel[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.65"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:31:57 2019: "Module" Storable[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 3.15"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:05 2019: "Module" Math::Spline[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.02"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:10 2019: "Module" File::Slurp::Tiny[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.004"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:11 2019: "Module" Tree::DAG_Node[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.31"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:12 2019: "Module" SVG::Graph[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.02"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:17 2019: "Module" libxml-perl[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.08"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:17 2019: "Module" XML::RegExp[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.04"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:18 2019: "Module" XML::DOM[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.46"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:25 2019: "Module" File::Which[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.23"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:27 2019: "Module" FFI::CheckLib[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.24"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:29 2019: "Module" File::chdir[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.1010"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:39 2019: "Module" Alien::Build[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.74"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:32:40 2019: "Module" Sort::Versions[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.62"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:33:30 2019: "Module" Alien::Libxml2[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.09"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 16:33:41 2019: "Module" XML::LibXML[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.0201"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 19:54:57 2019: "Module" XML::SAX[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.02"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 19:55:11 2019: "Module" XML::Simple[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 2.25"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 20:11:38 2019: "Module" XML::Twig[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 3.52"
##
## * "EXE_FILES: tools/xml_grep/xml_grep tools/xml_merge/xml_merge
## tools/xml_pp/xml_pp tools/xml_spellcheck/xml_spellcheck
## tools/xml_split/xml_split"
##
## [1mWed Jun 19 20:11:41 2019: "Module" XML::Writer[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.625"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 22:51:17 2019: "Module" Inline[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.83"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 22:51:24 2019: "Module" YAML::LibYAML[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.79"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 22:51:25 2019: "Module" Pegex[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.70"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 22:51:51 2019: "Module" Inline::C[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 0.81"
##
## * "EXE_FILES: "
##
## [1mWed Jun 19 22:51:54 2019: "Module" Test::NoWarnings[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.04"
##
## * "EXE_FILES: "
##
## [1mSun Oct 13 17:34:58 2019: "Module" Bio::EUtilities[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.75"
##
## * "EXE_FILES: bin/bp_einfo bin/bp_genbank_ref_extractor"
##
## [1mFri Nov 22 01:27:46 2019: "Module" Statistics::Distributions[0m
## * "installed into: /usr/local/share/perl/5.26.1"
##
## * "LINKTYPE: dynamic"
##
## * "VERSION: 1.02"
##
## * "EXE_FILES: "
find `perl -e 'print "@INC"' ` -name '*.pm' -print find `perl -e 'print "@INC"' ` -name '*.pm' -print | wc -l find `perl -e 'print "@INC"' ` -name '*.pm' -print | grep Statist # Perl 1liner para encontrar todos los módulos instalados en el sistema perl -MFile::Find=find -MFile::Spec::Functions -Tlwe 'find { wanted => sub{ print canonpath $_ if /\.pm\z/ }, no_chdir => 1 }, @INC'
Existen al menos dos paradigmas básicos de programación:
Programación por procedimientos (la que hemos visto/usado hasta ahora) http://en.wikipedia.org/wiki/Procedural_programming
Programación dirigida a objetos: las variables y código son encapsuladas en agrupaciones lógicas conocidas como clases. Las clases encapsulan descripciones generales de procesos u objetos de interés mediante la definición de interacciones entre objetos y sus métodos. http://en.wikipedia.org/wiki/Object-oriented_programming
Son módulos con una interfaz dirigida a objetos
Son un conjunto de datos con acciones y atributos asociados. Representan instancias particulares de una clase. Las acciones son funciones que un objeto puede hacer con los datos, las cuales vienen codificadas en los métodos del objeto.
Son análogos a funciones, ya que tienen un nombre y reciben parámetros para operar sobre datos. Pero no son lo mismo ya que hay que llamarlos con una sintaxis particular que contiene el nombre de una clase (métodos de clases) o de un objeto (métodos de objetos).
#!/usr/bin/env perl use strict; use warnings; use File::Basename; use Statistics::Descriptive::Discrete; my $progname = basename($0); my $VERSION = '0.01'; my $stats = Statistics::Descriptive::Discrete->new(); print "# Please enter at least three integers between 0 and 100: e.g. 1 4 4 5 3 6 4\n"; chomp( my $data_string = <> ); my @digits = split /\s+/, $data_string; die "# ERROR: need to enter at least three integers between 0 and 100: e.g. 1 4 4 5 3 6 4\n" if @digits < 3; # make sure only integers were provided my @non_digits = grep { !/\d+/ } @digits; die "# ERROR: need to enter at least three integers between 0 and 100: e.g. 1 4 4 5 3 6 4\n" if @non_digits ; $stats->add_data(@digits); print "count = ", $stats->count(), "\n"; print "uniq = ", $stats->uniq(), "\n"; print "sum = ", $stats->sum(), "\n"; print "min = ", $stats->min(), "\n"; print "max = ", $stats->max(), "\n"; print "mean = ", $stats->mean(), "\n"; print "standard_deviation = ", $stats->standard_deviation(), "\n"; print "variance = ", $stats->variance(), "\n"; print "sample_range = ", $stats->sample_range(), "\n"; print "mode = ", $stats->mode(), "\n"; print "median = ", $stats->median(), "\n";
# Please enter at least three integers between 0 and 100: e.g. 1 4 4 5 3 6 4 1 4 4 5 3 6 4 count = 7 uniq = 5 sum = 27 min = 1 max = 6 mean = 3.85714285714286 standard_deviation = 1.57359158493889 variance = 2.47619047619048 sample_range = 5 mode = 4 median = 4
Sintaxis básica para el uso de clases (módulos con interfaz dirigida a objetos):
#use Class::Name use Statistics::Descriptive::Discrete;
# my $object = Class::Name->new(parameter1, parameter2 …); # con params. my $stats = Statistics::Descriptive::Discrete->new(); # sin parámetros
# $object->methodName(parameter1, parameter2); # $object->methodName(); # if no parameter required $stats->add_data(@digits); print "count = ", $stats->count(), "\n"; # llamada al método count del objeto $stats …
El projecto BioPerl de código fuente abierto es fruto de la colaboración entre bioinformáticos, biólogos y científicos del área de la computación con el objetivo de desarrollar una plataforma de código para resolver todo tipo de problemas de bioinformática.
El proyecto inició en 1995 y tuvo su lanzamiento oficial el 11 de Junio de 2002, por lo que claramente es el primer y mayor proyecto de código abierto para bioinformática actuamente existente.
BioPerl es un proyecto activo, financiado por la Open Bioinformatics Foundation, basado en módulos de Perl con el fin de facilitar la administración y manipulación de información relacionada con ciencias de la vida, en particular secuecias genómicas, análisis de genes y proteínas, e interacción con diversos tipos de bases de datos.
En términos prácticos, BioPerl es un gran repositorio de módulos de Perl para bioinformática con interfaz dirigida a objetos, llamados clases, que cuenta con una excelente documentación y tutoriales.
Resulta que diseñar y abstraer el código en términos de clases y objetos es la técnica de programación más flexible, y en última instancia simple y escalable, para trabajar con datos de gran complejidad, como son los biológicos. Cada “dato”, como una secuencia, un genoma o una entrada de una base de datos, tiene una gran cantidad de atributos asociados, todos los cuales pueden ser modelados de manera consistente usando un sistema de clases o módulos con interfaz dirigida a objetos.
En sistemas Linux basados en Debian, la instalación de bioperl se puede hacer fácilmente usando el manejador de paquetes \(apt\)
apt-cache search bioperl
sudo apt install bioperl
Nota: Para las prácticas de este tema, es suficiente que instalen el conjunto de módulos básicos
cpanm Bio::Perl
Si tienes otros sistemas operativos, sigue las instrucciones en la página de installation, que encontrarás aquí: https://bioperl.org/INSTALL.html
Como se mencionó en la sección anterior, los módulos del proyecto BioPerl tiene una interfaz dirigida a objetos. Las clases son un tipo de módulo que incluye siempre, por definición, una subrutina ‘\(new\)’, en español ‘constructor’, que genera las instancias de la clase al hacer la llamada my $object = clase->new()..
Desde un punto de vista conceptual, un objeto o instancia de una clase es un agregado de variables (atributos), con identidad propia, que además incorpora una serie de subrutinas (métodos) para interaccionar con el mundo exterior o acceder a los contenidos del mismo.
En la práctica, una clase es un tipo de módulo que crea copias temporales de sí mismo, que duran mientras corre el programa que la invoca, cada una con su propia identidad. A cada instancia o copia de la clase le llamamos ‘objeto’. Un ejemplo en Biología podría ser la clase de las proteínas, que son polímeros de aminoácidos, pero cada una, cada objeto perteneciente a la clase, como la calmodulina, tiene su propia función, secuencia y nombre.
En este tema no podemos describir cómo se programan clases, nos limitaremos a aprender a usarlas. Es importante señalar que un módulo con interfaz dirigida a objetos, generalmente no utiliza el mecanismo de imporación-exportación descrito arriba para módulos tradicionales. La interfaz dirigida a objetos se basa en el uso de constructores, destructores, métodos, herencia y sobrecarga de operadores.
Desde la óptica del usuario, lo relevante es entender que tenemos que generar objetos e interactuar con ellos mediante los métodos asociados.
Dado que BioPerl cuenta con mucho módulos, tenemos que llamar al módulo adecuado para resolver nuestro problema. \(Bio::Seq\) es la clase principal para trabajar con secuencias en BioPerl. \(Bio::SeqIO\) puede leer y escribir secuencias biológicas en múltiples formatos, y por tanto tambien transformarlas de un formato a otro.
#!/usr/bin/env perl use strict; use warnings; use Bio::Seq;
# generación de un objeto my $seq_obj = Bio::Seq->new(-seq => 'ATGATTGCACATTATAA', -alphabet => 'dna' );
print $seq_obj->seq;
Va el script completo:
#!/usr/bin/env perl
use strict;
use warnings;
use Bio::Seq;
my $seq_obj = Bio::Seq->new(-seq => 'ATGATTGCACATTATAA',
-alphabet => 'dna' );
print $seq_obj->seq;
## ATGATTGCACATTATAA
La variable \(\$seq\_obj\) es un el objeto sequencia, un objeto muy simple ya que sólo contiene la secuencia, con un solo atributo: alfabeto tipo dna (también hay rna y proteína).
Los objetos de secuencia pueden ser creados manualmente, como hicimos arriba, pero son creados automáticamente en muchas operaciones de BioPerl, como cuando trabajamos con alineamientos o con entradas de bases de datos como Blast o GenBank.
El objeto \(\$seq\_obj\) no sólo es un “contenedor” para la secuencia. Los objetos de la clase \(Bio::Seq\) tienen el método \(seq()\), que imprime su contenido.
Además, podemos añadir más atributos al objeto \(\$seq\_obj\), como se muestra seguidamente.
Típicamente una secuencia tiene varios atributos adicionales, como un identificador y una descripción con metadatos adicionales. Vamos a crear un nueva instancia de la clase \(Bio::Seq\), es decir, un nuevo objeto \(\$seq\_obj\), con esta información adicional.
$seq_obj = Bio::Seq->new(-seq => "ATGATTGCACATTATAA", -display_id => "XXX_0123", -desc => "Bichococcus imaginarius, genX", -alphabet => "dna" );
Imprimamos ahora la secuencia, con sus nuevos atributos, en formato FASTA
#!/usr/bin/env perl
use strict;
use warnings;
use Bio::Seq;
my $seq_obj = Bio::Seq->new(-seq => "ATGATTGCACATTATAA",
-display_id => "XXX_0123",
-desc => "Bichococcus imaginarius, genX",
-alphabet => "dna" );
# imprimimos la secuencia en formato FASTA
print ">", $seq_obj->id, "|", $seq_obj->desc, "\n", $seq_obj->seq, "\n";
## >XXX_0123|Bichococcus imaginarius, genX
## ATGATTGCACATTATAA
Si queremos imprimir a un archivo el contenido del objeto \(\$seq\_obj\) que generamos arriba, podemos hacer uso de un nuevo objeto, de la clase \(Bio::SeqIO\), especializado en leer desde y escribir en archivos. De ahi su nombre SeqIO(), que alude a “sequence Input/Output”
use Bio::SeqIO; ... my $seqio_obj = Bio::SeqIO->new(-file => '>sequence.fasta', -format => 'fasta' );
Lo interesante es que los objetos de las clases \(Bio::Seq\) \(Bio::SeqIO\) pueden trabajar de manera coordinada, como se muestra en el siguiente ejemplo:
#!/usr/bin/env perl
use strict;
use warnings;
# l1. lamada a las clases
use Bio::Seq;
use Bio::SeqIO;
# 2. generamos una instancia de la clase Bio::Seq
my $seq_obj = Bio::Seq->new(-seq => "ATGATTGCACATTATAA",
-display_id => "XXX_0123",
-desc => "Bichococcus imaginarius, genX",
-alphabet => "dna" );
# 3. imprimimos la secuencia en formato FASTA usando una instancia de Bio::SeqIO
# 3.1 generamos un nuevo objeto de la clase Bio::SeqIO
my $seqio_obj = Bio::SeqIO->new(-file => '>Bichococcus_imaginarius_genX.fasta',
-format => 'fasta' );
# 3.2 usamos el método write_seq() del objeto $seqio_obj para escribir el contenido del
# objeto $seq_obj a disco.
$seqio_obj->write_seq($seq_obj);
[ -s Bichococcus_imaginarius_genX.fasta ] && cat Bichococcus_imaginarius_genX.fasta
## >XXX_0123 Bichococcus imaginarius, genX
## ATGATTGCACATTATAA
Una gran ventaja de usar clases bien diseñadas, es que es muy fácil para el usuario cambiar atributos de un objeto. Por ejemplo, podemos pedirle a \(Bio::SeqIO\) que nos imprima la secuencia ahora en formato GenBank. Para ello sólo necesitamos cambiar el atributo format del objeto \(\$seqio\_obj\), y usar un nuevo nombre de archivo de salida, como se muestra en el siguiente bloque.
my $seqio_obj = Bio::SeqIO->new(-file => '>Bichococcus_imaginarius_genX.gbk', -format => 'genbank' );
## LOCUS XXX_0123 17 bp dna linear UNK
## DEFINITION Bichococcus imaginarius, genX
## ACCESSION unknown
## FEATURES Location/Qualifiers
## ORIGIN
## 1 atgattgcac attataa
## //
¿Ta’güeno, verdad?
Para leer un archivo que tenemos en disco, usamos nuevamente la clase \(Bio::SeqIO\)
Como ejemplo, leamos el archivo GenBank que acabamos de generar e imprimamos en formato GenBank
#!/usr/bin/env perl
use strict;
use warnings;
# l1. lamada a las clases
use Bio::SeqIO;
# 2. leamos la la secuencia en formato GenBank usando una instancia de Bio::SeqIO
# 2.1 generando un nuevo objeto de la clase Bio::SeqIO
my $seqio_obj = Bio::SeqIO->new(-file => 'Bichococcus_imaginarius_genX.gbk',
-format => 'genbank' );
# 2.2 usamos el método next_seq() del objeto $seqio_obj leer el contenido del
# objeto $seqio_obj y asignarlo a un nuevo objeto $seq_obj.
# para leer una sola secuencia usamos:
# my $seq_obj = $seqio_obj->next_seq();
# si el objeto contiene varias, ponemos la llamada a next_seq() dentro de un bucle while
while ( my $seq_obj = $seqio_obj->next_seq ) {
# print the sequence
print ">", $seq_obj->id, "\n", $seq_obj->seq,"\n";
}
## >XXX_0123
## ATGATTGCACATTATAA
Con lo aprendido en secciones anteriores, debería ser fácil escribir un interconvertidor de formatos de secuencias.
#!/usr/bin/env perl use strict; use warnings; use File::Basename; use Bio::SeqIO; my $progname = basename($0); my $VERSION = 0.2; # November 21st, 2013 # get command-line arguments, or die with a usage statement my $usage =<<"EOF"; USAGE: $progname v.$VERSION infile infileformat outfile outfileformat accepted formats are: Fasta FASTA format EMBL EMBL format GenBank GenBank format swiss Swissprot format PIR Protein Information Resource format GCG GCG format raw Raw format (one sequence per line, no ID) ace ACeDB sequence format game GAME XML format phd phred output qual Quality values (get a sequence of quality scores) Fastq Fastq format SCF SCF tracefile format ABI ABI tracefile format ALF ALF tracefile format CTF CTF tracefile format ZTR ZTR tracefile format PLN Staden plain tracefile format EXP Staden tagged experiment tracefile format EOF my $infile = shift or die $usage; my $infileformat = shift or die $usage; my $outfile = shift or die $usage; my $outfileformat = shift or die $usage; # create one SeqIO object to read in,and another to write out my $in = Bio::SeqIO->new( -file => "<$infile", -format => $infileformat, ); my $out = Bio::SeqIO->new( -file => ">$outfile", -format => $outfileformat, ); # write each entry in the input file to the output file while (my $seq = $in->next_seq) { $out->write_seq($seq); }
Una llamada al script, para convertir el archivo Bichococcus_imaginarius_genX.gbk en formato GenBank a formato EMBL, sería así:
./convert_seqFormats_SeqIO.pl Bichococcus_imaginarius_genX.gbk genbank Bichococcus_imaginarius_genX.embl EMBL
Y podemos ver el resultado así
[ -s Bichococcus_imaginarius_genX.embl ] && cat 'Bichococcus_imaginarius_genX.embl'
## ID XXX_0123 standard; dna; UNK; 17 BP.
## XX
## AC unknown;
## XX
## DE Bichococcus imaginarius, genX
## XX
## FH Key Location/Qualifiers
## FH
## XX
## SQ Sequence 17 BP; 7 A; 2 C; 2 G; 6 T; 0 other;
## atgattgcac attataa 17
## //
Para más ejemplos de uso de la clase \(Bio::SeqIO\), vean el siguiente HOWTO en la página de bioperl.org https://bioperl.org/howtos/SeqIO_HOWTO.html
En la página de BioPerl HOWTOs encontrarás muchos ejemplos más, muy bien escritos. Para empezar, recomiendo estudiar los siguientes, en este órden
En el repositorio está el script \(run\_phylo\_pipeline1.pl\) que han de modifcar para que:
Puden usar el script \(run\_phylo\_pipeline1.pl\) como punto de arranque, y modifíquenlo acorde a sus necesidades, o para hacer lo que arriba se sugiere.
Va un ejemplo de corrida \(run\_phylo\_pipeline1.pl\) sin argumentos
script_dir=$HOME/Cursos/perl4bioinfo/my_code
$script_dir/run_phylo_pipeline1.pl
##
## USAGE:
## run_phylo_pipeline1.pl version 0.2 requires 2 arguments:
##
## - Required
## 1. A fasta file name
## 2. Sequence type: <aa|nt>
##
## - Optional
## 3. an alignment algorithm name <clustalo|muscle>; default: clustalo
##
## AIM:
## will run clustalo or muscle to align the input fasta file
## and FastTree to infer phylogeny
##
## CWD:
## /home/vinuesa/Cursos/perl4bioinfo
##
script_dir=$HOME/Cursos/perl4bioinfo/my_code
$script_dir/run_phylo_pipeline1.pl GDP_12_prokEuc.faa aa clustalo
## # sub run_clustalo is running /usr/local/bin/clustalo -i GDP_12_prokEuc.faa -o GDP_12_prokEuc_cluoAln.faa --force
## # run_clustalo() returned aligned outfile GDP_12_prokEuc_cluoAln.faa
## # sub run_FastTree is running: /usr/local/bin/FastTree -lg -gamma -quiet < GDP_12_prokEuc_cluoAln.faa > GDP_12_prokEuc_cluoAln_FTLGG.ph
## # run_clustalo() returned aligned outfile GDP_12_prokEuc_cluoAln_FTLGG.ph
Es todo, les deseamos mucho éxito en su futuro como programadores de Perl!