Secciones de la página

con-Q. tv


Árbol de ficheros


Declaraciones


Inclusiones


Estructuras de datos


Constantes


Proceso


Read agenda


Pruebas


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 con-Q.tv

Constructor de la Newsletter AVPPM con-Q.tv que genera tanto las páginas de la newsletter online, con el histórico de noticias, como el contenido de cada newsletter periódica, con las últimas noticias, que se envía a los socios por correo electrónico. Las noticias son posts con 4 niveles de importancia (status), que se organizan en un directorio con ficheros y estos con posts, que pueden pertenecer a múltiples clases o categorías. El programa esta basado en un macro-expansor a doble nivel de Tol en Html, que permite, por ejemplo, crear índices automáticos por artículos, por clases, por años que se tratan como clases, por niveles e índices de ilustraciones y por categorías de ilustraciones.

Los contenidos del sitio web con-Q.tv no son estáticos sino que cambian ligeramente en cada ejecución del programa lo que se consigue mediante textos alternativos cuando se redactan los posts. Este programa rellena automáticamente las descripciones y la lista de palabras clave de forma diferenciada para cada página como puede verse en los campos meta description y meta keywords de las páginas Html generadas. Las funciones principales de este programa son crear artículos, páginas de categorías, páginas de control de errores, el mapa del sitio web, crear los textos de la newsletter para ser enviados por email y poner todos los contenidos online.

Los posts pueden ser de las 4 siguientes niveles: a) anulados que no salen (que se determinan con la letra A), b) bajos con un tipo de letra pequeña en su clase y con artículo propio (con la letra B), c) comunes con un tipo de letra grande, fondo blanco, en su clase y con su articulo (con la letra C) y d) destacados con letra grande, fondo rosa, en su clase y en su artículo (con la letra D). Este programa emplea un directorio de agenda de posts, dentro de este directorio los posts se estructuran en varios ficheros que permiten organizarlos por su tipo de contenido y sus años de publicación.

Los posts pueden pertenecer a múltiples clases y se crean páginas Html de posts y de conjuntos de post por cada clase, a estas clases tambián se las denomina categorías. Con este programa las páginas de artículos se generan con la opción art, las páginas con los artículos agrupados por categorías con la opción cat que tambien crea los índices de clasificación de los artículos, las páginas Html por defecto del sitio (index.html) y de cada directorio, la absoluta y la de control de errores con la opción rot, el mapa del sitio en Xml con la opción xsm, de Xml site map y las opciones ftp, fup y snd permiten poner el contenido en online.

Este programa y la creación de este sitio web esta 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 que se emplea en este programa permite que los post contengan código Html y código Tol, por ejemplo, para crear índices, realizar cálculos, poner diferentes contenidos para una misma página en diferentes ejecuciones, etc.

Los comentarios del código de este programa están realizados utilizando unas veces el español, sin acentos dentro del código, y otras veces el inglés. 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 todo el conjunto de páginas sino las de modificadas de fecha más reciente que el último log de envío por ftp. Este control lo realiza la opción fup, 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 con la opción snd.

Árbol de ficheros

con-Q.tv construye las páginas del sitio y newsletter Con-Q.tv

  • make.tol proceso principal de generacion del sitio web y la newsletter
  • tol directorios de código Tol
    • cmm funciones comunes
      • txt.tol funciones de textos
      • set.tol funciones de conjuntos
      • fil.tol funciones de ficheros
      • dir.tol funciones directorios
      • tme.tol funciones del macro-expansor de Tol en Html
      • img.tol funciones de imagenes Html
      • ftp.tol para generar mandatos para hacer Ftp
      • xsm.tol para construir sitemaps en Xml
    • app funciones especificas de aplicacion
      • ads.tol funciones de anuncios de publicidad
      • pdb.tol funciones 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 Tol
  • agenda directorio destinado a la agenda de post
  • web directorio destinado a las páginas web generadas
    • css directorio para ficheros de estilo
      • common.css fichero de estilo Css para las páginas Html
    • seed directorio para ficheros semilla
      • seed.htm semilla de página Html con Tol embebido
      • lopd.htm texto Lopd para insertar en la newsletter de envío por email
    • src directorio para ficheros con código Javascript
      • common.js funciones Javascript para diferentes redes sociales
    • noticia directorio para páginas de noticias
    • quiosco directorio para páginas Html de categorias
      • asamblea.html ejemplo de página de categoría generada automáticamente
    • sitemap.xml mapa completo del sitio web generado en Xml automáticamente
  • presentacion.html vídeo de presentación de la Newsletter de la Avppm
  • con-q_tv.pdf documento resumen de funciones del programa de la newsletter

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.
  • Real CtrPxW
    Number of posts per whole posts page.
  • Real CtrKxP
    Number of keywords per page.
  • Real CtrPxC
    Number of posts per category page.
  • Real CtrPxN
    Number of posts per newsletter/notice page.
  • Real CtrPxA
    Number of posts per article page.
  • Real CtrPxD
    Number of posts per description.
  • Real CtrCxD
    Characters per description, LinkedIn uses 250 and Facebook uses 300.
  • Real CtrPxT
    Number of posts per title.
  • Real CtrAxP
    Advertisements per page ratio.
  • Set CatInx
    Categorias para el indice.
  • Set CatYea
    Categorias por años.
  • Set CatNot
    Categorias no indexables.
  • Set CatPag
    Categorias de las paginas.
  • Set CatAll
    Hay paginas para todas las categorias.

