Você está na página 1de 62

Sistemas Distribudos Resolvendo o Problema da Heterogeneidade

Especializao em Redes de Computadores


Prof. Fbio M. Costa Instituto de Informtica - UFG

Viso Geral
Linguagens de Programao Heterogneas
Modelo de objetos comum Linguagem de definio de interfaces comum Mapeamentos para linguagens de programao

Plataformas de Middleware Heterogneas


Interoperabilidade Inter-funcionamento

Representaes de Dados Heterogneas


Representao de dados padro Protocolo de transporte em nvel de aplicao Mquinas virtuais
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Linguagens de Programao Heterogneas

Motivao
Os componentes de sistemas distribudos so escritos em diferentes linguagens de programao Estas linguagens de programao podem ou no impor seus prprios modelos de objetos Modelos de objetos variam bastante Estas diferenas precisam ser contornadas para facilitar a integrao
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Por que usar uma IDL?


PL1 PL2 PL1 PL2

PL6

PL3

PL6

IDL

PL3

PL5

PL4

PL5

PL4

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Mapeamentos para Linguagens de Programao em CORBA


Smalltalk C++
IDL
Common Object Model

Ada-95

C
Cobol
Original: Wolfgang Emmerich, 2000

Java

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Finalidade de um Modelo de Objetos Comum


Meta-modelo para o sistema de tipos da plataforma de middleware Define o significado de:
Tipos de objetos Operaes Atributos Requisies Excees Sub-tipagem

Definido de maneira genrica o suficiente para permitir mapeamentos para a maioria das linguagens de programao
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Linguagem de Definio de Interfaces


Uma linguagem para se expressar todos os conceitos do modelo de objetos da plataforma de middleware Independente de linguagem de programao Mapeamentos para diferentes linguagens de programao so necessrios Exemplo: OMG/IDL
Permite expressar os conceitos do modelo de objetos de CORBA
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

example.idl
// example.idl typedef string<80> NameStr; interface Player { readonly attribute NameStr name; };

interface PlayerFactory { Player createPlayer(in NameStr name); };

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

example.idl (cont.)
interface Team { readonly attribute NameStr name; exception InvalidNumber{}; exception NumberOccupied{}; exception NoPlayerAtNumber{}; void add(in Player aPlayer, in short number) raises (InvalidNumber,NumberOccupied); void remove(in short number) raises (InvalidNumber,NoPlayerAtNumber); string print(); }; interface TeamFactory { Team createTeam(in NameStr teamname); }; Original: Wolfgang Emmerich, 2000 Prof. Fbio M. Costa - Instituto de Informtica / UFG

10

Arquivos Envolvidos, em C++


gerados
escritos example.hh

includo em ligado com


Player Team Server.hh Server.hh

Client.cc exampleC.cc exampleS.cc

Player Team Server.cc Server.cc

Client

Person Server

Team Server
11

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Diagrama de Interaes
main Team (Client Stub) ORB TeamDispatch (Server Skeleton) Team Server

print

request reply

request reply

print

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

12

example.idl: Implementao da Interface Player


// example.idl typedef string<80> NameStr; interface Player { readonly attribute NameStr name; };

interface PlayerFactory { Player createPlayer(in NameStr name); };

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

13

PlayerServer.hh
#include "example.hh" class PlayerServer:public virtual PlayerBOAImpl{ private: char * the_player_name; public: PlayerServer(); virtual NameStr name(); virtual void set_name(char *); }; class PlayerFactoryServer : public virtual PlayerFactoryBOAImpl { virtual Player * createPlayer(NameStr); };
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

14

PlayerServer.cc
#include "PlayerServer.hh" NameStr PlayerServer::name(){ char * ret; ret = new char[strlen(the_player_name)+1]; strcpy(ret,the_player_name); return(ret); }; Player * PlayerFactoryServer::createPlayer( NameStr name) { PlayerServer * aPlayer = new PlayerServer; aPlayer->set_name(name); aPlayer->_duplicate(); return aPlayer; }; Original: Wolfgang Emmerich, 2000 Prof. Fbio M. Costa - Instituto de Informtica / UFG

15

