Webview 2 + Html + ChatGPT !

User avatar
Antonio Linares
Site Admin
Posts: 42258
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Webview 2 + Html + ChatGPT !

Post by Antonio Linares »

regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 42258
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Webview 2 + Html + ChatGPT !

Post by Antonio Linares »

Comenzando a implementar la carga de apps previamente salvadas a DBF:

buildit.prg

Code: Select all | Expand

#include "FiveWin.ch"

REQUEST DbfCdx
// REQUEST HB_CODEPAGE_ESWIN
// REQUEST HB_LANG_ESWIN

// get your OpenAI key from https://platform.openai.com/api-keys
static cKey := "sk-proj-..."  
static oChatgpt
static oTree
static cCategory := "                              "
static oWebView
static cContext := "                                                                   "
static oExplBar, oExplPanel

//----------------------------------------------------------------------------//

function Main()

   local oWnd, oAppPanel

   oChatgpt = TChatgpt():New( cKey )

   DEFINE WINDOW oWnd TITLE "Build it"

   oExplBar = TExplorerBar():New( 0, 82, 480, 100, oWnd:oLeft, CLR_WHITE, RGB( 31, 31, 31 ) )
   oWnd:oLeft = oExplBar

   oExplPanel = oExplBar:AddPanel( "AI assistant" )
   oExplPanel:AddLink( "what is this app about ?",;
                       { || If( MsgGet( "App category", "Please specify it", @cCategory ), AddOptions( cCategory, oExplBar ),) } )
   oExplPanel:AddLink( "Add options to selected item", { || AddSubOptions() } )
   oExplPanel:AddLink( "Generate HTML for selected item", { || MsgRun( "Building the GUI", "Please wait", { || GenerateHTML() } ) } )
   oExplPanel:AddLink( "Modify HTML for selected item", { || ModifyHTML() } )
   oExplPanel:AddLink( "Overall context", { || Context() } ) 
   oExplPanel:AddLink( "Save App", { || SaveApp() } )
   oExplPanel:AddLink( "Load App", { || LoadApp() } )

   oWnd:oClient = TPanel():New( 0, 0, 100, 100, oWnd )

   oWebView = TWebView2():New( oWnd:oClient )
   oWebView:Navigate( "https://www.google.com" )

   ACTIVATE WINDOW oWnd MAXIMIZED ;
      ON RESIZE ( oWebView:SetSize( nWidth - oExplBar:nWidth, nHeight ), oExplBar:SetSize( 480, nHeight ) )

return nil    

//----------------------------------------------------------------------------//

function AddOptions( cCategory, oExplBar )

   local cOptions, aOptions, cOption, oAppPanel, oItem

   oChatgpt:cPrompt := "genera una lista separada por comas con las opciones de una aplicación de " + ;
                       hb_StrToUtf8( AllTrim( cCategory ) ) + ". No des ninguna explicación"
   MsgRun( "Asking ChatGPT", "Please wait", { || oChatgpt:Send() } ) 

   cOptions = oChatgpt:GetValue( "choices", "message", "content" )
   aOptions = hb_ATokens( cOptions, "," )

   oAppPanel = oExplBar:AddPanel( cCategory,, 700 )
   cCategory = hb_Utf8ToStr( AllTrim( cCategory ) )
   oTree = TTreeView():New( 2.5, 2, oAppPanel,,,,, 423, 675 )
   oTree:bChanged = { || oItem := oTree:GetSelected(), oWebView:SetHtml( If( ! Empty( oItem:Cargo ), oItem:Cargo, "" ) ) }

   for each cOption in aOptions 
      oItem = oTree:Add( cOption )
      oItem:Cargo = HtmlDefault()
   next   
    
return nil    

//----------------------------------------------------------------------------//