Proceso

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

Read agenda

  • Set CtrNoA
    Read all posts minus A(nulated).
  • Set CtrPdb
    Conjunto de posts Basicos, Comunes y Destacados.
  • Set CtrCmn
    Conjunto de posts Comunes y Destacados.
  • Set CtrDst
    Conjunto de posts Destacados.
  • Real makCat
    Build the category pages for CatPag 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.

Pruebas

  • Real makTst
    Realizar el test de algunas funcionalidades necesarias para el proceso.

Inclusiones

Set allInc

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

Estructuras de datos

Struct PdbSt   // Posts database
{
  Set  pstCla, // Conjunto de tipos de post
  Text pstSta, // Status A(nulado), B(ajo), C(comun), D(estacado)
  Text pstFil, // Camino del fichero (path)
  Text pstTit, // Titulo del post sin Html
  Text pstHtm, // Texto del post en Html
  Text pstRes, // Texto resumen del post en Html
  Text pstTxt  // Texto del post en Ascii puro
};

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);
//////////////////////////////////////////////////////////////////////////////

Real CtrPxW

//////////////////////////////////////////////////////////////////////////////
Real CtrPxW =  64;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per whole posts page.", CtrPxW);
//////////////////////////////////////////////////////////////////////////////

Real CtrKxP

//////////////////////////////////////////////////////////////////////////////
Real CtrKxP =  32;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of keywords per page.", CtrKxP);
//////////////////////////////////////////////////////////////////////////////

Real CtrPxC

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

Real CtrPxN

//////////////////////////////////////////////////////////////////////////////
Real CtrPxN =   4;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per newsletter/notice page.", CtrPxN);
//////////////////////////////////////////////////////////////////////////////

Real CtrPxA

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

Real CtrPxD

//////////////////////////////////////////////////////////////////////////////
Real CtrPxD =   6;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per description.", CtrPxD);
//////////////////////////////////////////////////////////////////////////////

Real CtrCxD

//////////////////////////////////////////////////////////////////////////////
Real CtrCxD = 384;
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Characters per description, LinkedIn uses 250 and Facebook uses 300.",
CtrCxD);
//////////////////////////////////////////////////////////////////////////////

Real CtrPxT

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

Real CtrAxP

//////////////////////////////////////////////////////////////////////////////
Real CtrAxP = .00; // Lo anulo antes de lanzar newsletter luego pondre 0.50
//////////////////////////////////////////////////////////////////////////////
PutDescription("Advertisements per page ratio.", CtrAxP);
//////////////////////////////////////////////////////////////////////////////

Set CatInx

