18 de noviembre de 2017

Obtener la ruta (path) en formato largo

En alguna ocasión puede que obtengamos un nombre de archivo en formato corto, por ejemplo "c:\Docum~1\Usuario\Misdoc~1\" y convertirlo a "c:\Documents and Settings\Usuario\Mis documentos\". A continuación una función API para llegar a ello.

DECLARE integer GetLongPathName IN WIN32API ;
 string @ lpszShortPath, string @ lpszLongPath, integer cchBuffer

#define MAXPATH 267
STORE SPACE(MAXPATH) TO lpszLongPath
lcPath = "C:\DOCUME~1\epalma\Misdoc~1\"
lnLen = GetLongPathName(m.lcPath,@lpszLongPath,MAXPATH)
if lnLen > 0
 ? SUBSTR(lpszLongPath,1,lnLen)
else
 ? Ruta Inválida'
endif

Çetin Basöz
MS Foxpro MVP, MCP

12 de noviembre de 2017

Calcular el dígito de verificación para Rapipago y Pagofacil (Argentina)

En Argentina existen al menos dos redes de cobranzas extrabancarias (Rapipago y Pagofacil) que permiten el pago de facturas, servicios, etc. a través de formularios con códigos de barras que se emiten con una estructura particular para cada caso.

En primer lugar, a la cadena a codificar se le deben agregan 1 ó 2 dígitos de verificación al final. El algoritmo (en código VFP) para la generación de estos dígitos es el siguiente:

CLEAR 

lc = "1234567890123456789012345678901234567890"
? "Sin dígito de verificación...: " + lc
? "Con 1 dígito de verificación.: " + GenerarDigitoVerificador(lc, 1)
? "Con 2 dígitos de verificación: " + GenerarDigitoVerificador(lc, 2)

FUNCTION GenerarDigitoVerificador(tcCadena, tn)
  *---
  * Parámetros
  *   tcCadena = Cadena a generar el/los dígito/s de verificación
  *   tn = Cantidad de dígito/s de verificación (1 ó 2)
  * Retorno:
  *   Caracter: La cadena mas el/los dígito/s de verificación
  *---

  IF EMPTY(tn) OR NOT INLIST(tn, 1, 2)
    tn = 1
  ENDIF

  tcCadena = ALLTRIM(tcCadena)

  LOCAL lnLen, lnIni, lnSum, lcSeq, lcRet
  lnLen = LEN(tcCadena)
  lcSeq = "1" + REPLICATE("3579", CEILING(lnLen/4))
  lnSum = 0
  FOR lnIni = 1 TO lnLen
    lnSum = lnSum + VAL(SUBSTR(tcCadena, lnIni, 1)) * VAL(SUBSTR(lcSeq, lnIni, 1))
  ENDFOR
  lcRet = tcCadena + TRANSFORM(MOD(INT(lnSum / 2), 10))
  IF tn = 2
    tcCadena = ALLTRIM(lcRet)
    lnLen = LEN(tcCadena)
    lcSeq = "1" + REPLICATE("3579", CEILING(lnLen/4))
    lnSum = 0
    FOR lnIni = 1 TO lnLen
      lnSum = lnSum + VAL(SUBSTR(tcCadena, lnIni, 1)) * VAL(SUBSTR(lcSeq, lnIni, 1))
    ENDFOR
    lcRet = tcCadena + TRANSFORM(MOD(INT(lnSum / 2), 10))
  ENDIF
  RETURN lcRet
ENDFUNC

Luego de añadir los dígitos de verificación, ya se puede generar el código de barra Interleved 2 of 5 (I2of5) o Código 128 C, que son los que utilizan ambas empresas.

Si desean realizar toda la tarea con Visual FoxPro, pueden utilizar la clase FoxBarcode que soporta ambas simbologías de códigos de barra. Si utilizan el código I2of5 se debe configurar la propiedad lAddCheckDigit que no genere el dígito de control: (lAddCheckDigit = .F.)

Luis María Guayán

7 de noviembre de 2017

Introducción a Cliente-Servidor

Articulo original: Introduction to Client-Server
https://www.tedroche.com/Present/1999/CS.html
Autor: Ted Roche
Traducido por: Esparta Palma

Introducción

