Secciones de la página

iForense


Árbol de ficheros


Declaraciones


Inclusiones


Estructuras de datos


Constantes


Proceso


Read agenda


Finalización


Time oriented language

Tol

Artículos del sitio

Presentación de Tol

Todos los programas

Simuladores visuales

Sitios que me gustan

Por categorías

Algoritmia

Búsqueda y ordenación

Computación fisiológica

Editorial y edición

Gráficos de datos

Herramientas y utilidades

Hipertexto

Informática forense

Lectura óptica de datos

Metaprogramación

No determinista

Ofimática

Recursión e iteración

Reglas y restricciones

Series y estadística









make.tol de iForense

Programa constructor del sitio web del dominio forense.info dedicado a contenidos de formación en informática forense en donde se presentan 3 cursos de experto, especialista y máster en informática forense y pericial. Los contenidos que emplea son posts con 3 niveles de importancia (status), que se organizan en un directorio, que se denomina agenda, este directorio tiene contiene varios ficheros, cada fichero contiene varios posts y cada post pertenece a una o varias clases (categorías) de posts. Dentro de este directorio de agenda, sin pertenecer a ella, hay un glosario de términos de informática forense que permiten ilustrar los contenidos del sitio de forma no determinista.

Este programa para la creación del sitio web forense.info: a) está basado en un macro-expansor de Tol en Html a doble nivel, b) crea índices de artículos e ilustraciones de forma automática, c) rellena automáticamente la descripción y la lista de palabras clave de cada página de una forma personalizada para ella (campos meta) y d) sus funciones principales son crear todos los artículos de contenido, crear todas las páginas por categorías, crear la homepage y las páginas absolutas y de control de errores, crear el mapa del sitio web en XML y poner los contenidos online.

Los posts de la agenda de contenidos pueden ser de los 3 siguientes niveles: a) anulados que no salen (se le denomina nivel A), b) bajos que se publican sólo dentro de sus clases, pero no con árticulo propio (nivel B) y c) comunes que se publican dentro de su clase y con en su propio artículo (nivel C), la mayoría de estos post tienen este nivel, por lo que es el nivel por defecto.

Este programa para la construcción del sitio web forense.info utiliza un directorio de agenda de posts, dentro de este directorio los posts se estructuran en varios ficheros, usualmente un fichero para cada clase de posts, lo que permite organizar los post por su tipo de contenido, por ejemplo, toda la bibliografía esta en el mismo fichero. Estos ficheros de posts tienen de extensión .age. En este mismo directorio se guarda un glosario de términos de informática forense y pericial con la que se complementa la información publicada en los posts. Los términos publicados junto con los posts bien pueden ser generales o bien ser relativos a la información concreta que proporciona en cada post.

Los posts pueden pertenecer a múltiples clases, también llamadas categorías, y se crean páginas Html de posts, artículos, en un directorio llamado articulos y de conjuntos de post para cada clase, en un directorio llamado categorias. Las páginas de artículos se generan en este programa con la opción art, las páginas con los artículos agrupados por categorías con la opción cat, las páginas por defecto de cada directorio, las absolutas y las de control de errores con la opción rot y el mapa del sitio web en Xml con la opción xsm, siglas de Xml site map.

Este programa y la creación de este sitio web sobre informática forense está basado en un macro-expansor a doble nivel de Tol embebido en Html, donde la semilla de Html contiene Tol embebido y los post también pueden contener Tol embebido, por lo que dentro de la primera expansión, la de la semilla, se pueden realizar otras expansiones, que son las contenida en los post. La macro-espansión de tol a doble nivel permite que los post contengan código en lenguaje Html y código en lenguaje Tol, ello permite, por ejemplo, crear índices o incluir definiciones de los términos del glosario de informática forense dentro de cada post. Para el manejo de los términos del glosario de informática forense del que dispone este programa, en su libreria glo.tol, se emplea de forma básica el álgebra de conjuntos de Tol, para evitar, en la medida de lo posible, la repetición de la ocurrencia de la definición de los términos.

Este programa sólo escribe los ficheros de páginas Html que son diferentes a los ya creados en ejecuciones anteriores, de forma que no haya que enviar y poner online todo el conjunto de páginas sino las modificadas en fecha más reciente al último log de envío. Este control de recencia lo realiza la opción fup, que son las siglas de ftp update, frente a la opción ftp que genera ficheros de mandatos de envío con todo el contenido del web. Nótese que las opciones fup y ftp sólo generan ficheros de mandatos ftp de envío y luego se pueden ejecutar estos ficheros con la opcion snd. Aunque también ha de observarse que la inclusión de términos del glosario es tan variada que en casi todas las ejecuciones las páginas Html generadas son diferentes a las generadas en la anterior ejecución por lo que se produce su envío.

Los comentarios del código de este programa están realizados utilizando unas veces el español no acentuado dentro del código y otras veces el inglés. Se ha comprobado el funcionamiento de este programa para las versiones de Tol 1.1.5, 1.1.6 y 2.0.1. Con la version 1.1.1 da problemas, por ejemplo, por el uso que se hace del tercer parámetro de la función de texto TextReplace(texto, tabla, numero de ciclos), ya que la versión de Tol 1.1.1 no se contemplaba el número de ciclos.

Árbol de ficheros