//////////////////////////////////////////////////////////////////////////////
Set CatInx =
[[
  "ANEI",
  "Asamblea",
  "Ayuntamiento de Madrid",
  "Cámara de Comercio",
  "CEIM CEOE",
  "Cliente",
  "CNC",
  "Consultoría",
  "Comunidad de Madrid",
  "Consumidor",
  "Desarrollo de negocio",
  "Distribuidor",
  "Economía",
  "Editor",
  "Elección",
  "Historia",
  "Internet",
  "Junta directiva",
  "Lector",
  "Legal",
  "Libro",
  "Madrid Emprende",
  "Ministerio de Industria",
  "Nota de prensa",
  "Prensa",
  "Publicidad",
  "Punto de conveniencia";
  "Qred",
  "Quiosco",
  "Quiosquero",
  "Red.es";
  "Revista",
  "Servicio de pago centralizado",
  "Tecnología",
  "Verano",
  "WiFi"
]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias para el indice.", CatInx);
//////////////////////////////////////////////////////////////////////////////

Set CatYea

//////////////////////////////////////////////////////////////////////////////
Set CatYea = PdbYearSet(CtrAge);
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias por años.", CatYea);
//////////////////////////////////////////////////////////////////////////////

Set CatNot

//////////////////////////////////////////////////////////////////////////////
Set CatNot =
[[
  "Advertencia legal", // Todas son bajas
  "Ilustración",       // Listas de ilustraciones
  "Mapa",              // Indice de articulos
  "Noticia",           // Son casi todos los articulos y repite el indice
  "Post"               // Todos son post, pues se mete automaticamente
]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias no indexables.", CatNot);
//////////////////////////////////////////////////////////////////////////////

Set CatPag

//////////////////////////////////////////////////////////////////////////////
Set CatPag = CatNot << CatYea << CatInx;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias de las paginas.", CatPag);
//////////////////////////////////////////////////////////////////////////////

Set CatAll

//////////////////////////////////////////////////////////////////////////////
Set CatAll = CatPag;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Hay paginas para todas las categorias.", 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 con-Q.tv site
  OPTION
    cat: build all category pages
    art: build all articles pages
    rot: build root absolute page
    xsm: build xml 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: cat, art, rot, xsm, fup, snd
    hlp: show this help
    tst: test some functions");
  TRUE
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Es cierto si se ha visualizado la ayuda.", makHlp);
//////////////////////////////////////////////////////////////////////////////

Read agenda

Set CtrNoA

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

Set CtrPdb

//////////////////////////////////////////////////////////////////////////////
Set  CtrPdb = Select(CtrNoA, Real(Set a) { a->pstSta <: [["B","C","D"]] });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto de posts Basicos, Comunes y Destacados.", CtrPdb);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("Status _BCD "+F(Card(CtrPdb))+" registers");

Set CtrCmn

//////////////////////////////////////////////////////////////////////////////
Set  CtrCmn = Select(CtrPdb, Real(Set a) { a->pstSta <: [["C","D"]] });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto de posts Comunes y Destacados.", CtrCmn);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("Status __CD "+F(Card(CtrCmn))+" registers");

Set CtrDst

//////////////////////////////////////////////////////////////////////////////
Set  CtrDst = Select(CtrCmn, Real(Set a) { a->pstSta == "D" }); // Destacado
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto de posts Destacados.", CtrDst);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("Status ___D "+F(Card(CtrDst))+" registers");

Real makCat

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

  // Make category pages
  Set  cicCat = EvalSet(CatPag, Real(Text CtrPag)
  {
    Text CtrDif = CtrPag; // Diferencia clases de artículos similares
    Text CtrFil = PhtCleanFilePath("web/quiosco", CtrPag, "html"); // Output
    Text Write(CtrFil+";"+CtrPag);

    Real maxPst = Case(CtrPag=="Noticia", CtrPxN,  // Pocos
                       CtrPag=="Post",    CtrPxW,  // Muchos, revisar en Word
                       TRUE,              CtrPxC); // Ni pocos ni muchos
    
    Set  SelPdb = // Selected post from database for this page
    {
      Set selSet = SetFirstN(Select(CtrPdb, Real(Set objPst) // B, C y D
                                    { CtrPag <: objPst->pstCla }), maxPst);
      Real selCrd = Card(selSet);
      Text WriteLn(";"+F(selCrd)+";posts selected");
  
      selSet
    };
    TmeFile("web/seed/seed.htm", CtrFil)
  });

  Card(cicCat)
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build the category pages for CatPag 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) // Only C y D
  {
    Set  SelPdb = SetSubCicle(CtrCmn, pstNum, CtrPxA);
    Set  pstFst = CtrCmn[pstNum]; // The very first
    Text CtrPag = pstFst->pstTit;
    Text CtrDif = PhtSpanishDate(pstFst);
    Text CtrFil = "web/"+pstFst->pstFil; // Output
    Text WriteLn(CtrDif+"|"+CtrFil+"\n"+Repeat(" ",10)+"|"+CtrPag);
    TmeFile("web/seed/seed.htm", CtrFil)
  });

  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 inxHtm = ReadFile("web/quiosco/noticia.html");

  // Texto Lopd que se inserta en la pagina newsletter de envio por email
  Text lpdHtm = ReadFile("web/seed/lopd.htm");

  Text cssSrc = ReadFile("web/css/common.css");
  Text cssOld = 
    "<link href='../css/common.css' rel='stylesheet' type='text/css' />";
  Text cmmNew =
    "<style type='text/css'>\n"    +
    Replace(cssSrc, " url('../", " url('http://www.con-q.tv/") +
    "</style>";

  Text absSav = ReplaceTable(inxHtm, // Save external references
  [[
     [[ " src=\"http:",    " src=\"Http:"]], // H grande evita cambios
     [[" href=\"http:",   " href=\"Http:"]]  // H grande evita cambios
  ]],1);

  Text absUrl = "\"http://www.con-q.tv/";
  Text absRep = ReplaceTable(absSav,
  [[
     [[ " src=\"../",    " src="+absUrl]],
     [[" href=\"../",   " href="+absUrl]],
     [["<!--LPD-->", lpdHtm]],
     [[      cssOld, cmmNew]]
  ]],1);
  Text absErr = Replace(absRep, "<h1>", "<h1 class='Red'>");

  Real FilWriteIfDiff("web/index.html",         absRep);
  Real FilWriteIfDiff("web/css/index.html",     absRep);
  Real FilWriteIfDiff("web/foto/index.html",    absRep);
  Real FilWriteIfDiff("web/noticia/index.html", absRep);
  Real FilWriteIfDiff("web/quiosco/index.html", absRep);
  Real FilWriteIfDiff("web/seed/index.htm",     absRep); // No en sitemap.xml

  Real FilWriteIfDiff("web/error404.html",      absErr);

  Text newCls = PhtCleanHtml(absRep);
  Real FilWriteIfDiff("web/newsletter.html", newCls); // Absolute + cleaned
  Real FilWriteIfDiff("web/newslocal.html",           // Relativa + cleaned
       Replace(PhtCleanHtml(absRep), " src="+absUrl, " src=\""));

  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.con-q.tv/")
});
//////////////////////////////////////////////////////////////////////////////
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.con-q.tv",           // 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
      [["",        "pdf",      "pdf",   TRUE]],   // Documentos Pdf
      [["src",     "js",       "js",    FALSE]],  // Javascript
      [["css",     "css",      "css",   FALSE]],  // Css
      [["css",     "png",      "png",   TRUE]],   // Png solo de css
      [["",        "jpg",      "jpg",   TRUE]]    // Jpeg de css y foto
    ]])
});
//////////////////////////////////////////////////////////////////////////////
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(W("ftp/con-Q.tv.bat"))
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Send files via ftp.", makSnd);
//////////////////////////////////////////////////////////////////////////////

