Architecture CORBA: les différents services dont le service de nommage Interopérabilité RMI CORBA

Documents pareils
Java Naming and Directory Interface

RMI. Remote Method Invocation: permet d'invoquer des méthodes d'objets distants.

Introduction à CORBA

Remote Method Invocation (RMI)

Intergiciels pour la répartition CORBA : Common Object Request Broker. Patrice Torguet torguet@irit.fr Université Paul Sabatier

Remote Method Invocation en Java (RMI)

Java RMI. Arnaud Labourel Courriel: Université de Provence. 8 mars 2011

CORBA. (Common Request Broker Architecture)

Programmation répartie: Objet distribué. CORBA (Common Object Request Broker Architectur)

Institut Supérieur de Gestion. Cours pour 3 ème LFIG. Java Enterprise Edition Introduction Bayoudhi Chaouki

NFP111 Systèmes et Applications Réparties

Principes. 2A-SI 3 Prog. réseau et systèmes distribués 3. 3 Programmation en CORBA. Programmation en Corba. Stéphane Vialle

Programmation réseau avec Java. 3/7 RMI, un peu de sécurité et CORBA

Intergiciel - concepts de base

Systèmes répartis. Fabrice Rossi Université Paris-IX Dauphine. Systèmes répartis p.1/49

Composants Logiciels. Le modèle de composant de CORBA. Plan

RMI le langage Java XII-1 JMF

Architecture JEE. Objectifs attendus. Serveurs d applications JEE. Architectures JEE Normes JEE. Systèmes distribués

Remote Method Invocation Les classes implémentant Serializable

Groupe Eyrolles, 2004 ISBN :

Environnements de Développement

CORBA haute performance

Connexion à SQL Server 2005 à partir du serveur d application SJSAS 9 Utilisation d une interface JDBC

GEI 465 : Systèmes répartis

Conception de serveurs d'applications ouverts

A. À propos des annuaires

Calcul Parallèle. Cours 5 - JAVA RMI

Dis papa, c est quoi un bus logiciel réparti?

Annuaires LDAP et méta-annuaires

Introduction aux «Services Web»

Extension SSO Java. Cette note technique décrit la configuration et la mise en œuvre du filtre de custom SSO Java.

Windows 2000 Server Active Directory

1 Introduction à l infrastructure Active Directory et réseau

Java et les bases de données

2 Chapitre 1 Introduction

4. SERVICES WEB REST 46

Vulgarisation Java EE Java EE, c est quoi?

[APPLICATON REPARTIE DE VENTE AUX ENCHERES]

Etude critique de mécanismes de sécurité pour l architecture Jini

Projet gestion d'objets dupliqués

CORBA. (Common Object Request Broker Architecture) Denivaldo LOPES

Le cadre des Web Services Partie 1 : Introduction

Programmation Web Avancée Introduction aux services Web

Supervision et infrastructure - Accès aux applications JAVA. Document FAQ. Page: 1 / 9 Dernière mise à jour: 15/04/12 16:14

NFS Maestro 8.0. Nouvelles fonctionnalités

EXA1415 : Annotations

Software Engineering and Middleware A Roadmap

Cedric Dumoulin (C) The Java EE 7 Tutorial

Cours Master Recherche RI 7 Extraction et Intégration d'information du Web «Services Web»

Introduction à la plateforme J2EE

et Active Directory Ajout, modification et suppression de comptes, extraction d adresses pour les listes de diffusion

Architecture Orientée Service, JSON et API REST

Tutoriel: Création d'un Web service en C++ avec WebContentC++Framework

Présentation de Active Directory

Déclarer un serveur MySQL dans l annuaire LDAP. Associer un utilisateur DiaClientSQL à son compte Windows (SSO)

Méta-annuaire LDAP-NIS-Active Directory

Compte Rendu d intégration d application

Les nouvelles architectures des SI : Etat de l Art

DUT. Vacataire : Alain Vidal - avidal_vac@outlook.fr

Sun Java System Access Manager Notes de version pour Microsoft Windows

Construction d Applications Réparties avec CORBA

Plan. Department of Informatics

Institut Supérieure Aux Etudes Technologiques De Nabeul. Département Informatique

Evaluation Idéopass Cahier d analyse technique