iForense construye las paginas del sitio sobre informática forense Forense.Info

  • make.tol proceso principal de generacion del sitio web y todas su páginas
  • tol directorios de código en lenguaje Tol
    • cmm funciones comunes
      • txt.tol código de funciones de textos
      • dte.tol código de funciones de fechas
      • set.tol código de funciones de conjuntos
      • fil.tol código de funciones de ficheros
      • dir.tol código de funciones de directorios
      • tme.tol funciones del macro-expansor doble de Tol en Html
      • img.tol funciones para imagenes declaradas en Html
      • ftp.tol para generar mandatos para hacer Ftp
      • xsm.tol para construir sitemaps en Xml
    • app funciones específicas de aplicación
      • glo.tol de términos del glosario forense e informatico
      • pdb.tol de manejo de los posts de una agenda
      • pht.tol funciones auxiliares para el Html de los post
    • inc.tol para la inclusión de ficheros en lenguaje Tol
  • agenda directorio destinado a la agenda de post
  • web directorio destinado a las páginas web generadas y a contenido
    • css directorio para ficheros de estilo de tipo Css
      • common.css fichero Cascading Style Sheets para las paginas Html
    • seed directorio para ficheros semilla
      • seed.htm semilla de página Html, template, con Tol embebido
    • src directorio para ficheros con código Javascript
      • common.js funciones Javascript de redes sociales y multimedia
    • imagenes directorio de ilustraciones del sitio web
    • articulos directorio para las páginas de artículos de informática forense
    • categorias directorio para paginas de categorias de informática forense
    • sitemap.xml mapa del sitio web generado automáticamente en Xml
  • resultado.html muestra del web de informática forense del dominio Forense.Info
  • iforense.pdf documento resumen de funciones del programa creador del web

Declaraciones

Inclusiones

  • Set allInc
    Inclusion de las funciones comunes y de aplicacion.

Constantes

  • Text makSep
    Linea horizontal para separar fases de operacion.
  • Text CtrAge
    All text files inside this directory.
  • Text CtrFil
    Para el volcado de estadisticas de posts.
  • Real CtrPxC
    Number of posts per category page.
  • Real CtrPxA
    Number of posts per article page.
  • Real CtrTit
    Number of posts per title.
  • Real CtrDes
    Number of posts per description.
  • Set CatMnu
    Categorias del menu principal.
  • Set CatAre
    Areas de conocimiento.
  • Set CatMod
    Módulos de las areas de conocimiento.
  • Set CatBib
    Referencias bibliograficas.
  • Set CatCon
    Datos de contacto y privacidad.
  • Set CatTop
    Todas las categorias de alto nivel.
  • Set CatNot
    Not to top category list.
  • Set CatAll
    Todas las categorias de cualquier nivel.

Proceso

  • Text ctrExe
    Argumento validado para la ejecucion del make.
  • Real makHlp
    Es cierto si se ha visualizado la ayuda.

Read agenda

  • Set CtrPdb
    Read all posts.
  • Set CtrCmn
    Posts comunes.
  • Set CtrAre
    Post de areas de conocimiento.
  • Set CtrMod
    Post de los modulos de las areas de conocimiento.
  • Set CtrBib
    Post de referencias bibliograficas.
  • Real makCat
    Build the category pages for CatAll set.
  • Real makArt
    Build all articles pages.
  • Real makRot
    Build root absolute page.
  • Real makXsm
    Build Xml site map.
  • Real makFtp
    Crear los ficheros de mandatos completos ftp o de actualizacion fup.
  • Real makSnd
    Send files via ftp.
  • Real makRep
    Massive file replacement.
  • Real gloSta
    Ver los terminos más frecuentes del glosario.

Inclusiones

Set allInc

//////////////////////////////////////////////////////////////////////////////
Set  allInc = Include("tol/inc.tol");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Inclusion de las funciones comunes y de aplicacion.", allInc);
//////////////////////////////////////////////////////////////////////////////

Estructuras de datos

// Status:
// A: Anulado, aunque este en la agenda no se publica
// B: Baja, solo se publica en su categoria, no como articulo independiente
// C: Comun, se publica en su categoria y como articulo independiente
// D: Destacado, se publica en su categoria y como articulo independiente y
//    si hay un menu de acceso a articulos importantes se incluye en el.
// Otros make web mios no terminan de implementar esto en toda su dimension
// En este (y probablemente en otros) no funcionaban los anulados porque en
// pdb.tol ponia a->pstSta != "-" en vez de a->pstSta != "A"
//////////////////////////////////////////////////////////////////////////////

Struct PdbSt   // Posts database
{
  Set  pstCla, // Conjunto de tipos de post
  Text pstSta, // Status A(nulado), B(ajo) y C(comun, por defecto)
  Text pstCod, // Identificador del post
  Text pstTh1, // Titulo del post en Html, h1, h2
  Text pstTit, // Titulo del post sin Html
  Date pstDte, // Fecha de ocurrencia
  Text pstAut, // Autor
  Text pstTxt  // Codigo de texto del post en Html+Javascript+Tol
};

Constantes

Text makSep

//////////////////////////////////////////////////////////////////////////////
Text makSep = "\n"+Repeat("_", 72)+"\n";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Linea horizontal para separar fases de operacion.", makSep);
//////////////////////////////////////////////////////////////////////////////

Text CtrAge

//////////////////////////////////////////////////////////////////////////////
Text CtrAge = "agenda";
//////////////////////////////////////////////////////////////////////////////
PutDescription("All text files inside this directory.", CtrAge);
//////////////////////////////////////////////////////////////////////////////

Text CtrFil

//////////////////////////////////////////////////////////////////////////////
Text CtrFil = "poststat.csv";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Para el volcado de estadisticas de posts.", CtrFil);
//////////////////////////////////////////////////////////////////////////////

Real CtrPxC