Pruebas

Real makTst

//////////////////////////////////////////////////////////////////////////////
Real makTst = If(ctrExe != "tst", FALSE,
{
  Text WriteLn(makSep+"test function SetGetRand()");

  Real numCic = 2000;
  Set  letCic = For(1, numCic, Text(Real pos)
  { SetGetRand([["a","b","c","d"]]) });
  Set letCla = Classify(letCic, Real(Text a, Text b) { Compare(a, b) });
  Set letTst = EvalSet(letCla, Real(Set letSet)
  {
    Text WriteLn(letSet[1]+" "+FormatReal(Card(letSet),"%.0lf")
                          +" "+FormatReal(Card(letSet)/numCic,"%.2lf"));
    Card(letSet)
  });

  TRUE
});
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Realizar el test de algunas funcionalidades necesarias para el proceso.",
makTst);
//////////////////////////////////////////////////////////////////////////////

Finalización

Text WriteLn("\ncon-Q.tv make: end");

Time oriented language

//////////////////////////////////////////////////////////////////////////////
// FILE    : make.tol
// AUTHOR  : http://www.asolver.com
// CLASS   : Metaprogramación; Hipertexto; Editorial; Aleatorio
// VERSION : Tol 1.1.5; Tol 1.1.6; Tol 2.0.1
// PURPOSE : Constructor de la Newsletter AVPPM con-Q.tv que genera
// tanto las páginas de la newsletter online, con el histórico de noticias,
// como el contenido de cada newsletter periódica, con las últimas noticias,
// que se envía a los socios por correo electrónico.
// 
// Las noticias son posts con 4 niveles de importancia (status),
// que se organizan en un directorio con ficheros y estos con posts,
// que pueden pertenecer a múltiples clases o categorías.
// 
// El programa esta basado en un macro-expansor a doble nivel de Tol en Html,
// que permite, por ejemplo, crear índices automáticos por artículos, por
// clases, por años que se tratan como clases, por niveles e
// índices de ilustraciones y por categorías de ilustraciones.
// _
// Los contenidos del sitio web con-Q.tv no son estáticos sino que cambian
// ligeramente en cada ejecución del programa lo que se consigue mediante
// textos alternativos cuando se redactan los posts.
// 
// Este programa rellena automáticamente las descripciones y la lista de
// palabras clave de forma diferenciada para cada página como puede verse
// en los campos meta description y meta keywords de las páginas Html
// generadas.
// 
// Las funciones principales de este programa son crear artículos, páginas de
// categorías, páginas de control de errores, el mapa del sitio web, crear
// los textos de la newsletter para ser enviados por email y poner todos los
// contenidos online.
// _
// Los posts pueden ser de las 4 siguientes niveles:
// a) anulados que no salen (que se determinan con la letra A),
// b) bajos con un tipo de letra pequeña en su clase y con artículo propio
//    (con la letra B),
// c) comunes con un tipo de letra grande, fondo blanco, en su clase y con su
//    articulo (con la letra C) y
// d) destacados con letra grande, fondo rosa, en su clase y en su artículo
//    (con la letra D).
// 
// Este programa emplea un directorio de agenda de posts, dentro de este
// directorio los posts se estructuran en varios ficheros que permiten
// organizarlos por su tipo de contenido y sus años de publicación.
// _
// Los posts pueden pertenecer a múltiples clases y se crean páginas Html de
// posts y de conjuntos de post por cada clase, a estas clases tambián se las
// denomina categorías.
// 
// Con este programa
// las páginas de artículos se generan con la opción art,
// las páginas con los artículos agrupados por categorías con la opción cat
// que tambien crea los índices de clasificación de los artículos,
// las páginas Html por defecto del sitio (index.html) y de cada directorio,
// la absoluta y la de control de errores con la opción rot,
// el mapa del sitio en Xml con la opción xsm, de Xml site map y
// las opciones ftp, fup y snd permiten poner el contenido en online.
// _
// Este programa y la creación de este sitio web esta 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 que se emplea en este programa
// permite que los post contengan código Html y código Tol, por ejemplo,
// para crear índices, realizar cálculos, poner diferentes contenidos
// para una misma página en diferentes ejecuciones, etc.
// _
// Los comentarios del código de este programa están realizados utilizando
// unas veces el español, sin acentos dentro del código, y otras veces el
// inglés.
// 
// 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
// todo el conjunto de páginas sino las de modificadas de fecha más reciente
// que el último log de envío por ftp.
// 
// Este control lo realiza la opción fup, 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 con la opción snd.
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// INCLUDE
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\ncon-Q.tv make: begin");

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