Déclarer un serveur MySQL dans l annuaire LDAP. Associer un utilisateur DiaClientSQL à son compte Windows (SSO)

Le modèle client-serveur

L annuaire et le Service DNS

Programmation répartie RPC & RMI

Java - RMI Remote Method Invocation. Java - RMI

Urbanisation des SI Conduite du changement IT 20/03/09. Patrick CHAMBET

Mise en œuvre des serveurs d application

Didier Donsez

Serveur d'application Client HTML/JS. Apache Thrift Bootcamp

JOnAS Day 5.1. Clustering

Préparation d un serveur Apache pour Zend Framework

Architectures web/bases de données

Evidian IAM Suite 8.0 Identity Management

Quelques patterns pour la persistance des objets avec DAO DAO. Principe de base. Utilité des DTOs. Le modèle de conception DTO (Data Transfer Object)

Meta Object Facility. Plan

Utilisation de JAVA coté Application serveur couplé avec Oracle Forms Hafed Benteftifa Novembre 2008

WEBSERVICES. Michael Fortier. Master Informatique 2ème année. A308, Université de Paris 13

Formateurs : Jackie DAÖN Franck DUBOIS Médiapôle de Guyancourt

Création d une application JEE

Chapitre VII : Principes des réseaux. Structure des réseaux Types de réseaux La communication Les protocoles de communication

Création d un service web avec NetBeans 5.5 et SJAS 9

Bases Java - Eclipse / Netbeans

Architectures Web Services RESTful

JOnAS 5. Serveur d application d

Couche application. La couche application est la plus élevée du modèle de référence.

ADMINISTRATION DE ADOBE LIVECYCLE MOSAIC 9.5

JADE : Java Agent DEvelopment framework. Laboratoire IBISC & Départ. GEII Université & IUT d Evry nadia.abchiche@ibisc.univ-evry.

OpenPaaS Le réseau social d'entreprise

XML, PMML, SOAP. Rapport. EPITA SCIA Promo janvier Julien Lemoine Alexandre Thibault Nicolas Wiest-Million

Chapitre VI- La validation de la composition.

Application Web et J2EE

L Orchestration de Services Web avec Orchestra. Goulven Le Jeune Orchestra Project Manager

Introduction aux services de domaine Active Directory

Urbanisation des SI. Des composants technologiques disponibles. Urbanisation des Systèmes d'information Henry Boccon Gibod 1

Transcription:

1 Module SI4 Applications réparties Architecture CORBA: les différents services dont le service de nommage Interopérabilité RMI CORBA Extraits de A. Occello, cours EPU 2009-2010, et L.Seinturier - 1 - Vue générale architecture d un système CORBA - 2 -

2-3 - - 4 -

3-5 - - 6 -

4 POA pour portable entre les différentes versions de ORBs Les POAs sont gérés par des POA Managers afin par ex. d ouvrir ou non le flux de requêtes, les bufferiser ou les rejeter, etc Les POAs sont configurables avec des politiques de gestion des servants: concernant leur persistance, assignation ou non de threads, autorisation d accès, etc => POA est un container - 7 - Utilisation du concept de POA - Exemple Côté serveur (et seulement!) ORB orb = ORB.init(args, null); // initialize the ORB // get reference to root poa & activate the POAManager POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); rootpoa.the_poamanager().activate(); // if not in ACTIVE state, requests to servants are not delivered but held in the corresponding POA associated to the servant // Here, we used as POA, the «rootpoa» which comes as Default in the ORB HelloImpl helloimpl = new HelloImpl(); // create the servant which is managed by its POA (remember that HelloImpl extends HelloPOA which extends Servant which is managed here by the default POA) // get object reference from the servant: this must be done through its POA org.omg.corba.object ref = rootpoa.servant_to_reference(helloimpl); Hello href = HelloHelper.narrow(ref); // and next, pass this reference to the client, using any means - 8 -

5 Ils sont utilisés en tant qu objets CORBA, qui exposent une interface IDL - 9 - Besoins d un service de nommage - 10 -

