Ambiente X-Windows
O ambiente X-Windows é um ambiente gráfico de janelas que tem como ponto forte o facto de
poder ser implementado de uma forma distribuída.
Embora seja completamente independente da plataforma é mais intensamente usado sobre
plataformas Unix.
A implementação de um sistema distribuido tem como principal desafio a necessidade de uma
total transparência para os utilizadores. A transparência em sistemas distribuídos implica
algumas ideias base:
- Os utilizadores só se autenticam uma vez perante o conjunto de máquinas.
- O utilizador não necessita de saber nada sobre as máquinas e serviços que compõem o
sistema distribuído.
Em plataformas Unix a implementação de um ambiente distribuido X-Windows utiliza um
conjunto de serviços baseados no conceito de máquina segura.
Neste documento pretende-se abordar não só o ambiente X-Windows, mas também esses serviços base,
tais como:
- NFS - "Network File System"
Trata-se de um serviço de ficheiros ("File Server"), com a particularidade
de não implementar autenticação de utilizadores.
- NIS ou "Yellow-Pages"
Serviço de directoria, tipicamente usado para centralizar as contas de
utilizador, graças a ele os utilizadores tem o mesmo UID em todas as
máquinas.
- RSH - "Remote Shell"
Permite a execução de comandos em sistemas remotos sem
a necessidade de autenticação.
Máquinas seguras
Os serviços mais tipicos de um ambiente LAN Unix baseiam-se no conceito de máquina segura.
Uma máquina é considerada segura se:
- O administrador (root) é de confiança, geralmente neste tipo de ambiente o administrador
é o mesmo em todas as máquinas.
- A máquina usa um sistema operativo seguro (Ex.: Unix), com controlo sobre as portas de
rede. Em Unix apenas a "root" pode usar as portas inferiores à 1024.
Nestas condições, quando um sistema servidor recebe um pedido de uma máquina
segura, proveniente de uma porta inferior a 1024, aceita o pedido sem necessidade de
qualquer verificação adicional.
Executáveis "setuid"
Tal como acontece em quase todos os sistemas operativos, em Unix
cada ficheiro tem um proprietário. Normalmente um ficheiro
executável quando invocado "corre" com a identificação
de utilizador (UID) correspondente a quem o invoca.
O Unix permite a definição da "flag" "s" ("setUID"), se um ficheiro executável possui
esta "flag", então quando invocado "corre" com a identificação de utilizador (UID)
correspondente ao proprietário.
Este mecanismo permite ao administrador ("root") disponibilizar
aos utilizadores correntes executáveis capazes de abrir portas abaixo de 1024.
Os executáveis "setUID" devem ser disponibizados com
extrema precaução. Esta técnica apenas pode ser aplicada com executáveis de comprovada
qualidade e idoneadade.
NFS ("Network File System")
Trata-se de um sistema servidor de ficheiros que usa o conceito
de "máquina segura". O servidor não exige qualquer tipo de "password", exige que a
máquina cliente seja considerada segura e que o pedido tenha como origem uma porta
inferior a 1024. O servidor NFS (nfsd e mountd) consulta o ficheiro
/etc/exports onde estão referenciados os directórios que deverão ser exportados,
para quais máquinas e em que modo "read-write" ou "read-only". É atraves deste ficheiro que
são definidas as "máquinas seguras".
Apenas o administrador pode "montar" sistemas de ficheiros remotos.
A operação "montar" ("mount") consiste na associação de um directório remoto exportado pelo
servidor NFS a um directório local. Depois de realizada os ficheiro remotos aparentam ser
locais para todos os utilizadores.
Tipicamente estas operações são realizadas durante o arranque das máquinas.
Como o NFS exporta as permissões associadas aos ficheiros, se os utilizadores possuem
os mesmos UIDs em todas as máquinas, então ficam com os mesmos direitos sobre o sistema
de ficheiros remoto em todas as máquinas.
Dadas as suas caracteristicas em NFS não existe o conceito de sessão. Quando um cliente
"monta" um directório remoto o "mountd" regista esse facto no ficheiro /etc/rmtab.
O servidor de ficheiros propriamente dito (nfsd) consulta esse ficheiro para saber se deve
atender os pedidos que lhe chegam. Um servidor NFS não tem estado porque não existem
sessões de utilizador.
Se a máquina onde se encontra o servidor NFS é reinicializada
depois de uma breve indisponibilidade o serviço NFS continua a funcionar nos clientes.
NIS ("Network Information Service")
Qualquer máquina mantém varias bases de dados internas de que necessita para o seu
funcionamento normal, num sistema Unix estes dados são guardados sob a forma de ficheiros
de texto, geralmente no directório /etc, alguns exemplos são /etc/passwd e /etc/group para
os utilizadores e grupos e /etc/hosts para os nomes de máquinas/endereços.
O NIS, também conhecido por "Yellow Pages" permite ter essa
informação centralizada numa única máquina.
Em Unix as preocupações de segurança com o NIS não são muito grandes porque a informação
manipulada é normalmente acessivel aos utilizadores dos sistemas.
O servidor NIS (ypserv) normalmente aceita pedidos de qualquer proveniencia, contudo é possivel
restringir usando o ficheiro /var/yp/securenets. Igualmente não são geralmente impostas restrições quanto
à porta de proveniencia, tal surge como uma opção.
Para efeitos de validação de um utilizador o cliente NIS (ypbind) contacta o servidor NIS, obtém
a respectiva entrada do ficheiro "passwd" e valida localmente. Sob o ponto de vista do servidor não
há necessidade de qualquer autenticação porque a informação fornecida é pública.
O ponto critico da gestão de utilizadores por NIS é a definição de "passwords", para o efeito
existe um servidor separado (yppasswdd). O "yppasswdd" é contactado pelo cliente (yppasswd) que lhe
fornece a identificação do utilizador (UID), a "password" antiga e a nova "password".
Sendo uma técnica válida está sujeita a falhas de confidencialidade na transmissão.
RSH - "Remote Shell"
O comando rsh está disponível na maioria dos sistemas Unix, permite a execução de outros comandos
em máquinas remotas. O grande interesse do rsh está no facto de mediante certas condições dispensar
a autenticação do utilizador.
O "rsh" é um programa "setuid root", isto permite-lhe abrir uma porta reservada (abaixo de 1024),
nestas condições o servidor (rshd) aceita o pedido sem autenticação desde que tenha origem numa máquina
segura (no caso do rshd, são consideradas seguras as máquinas registadas no ficheiro "/etc/hosts.equiv").
Quando uma aplicação é executada remotamente usando "rsh" o "stdin" da "shell" local é copiado para
a aplicação remota e os "stdout" e "stderr" remotos são copiados para a "shell" local. Na pratica não
existe qualquer diferença entre a execução local ou remota.
Ambiente distribuído baseado em NFS + NIS + RSH
Numa definição paradigmatica de distribuição de processamento cada aplicação é executada de modo
distribuído, isto é a aplicação está dividida em várias partes, sendo cada uma das quais executada em
máquinas distintas. Este tipo de abordagem exige quase sempre uma concepção apropriada das aplicações.
Numa outra abordagem mais ligeira pretende-se que as aplicações embora não sendo individualmente executadas
de forma distribuída, sejam no seu conjunto distribuídas, isto é quando um utilizador entra no sistema e arranca
aplicações, elas não vão ser todas executadas na mesma máquina.
Usados em conjunto o NFS e o NIS permitem que um conjunto de máquinas seguras se torne equivalente
entre sí. Sob o ponto de vista do utilizador tudo funcionará como se ele possuisse uma "conta" em todas as máquinas:
- O NIS permite que o "login name", "password", UID/GID sejam iguais em todas as máquinas.
- O NFS permite que a sua "HOME" esteja disponível em qualquer das máquinas.
Como estamos a falar de um conjunto de máquinas seguras a utilização do "rsh" entre elas é directa.
Nestas condições o administrador pode facilmente substituir ficheiros executáveis por "scripts" que usam
RSH para executar as aplicações em outras máquinas.
Este tipo de configuração tem duas utilidades:
- Distribuição de carga - o administrador pode facilmente definir um mecanismo que lhe permita
determinar qual é a máquina que em determinado instante se encontra com menor carga de processamento.
Usando este mecanismo pode levar os "scripts" a arrancarem a aplicação nessa máquina. Esta técnica obriga
a que as aplicações em causa estejam disponíveis (instaladas) em varias maquinas.
- Especialização de máquinas - de certo modo trata-se de uma abordagem contrária à
anterior, não são contudo incompativeis.
Neste tipo de configuração, uma determinada aplicação apenas está disponível (instalada) em uma ou algumas das máquinas,
o "script" de arranque usa "rsh" para fazer aplicação arrancar na máquina correcta.
X-Windows
O X-Windows é um ambiente de janelas constituido por dois componentes base:
- O servidor X - é uma aplicação passiva que recebe "ordens" de desenho da aplicação, por outro
lado envia à aplicação eventos relacionados com o rato, teclado e outras aplicações. A informação trocada
entre servidor X e aplicações usa um formato designado por protocolo X11. O servidor X é portanto
o componente que se encontra directamente ligado ao "hardware" de interface com o utilizador.
- Aplicações X - as aplicações X são desenvolvidas usando a biblioteca Xlib que funciona como interface
para com o protocolo X11. Na prática geralmente são usadas bibliotecas de nível superior já que a programação
directa sobre a Xlib é um pouco pesada.
Quando uma aplicação X arranca começa por invocar a função
"XOpenDisplay()", tal traduz-se pelo estabelecimento de uma conexão com o X-Server, esta conexão vai mais tarde
materializar-se no "ecran" do X-Server pelo surgimento de uma ou várias janelas.
Os dois componentes do sistema X-Windows podem ou não residir na mesma máquina, seja como for uma aplicação
X quando arranca necessita de conhecer o endereço do servidor X (esta é uma das caracteristicas básicas da
arquitectura cliente/servidor). Neste ambiente o endereço do servidor X é normalmente conhecido por "display name", ou
simplesmente "display". O "display name" é constituido do seguinte modo:
[HostName]:DisplayNumber[.ScreenNumber]
- "HostName" representa o nome da máquina onde se encontra o X-Server, pode também ser usado directamente o endereço IP. Se "Hostname" é omitido,
significa que o X-Server se encontra na mesma máquina onde se encontra a aplicação, nesta situação a comunicação em lugar de usar o protocolo TCP poderá usar
mecanismos de IPC, como por exemplo memória partilhada.
- "DisplayNumber" este número permite ter vários X-Servers numa mesma máquina, não é uma
situação muito vulgar, tipicamente existe apenas um X-Server logo o "DisplayNumber" usado é geralmente zero.
- "ScreenNumber" este número permite a um único X-Server controlar vários conjuntos teclado/rato/monitor, igualmente não é
uma situação vulgar e tipicamente o "ScreenNumber" é omitido o que corresponde ao valor zero.
O ambiente X-Windows dispõe de algumas vantagens importantes, uma delas é a universalidade, dado
que assenta sobre um protocolo bem definido, o X11, qualquer aplicação X, correndo em qualquer plataforma, pode usar
um servidor X, independentemente da plataforma em que este se encontra.
O sistema X-Windows é por definição distribuído, os dois componentes (Servidor X e Aplicação X) residem habitualmente em
máquinas distintas e dividem entre si um conjunto de tarefas noutros sistemas residem na mesma máquina.
Uma máquina que executa aplicações X está liberta de tarefas gráficas de baixo nível, estas são executadas
pelo servidor X.
Além de as aplicações serem executadas de forma distribuída é facil configurar o sistema de forma a que as aplicações sejam distribuídas
por várias máquinas. Poderemos estender os conceitos usados na combinação NIS + NFS + RSH às aplicações X-Windows, existem contudo
alguns detalhes a abordar.
Arranque do ambiente X, protocolo XDMCP
Quando um servidor X arranca surge o caracteristico fundo cinzento e nada mais, o servidor cumpre
a sua missão passiva de esperar o contacto de um cliente (aplicação X). Para fazer arrancar as aplicações
o utilizador tem de lançar mão de algum mecanismo paralelo, por exemplo uma sessão "telnet".
Seria muito mais cómodo se o próprio servidor X tomasse a iniciativa de utilizar um mecanismo paralelo
para autenticar o utilizador e lançar automaticamente um conjunto de aplicações X.
Para este efeito a maioria dos servidores X suporta o protocolo XDMCP ("X Display Manager Control Protocol").
O XDM funciona em sentido inverso do X-Windows, o servidor X é o cliente XDM e a máquina onde habitualmente
são executadas as aplicações X é o servidor XDM.
O cliente XDM (Servidor X) envia um "datagrama" UDP para a porta 177, contendo o "display name" do X Server.
O servidor XDM escuta "datagramas" UDP na porta 177, quando recebe um pedido abre uma conexão com o X-Server
(de acordo com o "display name" recebido) e apresenta uma janela de autenticação ("xlogin").
O servidor XDM é altamente configurável, inicialmente o "xlogin" é executado como "root", depois
da autenticação do utilizador assume o UID do mesmo e lança as aplicações X, nomeadamente um gestor
de janelas e sessão.
Uma vez que a emissão do pedido inicial do XDMCP usa como transporte um protocolo de "datagramas",
torna-se possível enviar o pedido em "broadcast", isto tem a vantagem de gerar uma corrida entre os vários
servidores XDM existentes na rede, que será ganha pela máquina mais rápida ou com menos carga. Constitui-se
assim num mecanismo de distribuição de carga.
Segurança de acesso X-Windows
Um problema significativo que a maioria dos sistemas distribuídos tem de resolver é a segurança de
acesso.
Quando um utilizador arranca uma aplicação X numa dada máquina, esta vai estabelecer uma conexão
TCP com o servidor X, supõe-se que a aplicação pertence ao utilizador que se encontra no servidor X em
questão, mas é necessário que o servidor X possa de algum modo validar esta suposição.
Sem segurança de acesso qualquer um poderia lançar aplicações X direccionadas para
qualquer servidor X e deste modo importunar o respectivo utilizador.
Os servidores X suportam vários tipos de controlo de acesso:
- "HOST ACCESS" - Trata-se de controlar os endereços de proveniência das conexões, determinadas máquinas
são assim autorizadas a estabelecer conexões com o servidor X. Em Unix utiliza-se o comando "xhost" para gerir a lista
de máquinas cliente autorizadas.
Este mecanismo é muito limitado, especialmente
se atendermos à possibilidade de numa mesma máquina serem executadas aplicações X de vários utilizadores.
- "MIT-MAGIC-COOKIE-1" - Este é um dos mecanismos de validação mais usados, é gerado um número aleatório
de 128 bits conhecido por "cookie", o "cookie" é fornecido ao servidor X. Cada aplicação
X que deseja utilizar o servidor X tem de enviar-lhe este "cookie" na altura em que abre o "display".
Quando se utiliza XDM todo este processo é automatizado: o XDM gera o "cookie", fornece-o ao
servidor X e depois da autenticação do utilizador guarda-o no ficheiro ".Xauthority" da respectiva "home"
(em Unix utiliza-se o comando "xauth" para gerir este ficheiro). As aplicações
X lançadas pelo utilizador obtêm o "cookie" deste ficheiro e assim serão autorizadas.
- "XDM-AUTHORIZATION-1" - O problema do "MIT-MAGIC-COOKIE-1" é que o "cookie" é enviado
pela rede sem cifrar, apesar do facto de cada "cookie" ter um tempo de vida igual ao da sessão X,
em certas situações tal não é admissivel. O "XDM-AUTHORIZATION-1" é algo semelhante ao anterior: é
gerado uma chave DES (56 bits) e um IDENTIFICADOR com 64 bits, ambos são fornecidos ao servidor X e
colocados no ficheiro ".Xauthority" para serem usados pelas aplicações X.
As aplicações X obtêm do ficheiro a chave e o identificador, geram um bloco com a data corrente
(em segundos) seguida do identificador, aplicam a cifragem com a chave DES e usam o bloco obtido
para validação durante a abertura do "display".
- Baseados em sistemas distribuídos de autenticação - Quando existem sistemas distribuídos de
autenticação instalados, este podem ser usados. É o caso do "MIT-KERBEROS-5" que utiliza a versão 5 do
"Kerberos", e do "SUN-DES-1" que utiliza o "secure RPC" da Sun. Neste tipo de situação as autorizações de
acesso são definidas na forma "user@host", em Unix utiliza-se novamente o comando "xhost".
Excluindo o "HOST ACCESS", todas estas técnicas são válidas para a implementação de aplicações
X distribuídas. Para as implementações baseadas no ficheiro ".Xauthority", a utilização de NFS+NIS
resolve o problema.
Ambiente X-Windows distribuído, baseado em NFS + NIS + RSH
Torna-se agora possível definir uma configuração em que as aplicações X que um dado utilizador usa
durante uma sessão não são executadas todas na mesma máquina.
A configuração poderá ser baseada no seguinte:
- Os utilizadores possuem o mesmo perfil em todas as máquinas (NIS).
- Os utilizadores possuem os mesmos ficheiro em todas as máquinas (NFS).
- As máquinas são consideradas seguras entre sí sob o ponto de vista do "rsh".
- Os servidores X são configurados para usarem o XDMCP em "broadcast". Podem existir várias
máquinas a correr o servidor XDM e como já foi referido a corrida entre elas vai constituir um
mecanismo de distribuição de carga.
- O controlo de acesso pode ser do tipo "MIT-MAGIC-COOKIE-1". O XDM gera um "cookie" e passa-o
ao servidor X, depois da autenticação o XDM guarda o "cookie" no ficheiro ".Xauthority" do utilizador.
Como as áreas de utilizador são iguais em todas as máquinas o "cookie" vai ficar disponível em todas
as máquinas.
Com estas caracteristicas, torna-se possível ao administrador definir onde arrancam as aplicações X invocadas
pelo utilizador. A melhor solução é definir um conjunto de "scripts" que serão distribuídos por NFS a todas
as máquinas. Cada "script" corresponde a uma aplicação X, ficando ao critério do administrador o tipo de
estratégias a usar, nomedamente "distribuíção de carga" e "especialização de máquinas".
Basicamente estes "scripts" de arranque de aplicações X executam "rsh" para lançar a aplicação X na máquina pretendida,
é necessário não esquecer de indicar às aplicações o endereço do servidor X, encontra-se disponível na variável de ambiente
"DISPLAY", mas apenas na "shell" lançada pelo XDM para inicio de sessão.
Depois da autenticação do utilizador, o XDM guarda o "cookie" no ficheiro do utilizador, define a variável "DISPLAY" com
a localização do servidor X e executa um "script" de arranque se sessão, basicamente trata-se
de arrancar a aplicação X gestora de janelas, tipicamente esta aplicação vai ser executada na mesma máquina onde
correu o XDM, mas tal não é obrigatório.
Protocolos de acesso gráfico em rede - "Thin-clients"
Existem vários protocolos que permitem o acesso a um ambiente gráfico remoto. Trata-se de implementações
independentes das aplicações que transmitem imagens de um "desktop" virtual ou não.
Estes sistemas possuem dois componentes base:
- Servidor - O servidor cria um "desktop" no qual as aplicações desenham a sua interface segundo
uma qualquer API (Ex: Win32). Esse "desktop" pode ou não ser virtual. Se o servidor se limita a ler imagens da
placa gráfica, trata-se de um "desktop" real.
O servidor detecta as alterações que as aplicações realizam
sobre o "desktop" e envia-as ao cliente. Por outro lado o servidor recebe do cliente os codigos das teclas
digitadas e as movimentações do rato.
- Cliente - O cliente é uma aplicação gráfica muito simples (o que origina a designação "Thin-client"") que reproduz o "desktop" residente no servidor
e lhe envia os códigos das teclas e movimentações do rato sobre a sua janela.
Embora se trate de principios de funcionamento totalmente diferentes, é interessante estabelecer uma
comparação destes protocolos com o X11 do ambiente X-Windows:
X-Windows (X11 e equivalentes) | Protocolos de acesso gráfico baseados em transmissão de imagens |
As aplicações só podem ser desenvolvidas usando a Xlib ou superiores (aplicações X). |
Podem ser usadas todas as aplicações que correm no "desktop" do servidor que pode ser de diversos tipos. |
O posto de trabalho deve ter alguma capacidade já que nele reside o servidor X. Por outro lado exige alguma configuração prévia. |
O posto de trabalho pode ser muito ligeiro já que o cliente realiza pouco processamento. Normalmente a configuração é muito ligeira. |
A actividade de processamento é distribuída entre as aplicações e o servidor X. |
A actividade de processamento fica totalmente a cargo do servidor. |
As aplicações podem ser distribuídas por diversas máquinas. |
As aplicações são todas executadas na máquina onde se encontra o servidor. |
A lactência é baixa e a capacidade de rede requerida não é muito elevada. Com o protocolo X11 as transferências de imagens são pontuais,
as fontes de caracteres são locais e existem inumeras funções para desenho. |
Devido à transmissão de imagens exige-se uma maior capacidade da rede, mesmo assim quando
existe um grande número de clientes a lactência torna-se elevada. |
Embora dificilmente possam atingir a performance do X11, estes protocolos podem ser mais ou menos elaborados:
- Normalmente os servidores não enviam imagens completas do "desktop", enviam apenas rectangulos ("frames") de actualização
correspondentes a partes que sofreram alteração.
- Existem vários modos de codificar as imagens antes de as enviar ao cliente, os servidores mais sofisticados
escolhem o formato mais adequado ao tipo de imagem.
- Os clientes guardam em memória ("frame-buffer") os últimos "frames" enviados pelo servidor.
- Geralmente existe uma função de cópia de imagens, trata-se talvez da caracteristica mais interessante deste tipo de
sistemas: o servidor em lugar de enviar ao cliente um "frame", envia-lhe uma ordem de cópia. A origem da cópia pode ser um
rectângulo do "ecran" actual ou de algum dos "frames" em memória e o destino pode ser qualquer ponto do "ecran". Este método
aumenta significativamente a eficiência sob o ponto de vista de lactência e tráfego de rede, mas exige muito
processamento do lado do servidor.
Existem inúmeros exemplos deste tipo de protocolos. Por se tratar de uma solução aberta e "freeware", tome-se o exemplo do VNC ("Virtual Network Computer"), inicialmente desenvolvido pela ORL ("Olivetti && Oracle Research Lab") e
actualmente pelos "AT&T Laboratories Cambridge" (http://www.uk.research.att.com/vnc).
A designação do protocolo é RFB ("Remote FrameBuffer"), a especificação da versão 3.3 pode ser consultada aqui (formato pdf).
O protocolo é muito simples:
- A única primitiva de desenho é a colocação de uma imagem no ponto x,y do "ecran".
- O controlo de fluxo é realizado pelo cliente, o servidor não envia "frames"
por iniciativa própria, apenas o faz a pedido do cliente. Este método tem a vantagem de produzir uma adaptação
automática à capacidade do cliente e da rede (o cliente só pede uma actualização depois de processar a anterior).
- As respostas do servidor ("frames") podem usar diversos formatos: "raw"; "RRE"; "coRRE"; "Hextile" e "Copy Rectangle". Na prática os
mais usados são os dois últimos. O "Hextile" permite a melhor compressão para o tipo de imagens mais comuns nos "desktops" e o "Copy Rectangle"
não é usado para enviar uma imagem, mas sim uma ordem de cópia do "framebuffer" do cliente para o seu "ecran".
- Tanto o cliente como o servidor suportam "cut & past".
- Existe um mecanismo de autenticação baseado exclusivamente em "password", esta é de algum modo préviamente fornecida ao
servidor:
- O servidor envia ao cliente um número aleatório de 16 bits.
- O cliente utiliza a password digitada como chave DES para cifrar os 16 bits.
- O cliente envia ao servidor o número cifrado.
- Os clientes podem ligar-se aos servidores em modo partilhado ou em modo exclusivo. O modo partilhado significa que outros
clientes podem ligar-se ao "desktop", em modo "view-only".
É aconselhada a consulta do artigo "Virtual Network Computing" de Tristan Richardson, Quentin Stafford-Fraser, Kenneth R. Wood e Andy Hopper, publicado
na revista IEEE Internet Computing Volume 2, Number 1 - January/February 1998.
Dado o seu carácter aberto tem surgido inúmeras contribuições externas que levam a uma
evolução muito rápida em muitos sentidos, tais como segurança/confidencialidade, compressão, portabilidade, etc.
Actualmente existem servidores VNC oficiais para 3 plataformas: X-Windows (Linux); Win32 e MacOS (Beta). Através de
contribuições externas existem servidores X-Windows para quase todas as plataformas Unix, para MacOS e para OS/2.
O servidor VNC para X-Windows constitui-se num verdadeiro "gateway" vnc/x-windows já que se trata de um servidor X virtual.
Devido a tratar-se de tecnologia proprietária a versão Win32 do servidor VNC limita-se a interceptar pedidos de desenho das
aplicações e por isso não é ainda muito eficiênte.
Em termos de clientes, oficialmente existem para X-Windows, Win32, Java, Macintosh e Windows CE.
[email protected] http://www.dei.isep.ipp.pt/~andre |