La arquitectura Cliente-Servidor parece ser muy simple en los ejemplos: cree una conexión, cree una vista remota hacia los datos, y estará en el negocio, correcto? . En esta sesión, Ted se introducirá en la potencia detrás del GUI, con la revisión de los comandos y funciones necesarias para crear un sistema Cliente-Servidor real. SQL Pass-throuhg, control manual de transacciones, manipulación de propiedades en conexiones, vistas y cursores, procesamiento en lote, precompilación y muchos otros temas que necesitará para la lucha con un sistema real a ser considerado.

Tecnologías Cliente Servidor y Visual FoxPro

Este pequeño documento no pretende ser una referencia completa hacia todo lo relacionado con Cliente-Servidor. En vez de eso, su intención es de servir como una pequeña introducción hacia los conceptos y las técnicas usadas para realizar una aplicación Cliente-Servidor con Visual FoxPro. Los lectores deberán estar familiarizados con Visual FoxPro y con el uso del contenedor de Base de Datos de FoxPro (DBC) y las vistas trabajando con datos locales. Empezaremos con algunas simples definiciones de los términos, revisaremos por qué deberías estar con Cliente-Servidor, y entonces cavaremos en los comandos y funciones para hacerlo posible. Concluiremos con algunas discusiones acerca de técnicas más avanzadas y cómo debería considerar la integración de Cliente-Servidor en su Framework.

¿Qué es Cliente-Servidor?
Hay una gran cantidad de definiciones acerca de qué es exactamente “Cliente-Servidor”, existen mas o menos estudiantiles, mas o menos robustas. Un vendedor hace algunos años diría: ¿“Cliente-Servidor”?, bueno, eso es cualquier cosa que debo vender ahora. Típicamente, para nuestros propósitos, el elemento clave de Cliente-Servidor es que dos procesos separados van a ser ejecutados, uno con Visual FoxPro, y otro que proveerá datos a Visual FoxPro. Estos dos programas pueden ser ejecutados tanto en la misma máquina como en forma separada, esto con algún tipo de conexión entre ellos (red, puerto serial o Internet) para permitir la comunicación.

¿Por qué Cliente-Servidor?
Muchos clientes ven interesante al esquema Cliente-Servidor por razones que están más allá de los méritos técnicos. Esto es ciertamente válido, pero tenga cuidado con las trampas en las que pueda caer si la solución Cliente-Servidor no fue realizada por una razón técnica primaria. Hay tres razones primordiales a considerar en Cliente-Servidor:
  • Tamaño de Datos: Visual FoxPro, al igual que todas las variantes de xBase anteriores a él, tenia la limitación de 2 GB en cualquiera de sus tablas o archivos. Esta limitación tiene que ver con la manera en que los bloqueos son realizados en los registros individuales y, mientras que es ciertamente factible que este límite sea alcanzado, esto es diferente a cómo normalmente lo hace Microsoft. A pesar de que hay muchos workarrounds para estos límites, estos incrementan los retos con Visual FoxPro en cuanto las tablas se agranden – tiempos prolongados para reindexar en caso de corrupción, por ejemplo. En resumen, si el tamaño se vuelve un factor mayor, considere si el uso de Cliente-Servidor es adecuado.
  • Seguridad: Fundamentalmente, todos los accesos a las tablas FoxPro van a través de la red del sistema operativo, así que los usuarios necesitan tener acceso a los directorios conteniendo las tablas VFP. Cualquiera que pueda tener acceso a las tablas puede, eventualmente, imaginarse como leerlos. También es simple usar un driver ODBC y Excel, o si ellos necesitan usar un editor hexadecimal para romper su esquema de encriptación. Muchos sistemas Cliente-Servidor pueden eliminar esta amenaza en conjunto con la restricción de acceso de los clientes a la interface del servidor, y no necesariamente a todos los datos. Si esta tratando con material altamente confidencial, Cliente-Servidor tiene sentido por razones de seguridad.
  • Bajo Ancho de Banda: Visual FoxPro es el producto para manejo bases de datos escritorio y basado en LAN mas rápido y con mejor mejor desempeño disponible en el mercado hoy en día. Pero VFP obtiene su desempeño fenomenal tomando ventaja del ambiente LAN, pre-obteniendo información de columna, haciendo localmente algún tipo de caching de encabezados de tablas y contenidos de índices. Mientras que el proceso de adquirir esta información es casi imperceptible en un ambiente de red, haciendo lenta la apertura inicial de tablas en milisegundos, esto puede ser un retardo substancial si se está en un “cable delgado” (por ejemplo conexiones Dial-Up, WAN o Internet saturado) entre el cliente y los datos. En estas situaciones, poner los datos, la responsabilidad de hacer las consultas y procesamiento de los datos en el servidor minizará los costos de comunicación y mejorará la velocidad.