6 Rappel: Besoins de Nommage et serveur CORBA 1. Initialiser le bus CORBA : obtenir l ORB 2. Initialiser l adaptateur d objets : obtenir le POA 3. Créer les implantations d objets 4. Enregistrer les implantations par l adaptateur 5. Diffuser leurs références (IOR) afficher une chaîne codifiant l IOR ou stocker l IOR dans un fichier OU Utiliser un service de nommage 6. Attendre des requêtes venant du bus 7. Destruction du Bus - 11 - Rappel: Besoins de nommage et client CORBA 1. Initialiser le bus (ORB) 2. Créer les souches des objets à utiliser 2.a.obtenir les références d objet (IOR) copier/coller l IOR affichée coté serveur ou lire le fichier contenant l IOR OU Accéder au service de nommage 2.b. convertir vers les types nécessaires (narrow) 3. Réaliser les traitements Accès à l écran/système de fichier du serveur INSATISFAISANT - 12 -

7 Les services de nommage : usage Les services de nommage (ex: rmiregistry) sont utilisés : Pour stocker des objets Pour offrir un point d'accès aux applications réparties Référentiels d'entreprise pour accéder à : des applications (machine/port), des bases de données, des informations de sécurité (gestion des accès au sein d'une entreprise) des dispositifs tels que les imprimantes - 14 - Serveur Service de nommage pour RMI : RMIregistry URL du registre RMI : rmi://host:port bind ou rebind java.rmi.naming RMI Registry Client URL du registre RMI + nom de l objet lookup java.rmi.remote conversion & utilisation - 15 -

8 Service de nommage pour CORBA : CosNaming Des différences dans le scénario d obtention du service de nommage : orbd ou tnameserv localhost:1050 Client ou Serveur resolve_initial_references ("NameService"); ORB org.omg.cosnaming.namingcontext // get the root naming context // NameService invokes the name service org.omg.corba.object objref = orb.resolve_initial_references("nameservice"); // Use NamingContextExt which is part conversion of the Interoperable // Naming Service (INS) specification. NamingContextExt ncref = NamingContextExtHelper.narrow(objRef); ajout,retrait,lecture,... Example on Server side: // bind the Object Reference in Naming String name = "Hello"; NameComponent path[] = ncref.to_name( name ); ncref.rebind(path, href); Example on Client side: // resolve the Object Reference in Naming String name = "Hello"; Hello helloimpl = HelloHelper.narrow( ncref.resolve_str(name)); - 16 - Utilisation du service de nommage CORBA: Ex de Configuration & exécution Lancement du service de nommage (dépend de l implem. CORBA utilisée évidemment); ici Orbacus Sous Windows : java com.ooc.cosnaming.server Sous Linux : nameserv Utiliser l option -i pour afficher l IOR puis exécuter la commande iordump pour voir la machine et le port sur lequel le service est lançé Lancement d un serveur/client avec l option : -ORBInitRef NameService=corbaloc:iiop:host:port/NameService ajoute le service de nom NameService à la liste des services initiaux de l ORB en précisant où trouver le service Pas de transparence vis-à-vis du service utilisé - 25 -

9 JNDI - 26 - JNDI en quelques mots Services de nommages connus : rmiregistry, Corba naming Services d annuaires connus : LDAP, DNS Des fonctionnalités communes Principe : Fournir une API (java) uniforme à des services de nommage ou d annuaire «Java Naming and Directory Interface» Utilisation de pilotes SPI dynamiquement chargeables LDAP, DNS, NIS, NDS, RMI, CORBA, et FileSystems - 27 -

10 Service providers (SPI) SPI est l interface permettant d attaquer différents providers de manière uniforme. Les providers «compatibles» doivent fournir un ensemble de classes implémentant javax.naming.spi. - 28 - Le contexte : notion de chemin d accès Structure hiérarchique de graphe équivalente à la notion de (sous)répertoire : nœuds = contextes (A, B, C, D) feuilles = objets (1, 2, 3, 4, 5) Le contexte permet une isolation des noms pour plusieurs applications => évite les collisions Unicité d un nom dans un contexte mais un objet peut avoir plusieurs noms L objet référencé «2» est commun aux contextes A/B et A/C - 29 -

11 Unicité des noms EPU SI MAM BIO ELEC pinna arthur clément estelle arthur - 30 - Interface Context : fonctions d enregistrement Lier un nom à un objet. Le nom ne doit pas déjà être lié à un autre objet void bind(string name, Object object) Lier un nom à un objet et si le nom est déjà lié, la liaison précédente est écrasée void rebind(string name, Object object) Délier l'objet pointé par le nom void unbind(string name) Modifier le nom auquel l'objet est lié void rename(string oldname, String newname) - 31 -

12 Interface Context : fonctions de recherche Renvoyer un objet à partir de son nom Object lookup(string name) Envoyer une énumération contenant les noms liés à un contexte, ainsi que les objets liés à ces noms et leur classe NamingEnumeration listbindings(string name) Renvoyer une énumération contenant les noms liés au contexte, ainsi que les noms de classes des objets liés NamingEnumeration list(string name) - 32 - Contexte initial et sous-contextes InitialContext définit UN point d entrée pour l utilisation de JNDI pas forcément le contexte racine donne une visibilité relative : X et X/Y ne sont pas accessibles depuis le contexte initial IC Possibilité de créer des sous-contextes Tous les contextes intermédiaires doivent exister : pour accéder à 1, A et A/B doivent exister public Context createsubcontext(string name) throws NamingException - 33 -

13 Nommage versus Annuaire Un service de nommage (Naming) permet de retrouver des objets à partir d'un nom ("pages blanches") Un service d annuaire (Directory) rajoute des fonctionnalités permettant d'associer des attributs aux points d'entrée, et de faire une recherche sur ces attributs ("pages jaunes") - 34 - Les fonctions de base d un service de pages jaunes (Directory) Mêmes méthodes que Context (rebind, lookup, createsubcontext,...) Créé à partir de InitialDirContext Rajoute la gestion des attributs Rajoute les fonctions sophistiquées de recherche - 35 -

14 RETOUR OU APERCU DE LDAP : Lightweight Directory Access Protocol Protocole d'annuaire sur TCP/IP. Adaptation du protocole DAP (protocole d'accès au service d'annuaire X500 de l'osi) à l'environnement TCP/IP. Frontal d'accès à des annuaires X500, 1995, Université du Michigan ( U-M LDAP). Annuaire natif (standalone LDAP) - 37 - Standard et Extensible le protocole : accéder à distance à l'information, un modèle d'information : définir le type de données, un modèle de nommage : définir comment l'information est organisée et référencée, un modèle fonctionnel : comment accéder à l'information, un modèle de sécurité : protéger données et accès, un modèle de duplication : répartir la base entre les serveurs de la base, des APIs : développer des applications clientes, LDIF : un format d'échange de données.