//////////////////////////////////////////////////////////////////////////////
// STRUCTS
//////////////////////////////////////////////////////////////////////////////

Struct PdbSt   // Posts database
{
  Set  pstCla, // Conjunto de tipos de post
  Text pstSta, // Status A(nulado), B(ajo), C(comun), D(estacado)
  Text pstFil, // Camino del fichero (path)
  Text pstTit, // Titulo del post sin Html
  Text pstHtm, // Texto del post en Html
  Text pstRes, // Texto resumen del post en Html
  Text pstTxt  // Texto del post en Ascii puro
};


//////////////////////////////////////////////////////////////////////////////
// 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);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real CtrPxW =  64;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per whole posts page.", CtrPxW);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real CtrKxP =  32;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of keywords per page.", CtrKxP);
//////////////////////////////////////////////////////////////////////////////


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


//////////////////////////////////////////////////////////////////////////////
Real CtrPxN =   4;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per newsletter/notice page.", CtrPxN);
//////////////////////////////////////////////////////////////////////////////


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


//////////////////////////////////////////////////////////////////////////////
Real CtrPxD =   6;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Number of posts per description.", CtrPxD);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Real CtrCxD = 384;
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Characters per description, LinkedIn uses 250 and Facebook uses 300.",
CtrCxD);
//////////////////////////////////////////////////////////////////////////////


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


