diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 152c3b5d8418a7fcad70874dd12103aaf7111492..449c691ef62600739a325b282415ee506713cc53 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -7,11 +7,11 @@ import { InternationalisationService, Language, LanguageCode } from './services/
 import { Observer } from './services/observer';
 import { ErrorService } from './services/error/error.service';
 import { AlertDialog } from './components/alert-dialog/alert-dialog.component';
+import { FormulaireService } from './services/formulaire/formulaire.service';
 
 @Component({
   selector: 'nghyd-app',
   template: `
-
   <select [(ngModel)]=_currentLanguage (change)=onSelectLang($event)>
     <option *ngFor="let l of intlService.languages" [value]=l.code>{{l.label}}</option>
   </select>
@@ -28,11 +28,13 @@ import { AlertDialog } from './components/alert-dialog/alert-dialog.component';
   <param-input symbol="Ks"></param-input>
   -->
   `,
-  providers: [ParamService, InternationalisationService, HttpService]
+  providers: [ParamService, InternationalisationService, HttpService, FormulaireService]
 })
 export class AppComponent implements Observer {
   private _currentLanguage: LanguageCode;
 
+  private _displayErrorDialog: boolean = false;
+
   constructor(private intlService: InternationalisationService, private appRef: ApplicationRef, private dialog: MdDialog, private errorService: ErrorService) { }
 
   private initLocale() {
@@ -74,16 +76,16 @@ export class AppComponent implements Observer {
     this.appRef.tick();
   }
 
-  ngAfterViewChecked() {
-    this.intlService.acknowledgeLocaleChanged();
-  }
-
   // interface Observer
 
   update(data: any): void {
     // on ouvre un dialogue avec le message d'erreur reçu
-    let dialogRef = this.dialog.open(AlertDialog);
-    let ad: AlertDialog = dialogRef.componentInstance;
-    ad.text = String(data);
+    if (this._displayErrorDialog) {
+      let dialogRef = this.dialog.open(AlertDialog);
+      let ad: AlertDialog = dialogRef.componentInstance;
+      ad.text = String(data);
+    }
+    else
+      console.log(data);
   }
 }
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index ae0292682d8f9ab1a68ada481b25d6b857954d37..e0bd258249d3ffb47103bbbd56bc273f92a0484b 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -10,11 +10,13 @@ import { AppComponent } from './app.component';
 import { ParamInputComponent } from './components/param-input/param-input.component';
 import { FieldSetComponent } from './components/field-set/field-set.component';
 import { ParamFieldLineComponent } from './components/param-field-line/param-field-line.component';
+import { SelectFieldLineComponent } from './components/select-field-line/select-field-line.component';
 import { CondDistriComponent } from './calculators/cond_distri/conddistri.component';
 import { LechaptCalmonComponent } from './calculators/lechapt-calmon/lechaptcalmon.component';
 import { AlertDialog } from './components/alert-dialog/alert-dialog.component';
 import { AppErrorModule } from './error.module';
 import { CalculatorResultsComponent } from './components/calculator-results/calculator-results.component';
+import { GenericCalculatorComponent } from './calculators/generic/calculator.component';
 
 @NgModule({
   imports: [
@@ -31,8 +33,8 @@ import { CalculatorResultsComponent } from './components/calculator-results/calc
     AppComponent,
     ParamInputComponent,
     FieldSetComponent,
-    ParamFieldLineComponent,
-    CondDistriComponent, LechaptCalmonComponent,
+    ParamFieldLineComponent, SelectFieldLineComponent,
+    CondDistriComponent, LechaptCalmonComponent, GenericCalculatorComponent,
     AlertDialog,
     CalculatorResultsComponent
   ],
diff --git a/src/app/calculators/cond_distri/conddistri.component.html b/src/app/calculators/cond_distri/conddistri.component.html
index 20774680a0cb47c61cb5fd6ed5e928aa66345233..c3bec4eb3bcc28ff1fcdbec84108a969640d54bb 100644
--- a/src/app/calculators/cond_distri/conddistri.component.html
+++ b/src/app/calculators/cond_distri/conddistri.component.html
@@ -1,18 +1,10 @@
 <h1 i18n="@@titre_cond_distri">Conduite distributrice</h1>
-<field-set *ngFor="let fs of _fieldSets" [fieldSet]=fs (onRadio)=onRadioClick($event)></field-set>
-
-<div style="text-align:center;">
-    <button type="button" class="button_compute" name="Calculer" (click)="doCompute()" i18n="@@hyd_compute">Calculer</button>
-</div>
-<calc-results [style.display]="getResultsStyleDisplay()"></calc-results>
-
+<hydrocalc type="ConduiteDistributrice"></hydrocalc>
 <!--
-    <tr *ngFor="let r of _results; let i=index" [class]="getResultClass(i)">
-
-    <h1>{{_title}}</h1>
-  <field-set *ngFor="let fs of _fieldSets" title="fs.title" fields="fs.paramList"></field-set>
-  <field-set title="titre de field set" fields="Q,D"></field-set>
-  <param-input symbol="Q"></param-input>
-  <param-input symbol="Q"></param-input>
-  <param-input symbol="Ks"></param-input>
+    <field-set *ngFor="let fs of _fieldSets" [fieldSet]=fs (onRadio)=onRadioClick($event)></field-set>
+    
+    <div style="text-align:center;">
+        <button type="button" class="button_compute" name="Calculer" (click)="doCompute()" i18n="@@hyd_compute">Calculer</button>
+    </div>
+    <calc-results [style.display]="getResultsStyleDisplay()"></calc-results>
  -->
\ No newline at end of file
diff --git a/src/app/calculators/cond_distri/conddistri.component.ts b/src/app/calculators/cond_distri/conddistri.component.ts
index 477ed697b4bfd02aa86756a0fe200708766bc719..45b4fce07bf3f76cfa47016c6cc894f05358415b 100644
--- a/src/app/calculators/cond_distri/conddistri.component.ts
+++ b/src/app/calculators/cond_distri/conddistri.component.ts
@@ -1,415 +1,8 @@
-import { Component, OnInit, DoCheck, ViewChild } from '@angular/core';
-import { Response } from '@angular/http';
-import { Observable } from "rxjs/Observable";
-import 'rxjs/add/operator/toPromise';
-
-import { IParamsEquation, Nub, ConduiteDistrib, ConduiteDistribParams } from "jalhyd";
-
-import { ParamService } from '../../services/param/param.service';
-import { HttpService } from '../../services/http/http.service';
-import { InternationalisationService } from '../../services/internationalisation/internationalisation.service';
-import { FieldSet } from '../../calculators/generic/formulaire';
-import { NgParameter, ParamRadioConfig } from '../../calculators/generic/ngparam';
-import { GenericCalculatorComponent } from '../generic/calculator.component';
-import { CalculatorResultsComponent } from '../../components/calculator-results/calculator-results.component';
+import { Component, } from '@angular/core';
 
 @Component({
     selector: 'cond-distri',
-    templateUrl: "./conddistri.component.html",
-    // styles: [`
-    //     .hyd_bouton_submit {
-    //     width: 10em;
-    // }`
-    // ]
-    styles: [`
-    .button_compute {
-        height: 3em;
-        width: 30%;
-    }
-    `
-    ]
+    templateUrl: "./conddistri.component.html"
 })
-export class CondDistriComponent extends GenericCalculatorComponent implements OnInit, DoCheck {
-    /**
-     * objet JSON chargé depuis le fichier de traduction
-     */
-    // private _localisation = {};
-
-    /**
-     * objet JSON chargé depuis le fichier de configuration de la calculette
-     */
-    // private _config = {};
-
-    // private _fieldSets: FieldSet[] = [];
-
-    /**
-     * symbole du paramètre à calculer par défaut (cf config "idCal")
-     */
-    // private _defaultCalculatedParam: string;
-
-    /**
-     * composant d'affichage des résultats
-     */
-    @ViewChild(CalculatorResultsComponent)
-    private resultsComponent: CalculatorResultsComponent;
-
-    /**
-     * flag d'affichage du composant de résultats
-     */
-    // private _showResults: boolean = false;
-
-    constructor(private paramSvc: ParamService, private httpSvc: HttpService, private intlSvc: InternationalisationService) {
-        super(paramSvc, httpSvc, intlSvc);
-    }
-
-    // // private loadLocalisation() {
-    // //     let ths = this;
-    // //     let processData = function (s: string) {
-    // //         // fermeture nécessaire pour capturer la valeur de this (undefined sinon)
-    // //         ths._localisation = JSON.parse(s);
-    // //         ths.paramService.updateLocalisation(ths._localisation);
-    // //     }
-
-    // //     let f: string = "app/calculators/cond_distri/cond_distri." + this.intlService.languageCode + ".json"
-    // //     this.httpService.httpGetRequest(undefined, undefined, undefined, f, processData);
-    // // }
-    // private loadLocalisation(): Promise<string> {
-    //     let ths = this;
-    //     let processData = function (s: string) {
-    //         // fermeture nécessaire pour capturer la valeur de this (undefined sinon)
-    //         ths._localisation = JSON.parse(s);
-    //         ths.paramService.updateLocalisation(ths._localisation);
-    //     }
-
-    //     let f: string = "app/calculators/cond_distri/cond_distri." + this.intlService.currentLanguage.tag + ".json"
-    //     let resp: Observable<Response> = this.httpService.httpGetRequestResponse(undefined, undefined, undefined, f);
-
-    //     let prom = resp.map(res => res.text()).toPromise();
-    //     prom.then((res) => {
-    //         processData(res);
-    //     })
-
-    //     return prom;
-    // }
-
-    // private logObject(obj: {}, m?: string) {
-    //     // évite le message "Value below was evaluated just now" dans le debugger de Chrome
-    //     if (m == undefined)
-    //         console.log(JSON.stringify(obj));
-    //     else
-    //         console.log(m + " " + JSON.stringify(obj));
-    // }
-
-    // private parseConfig() {
-    //     this._fieldSets = [];
-
-    //     for (let conf_index in this._config) {
-
-    //         let conf = this._config[conf_index];
-    //         let conf_id: string = conf["id"];
-
-    //         // field set
-    //         if (conf_id.startsWith("fs_")) {
-    //             let fieldSet: FieldSet = new FieldSet(conf_id);
-
-    //             let fields = conf["fields"];
-    //             for (let field_index in fields) {
-    //                 let field = fields[field_index];
-    //                 if (field["type"] === "input") {
-    //                     let input_id = field["id"];
-    //                     let param: NgParameter = this.paramService.getParameter(input_id);
-    //                     if (param != undefined) {
-    //                         param.unit = field["unit"];
-    //                         param.v = +field["value"];
-    //                         param.radioConfig = NgParameter.getRadioConfig(conf["option"]);
-    //                         param.radioState = ParamRadioConfig.FIX;
-    //                         param.isDefault = false; // malgré le fait qu'il soit initialisé dans la déclaration de la classe NgParam à false, quand on relit sa valeur, il vaut undefined (merci Microsoft)
-    //                         fieldSet.addField(param);
-    //                     }
-    //                 }
-    //             }
-    //             if (!fieldSet.isEmpty()) {
-    //                 this._fieldSets.push(fieldSet);
-    //             }
-    //         }
-    //         // options globales
-    //         else if (conf_id === "options") {
-    //             // id du paramètre à calculer par défaut
-    //             this._defaultCalculatedParam = conf["idCal"];
-    //             let p = this.getParamFromSymbol(this._defaultCalculatedParam);
-    //             p.isDefault = true;
-    //             p.radioState = ParamRadioConfig.CAL;
-    //         }
-    //     }
-    // }
-
-    // private getParamFromSymbol(symbol: string): NgParameter {
-    //     for (let fs of this._fieldSets) {
-    //         for (let p of fs.fields) {
-    //             if (p.symbol === symbol)
-    //                 return p;
-    //         }
-    //     }
-    //     return undefined;
-    // }
-
-    // private getParamFromState(st: ParamRadioConfig): NgParameter {
-    //     for (let fs of this._fieldSets) {
-    //         for (let p of fs.params) {
-    //             if (p.radioState == st)
-    //                 return p;
-    //         }
-    //     }
-    //     return undefined;
-    // }
-
-    // private loadConfig() {
-    //     let ths = this;
-    //     let processData = function (s: string) {
-    //         // fermeture nécessaire pour capturer la valeur de this (undefined sinon)
-    //         ths._config = JSON.parse(s);
-    //         ths.parseConfig();
-    //     }
-
-    //     let f: string = "app/calculators/cond_distri/cond_distri.config.json"
-    //     this.httpService.httpGetRequest(undefined, undefined, undefined, f, processData);
-    // }
-
-    // ngOnInit() {
-    //     this.loadLocalisation();
-    //     this.loadConfig();
-    //     // this.updateLanguage();
-    // }
-
-    // private getFieldSet(id: string) {
-    //     for (let fs of this._fieldSets) {
-    //         if (fs.id == id)
-    //             return fs;
-    //     }
-    //     return undefined;
-    // }
-
-    // private updateLanguage() {
-    //     for (let conf_index in this._config) {
-    //         let conf = this._config[conf_index];
-    //         let conf_id: string = conf["id"];
-
-    //         if (conf_id.startsWith("fs_")) {
-    //             let fieldSet: FieldSet = this.getFieldSet(conf_id);
-    //             if (fieldSet != undefined)
-    //                 fieldSet.title = this._localisation[conf_id];
-    //         }
-    //     }
-    // }
-
-    // ngDoCheck() {
-    //     // let q = this.getParamFromSymbol("Q");  // A VIRER !!!!
-    //     // if (q != undefined) {
-    //     //     q.radioState = ParamRadioConfig.VAR;
-    //     //     q.minValue = 1.5;
-    //     //     q.maxValue = 6;
-    //     //     q.stepValue = 0.3;
-    //     // }
-
-    //     if (this.intlService.localeChanged) {
-    //         const promise = this.loadLocalisation()
-    //             .then(() => {
-    //                 this.updateLanguage();
-    //             });
-    //     }
-    // }
-
-    /*
-     * gestion des événements clic sur les radios :
-     * envoi d'un message au composant parent
-     * cf. https://angular.io/guide/component-interaction#parent-listens-for-child-event
-     */
-
-    // private onRadioClick(info: string) {
-    //     this._showResults = false;
-
-    //     // console.log("CondDistriComponent " + info);
-    //     let tmp: string[] = info.split("_");
-    //     let symbol: string = tmp[0];
-
-    //     let sourceParam = this.getParamFromSymbol(symbol);
-    //     let oldState: ParamRadioConfig = sourceParam.radioState;
-    //     let newState: ParamRadioConfig = ParamRadioConfig[tmp[1].toUpperCase()];
-    //     // console.log(sourceParam.symbol + " : " + ParamRadioConfig[oldState] + " -> " + ParamRadioConfig[newState]);
-    //     // this.logObject(sourceParam, "sourceobj1");
-
-    //     switch (oldState) {
-    //         case ParamRadioConfig.FIX:
-    //             switch (newState) {
-    //                 case ParamRadioConfig.VAR:
-    //                     this.resetOther(sourceParam, ParamRadioConfig.CAL);
-    //                     break;
-
-    //                 case ParamRadioConfig.CAL:
-    //                     this.resetOther(sourceParam, ParamRadioConfig.VAR);
-    //                     break;
-    //             }
-    //             break;
-
-    //         case ParamRadioConfig.VAR:
-    //             switch (newState) {
-    //                 case ParamRadioConfig.CAL:
-    //                     this.resetOther(sourceParam, ParamRadioConfig.VAR);
-    //                     break;
-    //             }
-    //             break;
-
-    //         case ParamRadioConfig.CAL:
-    //             switch (newState) {
-    //                 case ParamRadioConfig.FIX:
-    //                     this.setDefault();
-    //                     break;
-
-    //                 case ParamRadioConfig.VAR:
-    //                     this.resetOther(sourceParam, ParamRadioConfig.CAL);
-    //                     this.setDefault();
-    //                     break;
-    //             }
-    //     }
-
-    //     sourceParam.radioState = newState;
-
-    //     // this.appRef.tick();
-    //     //        this.changeDetectorRef.detectChanges();  // provoque une détection des changements dans les contrôles
-    // }
-
-    /**
-     * remet tous les paramètres à FIX sauf "me" et ceux (celui) à l'état "except"
-     */
-    // private resetOther(me: NgParameter, except: ParamRadioConfig) {
-    //     // console.log("reset me=" + me.symbol + " sauf=" + ParamRadioConfig[except])
-    //     for (let fs of this._fieldSets) {
-    //         for (let p of fs.params) {
-    //             if (p != me && p.radioState != except && p.radioConfig != ParamRadioConfig.FIX) {
-    //                 // console.log("reset " + p.symbol + " st " + ParamRadioConfig[p.radioState] + " -> FIX");
-    //                 p.radioState = ParamRadioConfig.FIX;
-    //             }
-    //         }
-    //     }
-    // }
-
-    /**
-     * met le paramètre par défaut à CAL
-     */
-    // private setDefault() {
-    //     let defaultParamCal = this.getParamFromSymbol(this._defaultCalculatedParam);
-    //     // console.log("setdefault " + defaultParamCal.symbol + " -> CAL")
-    //     defaultParamCal.radioState = ParamRadioConfig.CAL;
-    // }
-
-    // private getParameterValue(symbol: string): number {
-    //     for (let fs of this._fieldSets) {
-    //         for (let p of fs.params) {
-    //             if (p.symbol === symbol) {
-    //                 switch (p.radioState) {
-    //                     case ParamRadioConfig.FIX:
-    //                         return p.v;
-
-    //                     case ParamRadioConfig.VAR:
-    //                     case ParamRadioConfig.CAL:
-    //                         return undefined;
-    //                 }
-    //             }
-    //         }
-    //     }
-    // }
-
-    // private getComputedParameter(): NgParameter {
-    //     return this.getParamFromState(ParamRadioConfig.CAL);
-    // }
-
-    // private getVariatedParameter(): NgParameter {
-    //     return this.getParamFromState(ParamRadioConfig.VAR);
-    // }
-
-    // private addFixedResults(nDigits: number) {
-    //     for (let fs of this._fieldSets) {
-    //         for (let p of fs.params) {
-    //             if (p.radioState == ParamRadioConfig.FIX && p.symbol !== "Pr") {
-    //                 this.resultsComponent.addFixedResult(p, p.v, nDigits);
-    //             }
-    //         }
-    //     }
-    // }
-
-    // private doCompute() {
-    //     this._showResults = false;
-    //     let computedParam = this.getComputedParameter();
-
-    //     let Q: number = this.getParameterValue("Q"); // débit Q
-    //     let D: number = this.getParameterValue("D"); // diamètre D
-    //     let J: number = this.getParameterValue("J"); // perte de charge J
-    //     let Lg: number = this.getParameterValue("Lg"); // Longueur de la conduite Lg
-    //     let Nu: number = this.getParameterValue("Nu"); // Viscosité dynamique Nu
-    //     let prec: number = this.getParameterValue("Pr"); // précision
-    //     let nDigits = -Math.log10(prec);
-
-    //     let prms = new ConduiteDistribParams(Q, D, J, Lg, Nu);
-    //     let nub = new ConduiteDistrib(prms);
-
-    //     let varParam = this.getVariatedParameter();
-    //     this.resultsComponent.reset(varParam == undefined);
-    //     if (varParam == undefined) {
-    //         // pas de paramètre à varier
-
-    //         let res = nub.Calc(computedParam.symbol, 0, prec).vCalc;
-
-    //         this.addFixedResults(nDigits);
-    //         this.resultsComponent.addFixedResult(computedParam, res, nDigits);
-    //     }
-    //     else {
-    //         // il y a un paramètre à varier
-
-    //         this.addFixedResults(nDigits);
-    //         this.resultsComponent.setVariableParamHeader(varParam);
-    //         this.resultsComponent.setVariableResultHeader(computedParam);
-
-    //         let min: number = +varParam.minValue;
-    //         let max: number = +varParam.maxValue;
-    //         let step: number = +varParam.stepValue;
-
-    //         for (let val = min; val <= max; val += step) {
-    //             prms[varParam.symbol].v = val;
-
-    //             let res = nub.Calc(computedParam.symbol, 0, prec).vCalc;
-    //             this.resultsComponent.addVarResult(val, res, nDigits);
-    //         }
-    //         // for (let vr of this._varResults) {
-    //         //     console.log(vr);
-    //         // }
-
-    //         this.resultsComponent.setGraphTitle(computedParam.symbol + " = f( " + varParam.symbol + " )");
-    //         this.resultsComponent.generateGraph();
-    //     }
-    //     this._showResults = true;
-    // }
-
-    // private getResultsStyleDisplay() {
-    //     return this._showResults ? "block" : "none";
-    // }
-
-    protected getConfigPathPrefix(): string {
-        return "app/calculators/cond_distri/cond_distri."
-    }
-
-    protected getNubAndParameters(): [Nub, IParamsEquation] {
-        let Q: number = this.getParameterValue("Q"); // débit Q
-        let D: number = this.getParameterValue("D"); // diamètre D
-        let J: number = this.getParameterValue("J"); // perte de charge J
-        let Lg: number = this.getParameterValue("Lg"); // Longueur de la conduite Lg
-        let Nu: number = this.getParameterValue("Nu"); // viscosité dynamique 
-        let prms = new ConduiteDistribParams(Q, D, J, Lg, Nu);
-        let nub = new ConduiteDistrib(prms);
-
-        return [nub, prms];
-    }
-
-    protected getCalculatorResultsComponent(): CalculatorResultsComponent {
-        return this.resultsComponent;
-    }
+export class CondDistriComponent {
 }
diff --git a/src/app/calculators/generic/calculator.component.html b/src/app/calculators/generic/calculator.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..e3b9930131d5a4a0222269c659353fee84c5ef08
--- /dev/null
+++ b/src/app/calculators/generic/calculator.component.html
@@ -0,0 +1,6 @@
+<field-set *ngFor="let fs of fieldSets" [id]=fs.id [fieldSet]=fs (onRadio)=onRadioClick($event) (onSelectChange)=onSelectChanged($event)></field-set>
+
+<div style="text-align:center;">
+    <button type="button" class="button_compute" name="Calculer" (click)="doCompute()" i18n="@@hyd_compute">Calculer</button>
+</div>
+<calc-results [style.display]="getResultsStyleDisplay()"></calc-results>
\ No newline at end of file
diff --git a/src/app/calculators/generic/calculator.component.ts b/src/app/calculators/generic/calculator.component.ts
index 536b87ce6c69b8f3741f81485e328a55225cc5ec..8c02a02198442e7c7a0ff2e88ce034265db0f224 100644
--- a/src/app/calculators/generic/calculator.component.ts
+++ b/src/app/calculators/generic/calculator.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit, DoCheck, ViewChild } from '@angular/core';
+import { Component, OnInit, DoCheck, ViewChild, Input } from '@angular/core';
 import { Response } from '@angular/http';
 import { Observable } from "rxjs/Observable";
 import 'rxjs/add/operator/toPromise';
@@ -7,12 +7,13 @@ import { IParamsEquation, Nub } from "jalhyd";
 
 import { ParamService } from '../../services/param/param.service';
 import { HttpService } from '../../services/http/http.service';
+import { FormulaireService } from '../../services/formulaire/formulaire.service';
 import { InternationalisationService } from '../../services/internationalisation/internationalisation.service';
-import { FormulaireDefinition } from '../../calculators/generic/formulaire';
+import { FieldSet, FormulaireDefinition, CalculatorType, Dependency, ExistenceDependency, ValueDependency } from '../../calculators/generic/formulaire';
 import { NgParameter, ParamRadioConfig } from './ngparam';
 import { CalculatorResultsComponent } from '../../components/calculator-results/calculator-results.component';
+import { Observer } from '../../services/observer';
 
-/*
 @Component({
     selector: 'hydrocalc',
     templateUrl: "./calculator.component.html",
@@ -24,37 +25,43 @@ import { CalculatorResultsComponent } from '../../components/calculator-results/
     `
     ]
 })
-*/
-export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
+export class GenericCalculatorComponent implements OnInit, DoCheck, Observer {
+    /**
+     * Calculator type input attribute
+     */
+    private _calculatorType: CalculatorType;
+
+    @Input()
+    private set type(s: string) {
+        this._calculatorType = CalculatorType[s];
+    }
+
+    /**
+     * composant d'affichage des résultats
+     */
+    @ViewChild(CalculatorResultsComponent)
+    private resultsComponent: CalculatorResultsComponent;
+
     /**
      * objet JSON chargé depuis le fichier de traduction
      */
     private _localisation = {};
 
-    // private _fieldSets: FieldSet[] = [];
     private _formulaire: FormulaireDefinition;
 
-    // /**
-    //  * composant d'affichage des résultats
-    //  */
-    // @ViewChild(CalculatorResultsComponent)
-    // private resultsComponent: CalculatorResultsComponent;
-
     /**
      * flag d'affichage du composant de résultats
      */
     private _showResults: boolean = false;
 
-    private paramService: ParamService;
-    private httpService: HttpService;
-    private intlService: InternationalisationService;
+    constructor(private paramService: ParamService, private httpService: HttpService, private intlService: InternationalisationService, private formulaireService: FormulaireService) {
+        this.intlService.addObserver(this);
+    }
 
-    // constructor(private paramService: ParamService, private httpService: HttpService, private intlService: InternationalisationService) {
-    constructor(paramService: ParamService, httpService: HttpService, intlService: InternationalisationService) {
-        this.paramService = paramService;
-        this.httpService = httpService;
-        this.intlService = intlService;
-        this._formulaire = new FormulaireDefinition(paramService);
+    private get fieldSets(): FieldSet[] {
+        if (this._formulaire == undefined)
+            return [];
+        return this._formulaire.fieldSets;
     }
 
     private loadLocalisation(): Promise<string> {
@@ -62,11 +69,9 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
         let processData = function (s: string) {
             // fermeture nécessaire pour capturer la valeur de this (undefined sinon)
             ths._localisation = JSON.parse(s);
-            ths.paramService.updateLocalisation(ths._localisation);
         }
 
-        // let f: string = "app/calculators/cond_distri/cond_distri." + this.intlService.currentLanguage.tag + ".json"
-        let f: string = this.getConfigPathPrefix() + this.intlService.currentLanguage.tag + ".json"
+        let f: string = this.formulaireService.getConfigPathPrefix(this._calculatorType) + this.intlService.currentLanguage.tag + ".json"
         let resp: Observable<Response> = this.httpService.httpGetRequestResponse(undefined, undefined, undefined, f);
 
         let prom = resp.map(res => res.text()).toPromise();
@@ -77,6 +82,24 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
         return prom;
     }
 
+    private loadFormulaire(): Promise<FormulaireDefinition> {
+        if (this._formulaire == undefined) {
+            let prom = this.formulaireService.loadFormulaire(this._calculatorType);
+            prom.then(res => {
+                this._formulaire = res;
+            });
+            prom.then(
+                _ => this.loadLocalisation()
+            );
+            prom.then(
+                _ => this.formulaireService.updateLocalisation(this._localisation)
+            );
+
+            return prom;
+        }
+        return undefined;
+    }
+
     private logObject(obj: {}, m?: string) {
         // évite le message "Value below was evaluated just now" dans le debugger de Chrome
         if (m == undefined)
@@ -85,27 +108,67 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
             console.log(m + " " + JSON.stringify(obj));
     }
 
-    /**
-     * chaine préfixe pour le chargement de la config et de l'internationalisation
-     */
-    protected abstract getConfigPathPrefix(): string;
-
-    private loadConfig() {
-        let ths = this;
-        let processData = function (s: string) {
-            // fermeture nécessaire pour capturer la valeur de this (undefined sinon)
-            ths._formulaire.parseConfig(JSON.parse(s));
-            ths._formulaire.updateLanguage(ths._localisation);
+    /*
+    private getHtmlElementFromId_helper(elm: HTMLElement, id: string): HTMLElement {
+        if (elm.hasAttribute('id'))
+            if (elm.getAttribute('id') === id)
+                return elm;
+
+        let kids: NodeList = elm.childNodes;
+        for (let i = 0; i < kids.length; i++) {
+            let kid = kids[i];
+            if (kid instanceof HTMLElement) {
+                let e = this.getHtmlElementFromId_helper(<HTMLElement>kid, id);
+                if (e != undefined)
+                    return e;
+            }
         }
 
-        // let f: string = "app/calculators/cond_distri/cond_distri.config.json"
-        let f: string = this.getConfigPathPrefix() + "config.json"
-        this.httpService.httpGetRequest(undefined, undefined, undefined, f, processData);
+        return undefined;
+    }
+
+    private getHtmlElementFromId(id: string): HTMLElement {
+        let he: HTMLElement = this.elementRef.nativeElement;
+        return this.getHtmlElementFromId_helper(he, id);
+    }
+
+    private getHtmlElementValue(e: HTMLElement): string {
+        if (e instanceof HTMLSelectElement)
+            return e.value;
+        return undefined;
+    }
+    private setHtmlElementValue(e: HTMLElement, val: string) {
+        if (e instanceof HTMLInputElement)
+            e.value = val;
+    }
+    */
+
+    private applyDependencies() {
+        if (this._formulaire == undefined)
+            return;
+        this._formulaire.applyDependencies();
+
+        /*
+        for (let d of this._formulaire.dependencies) {
+            if (d instanceof ExistenceDependency) {
+            }
+            else if (d instanceof ValueDependency) {
+                let vd = <ValueDependency>d;
+                let master: HTMLElement = this.getHtmlElementFromId(d.masterElement.id);
+                if (this.getHtmlElementValue(master) == vd.masterValue) {
+                    let slave: HTMLElement = this.getHtmlElementFromId(d.slaveElement.id);
+                    this.setHtmlElementValue(slave, vd.slaveValue);
+                }
+            }
+        }
+        */
     }
 
     ngOnInit() {
-        this.loadLocalisation();
-        this.loadConfig();
+        let prom = this.loadFormulaire();
+        prom.then(
+            _ => this.applyDependencies()
+        );
     }
 
     ngDoCheck() {
@@ -116,13 +179,6 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
         //     q.maxValue = 6;
         //     q.stepValue = 0.3;
         // }
-
-        if (this.intlService.localeChanged) {
-            const promise = this.loadLocalisation()
-                .then(() => {
-                    this._formulaire.updateLanguage(this._localisation);
-                });
-        }
     }
 
     /*
@@ -181,24 +237,7 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
         //        this.changeDetectorRef.detectChanges();  // provoque une détection des changements dans les contrôles
     }
 
-
-
     protected getParameterValue(symbol: string): number {
-        // for (let fs of this._fieldSets) {
-        //     for (let p of fs.params) {
-        //         if (p instanceof NgParameter)
-        //             if (p.symbol === symbol) {
-        //                 switch (p.radioState) {
-        //                     case ParamRadioConfig.FIX:
-        //                         return p.v;
-
-        //                     case ParamRadioConfig.VAR:
-        //                     case ParamRadioConfig.CAL:
-        //                         return undefined;
-        //                 }
-        //             }
-        //     }
-        // }
         return this._formulaire.getParameterValue(symbol);
     }
 
@@ -211,30 +250,13 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
     }
 
     private addFixedResults(nDigits: number) {
-        // for (let fs of this._fieldSets) {
-        //     for (let p of fs.params) {
-        //         if (p instanceof NgParameter)
-        for (let p of this._formulaire.getInputParameters()) {
-            if (p.radioState == ParamRadioConfig.FIX && p.symbol !== "Pr") {
-                this.getCalculatorResultsComponent().addFixedResult(p, p.v, nDigits);
-            }
-            // }
-        }
+        for (let p of this._formulaire.getInputParameters())
+            if (p.radioState == ParamRadioConfig.FIX && p.symbol !== "Pr")
+                this.resultsComponent.addFixedResult(p, p.v, nDigits);
     }
 
-    protected abstract getNubAndParameters(): [Nub, IParamsEquation];
-
-    protected abstract getCalculatorResultsComponent(): CalculatorResultsComponent;
-
     private doCompute() {
-        // let Q: number = this.getParameterValue("Q"); // débit Q
-        // let D: number = this.getParameterValue("D"); // diamètre D
-        // let J: number = this.getParameterValue("J"); // perte de charge J
-        // let Lg: number = this.getParameterValue("Lg"); // Longueur de la conduite Lg
-        // let Nu: number = this.getParameterValue("Nu"); // Viscosité dynamique Nu
-        // let prms = new ConduiteDistribParams(Q, D, J, Lg, Nu);
-        // let nub = new ConduiteDistrib(prms);
-        let np: [Nub, IParamsEquation] = this.getNubAndParameters();
+        let np: [Nub, IParamsEquation] = this.formulaireService.getNubAndParameters(this._calculatorType);
         let nub: Nub = np[0];
         let prms: IParamsEquation = np[1];
 
@@ -245,22 +267,21 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
         let computedParam = this.getComputedParameter();
 
         let varParam = this.getVariatedParameter();
-        let resultsComponent: CalculatorResultsComponent = this.getCalculatorResultsComponent();
-        resultsComponent.reset(varParam == undefined);
+        this.resultsComponent.reset(varParam == undefined);
         if (varParam == undefined) {
             // pas de paramètre à varier
 
             let res = nub.Calc(computedParam.symbol, 0, prec).vCalc;
 
             this.addFixedResults(nDigits);
-            resultsComponent.addFixedResult(computedParam, res, nDigits);
+            this.resultsComponent.addFixedResult(computedParam, res, nDigits);
         }
         else {
             // il y a un paramètre à varier
 
             this.addFixedResults(nDigits);
-            resultsComponent.setVariableParamHeader(varParam);
-            resultsComponent.setVariableResultHeader(computedParam);
+            this.resultsComponent.setVariableParamHeader(varParam);
+            this.resultsComponent.setVariableResultHeader(computedParam);
 
             let min: number = +varParam.minValue;
             let max: number = +varParam.maxValue;
@@ -270,14 +291,14 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
                 prms[varParam.symbol].v = val;
 
                 let res = nub.Calc(computedParam.symbol, 0, prec).vCalc;
-                resultsComponent.addVarResult(val, res, nDigits);
+                this.resultsComponent.addVarResult(val, res, nDigits);
             }
             // for (let vr of this._varResults) {
             //     console.log(vr);
             // }
 
-            resultsComponent.setGraphTitle(computedParam.symbol + " = f( " + varParam.symbol + " )");
-            resultsComponent.generateGraph();
+            this.resultsComponent.setGraphTitle(computedParam.symbol + " = f( " + varParam.symbol + " )");
+            this.resultsComponent.generateGraph();
         }
         this._showResults = true;
     }
@@ -285,4 +306,21 @@ export abstract class GenericCalculatorComponent implements OnInit, DoCheck {
     private getResultsStyleDisplay() {
         return this._showResults ? "block" : "none";
     }
+
+    // interface Observer
+
+    update(data: any): void {
+        // message de InternationalisationService
+        const promise = this.loadLocalisation()
+            .then(() => {
+                this.formulaireService.updateLocalisation(this._localisation);
+            });
+    }
+
+    /**
+     * réception d'un événement d'un select
+     */
+    private onSelectChanged(val: string) {
+        this.applyDependencies();
+    }
 }
diff --git a/src/app/calculators/generic/formulaire.ts b/src/app/calculators/generic/formulaire.ts
index 626788aafbbcb20909ae3f9e61894037be190c3d..9831daf627e58e3f38fb8b4d7aa2828728812383 100644
--- a/src/app/calculators/generic/formulaire.ts
+++ b/src/app/calculators/generic/formulaire.ts
@@ -2,6 +2,11 @@ import { ParamDefinition } from 'jalhyd';
 
 import { NgParameter, ParamRadioConfig } from '../generic/ngparam';
 import { ParamService } from '../../services/param/param.service';
+import { StringMap } from '../../stringmap';
+
+export enum CalculatorType {
+    ConduiteDistributrice, LechaptCalmon
+}
 
 export class FormulaireDefinition {
     /**
@@ -18,7 +23,19 @@ export class FormulaireDefinition {
 
     private _dependencies: Dependency[] = [];
 
-    constructor(private paramService: ParamService) {
+    constructor(private paramService: ParamService, private _type: CalculatorType) {
+    }
+
+    public get type(): CalculatorType {
+        return this._type;
+    }
+
+    public get fieldSets(): FieldSet[] {
+        return this._fieldSets;
+    }
+
+    public get dependencies(): Dependency[] {
+        return this._dependencies;
     }
 
     private getFieldSet(id: string) {
@@ -116,13 +133,20 @@ export class FormulaireDefinition {
         return undefined;
     }
 
+    public getFieldById(id: string): Field {
+        let res = this.getFormulaireElementById(id);
+        if (res instanceof Field)
+            return res;
+        return undefined;
+    }
+
     private parse_value_dependencies(json: {}, slave: FormulaireElement) {
         for (let di in json) {
             let d = json[di];
             let refField: FormulaireElement = this.getFormulaireElementById(d["refid"]);
             if (refField != undefined) {
-                let refVal = d["refvalue"];
                 let dep = new ValueDependency(refField, slave);
+                dep.masterValue = d["refvalue"];
                 dep.slaveValue = d["value"];
                 this._dependencies.push(dep);
             }
@@ -154,32 +178,37 @@ export class FormulaireDefinition {
         }
     }
 
-    private parse_select(json: {}): SelectField {
-        let id = json["id"];
+    private parse_select(field: {}): SelectField {
+        let id = field["id"];
         let res: SelectField = new SelectField(id);
-        let values = json["select"];
-        for (let v of values)
-            res.addValue(v["id"]);
+        let values = field["select"];
+
+        for (let v of values) {
+            let e: SelectEntry = new SelectEntry(v["id"], undefined);
+            res.addEntry(e);
+        }
 
         return res;
     }
 
     private parse_input(fieldset: {}, field: {}): NgParameter {
         let input_id = field["id"];
-        let param: NgParameter = this.paramService.getParameter(input_id);
-        if (param != undefined) {
-            param.unit = field["unit"];
-            param.v = +field["value"];
-            param.radioConfig = NgParameter.getRadioConfig(fieldset["option"]);
-            param.radioState = ParamRadioConfig.FIX;
-            param.isDefault = false; // malgré le fait qu'il soit initialisé dans la déclaration de la classe NgParam à false, quand on relit sa valeur, il vaut undefined (merci Microsoft)
-            this.parse_dependencies(param, field);
+        let res: NgParameter = this.paramService.getParameter(input_id);
+        if (res != undefined) {
+            res.unit = field["unit"];
+            let val = field["value"];
+            if (val != undefined)
+                res.v = +val;
+            res.radioConfig = NgParameter.getRadioConfig(fieldset["option"]);
+            res.radioState = ParamRadioConfig.FIX;
+            res.isDefault = false; // malgré le fait qu'il soit initialisé dans la déclaration de la classe NgParam à false, quand on relit sa valeur, il vaut undefined (merci Microsoft)
         }
-        return param;
+        return res;
     }
 
-    private parse_fieldset(fieldset: {}, conf_id: string): FieldSet {
+    private parse_fieldset(fieldset: {}, conf_id: string) {
         let res: FieldSet = new FieldSet(conf_id);
+        this._fieldSets.push(res);
 
         let fields = fieldset["fields"];
         for (let field_index in fields) {
@@ -188,13 +217,13 @@ export class FormulaireDefinition {
                 let param = this.parse_input(fieldset, field);
                 if (param != undefined)
                     res.addField(param);
+                this.parse_dependencies(param, field);
             } else if (field["type"] === "select") {
                 let param = this.parse_select(field);
-                if (param != undefined)
-                    res.addField(param);
+                res.addField(param);
+                this.parse_dependencies(param, field);
             }
         }
-        return res;
     }
 
     public parseConfig(config: {}) {
@@ -209,10 +238,7 @@ export class FormulaireDefinition {
 
             // field set
             if (conf_id.startsWith("fs_")) {
-                let fieldSet: FieldSet = this.parse_fieldset(conf, conf_id);
-                if (fieldSet.fields.length > 0) {
-                    this._fieldSets.push(fieldSet);
-                }
+                this.parse_fieldset(conf, conf_id);
             }
             // options globales
             else if (conf_id === "options") {
@@ -225,39 +251,75 @@ export class FormulaireDefinition {
         }
     }
 
-    public updateLanguage(localisation: {}) {
-        for (let conf_index in this._config) {
-            let conf = this._config[conf_index];
-            let conf_id: string = conf["id"];
+     private getDependencyFromMasterValue(v: any): Dependency {
+        for (let d of this._dependencies)
+            if (d.masterValue === v)
+                return d;
+        return undefined;
+    }
 
-            if (conf_id.startsWith("fs_")) {
-                let fieldSet: FieldSet = this.getFieldSet(conf_id);
-                if (fieldSet != undefined)
-                    fieldSet.title = localisation[conf_id];
+    public applyDependencies() {
+        for (let d of this.dependencies) {
+            if (d instanceof ExistenceDependency) {
+            }
+            else if (d instanceof ValueDependency) {
+                let vd = <ValueDependency>d;
+                /*
+                let master: HTMLElement = this.getHtmlElementFromId(d.masterElement.id);
+                if (this.getHtmlElementValue(master) == vd.masterValue) {
+                    let slave: HTMLElement = this.getHtmlElementFromId(d.slaveElement.id);
+                    this.setHtmlElementValue(slave, vd.slaveValue);
+                }
+                */
+                let master = this.getFieldById(d.masterElement.id);
+                if (master.getValue() == vd.masterValue) {
+                    let slave = this.getFieldById(d.slaveElement.id);
+                    slave.setValue(vd.slaveValue);
+                }
             }
         }
     }
 }
 
-abstract class FormulaireElement {
+export abstract class FormulaireElement {
     private _id: string;
     private _isDisplayed: boolean;
+    public label: string;
 
     constructor(id: string) {
         this._id = id;
         this._isDisplayed = true;
     }
 
-    get id() {
+    get id(): string {
         return this._id;
     }
+
+    public abstract updateLocalisation(loc: StringMap): void;
+}
+
+export enum FieldType {
+    Input, Select
 }
 
 export abstract class Field extends FormulaireElement {
+    constructor(id: string, private _type: FieldType) {
+        super(id);
+    }
+
+    public get isInput(): boolean {
+        return this._type == FieldType.Input;
+    }
+
+    public get isSelect(): boolean {
+        return this._type == FieldType.Select;
+    }
+
+    public abstract getValue(): any;
+    public abstract setValue(val: any): void;
 }
 
 export class FieldSet extends FormulaireElement {
-    title: string;
     private _fields: Field[];
 
     constructor(id: string) {
@@ -273,8 +335,11 @@ export class FieldSet extends FormulaireElement {
         this._fields.push(f);
     }
 
-    public get isEmpty(): boolean {
-        return this._fields.length == 0;
+    public get hasInputs(): boolean {
+        for (let f of this._fields)
+            if (f instanceof NgParameter)
+                return true;
+        return false;
     }
 
     public getInput(i: number): NgParameter {
@@ -288,24 +353,91 @@ export class FieldSet extends FormulaireElement {
         }
         return undefined;
     }
+
+    public updateLocalisation(loc: StringMap) {
+        this.label = loc[this.id];
+    }
+}
+
+export class SelectEntry {
+    private _value: string;
+    public label: string;
+
+    constructor(v: string, l: string) {
+        this._value = v;
+        this.label = l;
+    }
+
+    get value(): string {
+        return this._value;
+    }
 }
 
 export class SelectField extends Field {
-    private _values: string[];
+    private _entries: SelectEntry[];
+
+    public selectedEntry: SelectEntry;
+
+    public get entries() {
+        return this._entries;
+    }
+
+    constructor(id: string) {
+        super(id, FieldType.Select);
+        this._entries = [];
+    }
+
+    public addEntry(e: SelectEntry) {
+        this._entries.push(e);
+        if (this.selectedEntry == undefined)
+            this.selectedEntry = e;
+    }
+
+    public getValue() {
+        if (this.selectedEntry == undefined)
+            return undefined;
+        return this.selectedEntry.value;
+    }
+
+    public setValue(val: string) {
+        for (let e of this._entries)
+            if (e.value === val) {
+                this.selectedEntry = e;
+                return;
+            }
+    }
+
+    public updateLocalisation(loc: StringMap) {
+        this.label = loc[this.id];
+        for (let e of this._entries) {
+            e.label = loc[e.value];
+        }
+    }
+}
+
+export class InputField extends Field {
+    private _value: any;
 
     constructor(id: string) {
-        super(id)
-        this._values = [];
+        super(id, FieldType.Input);
+    }
+
+    public getValue() {
+        return this._value;
+    }
+
+    public setValue(val: any) {
+        this._value = val;
     }
 
-    public addValue(value: string) {
-        this._values.push(value);
+    public updateLocalisation(loc: StringMap) {
+        this.label = loc[this.id];
     }
 }
 
-abstract class Dependency {
+export abstract class Dependency {
     private _master: FormulaireElement;
-    private _masterValue: any;
+    public masterValue: any;
 
     private _slave: FormulaireElement;
 
@@ -313,6 +445,14 @@ abstract class Dependency {
         this._master = m;
         this._slave = s;
     }
+
+    public get masterElement(): FormulaireElement {
+        return this._master;
+    }
+
+    public get slaveElement(): FormulaireElement {
+        return this._slave;
+    }
 }
 
 export class ValueDependency extends Dependency {
diff --git a/src/app/calculators/generic/ngparam.ts b/src/app/calculators/generic/ngparam.ts
index 889c0bf1f8e2af0b864ab201fed66fb6ad299fe1..c68dbe4e59196d0a6933cd9ee5cc14b3335fab7a 100644
--- a/src/app/calculators/generic/ngparam.ts
+++ b/src/app/calculators/generic/ngparam.ts
@@ -1,6 +1,7 @@
 import { ParamDefinition, ParamDomainValue, ErrorMessage } from 'jalhyd';
 
-import { Field } from './formulaire';
+import { InputField } from './formulaire';
+import { StringMap } from '../../stringmap';
 
 export enum ParamRadioConfig {
     /**
@@ -22,9 +23,8 @@ export enum ParamRadioConfig {
 /**
  * class englobante de ParamDefinition (champs supplémentaires pour l'affichage, radio boutons, ...)
  */
-export class NgParameter extends Field {
+export class NgParameter extends InputField {
     public unit: string;
-    public label: string;
     public radioConfig: ParamRadioConfig;
     public radioState: ParamRadioConfig;
     public isDefault: boolean = false; // archi bug du langage ! si on relit cette propriété sans l'avoir modifiée entre-temps, elle vaut undefined !
@@ -69,6 +69,14 @@ export class NgParameter extends Field {
         this._paramDef.v = val;
     }
 
+    public getValue() {
+        return this.v;
+    }
+
+    public setValue(val: number) {
+        this.v = val;
+    }
+
     get isDefined(): boolean {
         return this._paramDef.isDefined;
     }
@@ -89,4 +97,9 @@ export class NgParameter extends Field {
 
         throw "invalid parameter radio configuration " + s;
     }
+
+
+    public updateLocalisation(loc: StringMap) {
+        this.label = loc[this.id];
+    }
 }
diff --git a/src/app/calculators/lechapt-calmon/lechapt-calmon.en.json b/src/app/calculators/lechapt-calmon/lechapt-calmon.en.json
index 372fff647c2cf4372aef6d6fcd9e55fd35d9a506..983b3941249649334ce353338a0d453194f6e953 100644
--- a/src/app/calculators/lechapt-calmon/lechapt-calmon.en.json
+++ b/src/app/calculators/lechapt-calmon/lechapt-calmon.en.json
@@ -1,10 +1,20 @@
 {
+    "fs_materiau": "Type of material",
+    "select_material": "Choice of material",
+    "select_material_1": "Unlined cast iron - Coarse concrete (corrosive water)",
+    "select_material_2": "Cast steel or uncoated - Coarse concrete (somewhat corrosive water)",
+    "select_material_3": "Cast steel or cement coating",
+    "select_material_4": "Cast iron or steel coating bitumen - Centrifuged concrete ",
+    "select_material_5": "Rolled steel - Smooth concrete",
+    "select_material_6": "Cast iron or steel coating centrifuged",
+    "select_material_7": "PVC - Polyethylene",
+    "select_material_8": "Hydraulically smooth pipe - 0.05 ≤ D ≤ 0.2",
+    "select_material_9": "Hydraulically smooth pipe - 0.25 ≤ D ≤ 1",
     "fs_hydraulique": "Hydraulic features",
     "Q": "Flow",
     "D": "Pipe diameter",
     "J": "Head drop",
     "Lg": "Pipe length",
-    "Nu": "Dynamic (shear) viscosity",
     "fs_param_calc": "Calculation parameters",
     "Pr": "Display accuracy"
 }
\ No newline at end of file
diff --git a/src/app/calculators/lechapt-calmon/lechaptcalmon.component.html b/src/app/calculators/lechapt-calmon/lechaptcalmon.component.html
index 3a9b25a4b0067ed2bf1e7081b3491f2c28b87a77..00f365ed7710863691ab0caba7d3d1612623b98e 100644
--- a/src/app/calculators/lechapt-calmon/lechaptcalmon.component.html
+++ b/src/app/calculators/lechapt-calmon/lechaptcalmon.component.html
@@ -1,7 +1,10 @@
 <h1>Lechapt-Calmon</h1>
+<hydrocalc type="LechaptCalmon"></hydrocalc>
+<!--
 <field-set *ngFor="let fs of _fieldSets" [fieldSet]=fs (onRadio)=onRadioClick($event)></field-set>
 
 <div style="text-align:center;">
     <button type="button" class="button_compute" name="Calculer" (click)="doCompute()" i18n="@@hyd_compute">Calculer</button>
 </div>
-<calc-results [style.display]="getResultsStyleDisplay()"></calc-results>
\ No newline at end of file
+<calc-results [style.display]="getResultsStyleDisplay()"></calc-results>
+-->
\ No newline at end of file
diff --git a/src/app/calculators/lechapt-calmon/lechaptcalmon.component.ts b/src/app/calculators/lechapt-calmon/lechaptcalmon.component.ts
index 4576a420059c17adc1b82b75985521afd7cf1a3e..811e4d247fe4f6ffe16ac02d6f57f254bacf4449 100644
--- a/src/app/calculators/lechapt-calmon/lechaptcalmon.component.ts
+++ b/src/app/calculators/lechapt-calmon/lechaptcalmon.component.ts
@@ -1,57 +1,8 @@
-import { Component, ViewChild } from '@angular/core';
-
-//import { ConduiteDistrib, ConduiteDistribParams } from "jalhyd";
-import { IParamsEquation, Nub, LechaptCalmon, LechaptCalmonParams } from "jalhyd";
-
-import { ParamService } from '../../services/param/param.service';
-import { HttpService } from '../../services/http/http.service';
-import { InternationalisationService } from '../../services/internationalisation/internationalisation.service';
-import { GenericCalculatorComponent } from '../generic/calculator.component';
-import { CalculatorResultsComponent } from '../../components/calculator-results/calculator-results.component';
-
+import { Component } from '@angular/core';
 
 @Component({
     selector: 'lechapt-calmon',
-    templateUrl: "./lechaptcalmon.component.html",
-    styles: [`
-    .button_compute {
-        height: 3em;
-        width: 30%;
-    }
-    `
-    ]
+    templateUrl: "./lechaptcalmon.component.html"
 })
-export class LechaptCalmonComponent extends GenericCalculatorComponent {
-    /**
-     * composant d'affichage des résultats
-     */
-    @ViewChild(CalculatorResultsComponent)
-    private resultsComponent: CalculatorResultsComponent;
-
-    constructor(private paramSrv: ParamService, private httpSrv: HttpService, private intlSrv: InternationalisationService) {
-        super(paramSrv, httpSrv, intlSrv);
-    }
-
-    protected getConfigPathPrefix(): string {
-        return "app/calculators/lechapt-calmon/lechapt-calmon."
-    }
-
-    protected getNubAndParameters(): [Nub, IParamsEquation] {
-        let Q: number = this.getParameterValue("Q"); // débit Q
-        let D: number = this.getParameterValue("D"); // diamètre D
-        let J: number = this.getParameterValue("J"); // perte de charge J
-        let Lg: number = this.getParameterValue("Lg"); // Longueur de la conduite Lg
-        let L: number = this.getParameterValue("L"); // paramètre de matériau 1
-        let M: number = this.getParameterValue("M"); // paramètre de matériau 2
-        let N: number = this.getParameterValue("N"); // paramètre de matériau 3
-
-        let prms = new LechaptCalmonParams(Q, D, J, Lg, L, M, N);
-        let nub = new LechaptCalmon(prms);
-
-        return [nub, prms];
-    }
-
-    protected getCalculatorResultsComponent(): CalculatorResultsComponent {
-        return this.resultsComponent;
-    }
+export class LechaptCalmonComponent {
 }
diff --git a/src/app/components/field-set/field-set.component.ts b/src/app/components/field-set/field-set.component.ts
index a25b1fe667a4079805641f6ab8c42832d89a303a..095ffe9d65a2a2be688416c45e6ca479c43d4e8a 100644
--- a/src/app/components/field-set/field-set.component.ts
+++ b/src/app/components/field-set/field-set.component.ts
@@ -34,7 +34,7 @@ export class FieldSetComponent {
     }
 
     private hasRadioFix(): boolean {
-        if (!this._fieldSet.isEmpty)
+        if (this._fieldSet.hasInputs)
             switch (this._fieldSet.getInput(0).radioConfig) {
                 case ParamRadioConfig.FIX:
                     return false;
@@ -46,7 +46,7 @@ export class FieldSetComponent {
     }
 
     private hasRadioVar(): boolean {
-        if (!this._fieldSet.isEmpty)
+        if (this._fieldSet.hasInputs)
             switch (this._fieldSet.getInput(0).radioConfig) {
                 case ParamRadioConfig.VAR:
                 case ParamRadioConfig.CAL:
@@ -59,7 +59,7 @@ export class FieldSetComponent {
     }
 
     private hasRadioCal(): boolean {
-        if (!this._fieldSet.isEmpty)
+        if (this._fieldSet.hasInputs)
             switch (this._fieldSet.getInput(0).radioConfig) {
                 case ParamRadioConfig.CAL:
                     return true;
@@ -83,4 +83,15 @@ export class FieldSetComponent {
 
     @Output()
     private onRadio = new EventEmitter<string>();
+
+    /**
+     * réception d'un événement d'un select
+     */
+    private onSelectChanged(val: string) {
+        //console.log("fieldset " + val);
+        this.onSelectChange.emit(val); // on transmet au parent
+    }
+
+    @Output()
+    private onSelectChange = new EventEmitter<string>();
 }
diff --git a/src/app/components/field-set/field-set.html b/src/app/components/field-set/field-set.html
index 2fd8f7e514dac78c81bd6e58d57aeca19e908508..35773c06589d16196e2834a173e26df5289bd1b7 100644
--- a/src/app/components/field-set/field-set.html
+++ b/src/app/components/field-set/field-set.html
@@ -1,7 +1,7 @@
 <table>
     <tr id="tr_type_section_title">
         <td colspan="5">
-            <div class="fieldset_title">{{_fieldSet.title}}</div>
+            <div class="fieldset_title">{{_fieldSet.label}}</div>
         </td>
     </tr>
     <tr id="tr_fs_hydraulique_header">
@@ -10,9 +10,12 @@
         <td *ngIf="hasRadioVar()" align="center" class="radio_param_header" i18n="@@radio_param_header_var">Paramètre à varier</td>
         <td *ngIf="hasRadioCal()" align="center" class="radio_param_header" i18n="@@radio_param_header_cal">Paramètre à calculer</td>
     </tr>
-    <tr id="tr_type_section_fs" *ngFor="let p of _fieldSet.params">
-        <td colspan="5">
+    <tr id="tr_type_section_fs" *ngFor="let p of _fieldSet.fields">
+        <td *ngIf="p.isInput" colspan="5">
             <param-field-line [symbol]=p.symbol (onRadio)=onRadioClick($event)></param-field-line>
         </td>
+        <td *ngIf="p.isSelect" colspan="5">
+            <select-field-line [id]=p.id (onSelectChange)=onSelectChanged($event)></select-field-line>
+        </td>
     </tr>
-</table>
+</table>
\ No newline at end of file
diff --git a/src/app/components/param-field-line/param-field-line.component.ts b/src/app/components/param-field-line/param-field-line.component.ts
index c17289fded2fc87bc8e6b1e1f4c60cf266478f9d..65682d61f188e14ee2e9261e57b59090542c3c4a 100644
--- a/src/app/components/param-field-line/param-field-line.component.ts
+++ b/src/app/components/param-field-line/param-field-line.component.ts
@@ -19,26 +19,19 @@ import { NgParameter, ParamRadioConfig } from '../../calculators/generic/ngparam
         }`
     ]
 })
-export class ParamFieldLineComponent implements DoCheck {
+export class ParamFieldLineComponent {
     private _param: NgParameter;
 
     constructor(private paramService: ParamService) {
     }
 
-    /**
-     * associated (localised) label
-     */
-    private _label: string;
-
-    /**
-     * associated unit
-     */
-    get _unit(): string {
-        return this._param.unit;
-    }
-
-    private updateLanguage() {
-        this._label = this._param.label;
+    private get title(): string {
+        let t = "";
+        if (this._param.label != undefined)
+            t = this._param.label;
+        if (this._param.unit != undefined && this._param.unit != "")
+            t = t + " (" + this._param.unit + ")";
+        return t;
     }
 
     /**
@@ -47,7 +40,6 @@ export class ParamFieldLineComponent implements DoCheck {
     @Input()
     private set symbol(s: string) {
         this._param = this.paramService.getParameter(s);
-        this.updateLanguage();
     }
 
     /**
@@ -57,10 +49,6 @@ export class ParamFieldLineComponent implements DoCheck {
         return this._param.symbol;
     }
 
-    public ngDoCheck() {
-        this.updateLanguage();
-    }
-
     /**
      * calcule la présence du radio "paramètre fixé"
      */
diff --git a/src/app/components/param-field-line/param-field-line.html b/src/app/components/param-field-line/param-field-line.html
index a3fc4efb44c58abfa7a2292135b182fd2c4363d7..162c64fc2911242e122d5daf0113f3de839a8c82 100644
--- a/src/app/components/param-field-line/param-field-line.html
+++ b/src/app/components/param-field-line/param-field-line.html
@@ -1,5 +1,5 @@
 <tr id="tr_FT_rLargeurFond">
-    <td align="right" class="param_title">{{_label}} ({{_unit}})</td>
+    <td align="right" class="param_title">{{title}}</td>
 
     <td>
         <!--
diff --git a/src/app/components/param-input/param-input.component.html b/src/app/components/param-input/param-input.component.html
index 5d2fedc79879a2908425cb0fb2b55dbb59867aa0..b19228b74230109a610738d7474d1246b8fcca28 100644
--- a/src/app/components/param-input/param-input.component.html
+++ b/src/app/components/param-input/param-input.component.html
@@ -4,16 +4,13 @@ i18n="<meaning>|<description>@@<custom id>"
 <p i18n="titre saisie|Titre du contrôle de saisie de paramètre@@titre_saisie_param">Saisie de paramètre</p>
 -->
 <p *ngIf="displayTitle" i18n="@@titre_saisie_param">Saisie de paramètre</p>
+<input placeholder="{{_paramDef.symbol}}" [ngModel]="_uiValue.uncheckedValueString" (ngModelChange)="setValue($event)" />
+<br/> {{_message}}
+<!--
+<p *ngIf="displayTitle" i18n="@@titre_saisie_param">Saisie de paramètre</p>
 <md-input-container>
     <input mdInput placeholder="{{_paramDef.symbol}}" [ngModel]="_uiValue.uncheckedValueString" (ngModelChange)="setValue($event)"
     />
     <md-hint>{{_message}}</md-hint>
 </md-input-container>
-<!--
-    <md-error *ngIf="_message">
-        {{_message}}
-    </md-error>
-    <input mdInput placeholder="{{_paramDef.symbol}}" [ngModel]="getValue()" (ngModelChange)="setValue($event)" />
-    <md-error *ngIf="hasError()">
-    <md-hint *ngIf="hasError()">{{_message}}</md-hint>
 -->
\ No newline at end of file
diff --git a/src/app/components/param-input/param-input.component.ts b/src/app/components/param-input/param-input.component.ts
index 60ac6f369f9e6db8392a13707d6c53a8a2b52f9f..9ea37e20db37fbed1809fb7fd363e59639bc64e6 100644
--- a/src/app/components/param-input/param-input.component.ts
+++ b/src/app/components/param-input/param-input.component.ts
@@ -43,10 +43,6 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
 
     private _message: string;
 
-    private static _idGen: number = 0; // A VIRER
-    private _id: number; // A VIRER
-    private static _startTime: number;  // A VIRER
-
     /**
      * flag d'affichage du titre
      */
@@ -65,10 +61,6 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
     private _uiValue: NumericalString;
 
     constructor(private paramService: ParamService, private changeDetector: ChangeDetectorRef, private intlService: InternationalisationService) {
-        this._id = ParamInputComponent._idGen++;
-        if (ParamInputComponent._startTime == undefined)
-            ParamInputComponent._startTime = new Date().getTime();
-
         this._uiValue = new NumericalString();
     }
 
@@ -101,14 +93,6 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
         this._paramDef = this.paramService.getParameter(this._paramSymbol);
     }
 
-    // private getValue() {
-    //     if (this._paramDef.isDefined)
-    //         return this._paramDef.v;
-    //     return "";
-
-    //     // return this._uiValue.value;
-    // }
-
     /**
      * fonction appelée lorsque l'utilisateur fait une saisie
      * @param event valeur du contrôle
@@ -207,10 +191,9 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
         return null;
     }
 
-    private log(m: string) {
-        let t: number = new Date().getTime() - ParamInputComponent._startTime;
-        console.log("ParamInputComponent(" + this._id + ") " + t + " : " + m);
-    }
+    // private log(m: string) {
+    //     console.log("ParamInputComponent(" + this._id + ") : " + m);
+    // }
 
     // ControlValueAccessor interface
 
@@ -225,7 +208,7 @@ export class ParamInputComponent implements ControlValueAccessor, OnInit, DoChec
     }
     */
     writeValue(value: any) {
-        this.log("writeValue " + value);
+        // this.log("writeValue " + value);
     }
 
     registerOnChange(fn: any) {
diff --git a/src/app/components/select-field-line/select-field-line.component.ts b/src/app/components/select-field-line/select-field-line.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4a2a11f4ad4aba34ab0226aa58a7fc6db628606a
--- /dev/null
+++ b/src/app/components/select-field-line/select-field-line.component.ts
@@ -0,0 +1,50 @@
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+
+import { SelectField, SelectEntry } from '../../calculators/generic/formulaire';
+import { FormulaireService } from '../../services/formulaire/formulaire.service';
+
+@Component({
+    selector: 'select-field-line',
+    templateUrl: "./select-field-line.html",
+})
+export class SelectFieldLineComponent {
+    private _select: SelectField;
+
+    private currentValue: string;
+
+    constructor(private formulaireService: FormulaireService) {
+    }
+
+    private get entries(): SelectEntry[] {
+        return this._select.entries;
+    }
+
+    /**
+    * id input attribute
+    */
+    private _id: string;
+
+    @Input()
+    private set id(s: string) {
+        this._id = s;
+        this.updateSelect();
+    }
+
+    /**
+     * selected value event
+     */
+    @Output()
+    private onSelectChange = new EventEmitter<string>();
+
+    private updateSelect() {
+        this._select = this.formulaireService.getSelectField(this._id);
+        if (this._select.selectedEntry != undefined)
+            this.currentValue = this._select.selectedEntry.value;
+    }
+
+    private onSelect(event: any) {
+        let val = event.target.value;
+        this._select.setValue(val);
+        this.onSelectChange.emit(val);
+    }
+}
diff --git a/src/app/components/select-field-line/select-field-line.html b/src/app/components/select-field-line/select-field-line.html
new file mode 100644
index 0000000000000000000000000000000000000000..9041cd7264cd0cf3402db3ff1632b6a345886827
--- /dev/null
+++ b/src/app/components/select-field-line/select-field-line.html
@@ -0,0 +1,8 @@
+<tr>
+    <td align="right">{{_select.label}}</td>
+    <td colspan="3">
+        <select [(ngModel)]=currentValue (change)=onSelect($event)>
+    <option *ngFor="let e of entries" [value]=e.value>{{e.label}}</option>
+</select>
+    </td>
+</tr>
\ No newline at end of file
diff --git a/src/app/services/formulaire/formulaire.service.ts b/src/app/services/formulaire/formulaire.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90925ed388a864e46b433c9d7a0720f7d3d7f411
--- /dev/null
+++ b/src/app/services/formulaire/formulaire.service.ts
@@ -0,0 +1,130 @@
+import { Injectable } from '@angular/core';
+import { Response } from '@angular/http';
+
+import { IParamsEquation, Nub, ConduiteDistrib, ConduiteDistribParams, LechaptCalmon, LechaptCalmonParams } from "jalhyd";
+
+import { ParamService } from '../param/param.service';
+import { HttpService } from '../../services/http/http.service';
+import { FormulaireDefinition, FormulaireElement, CalculatorType, SelectField } from '../../calculators/generic/formulaire';
+import { StringMap } from '../../stringmap';
+
+@Injectable()
+export class FormulaireService {
+    private _formulaires: FormulaireDefinition[];
+
+    constructor(private paramService: ParamService, private httpService: HttpService) {
+        this._formulaires = [];
+    }
+
+    private loadConfig(form: FormulaireDefinition, ct: CalculatorType): Promise<Response> {
+        let processData = function (s: string) {
+            form.parseConfig(JSON.parse(s));
+        }
+
+        let f: string = this.getConfigPathPrefix(ct) + "config.json"
+        return this.httpService.httpGetRequest(undefined, undefined, undefined, f, processData);
+    }
+
+    public loadFormulaire(ct: CalculatorType): Promise<FormulaireDefinition> {
+        if (ct == undefined)
+            throw "FormulaireService.getFormulaire() : invalid undefined CalculatorType"
+
+        let f = new FormulaireDefinition(this.paramService, ct);
+        this._formulaires.push(f);
+        let pr: Promise<FormulaireDefinition> = this.loadConfig(f, ct)
+            .then(res => {
+                return f;
+            });
+        return pr;
+    }
+
+    private getFormulaire(ct: CalculatorType): FormulaireDefinition {
+        if (ct == undefined)
+            throw "FormulaireService.getFormulaire() : invalid undefined CalculatorType"
+
+        for (let f of this._formulaires) {
+            if (f.type == ct)
+                return f;
+        }
+
+        throw "FormulaireService.getFormulaire() : type '" + ct + "' form is not loaded";
+    }
+
+    private getFormulaireElementById(id: string): FormulaireElement {
+        for (let f of this._formulaires) {
+            let s = f.getFormulaireElementById(id);
+            if (s != undefined)
+                return s;
+        }
+        return undefined;
+    }
+
+    public getSelectField(id: string): SelectField {
+        for (let f of this._formulaires) {
+            let s = f.getFormulaireElementById(id);
+            if (s != undefined)
+                if (!(s instanceof SelectField))
+                    throw "Form element with id '" + id + "' is not a select";
+            return <SelectField>s;
+        }
+        return undefined;
+    }
+
+    public updateLocalisation(localisation: StringMap) {
+        for (let loc_id in localisation) {
+            let fe = this.getFormulaireElementById(loc_id);
+            if (fe != undefined)
+                fe.updateLocalisation(localisation);
+        }
+    }
+
+    public getNubAndParameters(ct: CalculatorType): [Nub, IParamsEquation] {
+        let f = this.getFormulaire(ct);
+        switch (ct) {
+            case CalculatorType.ConduiteDistributrice:
+                {
+                    let Q: number = f.getParameterValue("Q"); // débit Q
+                    let D: number = f.getParameterValue("D"); // diamètre D
+                    let J: number = f.getParameterValue("J"); // perte de charge J
+                    let Lg: number = f.getParameterValue("Lg"); // Longueur de la conduite Lg
+                    let Nu: number = f.getParameterValue("Nu"); // viscosité dynamique 
+                    let prms = new ConduiteDistribParams(Q, D, J, Lg, Nu);
+                    let nub = new ConduiteDistrib(prms);
+                    return [nub, prms];
+                }
+
+            case CalculatorType.LechaptCalmon:
+                {
+                    let Q: number = f.getParameterValue("Q"); // débit Q
+                    let D: number = f.getParameterValue("D"); // diamètre D
+                    let J: number = f.getParameterValue("J"); // perte de charge J
+                    let Lg: number = f.getParameterValue("Lg"); // Longueur de la conduite Lg
+                    let L: number = f.getParameterValue("L"); // paramètre de matériau 1
+                    let M: number = f.getParameterValue("M"); // paramètre de matériau 2
+                    let N: number = f.getParameterValue("N"); // paramètre de matériau 3
+                    let prms = new LechaptCalmonParams(Q, D, J, Lg, L, M, N);
+                    let nub = new LechaptCalmon(prms);
+                    return [nub, prms];
+                }
+
+            default:
+                throw "FormulaireService.getNubAndParameters() : valeur de CalculatorType " + ct + " non implémentée"
+        }
+    }
+
+    public getConfigPathPrefix(ct: CalculatorType): string {
+        if (ct == undefined)
+            throw "FormulaireService.getConfigPathPrefix() : invalid undefined CalculatorType"
+
+        switch (ct) {
+            case CalculatorType.ConduiteDistributrice:
+                return "app/calculators/cond_distri/cond_distri.";
+
+            case CalculatorType.LechaptCalmon:
+                return "app/calculators/lechapt-calmon/lechapt-calmon.";
+
+            default:
+                throw "FormulaireService.getConfigPathPrefix() : valeur de CalculatorType " + ct + " non implémentée"
+        }
+    }
+}
diff --git a/src/app/services/http/http.service.ts b/src/app/services/http/http.service.ts
index ecc167c565738ea0dbc5e9b2806682babcd7ec30..1c1556acdff8368477d415a41407d7133509d913 100644
--- a/src/app/services/http/http.service.ts
+++ b/src/app/services/http/http.service.ts
@@ -17,7 +17,7 @@ export class HttpService {
         return s1 + s2;
     }
 
-    public httpGetRequest(protocol: string, host: string, port: number, path: string, processDataCallback: (s: string) => void) {
+    public httpGetRequest(protocol: string, host: string, port: number, path: string, processDataCallback: (s: string) => void): Promise<Response> {
         let resp: Observable<Response> = this.httpGetRequestResponse(protocol, host, port, path);
 
         resp.map(res => res.text())
@@ -26,6 +26,8 @@ export class HttpService {
             //            err => this.logError(err),
             //            () => console.log('Random Quote Complete')
         );
+
+        return resp.toPromise();
     }
 
     public httpGetRequestResponse(protocol: string, host: string, port: number, path: string): Observable<Response> {
diff --git a/src/app/services/internationalisation/internationalisation.service.ts b/src/app/services/internationalisation/internationalisation.service.ts
index 7cfef31390f96f29170152fdc8382c0381c4890a..f17f03aa7e2de02c6ca607952f37aeaed39515c8 100644
--- a/src/app/services/internationalisation/internationalisation.service.ts
+++ b/src/app/services/internationalisation/internationalisation.service.ts
@@ -1,8 +1,11 @@
 import { Injectable } from '@angular/core';
+import { Response } from '@angular/http';
 
 import { ErrorMessage, ErrorCode } from "jalhyd";
 
 import { HttpService } from "../http/http.service";
+import { Observable } from "../observer";
+import { StringMap } from "../../stringmap";
 
 /*
   language tag : fr-FR
@@ -41,19 +44,15 @@ export class Language {
 }
 
 @Injectable()
-export class InternationalisationService {
+export class InternationalisationService extends Observable {
     private _currLang: Language;
     private _sLang: string;
-    private _errorMessages: { [key: string]: string };
+    private _errorMessages: StringMap;
 
     private _languages: Language[];
 
-    /**
-     * indique que la langue a été changée
-     */
-    private _localeChanged: boolean = false;
-
     public constructor(private httpService: HttpService) {
+        super();
         this._languages = [];
         this._languages.push(new Language(LanguageCode.FRENCH, "fr", "Français"));
         this._languages.push(new Language(LanguageCode.ENGLISH, "en", "English"));
@@ -96,30 +95,14 @@ export class InternationalisationService {
         else {
             this._currLang = this.getLanguageFromCode(lng);
         }
-        this._localeChanged = this._currLang.code != oldLang;
-
 
-        // this.loadErrorMessages();
-        this.httpGetErrorMessages();
+        let prom = this.httpGetErrorMessages();
+        prom.then((res) => {
+            this.notifyObservers(undefined);
+        })
     }
 
-    // private loadErrorMessages() {
-    //     let l;
-    //     switch (this.lang) {
-    //         case Language.FRENCH:
-    //             l = "fr";
-    //             break;
-
-    //         default:
-    //             l = "en";
-    //     }
-
-    //     let s: string = fs.readFileSync("src/error_messages." + l + ".json", "utf8");
-    //     this._errorMessages = JSON.parse(s);
-    // }
-
-
-    private httpGetErrorMessages() {
+    private httpGetErrorMessages(): Promise<Response> {
         let is: InternationalisationService = this;
         let processData = function (s: string) {
             // fermeture nécessaire pour capturer la valeur de this (undefined sinon)
@@ -137,7 +120,7 @@ export class InternationalisationService {
         }
 
         let f: string = "error_messages." + l + ".json"
-        this.httpService.httpGetRequest(undefined, undefined, undefined, "locale/" + f, processData);
+        return this.httpService.httpGetRequest(undefined, undefined, undefined, "locale/" + f, processData);
     }
 
     private getErrorMessageFromCode(c: ErrorCode): string {
@@ -159,12 +142,4 @@ export class InternationalisationService {
 
         return m;
     }
-
-    get localeChanged() {
-        return this._localeChanged;
-    }
-
-    public acknowledgeLocaleChanged() {
-        this._localeChanged = false;
-    }
 }
diff --git a/src/app/services/param/param.service.ts b/src/app/services/param/param.service.ts
index 935cc3f8acb0f336052550920df497181d8555ee..64ca6dfe9aea3c058d78570a65f3ee501fa4637d 100644
--- a/src/app/services/param/param.service.ts
+++ b/src/app/services/param/param.service.ts
@@ -15,6 +15,7 @@ export class ParamService {
         this._params.push(new NgParameter(pr));
 
         this.addParameters("cond_distri");
+        this.addParameters("lechapt_calmon");
     }
 
     private hasParameter(symbol: string): boolean {
@@ -44,7 +45,7 @@ export class ParamService {
         }
     }
 
-    getParameter(s: string): NgParameter {
+    public getParameter(s: string): NgParameter {
         for (let p of this._params) {
             if (p.symbol == s)
                 return p;
@@ -52,12 +53,4 @@ export class ParamService {
 
         return undefined;
     }
-
-    updateLocalisation(loc: { [key: string]: string }) {
-        for (let ki in loc) {
-            let p = this.getParameter(ki);
-            if (p != undefined)
-                p.label = loc[ki];
-        }
-    }
 }
diff --git a/src/app/stringmap.ts b/src/app/stringmap.ts
new file mode 100644
index 0000000000000000000000000000000000000000..75efb4f15d5c6ca34994fb3bb7af3540e4c1ca0a
--- /dev/null
+++ b/src/app/stringmap.ts
@@ -0,0 +1,3 @@
+export interface StringMap {
+    [key: string]: string;
+}