15 Le protocole Communication client-serveur. se connecter ou se déconnecter, rechercher, comparer, créer, modifier ou effacer des entrées. Dialogue LDAP pas en ASCII mais utilise le format de codage Basic Encoding Rule (BER). Comment utiliser LDAP, Corba Naming ou RMI registry via JNDI - 43 -

16 Packages JNDI javax.naming : fonctionnalités de nommage enregitrement et recherche (bind, lookup) javax.naming.directory : fonctionnalités étendues aux services d annuaire javax.naming.spi : interface pour les fournisseurs javax.naming.event, javax.naming.ldap,... - 44 - Configuration de JNDI : ContextFactory & Provider Consiste à choisir : quel service de nommage utiliser un fournisseur particulier Utilisation de propriétés systèmes "java.naming.factory.initial" ou Context.INITIAL_CONTEXT_FACTORY "java.naming.provider.url" ou Context.PROVIDER_URL - 45 -

17 Configuration de JNDI : ContextFactory & Provider Deux façons de configurer ces propriétés : Paramétrer le contexte initial : Hashtable env = new Hashtable(); env.put("java.naming.factory.initial",...); env.put("java.naming.provider.url",...); javax.naming.context ct = new InitialContext(env); Passer en paramètre de ligne de commande de Java : java -Djava.naming.factory.initial=value -Djava.naming.provider.url=value Server - 46 - ContextFactory : exemples FileSystem : com.sun.jndi.fscontext.fscontextfactory Lightweight Directory Access Protocol (LDAP) : com.sun.jndi.ldap.ldapctxfactory CORBA services (COS) naming service : com.sun.jndi.cosnaming.cnctxfactory Java Remote Method Invocation (RMI) Registry : com.sun.jndi.rmi.registry.registrycontextfactory NIS : com.sun.jndi.nis.nisctxfactory NDS : com.novell.naming.service.nds.ndsinitialcontextfactory - 47 -