//////////////////////////////////////////////////////////////////////////////
Real CtrAxP = .00; // Lo anulo antes de lanzar newsletter luego pondre 0.50
//////////////////////////////////////////////////////////////////////////////
PutDescription("Advertisements per page ratio.", CtrAxP);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CatInx =
[[
  "ANEI",
  "Asamblea",
  "Ayuntamiento de Madrid",
  "Cámara de Comercio",
  "CEIM CEOE",
  "Cliente",
  "CNC",
  "Consultoría",
  "Comunidad de Madrid",
  "Consumidor",
  "Desarrollo de negocio",
  "Distribuidor",
  "Economía",
  "Editor",
  "Elección",
  "Historia",
  "Internet",
  "Junta directiva",
  "Lector",
  "Legal",
  "Libro",
  "Madrid Emprende",
  "Ministerio de Industria",
  "Nota de prensa",
  "Prensa",
  "Publicidad",
  "Punto de conveniencia";
  "Qred",
  "Quiosco",
  "Quiosquero",
  "Red.es";
  "Revista",
  "Servicio de pago centralizado",
  "Tecnología",
  "Verano",
  "WiFi"
]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias para el indice.", CatInx);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CatYea = PdbYearSet(CtrAge);
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias por años.", CatYea);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CatNot =
[[
  "Advertencia legal", // Todas son bajas
  "Ilustración",       // Listas de ilustraciones
  "Mapa",              // Indice de articulos
  "Noticia",           // Son casi todos los articulos y repite el indice
  "Post"               // Todos son post, pues se mete automaticamente
]];
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias no indexables.", CatNot);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CatPag = CatNot << CatYea << CatInx;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Categorias de las paginas.", CatPag);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
Set CatAll = CatPag;
//////////////////////////////////////////////////////////////////////////////
PutDescription("Hay paginas para todas las categorias.", CatAll);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// MAKE
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\ncon-Q.tv make: 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 con-Q.tv site
  OPTION
    cat: build all category pages
    art: build all articles pages
    rot: build root absolute page
    xsm: build xml 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: cat, art, rot, xsm, fup, snd
    hlp: show this help
    tst: test some functions");
  TRUE
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Es cierto si se ha visualizado la ayuda.", makHlp);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// Read agenda
//////////////////////////////////////////////////////////////////////////////
Text Write(makSep);

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


//////////////////////////////////////////////////////////////////////////////
Set  CtrPdb = Select(CtrNoA, Real(Set a) { a->pstSta <: [["B","C","D"]] });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto de posts Basicos, Comunes y Destacados.", CtrPdb);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("Status _BCD "+F(Card(CtrPdb))+" registers");


//////////////////////////////////////////////////////////////////////////////
Set  CtrCmn = Select(CtrPdb, Real(Set a) { a->pstSta <: [["C","D"]] });
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto de posts Comunes y Destacados.", CtrCmn);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("Status __CD "+F(Card(CtrCmn))+" registers");