¿Por qué NO Cliente-Servidor?
Como se mencionó anteriormente, los clientes pueden estar decepcionados si ellos han seleccionado una arquitectura Cliente-Servidor y sólo encuentran que el producto resultante es menos que satisfactorio. Hay muchas razones a considerar para no escoger Cliente-Servidor:
  • Complicaciones de Recursos: Cliente-Servidor es fundamentalmente mas complejo que un single-tier o aplicación monolítica. Nuevas necesidades de aplicación deben ser aprendidas, con esta terminología extranjera, sintaxis y lenguaje. Connectividad, ODBC y temas de red necesitan ser tomadas en cuenta. Nuevas APIs pueden ser necesitadas y dominadas. Anomalías, desdichas y plantear viejos bugs en la interface del vendedor, además de la búsqueda de driver. Si su equipo es maximizado y agendado, no piense que Cliente-Servidor será una “bala de plata”.>
  • Mantenimiento en Curso: Mientras que los vendedores están tratando de hacer sus aplicaciones mas “Instálelo y Olvídelo”, no existen instalaciones “hands-free”. Un administrador de Base de Datos (DBA, Database Administrator) tiene que estar disponible, al menos por periodos, revisar logs, asegurarse que los respaldos estén trabajando, el espacio en disco sea adecuado, etc. En realidad, esto es un requisito para muchas instalaciones de computadoras, pero los server típicamente necesitan un poco de atención adicional. Asegure el factor de costo de un DBA como parte de su vida en Cliente-Servidor.
  • Inestabilidad de Infraestructura: La percepción entre la gerencia superior es que Cliente-Servidor es inherentemente mas robusto, y que una instalación de este tipo es menos propensa a caídas que una instalación FoxPro. De hecho, la estabilidad de la red del sistema operativo y sus servidores no tienen relación con el software ejecutándose en ellos, y una inestabilidad no supone que las caídas y requerimientos de las aplicaciones FoxPro para reindexar todos sus archivos van a requerir un servidor que vaya a través de los procedimientos de recuperación. Un mejor uso del esfuerzo en mucho de estos casos es reparar los servidores con problemas.
  • Rendimiento: Como condición de que el suficiente ancho de banda está disponible, el rendimiento por sí solo nunca es razón para considerar al Cliente-Servidor, a menos de que los clientes requieran que la aplicación funcione más lentamente. En hardware equivalente, Visual FoxPro ejecuta muy decentemente en comparación de un software de servidor de datos


¿Cómo funciona Cliente-Servidor?
La diferencia principal entre trabajar con datos locales (datos VFP nativos) y datos cliente servidor es la necesidad de establecer una conexión con el servidor. Después de que la conexión es establecida, una vista puede ser usada para leer y escribir datos. En adición, la equivalencia de las sentencias SQL nativas de VFP pueden ser usadas para proporcionar un control más directo que el usualmente disponible vía Vista. Finalmente, como casi todo en Visual FoxPro, existe otra capa de fino control disponible a los desarrolladores que lo requieran.

Conexiones

Una conexión usa porciones del Microsoft Open Dabatase Connectivity (ODBC) para establecer una conexión de dos vías de comunicación entre Visual FoxPro y el servidor destino. Cada vendedor tiene su propio mecanismo para proveer, instalar, configurar y soportar esos drivers. Una vez establecida, la conexión de FoxPro puede ser configurada. Hay cierta confusión en la aplicación de la terminología VFP con respecto a conexiones. Cuando usted crea o modifica una conexión usando su sintaxis correspondiente, está modificando la definición de una conexión, y no está afectando una conexión existente. Las conexiones son almacenadas en el DBC y las definiciones son usadas cuando son llamadas. Las conexiones FoxPro pueden ser definidas visualmente con el Database Container (DBC) o directamente desde el Command Window con CREATE CONNECTION. Situación similar sucede con los equivalentes a los comandos DELETE, MODIFY, RENAME y DISPLAY CONNECTION. Las conexiones pueden referirse a un ODBC Data Source Name (DSN), definidas con el Applet “Panel de Control ODBC”, o se pueden especificar directamente los parámetros equivalentes. Por código, la conexión podría lucir como el siguiente:

** La primera conexión depende de un DSN pre-establecido
DEFINE Connection cnTest  
DATASOURCE dsnAccessNWind          
DATABASE C:\Access\nWind.MDB