18 Providers et formats d accès : exemples FileSystem : file://directory_path Lightweight Directory Access Protocol (LDAP) : ldap://host:port CORBA services (COS) naming service : corbaloc::host:port/nameservice Java Remote Method Invocation (RMI) Registry : rmi://host:port/ NIS : nis://servername/domain NDS : nds://ndstreename - 48 - Création du contexte initial : exemple pour un système de fichier import javax.naming.context; import javax.naming.initialcontext; import javax.naming.binding; import javax.naming.namingenumeration; import javax.naming.namingexception; // Pour les paramètres d'initialisation import java.util.hashtable; Hashtable hashtableenvironment = new Hashtable(); hashtableenvironment.put(context.initial_context_factory, "com.sun.jndi.fscontext.fscontextfactory"); hashtableenvironment.put(context.provider_url, "file://tmp"); Context context = new InitialContext(hashtableEnvironment); - 49 -

19 Lien avec la sécurité private Context getinitialctx() { // Set up our JNDI environment properties Hashtable env = new Hashtable(); env.put(context.initial_context_factory, INITCTX); env.put(context.provider_url, HOST); env.put(context.security_authentication, "simple"); env.put(context.security_principal, USER); env.put(context.security_credentials, PASSWORD); try { return new InitialDirContext(env); } catch(namingexception e) {... } Sécurité associée à un nœud Se répercute aux sous-nœuds - 50 - Lister un contexte Lister un contexte NamingEnumeration list = ctx.list("awt"); while (list.hasmore()) { NameClassPair nc = (NameClassPair)list.next(); System.out.println(nc); } - 51 -

20 Lier un objet à un contexte Création d'un sous-contexte Context result = ctx.createsubcontext("new"); - Création de la liaison ctx.bind("favorite", fruit); On peut utiliser rebind. Il est également possible de renommer un objet en utilisant Context.rename(). - 52 - RMI-IIOP et JNDI pour l interopérabilité CORBA/RMI - 60 -

21 Communication inter-orb composant c++ (O.R.B.) composant java (O.R.B.) (O.R.B.) BD composant cobol (O.R.B.) Java-RMI? IIOP IIOP? composant TCP/IP network (O.R.B.) DCE-CIOP IIOP DCE network IIOP DCE-CIOP DCE-CIOP Bridge (O.R.B.) (O.R.B.) composant BD - 61 - Protocoles : GIOP, IIOP et JRMP GIOP (General Inter-ORB Protocol) spécifie un standard de communications entre ORBs basé sur : un format pour les références d objet interopérable (IOR) une représentation commune des données échangées entre les ORBs : la spécification CDR (Common Data Representation) un ensemble de messages de transport de requêtes aux objets (reply, Request, ) IIOP (Internet Inter-ORB Protocol) est l'implémentation la + populaire du protocole GIOP au dessus de TCP/IP JRMP (Java Remote Method Protocol) est le protocole utilisé par Java RMI IIOP et JRMP sont incompatibles : comment faire interopérer Corba et RMI? - 62 -

22 Pourquoi faire interopérer RMI et CORBA? RMI est une solution tout-java Un modèle simple de programmation Un monde clos CORBA est un standard pour les objets distribués Un modèle de programmation pas si simple et non dédié spécifiquement à Java Offre l interopérabilité à moindre coût Combiner leurs avantages respectifs sans passer par un nouveau middleware - 63 - Intégration Java-RMI/CORBA Coté CORBA : à partir de la spec 2.3 la spec précise quel sous ensemble de JAVA RMI peut être utilisé pour faire du CORBA Java to IDL : Prise en charge de la sémantique liée objets RMI Passage par valeur : un équivalent à la sérialisation Java Coté RMI : à partir de la jdk 1.3 Extension du compilateur rmic pour pouvoir générer à partir de code Java : des souches compatibles IIOP des IDLs Interopérabilité et service de nommage : JNDI Restrictions : pas de D.Garbage collector, pas de cast Java, pas de surcharge, pas de RMISSLxxxSocketFactory - 64 -

23 RMI : Compatibilité IIOP Différences de développement coté (RMI) serveur (1/2) 1. Clause d importation javax.rmi.portableremoteobject au lieu de java.rmi.unicastremoteobject javax.naming.initialcontext au lieu de java.rmi.naming 2. Définition de l objet distant pas de différence au niveau de l interface de l objet au niveau de l implémentation : public class MyObjectImpl extends PortableRemoteObject implements MyObject 3. Enregistrement de l objet distant via JNDI InitialContext.rebind("obj_ref", obj); 4. Génération des souches compatibles IIOP : rmic iiop MyObjectImpl (ce qui génère alors tout ce qu il faut pour fonctionner côté serveur) - 65 - RMI: Compatibilité IIOP Différences de développement coté (RMI) serveur (2/2) 5. Lancement du service de nommage choisi : (rmiregistry, CosNaming, ) 6. Dans le cas de l interopérabilité avec CORBA, une étape supplémentaire : génération de l IDL avec rmic -idl Pour générer les descriptions IDL des interfaces RMI - 66 -

24 RMI: Compatibilité IIOP Différences de développement coté (RMI) client 1. Clause d importation (idem serveur) javax.rmi.portableremoteobject; javax.naming.initialcontext; 2. Obtenir un objet distant toujours via JNDI InitialContext IC = new InitialContext(env); Object obj = IC.lookup("obj_ref"); MyObject myobj = (MyObject)PortableRemoteObject.narrow(obj,MyObject.class); 3. Génération des souches compatibles IIOP pour les interfaces distantes à utiliser : rmic iiop MyObject Rem: les.class obtenus + ceux du client peuvent être déployés où on veut (autre machine par ex.) - 67 - Procédure de compilation : rmic -iiop Implementation File (MyObjectImpl.class) Coté serveur rmic -iiop Coté serveur _MyObject_Stub.class _MyObject_Tie.class Interface File (MyObject.class) Coté client rmic -iiop _MyObject_Stub.class - 68 -

25 Client (java) CORBA + Serveur RMI IDL CORBA de l objet 2) rmic -idl Interface RMI de l objet 3) jidl Ou idlj Client CORBA Implémentation RMI de l objet 1) rmic -iiop Stub CORBA Squelette RMI ORB Protocole IIOP ORB - 69 - Client (java) WS (axis)+ Serveur RMI WSDL de l interface 2) WSDL2Java --server 3) WSDL2Java SOAP Client du WS (ou servlet, ou navigateur) Client RMI=implem du WS (déployé sur Axis) Stub RMI 1) Java2WSDL Interface RMI de l objet Implémentation RMI de l objet Squelette RMI Protocole (JRMP ou IIOP) RMI RMI Le WS ne sert que de relai entre les méthodes exposées dans le WSDL et celles exposées par l interface RMI Impossible de faire différemment car on veut pouvoir supporter différentes technos de clients pas raisonnable que le WS=appli RMI, s initialise au moment d un appel sur le WS - 70 -