//////////////////////////////////////////////////////////////////////////////
Set  CtrDst = Select(CtrCmn, Real(Set a) { a->pstSta == "D" }); // Destacado
//////////////////////////////////////////////////////////////////////////////
PutDescription("Conjunto de posts Destacados.", CtrDst);
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("Status ___D "+F(Card(CtrDst))+" registers");


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

  // Make category pages
  Set  cicCat = EvalSet(CatPag, Real(Text CtrPag)
  {
    Text CtrDif = CtrPag; // Diferencia clases de artículos similares
    Text CtrFil = PhtCleanFilePath("web/quiosco", CtrPag, "html"); // Output
    Text Write(CtrFil+";"+CtrPag);

    Real maxPst = Case(CtrPag=="Noticia", CtrPxN,  // Pocos
                       CtrPag=="Post",    CtrPxW,  // Muchos, revisar en Word
                       TRUE,              CtrPxC); // Ni pocos ni muchos
    
    Set  SelPdb = // Selected post from database for this page
    {
      Set selSet = SetFirstN(Select(CtrPdb, Real(Set objPst) // B, C y D
                                    { CtrPag <: objPst->pstCla }), maxPst);
      Real selCrd = Card(selSet);
      Text WriteLn(";"+F(selCrd)+";posts selected");
  
      selSet
    };
    TmeFile("web/seed/seed.htm", CtrFil)
  });

  Card(cicCat)
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Build the category pages for CatPag 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) // Only C y D
  {
    Set  SelPdb = SetSubCicle(CtrCmn, pstNum, CtrPxA);
    Set  pstFst = CtrCmn[pstNum]; // The very first
    Text CtrPag = pstFst->pstTit;
    Text CtrDif = PhtSpanishDate(pstFst);
    Text CtrFil = "web/"+pstFst->pstFil; // Output
    Text WriteLn(CtrDif+"|"+CtrFil+"\n"+Repeat(" ",10)+"|"+CtrPag);
    TmeFile("web/seed/seed.htm", CtrFil)
  });

  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 inxHtm = ReadFile("web/quiosco/noticia.html");

  // Texto Lopd que se inserta en la pagina newsletter de envio por email
  Text lpdHtm = ReadFile("web/seed/lopd.htm");

  Text cssSrc = ReadFile("web/css/common.css");
  Text cssOld = 
    "<link href='../css/common.css' rel='stylesheet' type='text/css' />";
  Text cmmNew =
    "<style type='text/css'>\n"    +
    Replace(cssSrc, " url('../", " url('http://www.con-q.tv/") +
    "</style>";

  Text absSav = ReplaceTable(inxHtm, // Save external references
  [[
     [[ " src=\"http:",    " src=\"Http:"]], // H grande evita cambios
     [[" href=\"http:",   " href=\"Http:"]]  // H grande evita cambios
  ]],1);

  Text absUrl = "\"http://www.con-q.tv/";
  Text absRep = ReplaceTable(absSav,
  [[
     [[ " src=\"../",    " src="+absUrl]],
     [[" href=\"../",   " href="+absUrl]],
     [["<!--LPD-->", lpdHtm]],
     [[      cssOld, cmmNew]]
  ]],1);
  Text absErr = Replace(absRep, "<h1>", "<h1 class='Red'>");

  Real FilWriteIfDiff("web/index.html",         absRep);
  Real FilWriteIfDiff("web/css/index.html",     absRep);
  Real FilWriteIfDiff("web/foto/index.html",    absRep);
  Real FilWriteIfDiff("web/noticia/index.html", absRep);
  Real FilWriteIfDiff("web/quiosco/index.html", absRep);
  Real FilWriteIfDiff("web/seed/index.htm",     absRep); // No en sitemap.xml

  Real FilWriteIfDiff("web/error404.html",      absErr);

  Text newCls = PhtCleanHtml(absRep);
  Real FilWriteIfDiff("web/newsletter.html", newCls); // Absolute + cleaned
  Real FilWriteIfDiff("web/newslocal.html",           // Relativa + cleaned
       Replace(PhtCleanHtml(absRep), " src="+absUrl, " src=\""));

  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.con-q.tv/")
});
//////////////////////////////////////////////////////////////////////////////
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.con-q.tv",           // 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
      [["",        "pdf",      "pdf",   TRUE]],   // Documentos Pdf
      [["src",     "js",       "js",    FALSE]],  // Javascript
      [["css",     "css",      "css",   FALSE]],  // Css
      [["css",     "png",      "png",   TRUE]],   // Png solo de css
      [["",        "jpg",      "jpg",   TRUE]]    // Jpeg de css y foto
    ]])
});
//////////////////////////////////////////////////////////////////////////////
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(W("ftp/con-Q.tv.bat"))
});
//////////////////////////////////////////////////////////////////////////////
PutDescription("Send files via ftp.", makSnd);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// TEST
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
Real makTst = If(ctrExe != "tst", FALSE,
{
  Text WriteLn(makSep+"test function SetGetRand()");

  Real numCic = 2000;
  Set  letCic = For(1, numCic, Text(Real pos)
  { SetGetRand([["a","b","c","d"]]) });
  Set letCla = Classify(letCic, Real(Text a, Text b) { Compare(a, b) });
  Set letTst = EvalSet(letCla, Real(Set letSet)
  {
    Text WriteLn(letSet[1]+" "+FormatReal(Card(letSet),"%.0lf")
                          +" "+FormatReal(Card(letSet)/numCic,"%.2lf"));
    Card(letSet)
  });

  TRUE
});
//////////////////////////////////////////////////////////////////////////////
PutDescription(
"Realizar el test de algunas funcionalidades necesarias para el proceso.",
makTst);
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
// END
//////////////////////////////////////////////////////////////////////////////
Text WriteLn("\ncon-Q.tv make: end");

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

Tol