function AddSubOptions()

   local oItem 
   local cOption := If( ( oItem := oTree:GetSelected() ) != nil, oItem:cPrompt, "" ) 
   local cOptions, cSubOption, aOptions, oSubItem

   if ! Empty( cOption )
      oChatgpt:cPrompt := "genera una lista separada por comas con las opciones de " + hb_StrToUtf8( cOption ) + ;
                          " para una aplicación de " + hb_StrToUtf8( cCategory ) + ". No des ninguna explicación"
      MsgRun( "Asking ChatGPT", "Please wait", { || oChatgpt:Send() } )

      cOptions = oChatgpt:GetValue( "choices", "message", "content" )
      aOptions = hb_ATokens( cOptions, "," )

      for each cSubOption in aOptions 
         oSubItem = oItem:Add( cSubOption )
         oSubItem:Cargo = HtmlDefault()
      next   

      oItem:Expand()
   endif   

return nil    

//----------------------------------------------------------------------------//

function GenerateHTML()

   local oItem, cHTML 
   local cOption := If( ( oItem := oTree:GetSelected() ) != nil, oItem:cPrompt, "" ) 

   if ! Empty( cOption )
      oChatgpt:cPrompt := "genera el código HTML usando bootstrap para la opción " + hb_StrToUtf8( cOption ) + ;
                          " para una aplicación de " + hb_StrToUtf8( AllTrim( cCategory ) ) + ;
                          ". Que se vea muy profesional y elegante. No des ninguna explicación. " + ;
                          cContext 
      oChatgpt:Send()
      cHTML = oChatgpt:GetValue( "choices", "message", "content" )
      oItem:Cargo = SubStr( cHTML, 8, Len( cHTML ) - 10 )
      oWebView:SetHTML( oItem:Cargo )
   endif   

return nil   

//----------------------------------------------------------------------------//

function ModifyHTML()

   local oItem, cHTML 
   local cOption := If( ( oItem := oTree:GetSelected() ) != nil, oItem:cPrompt, "" ) 
   local cChange := Space( 50 )

   if fw_memoEdit( @cChange, "What do you want to change ?" )
      cChange = AllTrim( cChange )
   endif      

   if ! Empty( cOption )
      oChatgpt:cPrompt := "modifica este código HTML usando bootstrap para la opción " + hb_StrToUtf8( cOption ) + ;
                          " para una aplicación de " + hb_StrToUtf8( AllTrim( cCategory ) ) + ;
                          ". Que se vea muy profesional y elegante. No des ninguna explicación. " + ;
                          cContext + ". Y aplica _ exactamente: " + hb_StrToUtf8( cChange ) + ;
                          oItem:Cargo 
      MsgRun( "Asking ChatGPT", "Please wait", { || oChatgpt:Send() } ) 
      cHTML = oChatgpt:GetValue( "choices", "message", "content" )
      oItem:Cargo = SubStr( cHTML, 8, Len( cHTML ) - 10 )
      oWebView:SetHTML( oItem:Cargo )
   endif   

return nil   

//----------------------------------------------------------------------------//

function Context()

   if fw_memoEdit( @cContext, "Overall context for HTML generation" )
      cContext = AllTrim( cContext )
   endif      

return nil   

//----------------------------------------------------------------------------//

function CreateDBF( cFileName )

   DbCreate( cFileName + ".dbf", { { "prompt", "C", 80, 0 },;
                                   { "level",  "N",  3, 0 },;
                                   { "html",   "M", 10, 0 } }, "DBFCDX" )
   USE ( cFileName )

return nil

//----------------------------------------------------------------------------//

function SaveApp()

   if ! File( cCategory + ".dbf" )
      CreateDBF( StrTran( AllTrim( cCategory ), " ", "_" ) )
   else
      if MsgYesNo ("App already exists", "Do you want to overwrite it?" )
         CreateDBF( StrTran( AllTrim( cCategory ), " ", "_" ) )
      else
         return nil
      endif
   endif

   oTree:Scan( { | oItem, nPos, nLevel | DbAppend(), field->prompt := oItem:cPrompt,;
               field->level := nLevel, field->html := oItem:Cargo, .F. } )
   GO TOP
   XBrowse()
   USE

return nil   

//----------------------------------------------------------------------------//