PlayerServer.cc (cont.)
int main(int argc, char* argv[]) { PlayerFactoryServer myplayergenerator; try { CORBA::BOA.impl_is_ready("PlayerFactory"); } catch (const Exception &excpt) { // an error occured calling impl_is_ready() cerr << excpt; } }

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

16

example.idl: Implementao da Interface Team


interface Team { readonly attribute NameStr name; exception InvalidNumber{}; exception NumberOccupied{}; exception NoPlayerAtNumber{}; void add(in Player aPlayer, in short number) raises (InvalidNumber,NumberOccupied); void remove(in short number) raises (InvalidNumber,NoPlayerAtNumber); string print(); }; interface TeamFactory { Team createTeam(in NameStr teamname); }; Original: Wolfgang Emmerich, 2000 Prof. Fbio M. Costa - Instituto de Informtica / UFG

17

TeamServer.hh
#include "example.hh" class TeamServer : public virtual TeamBOAImpl { private: Player * the_team[MAXPLAYERS+1]; char * the_team_name; public: virtual void set_name(char *); virtual NameStr name(); virtual void add(Player *, short); virtual void remove(short); virtual char * print(); }; class TeamFactoryServer : public virtual TeamFactoryBOAImpl { virtual Team * createTeam(NameStr); }; Original: Wolfgang Emmerich, 2000
Prof. Fbio M. Costa - Instituto de Informtica / UFG

18

TeamServer.cc
#include "TeamServer.hh" void TeamServer::add(Player *aPlayer,short num){ if (num<1 || num > MAXPLAYERS) { throw(InvalidNumber); } else if ((the_team[num]!=NULL)) { throw(NumberOccupied); } else { aPlayer->_duplicate(); the_team[num]=aPlayer; } Demais mtodos: remove, print };
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

19

TeamServer.cc (cont.)
Team* TeamFactoryServer::createTeam( NameStr name) { TeamServer * aTeam = new TeamServer; aTeam->set_name(name); aTeam->_duplicate(); return(aTeam); }; int main(int argc, char* argv[]) { TeamFactoryServer myteamgenerator; try { CORBA::BOA.impl_is_ready("TeamFactory"); } catch (const Exception &excpt) { cerr << excpt; } Original: Wolfgang Emmerich, 2000 Prof. Fbio M. Costa - Instituto de Informtica / UFG }

20

Client.cc
#include "example.hh" int main(int argc, char* argv[]) { PlayerFactory * pf; TeamFactory * tf; Team * t; Player *goalkeeper, *forward; char * output; //obtain references for player and team factory ...

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

21

Client.cc (cont.)
try { t=tf->createTeam("Germany"); } catch (const Exception &excpt) { cerr << "Unexpected exception " << excpt; exit(1); } cout<< "successfully created team "<< t->name(); try { goalkeeper=pf->createPlayer("Stefan Klos"); forward=pf->createPlayer("Andy Moeller"); } catch (const Exception &excpt) { cerr << "Unexpected exception " << excpt ; exit(1); Original: Wolfgang Emmerich, 2000
Prof. Fbio M. Costa - Instituto de Informtica / UFG 22

Client.cc (cont.)
output=goalkeeper->name(); cout << "created player " << output << endl; output=forward->name(); cout << "created player " << output << endl; try { t->add(goalkeeper,1); t->add(forward,10); output=t->print(); cout << output << endl; } catch (const Exception &excpt) { cerr << excpt << endl; exit(1); } } Original: Wolfgang Emmerich, 2000
Prof. Fbio M. Costa - Instituto de Informtica / UFG

23

Plataformas de Middleware Heterogneas

Motivao
Component Component Component Component Component Component Component

Middleware Vendor A

Middleware Vendor B

Middleware Vendor C

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

25

Quando Necessrio Ter Diferentes Plataformas de Middleware


Implementaes de plataformas de middleware se diferenciam em vrios critrios:
Mapeamentos de linguagens de programao disponveis Servios e facilidades disponveis Plataformas de hardware suportadas Plataformas de sistemas operacionais suportadas

Separao de domnios de segurana Sistemas distribudos em larga escala


Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

26

Integrao de Plataformas de Middleware


Component Component Component Component Component Component Component

OLE ORB

ORB

ORB

RPC

Bridge

Bridge
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

27

Pontes
in-line
Client

Em nvel de requisies
Client
DSI
DII

Obj. Imp.

Obj. Imp.

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

28

Integrao de Middleware
Interoperabilidade: habilidade de diferentes implementaes do mesmo padro de middleware operarem em conjunto
Requer a definio de protocolos de interao

Inter-funcionamento: integrao de diferentes padres de middleware


Requer
Mapeamento entre modelos de objetos Definio de protocolos de interao
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

29

Interoperabilidade versus Inter-funcionamento


Interoperabilidade entre diferentes implementaes do mesmo padro
Ex.: entre diferentes produtos CORBA

Inter-funcionamento entre diferentes padres


CORBA DCE CORBA COM/DCOM/OLE

Fazem parte do padro da OMG:


Interoperabilidade em CORBA Inter-funcionamento entre COM e CORBA
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

30

Referncias de Objeto Interoperveis (IORs)


Referncias de objetos so opacas para os clientes Fabricantes de ORBs tm liberdade para definir implementao das referncias IORs so usadas para apresentar referncias de objetos no formato nativo de cada ORB
Formato padro (IOR) traduzido para o formato nativo de cada ORB

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

31

Protocolos de Interoperabilidade
Applications CORBA 2.0 GIOP ........ ESIOP

IIOP

DOETalk

DCE-CIOP

........

Mandatory: provides "out of the box" interoperability

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

32

General Inter-ORB Protocol (GIOP)


Define sete tipos de mensagens padro trocados entre ORBs distintos
Request Reply Locate Request Locate Reply Cancel request Close Connection Message Error
um protocolo abstrato: implementao de acordo com a tecnologia disponvel

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

33

Internet Inter-ORB Protocol (IIOP)


Mapeia GIOP para TCP/IP Prov operaes para abrir e fechar conexes TCP/IP requisito necessrio para conformidade com o padro CORBA Suportado por todos os ORBs CORBA existentes no mercado
Ex.: ORB embutido no Netscape Communicator
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

34

Representao de Dados Comum


Definida como parte do GIOP Implementao da camada de apresentao para suporte heterogeneidade Mapeamento de tipos de dados IDL para fluxos de bytes segundo o protocolo de transporte Define codificao para:
Tipos primitivos Tipos estruturados IORs
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

35

Motivao para InterFuncionamento


COM e OLE/Automation so amplamente utilizados para a integrao de aplicaes em desktops
Documentos compostos Interfaces com o usurio (VB, VC++)

OMG ainda no oferece suporte para documentos compostos e interfaces com o usurio COM e OLE no suportam distribuio
embora DCOM, introduzido posteriormente, o faa

CORBA foi projetada para suportar distribuio


Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

36

Inter-Funcionamento COM-CORBA
Objetivo: prover um mapeamento bi-direcional e transparente entre COM/OLE e CORBA A especificao adotada foi submetida em conjunto por 11 fabricantes de ORBs
A maioria deles j tinha esta habilidade de interfuncionamento implementada em seus ORBs Adotada em maro de 1996

A Microsoft decidiu no se envolver neste esforo


Ao invs disto, procurou definir seu prprio ambiente distribudo: DCOM
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

37

Arquitetura de Inter-Funcionamento
Sistema de Objetos A ref. de obj. em A Ponte ref. de obj. em B implementao de objeto em B Sistema de Objetos B

viso em A do objeto alvo em B

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

38

Instanciaes Especficas
Bridge

Bridge

Target CORBA object CORBA server

COM view of CORBA object COM client

Target CORBA object CORBA server

Autom. view of CORBA object Automation client

CORBA objref

Bridge

CORBA objref

Bridge

CORBA view of COM object CORBA client


Original: Wolfgang Emmerich, 2000

Target COM object


COM server

CORBA view of Autom. object CORBA client

Automation object
Automation server
39

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Questes de Mapeamento em Inter-Funcionamento


Mapeamento de interfaces Mapeamento de composio de interfaces Mapeamento de identificadores (de objetos) Inversibilidade do mapeamento

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

40

CORBA COM
Habilita clientes COM a fazerem acesso a objetos CORBA Mapeamento razoavelmente bvio:
Tipos atmicos de IDL so semelhantes aos tipos primitivos de COM Tipos estruturados: idem Referncias de objeto CORBA mapeiam para ponteiros de interface COM Herana de interfaces em CORBA pode ser representada por meio de objetos COM com mltiplas interfaces Atributos CORBA so mapeados para operaes get e set em COM
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

41

Representaes de Dados Heterogneas

O Problema
Os computadores onde residem cliente e servidor podem usar diferentes formatos de representao de dados
Servidores RISC/Unix: big-endian Estaes NT e PCs/Unix: little endian
n+3 little-endians memory n+2 n+1 n

sign
n big-endians
Original: Wolfgang Emmerich, 2000

n+1

n+2

n+3

memory

sign
Prof. Fbio M. Costa - Instituto de Informtica / UFG 43

O Problema (cont.)
Diferentes esquemas de codificao de caracteres
P EBCDIC ASCII ISO-8859-1 UCS D7 50 50 r 99 72 72 e 85 65 65 u e n 95 6E 6E 40 20 20 M n s A2 73 73 t A3 74 74 e 85 65 65 r 99 72 72

A4 A2 A2 85 75 73 73 65 75 DF 65

D4 A4 85 95 4D 75 76 6E 4D FC 6E

0050 0072 0065 0075 00DF 0065 006E 0020 004D 00FC 006E 0073 0074 0065 0072

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

44

O Problema (cont.)
Diferentes linguagens de programao usam diferentes representaes de dados Exemplo: cadeias de caracteres em Pascal e em C++:
Pascal memria memria

3 a

a b

b c

c \0

C++

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

45

O Problema (cont.)
Representao little endian e big endian de uma seqncia:
sequence<unsigned short>:[2,3]
Big endian 0 0 0 2 0 2 0 3 Little endian 2 0 0 0 2 0 3 0
46

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Motivao
Representaes de dados precisam ser convertidas entre objetos clientes e servidores heterogneos Esta converso deve ser transparente para o desenvolvedor de aplicaes A converso pode ser feita:
na implementao da camada de apresentao na implementao da camada de aplicao na implementao da plataforma
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

47

Abordagens
Camada de apresentao: Representao de Dados Padronizada
XDR da Sun (eXternal Data Representation) CDR da OMG (Common Data Representation)

Camada de aplicao: uso de uma notao de sintaxe abstrata


ASN.1 XML & SGML

Plataforma: Mquina Virtual (ex.: Java)


Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

48

Common Data Representation da OMG


CDR define como ORBs de diferentes fabricantes trocam dados entre si Define como tipos definidos em IDL so mapeados para fluxos de octetos (bytes) e viceversa Lida com o mapeamento de:
tipos atmicos (primitivos) tipos estruturados pseudo-tipos (ex.: excees) referncias de objeto
Prof. Fbio M. Costa - Instituto de Informtica / UFG 49

Original: Wolfgang Emmerich, 2000

Mapeamento CDR para Tipos Atmicos


Inclui ambas as codificaes little e big endian
Mensagens explicitam a codificao escolhida Receptor responsvel pela converso, se necessria Reduz o overhead para transferncia de dados entre mquinas com a mesma representao

Determina tamanhos padro (e alinhamentos) para todos os tipos atmicos


Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

50

Alinhamento de Dados em CDR

Type Alignment Type Alignment Type Alignment char 1 long 4 double 4 octet 1 long long 8 boolean 1 short 2 float 4 enum 4

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

51

Exemplo: Alinhamento para Inteiros em CDR


Big Endian 12345 (short) 123456789 (long) 0x30 0x39 0x07 0x5B 0xCD 0x15 0x00 0x00 0x01 0x1F 0x71 0xFB 0x04 0xCB Little Endian 0x39 0x30 0x15 0xCD 0x5B 0x07 0xCB 0x04 0xFB 0x71 0x1F 0x01 0x00 0x00 Byte 0 1 0 1 2 3 0 1 2 3 4 5 6 7
52

1234567890123 (long long)

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Mapeamento CDR para Tipos Estruturados


Nmero de elementos (em uma dada codificao) Elementos como resultado do mapeamento de tipos aninhados (atmicos ou estruturados) Exemplo: sequence<unsigned short>:[2,3]
Big endian 0 0 0 2 0 2 0 Little endian 2 0 0 0 2 0 3
53

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

Mapeamento CDR para Referncias de Objeto


Informao necessria para representar uma referncia de objeto:
se NULL (no ser usada para requisies) Tipo do objeto referenciado Protocolos suportados Servios do ORB envolvidos no acesso ao objeto atravs da referncia

Estas informaes so fornecidas nas Referncias de Objeto Interoperveis (IORs)


Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

54

Resoluo na Camada de Aplicao


A plataforma de middleware somente pode resolver a heterogeneidade se ela sabe como os dados esto estruturados Algumas vezes no apropriado revelar as estruturas de dados para o middleware:
A plataforma no precisa realizar qualquer processamento das estruturas de dados Definies de interface se tornariam desnecessariamente complexas Transformaes de dados durante marshalling e unmarshalling no podem ser toleradas Os dados esto estruturados segundo uma abordagem especfica do domnio da aplicao
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

55

Abordagens para Domnios Especficos


ASN.1
Abstract Syntax Notation, definida pela International Telecommunication Union (ITU)

SGML
Usada na rea de automao de escritrios

XML
Intercmbio de dados estruturados na Web

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

56

Exemplo: DTD XML para Times de Futebol


<!ELEMENT Team ((Player|PlayerTrainer)*)> <!ATTLIST Team name #CDATA #REQUIRED> <!ELEMENT PlayerTrainer EMPTY> <!ATTLIST PlayerTrainer name #CDATA #REQUIRED role (Defender|Midfield|Forward) #REQUIRED Number #CDATA #REQUIRED Salary #CDATA #REQUIRED > <!ELEMENT Player EMPTY> <!ATTLIST Player name #CDATA #REQUIRED role (Defender|Midfield|Forward) #REQUIRED Number #CDATA #REQUIRED Original: > Wolfgang Emmerich, 2000 Prof. Fbio M. Costa - Instituto de Informtica / UFG

57

Exemplo: DTD XML para Times de Futebol (cont.)


<!DOCTYPE Team SYSTEM Soccer.dtd> <Team name=Chelsea FC> <PlayerTrainer name=Gianluca Vialli role=Forward Number = 10 Salary=10000000 /> <Player name=Marcel Desaily role=Defender Number=5 /> ... Original: Wolfgang Emmerich, 2000 </Team> Prof. Fbio M. Costa - Instituto de Informtica / UFG

58

Resolvendo a Heterogeneidade no Nvel da Plataforma


Mquina Virtual
Uma plataforma acima do sistema operacional Por definio, impe uma representao de dados comum

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

59

Exemplo: Mquina Virtual Java


Define os seguintes tipos atmicos:
boolean: representado como um int byte: inteiro de 8 bits sinalizado, em complemento de dois short: inteiro de 16 bits sinalizado, em compl. de dois int: inteiro de 32 bits sinalizado, em compl. de dois long: inteiro de 64 bits sinalizado, compl. de dois char: caracter UCS de 16 bits float: nmero de ponto flutuante de 32 bits, segundo o padro IEEE 754 double: nmero de ponto flutuante de 64 bits, segundo o padro IEEE 754
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

60

Pontos-Chave
Heterogeneidade pode ocorrer em vrios nveis:
Linguagem de Programao Middleware Representao de Dados

CORBA e COM resolvem a heterogeneidade de linguagem de programao atravs de uma IDL com mapeamentos para vrias linguagens Heterogeneidade de middleware resolvida atravs de especificaes de interoperabilidade e inter-funcionamento
Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

61

Pontos-Chave
Heterogeneidade de dados pode ser resolvida atravs de:
Representaes de dados padronizadas
CDR, NDR, XDR

Estruturao dos dados no nvel das aplicaes


XML, SGML, ASN.1

Mquinas Virtuais
JVM, Python VM, etc.

Original: Wolfgang Emmerich, 2000

Prof. Fbio M. Costa - Instituto de Informtica / UFG

62

Você também pode gostar