26 Client RMI + Serveur (java) CORBA Interface RMI de l objet 1) rmic -idl IDL CORBA de l objet 3) rmic -iiop Client RMI Implémentation CORBA de l objet 2) jidl ou idlj Stub RMI Squelette CORBA ORB Protocole IIOP ORB Étape 1 pas naturelle! Spécification s est concrétisée par des fichiers d interface RMI. Finalement, on décide d implanter le serveur en Corba Pertinent pour l écriture de nouvelles applications - 71 - Conclusion Interopérabilité CORBA/Java RMI peu courante mais Première approche d'unification : CORBA/Java RMI contre Micro$oft => effort pour faire face aux solutions tout Microsoft des utilisations plus fréquentes depuis l'apparition des EJB Importance de l interopérabilité face à la prolifération des langages, des middlewares,... Maturation des technologies émergence des middlewares orientés composants : ccm,.net Réalité différente dans les entreprises : solutions tout XML nécessité de traduire de A vers XML puis de XML vers B même mécanismes sous-jacents (langage intermédiaire, conversion des données,...) Pourquoi réinventer la roue? - 72 -

27 Quelques références... Le cours initial, complet : http://www.essi.fr/~occello/apprep/coursiiop-jndi.ppt Le site de Sun sur RMI-IIOP : http://java.sun.com/j2se/1.4.2/docs/guide/rmi-iiop/ Un article sur l interopérabilité RMI/CORBA : http://www.javaworld.com/jw-12-1999/jw-12-iiop.html Tutorial JNDI http://java.sun.com/products/jndi/tutorial/toc.html - 73 -