function LoadApp()

   local cFileName := cGetFile( "DBF file| *.dbf", "Please select a DBF" )
   local oAppPanel, oItem, oLastItem, nLevel := 1, aLevels := {}

   USE ( cFileName )

   oAppPanel = oExplBar:AddPanel( cFileNoExt( cFileName ),, 700 )
   oTree = TTreeView():New( 2.5, 2, oAppPanel,,,,, 423, 675 )

   while ! EoF()
      IF field->level > nLevel
         // Aumenta el nivel, guarda el elemento actual y crea una nueva rama
         AADD(aLevels, oLastItem)
         nLevel++
         oItem := oLastItem:Add(field->prompt)
         oLastItem := oItem
      ELSEIF field->level < nLevel
         // Disminuye el nivel, recupera el elemento del nivel anterior
         WHILE nLevel > field->level .AND. !EMPTY(aLevels)
            nLevel--
            oLastItem := ATAIL(aLevels)
            ADEL(aLevels, LEN(aLevels))
         ENDDO
         if oLastItem != nil
            oItem := oLastItem:Add( field->prompt )
         endif   
      ELSE
         // Mismo nivel, añade un nuevo elemento al nivel actual
         oItem := oTree:Add( field->prompt )
         oLastItem := oItem
      ENDIF
   
      oItem:Cargo := field->html
      SKIP
   end  

   USE

return nil   

//----------------------------------------------------------------------------//

function HtmlDefault()

   local cHtml

   TEXT INTO cHtml
      <!DOCTYPE html>
      <html lang="es">
      <head>
         <style>
            body {
                  background-color: rgb(31, 31, 31);
            }
         </style>
      </head>
      <body>
      </body>
      </html>
   ENDTEXT 

return cHtml

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
cmsoft
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Webview 2 + Html + ChatGPT !

Post by cmsoft »

Antonio:
Donde puedo descargar habour completo
Ya que el path %hdir%\bin\win\bcc\harbour no existe
Enrrique Vertiz
Posts: 549
Joined: Fri Oct 07, 2005 2:17 pm
Location: Lima - Peru
Contact:

Re: Webview 2 + Html + ChatGPT !

Post by Enrrique Vertiz »

Saludos Antonio

Entiendo que al tener cambio FWH, no podemos compilar los ejemplos que aqui estas colocando, pero indicas que pasaras un EXE, me dices x favor de donde descargarlo para empezar a probar y donde coloco mi Key de OpenIA para probarlo
Gracias
Enrrique Vertiz Pitta
Lima-Peru
xHb 1.23.1026X, Fwh 24.09, BCC74, MySQL 8.0.X, SQLLIB 1.9m
User avatar
wilsongamboa
Posts: 600
Joined: Wed Oct 19, 2005 6:41 pm
Location: Quito - Ecuador

Re: Webview 2 + Html + ChatGPT !

Post by wilsongamboa »

buenos dias con todos a mi si me compila pero no puedo probar porque
1.- no se de que se trata ??
2.- no tengo ese chatgpt o esa suscripcion

alguna alma caritativa que pueda explicarnos de que se trata
hacer un programa con webview ?? y chtgpt ?
saludospd: perdon la ignorancia
Wilson 'W' Gamboa A
Wilson.josenet@gmail.com
User avatar
cmsoft
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Webview 2 + Html + ChatGPT !

Post by cmsoft »