** La segunda conexión, una conexión sin DSN (DSN-Less)
DEFINE Connection cnVFPFile     
CONNSTRING "DRIVER={Microsoft Visual FoxPro};" + ;     
                        "SOURCETYPE=DBF;" + ;          
                   "SOURCEDB=C:\VS98\VFP98\



Finalmente, las conexiones no necesitan ser mantenidas en un DBC. Si el resto de el sistema está usando SQL Pass Through, las conexiones pueden ser creadas al vuelo, usando las funciones SQLConnect() y SQLStringConnect():
** Abrir una conexión usando un DSN, UserID y PassWord
lnHandle = SQLConnect("mySQLServerDSN","SA","")

** Conectar a una tabla via el Driver ODBC driver sin un DSN:
lnHandle = SQLStringConnect("DRIVER={Microsoft Visual FoxPro};"+;
                            "SOURCETYPE=DBF;"+ ;                                                 
                            "SOURCEDB=C:\VS98\VFP98\")



Vistas
Las Vistas Remotas no son muy diferentes a las vistas locales, pero hay un par de áreas que nos pueden preocupar. La primera preocupación es sobre los tipos de datos almacenados en la base de datos remota pueden no compararse exactamente con los tipos de Visual FoxPro. Por ejemplo, no hay concepto de tipo de datos Lógico o Booleano en el esquema de Oracle. Esto puede ser fácilmente resuelto usando el Diálogo “Propiedades del Campo” y especificar el tipo de datos deseado. Use esta opción para mapear campos DateTime a datos tipo Fecha. Los campos Fecha son poco comunes en backends de base de datos, pero las funciones matemáticas de fechas de VFP están en días y las tipo DateTime en segundos. Tenga cuidado de asegurarse que se usan las unidades de medida correctas. La segunda preocupación es uso apropiado de conexiones. En el diseñador de Vistas, bajo las Opciones Avanzadas -> Menú Opciones, en la sección “Query”, verá un checkbox etiquetado “Compartir Conexión” (“Share Connection” para la versión en inglés). Por el simple hecho de que las vistas utilizan la misma conexión, no significa que cada uno intentará compartir la conexión actual, por el contrario, cada vista creará su propia copia de la conexión definida a menos de que ese checkbox esté marcado. Hay una configuración global equivalente, esta se encuentra en Herramientas/Opciones/Datos Remotos, esto no hacía nada en VFP 3 y 5. Finalmente, en VFP 6, esta ocasionaba que la compartición de conexión fuera seleccionada por default cuando estaba marcada. Vea “Vistas y Conexiones” mas adelante para una discusión sobre los temas envueltos.

Al igual que las conexiones, las Vistas pueden ser definidas y manipuladas programáticamente, al igual que visualmente. Hay algunas ventajas reales al definir las vistas programáticamente. Es fácil para todos el ver la definición de la vista. No necesita meterse en problemas con el Diseñador de Vistas cuando las relaciones complejas no son visualizadas correctamente. Finalmente, puede extender facilemente la naturaleza del meta-data del sistema para generar la Vista al vuelo. Revise el GenDBC (incluido con Visual FoxPro en el directorio (HOME()+”Tools\GENDBC”) para algunas ideas al extraer meta-data desde el DBC o usarlo para generar los comando requeridos para regenerar el DBC.

El comando CREATE VIEW crea una vista remota en el contenedor de base de datos actual. El formato de el comando parece un poco extraño, debido a que el comando SQL SELECT contenido dentro del CREATE VIEW no está delimitado de ningún modo – no se le establece comillas o paréntesis o algo. Este comando SQL SELECT describe como obtener los datos para producir la Vista. Recuerde que Visual FoxPro no está dando los datos – una aplicación servidor lo hace. Así,el SQL usado en el comando CREATE VIEW es el SQL y su extensiones nativas al server, no así a Visual FoxPro. Esto significa que debería evitar “FoxProismos” o funciones integradas de FoxPro (TRIM(), STR(), VAL()), a menos de que sepa que son soportadas por el server. Hay una excepción hablando del lenguaje materno del servidor, y esta situación de pedirle al ODBC que traduzca algunas frase en el proceso. Recuerde que se está usando ODBC para conectar Visual FoxPro al driver de base de datos correcto. ODBC también provee una API e incluye la habilidad para traducir la requisición desde un SQL más genérico hacia uno entendible por el backend. Las funciones pedidas al ODBC se desactivan del código SQL al poner llaves (símbolos { } ). Estos códigos pueden incluir peticiones para funciones internas del ODBC, traducciones de ciertos datos en formatos fecha y tiempo, y hasta extensiones específicas soportadas por algunos drivers. Revise la documentación de su driver ODBC llamando el Applet ODBC y selecionando ayuda.
* Ejemplo de una vista definida por código:

CREATE VIEW l_Customers_State ;
   REMOTE CONNECTION cnOracle SHARED AS ;
   SELECT * ;
     FROM Customer ;
    WHERE Customer.State = &pcState ;
    ORDER BY Customer.Name
Vistas y Conexiones
La razón por la cual usted necesita entender cuantas conexiones establecer con el servidor es por que cada conexión consume recursos, recursos que tienden a ser preciosos para el rendimiento del server y tienden a limitar la escalabilidad del sistema entero. También, algunos vendedores tienen licencias de sus servidores por conexión, en vez de usuarios, así que esto podría convertirse en un problema de licencias. Entonces, ¿Por qué no compartir toda la comunicación con el server sólo con una conexión? Bien, hay algunas restricciones que hacen esto mas complicado al usar sólo una conexión. Primero, las conexiones son definidas en el DBC y sólo pueden ser usadas por vistas en el DBC. Si tiene múltiples DBCs en su aplicación (y hay una o muchas buenas razones para no hacer esto), entonces estará manteniendo múltiples conexiones. Segundo, mientras que los comandos SQL Pass Through pueden compartir una conexión con una vista, consultando su conexión y entonces usar el mismo manejador, una vista no compartirá una conexión [Nota del Editor: Esto ha cambiado con la llegada de Visual FoxPro 8, en esta versión si es posible compartir conexiones entre SPT y las Vistas Remotas]. Finalmente, los comandos están diseñados para tomar algún tiempo o que requiera de más de un simple comunicación de “Pedir-Responder” entre el Cliente y el Servidor, serán propensos a “bloquear la línea telefónica” y necesita estar en su propia conexión. Dichos comandos incluyen peticiones progresivas, comandos por lotes, comandos precompilados y muchas otras situaciones. Es estos casos, planee una o mas conexiones para los procesos en lotes, y también planee una conexión compartida, si es posible, una para vistas y otra para sentencias cortas en el lenguaje SQL. SQL Pass-Through (SPT) Como se mencionó en secciones previas, toda la funcionalidad que puede ser obtenida usando el Contenedor de Base de Datos y las herramientas visuales también está disponible programáticamente con el lenguaje. Como siempre, esto es una de los puntos destacados de Visual FoxPro, los cuales están bien implementados aquí:

Función Propósito
SQLTables() Retorna una lista de tablas o vistas para una conexión específica. Útil para utilerías de “caja negra”
SQLColumns() Retorna especificaciones de campos en uno de varios formatos, útil para comparar capacidades de VFP con base de datos externas.
SQLConnect(), SQLStringConnect() Descritos anteriormente, son usados para establecer una conexión con el servidor
SQLExec() Pasa comandos al server vía ODBC, estos serán ejecutados.
SQLCommit(), SQLRollback() Provee la funcionalidad para completar o abortar una transacción. La transacción debe ser empezada en modo manual, utilizando SQLSetProp() descrita más abajo.
SQLSetProp(), SQLGetProp() Lee y establece propiedades de una conexión existente.
DBSetProp(), DBGetProp() Lee y establece propiedades de un Contenedor de Base de Datos con respecto a vistas, conexiones, tablas, etc. Estos son los únicos valores persistentes entre sesiones.
CursorSetProp(), CursorGetProp() Establece o lee propiedades en un cursor abierto, incluyendo el buffering.


Cliente Servidor Avanzado
Puede que los detalles de estos tópicos estén lejos de lo que es apropiado cubrir en una sesión introductoria, exponer estos conceptos puede darle algunas ideas sobre de lo que puede considerar estos productos en aplicaciones más avanzadas:

Batch SQL: Múltiples estatutos SQL pueden ser enviados al servidor, con procesamiento contínuo en el cliente, y ocasionalmente revisar el estatus del procesamiento.
Progressive Fetching: Muy conveniente cuando se descarga un conjunto de datos potencialmente grande, este método retorna el control a FoxPro después de que una cantidad predeterminada de registros han sido devueltos, y automáticamente obtiene registros adicionales en medida de que se vayan necesitando. Un ejemplo excelente sería un Grid para tomar la lista de clientes, donde el operador podría especificar un criterio de búsqueda, y el cliente podría estar listado si está dentro del criterio. El operador podría recorrer la página en la lista, y los registros adicionales podrían ser obtenidos así sean necesitados.
Precompilación: La función SQLPREPARE() permite al servidor recibir una sentencia SQL a ejecutar, y realizar sus funciones sobre ella – revisión, análisis, desarrollo del plan de trabajo, etc. - y entonces ejecutar la operación mucho más rápido que cuando es llamado.
Entodos estos tres casos, estas funciones requerirán una conexión separada, ya que ellas “bloquearán la linea telefónica” como fue mencionado anteriormente en la sección de Vistas y Conexiones. Sin embargo, estas funciones proveen esta necesidad de conexión.

Sugerencias en el aprendizaje de Cliente-Servidor
Las aplicaciones Cliente-Servidor pueden verse como algo muy complicad, pero no son muy difíciles si se aprende una parte a la vez. Recomiendo aprender a usar la funcionalidad básica de ODBC con Visual FoxPro a través de la experimentación directa con otra tabla o base de datos en su máquina, usando el driver ODBC de VFP. Una vez que gana experiencia, intente con conexiones sin DSN (DSN-Less), conexión directas usando SPT, e intenta cancelar y aceptar varios cambios a los datos. Después de que se haya familiarizado con los comandos y funciones básicas con Visual FoxPro, mire en el software del server. Aprenda cómo instalarlo y configurarlo, si es necesario, y aprenda que componentes son requeridos para instalar conectividad con clientes y driver. Muchos productos vienen con una sencilla ventana de comandos o interface interactiva, úsela para verificar que la conectividad está trabajando correctamente. Puede ser bastante frustrante el tomar algo desconocido y buscar por uno mismo que es lo que no funciona en el sistema, más aún si no hay manera de saber que sucede debido a la mala especificación de protocolo de red, direcciones o puertos incorrectos, o si falta algo por configurar.

Soporte del Framework
Todos los desarrolladores deberían estar usando un framework consistente para desarrollar sus aplicaciones; en vez de empezar de la nada y reinventar la rueda, un framework puede proveer un buen punto de inicio para desarrollo, y un siempre creciente nivel de sofisticación en el servicio proveido. Una de las características clave que debería proveer un framework debería ser las rutinas de servicio para obtener y guardar datos. Visual FoxPro es ideal proveyendo soporte para frameworks de servicios de datos debido a esto hay mucha consistencia y ricos modelos para trabajar con datos. Seleccionando uno de estos modelos y usándolos consistentemente con su framework proveerá un robusto mecanismo de datos.

Conclusión Visual FoxPro provee excelentes herramientas para obtener un control completo de Cliente-Servidor, tanto en variedad gráfica, como a través de la línea de comando. La tecnología Cliente-Servidor es apropiada para tamaños de datos extremadamente grandes, para situaciones de seguridad de alto riesgo, y para ambientes con comunicaciones con bajo ancho de banda desde el cliente al servidor. Además de que el Diseñador de Vistas y el Diseñador de Conexiones pueden permitir un completo diseñado gráficamente, Visual FoxPro también provee las herramientas y funciones para mezclar diseños programáticos y gráficos(o hasta basado en metatablas). Esta combinación hace fácil de aprender combinando el poder en la implementación.

Acerca del Autor. Ted Roche es un Desarrollador Certificado por Microsoft y es el director de desarrollo en Blackstone Incorporated, una compañía catalogada como Microsoft Certified Solution Provider en Waltham, Massachussets, USA, donde el desarrolla aplicaciones complejas usando herramientas visuales y “BackOffice” de Microsoft. Él es un contribuidor de seis libros de FoxPro, los últimos esfuerzos de Ted han sido como coautor de “Hacker's Guide to Visual FoxPro 6.0” disponible en Hentzenwerke Publishing, así como también en librerías de prestigio. Ted ha dado mas de una docena de conferencias profesionales en Canada, Europa y USA, ha sido coautor de “Advisor Answers” (Respuestas Advisor), una columna para la revista FoxPro Advisor. Contacte a Ted vía telefónica (781) 663-7400, o vía email en tedroche@compuserve.com

Derechos Reservados © 1999-2003 por Ted Roche bajo licencia Creative Commons Attribution - ShareAlike 1.0 - vea http://creativecommons.org/licenses/by-sa/1.0/ para mas detalles.