//////////////////////////////////////////////////////////////////////////////
Real CtrPxC =  20;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per category page.", CtrPxC);
//////////////////////////////////////////////////////////////////////////////

Real CtrPxA

//////////////////////////////////////////////////////////////////////////////
Real CtrPxA =   6;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per article page.", CtrPxA);
//////////////////////////////////////////////////////////////////////////////

Real CtrTit

//////////////////////////////////////////////////////////////////////////////
Real CtrTit =   2;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per title.", CtrTit);
//////////////////////////////////////////////////////////////////////////////

Real CtrDes

//////////////////////////////////////////////////////////////////////////////
Real CtrDes =  20;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per description.", CtrDes);
//////////////////////////////////////////////////////////////////////////////

Set CatMnu

//////////////////////////////////////////////////////////////////////////////
Set CatMnu =
[[
  "Presentación",
  "Derecho e informática",
  "Informática forense",
  "Investigación básica",
  "Investigación avanzada",
  "Base documental"
]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias del menu principal.", CatMnu);
//////////////////////////////////////////////////////////////////////////////

Set CatAre

//////////////////////////////////////////////////////////////////////////////
Set CatAre = [["Área"]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Areas de conocimiento.", CatAre);
//////////////////////////////////////////////////////////////////////////////

Set CatMod

//////////////////////////////////////////////////////////////////////////////
Set CatMod = [["Módulo"]];       // 
//////////////////////////////////////////////////////////////////////////////
PutDescription("Módulos de las areas de conocimiento.", CatMod);
//////////////////////////////////////////////////////////////////////////////

Set CatBib

//////////////////////////////////////////////////////////////////////////////
Set CatBib = [["Bibliografía"]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Referencias bibliograficas.", CatBib);
//////////////////////////////////////////////////////////////////////////////

Set CatCon

//////////////////////////////////////////////////////////////////////////////
Set CatCon = [["Contacto"]];     // Contacto y privacidad
//////////////////////////////////////////////////////////////////////////////
PutDescription("Datos de contacto y privacidad.", CatCon);
//////////////////////////////////////////////////////////////////////////////

Set CatTop

//////////////////////////////////////////////////////////////////////////////
Set CatTop = CatMnu << CatAre << CatMod << CatBib << CatCon;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Todas las categorias de alto nivel.", CatTop);
//////////////////////////////////////////////////////////////////////////////

Set CatNot

//////////////////////////////////////////////////////////////////////////////
Set CatNot =
[[
  "Tema",
  "Resumen",
  "Multimedia", "Documentación PDF", "Vídeo MP4",
  "Mapa del web"
]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Not to top category list.", CatNot);
//////////////////////////////////////////////////////////////////////////////

Set CatAll

//////////////////////////////////////////////////////////////////////////////
Set CatAll = CatTop << CatNot;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Todas las categorias de cualquier nivel.", CatAll);
//////////////////////////////////////////////////////////////////////////////

Proceso

Text ctrExe

//////////////////////////////////////////////////////////////////////////////
Text ctrExe = If(Not(ObjectExist("Text","ctrBat")), "hlp",
              If(ctrBat=="",                        "hlp",
                                                    ToLower(ctrBat)));
//////////////////////////////////////////////////////////////////////////////
PutDescription("Argumento validado para la ejecucion del make.", ctrExe);
//////////////////////////////////////////////////////////////////////////////

Real makHlp

//////////////////////////////////////////////////////////////////////////////
Real makHlp = If(ctrExe!="hlp", FALSE,
{
  Text WriteLn(
  makSep+"help:
  Usage: make [OPTION]
  Builds Forense.Info site
  OPTION
    cat: build all category pages
    art: build all articles pages
    rot: build root absolute page
    xsm: build sm site maps
    ftp: build ftp files (go to ftp dir and run manually)
    fup: build a file update protocol (newer than ftp.log file)
    snd: send file via ftp
    all: do all works: xml, fup...
    rep: massive file replacement (internal order)
    hlp: show this help
    tst: test some functions");
  TRUE
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Es cierto si se ha visualizado la ayuda.", makHlp);
//////////////////////////////////////////////////////////////////////////////

Read agenda

Set CtrPdb

//////////////////////////////////////////////////////////////////////////////
Set CtrPdb = If(! (ctrExe <: [["all", "cat", "art"]]), Empty,
                PdbRead(CtrAge)); // Read all posts
//////////////////////////////////////////////////////////////////////////////
PutDescription("Read all posts.", CtrPdb);
//////////////////////////////////////////////////////////////////////////////

Set CtrCmn

//////////////////////////////////////////////////////////////////////////////
Set CtrCmn = Select(CtrPdb, Real(Set a) { a->pstSta >= "C" });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Posts comunes.", CtrCmn);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("Status __C "+FormatReal(Card(CtrCmn),"%3.0lf")+" registers");

Set CtrAre

//////////////////////////////////////////////////////////////////////////////
Set CtrAre = Select(CtrCmn, Real(Set a) { And(  CatAre[1] <: a->pstCla,
                                              !("Resumen" <: a->pstCla)) });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Post de areas de conocimiento.", CtrAre);
//////////////////////////////////////////////////////////////////////////////

Set CtrMod

//////////////////////////////////////////////////////////////////////////////
Set CtrMod = Select(CtrCmn, Real(Set a) { CatMod[1] <: a->pstCla });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Post de los modulos de las areas de conocimiento.", CtrMod);
//////////////////////////////////////////////////////////////////////////////

Set CtrBib

//////////////////////////////////////////////////////////////////////////////
Set CtrBib = Select(CtrCmn, Real(Set a) { CatBib[1] <: a->pstCla });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Post de referencias bibliograficas.", CtrBib);
//////////////////////////////////////////////////////////////////////////////

Real makCat

//////////////////////////////////////////////////////////////////////////////
Real makCat = If(And(ctrExe!="all",ctrExe!="cat"), FALSE,
{
  Text WriteLn(makSep+"building all category pages...");
  Text WriteFile(CtrFil, "Posts; Class\n");
  
  Real CtrArt = FALSE; // Categories, not articles

  // Make category pages
  Set  cicCat = EvalSet(CatAll, Real(Text CtrPag)
  {
    Text filNam = PhtFileName(CtrPag); // Output file
    Text WriteLn("["+CtrPag+"|"+filNam+"]");
    
    Set  SelPdb = // Selected post from database for this page
    {
      Set selSet = Select(CtrPdb, Real(Set pdbObj) { CtrPag <: pdbObj->pstCla });
      Real selCrd = Card(selSet);
      Text txtCrd = FormatReal(selCrd,"%.0lf");
      Text WriteLn("  "+txtCrd+" posts selected");
      Text AppendFile(CtrFil, txtCrd+"; "+CtrPag+"\n");
  
      selSet
    };

    TmeFile("web/seed/seed.htm", "web/"+filNam)
  });

  // Make special category completo, all the posts
  Real  allCat =
  {
    Text CtrPag = "Completo";
    Text filNam = PhtFileName(CtrPag); // Output file
    Text WriteLn("["+CtrPag+"|"+filNam+"]");
    Set  SelPdb = CtrPdb; // Todos los posts
    TmeFile("web/seed/seed.htm", "web/"+filNam)
  };


  Card(cicCat)+allCat
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build the category pages for CatAll set.", makCat);
//////////////////////////////////////////////////////////////////////////////

Real makArt

//////////////////////////////////////////////////////////////////////////////
Real makArt = If(And(ctrExe!="all",ctrExe!="art"), FALSE,
{
  Text WriteLn(makSep+"building all article pages...");
  
  Real CtrArt = TRUE; // Articles

  // Make article pages
  Set  cicArt = For(1, Card(CtrCmn), Real(Real pstNum)
  {
    Set  SelPdb = SetSubCicle(CtrCmn, pstNum, CtrPxA);
    Text CtrPag = TxtOutside2Tag(CtrCmn[pstNum]->pstTit,"<",">");

    Text filNam = PhtFileName(CtrPag); // Output file
    Text WriteLn("["+CtrPag+"\n  |"+filNam+"]");
    TmeFile("web/seed/seed.htm", "web/"+filNam)
  });

  Card(cicArt)
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build all articles pages.", makArt);
//////////////////////////////////////////////////////////////////////////////

Real makRot

//////////////////////////////////////////////////////////////////////////////
Real makRot = If(And(ctrExe!="all",ctrExe!="rot"), FALSE,
{
  Text WriteLn(makSep+"building root absolute page...");
  
  Text WriteLn("-> creación del index.html, homepage");
  Text inxHtm = ReadFile("web/categorias/presentacion.html");
  Text inxRot = ReplaceTable(inxHtm,
  [[
     [[ "\"../",                            "\""]]
  ]]);
  Real FilWriteIfDiff("web/index.html", inxRot);
  
  Text WriteLn("-> creación del indice de enlaces absolutos");
  // Save external references
  Text absSav = Replace(inxHtm, " href=\"http", " _XX_=\"_XX_"); 
  Text absRep = ReplaceTable(absSav,
  [[
     [[ " src=\"../", "  src=\"http://www.forense.info/"]],
     [[" href=\"../", " href=\"http://www.forense.info/"]]
  ]],1);
  
  // Recall external references
  Text absRec = Replace(absRep, " _XX_=\"_XX_", " href=\"http"); 
  Real FilWriteIfDiff("web/absoluto.html", absRec);

  Text WriteLn("-> creación de la pagina 404");
  Text errRec = Replace(absRec,
    "Formación en el",
    "La página no existe |");
  Real FilWriteIfDiff("web/error404.html", errRec);

  Text WriteLn("-> protección de directorios con absolutos");
  Real FilWriteIfDiff("web/articulos/index.html",  absRep);
  Real FilWriteIfDiff("web/categorias/index.html", absRep);
  Real FilWriteIfDiff("web/css/index.html",        absRep);
  Real FilWriteIfDiff("web/imagenes/index.html",   absRep);
  Real FilWriteIfDiff("web/practicas/index.html",  absRep);
  Real FilWriteIfDiff("web/src/index.html",        absRep);
  Real FilWriteIfDiff("web/tablas/index.html",     absRep);

  Real FilWriteIfDiff("web/seed/index.htm", absRep); // No en sitemap.xml

  Text WriteLn("-> common directory page, utf-8");
  FilCopy("../common/dir.html", "web/categorias/comxidir.html", TRUE)
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build root absolute page.", makRot);
//////////////////////////////////////////////////////////////////////////////

Real makXsm

//////////////////////////////////////////////////////////////////////////////
Real makXsm = If(And(ctrExe!="all",ctrExe!="xsm"), FALSE,
{
  Text WriteLn(makSep+"building xml site map...");
  XsmDir("web/sitemap.xml", "web", "http://www.forense.info/")
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build Xml site map.", makXsm);
//////////////////////////////////////////////////////////////////////////////

Real makFtp

//////////////////////////////////////////////////////////////////////////////
Real makFtp = If(!(ctrExe <: [["ftp","fup","all"]]), FALSE,
{
  Text msgTxt = If(ctrExe=="ftp", "ftp (all files)", "fup (update)");
  Text absPth = Replace(GetSourcePath(ctrExe),"/make.tol","");     // Absoluto
  Text locPth = absPth+"/web";                  // Ha de ser una ruta absoluta
  Text webNam = GetFileName(absPth);           // Nombre del directorio actual
  Text dtePth = If(ctrExe=="ftp", "", "ftp/"+webNam+".log");       // Relativo

  Text WriteLn(makSep+webNam+": building "+msgTxt+" from "+locPth+"...");
  FtpAll(
    webNam,                   // Web name 
    "www.forense.info",       // Host remoto 
    locPth,                   // Directorio local
    dtePth,                   // Fichero señal de fecha de actualizacion
    [[//dir        extension    type    binary or ascii 
      [["",        "html",     "html",  FALSE]],  // Ascii Html
      [["",        "ico",      "ico",   TRUE]],   // Binary favicon.ico
      [["",        "xml",      "xml",   FALSE]],  // Ascii site map, rss
      [["",        "js",       "js",    FALSE]],  // Javascript
      [["",        "css",      "css",   FALSE]],  // Css
      [["",        "pdf",      "pdf",   TRUE]],   // Pdf documents
      [["",        "png",      "png",   TRUE]]    // Png solo de css
    ]])
});
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Crear los ficheros de mandatos completos ftp o de actualizacion fup.",
makFtp);
//////////////////////////////////////////////////////////////////////////////

Real makSnd

//////////////////////////////////////////////////////////////////////////////
Real makSnd = If(And(ctrExe!="all",ctrExe!="snd"), FALSE,
{
  Text WriteLn(makSep+"sending files using ftp...");
  System("ftp\\iForense.bat")
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Send files via ftp.", makSnd);
//////////////////////////////////////////////////////////////////////////////

Real makRep

//////////////////////////////////////////////////////////////////////////////
Real makRep = If(ctrExe!="rep", FALSE,
{
  Text WriteLn(makSep+"massive file replacement...");
  Set  repTab = [[ [["\n<Pst.Sta> C\n",               "\n"]],
                   [["\n<Pst.Typ> post\n",            "\n"]],
                   [["\n<Pst.Aut> Antonio Salmerón\n","\n"]] ]];
  Text WriteLn(Replace(F(repTab),"\n",""));

  Set  filSet = DirExtAll(CtrAge, "age", FALSE, TRUE);
  Set  filCic = EvalSet(filSet, Real(Text filPth)
  {
    Text oldTxt = ReadFile(filPth);
    Text oldPth = Replace(filPth, ".age", ".seg");
    Text WriteLn(filPth+"->"+oldPth);
    Text WriteFile(oldPth, oldTxt);
    
    Text newTxt = ReplaceTable(oldTxt, repTab, 1); // Only one loop
    Text WriteFile(filPth, newTxt);
    
    TRUE
  });
  Card(filCic)
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Massive file replacement.", makRep);
//////////////////////////////////////////////////////////////////////////////

Real gloSta

//////////////////////////////////////////////////////////////////////////////
Real gloSta = GloStats(2); // Terminos del glosario con mas de 1 ocurrencias
//////////////////////////////////////////////////////////////////////////////
PutDescription("Ver los terminos más frecuentes del glosario.", gloSta);
//////////////////////////////////////////////////////////////////////////////

Finalización

Text WriteLn("\nForense.Info make: end");

Time oriented language

//////////////////////////////////////////////////////////////////////////////
// FILE    : make.tol
// AUTHOR  : http://www.asolver.com
// CLASS   : Metaprogramación; Hipertexto; Forense; Aleatorio
// VERSION : Tol 1.1.5; Tol 1.1.6; Tol 2.0.1
// PURPOSE : Programa constructor del sitio web del dominio forense.info
// dedicado a contenidos de formación en informática forense en donde se
// presentan 3 cursos de experto, especialista y máster en informática
// forense y pericial.
// 
// Los contenidos que emplea son posts con 3 niveles de importancia (status),
// que se organizan en un directorio, que se denomina agenda,
// este directorio tiene contiene varios ficheros,
// cada fichero contiene varios posts y cada post pertenece a una o varias
// clases (categorías) de posts.
// 
// Dentro de este directorio de agenda, sin pertenecer a ella,
// hay un glosario de términos de informática forense que
// permiten ilustrar los contenidos del sitio de forma no determinista.
// _
// Este programa para la creación del sitio web forense.info:
// a) está basado en un macro-expansor de Tol en Html a doble nivel,
// b) crea índices de artículos e ilustraciones de forma automática,
// c) rellena automáticamente la descripción y la lista de palabras clave
//    de cada página de una forma personalizada para ella (campos meta) y
// d) sus funciones principales son
//    crear todos los artículos de contenido,
//    crear todas las páginas por categorías,
//    crear la homepage y  las páginas absolutas y de control de errores,
//    crear el mapa del sitio web en XML y
//    poner los contenidos online.
// _
// Los posts de la agenda de contenidos pueden ser de los 3 siguientes
// niveles:
// a) anulados que no salen (se le denomina nivel A),
// b) bajos que se publican sólo dentro de sus clases,
//    pero no con árticulo propio (nivel B) y
// c) comunes que se publican dentro de su clase y con en su propio artículo
//    (nivel C), la mayoría de estos post tienen este nivel,
//    por lo que es el nivel por defecto.
// _
// Este programa para la construcción del sitio web forense.info utiliza un
// directorio de agenda de posts,
// dentro de este directorio los posts se estructuran en varios ficheros,
// usualmente un fichero para cada clase de posts,
// lo que permite organizar los post por su tipo de contenido,
// por ejemplo, toda la bibliografía esta en el mismo fichero.
// Estos ficheros de posts tienen de extensión .age.
// 
// En este mismo directorio se guarda un glosario de términos de
// informática forense y pericial con la que se complementa la
// información publicada en los posts.
// Los términos publicados junto con los posts bien pueden ser generales o
// bien ser relativos a la información concreta que proporciona en cada post.
// _
// Los posts pueden pertenecer a múltiples clases,
// también llamadas categorías, y se crean páginas Html de
// posts, artículos, en un directorio llamado articulos y
// de conjuntos de post para cada clase, en un directorio llamado categorias.
// 
// Las páginas de artículos se generan en este programa con la opción art,
// las páginas con los artículos agrupados por categorías con la opción cat,
// las páginas por defecto de cada directorio, las absolutas y las de control
// de errores con la opción rot y
// el mapa del sitio web en Xml con la opción xsm, siglas de Xml site map.
// _
// Este programa y la creación de este sitio web sobre informática forense
// está basado en un macro-expansor a doble nivel de Tol embebido en Html,
// donde la semilla de Html contiene Tol embebido y los post también pueden
// contener Tol embebido, por lo que dentro de la primera expansión,
// la de la semilla, se pueden realizar otras expansiones,
// que son las contenida en los post.
// 
// La macro-espansión de tol a doble nivel permite que los post contengan
// código en lenguaje Html y código en lenguaje Tol, ello permite,
// por ejemplo, crear índices o incluir definiciones de los términos del
// glosario de informática forense dentro de cada post.
// 
// Para el manejo de los términos del glosario de informática forense del que
// dispone este programa, en su libreria glo.tol, se emplea de forma básica
// el álgebra de conjuntos de Tol, para evitar, en la medida de lo posible,
// la repetición de la ocurrencia de la definición de los términos.
// _
// Este programa sólo escribe los ficheros de páginas Html que son diferentes
// a los ya creados en ejecuciones anteriores,
// de forma que no haya que enviar y poner online todo el conjunto de páginas
// sino las modificadas en fecha más reciente al último log de envío.
// Este control de recencia lo realiza la opción fup, que son las siglas de
// ftp update,
// frente a la opción ftp que genera ficheros de mandatos de envío con todo
// el contenido del web.
// 
// Nótese que las opciones fup y ftp sólo generan ficheros de mandatos ftp de
// envío y luego se pueden ejecutar estos ficheros con la opcion snd.
// 
// Aunque también ha de observarse que la inclusión de términos del
// glosario es tan variada que en casi todas las ejecuciones las páginas Html
// generadas son diferentes a las generadas en la anterior ejecución por lo
// que se produce su envío.
// _
// Los comentarios del código de este programa están realizados utilizando
// unas veces el español no acentuado dentro del código y otras veces el
// inglés.
// 
// Se ha comprobado el funcionamiento de este programa para las versiones de
// Tol 1.1.5, 1.1.6 y 2.0.1. 
// Con la version 1.1.1 da problemas, por ejemplo,
// por el uso que se hace del tercer parámetro de la función de texto
// TextReplace(texto, tabla, numero de ciclos),
// ya que la versión de Tol 1.1.1 no se contemplaba el número de ciclos.
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// INCLUDE
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nForense.Info make: begin");

//////////////////////////////////////////////////////////////////////////////
Set  allInc = Include("tol/inc.tol");
//////////////////////////////////////////////////////////////////////////////
PutDescription("Inclusion de las funciones comunes y de aplicacion.", allInc);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// STRUCTS
//////////////////////////////////////////////////////////////////////////////
// Status:
// A: Anulado, aunque este en la agenda no se publica
// B: Baja, solo se publica en su categoria, no como articulo independiente
// C: Comun, se publica en su categoria y como articulo independiente
// D: Destacado, se publica en su categoria y como articulo independiente y
//    si hay un menu de acceso a articulos importantes se incluye en el.
// Otros make web mios no terminan de implementar esto en toda su dimension
// En este (y probablemente en otros) no funcionaban los anulados porque en
// pdb.tol ponia a->pstSta != "-" en vez de a->pstSta != "A"
//////////////////////////////////////////////////////////////////////////////

Struct PdbSt   // Posts database
{
  Set  pstCla, // Conjunto de tipos de post
  Text pstSta, // Status A(nulado), B(ajo) y C(comun, por defecto)
  Text pstCod, // Identificador del post
  Text pstTh1, // Titulo del post en Html, h1, h2
  Text pstTit, // Titulo del post sin Html
  Date pstDte, // Fecha de ocurrencia
  Text pstAut, // Autor
  Text pstTxt  // Codigo de texto del post en Html+Javascript+Tol
};


//////////////////////////////////////////////////////////////////////////////
// CONSTANTS
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Text makSep = "\n"+Repeat("_", 72)+"\n";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Linea horizontal para separar fases de operacion.", makSep);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Text CtrAge = "agenda";
//////////////////////////////////////////////////////////////////////////////
PutDescription("All text files inside this directory.", CtrAge);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Text CtrFil = "poststat.csv";
//////////////////////////////////////////////////////////////////////////////
PutDescription("Para el volcado de estadisticas de posts.", CtrFil);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real CtrPxC =  20;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per category page.", CtrPxC);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real CtrPxA =   6;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per article page.", CtrPxA);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real CtrTit =   2;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per title.", CtrTit);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real CtrDes =  20;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per description.", CtrDes);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CatMnu =
[[
  "Presentación",
  "Derecho e informática",
  "Informática forense",
  "Investigación básica",
  "Investigación avanzada",
  "Base documental"
]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias del menu principal.", CatMnu);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set CatAre = [["Área"]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Areas de conocimiento.", CatAre);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set CatMod = [["Módulo"]];       // 
//////////////////////////////////////////////////////////////////////////////
PutDescription("Módulos de las areas de conocimiento.", CatMod);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set CatBib = [["Bibliografía"]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Referencias bibliograficas.", CatBib);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set CatCon = [["Contacto"]];     // Contacto y privacidad
//////////////////////////////////////////////////////////////////////////////
PutDescription("Datos de contacto y privacidad.", CatCon);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set CatTop = CatMnu << CatAre << CatMod << CatBib << CatCon;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Todas las categorias de alto nivel.", CatTop);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set CatNot =
[[
  "Tema",
  "Resumen",
  "Multimedia", "Documentación PDF", "Vídeo MP4",
  "Mapa del web"
]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Not to top category list.", CatNot);
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set CatAll = CatTop << CatNot;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Todas las categorias de cualquier nivel.", CatAll);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// MAKE
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nForense.Info: process");

//////////////////////////////////////////////////////////////////////////////
Text ctrExe = If(Not(ObjectExist("Text","ctrBat")), "hlp",
              If(ctrBat=="",                        "hlp",
                                                    ToLower(ctrBat)));
//////////////////////////////////////////////////////////////////////////////
PutDescription("Argumento validado para la ejecucion del make.", ctrExe);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real makHlp = If(ctrExe!="hlp", FALSE,
{
  Text WriteLn(
  makSep+"help:
  Usage: make [OPTION]
  Builds Forense.Info site
  OPTION
    cat: build all category pages
    art: build all articles pages
    rot: build root absolute page
    xsm: build sm site maps
    ftp: build ftp files (go to ftp dir and run manually)
    fup: build a file update protocol (newer than ftp.log file)
    snd: send file via ftp
    all: do all works: xml, fup...
    rep: massive file replacement (internal order)
    hlp: show this help
    tst: test some functions");
  TRUE
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Es cierto si se ha visualizado la ayuda.", makHlp);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// Read agenda
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Set CtrPdb = If(! (ctrExe <: [["all", "cat", "art"]]), Empty,
                PdbRead(CtrAge)); // Read all posts
//////////////////////////////////////////////////////////////////////////////
PutDescription("Read all posts.", CtrPdb);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CtrCmn = Select(CtrPdb, Real(Set a) { a->pstSta >= "C" });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Posts comunes.", CtrCmn);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("Status __C "+FormatReal(Card(CtrCmn),"%3.0lf")+" registers");


//////////////////////////////////////////////////////////////////////////////
Set CtrAre = Select(CtrCmn, Real(Set a) { And(  CatAre[1] <: a->pstCla,
                                              !("Resumen" <: a->pstCla)) });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Post de areas de conocimiento.", CtrAre);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CtrMod = Select(CtrCmn, Real(Set a) { CatMod[1] <: a->pstCla });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Post de los modulos de las areas de conocimiento.", CtrMod);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CtrBib = Select(CtrCmn, Real(Set a) { CatBib[1] <: a->pstCla });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Post de referencias bibliograficas.", CtrBib);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real makCat = If(And(ctrExe!="all",ctrExe!="cat"), FALSE,
{
  Text WriteLn(makSep+"building all category pages...");
  Text WriteFile(CtrFil, "Posts; Class\n");
  
  Real CtrArt = FALSE; // Categories, not articles

  // Make category pages
  Set  cicCat = EvalSet(CatAll, Real(Text CtrPag)
  {
    Text filNam = PhtFileName(CtrPag); // Output file
    Text WriteLn("["+CtrPag+"|"+filNam+"]");
    
    Set  SelPdb = // Selected post from database for this page
    {
      Set selSet = Select(CtrPdb, Real(Set pdbObj) { CtrPag <: pdbObj->pstCla });
      Real selCrd = Card(selSet);
      Text txtCrd = FormatReal(selCrd,"%.0lf");
      Text WriteLn("  "+txtCrd+" posts selected");
      Text AppendFile(CtrFil, txtCrd+"; "+CtrPag+"\n");
  
      selSet
    };

    TmeFile("web/seed/seed.htm", "web/"+filNam)
  });

  // Make special category completo, all the posts
  Real  allCat =
  {
    Text CtrPag = "Completo";
    Text filNam = PhtFileName(CtrPag); // Output file
    Text WriteLn("["+CtrPag+"|"+filNam+"]");
    Set  SelPdb = CtrPdb; // Todos los posts
    TmeFile("web/seed/seed.htm", "web/"+filNam)
  };


  Card(cicCat)+allCat
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build the category pages for CatAll set.", makCat);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real makArt = If(And(ctrExe!="all",ctrExe!="art"), FALSE,
{
  Text WriteLn(makSep+"building all article pages...");
  
  Real CtrArt = TRUE; // Articles

  // Make article pages
  Set  cicArt = For(1, Card(CtrCmn), Real(Real pstNum)
  {
    Set  SelPdb = SetSubCicle(CtrCmn, pstNum, CtrPxA);
    Text CtrPag = TxtOutside2Tag(CtrCmn[pstNum]->pstTit,"<",">");

    Text filNam = PhtFileName(CtrPag); // Output file
    Text WriteLn("["+CtrPag+"\n  |"+filNam+"]");
    TmeFile("web/seed/seed.htm", "web/"+filNam)
  });

  Card(cicArt)
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build all articles pages.", makArt);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real makRot = If(And(ctrExe!="all",ctrExe!="rot"), FALSE,
{
  Text WriteLn(makSep+"building root absolute page...");
  
  Text WriteLn("-> creación del index.html, homepage");
  Text inxHtm = ReadFile("web/categorias/presentacion.html");
  Text inxRot = ReplaceTable(inxHtm,
  [[
     [[ "\"../",                            "\""]]
  ]]);
  Real FilWriteIfDiff("web/index.html", inxRot);
  
  Text WriteLn("-> creación del indice de enlaces absolutos");
  // Save external references
  Text absSav = Replace(inxHtm, " href=\"http", " _XX_=\"_XX_"); 
  Text absRep = ReplaceTable(absSav,
  [[
     [[ " src=\"../", "  src=\"http://www.forense.info/"]],
     [[" href=\"../", " href=\"http://www.forense.info/"]]
  ]],1);
  
  // Recall external references
  Text absRec = Replace(absRep, " _XX_=\"_XX_", " href=\"http"); 
  Real FilWriteIfDiff("web/absoluto.html", absRec);

  Text WriteLn("-> creación de la pagina 404");
  Text errRec = Replace(absRec,
    "Formación en el",
    "La página no existe |");
  Real FilWriteIfDiff("web/error404.html", errRec);

  Text WriteLn("-> protección de directorios con absolutos");
  Real FilWriteIfDiff("web/articulos/index.html",  absRep);
  Real FilWriteIfDiff("web/categorias/index.html", absRep);
  Real FilWriteIfDiff("web/css/index.html",        absRep);
  Real FilWriteIfDiff("web/imagenes/index.html",   absRep);
  Real FilWriteIfDiff("web/practicas/index.html",  absRep);
  Real FilWriteIfDiff("web/src/index.html",        absRep);
  Real FilWriteIfDiff("web/tablas/index.html",     absRep);

  Real FilWriteIfDiff("web/seed/index.htm", absRep); // No en sitemap.xml

  Text WriteLn("-> common directory page, utf-8");
  FilCopy("../common/dir.html", "web/categorias/comxidir.html", TRUE)
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build root absolute page.", makRot);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real makXsm = If(And(ctrExe!="all",ctrExe!="xsm"), FALSE,
{
  Text WriteLn(makSep+"building xml site map...");
  XsmDir("web/sitemap.xml", "web", "http://www.forense.info/")
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build Xml site map.", makXsm);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real makFtp = If(!(ctrExe <: [["ftp","fup","all"]]), FALSE,
{
  Text msgTxt = If(ctrExe=="ftp", "ftp (all files)", "fup (update)");
  Text absPth = Replace(GetSourcePath(ctrExe),"/make.tol","");     // Absoluto
  Text locPth = absPth+"/web";                  // Ha de ser una ruta absoluta
  Text webNam = GetFileName(absPth);           // Nombre del directorio actual
  Text dtePth = If(ctrExe=="ftp", "", "ftp/"+webNam+".log");       // Relativo

  Text WriteLn(makSep+webNam+": building "+msgTxt+" from "+locPth+"...");
  FtpAll(
    webNam,                   // Web name 
    "www.forense.info",       // Host remoto 
    locPth,                   // Directorio local
    dtePth,                   // Fichero señal de fecha de actualizacion
    [[//dir        extension    type    binary or ascii 
      [["",        "html",     "html",  FALSE]],  // Ascii Html
      [["",        "ico",      "ico",   TRUE]],   // Binary favicon.ico
      [["",        "xml",      "xml",   FALSE]],  // Ascii site map, rss
      [["",        "js",       "js",    FALSE]],  // Javascript
      [["",        "css",      "css",   FALSE]],  // Css
      [["",        "pdf",      "pdf",   TRUE]],   // Pdf documents
      [["",        "png",      "png",   TRUE]]    // Png solo de css
    ]])
});
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Crear los ficheros de mandatos completos ftp o de actualizacion fup.",
makFtp);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real makSnd = If(And(ctrExe!="all",ctrExe!="snd"), FALSE,
{
  Text WriteLn(makSep+"sending files using ftp...");
  System("ftp\\iForense.bat")
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Send files via ftp.", makSnd);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real makRep = If(ctrExe!="rep", FALSE,
{
  Text WriteLn(makSep+"massive file replacement...");
  Set  repTab = [[ [["\n<Pst.Sta> C\n",               "\n"]],
                   [["\n<Pst.Typ> post\n",            "\n"]],
                   [["\n<Pst.Aut> Antonio Salmerón\n","\n"]] ]];
  Text WriteLn(Replace(F(repTab),"\n",""));

  Set  filSet = DirExtAll(CtrAge, "age", FALSE, TRUE);
  Set  filCic = EvalSet(filSet, Real(Text filPth)
  {
    Text oldTxt = ReadFile(filPth);
    Text oldPth = Replace(filPth, ".age", ".seg");
    Text WriteLn(filPth+"->"+oldPth);
    Text WriteFile(oldPth, oldTxt);
    
    Text newTxt = ReplaceTable(oldTxt, repTab, 1); // Only one loop
    Text WriteFile(filPth, newTxt);
    
    TRUE
  });
  Card(filCic)
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Massive file replacement.", makRep);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real gloSta = GloStats(2); // Terminos del glosario con mas de 1 ocurrencias
//////////////////////////////////////////////////////////////////////////////
PutDescription("Ver los terminos más frecuentes del glosario.", gloSta);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// END
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\nForense.Info make: end");

2015 asolver.com | Aviso legal | XHTML | Δ Θ Ξ | Creative Commons | Mapa y funciones del sitio

Tol