Wilson:
La idea es tener integrado OpenIA con Fivewin.
En conjuto con WebView para mostrar el resultado html de lo que se le solicita a la IA para ver como va respondiendo .
Para esto, además del programa que muestra Antonio, hay que registrarse en OpenIA (https://platform.openai.com/) para obtener una Key de la API
Es muy interesante lo que está desarrollando Antonio con todo esto.
User avatar
wilsongamboa
Posts: 600
Joined: Wed Oct 19, 2005 6:41 pm
Location: Quito - Ecuador

Re: Webview 2 + Html + ChatGPT !

Post by wilsongamboa »

Cesar muchas gracias la info ahi me aclara
esa suscripcion es de pago ?
saludos
Wilson 'W' Gamboa A
Wilson.josenet@gmail.com
User avatar
wilsongamboa
Posts: 600
Joined: Wed Oct 19, 2005 6:41 pm
Location: Quito - Ecuador

Re: Webview 2 + Html + ChatGPT !

Post by wilsongamboa »

perdon ya averigue son 20 dolares por mes
saludos
Wilson 'W' Gamboa A
Wilson.josenet@gmail.com
User avatar
wilsongamboa
Posts: 600
Joined: Wed Oct 19, 2005 6:41 pm
Location: Quito - Ecuador

Re: Webview 2 + Html + ChatGPT !

Post by wilsongamboa »

y la gratuita no tiene acceso a la API
Wilson 'W' Gamboa A
Wilson.josenet@gmail.com
User avatar
cmsoft
Posts: 1293
Joined: Wed Nov 16, 2005 9:14 pm
Location: Mercedes - Bs As. Argentina

Re: Webview 2 + Html + ChatGPT !

Post by cmsoft »

Si, es de pago... Lamentablemente.
User avatar
wilsongamboa
Posts: 600
Joined: Wed Oct 19, 2005 6:41 pm
Location: Quito - Ecuador

Re: Webview 2 + Html + ChatGPT !

Post by wilsongamboa »

gracias Cesar veamos hasta donde se llega con esto y evaluamos usarlo tambien
saludos
Wilson 'W' Gamboa A
Wilson.josenet@gmail.com
User avatar
Antonio Linares
Site Admin
Posts: 42258
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Webview 2 + Html + ChatGPT !

Post by Antonio Linares »

wilsongamboa wrote:perdon ya averigue son 20 dolares por mes
saludos
No, ese precio es para la versión plus. El precio es menos de un dolar!

Solo teneis que proporcionar los datos de pago en OpenAI. La version gpt-4o-mini que usamos es muy muy barata.

Daros de alta, realmente merece la pena y los resultados son espectaculares!
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 42258
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Webview 2 + Html + ChatGPT !

Post by Antonio Linares »

cmsoft wrote:Antonio:
Donde puedo descargar habour completo
Ya que el path %hdir%\bin\win\bcc\harbour no existe
https://github.com/FiveTechSoft/harbour ... 240814.zip
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 42258
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Webview 2 + Html + ChatGPT !

Post by Antonio Linares »

Estamos construyendo un generador/prototipador de aplicaciones usando Inteligencia Artificial y Harbour + FWH

Os recomiendo probarlo, es simplemente espectacular! :-)

Y las posibilidades son enormes!
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 42258
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Webview 2 + Html + ChatGPT !

Post by Antonio Linares »

Carga de la aplicación funcionando correctamente:

buildit.prg

Code: Select all | Expand

#include "FiveWin.ch"

REQUEST DbfCdx
// REQUEST HB_CODEPAGE_ESWIN
// REQUEST HB_LANG_ESWIN

// get your OpenAI key from https://platform.openai.com/api-keys
static cKey := "sk-proj-..."  
static oChatgpt
static oTree
static cCategory := "                              "
static oWebView
static cContext := "                                                                   "
static oExplBar, oExplPanel

//----------------------------------------------------------------------------//

function Main()

   local oWnd, oAppPanel

   oChatgpt = TChatgpt():New( cKey )

   DEFINE WINDOW oWnd TITLE "Build it"

   oExplBar = TExplorerBar():New( 0, 82, 480, 100, oWnd:oLeft, CLR_WHITE, RGB( 31, 31, 31 ) )
   oWnd:oLeft = oExplBar

   oExplPanel = oExplBar:AddPanel( "AI assistant" )
   oExplPanel:AddLink( "what is this app about ?",;
                       { || If( MsgGet( "App category", "Please specify it", @cCategory ), AddOptions( cCategory, oExplBar ),) } )
   oExplPanel:AddLink( "Add options to selected item", { || AddSubOptions() } )
   oExplPanel:AddLink( "Generate HTML for selected item", { || MsgRun( "Building the GUI", "Please wait", { || GenerateHTML() } ) } )
   oExplPanel:AddLink( "Modify HTML for selected item", { || ModifyHTML() } )
   oExplPanel:AddLink( "Overall context", { || Context() } )
   oExplPanel:AddLink( "Save App", { || SaveApp() } )
   oExplPanel:AddLink( "Load App", { || LoadApp() } )

   oWnd:oClient = TPanel():New( 0, 0, 100, 100, oWnd )

   oWebView = TWebView2():New( oWnd:oClient )
   oWebView:Navigate( "https://www.google.com" )

   ACTIVATE WINDOW oWnd MAXIMIZED ;
      ON RESIZE ( oWebView:SetSize( nWidth - oExplBar:nWidth, nHeight ), oExplBar:SetSize( 480, nHeight ) )

return nil    

//----------------------------------------------------------------------------//

function AddOptions( cCategory, oExplBar )

   local cOptions, aOptions, cOption, oAppPanel, oItem

   oChatgpt:cPrompt := "genera una lista separada por comas con las opciones de una aplicación de " + ;
                       hb_StrToUtf8( AllTrim( cCategory ) ) + ". No des ninguna explicación"
   MsgRun( "Asking ChatGPT", "Please wait", { || oChatgpt:Send() } )

   cOptions = oChatgpt:GetValue( "choices", "message", "content" )
   aOptions = hb_ATokens( cOptions, "," )

   oAppPanel = oExplBar:AddPanel( cCategory,, 700 )
   cCategory = hb_Utf8ToStr( AllTrim( cCategory ) )
   oTree = TTreeView():New( 2.5, 2, oAppPanel,,,,, 423, 675 )
   oTree:bChanged = { || oItem := oTree:GetSelected(), oWebView:SetHtml( If( ! Empty( oItem:Cargo ), oItem:Cargo, "" ) ) }

   for each cOption in aOptions
      oItem = oTree:Add( cOption )
      oItem:Cargo = HtmlDefault()
   next  
   
return nil    

//----------------------------------------------------------------------------//

function AddSubOptions()

   local oItem
   local cOption := If( ( oItem := oTree:GetSelected() ) != nil, oItem:cPrompt, "" )
   local cOptions, cSubOption, aOptions, oSubItem

   if ! Empty( cOption )
      oChatgpt:cPrompt := "genera una lista separada por comas con las opciones de " + hb_StrToUtf8( cOption ) + ;
                          " para una aplicación de " + hb_StrToUtf8( cCategory ) + ". No des ninguna explicación"
      MsgRun( "Asking ChatGPT", "Please wait", { || oChatgpt:Send() } )

      cOptions = oChatgpt:GetValue( "choices", "message", "content" )
      aOptions = hb_ATokens( cOptions, "," )

      for each cSubOption in aOptions
         oSubItem = oItem:Add( cSubOption )
         oSubItem:Cargo = HtmlDefault()
      next  

      oItem:Expand()
   endif  

return nil    

//----------------------------------------------------------------------------//

function GenerateHTML()

   local oItem, cHTML
   local cOption := If( ( oItem := oTree:GetSelected() ) != nil, oItem:cPrompt, "" )

   if ! Empty( cOption )
      oChatgpt:cPrompt := "genera el código HTML usando bootstrap para la opción " + hb_StrToUtf8( cOption ) + ;
                          " para una aplicación de " + hb_StrToUtf8( AllTrim( cCategory ) ) + ;
                          ". Que se vea muy profesional y elegante. No des ninguna explicación. " + ;
                          cContext
      oChatgpt:Send()
      cHTML = oChatgpt:GetValue( "choices", "message", "content" )
      oItem:Cargo = SubStr( cHTML, 8, Len( cHTML ) - 10 )
      oWebView:SetHTML( oItem:Cargo )
   endif  

return nil  

//----------------------------------------------------------------------------//

function ModifyHTML()

   local oItem, cHTML
   local cOption := If( ( oItem := oTree:GetSelected() ) != nil, oItem:cPrompt, "" )
   local cChange := Space( 50 )

   if fw_memoEdit( @cChange, "What do you want to change ?" )
      cChange = AllTrim( cChange )
   endif      

   if ! Empty( cOption )
      oChatgpt:cPrompt := "modifica este código HTML usando bootstrap para la opción " + hb_StrToUtf8( cOption ) + ;
                          " para una aplicación de " + hb_StrToUtf8( AllTrim( cCategory ) ) + ;
                          ". Que se vea muy profesional y elegante. No des ninguna explicación. " + ;
                          cContext + ". Y aplica _ exactamente: " + hb_StrToUtf8( cChange ) + ;
                          oItem:Cargo
      MsgRun( "Asking ChatGPT", "Please wait", { || oChatgpt:Send() } )
      cHTML = oChatgpt:GetValue( "choices", "message", "content" )
      oItem:Cargo = SubStr( cHTML, 8, Len( cHTML ) - 10 )
      oWebView:SetHTML( oItem:Cargo )
   endif  

return nil  

//----------------------------------------------------------------------------//

function Context()

   if fw_memoEdit( @cContext, "Overall context for HTML generation" )
      cContext = AllTrim( cContext )
   endif      

return nil  

//----------------------------------------------------------------------------//

function CreateDBF( cFileName )

   DbCreate( cFileName + ".dbf", { { "prompt", "C", 80, 0 },;
                                   { "level",  "N",  3, 0 },;
                                   { "html",   "M", 10, 0 } }, "DBFCDX" )
   USE ( cFileName )

return nil

//----------------------------------------------------------------------------//

function SaveApp()

   if ! File( cCategory + ".dbf" )
      CreateDBF( StrTran( AllTrim( cCategory ), " ", "_" ) )
   else
      if MsgYesNo ("App already exists", "Do you want to overwrite it?" )
         CreateDBF( StrTran( AllTrim( cCategory ), " ", "_" ) )
      else
         return nil
      endif
   endif

   oTree:Scan( { | oItem, nPos, nLevel | DbAppend(), field->prompt := oItem:cPrompt,;
               field->level := nLevel, field->html := oItem:Cargo, .F. } )
   GO TOP
   XBrowse()
   USE

return nil  

//----------------------------------------------------------------------------//

function LoadApp()

   local cFileName := cGetFile( "DBF file| *.dbf", "Please select a DBF" )
   local oAppPanel, oItem, oLastItem, nLevel := 1, aLevels := {}

   if Empty( cFileName )
      return nil 
   endif   

   cCategory = cFileNoExt( cFileName )
   USE ( cFileName )

   oAppPanel = oExplBar:AddPanel( cFileNoExt( cFileName ),, 700 )
   oTree = TTreeView():New( 2.5, 2, oAppPanel,,,,, 423, 675 )
   oTree:bChanged = { || oItem := oTree:GetSelected(), oWebView:SetHtml( If( ! Empty( oItem:Cargo ), oItem:Cargo, "" ) ) }

   while ! EoF()
      do case
         case field->level > nLevel
            nLevel = field->level
            oItem = oLastItem:Add( field->prompt )
            oLastItem = oItem
            AAdd( aLevels, oLastItem )

         case field->level < nLevel
            oLastItem = ATail( aLevels )
            aLevels = ASize( aLevels, Len( aLevels ) - 1 )
            nLevel = field->level
            if nLevel == 1
               oItem = oTree:Add( field->prompt )
            else   
               oItem = oLastItem:oParent:Add( field->prompt )
            endif   
            oLastItem = oItem

         case field->level == nLevel  
            if nLevel == 1
               oItem = oTree:Add( field->prompt )
            else 
               oItem = oLastItem:oParent:Add( field->prompt )  
            endif      
            oLastItem = oItem
      endcase
   
      oItem:Cargo = field->html
      SKIP
   end  

   USE

return nil  

//----------------------------------------------------------------------------//

function HtmlDefault()

   local cHtml

   TEXT INTO cHtml
      <!DOCTYPE html>
      <html lang="es">
      <head>
         <style>
            body {
                  background-color: rgb(31, 31, 31);
            }
         </style>
      </head>
      <body>
      </body>
      </html>
   ENDTEXT

return cHtml

//----------------------------------------------------------------------------//
regards, saludos

Antonio Linares
www.fivetechsoft.com
Post Reply