diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index f308e323b7a817c5a79c476d4c70dd39426feb69..364b60d6bb4fc01efd71b9bfa8118c79fa03961d 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -44,839 +44,839 @@ declare let cordova: any;
 declare let device: any;
 
 @Component({
-  selector: "nghyd-app",
-  templateUrl: "./app.component.html",
-  styleUrls: ["./app.component.scss"],
-  providers: [ErrorService]
+    selector: "nghyd-app",
+    templateUrl: "./app.component.html",
+    styleUrls: ["./app.component.scss"],
+    providers: [ErrorService]
 })
 export class AppComponent implements OnInit, OnDestroy, Observer {
 
-  @ViewChild("sidenav")
-  public sidenav: MatSidenav;
-
-  @ViewChild("navbar")
-  public navbar: MatToolbar;
-
-  /** current calculator, inferred from _currentFormId by setActiveCalc() (used for navbar menu) */
-  public currentCalc: any;
-
-  /** shows or hides the progressbar under the navbar */
-  public showProgressBar = false;
-
-  /** liste des modules de calcul ouverts */
-  private _calculators: Array<{
-    title: string,
-    type: CalculatorType,
-    uid: string,
-    active?: boolean,
-    latestAnchor?: string
-  }> = [];
-
-  /**
-   * id du formulaire courant
-   * on utilise pas directement FormulaireService.currentFormId pour éviter l'erreur
-   * ExpressionChangedAfterItHasBeenCheckedError
-   */
-  private _currentFormId: string;
-
-  private _innerWidth: number;
-
-  constructor(
-    private intlService: I18nService,
-    private appSetupService: ApplicationSetupService,
-    private errorService: ErrorService,
-    private router: Router,
-    private formulaireService: FormulaireService,
-    private httpService: HttpService,
-    private notificationsService: NotificationsService,
-    private confirmEmptySessionDialog: MatDialog,
-    private saveSessionDialog: MatDialog,
-    private loadSessionDialog: MatDialog,
-    private confirmCloseCalcDialog: MatDialog,
-    private hotkeysService: HotkeysService,
-    private matomoInjector: MatomoInjector,
-    private matomoTracker: MatomoTracker
-  ) {
-    ServiceFactory.httpService = httpService;
-    ServiceFactory.applicationSetupService = appSetupService;
-    ServiceFactory.i18nService = intlService;
-    ServiceFactory.formulaireService = formulaireService;
-    ServiceFactory.notificationsService = notificationsService;
-
-    if (! isDevMode()) {
-      // évite de mettre en place un bandeau RGPD
-      this.matomoTracker.disableCookies();
-      // Set custom dimension for Electron / Cordova / pure Web browser
-      this.matomoTracker.setCustomDimension(1, this.getRunningPlatform());
-      // Matomo open-source Web analytics
-      this.matomoInjector.init("https://stasi.g-eau.fr/", 1);
-    }
-
-    this.router.events.subscribe((event: Event) => {
-      // close side navigation when clicking a calculator tab
-      if (event instanceof NavigationEnd) {
-        this.sidenav.close();
-        window.scrollTo(0, 0);
-      }
-      // [de]activate calc tabs depending on loaded route
-      if (event instanceof ActivationEnd) {
-        const path = event.snapshot.url[0].path;
-        if (path === "calculator") {
-          const calcUid = event.snapshot.params.uid;
-          if (this.calculatorExists(calcUid)) {
-            this.setActiveCalc(calcUid);
-          } else {
-            // if required calculator does not exist, redirect to list page
-            this.toList();
-          }
-        } else {
-          this.setActiveCalc(null);
+    @ViewChild("sidenav")
+    public sidenav: MatSidenav;
+
+    @ViewChild("navbar")
+    public navbar: MatToolbar;
+
+    /** current calculator, inferred from _currentFormId by setActiveCalc() (used for navbar menu) */
+    public currentCalc: any;
+
+    /** shows or hides the progressbar under the navbar */
+    public showProgressBar = false;
+
+    /** liste des modules de calcul ouverts */
+    private _calculators: Array<{
+        title: string,
+        type: CalculatorType,
+        uid: string,
+        active?: boolean,
+        latestAnchor?: string
+    }> = [];
+
+    /**
+     * id du formulaire courant
+     * on utilise pas directement FormulaireService.currentFormId pour éviter l'erreur
+     * ExpressionChangedAfterItHasBeenCheckedError
+     */
+    private _currentFormId: string;
+
+    private _innerWidth: number;
+
+    constructor(
+        private intlService: I18nService,
+        private appSetupService: ApplicationSetupService,
+        private errorService: ErrorService,
+        private router: Router,
+        private formulaireService: FormulaireService,
+        private httpService: HttpService,
+        private notificationsService: NotificationsService,
+        private confirmEmptySessionDialog: MatDialog,
+        private saveSessionDialog: MatDialog,
+        private loadSessionDialog: MatDialog,
+        private confirmCloseCalcDialog: MatDialog,
+        private hotkeysService: HotkeysService,
+        private matomoInjector: MatomoInjector,
+        private matomoTracker: MatomoTracker
+    ) {
+        ServiceFactory.httpService = httpService;
+        ServiceFactory.applicationSetupService = appSetupService;
+        ServiceFactory.i18nService = intlService;
+        ServiceFactory.formulaireService = formulaireService;
+        ServiceFactory.notificationsService = notificationsService;
+
+        if (!isDevMode()) {
+            // évite de mettre en place un bandeau RGPD
+            this.matomoTracker.disableCookies();
+            // Set custom dimension for Electron / Cordova / pure Web browser
+            this.matomoTracker.setCustomDimension(1, this.getRunningPlatform());
+            // Matomo open-source Web analytics
+            this.matomoInjector.init("https://stasi.g-eau.fr/", 1);
         }
-      }
-    });
-
-    // hotkeys listeners
-    this.hotkeysService.add(new Hotkey("alt+s", AppComponent.onHotkey(this.saveForm, this)));
-    this.hotkeysService.add(new Hotkey("alt+o", AppComponent.onHotkey(this.loadSession, this)));
-    this.hotkeysService.add(new Hotkey("alt+q", AppComponent.onHotkey(this.emptySession, this)));
-    this.hotkeysService.add(new Hotkey("alt+n", AppComponent.onHotkey(this.toList, this)));
-    this.hotkeysService.add(new Hotkey("alt+g", AppComponent.onHotkey(this.toDiagram, this)));
-  }
-
-  /**
-   * Wrapper for hotkeys triggers, that executes given function only if
-   * hotkeys are enabled in app preferences
-   * @param func function to execute when hotkey is entered
-   */
-  public static onHotkey(func: any, that: any) {
-    return (event: KeyboardEvent): boolean => {
-      if (ServiceFactory.applicationSetupService.enableHotkeys) {
-        func.call(that);
-        return false; // Prevent bubbling
-      } else {
-        console.log("Hotkeys are disabled in app preferences");
-      }
-    };
-  }
-
-  public static exportAsImage(canvas: HTMLCanvasElement) {
-    canvas.toBlob((blob) => {
-      AppComponent.download(blob, "chart.png", "image/png");
-    }); // defaults to image/png
-  }
-
-  /**
-   * Exports a results data table to XLSX format, and removes "help" mentions
-   * from the parameters names columns if needed
-   * @param table results data table
-   * @param namesInFirstCol if true, will look for parameters names in 1st column
-   *    (for fixed results), else in 1st row (variable results, by default)
-   */
-  public static exportAsSpreadsheet(table: ElementRef, namesInFirstCol: boolean = false) {
-    const ws: XLSX.WorkSheet = XLSX.utils.table_to_sheet(table);
-
-    let regExCellKey;
-    if (namesInFirstCol) {
-      regExCellKey = new RegExp("^A\\d$");
-    } else {
-      regExCellKey = new RegExp("^\\w1$");
-    }
-    // browse all cells
-    for (const key in ws) {
-      // look for 1st row or 1st col
-      if (regExCellKey.test(key) === true) {
-        const regExCellName = new RegExp("help$");
-        const v: string = ws[key].v;
-        // remove "help" from cell name's ending
-        if (regExCellName.test(v) === true) {
-          const newV = v.substr(0, v.length - 4);
-          ws[key].v = newV;
+
+        this.router.events.subscribe((event: Event) => {
+            // close side navigation when clicking a calculator tab
+            if (event instanceof NavigationEnd) {
+                this.sidenav.close();
+                window.scrollTo(0, 0);
+            }
+            // [de]activate calc tabs depending on loaded route
+            if (event instanceof ActivationEnd) {
+                const path = event.snapshot.url[0].path;
+                if (path === "calculator") {
+                    const calcUid = event.snapshot.params.uid;
+                    if (this.calculatorExists(calcUid)) {
+                        this.setActiveCalc(calcUid);
+                    } else {
+                        // if required calculator does not exist, redirect to list page
+                        this.toList();
+                    }
+                } else {
+                    this.setActiveCalc(null);
+                }
+            }
+        });
+
+        // hotkeys listeners
+        this.hotkeysService.add(new Hotkey("alt+s", AppComponent.onHotkey(this.saveForm, this)));
+        this.hotkeysService.add(new Hotkey("alt+o", AppComponent.onHotkey(this.loadSession, this)));
+        this.hotkeysService.add(new Hotkey("alt+q", AppComponent.onHotkey(this.emptySession, this)));
+        this.hotkeysService.add(new Hotkey("alt+n", AppComponent.onHotkey(this.toList, this)));
+        this.hotkeysService.add(new Hotkey("alt+g", AppComponent.onHotkey(this.toDiagram, this)));
+    }
+
+    /**
+     * Wrapper for hotkeys triggers, that executes given function only if
+     * hotkeys are enabled in app preferences
+     * @param func function to execute when hotkey is entered
+     */
+    public static onHotkey(func: any, that: any) {
+        return (event: KeyboardEvent): boolean => {
+            if (ServiceFactory.applicationSetupService.enableHotkeys) {
+                func.call(that);
+                return false; // Prevent bubbling
+            } else {
+                console.log("Hotkeys are disabled in app preferences");
+            }
+        };
+    }
+
+    public static exportAsImage(canvas: HTMLCanvasElement) {
+        canvas.toBlob((blob) => {
+            AppComponent.download(blob, "chart.png", "image/png");
+        }); // defaults to image/png
+    }
+
+    /**
+     * Exports a results data table to XLSX format, and removes "help" mentions
+     * from the parameters names columns if needed
+     * @param table results data table
+     * @param namesInFirstCol if true, will look for parameters names in 1st column
+     *    (for fixed results), else in 1st row (variable results, by default)
+     */
+    public static exportAsSpreadsheet(table: ElementRef, namesInFirstCol: boolean = false) {
+        const ws: XLSX.WorkSheet = XLSX.utils.table_to_sheet(table);
+
+        let regExCellKey;
+        if (namesInFirstCol) {
+            regExCellKey = new RegExp("^A\\d$");
+        } else {
+            regExCellKey = new RegExp("^\\w1$");
         }
-      }
-    }
-
-    const wb: XLSX.WorkBook = XLSX.utils.book_new();
-    XLSX.utils.book_append_sheet(wb, ws, "default");
-    const wopts: any = { bookType: "xlsx", bookSST: false, type: "array" };
-    const wbout = XLSX.write(wb, wopts);
-    AppComponent.download(
-      new Blob([wbout], {type: "application/octet-stream"}),
-      "cassiopee-results.xlsx",
-      "application/vnd.ms-excel"
-    );
-  }
-
-  /**
-   * Cordova-compatible file download method
-   * @see https://esstudio.site/2019/02/16/downloading-saving-and-opening-files-with-cordova.html
-   * @param blob binary object to download
-   * @param filename
-   * @param mimeType
-   */
-  public static download(blob: Blob, filename: string, mimeType: string) {
-    if (window.cordova && cordova.platformId !== "browser") {
-      document.addEventListener("deviceready", function () {
-        // save file using codova-plugin-file
-        let storageLocation = "";
-        switch (device.platform) {
-          case "Android":
-            storageLocation = cordova.file.externalDataDirectory;
-            break;
-          case "iOS":
-            storageLocation = cordova.file.documentsDirectory;
-            break;
+        // browse all cells
+        for (const key in ws) {
+            // look for 1st row or 1st col
+            if (regExCellKey.test(key) === true) {
+                const regExCellName = new RegExp("help$");
+                const v: string = ws[key].v;
+                // remove "help" from cell name's ending
+                if (regExCellName.test(v) === true) {
+                    const newV = v.substr(0, v.length - 4);
+                    ws[key].v = newV;
+                }
+            }
         }
-        const folderPath = storageLocation;
-        window.resolveLocalFileSystemURL(folderPath, (dir) => {
-            dir.getFile(
-              filename,
-              { create: true },
-              (file) => {
-                file.createWriter(
-                  function (fileWriter) {
-                    fileWriter.write(blob);
-                    fileWriter.onwriteend = () => {
-                      const url = file.toURL();
-                      cordova.plugins.fileOpener2.open(url, mimeType, {
-                        error: (err) => {
-                          console.error(err);
-                          alert(`No app found to handle type "${mimeType}"`);
+
+        const wb: XLSX.WorkBook = XLSX.utils.book_new();
+        XLSX.utils.book_append_sheet(wb, ws, "default");
+        const wopts: any = { bookType: "xlsx", bookSST: false, type: "array" };
+        const wbout = XLSX.write(wb, wopts);
+        AppComponent.download(
+            new Blob([wbout], { type: "application/octet-stream" }),
+            "cassiopee-results.xlsx",
+            "application/vnd.ms-excel"
+        );
+    }
+
+    /**
+     * Cordova-compatible file download method
+     * @see https://esstudio.site/2019/02/16/downloading-saving-and-opening-files-with-cordova.html
+     * @param blob binary object to download
+     * @param filename
+     * @param mimeType
+     */
+    public static download(blob: Blob, filename: string, mimeType: string) {
+        if (window.cordova && cordova.platformId !== "browser") {
+            document.addEventListener("deviceready", function () {
+                // save file using codova-plugin-file
+                let storageLocation = "";
+                switch (device.platform) {
+                    case "Android":
+                        storageLocation = cordova.file.externalDataDirectory;
+                        break;
+                    case "iOS":
+                        storageLocation = cordova.file.documentsDirectory;
+                        break;
+                }
+                const folderPath = storageLocation;
+                window.resolveLocalFileSystemURL(folderPath, (dir) => {
+                    dir.getFile(
+                        filename,
+                        { create: true },
+                        (file) => {
+                            file.createWriter(
+                                function (fileWriter) {
+                                    fileWriter.write(blob);
+                                    fileWriter.onwriteend = () => {
+                                        const url = file.toURL();
+                                        cordova.plugins.fileOpener2.open(url, mimeType, {
+                                            error: (err) => {
+                                                console.error(err);
+                                                alert(`No app found to handle type "${mimeType}"`);
+                                            },
+                                            success: () => {
+                                                console.log("success with opening the file");
+                                            }
+                                        });
+                                    };
+                                    fileWriter.onerror = function (err) {
+                                        console.error(err);
+                                    };
+                                },
+                                function (err) {
+                                    console.error(err);
+                                }
+                            );
                         },
-                        success: () => {
-                          console.log("success with opening the file");
+                        (err) => {
+                            console.error(err);
                         }
-                      });
-                    };
-                    fileWriter.onerror = function (err) {
-                      console.error(err);
-                    };
-                  },
-                  function (err) {
+                    );
+                }, (err) => {
                     console.error(err);
-                  }
+                }
                 );
-              },
-              (err) => {
-                console.error(err);
-              }
+            });
+        } else {
+            saveAs(blob, filename);
+        }
+    }
+
+    /**
+     * Triggered at app startup.
+     * Preferences are loaded by app setup service
+     * @see ApplicationSetupService.construct()
+     */
+    ngOnInit() {
+        this.formulaireService.addObserver(this);
+        this.subscribeErrorService();
+        this._innerWidth = window.innerWidth;
+    }
+
+    ngOnDestroy() {
+        this.unsubscribeErrorService();
+        this.formulaireService.removeObserver(this);
+    }
+
+    @HostListener("window:resize", ["$event"])
+    onResize(event) {
+        // keep track of window size for navbar tabs arrangement
+        this._innerWidth = window.innerWidth;
+    }
+
+    public get uitextSidenavNewCalc() {
+        return this.intlService.localizeText("INFO_MENU_NOUVELLE_CALC");
+    }
+
+    public get uitextSidenavParams() {
+        return this.intlService.localizeText("INFO_SETUP_TITLE");
+    }
+
+    public get uitextSidenavLoadSession() {
+        return this.intlService.localizeText("INFO_MENU_LOAD_SESSION_TITLE");
+    }
+
+    public get uitextSidenavSaveSession() {
+        return this.intlService.localizeText("INFO_MENU_SAVE_SESSION_TITLE");
+    }
+
+    public get uitextSidenavEmptySession() {
+        return this.intlService.localizeText("INFO_MENU_EMPTY_SESSION_TITLE");
+    }
+
+    public get uitextSidenavDiagram() {
+        return this.intlService.localizeText("INFO_MENU_DIAGRAM_TITLE");
+    }
+
+    public get uitextSidenavSessionProps() {
+        return this.intlService.localizeText("INFO_MENU_SESSION_PROPS");
+    }
+
+    public get uitextSidenavReportBug() {
+        return this.intlService.localizeText("INFO_MENU_REPORT_BUG");
+    }
+
+    public get uitextSidenavHelp() {
+        return this.intlService.localizeText("INFO_MENU_HELP_TITLE");
+    }
+
+    public get uitextSelectCalc() {
+        return this.intlService.localizeText("INFO_MENU_SELECT_CALC");
+    }
+
+    public getCalculatorLabel(t: CalculatorType) {
+        return decodeHtml(this.formulaireService.getLocalisedTitleFromCalculatorType(t));
+    }
+
+    public getFullCalculatorTitle(calc: { title: string, type: CalculatorType, active?: boolean }): string {
+        return decodeHtml(calc.title + " (" + this.getCalculatorLabel(calc.type) + ")");
+    }
+
+    public get calculators() {
+        return this._calculators;
+    }
+
+    public get currentFormId() {
+        return this._currentFormId;
+    }
+
+    public get currentRoute(): string {
+        return this.router.url;
+    }
+
+    public get currentCalcUid(): string {
+        return this.currentCalc ? this.currentCalc.uid : undefined;
+    }
+
+    public setActiveCalc(uid: string) {
+        this._calculators.forEach((calc) => {
+            calc.active = (calc.uid === uid);
+        });
+        // mark current calc for navbar menu
+        const index = this.getCalculatorIndexFromId(uid);
+        this.currentCalc = this._calculators[index];
+    }
+
+    /**
+     * Close calculator using middle click on tab
+     */
+    public onMouseUp(event: any, uid: string) {
+        if (event.which === 2) {
+            const dialogRef = this.confirmCloseCalcDialog.open(
+                DialogConfirmCloseCalcComponent,
+                {
+                    data: {
+                        uid: uid
+                    },
+                    disableClose: true
+                }
             );
-          }, (err) => {
-            console.error(err);
-          }
+            dialogRef.afterClosed().subscribe(result => {
+                if (result) {
+                    this.formulaireService.requestCloseForm(uid);
+                }
+            });
+        }
+    }
+
+    /**
+     * Returns true if sum of open calculator tabs witdh is lower than navbar
+     * available space (ie. if navbar is not overflowing), false otherwise
+     */
+    public get tabsFitInNavbar() {
+        // manual breakpoints
+        // @WARNING keep in sync with .calculator-buttons sizes in app.component.scss
+        let tabsLimit = 0;
+        if (this._innerWidth > 480) {
+            tabsLimit = 3;
+        }
+        if (this._innerWidth > 640) {
+            tabsLimit = 4;
+        }
+        if (this._innerWidth > 800) {
+            tabsLimit = 6;
+        }
+
+        const fits = this._calculators.length <= tabsLimit;
+        return fits;
+    }
+
+    /**
+     * abonnement au service d'erreurs
+     */
+    private subscribeErrorService() {
+        this.errorService.addObserver(this);
+    }
+
+    private unsubscribeErrorService() {
+        this.errorService.removeObserver(this);
+    }
+
+    public get enableHeaderDoc(): boolean {
+        return this.currentRoute === "/list" && this._calculators.length === 0;
+    }
+
+    public get enableSaveSessionMenu(): boolean {
+        return this._calculators.length > 0;
+    }
+
+    public get enableModulesDiagramMenu(): boolean {
+        return this._calculators.length > 0;
+    }
+
+    public get enableSessionPropertiesMenu(): boolean {
+        return this._calculators.length > 0;
+    }
+
+    public get enableEmptySessionMenu(): boolean {
+        return this._calculators.length > 0;
+    }
+
+    // interface Observer
+
+    public update(sender: any, data: any): void {
+        if (sender instanceof FormulaireService) {
+            switch (data["action"]) {
+                case "createForm":
+                    // add newly created form to calculators list
+                    const f: FormulaireDefinition = data["form"];
+                    this._calculators.push(
+                        {
+                            "title": f.calculatorName,
+                            "type": f.calculatorType,
+                            "uid": f.uid
+                        }
+                    );
+
+                    // abonnement en tant qu'observateur du nouveau formulaire
+                    f.addObserver(this);
+                    break;
+
+                case "invalidFormId":
+                    this.toList();
+                    break;
+
+                case "currentFormChanged":
+                    this._currentFormId = data["formId"];
+                    break;
+
+                case "saveForm":
+                    this.saveForm(data["form"]);
+                    break;
+
+                case "closeForm":
+                    const form: FormulaireDefinition = data["form"];
+                    this.closeCalculator(form);
+                    break;
+            }
+        } else if (sender instanceof FormulaireDefinition) {
+            switch (data["action"]) {
+                case "nameChanged":
+                    this.updateCalculatorTitle(sender, data["name"]);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Returns true if a form having "formUid" as UID exists
+     * @param formId UID to look for
+     */
+    private calculatorExists(formId: string): boolean {
+        return (this.getCalculatorIndexFromId(formId) > -1);
+    }
+
+    private getCalculatorIndexFromId(formId: string) {
+        const index = this._calculators.reduce((resultIndex, calc, currIndex) => {
+            if (resultIndex === -1 && calc["uid"] === formId) {
+                resultIndex = currIndex;
+            }
+            return resultIndex;
+        }, -1);
+
+        return index;
+    }
+
+    private updateCalculatorTitle(f: FormulaireDefinition, title: string) {
+        const formIndex = this.getCalculatorIndexFromId(f.uid);
+        this._calculators[formIndex]["title"] = title;
+    }
+
+    /**
+     * Saves a JSON serialised session file, for one or more calc modules
+     * @param calcList modules to save
+     * @param filename
+     */
+    private saveSession(calcList: any[], filename: string) {
+        const session: string = this.buildSessionFile(calcList);
+        if (!isDevMode()) {
+            this.matomoTracker.trackEvent("userAction", "saveSession");
+        }
+        this.formulaireService.downloadTextFile(session, filename);
+    }
+
+    /**
+     * Builds a session file including Nubs, GUI-specific Nubs metadata,
+     * model settings, GUI settings
+     * @param calcList Nubs to save
+     */
+    private buildSessionFile(calcList: any[]): string {
+        const serialiseOptions: { [key: string]: {} } = {};
+        for (const c of calcList) {
+            if (c.selected) {
+                serialiseOptions[c.uid] = { // GUI-dependent metadata to add to the session file
+                    title: c.title
+                };
+            }
+        }
+        const settings = {
+            precision: this.appSetupService.computePrecision,
+            maxIterations: this.appSetupService.maxIterations,
+            displayPrecision: this.appSetupService.displayPrecision,
+        };
+        return Session.getInstance().serialise(serialiseOptions, settings);
+    }
+
+    /**
+     * Supprime un module de calcul **de l'interface**
+     * ATTENTION, ne supprime pas le module de calcul en mémoire !
+     * Pour cela, utiliser FormulaireService.requestCloseForm(form.uid);
+     * @param form module de calcul à fermer
+     */
+    private closeCalculator(form: FormulaireDefinition) {
+        const formId: string = form.uid;
+
+        // désabonnement en tant qu'observateur
+        form.removeObserver(this);
+        // recherche du module de calcul correspondant à formId
+        const closedIndex = this.getCalculatorIndexFromId(formId);
+
+        /*
+         * détermination du nouveau module de calcul à afficher :
+         * - celui après celui supprimé
+         * - ou celui avant celui supprimé si on supprime le dernier
+         */
+        let newId = null;
+        const l = this._calculators.length;
+        if (l > 1) {
+            if (closedIndex === l - 1) {
+                newId = this._calculators[closedIndex - 1]["uid"];
+            } else {
+                newId = this._calculators[closedIndex + 1]["uid"];
+            }
+        }
+
+        // suppression
+
+        this._calculators = this._calculators.filter(calc => {
+            return formId !== calc["uid"];
+        });
+
+        // MAJ affichage
+
+        if (newId === null) {
+            this.toList();
+            this._currentFormId = null;
+        } else {
+            this.toCalc(newId);
+        }
+    }
+
+    private toList() {
+        this.router.navigate(["/list"]);
+    }
+
+    public toDiagram() {
+        this.router.navigate(["/diagram"]);
+    }
+
+    public toCalc(id: string) {
+        this.router.navigate(["/calculator", id]);
+        this.setActiveCalc(id);
+        setTimeout(() => { // @WARNING clodo trick to wait for Angular refresh
+            this.scrollToLatestQuicknav(id);
+        }, 50);
+    }
+
+    /**
+     * restarts a fresh session by closing all calculators
+     */
+    public emptySession() {
+        const dialogRef = this.confirmEmptySessionDialog.open(
+            DialogConfirmEmptySessionComponent,
+            { disableClose: true }
         );
-      });
-    } else {
-      saveAs(blob, filename);
-    }
-  }
-
-  /**
-   * Triggered at app startup.
-   * Preferences are loaded by app setup service
-   * @see ApplicationSetupService.construct()
-   */
-  ngOnInit() {
-    this.formulaireService.addObserver(this);
-    this.subscribeErrorService();
-    this._innerWidth = window.innerWidth;
-  }
-
-  ngOnDestroy() {
-    this.unsubscribeErrorService();
-    this.formulaireService.removeObserver(this);
-  }
-
-  @HostListener("window:resize", ["$event"])
-  onResize(event) {
-    // keep track of window size for navbar tabs arrangement
-    this._innerWidth = window.innerWidth;
-  }
-
-  public get uitextSidenavNewCalc() {
-    return this.intlService.localizeText("INFO_MENU_NOUVELLE_CALC");
-  }
-
-  public get uitextSidenavParams() {
-    return this.intlService.localizeText("INFO_SETUP_TITLE");
-  }
-
-  public get uitextSidenavLoadSession() {
-    return this.intlService.localizeText("INFO_MENU_LOAD_SESSION_TITLE");
-  }
-
-  public get uitextSidenavSaveSession() {
-    return this.intlService.localizeText("INFO_MENU_SAVE_SESSION_TITLE");
-  }
-
-  public get uitextSidenavEmptySession() {
-    return this.intlService.localizeText("INFO_MENU_EMPTY_SESSION_TITLE");
-  }
-
-  public get uitextSidenavDiagram() {
-    return this.intlService.localizeText("INFO_MENU_DIAGRAM_TITLE");
-  }
-
-  public get uitextSidenavSessionProps() {
-    return this.intlService.localizeText("INFO_MENU_SESSION_PROPS");
-  }
-
-  public get uitextSidenavReportBug() {
-    return this.intlService.localizeText("INFO_MENU_REPORT_BUG");
-  }
-
-  public get uitextSidenavHelp() {
-    return this.intlService.localizeText("INFO_MENU_HELP_TITLE");
-  }
-
-  public get uitextSelectCalc() {
-    return this.intlService.localizeText("INFO_MENU_SELECT_CALC");
-  }
-
-  public getCalculatorLabel(t: CalculatorType) {
-    return decodeHtml(this.formulaireService.getLocalisedTitleFromCalculatorType(t));
-  }
-
-  public getFullCalculatorTitle(calc: { title: string, type: CalculatorType, active?: boolean }): string {
-    return decodeHtml(calc.title + " (" + this.getCalculatorLabel(calc.type) + ")");
-  }
-
-  public get calculators() {
-    return this._calculators;
-  }
-
-  public get currentFormId() {
-    return this._currentFormId;
-  }
-
-  public get currentRoute(): string {
-    return this.router.url;
-  }
-
-  public get currentCalcUid(): string {
-    return this.currentCalc ? this.currentCalc.uid : undefined;
-  }
-
-  public setActiveCalc(uid: string) {
-    this._calculators.forEach((calc) => {
-      calc.active = (calc.uid === uid);
-    });
-    // mark current calc for navbar menu
-    const index = this.getCalculatorIndexFromId(uid);
-    this.currentCalc = this._calculators[index];
-  }
-
-  /**
-   * Close calculator using middle click on tab
-   */
-  public onMouseUp(event: any, uid: string) {
-    if (event.which === 2) {
-      const dialogRef = this.confirmCloseCalcDialog.open(
-        DialogConfirmCloseCalcComponent,
-        {
-            data: {
-              uid: uid
+        dialogRef.afterClosed().subscribe(result => {
+            if (result) {
+                this.doEmptySession();
+            }
+        });
+    }
+
+    public doEmptySession() {
+        // temporarily disable notifications
+        const oldNotifState = this.appSetupService.enableNotifications;
+        this.appSetupService.enableNotifications = false;
+        // close all calculators
+        for (const c of this._calculators) {
+            const form = this.formulaireService.getFormulaireFromId(c.uid);
+            this.formulaireService.requestCloseForm(form.uid);
+        }
+        // just to be sure, get rid of any Nub possibly stuck in session without any form attached
+        Session.getInstance().clear();
+        Session.getInstance().documentation = "";
+        // restore notifications
+        this.appSetupService.enableNotifications = oldNotifState;
+    }
+
+    public loadSession() {
+        // création du dialogue de sélection des formulaires à sauver
+        const dialogRef = this.loadSessionDialog.open(
+            DialogLoadSessionComponent,
+            { disableClose: false }
+        );
+        dialogRef.afterClosed().subscribe(result => {
+            if (result) {
+                if (result.emptySession) {
+                    this.doEmptySession();
+                }
+                this.loadSessionFile(result.file, result.calculators);
+            }
+        });
+    }
+
+    public loadSessionFile(f: File, info?: any) {
+        // notes merge detection: was there already some notes ?
+        const existingNotes = Session.getInstance().documentation;
+        // load
+        this.formulaireService.loadSession(f, info)
+            .then((data) => {
+                if (data.hasErrors) {
+                    this.notificationsService.notify(this.intlService.localizeText("ERROR_PROBLEM_LOADING_SESSION"), 3500);
+                } else {
+                    if (data.loaded && data.loaded.length > 0) {
+                        if (!isDevMode()) {
+                            this.matomoTracker.trackEvent("userAction", "loadSession");
+                        }
+                        // notes merge detection: was there already some notes ?
+                        const currentNotes = Session.getInstance().documentation;
+                        if (existingNotes !== "" && currentNotes !== existingNotes) {
+                            this.notificationsService.notify(this.intlService.localizeText("WARNING_SESSION_LOAD_NOTES_MERGED"), 3500);
+                        }
+                        // go to calc or diagram depending on what was loaded
+                        if (data.loaded.length > 1) {
+                            this.toDiagram();
+                        } else {
+                            this.toCalc(data.loaded[0]);
+                        }
+                    }
+                }
+            })
+            .catch((err) => {
+                this.notificationsService.notify(this.intlService.localizeText("ERROR_LOADING_SESSION"), 3500);
+                console.error("error loading session - ", err);
+                // rollback to ensure session is clean
+                this.doEmptySession();
+            });
+    }
+
+    /**
+     * Demande au client d'envoyer un email (génère un lien mailto:), pré-rempli
+     * avec un texte standard, et le contenu de la session au format JSON
+     */
+    public reportBug() {
+        const recipient = "bug@cassiopee.g-eau.fr";
+        const subject = "[ISSUE] " + this.intlService.localizeText("INFO_REPORT_BUG_SUBJECT");
+        let body = this.intlService.localizeText("INFO_REPORT_BUG_BODY");
+
+        // add session description
+
+        // get all forms
+        const list = [];
+        for (const c of this._calculators) {
+            list.push({
+                title: c.title,
+                uid: c.uid,
+                selected: true
+            });
+        }
+        let session = this.buildSessionFile(list);
+
+        // compress
+        session = pako.deflate(session, { to: "string" }); // gzip (zlib)
+        session = btoa(session); // base64
+
+        body += session + "\n";
+        body = encodeURIComponent(body);
+
+        const mailtoURL = `mailto:${recipient}?subject=${subject}&body=${body}`;
+
+        // temporarily disable tab closing alert, as tab won't be closed for real
+        this.appSetupService.warnBeforeTabClose = false;
+        window.location.href = mailtoURL;
+        this.appSetupService.warnBeforeTabClose = true;
+    }
+
+    public get revisionInfo(): any {
+        return {
+            jalhyd: {
+                date: jalhydDateRev,
+                version: jalhydVersion,
             },
-            disableClose: true
+            nghyd: {
+                date: nghydDateRev,
+                version: nghydVersion
+            }
+        };
+    }
+
+    /**
+     * sauvegarde du/des formulaires
+     * @param form formulaire à sélectionner par défaut dans la liste
+     */
+    public saveForm(form?: FormulaireDefinition) {
+        // liste des formulaires
+        const list = [];
+        for (const c of this._calculators) {
+            const uid = c["uid"];
+            const nub = Session.getInstance().findNubByUid(uid);
+            let required = nub.getTargettedNubs().map((req) => {
+                return req.uid;
+            });
+            required = required.filter(
+                (item, index) => required.indexOf(item) === index // deduplicate
+            );
+            list.push({
+                "children": nub.getChildren().map((child) => {
+                    return child.uid;
+                }),
+                "requires": required,
+                "selected": form ? (uid === form.uid) : true,
+                "title": c["title"],
+                "uid": uid
+            });
         }
-      );
-      dialogRef.afterClosed().subscribe(result => {
-          if (result) {
-              this.formulaireService.requestCloseForm(uid);
-          }
-      });
-    }
-  }
-
-  /**
-   * Returns true if sum of open calculator tabs witdh is lower than navbar
-   * available space (ie. if navbar is not overflowing), false otherwise
-   */
-  public get tabsFitInNavbar() {
-    // manual breakpoints
-    // @WARNING keep in sync with .calculator-buttons sizes in app.component.scss
-    let tabsLimit = 0;
-    if (this._innerWidth > 480) {
-      tabsLimit = 3;
-    }
-    if (this._innerWidth > 640) {
-      tabsLimit = 4;
-    }
-    if (this._innerWidth > 800) {
-      tabsLimit = 6;
-    }
-
-    const fits = this._calculators.length <= tabsLimit;
-    return fits;
-  }
-
-  /**
-   * abonnement au service d'erreurs
-   */
-  private subscribeErrorService() {
-    this.errorService.addObserver(this);
-  }
-
-  private unsubscribeErrorService() {
-    this.errorService.removeObserver(this);
-  }
-
-  public get enableHeaderDoc(): boolean {
-    return this.currentRoute === "/list" && this._calculators.length === 0;
-  }
-
-  public get enableSaveSessionMenu(): boolean {
-    return this._calculators.length > 0;
-  }
-
-  public get enableModulesDiagramMenu(): boolean {
-    return this._calculators.length > 0;
-  }
-
-  public get enableSessionPropertiesMenu(): boolean {
-    return this._calculators.length > 0;
-  }
-
-  public get enableEmptySessionMenu(): boolean {
-    return this._calculators.length > 0;
-  }
-
-  // interface Observer
-
-  public update(sender: any, data: any): void {
-    if (sender instanceof FormulaireService) {
-      switch (data["action"]) {
-        case "createForm":
-        // add newly created form to calculators list
-          const f: FormulaireDefinition = data["form"];
-          this._calculators.push(
+        // dialogue de sélection des formulaires à sauver
+        const dialogRef = this.saveSessionDialog.open(
+            DialogSaveSessionComponent,
             {
-              "title": f.calculatorName,
-              "type": f.calculatorType,
-              "uid": f.uid
+                data: {
+                    calculators: list
+                },
+                disableClose: false
             }
-          );
-
-          // abonnement en tant qu'observateur du nouveau formulaire
-          f.addObserver(this);
-          break;
-
-        case "invalidFormId":
-          this.toList();
-          break;
-
-        case "currentFormChanged":
-          this._currentFormId = data["formId"];
-          break;
-
-        case "saveForm":
-          this.saveForm(data["form"]);
-          break;
-
-        case "closeForm":
-          const form: FormulaireDefinition = data["form"];
-          this.closeCalculator(form);
-          break;
-      }
-    } else if (sender instanceof FormulaireDefinition) {
-      switch (data["action"]) {
-        case "nameChanged":
-          this.updateCalculatorTitle(sender, data["name"]);
-          break;
-      }
-    }
-  }
-
-  /**
-   * Returns true if a form having "formUid" as UID exists
-   * @param formId UID to look for
-   */
-  private calculatorExists(formId: string): boolean {
-    return (this.getCalculatorIndexFromId(formId) > -1);
-  }
-
-  private getCalculatorIndexFromId(formId: string) {
-    const index = this._calculators.reduce((resultIndex, calc, currIndex) => {
-      if (resultIndex === -1 && calc["uid"] === formId) {
-        resultIndex = currIndex;
-      }
-      return resultIndex;
-    }, -1);
-
-    return index;
-  }
-
-  private updateCalculatorTitle(f: FormulaireDefinition, title: string) {
-    const formIndex = this.getCalculatorIndexFromId(f.uid);
-    this._calculators[formIndex]["title"] = title;
-  }
-
-  /**
-   * Saves a JSON serialised session file, for one or more calc modules
-   * @param calcList modules to save
-   * @param filename
-   */
-  private saveSession(calcList: any[], filename: string) {
-    const session: string = this.buildSessionFile(calcList);
-    if (! isDevMode()) {
-      this.matomoTracker.trackEvent("userAction", "saveSession");
-    }
-    this.formulaireService.downloadTextFile(session, filename);
-  }
-
-  /**
-   * Builds a session file including Nubs, GUI-specific Nubs metadata,
-   * model settings, GUI settings
-   * @param calcList Nubs to save
-   */
-  private buildSessionFile(calcList: any[]): string {
-    const serialiseOptions: { [key: string]: {} } = {};
-    for (const c of calcList) {
-      if (c.selected) {
-        serialiseOptions[c.uid] = { // GUI-dependent metadata to add to the session file
-          title: c.title
-        };
-      }
-    }
-    const settings = {
-      precision: this.appSetupService.computePrecision,
-      maxIterations: this.appSetupService.maxIterations,
-      displayPrecision: this.appSetupService.displayPrecision,
-    };
-    return Session.getInstance().serialise(serialiseOptions, settings);
-  }
-
-  /**
-   * Supprime un module de calcul **de l'interface**
-   * ATTENTION, ne supprime pas le module de calcul en mémoire !
-   * Pour cela, utiliser FormulaireService.requestCloseForm(form.uid);
-   * @param form module de calcul à fermer
-   */
-  private closeCalculator(form: FormulaireDefinition) {
-    const formId: string = form.uid;
-
-    // désabonnement en tant qu'observateur
-    form.removeObserver(this);
-    // recherche du module de calcul correspondant à formId
-    const closedIndex = this.getCalculatorIndexFromId(formId);
-
-    /*
-     * détermination du nouveau module de calcul à afficher :
-     * - celui après celui supprimé
-     * - ou celui avant celui supprimé si on supprime le dernier
+        );
+        dialogRef.afterClosed().subscribe(result => {
+            if (result) {
+                let name = result.filename;
+
+                // ajout extension ".json"
+                const re = /.+\.json/;
+                const match = re.exec(name.toLowerCase());
+                if (match === null) {
+                    name = name + ".json";
+                }
+
+                this.saveSession(result.calculators, name);
+            }
+        });
+    }
+
+    /**
+     * Moves the view to one of the Quicknav anchors in the page, and saves this anchor
+     * as the latest visited, in _calculators list
+     * @param itemId a Quicknav anchor id (ex: "input" or "results")
      */
-    let newId = null;
-    const l = this._calculators.length;
-    if (l > 1) {
-      if (closedIndex === l - 1) {
-        newId = this._calculators[closedIndex - 1]["uid"];
-      } else {
-        newId = this._calculators[closedIndex + 1]["uid"];
-      }
-    }
-
-    // suppression
-
-    this._calculators = this._calculators.filter(calc => {
-      return formId !== calc["uid"];
-    });
-
-    // MAJ affichage
-
-    if (newId === null) {
-      this.toList();
-      this._currentFormId = null;
-    } else {
-      this.toCalc(newId);
-    }
-  }
-
-  private toList() {
-    this.router.navigate(["/list"]);
-  }
-
-  public toDiagram() {
-    this.router.navigate(["/diagram"]);
-  }
-
-  public toCalc(id: string) {
-    this.router.navigate(["/calculator", id]);
-    this.setActiveCalc(id);
-    setTimeout(() => { // @WARNING clodo trick to wait for Angular refresh
-      this.scrollToLatestQuicknav(id);
-    }, 50);
-  }
-
-  /**
-   * restarts a fresh session by closing all calculators
-   */
-  public emptySession() {
-    const dialogRef = this.confirmEmptySessionDialog.open(
-      DialogConfirmEmptySessionComponent,
-      { disableClose: true }
-    );
-    dialogRef.afterClosed().subscribe(result => {
-      if (result) {
-        this.doEmptySession();
-      }
-    });
-  }
-
-  public doEmptySession() {
-    // temporarily disable notifications
-    const oldNotifState = this.appSetupService.enableNotifications;
-    this.appSetupService.enableNotifications = false;
-    // close all calculators
-    for (const c of this._calculators) {
-      const form = this.formulaireService.getFormulaireFromId(c.uid);
-      this.formulaireService.requestCloseForm(form.uid);
-    }
-    // just to be sure, get rid of any Nub possibly stuck in session without any form attached
-    Session.getInstance().clear();
-    Session.getInstance().documentation = "";
-    // restore notifications
-    this.appSetupService.enableNotifications = oldNotifState;
-  }
-
-  public loadSession() {
-    // création du dialogue de sélection des formulaires à sauver
-    const dialogRef = this.loadSessionDialog.open(
-      DialogLoadSessionComponent,
-      { disableClose: false }
-    );
-    dialogRef.afterClosed().subscribe(result => {
-      if (result) {
-        if (result.emptySession) {
-          this.doEmptySession();
+    public scrollToQuicknav(itemId: string, behavior: ScrollBehavior = "smooth") {
+        const idx = this.getCalculatorIndexFromId(this.currentFormId);
+        let succeeded = false;
+        if (idx > -1) {
+            const id = QuicknavComponent.prefix + itemId;
+            // Scroll https://stackoverflow.com/a/56391657/5986614
+            const element = document.getElementById(id);
+            if (element && element.offsetParent !== null) { // offsetParent is null when element is not visible
+                const yCoordinate = element.getBoundingClientRect().top + window.pageYOffset;
+                window.scrollTo({
+                    top: yCoordinate - 60, // substract a little more than navbar height
+                    behavior: behavior
+                });
+                succeeded = true;
+                // Save position
+                this._calculators[idx].latestAnchor = itemId;
+            }
         }
-        this.loadSessionFile(result.file, result.calculators);
-      }
-    });
-  }
-
-  public loadSessionFile(f: File, info?: any) {
-    // notes merge detection: was there already some notes ?
-    const existingNotes = Session.getInstance().documentation;
-    // load
-    this.formulaireService.loadSession(f, info)
-    .then((data) => {
-      if (data.hasErrors) {
-        this.notificationsService.notify(this.intlService.localizeText("ERROR_PROBLEM_LOADING_SESSION"), 3500);
-      } else {
-        if (data.loaded && data.loaded.length > 0) {
-          if (! isDevMode()) {
-            this.matomoTracker.trackEvent("userAction", "loadSession");
-          }
-          // notes merge detection: was there already some notes ?
-          const currentNotes = Session.getInstance().documentation;
-          if (existingNotes !== "" && currentNotes !== existingNotes) {
-            this.notificationsService.notify(this.intlService.localizeText("WARNING_SESSION_LOAD_NOTES_MERGED"), 3500);
-          }
-          // go to calc or diagram depending on what was loaded
-          if (data.loaded.length > 1) {
-            this.toDiagram();
-          } else {
-            this.toCalc(data.loaded[0]);
-          }
+        if (!succeeded) {
+            // throw an error so that caller CalculatorComponent.scrollToResults()
+            // switches to plan B, in case we're trying to scroll to results pane
+            // after a module is calculated
+            throw Error("unable to scroll to quicknav anchor");
         }
-      }
-    })
-    .catch((err) => {
-      this.notificationsService.notify(this.intlService.localizeText("ERROR_LOADING_SESSION"), 3500);
-      console.error("error loading session - ", err);
-      // rollback to ensure session is clean
-      this.doEmptySession();
-    });
-  }
-
-  /**
-   * Demande au client d'envoyer un email (génère un lien mailto:), pré-rempli
-   * avec un texte standard, et le contenu de la session au format JSON
-   */
-  public reportBug() {
-    const recipient = "bug@cassiopee.g-eau.fr";
-    const subject = "[ISSUE] " + this.intlService.localizeText("INFO_REPORT_BUG_SUBJECT");
-    let body = this.intlService.localizeText("INFO_REPORT_BUG_BODY");
-
-    // add session description
-
-    // get all forms
-    const list = [];
-    for (const c of this._calculators) {
-      list.push({
-        title: c.title,
-        uid: c.uid,
-        selected: true
-      });
-    }
-    let session = this.buildSessionFile(list);
-
-    // compress
-    session = pako.deflate(session, { to: "string" }); // gzip (zlib)
-    session = btoa(session); // base64
-
-    body += session + "\n";
-    body = encodeURIComponent(body);
-
-    const mailtoURL = `mailto:${recipient}?subject=${subject}&body=${body}`;
-
-    // temporarily disable tab closing alert, as tab won't be closed for real
-    this.appSetupService.warnBeforeTabClose = false;
-    window.location.href = mailtoURL;
-    this.appSetupService.warnBeforeTabClose = true;
-  }
-
-  public get revisionInfo(): any {
-    return {
-      jalhyd: {
-        date: jalhydDateRev,
-        version: jalhydVersion,
-      },
-      nghyd: {
-        date: nghydDateRev,
-        version: nghydVersion
-      }
-    };
-  }
-
-  /**
-   * sauvegarde du/des formulaires
-   * @param form formulaire à sélectionner par défaut dans la liste
-   */
-  public saveForm(form?: FormulaireDefinition) {
-    // liste des formulaires
-    const list = [];
-    for (const c of this._calculators) {
-      const uid = c["uid"];
-      const nub = Session.getInstance().findNubByUid(uid);
-      let required = nub.getTargettedNubs().map((req) => {
-        return req.uid;
-      });
-      required = required.filter(
-        (item, index) => required.indexOf(item) === index // deduplicate
-      );
-      list.push({
-        "children": nub.getChildren().map((child) => {
-          return child.uid;
-        }),
-        "requires": required,
-        "selected": form ? (uid === form.uid) : true,
-        "title": c["title"],
-        "uid": uid
-      });
-    }
-    // dialogue de sélection des formulaires à sauver
-    const dialogRef = this.saveSessionDialog.open(
-      DialogSaveSessionComponent,
-      {
-        data: {
-          calculators: list
-        },
-        disableClose: false
-      }
-    );
-    dialogRef.afterClosed().subscribe(result => {
-      if (result) {
-        let name = result.filename;
-
-        // ajout extension ".json"
-        const re = /.+\.json/;
-        const match = re.exec(name.toLowerCase());
-        if (match === null) {
-          name = name + ".json";
+    }
+
+    /**
+     * Moves the view to the latest known Quicknav anchor of the current module
+     */
+    public scrollToLatestQuicknav(formId: string) {
+        // Get position
+        const idx = this.getCalculatorIndexFromId(formId);
+        if (idx > -1) {
+            const itemId = this._calculators[idx].latestAnchor;
+            // Scroll
+            if (itemId) {
+                this.scrollToQuicknav(itemId, "auto");
+            }
         }
+    }
 
-        this.saveSession(result.calculators, name);
-      }
-    });
-  }
-
-  /**
-   * Moves the view to one of the Quicknav anchors in the page, and saves this anchor
-   * as the latest visited, in _calculators list
-   * @param itemId a Quicknav anchor id (ex: "input" or "results")
-   */
-  public scrollToQuicknav(itemId: string, behavior: ScrollBehavior = "smooth") {
-    const idx = this.getCalculatorIndexFromId(this.currentFormId);
-    let succeeded = false;
-    if (idx > -1) {
-      const id = QuicknavComponent.prefix + itemId;
-      // Scroll https://stackoverflow.com/a/56391657/5986614
-      const element = document.getElementById(id);
-      if (element && element.offsetParent !== null) { // offsetParent is null when element is not visible
-          const yCoordinate = element.getBoundingClientRect().top + window.pageYOffset;
-          window.scrollTo({
-              top: yCoordinate - 60, // substract a little more than navbar height
-              behavior: behavior
-          });
-          succeeded = true;
-          // Save position
-          this._calculators[idx].latestAnchor = itemId;
-      }
-    }
-    if (! succeeded) {
-      // throw an error so that caller CalculatorComponent.scrollToResults()
-      // switches to plan B, in case we're trying to scroll to results pane
-      // after a module is calculated
-      throw Error("unable to scroll to quicknav anchor");
-    }
-  }
-
-  /**
-   * Moves the view to the latest known Quicknav anchor of the current module
-   */
-  public scrollToLatestQuicknav(formId: string) {
-    // Get position
-    const idx = this.getCalculatorIndexFromId(formId);
-    if (idx > -1) {
-      const itemId = this._calculators[idx].latestAnchor;
-      // Scroll
-      if (itemId) {
-        this.scrollToQuicknav(itemId, "auto");
-      }
-    }
-  }
-
-  public dropCalcButton(event: CdkDragDrop<string[]>) {
-    moveItemInArray(this.calculators, event.previousIndex, event.currentIndex);
-  }
-
-  public get docIndexPath(): string {
-    return "assets/docs/" + this.appSetupService.language + "/index.html";
-  }
-
-  /**
-   * Returns a string representing the running platform :
-   * "cordova", "electron", or "browser"
-   */
-  public getRunningPlatform(): string {
-    let runningPlatform = "browser";
-    if (navigator.userAgent.toLowerCase().indexOf("electron") > -1) {
-      runningPlatform = "electron";
-    } else if (window.cordova) {
-      runningPlatform = "cordova";
-    }
-    // console.log(">> running platform: ", runningPlatform);
-    return runningPlatform;
-  }
-
-  /**
-   * détection de la fermeture de la page/navigateur et demande de confirmation
-   */
-  @HostListener("window:beforeunload", [ "$event" ]) confirmExit($event) {
-    if (
-      this.appSetupService.warnBeforeTabClose
-      && environment.production // otherwise prevents dev server to reload app after recompiling
-    ) {
-      // affecter une valeur différente de null provoque l'affichage d'un dialogue de confirmation, mais le texte n'est pas affiché
-      $event.returnValue = "Your data will be lost !";
+    public dropCalcButton(event: CdkDragDrop<string[]>) {
+        moveItemInArray(this.calculators, event.previousIndex, event.currentIndex);
     }
-  }
 
-  @HostListener("keydown", [ "$event" ]) onKeydown(event: any) {
-    if (event.which === 38 || event.which === 40) { // up / down arrow
-      if (event.srcElement.type === "number") {
-        event.preventDefault();
-      }
+    public get docIndexPath(): string {
+        return "assets/docs/" + this.appSetupService.language + "/index.html";
+    }
+
+    /**
+     * Returns a string representing the running platform :
+     * "cordova", "electron", or "browser"
+     */
+    public getRunningPlatform(): string {
+        let runningPlatform = "browser";
+        if (navigator.userAgent.toLowerCase().indexOf("electron") > -1) {
+            runningPlatform = "electron";
+        } else if (window.cordova) {
+            runningPlatform = "cordova";
+        }
+        // console.log(">> running platform: ", runningPlatform);
+        return runningPlatform;
+    }
+
+    /**
+     * détection de la fermeture de la page/navigateur et demande de confirmation
+     */
+    @HostListener("window:beforeunload", ["$event"]) confirmExit($event) {
+        if (
+            this.appSetupService.warnBeforeTabClose
+            && environment.production // otherwise prevents dev server to reload app after recompiling
+        ) {
+            // affecter une valeur différente de null provoque l'affichage d'un dialogue de confirmation, mais le texte n'est pas affiché
+            $event.returnValue = "Your data will be lost !";
+        }
+    }
+
+    @HostListener("keydown", ["$event"]) onKeydown(event: any) {
+        if (event.which === 38 || event.which === 40) { // up / down arrow
+            if (event.srcElement.type === "number") {
+                event.preventDefault();
+            }
+        }
     }
-  }
 }
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index b25a7887f3039299d000a972fbebda921f634427..ca149bc7eef258e3303acc02ab589d3872715863 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -34,10 +34,10 @@ import { MarkdownModule, MarkedOptions } from "ngx-markdown";
 
 import { FlexLayoutModule } from "@angular/flex-layout";
 import {
-  CustomBreakPointsProvider,
-  FlexGtXxsShowHideDirective,
-  FlexXxsShowHideDirective,
-  FlexLtXsShowHideDirective
+    CustomBreakPointsProvider,
+    FlexGtXxsShowHideDirective,
+    FlexXxsShowHideDirective,
+    FlexLtXsShowHideDirective
 } from "./directives/flex-xxs.directive";
 
 import { HttpClientModule } from "@angular/common/http";
@@ -109,163 +109,163 @@ import { DialogSaveSessionComponent } from "./components/dialog-save-session/dia
 
 import { JalhydAsyncModelValidationDirective } from "./directives/jalhyd-async-model-validation.directive";
 import {
-  JalhydModelValidationDirective,
-  JalhydModelValidationMinDirective,
-  JalhydModelValidationMaxDirective,
-  JalhydModelValidationStepDirective
+    JalhydModelValidationDirective,
+    JalhydModelValidationMinDirective,
+    JalhydModelValidationMaxDirective,
+    JalhydModelValidationStepDirective
 } from "./directives/jalhyd-model-validation.directive";
 import { ImmediateErrorStateMatcher } from "./formulaire/immediate-error-state-matcher";
 
 const appRoutes: Routes = [
-  { path: "list", component: CalculatorListComponent },
-  { path: "calculator/:uid", component: GenericCalculatorComponent },
-  { path: "setup", component: ApplicationSetupComponent },
-  { path: "diagram", component: ModulesDiagramComponent },
-  { path: "properties", component: SessionPropertiesComponent },
-  { path: "**", redirectTo: "list", pathMatch: "full" }
+    { path: "list", component: CalculatorListComponent },
+    { path: "calculator/:uid", component: GenericCalculatorComponent },
+    { path: "setup", component: ApplicationSetupComponent },
+    { path: "diagram", component: ModulesDiagramComponent },
+    { path: "properties", component: SessionPropertiesComponent },
+    { path: "**", redirectTo: "list", pathMatch: "full" }
 ];
 
 @NgModule({
-  imports: [
-    FormsModule, // <-- import the FormsModule before binding with [(ngModel)]
-    ReactiveFormsModule,
-    BrowserAnimationsModule,
-    BrowserModule,
-    ChartModule,
-    DragDropModule,
-    FlexLayoutModule,
-    HotkeyModule.forRoot(),
-    HttpClientModule,
-    MarkdownModule.forRoot({
-      markedOptions: {
-        provide: MarkedOptions,
-        useValue: {
-          gfm: true,
-          breaks: true
+    imports: [
+        FormsModule, // <-- import the FormsModule before binding with [(ngModel)]
+        ReactiveFormsModule,
+        BrowserAnimationsModule,
+        BrowserModule,
+        ChartModule,
+        DragDropModule,
+        FlexLayoutModule,
+        HotkeyModule.forRoot(),
+        HttpClientModule,
+        MarkdownModule.forRoot({
+            markedOptions: {
+                provide: MarkedOptions,
+                useValue: {
+                    gfm: true,
+                    breaks: true
+                }
+            }
+        }),
+        MatBadgeModule,
+        MatButtonModule,
+        MatButtonToggleModule,
+        MatCardModule,
+        MatCheckboxModule,
+        MatDialogModule,
+        MaterialFileInputModule,
+        MatFormFieldModule,
+        MatIconModule,
+        MatInputModule,
+        MatListModule,
+        MatMenuModule,
+        MatProgressBarModule,
+        MatRadioModule,
+        MatSelectModule,
+        MatSidenavModule,
+        MatSnackBarModule,
+        MatTableModule,
+        MatTabsModule,
+        MatToolbarModule,
+        MatTooltipModule,
+        MatomoModule,
+        RouterModule.forRoot(
+            appRoutes,
+            {
+                useHash: true, // prevents reloading whole app when typing url in browser's navigation bar
+                enableTracing: false // debugging purposes only
+            }
+        ),
+        StorageServiceModule,
+        TableModule,
+        KonamiModule
+    ],
+    declarations: [ // composants, pipes et directives
+        AppComponent,
+        ApplicationSetupComponent,
+        BaseParamInputComponent,
+        CalcCanvasComponent,
+        CalculatorListComponent,
+        CalculatorNameComponent,
+        CalculatorResultsComponent,
+        DialogConfirmCloseCalcComponent,
+        DialogConfirmEmptySessionComponent,
+        DialogEditPabComponent,
+        DialogEditParamComputedComponent,
+        DialogEditParamValuesComponent,
+        DialogGeneratePABComponent,
+        DialogGeneratePARSimulationComponent,
+        DialogLoadPredefinedEspeceComponent,
+        DialogLoadSessionComponent,
+        DialogLogEntriesDetailsComponent,
+        DialogSaveSessionComponent,
+        FieldSetComponent,
+        FieldsetContainerComponent,
+        FixedResultsComponent,
+        FixedVarResultsComponent,
+        FlexGtXxsShowHideDirective,
+        FlexLtXsShowHideDirective,
+        FlexXxsShowHideDirective,
+        GenericCalculatorComponent,
+        ChartTypeSelectComponent,
+        JalhydAsyncModelValidationDirective,
+        JalhydModelValidationDirective,
+        JalhydModelValidationMinDirective,
+        JalhydModelValidationMaxDirective,
+        JalhydModelValidationStepDirective,
+        JetResultsComponent,
+        JetTrajectoryChartComponent,
+        LogComponent,
+        LogDrawerComponent,
+        LogEntryComponent,
+        ModulesDiagramComponent,
+        NgParamInputComponent,
+        PabProfileChartComponent,
+        PabResultsComponent,
+        VerificateurResultsComponent,
+        PabResultsTableComponent,
+        PabTableComponent,
+        VariableResultsSelectorComponent,
+        MacrorugoCompoundResultsComponent,
+        MacrorugoCompoundResultsTableComponent,
+        ParamComputedComponent,
+        ParamFieldLineComponent,
+        ParamLinkComponent,
+        ParamValuesComponent,
+        QuicknavComponent,
+        RemousResultsComponent,
+        ResultsChartComponent,
+        SectionCanvasComponent,
+        SectionResultsComponent,
+        SelectFieldLineComponent,
+        SessionPropertiesComponent,
+        VarResultsComponent
+    ],
+    entryComponents: [
+        DialogConfirmCloseCalcComponent,
+        DialogConfirmEmptySessionComponent,
+        DialogEditPabComponent,
+        DialogEditParamComputedComponent,
+        DialogEditParamValuesComponent,
+        DialogGeneratePABComponent,
+        DialogGeneratePARSimulationComponent,
+        DialogLoadPredefinedEspeceComponent,
+        DialogSaveSessionComponent,
+        DialogLoadSessionComponent,
+        DialogLogEntriesDetailsComponent
+    ],
+    providers: [ // services
+        ApplicationSetupService,
+        CustomBreakPointsProvider,
+        FormulaireService,
+        HttpService,
+        I18nService,
+        NotificationsService,
+        {
+            provide: ErrorStateMatcher,
+            useClass: ImmediateErrorStateMatcher
         }
-      }
-    }),
-    MatBadgeModule,
-    MatButtonModule,
-    MatButtonToggleModule,
-    MatCardModule,
-    MatCheckboxModule,
-    MatDialogModule,
-    MaterialFileInputModule,
-    MatFormFieldModule,
-    MatIconModule,
-    MatInputModule,
-    MatListModule,
-    MatMenuModule,
-    MatProgressBarModule,
-    MatRadioModule,
-    MatSelectModule,
-    MatSidenavModule,
-    MatSnackBarModule,
-    MatTableModule,
-    MatTabsModule,
-    MatToolbarModule,
-    MatTooltipModule,
-    MatomoModule,
-    RouterModule.forRoot(
-      appRoutes,
-      {
-        useHash: true, // prevents reloading whole app when typing url in browser's navigation bar
-        enableTracing: false // debugging purposes only
-      }
-    ),
-    StorageServiceModule,
-    TableModule,
-    KonamiModule
-  ],
-  declarations: [ // composants, pipes et directives
-    AppComponent,
-    ApplicationSetupComponent,
-    BaseParamInputComponent,
-    CalcCanvasComponent,
-    CalculatorListComponent,
-    CalculatorNameComponent,
-    CalculatorResultsComponent,
-    DialogConfirmCloseCalcComponent,
-    DialogConfirmEmptySessionComponent,
-    DialogEditPabComponent,
-    DialogEditParamComputedComponent,
-    DialogEditParamValuesComponent,
-    DialogGeneratePABComponent,
-    DialogGeneratePARSimulationComponent,
-    DialogLoadPredefinedEspeceComponent,
-    DialogLoadSessionComponent,
-    DialogLogEntriesDetailsComponent,
-    DialogSaveSessionComponent,
-    FieldSetComponent,
-    FieldsetContainerComponent,
-    FixedResultsComponent,
-    FixedVarResultsComponent,
-    FlexGtXxsShowHideDirective,
-    FlexLtXsShowHideDirective,
-    FlexXxsShowHideDirective,
-    GenericCalculatorComponent,
-    ChartTypeSelectComponent,
-    JalhydAsyncModelValidationDirective,
-    JalhydModelValidationDirective,
-    JalhydModelValidationMinDirective,
-    JalhydModelValidationMaxDirective,
-    JalhydModelValidationStepDirective,
-    JetResultsComponent,
-    JetTrajectoryChartComponent,
-    LogComponent,
-    LogDrawerComponent,
-    LogEntryComponent,
-    ModulesDiagramComponent,
-    NgParamInputComponent,
-    PabProfileChartComponent,
-    PabResultsComponent,
-    VerificateurResultsComponent,
-    PabResultsTableComponent,
-    PabTableComponent,
-    VariableResultsSelectorComponent,
-    MacrorugoCompoundResultsComponent,
-    MacrorugoCompoundResultsTableComponent,
-    ParamComputedComponent,
-    ParamFieldLineComponent,
-    ParamLinkComponent,
-    ParamValuesComponent,
-    QuicknavComponent,
-    RemousResultsComponent,
-    ResultsChartComponent,
-    SectionCanvasComponent,
-    SectionResultsComponent,
-    SelectFieldLineComponent,
-    SessionPropertiesComponent,
-    VarResultsComponent
-  ],
-  entryComponents: [
-    DialogConfirmCloseCalcComponent,
-    DialogConfirmEmptySessionComponent,
-    DialogEditPabComponent,
-    DialogEditParamComputedComponent,
-    DialogEditParamValuesComponent,
-    DialogGeneratePABComponent,
-    DialogGeneratePARSimulationComponent,
-    DialogLoadPredefinedEspeceComponent,
-    DialogSaveSessionComponent,
-    DialogLoadSessionComponent,
-    DialogLogEntriesDetailsComponent
-  ],
-  providers: [ // services
-    ApplicationSetupService,
-    CustomBreakPointsProvider,
-    FormulaireService,
-    HttpService,
-    I18nService,
-    NotificationsService,
-    {
-      provide: ErrorStateMatcher,
-      useClass: ImmediateErrorStateMatcher
-    }
-  ],
-  schemas: [ NO_ERRORS_SCHEMA ],
-  bootstrap: [ AppComponent ]
+    ],
+    schemas: [NO_ERRORS_SCHEMA],
+    bootstrap: [AppComponent]
 })
 
 export class AppModule { }
diff --git a/src/app/components/app-setup/app-setup.component.html b/src/app/components/app-setup/app-setup.component.html
index 6305c1bb9a36d21d3d191dc8d297042b8344f317..87f52357afe63aad94befa23b4cbb47f643ba248 100644
--- a/src/app/components/app-setup/app-setup.component.html
+++ b/src/app/components/app-setup/app-setup.component.html
@@ -1,98 +1,105 @@
-
 <div class="container" fxLayout="row" fxLayoutAlign="center space-evenly">
-  <mat-card id="app-setup">
-
-    <mat-card-header class="mat-card-header-text-margin-0">
-      <mat-card-title>
-        <h1>{{ uitextTitle }}</h1>
-      </mat-card-title>
-
-      <button type="button" mat-icon-button (click)="storePreferences()" [title]="uitextStorePreferences">
-        <mat-icon>file_download</mat-icon>
-      </button>
-      <button type="button" mat-icon-button (click)="restoreDefaultValues()" [title]="uitextRestoreDefaultValues">
-        <mat-icon>settings_backup_restore</mat-icon>
-      </button>
-    </mat-card-header>
-
-    <mat-card-content>
-      <!-- template-driven form -->
-      <form>
-
-        <!-- précision d'affichage -->
-        <mat-form-field data-testclass="numeric-input">
-            <input matInput [placeholder]="uitextDisplayAccuracy" #dp="ngModel" name="dp" inputmode="numeric"
-                [ngModel]="displayPrec.value" (ngModelChange)="!dp.invalid ? displayPrec.setValue($event): null"
-                pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$" required [appJalhydModelValidation]="displayPrec">
-
-            <mat-error *ngIf="dp.invalid && (dp.dirty || dp.touched)">
-                <div *ngIf="dp.errors.required || dp.errors.pattern">
-                    {{ uitextMustBeANumber }}
-                </div>
-                <div *ngIf="! dp.errors.required && dp.errors.jalhydModel" [innerHTML]="dp.errors.jalhydModel.message">
-                </div>
-            </mat-error>
-        </mat-form-field>
-
-        <!-- précision de calcul -->
-        <mat-form-field data-testclass="numeric-input">
-            <input matInput [placeholder]="uitextComputeAccuracy" #cp="ngModel" name="cp" inputmode="numeric"
-                [ngModel]="computePrec.value" (ngModelChange)="!cp.invalid ? computePrec.setValue($event): null"
-                pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$" required [appJalhydModelValidation]="computePrec">
-
-            <mat-error *ngIf="cp.invalid">
-                <div *ngIf="cp.errors.required || cp.errors.pattern">
-                    {{ uitextMustBeANumber }}
-                </div>
-                <div *ngIf="! cp.errors.required && cp.errors.jalhydModel" [innerHTML]="cp.errors.jalhydModel.message">
-                </div>
-            </mat-error>
-        </mat-form-field>
-
-        <!-- nombre d'itérations max Newton -->
-        <mat-form-field data-testclass="numeric-input">
-            <input matInput [placeholder]="uitextNewtonMaxIteration" #nmi="ngModel" name="nmi" inputmode="numeric"
-                [ngModel]="newtonMaxIter.value" (ngModelChange)="!nmi.invalid ? newtonMaxIter.setValue($event): null"
-                pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$" required [appJalhydModelValidation]="newtonMaxIter">
-
-            <mat-error *ngIf="nmi.invalid && (nmi.dirty || nmi.touched)">
-                <div *ngIf="nmi.errors.required || nmi.errors.pattern">
-                    {{ uitextMustBeANumber }}
-                </div>
-                <div *ngIf="! nmi.errors.required && nmi.errors.jalhydModel" [innerHTML]="nmi.errors.jalhydModel.message">
-                </div>
-            </mat-error>
-        </mat-form-field>
-
-        <!-- notifications (snackbar) -->
-        <mat-checkbox id="cb_notifications" class="wrapped-checkbox" name="notifications"
-          [(ngModel)]="enableNotifications" [ngModelOptions]="{standalone: true}">
-          {{ uitextEnableNotifications }}
-        </mat-checkbox>
-
-        <!-- hotkeys -->
-        <mat-checkbox id="cb_hotkeys" class="wrapped-checkbox" name="hotkeys"
-          [(ngModel)]="enableHotkeys" [ngModelOptions]="{standalone: true}">
-          {{ uitextEnableHotkeys }}
-        </mat-checkbox>
-
-        <!-- empty all fields when creating a new form -->
-        <mat-checkbox id="cb_emptyFields" class="wrapped-checkbox" name="emptyFields"
-          [(ngModel)]="enableEmptyFieldsOnFormInit" [ngModelOptions]="{standalone: true}">
-          {{ uitextEnableEmptyFieldsOnFormInit }}
-        </mat-checkbox>
-
-        <!-- langue -->
-        <mat-form-field>
-            <mat-select [placeholder]="uitextLanguage" [(value)]="currentLanguageCode" data-testid="language-select">
-                <mat-option *ngFor="let l of availableLanguages | keyvalue" [value]="l.key" [title]="l.value">
-                    {{ l.value }}
-                </mat-option>
-            </mat-select>
-        </mat-form-field>
-
-        </form>
-    </mat-card-content>
-
-  </mat-card>
-</div>
+    <mat-card id="app-setup">
+
+        <mat-card-header class="mat-card-header-text-margin-0">
+            <mat-card-title>
+                <h1>{{ uitextTitle }}</h1>
+            </mat-card-title>
+
+            <button type="button" mat-icon-button (click)="storePreferences()" [title]="uitextStorePreferences">
+                <mat-icon>file_download</mat-icon>
+            </button>
+            <button type="button" mat-icon-button (click)="restoreDefaultValues()" [title]="uitextRestoreDefaultValues">
+                <mat-icon>settings_backup_restore</mat-icon>
+            </button>
+        </mat-card-header>
+
+        <mat-card-content>
+            <!-- template-driven form -->
+            <form>
+
+                <!-- précision d'affichage -->
+                <mat-form-field data-testclass="numeric-input">
+                    <input matInput [placeholder]="uitextDisplayAccuracy" #dp="ngModel" name="dp" inputmode="numeric"
+                        [ngModel]="displayPrec.value" (ngModelChange)="!dp.invalid ? displayPrec.setValue($event): null"
+                        pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$" required
+                        [appJalhydModelValidation]="displayPrec">
+
+                    <mat-error *ngIf="dp.invalid && (dp.dirty || dp.touched)">
+                        <div *ngIf="dp.errors.required || dp.errors.pattern">
+                            {{ uitextMustBeANumber }}
+                        </div>
+                        <div *ngIf="! dp.errors.required && dp.errors.jalhydModel"
+                            [innerHTML]="dp.errors.jalhydModel.message">
+                        </div>
+                    </mat-error>
+                </mat-form-field>
+
+                <!-- précision de calcul -->
+                <mat-form-field data-testclass="numeric-input">
+                    <input matInput [placeholder]="uitextComputeAccuracy" #cp="ngModel" name="cp" inputmode="numeric"
+                        [ngModel]="computePrec.value" (ngModelChange)="!cp.invalid ? computePrec.setValue($event): null"
+                        pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$" required
+                        [appJalhydModelValidation]="computePrec">
+
+                    <mat-error *ngIf="cp.invalid">
+                        <div *ngIf="cp.errors.required || cp.errors.pattern">
+                            {{ uitextMustBeANumber }}
+                        </div>
+                        <div *ngIf="! cp.errors.required && cp.errors.jalhydModel"
+                            [innerHTML]="cp.errors.jalhydModel.message">
+                        </div>
+                    </mat-error>
+                </mat-form-field>
+
+                <!-- nombre d'itérations max Newton -->
+                <mat-form-field data-testclass="numeric-input">
+                    <input matInput [placeholder]="uitextNewtonMaxIteration" #nmi="ngModel" name="nmi"
+                        inputmode="numeric" [ngModel]="newtonMaxIter.value"
+                        (ngModelChange)="!nmi.invalid ? newtonMaxIter.setValue($event): null"
+                        pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$" required
+                        [appJalhydModelValidation]="newtonMaxIter">
+
+                    <mat-error *ngIf="nmi.invalid && (nmi.dirty || nmi.touched)">
+                        <div *ngIf="nmi.errors.required || nmi.errors.pattern">
+                            {{ uitextMustBeANumber }}
+                        </div>
+                        <div *ngIf="! nmi.errors.required && nmi.errors.jalhydModel"
+                            [innerHTML]="nmi.errors.jalhydModel.message">
+                        </div>
+                    </mat-error>
+                </mat-form-field>
+
+                <!-- notifications (snackbar) -->
+                <mat-checkbox id="cb_notifications" class="wrapped-checkbox" name="notifications"
+                    [(ngModel)]="enableNotifications" [ngModelOptions]="{standalone: true}">
+                    {{ uitextEnableNotifications }}
+                </mat-checkbox>
+
+                <!-- hotkeys -->
+                <mat-checkbox id="cb_hotkeys" class="wrapped-checkbox" name="hotkeys" [(ngModel)]="enableHotkeys"
+                    [ngModelOptions]="{standalone: true}">
+                    {{ uitextEnableHotkeys }}
+                </mat-checkbox>
+
+                <!-- empty all fields when creating a new form -->
+                <mat-checkbox id="cb_emptyFields" class="wrapped-checkbox" name="emptyFields"
+                    [(ngModel)]="enableEmptyFieldsOnFormInit" [ngModelOptions]="{standalone: true}">
+                    {{ uitextEnableEmptyFieldsOnFormInit }}
+                </mat-checkbox>
+
+                <!-- langue -->
+                <mat-form-field>
+                    <mat-select [placeholder]="uitextLanguage" [(value)]="currentLanguageCode"
+                        data-testid="language-select">
+                        <mat-option *ngFor="let l of availableLanguages | keyvalue" [value]="l.key" [title]="l.value">
+                            {{ l.value }}
+                        </mat-option>
+                    </mat-select>
+                </mat-form-field>
+
+            </form>
+        </mat-card-content>
+
+    </mat-card>
+</div>
\ No newline at end of file
diff --git a/src/app/components/calculator-list/calculator-list.component.html b/src/app/components/calculator-list/calculator-list.component.html
index 23db26dca6feeb6d9abeb702ecb44ba292e1a6ce..904c6d994d64971f644d82d4df903558e4c824f3 100644
--- a/src/app/components/calculator-list/calculator-list.component.html
+++ b/src/app/components/calculator-list/calculator-list.component.html
@@ -53,15 +53,15 @@
 
         <mat-card-content>
             <mat-list id="examples-list" role="list">
-              <mat-list-item role="listitem" *ngFor="let f of exampleFiles">
-                <mat-icon color="primary">folder_open</mat-icon>
-                <a class="load-example" (click)="loadExample(f.path)">
-                    {{ f.label }}
-                </a>
-              </mat-list-item>
+                <mat-list-item role="listitem" *ngFor="let f of exampleFiles">
+                    <mat-icon color="primary">folder_open</mat-icon>
+                    <a class="load-example" (click)="loadExample(f.path)">
+                        {{ f.label }}
+                    </a>
+                </mat-list-item>
             </mat-list>
         </mat-card-content>
 
     </mat-card>
 
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/dialog-confirm-close-calc/dialog-confirm-close-calc.component.html b/src/app/components/dialog-confirm-close-calc/dialog-confirm-close-calc.component.html
index 6398d84244504374defd3121aaa7126c87856fcc..c962d42880854bb2b0b20b43f5e758ba027f6abd 100644
--- a/src/app/components/dialog-confirm-close-calc/dialog-confirm-close-calc.component.html
+++ b/src/app/components/dialog-confirm-close-calc/dialog-confirm-close-calc.component.html
@@ -1,26 +1,26 @@
 <h1 mat-dialog-title [innerHTML]="uitextCloseCalcTitle"></h1>
 <div mat-dialog-content>
 
-  <div *ngIf="dependingNubs.length">
-    {{ uitextDependingModules }}
+    <div *ngIf="dependingNubs.length">
+        {{ uitextDependingModules }}
 
-    <div class="dependencies-problems">
-      <mat-list role="list">
-        <mat-list-item role="listitem" *ngFor="let dn of dependingNubs">
-          <mat-icon color="warn">error_outline</mat-icon> {{ dn }}
-        </mat-list-item>
-      </mat-list>
+        <div class="dependencies-problems">
+            <mat-list role="list">
+                <mat-list-item role="listitem" *ngFor="let dn of dependingNubs">
+                    <mat-icon color="warn">error_outline</mat-icon> {{ dn }}
+                </mat-list-item>
+            </mat-list>
+        </div>
     </div>
-  </div>
 </div>
 
 <p [innerHTML]="uitextCloseCalcBody"></p>
 
 <div mat-dialog-actions [attr.align]="'end'">
-  <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
-    {{ uitextNo }}
-  </button>
-  <button mat-raised-button color="warn" [mat-dialog-close]="true">
-    {{ uitextYes }}
-  </button>
-</div>
+    <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
+        {{ uitextNo }}
+    </button>
+    <button mat-raised-button color="warn" [mat-dialog-close]="true">
+        {{ uitextYes }}
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/components/dialog-confirm-close-calc/dialog-confirm-close-calc.component.ts b/src/app/components/dialog-confirm-close-calc/dialog-confirm-close-calc.component.ts
index 3a4858edac60fb0e0e49fb43968fbd439dbe4920..8be28ac26fd74eee03330c3445dc147c392b1152 100644
--- a/src/app/components/dialog-confirm-close-calc/dialog-confirm-close-calc.component.ts
+++ b/src/app/components/dialog-confirm-close-calc/dialog-confirm-close-calc.component.ts
@@ -8,7 +8,7 @@ import { Session } from "jalhyd";
     selector: "dialog-confirm-close-calc",
     templateUrl: "dialog-confirm-close-calc.component.html",
     styleUrls: [
-      "dialog-confirm-close-calc.component.scss"
+        "dialog-confirm-close-calc.component.scss"
     ]
 })
 export class DialogConfirmCloseCalcComponent {
@@ -27,27 +27,27 @@ export class DialogConfirmCloseCalcComponent {
     }
 
     public get uitextYes() {
-      return this.intlService.localizeText("INFO_OPTION_CLOSE");
+        return this.intlService.localizeText("INFO_OPTION_CLOSE");
     }
 
     public get uitextNo() {
-      return this.intlService.localizeText("INFO_OPTION_CANCEL");
+        return this.intlService.localizeText("INFO_OPTION_CANCEL");
     }
 
     public get uitextCloseCalcTitle() {
-      return this.intlService.localizeText("INFO_CLOSE_DIALOGUE_TITRE");
+        return this.intlService.localizeText("INFO_CLOSE_DIALOGUE_TITRE");
     }
 
     public get uitextCloseCalcBody() {
-      return this.intlService.localizeText("INFO_CLOSE_DIALOGUE_TEXT");
+        return this.intlService.localizeText("INFO_CLOSE_DIALOGUE_TEXT");
     }
 
     public get uitextDependingModules() {
-      return this.intlService.localizeText("INFO_CLOSE_DIALOGUE_DEPENDING_MODULES");
+        return this.intlService.localizeText("INFO_CLOSE_DIALOGUE_DEPENDING_MODULES");
     }
 
     public get dependingNubs() {
-      return this._dependingNubs;
+        return this._dependingNubs;
     }
 
 }
diff --git a/src/app/components/dialog-confirm-empty-session/dialog-confirm-empty-session.component.html b/src/app/components/dialog-confirm-empty-session/dialog-confirm-empty-session.component.html
index 565d03593cd888dc97ede1cb96623b3be590b033..f9ea392d0573bc2e369793f2dcde0fd00db55115 100644
--- a/src/app/components/dialog-confirm-empty-session/dialog-confirm-empty-session.component.html
+++ b/src/app/components/dialog-confirm-empty-session/dialog-confirm-empty-session.component.html
@@ -1,12 +1,12 @@
 <h1 mat-dialog-title [innerHTML]="uitextEmptySessionTitle"></h1>
 <div mat-dialog-content>
-  <p [innerHTML]="uitextEmptySessionBody"></p>
+    <p [innerHTML]="uitextEmptySessionBody"></p>
 </div>
 <div mat-dialog-actions [attr.align]="'end'">
-  <button id="cancel-new-session" mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
-    {{ uitextNo }}
-  </button>
-  <button id="confirm-new-session" mat-raised-button color="warn" [mat-dialog-close]="true">
-    {{ uitextYes }}
-  </button>
-</div>
+    <button id="cancel-new-session" mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
+        {{ uitextNo }}
+    </button>
+    <button id="confirm-new-session" mat-raised-button color="warn" [mat-dialog-close]="true">
+        {{ uitextYes }}
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/components/dialog-confirm-empty-session/dialog-confirm-empty-session.component.ts b/src/app/components/dialog-confirm-empty-session/dialog-confirm-empty-session.component.ts
index ad892f6ea973fe8ddb7e831d803e8a00ac0c8b75..38e2e6fc3155728843243068bf86a17bcd263ee1 100644
--- a/src/app/components/dialog-confirm-empty-session/dialog-confirm-empty-session.component.ts
+++ b/src/app/components/dialog-confirm-empty-session/dialog-confirm-empty-session.component.ts
@@ -15,19 +15,19 @@ export class DialogConfirmEmptySessionComponent {
     ) { }
 
     public get uitextYes() {
-      return this.intlService.localizeText("INFO_OPTION_START_NEW");
+        return this.intlService.localizeText("INFO_OPTION_START_NEW");
     }
 
     public get uitextNo() {
-      return this.intlService.localizeText("INFO_OPTION_CANCEL");
+        return this.intlService.localizeText("INFO_OPTION_CANCEL");
     }
 
     public get uitextEmptySessionTitle() {
-      return this.intlService.localizeText("INFO_EMPTY_SESSION_DIALOGUE_TITRE");
+        return this.intlService.localizeText("INFO_EMPTY_SESSION_DIALOGUE_TITRE");
     }
 
     public get uitextEmptySessionBody() {
-      return this.intlService.localizeText("INFO_EMPTY_SESSION_DIALOGUE_TEXT");
+        return this.intlService.localizeText("INFO_EMPTY_SESSION_DIALOGUE_TEXT");
     }
 
 }
diff --git a/src/app/components/dialog-edit-pab/dialog-edit-pab.component.html b/src/app/components/dialog-edit-pab/dialog-edit-pab.component.html
index c5658d7f41095ce626f2b91b61f896ca1cdfde95..fd7170e38b8c7ffb2c5bf8cc8131c9e1d6100810 100644
--- a/src/app/components/dialog-edit-pab/dialog-edit-pab.component.html
+++ b/src/app/components/dialog-edit-pab/dialog-edit-pab.component.html
@@ -2,73 +2,73 @@
 
 <form>
 
-  <div mat-dialog-content>
+    <div mat-dialog-content>
 
-    <!-- récap selection -->
-    <div id="selection-abstract">
-      {{ selectionAbstract }}
-    </div>
+        <!-- récap selection -->
+        <div id="selection-abstract">
+            {{ selectionAbstract }}
+        </div>
 
-    <!-- champ à modifier -->
-    <mat-form-field class="select-form-field">
-      <mat-select [placeholder]="uitextVariable" [(value)]="variable">
-          <mat-option *ngFor="let v of availableVariables" [value]="v.value" [title]="v.label">
-              {{ v.label }}
-          </mat-option>
-      </mat-select>
-    </mat-form-field>
+        <!-- champ à modifier -->
+        <mat-form-field class="select-form-field">
+            <mat-select [placeholder]="uitextVariable" [(value)]="variable">
+                <mat-option *ngFor="let v of availableVariables" [value]="v.value" [title]="v.label">
+                    {{ v.label }}
+                </mat-option>
+            </mat-select>
+        </mat-form-field>
 
-    <!-- ngDefaultControl : see https://github.com/angular/components/issues/8267 -->
-    <mat-radio-group ngDefaultControl [(ngModel)]="varAction" name="varAction">
+        <!-- ngDefaultControl : see https://github.com/angular/components/issues/8267 -->
+        <mat-radio-group ngDefaultControl [(ngModel)]="varAction" name="varAction">
 
-      <div class="radio-button-and-input-wrapper rbaiw-set-value">
-        <mat-radio-button value="set-value">
-          {{ uitextSetValue }}
-        </mat-radio-button>
-        <mat-form-field class="input-form-field">
-          <input matInput [(ngModel)]="valueToSet" name="valueToSet" #valueToSetRef="ngModel"
-            required pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
-        </mat-form-field>
-        <mat-error *ngIf="varAction === 'set-value' && valueToSetRef.invalid">
-            {{ uitextMustBeANumber }}
-        </mat-error>
-      </div>
+            <div class="radio-button-and-input-wrapper rbaiw-set-value">
+                <mat-radio-button value="set-value">
+                    {{ uitextSetValue }}
+                </mat-radio-button>
+                <mat-form-field class="input-form-field">
+                    <input matInput [(ngModel)]="valueToSet" name="valueToSet" #valueToSetRef="ngModel" required
+                        pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
+                </mat-form-field>
+                <mat-error *ngIf="varAction === 'set-value' && valueToSetRef.invalid">
+                    {{ uitextMustBeANumber }}
+                </mat-error>
+            </div>
 
-      <div class="radio-button-and-input-wrapper rbaiw-delta">
-        <mat-radio-button value="delta">
-          {{ uitextDelta }}
-        </mat-radio-button>
-        <mat-form-field class="input-form-field">
-          <input matInput [(ngModel)]="delta" name="delta" #deltaRef="ngModel"
-            required pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
-        </mat-form-field>
-        <mat-error *ngIf="varAction === 'delta' && deltaRef.invalid">
-            {{ uitextMustBeANumber }}
-        </mat-error>
-      </div>
+            <div class="radio-button-and-input-wrapper rbaiw-delta">
+                <mat-radio-button value="delta">
+                    {{ uitextDelta }}
+                </mat-radio-button>
+                <mat-form-field class="input-form-field">
+                    <input matInput [(ngModel)]="delta" name="delta" #deltaRef="ngModel" required
+                        pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
+                </mat-form-field>
+                <mat-error *ngIf="varAction === 'delta' && deltaRef.invalid">
+                    {{ uitextMustBeANumber }}
+                </mat-error>
+            </div>
 
-      <div class="radio-button-and-input-wrapper">
-        <mat-radio-button value="interpolate" [disabled]="! interpolationEnabled">
-          {{ uitextInterpolate }}
-          <span class="interpolation-bounds">
-            {{ interpolationBounds }}
-          </span>
-        </mat-radio-button>
-      </div>
+            <div class="radio-button-and-input-wrapper">
+                <mat-radio-button value="interpolate" [disabled]="! interpolationEnabled">
+                    {{ uitextInterpolate }}
+                    <span class="interpolation-bounds">
+                        {{ interpolationBounds }}
+                    </span>
+                </mat-radio-button>
+            </div>
 
-    </mat-radio-group>
+        </mat-radio-group>
 
-  </div>
+    </div>
 
-  <div mat-dialog-actions [attr.align]="'end'">
-    <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
-      {{ uitextCancel }}
-    </button>
-    <button mat-raised-button type="submit" color="warn" (click)="applyValues()"
-      [disabled]="buttonDisabled(valueToSetRef, deltaRef)">
+    <div mat-dialog-actions [attr.align]="'end'">
+        <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
+            {{ uitextCancel }}
+        </button>
+        <button mat-raised-button type="submit" color="warn" (click)="applyValues()"
+            [disabled]="buttonDisabled(valueToSetRef, deltaRef)">
 
-      {{ uitextValidate }}
-    </button>
-  </div>
+            {{ uitextValidate }}
+        </button>
+    </div>
 
-</form>
+</form>
\ No newline at end of file
diff --git a/src/app/components/dialog-edit-pab/dialog-edit-pab.component.ts b/src/app/components/dialog-edit-pab/dialog-edit-pab.component.ts
index 3ae949d911c1500bdc4f8622f521badff6e56564..d12470e4bed6595a578367ebe583cd06813c45f0 100644
--- a/src/app/components/dialog-edit-pab/dialog-edit-pab.component.ts
+++ b/src/app/components/dialog-edit-pab/dialog-edit-pab.component.ts
@@ -8,190 +8,190 @@ import { sprintf } from "sprintf-js";
 @Component({
     selector: "dialog-edit-pab",
     templateUrl: "dialog-edit-pab.component.html",
-    styleUrls: [ "dialog-edit-pab.component.scss" ]
+    styleUrls: ["dialog-edit-pab.component.scss"]
 })
 export class DialogEditPabComponent {
 
-  /** variables eligible to modification */
-  public availableVariables: any[];
-
-  /** symbols of the variables eligible to modification */
-  public availableVariableSymbols: string[];
-
-  /** action to apply to the variable */
-  public varAction: string;
-
-  /** value to set to all occurrences of the variable */
-  public valueToSet: number;
-
-  /** delta to apply (add) to all occurrences of the variable */
-  public delta: number;
-
-  /** true if selected devices are contained in one unique column */
-  public vertical: boolean;
-
-  /** variable to modify on every selected object */
-  private _variable: string;
-
-  /** number of selected walls and devices */
-  private selectedItemsAbstract: { walls: number, wallsDevices: number, devices: number };
-
-  constructor(
-    public dialogRef: MatDialogRef<DialogEditPabComponent>,
-    private intlService: I18nService,
-    @Inject(MAT_DIALOG_DATA) public data: any
-  ) {
-    this.selectedItemsAbstract = this.data.selectedItemsAbstract;
-    this.vertical = this.data.vertical;
-    this.availableVariables = this.data.availableVariables;
-    // console.log("AV VAR", this.availableVariables);
-    this.availableVariableSymbols = this.availableVariables.map(av => av.value);
-    this.variable = this.availableVariableSymbols[0];
-    // default action
-    this.varAction = "set-value";
-    // example values for validation / avoiding using a placeholder
-    this.valueToSet = this.availableVariables[0].first;
-    this.delta = 0;
-  }
-
-  public get variable(): string {
-    return this._variable;
-  }
-
-  // find available variable details from key
-  private findVariableDetails(variable: string): any {
-    let details: any;
-    for (const av of this.availableVariables) {
-      if (av.value === variable) {
-        details = av;
-      }
-    }
-    return details;
-  }
-
-  // preloads valueToSet depending on variable chosen
-  public set variable(v: string) {
-    this._variable = v;
-    const av = this.findVariableDetails(v);
-    this.valueToSet = av.first;
-  }
-
-  /** closes dialog and tells parent to apply modifications */
-  public applyValues() {
-    this.dialogRef.close({
-      action: this.varAction,
-      variable: this.variable,
-      value: Number(this.valueToSet),
-      delta: Number(this.delta),
-      variableDetails: this.findVariableDetails(this.variable)
-    });
-  }
-
-  public buttonDisabled(value: any, delta: any) {
-    return (
-      (this.varAction === "set-value" && ! value.valid)
-      || (this.varAction === "delta" && ! delta.valid)
-    );
-  }
-
-  /** returns a short text summing up what is selected */
-  public get selectionAbstract() {
-    let abstract = "";
-    if (this.selectedItemsAbstract.walls > 0) {
-      // devices outside of complete walls ?
-      if (this.selectedItemsAbstract.devices > 0) {
-        abstract = sprintf(
-          this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_N_WALLS_P_DEVICES"),
-          this.selectedItemsAbstract.walls,
-          this.selectedItemsAbstract.devices,
-          this.selectedItemsAbstract.wallsDevices + this.selectedItemsAbstract.devices
-        );
-      } else {
-        // only complete walls
-        abstract = sprintf(
-          this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_N_WALLS"),
-          this.selectedItemsAbstract.walls,
-          this.selectedItemsAbstract.wallsDevices
+    /** variables eligible to modification */
+    public availableVariables: any[];
+
+    /** symbols of the variables eligible to modification */
+    public availableVariableSymbols: string[];
+
+    /** action to apply to the variable */
+    public varAction: string;
+
+    /** value to set to all occurrences of the variable */
+    public valueToSet: number;
+
+    /** delta to apply (add) to all occurrences of the variable */
+    public delta: number;
+
+    /** true if selected devices are contained in one unique column */
+    public vertical: boolean;
+
+    /** variable to modify on every selected object */
+    private _variable: string;
+
+    /** number of selected walls and devices */
+    private selectedItemsAbstract: { walls: number, wallsDevices: number, devices: number };
+
+    constructor(
+        public dialogRef: MatDialogRef<DialogEditPabComponent>,
+        private intlService: I18nService,
+        @Inject(MAT_DIALOG_DATA) public data: any
+    ) {
+        this.selectedItemsAbstract = this.data.selectedItemsAbstract;
+        this.vertical = this.data.vertical;
+        this.availableVariables = this.data.availableVariables;
+        // console.log("AV VAR", this.availableVariables);
+        this.availableVariableSymbols = this.availableVariables.map(av => av.value);
+        this.variable = this.availableVariableSymbols[0];
+        // default action
+        this.varAction = "set-value";
+        // example values for validation / avoiding using a placeholder
+        this.valueToSet = this.availableVariables[0].first;
+        this.delta = 0;
+    }
+
+    public get variable(): string {
+        return this._variable;
+    }
+
+    // find available variable details from key
+    private findVariableDetails(variable: string): any {
+        let details: any;
+        for (const av of this.availableVariables) {
+            if (av.value === variable) {
+                details = av;
+            }
+        }
+        return details;
+    }
+
+    // preloads valueToSet depending on variable chosen
+    public set variable(v: string) {
+        this._variable = v;
+        const av = this.findVariableDetails(v);
+        this.valueToSet = av.first;
+    }
+
+    /** closes dialog and tells parent to apply modifications */
+    public applyValues() {
+        this.dialogRef.close({
+            action: this.varAction,
+            variable: this.variable,
+            value: Number(this.valueToSet),
+            delta: Number(this.delta),
+            variableDetails: this.findVariableDetails(this.variable)
+        });
+    }
+
+    public buttonDisabled(value: any, delta: any) {
+        return (
+            (this.varAction === "set-value" && !value.valid)
+            || (this.varAction === "delta" && !delta.valid)
         );
-      }
-    } else {
-      // no complete wall, devices only
-      abstract = sprintf(
-        this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_N_DEVICES"),
-        this.selectedItemsAbstract.devices
-      );
-    }
-    return abstract;
-  }
-
-  public variableLabel(v: string) {
-    const av = this.findVariableDetails(v);
-    return av.label;
-  }
-
-  public get interpolationEnabled() {
-    const varDetails = this.findVariableDetails(this.variable);
-    return (
-      this.vertical
-      && (this.selectedItemsAbstract.devices + this.selectedItemsAbstract.wallsDevices) > 1
-      && (varDetails.occurrences > 1)
-      && ([ "ZRAM", "ZRMB", "ZDV" ].includes(this.variable))
-    );
-  }
-
-  public get interpolationBounds() {
-    let bounds = "";
-    if (this.interpolationEnabled) {
-      const varDetails = this.findVariableDetails(this.variable);
-      if (varDetails) {
-        bounds = sprintf(
-          this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_INTERPOLATION_BOUNDS"),
-          varDetails.first,
-          varDetails.last
+    }
+
+    /** returns a short text summing up what is selected */
+    public get selectionAbstract() {
+        let abstract = "";
+        if (this.selectedItemsAbstract.walls > 0) {
+            // devices outside of complete walls ?
+            if (this.selectedItemsAbstract.devices > 0) {
+                abstract = sprintf(
+                    this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_N_WALLS_P_DEVICES"),
+                    this.selectedItemsAbstract.walls,
+                    this.selectedItemsAbstract.devices,
+                    this.selectedItemsAbstract.wallsDevices + this.selectedItemsAbstract.devices
+                );
+            } else {
+                // only complete walls
+                abstract = sprintf(
+                    this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_N_WALLS"),
+                    this.selectedItemsAbstract.walls,
+                    this.selectedItemsAbstract.wallsDevices
+                );
+            }
+        } else {
+            // no complete wall, devices only
+            abstract = sprintf(
+                this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_N_DEVICES"),
+                this.selectedItemsAbstract.devices
+            );
+        }
+        return abstract;
+    }
+
+    public variableLabel(v: string) {
+        const av = this.findVariableDetails(v);
+        return av.label;
+    }
+
+    public get interpolationEnabled() {
+        const varDetails = this.findVariableDetails(this.variable);
+        return (
+            this.vertical
+            && (this.selectedItemsAbstract.devices + this.selectedItemsAbstract.wallsDevices) > 1
+            && (varDetails.occurrences > 1)
+            && (["ZRAM", "ZRMB", "ZDV"].includes(this.variable))
         );
-      }
     }
-    return bounds;
-  }
 
-  public get uitextEditPabTitle() {
-    return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_TITLE");
-  }
+    public get interpolationBounds() {
+        let bounds = "";
+        if (this.interpolationEnabled) {
+            const varDetails = this.findVariableDetails(this.variable);
+            if (varDetails) {
+                bounds = sprintf(
+                    this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_INTERPOLATION_BOUNDS"),
+                    varDetails.first,
+                    varDetails.last
+                );
+            }
+        }
+        return bounds;
+    }
 
-  public get uitextVariable() {
-    return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_OPTION_VARIABLE");
-  }
+    public get uitextEditPabTitle() {
+        return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_TITLE");
+    }
 
-  public get uitextSetValue() {
-    return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_OPTION_SET_VALUE");
-  }
+    public get uitextVariable() {
+        return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_OPTION_VARIABLE");
+    }
+
+    public get uitextSetValue() {
+        return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_OPTION_SET_VALUE");
+    }
 
-  public get uitextDelta() {
-    return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_OPTION_DELTA");
-  }
+    public get uitextDelta() {
+        return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_OPTION_DELTA");
+    }
 
-  public get uitextInterpolate() {
-    return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_OPTION_INTERPOLATE");
-  }
+    public get uitextInterpolate() {
+        return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_OPTION_INTERPOLATE");
+    }
 
-  public get uitextSetValueInput() {
-    return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_SET_VALUE_INPUT");
-  }
+    public get uitextSetValueInput() {
+        return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_SET_VALUE_INPUT");
+    }
 
-  public get uitextDeltaInput() {
-    return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_DELTA_INPUT");
-  }
+    public get uitextDeltaInput() {
+        return this.intlService.localizeText("INFO_DIALOG_EDIT_PAB_DELTA_INPUT");
+    }
 
-  public get uitextMustBeANumber(): string {
-      return this.intlService.localizeText("ERROR_PARAM_MUST_BE_A_NUMBER");
-  }
+    public get uitextMustBeANumber(): string {
+        return this.intlService.localizeText("ERROR_PARAM_MUST_BE_A_NUMBER");
+    }
 
-  public get uitextValidate() {
-    return this.intlService.localizeText("INFO_OPTION_VALIDATE");
-  }
+    public get uitextValidate() {
+        return this.intlService.localizeText("INFO_OPTION_VALIDATE");
+    }
 
-  public get uitextCancel() {
-    return this.intlService.localizeText("INFO_OPTION_CANCEL");
-  }
+    public get uitextCancel() {
+        return this.intlService.localizeText("INFO_OPTION_CANCEL");
+    }
 
 }
diff --git a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html
index e3a40065da10db038c0e6aebc7f63cf657bd19d2..0ec1a116e403907574eb6db4a0c039b2061bbdb7 100644
--- a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html
+++ b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.html
@@ -2,17 +2,17 @@
 
 <form>
 
-  <div mat-dialog-content>
-    <ngparam-input [title]="param.title" ></ngparam-input>
-  </div>
+    <div mat-dialog-content>
+        <ngparam-input [title]="param.title"></ngparam-input>
+    </div>
 
-  <div mat-dialog-actions [attr.align]="'end'">
-    <button mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>
-        {{ uitextCancel }}
-    </button>
-    <button mat-raised-button color="warn" (click)="onValidate()">
-        {{ uitextValidate }}
-    </button>
-  </div>
+    <div mat-dialog-actions [attr.align]="'end'">
+        <button mat-raised-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>
+            {{ uitextCancel }}
+        </button>
+        <button mat-raised-button color="warn" (click)="onValidate()">
+            {{ uitextValidate }}
+        </button>
+    </div>
 
-</form>
+</form>
\ No newline at end of file
diff --git a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts
index d971e1ea6851430ebe9cae41ded481c02ca89d6e..4984494eb4220fc5b73ae2b588afb6a7a62ca6bb 100644
--- a/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts
+++ b/src/app/components/dialog-edit-param-computed/dialog-edit-param-computed.component.ts
@@ -20,17 +20,17 @@ export class DialogEditParamComputedComponent implements OnInit {
     private _ngParamInputComponent: NgParamInputComponent;
 
     constructor(
-      public dialogRef: MatDialogRef<DialogEditParamComputedComponent>,
-      private intlService: I18nService,
-      @Inject(MAT_DIALOG_DATA) public data: any
+        public dialogRef: MatDialogRef<DialogEditParamComputedComponent>,
+        private intlService: I18nService,
+        @Inject(MAT_DIALOG_DATA) public data: any
     ) {
-      // copy given parameter in a "fake" Ngparameter
-      const nP = data.param as NgParameter;
-      const p = nP.paramDefinition as ParamDefinition;
-      const pDef = new ParamDefinition(undefined, p.symbol, p.domain, p.unit, p.getValue(), p.family, p.visible);
-      this.param = new NgParameter(pDef, undefined);
-      this.param.setLabel(nP.label);
-      this.param.unit = nP.unit;
+        // copy given parameter in a "fake" Ngparameter
+        const nP = data.param as NgParameter;
+        const p = nP.paramDefinition as ParamDefinition;
+        const pDef = new ParamDefinition(undefined, p.symbol, p.domain, p.unit, p.getValue(), p.family, p.visible);
+        this.param = new NgParameter(pDef, undefined);
+        this.param.setLabel(nP.label);
+        this.param.unit = nP.unit;
     }
 
     public get uitextCancel(): string {
@@ -42,16 +42,16 @@ export class DialogEditParamComputedComponent implements OnInit {
     }
 
     public get uitextEditParamComputedInitialValue() {
-      return this.intlService.localizeText("INFO_DIALOG_COMPUTED_VALUE_TITLE");
+        return this.intlService.localizeText("INFO_DIALOG_COMPUTED_VALUE_TITLE");
     }
 
     public ngOnInit() {
-      this._ngParamInputComponent.model = this.param;
+        this._ngParamInputComponent.model = this.param;
     }
 
     public onValidate() {
-      this.dialogRef.close({
-        value: this.param.getValue()
-      });
+        this.dialogRef.close({
+            value: this.param.getValue()
+        });
     }
 }
diff --git a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
index 594a6de2c606b0fb3ffc03b01e03c9e5aecdcfc6..8a454d5c176463e73a6ebf8b8f54c95be76b6121 100644
--- a/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
+++ b/src/app/components/dialog-edit-param-values/dialog-edit-param-values.component.html
@@ -5,15 +5,15 @@
 
 <h1 mat-dialog-title>{{ uitextEditParamVariableValues }} ({{ numberOfValues }})</h1>
 
-  <div mat-dialog-content *ngIf="! viewChart">
+<div mat-dialog-content *ngIf="! viewChart">
 
     <mat-form-field>
-      <mat-select [placeholder]="uiTextModeSelection" [(value)]="selectedValueMode" (selectionChange)="onValueModeChange($event)"
-        data-testid="variable-value-mode-select">
-          <mat-option *ngFor="let e of valueModes" [value]="e.value">
-              {{ e.label }}
-          </mat-option>
-      </mat-select>
+        <mat-select [placeholder]="uiTextModeSelection" [(value)]="selectedValueMode"
+            (selectionChange)="onValueModeChange($event)" data-testid="variable-value-mode-select">
+            <mat-option *ngFor="let e of valueModes" [value]="e.value">
+                {{ e.label }}
+            </mat-option>
+        </mat-select>
     </mat-form-field>
 
     <div *ngIf="isMinMax" class="min-max-step-container">
@@ -21,8 +21,8 @@
             <mat-form-field>
                 <input matInput class="form-control" type="number" inputmode="numeric" name="min-value" step="0.01"
                     [placeholder]="uitextValeurMini" [(ngModel)]="minValue" #min="ngModel" name="min"
-                    (input)="minMaxForm.controls.max.updateValueAndValidity()"
-                    [appJalhydModelValidationMin]="param" required pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
+                    (input)="minMaxForm.controls.max.updateValueAndValidity()" [appJalhydModelValidationMin]="param"
+                    required pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
 
                 <mat-error *ngIf="min.errors">
                     <div *ngIf="min.errors.required || min.errors.pattern">
@@ -37,28 +37,27 @@
             <mat-form-field>
                 <input matInput class="form-control" type="number" inputmode="numeric" name="max-value" step="0.01"
                     [placeholder]="uitextValeurMaxi" [(ngModel)]="maxValue" #max="ngModel" name="max"
-                    (input)="minMaxForm.controls.min.updateValueAndValidity()"
-                    [appJalhydModelValidationMax]="param" required pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
-
-                    <mat-error *ngIf="max.errors">
-                        <div *ngIf="max.errors.required || max.errors.pattern">
-                            {{ uitextMustBeANumber }}
-                        </div>
-                        <div *ngIf="! max.errors.required && max.errors.jalhydModelMax">
-                            {{ max.errors.jalhydModelMax.message }}
-                        </div>
-                    </mat-error>
+                    (input)="minMaxForm.controls.min.updateValueAndValidity()" [appJalhydModelValidationMax]="param"
+                    required pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
+
+                <mat-error *ngIf="max.errors">
+                    <div *ngIf="max.errors.required || max.errors.pattern">
+                        {{ uitextMustBeANumber }}
+                    </div>
+                    <div *ngIf="! max.errors.required && max.errors.jalhydModelMax">
+                        {{ max.errors.jalhydModelMax.message }}
+                    </div>
+                </mat-error>
             </mat-form-field>
 
             <mat-form-field>
                 <input matInput class="form-control" type="number" inputmode="numeric" name="step-value" step="0.01"
                     [placeholder]="uitextPasVariation" [(ngModel)]="stepValue" #step="ngModel" name="step"
-                    [appJalhydModelValidationStep]="param"
-                    required pattern="^([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
+                    [appJalhydModelValidationStep]="param" required pattern="^([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$">
 
-                    <mat-error *ngIf="step.errors">
-                        {{ uitextMustBePositive }}
-                    </mat-error>
+                <mat-error *ngIf="step.errors">
+                    {{ uitextMustBePositive }}
+                </mat-error>
             </mat-form-field>
         </form>
     </div>
@@ -68,7 +67,7 @@
             <mat-form-field>
                 <textarea matInput matTextareaAutosize [placeholder]="uitextListeValeurs" formControlName="valuesList"
                     [value]="valuesList"></textarea>
-                    <!-- (input)="valuesList = $event.target.value" -->
+                <!-- (input)="valuesList = $event.target.value" -->
                 <mat-error>
                     <span *ngIf="valuesListForm.controls.valuesList.hasError('model')">
                         {{ valuesListForm.controls.valuesList.errors.model }}
@@ -92,8 +91,8 @@
                 <div fxHide.xs fxFlex.gt-xs="0 0 16px"></div>
 
                 <mat-form-field class="values-file file-input-field" fxFlex.gt-xs="1 0 auto" fxFlex.lt-sm="1 0 100%">
-                    <ngx-mat-file-input #valuesFile [placeholder]="uitextImportFile"
-                        (change)="onFileSelected($event)" formControlName="file">
+                    <ngx-mat-file-input #valuesFile [placeholder]="uitextImportFile" (change)="onFileSelected($event)"
+                        formControlName="file">
                     </ngx-mat-file-input>
                     <button mat-icon-button matSuffix *ngIf="!valuesFile.empty" (click)="valuesFile.clear($event)">
                         <mat-icon>clear</mat-icon>
@@ -104,22 +103,22 @@
     </div>
 
     <mat-form-field>
-      <mat-select [placeholder]="uitextExtensionStrategy" [(value)]="selectedExtensionStrategy"
-        data-testid="variable-extension-strategy-select">
-          <mat-option *ngFor="let e of extensionStrategies" [value]="e.value" [title]="e.label">
-              {{ e.label }}
-          </mat-option>
-      </mat-select>
+        <mat-select [placeholder]="uitextExtensionStrategy" [(value)]="selectedExtensionStrategy"
+            data-testid="variable-extension-strategy-select">
+            <mat-option *ngFor="let e of extensionStrategies" [value]="e.value" [title]="e.label">
+                {{ e.label }}
+            </mat-option>
+        </mat-select>
     </mat-form-field>
 
-  </div>
+</div>
 
-  <div mat-dialog-content *ngIf="viewChart">
-        <chart id="values-chart" type="scatter" [data]="chartData" [options]="chartOptions">
-        </chart>
-  </div>
+<div mat-dialog-content *ngIf="viewChart">
+    <chart id="values-chart" type="scatter" [data]="chartData" [options]="chartOptions">
+    </chart>
+</div>
 
-  <div mat-dialog-actions [attr.align]="'end'">
+<div mat-dialog-actions [attr.align]="'end'">
     <div *ngIf="isMinMax || viewChart">
         <button mat-raised-button [mat-dialog-close]="true" [disabled]="minMaxFormInvalid" cdkFocusInitial>
             {{ uitextClose }}
@@ -133,4 +132,4 @@
             {{ uitextValidate }}
         </button>
     </div>
-  </div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.html b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.html
index c1161f20c451d272622d87db4d7f3b5d795b9a02..2f1ad4f3bfd9aaac1f0fa6ab74515300fed75cf7 100644
--- a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.html
+++ b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.html
@@ -2,48 +2,48 @@
 
 <form id="form-generate-pab">
 
-  <div mat-dialog-content>
-
-    <mat-form-field>
-      <input matInput required [placeholder]="uitextDebit" pattern="^([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$"
-      [(ngModel)]="debit" name="debit" #inputDebit="ngModel" id="generatePabDebit">
-    </mat-form-field>
-    <mat-error *ngIf="inputDebit.invalid && (inputDebit.dirty || inputDebit.touched)">
-        <div *ngIf="inputDebit.errors.required || inputDebit.errors.pattern">
-            {{ uitextMustBePositive }}
-        </div>
-    </mat-error>
-
-    <mat-form-field>
-      <input matInput required [placeholder]="uitextCoteAmont" pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$"
-      [(ngModel)]="coteAmont" name="coteAmont" #inputCoteAmont="ngModel" id="generatePabCoteAmont">
-    </mat-form-field>
-    <mat-error *ngIf="inputCoteAmont.invalid && (inputCoteAmont.dirty || inputCoteAmont.touched)">
-        <div *ngIf="inputCoteAmont.errors.required || inputCoteAmont.errors.pattern">
-            {{ uitextMustBeANumber }}
-        </div>
-    </mat-error>
-
-    <mat-form-field>
-      <input matInput required [placeholder]="uitextNBBassins" pattern="^([2-9]|[1-9][0-9]+)$"
-      [(ngModel)]="nbBassins" name="nbBassins" #inputNbBassins="ngModel" id="generatePabNbBassins">
-    </mat-form-field>
-    <mat-error *ngIf="inputNbBassins.invalid && (inputNbBassins.dirty || inputNbBassins.touched)">
-        <div *ngIf="inputNbBassins.errors.required || inputNbBassins.errors.pattern">
-            {{ uitextMustBeAtLeastTwo }}
-        </div>
-    </mat-error>
-
-  </div>
-
-  <div mat-dialog-actions [attr.align]="'end'">
-    <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
-      {{ uitextCancel }}
-    </button>
-    <button mat-raised-button type="submit" color="warn" (click)="generatePAB()" id="do-generate"
-      [disabled]="(inputDebit.invalid || inputCoteAmont.invalid || inputNbBassins.invalid)">
-      {{ uitextGenerate }}
-    </button>
-  </div>
-
-</form>
+    <div mat-dialog-content>
+
+        <mat-form-field>
+            <input matInput required [placeholder]="uitextDebit" pattern="^([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$"
+                [(ngModel)]="debit" name="debit" #inputDebit="ngModel" id="generatePabDebit">
+        </mat-form-field>
+        <mat-error *ngIf="inputDebit.invalid && (inputDebit.dirty || inputDebit.touched)">
+            <div *ngIf="inputDebit.errors.required || inputDebit.errors.pattern">
+                {{ uitextMustBePositive }}
+            </div>
+        </mat-error>
+
+        <mat-form-field>
+            <input matInput required [placeholder]="uitextCoteAmont" pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$"
+                [(ngModel)]="coteAmont" name="coteAmont" #inputCoteAmont="ngModel" id="generatePabCoteAmont">
+        </mat-form-field>
+        <mat-error *ngIf="inputCoteAmont.invalid && (inputCoteAmont.dirty || inputCoteAmont.touched)">
+            <div *ngIf="inputCoteAmont.errors.required || inputCoteAmont.errors.pattern">
+                {{ uitextMustBeANumber }}
+            </div>
+        </mat-error>
+
+        <mat-form-field>
+            <input matInput required [placeholder]="uitextNBBassins" pattern="^([2-9]|[1-9][0-9]+)$"
+                [(ngModel)]="nbBassins" name="nbBassins" #inputNbBassins="ngModel" id="generatePabNbBassins">
+        </mat-form-field>
+        <mat-error *ngIf="inputNbBassins.invalid && (inputNbBassins.dirty || inputNbBassins.touched)">
+            <div *ngIf="inputNbBassins.errors.required || inputNbBassins.errors.pattern">
+                {{ uitextMustBeAtLeastTwo }}
+            </div>
+        </mat-error>
+
+    </div>
+
+    <div mat-dialog-actions [attr.align]="'end'">
+        <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
+            {{ uitextCancel }}
+        </button>
+        <button mat-raised-button type="submit" color="warn" (click)="generatePAB()" id="do-generate"
+            [disabled]="(inputDebit.invalid || inputCoteAmont.invalid || inputNbBassins.invalid)">
+            {{ uitextGenerate }}
+        </button>
+    </div>
+
+</form>
\ No newline at end of file
diff --git a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts
index 062a4f2375fe5d0870f32857a51f59c6048e0e9b..9634a342bf3e3109f3670613af3adbb00a7cb1ff 100644
--- a/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts
+++ b/src/app/components/dialog-generate-pab/dialog-generate-pab.component.ts
@@ -14,76 +14,76 @@ import { round } from "jalhyd";
 })
 export class DialogGeneratePABComponent {
 
-  public debit = 1.5;
-
-  public coteAmont = 102;
-
-  public chute: number;
-
-  public nbBassins = 6;
-
-  constructor(
-    public dialogRef: MatDialogRef<DialogGeneratePABComponent>,
-    private intlService: I18nService,
-    private appSetupService: ApplicationSetupService,
-    @Inject(MAT_DIALOG_DATA) public data: any
-  ) {
-    const nDigits = this.appSetupService.displayPrecision;
-    this.coteAmont = round(data.coteAmont, nDigits);
-    this.debit = round(data.debit, nDigits);
-    this.chute = round(data.chute, nDigits);
-  }
-
-  public generatePAB() {
-    // calculate downstream elevation
-    const coteAval = this.coteAmont - (this.chute * this.nbBassins);
-    // create PAB
-    this.dialogRef.close({
-      generate: true,
-      debit: this.debit,
-      coteAmont: this.coteAmont,
-      coteAval: coteAval,
-      nbBassins: this.nbBassins
-    });
-  }
-
-  public get uitextDebit() {
-    return this.intlService.localizeText("INFO_DIALOG_PAB_Q");
-  }
-
-  public get uitextCoteAmont() {
-    return this.intlService.localizeText("INFO_DIALOG_PAB_Z1");
-  }
-
-  public get uitextCoteAval() {
-    return this.intlService.localizeText("INFO_DIALOG_PAB_Z2");
-  }
-
-  public get uitextNBBassins() {
-    return this.intlService.localizeText("INFO_DIALOG_PAB_NB");
-  }
-
-  public get uitextMustBeANumber() {
-    return this.intlService.localizeText("ERROR_PARAM_MUST_BE_A_NUMBER");
-  }
-
-  public get uitextMustBePositive() {
-    return this.intlService.localizeText("ERROR_PARAM_MUST_BE_POSITIVE");
-  }
-
-  public get uitextMustBeAtLeastTwo() {
-    return sprintf(this.intlService.localizeText("ERROR_PARAM_MUST_BE_AT_LEAST"), 2);
-  }
-
-  public get uitextGeneratePAB() {
-      return this.intlService.localizeText("INFO_CALCULATOR_RESULTS_GENERATE_PAB");
-  }
-
-  public get uitextGenerate() {
-    return this.intlService.localizeText("INFO_OPTION_GENERATE");
-  }
-
-  public get uitextCancel() {
-    return this.intlService.localizeText("INFO_OPTION_CANCEL");
-  }
+    public debit = 1.5;
+
+    public coteAmont = 102;
+
+    public chute: number;
+
+    public nbBassins = 6;
+
+    constructor(
+        public dialogRef: MatDialogRef<DialogGeneratePABComponent>,
+        private intlService: I18nService,
+        private appSetupService: ApplicationSetupService,
+        @Inject(MAT_DIALOG_DATA) public data: any
+    ) {
+        const nDigits = this.appSetupService.displayPrecision;
+        this.coteAmont = round(data.coteAmont, nDigits);
+        this.debit = round(data.debit, nDigits);
+        this.chute = round(data.chute, nDigits);
+    }
+
+    public generatePAB() {
+        // calculate downstream elevation
+        const coteAval = this.coteAmont - (this.chute * this.nbBassins);
+        // create PAB
+        this.dialogRef.close({
+            generate: true,
+            debit: this.debit,
+            coteAmont: this.coteAmont,
+            coteAval: coteAval,
+            nbBassins: this.nbBassins
+        });
+    }
+
+    public get uitextDebit() {
+        return this.intlService.localizeText("INFO_DIALOG_PAB_Q");
+    }
+
+    public get uitextCoteAmont() {
+        return this.intlService.localizeText("INFO_DIALOG_PAB_Z1");
+    }
+
+    public get uitextCoteAval() {
+        return this.intlService.localizeText("INFO_DIALOG_PAB_Z2");
+    }
+
+    public get uitextNBBassins() {
+        return this.intlService.localizeText("INFO_DIALOG_PAB_NB");
+    }
+
+    public get uitextMustBeANumber() {
+        return this.intlService.localizeText("ERROR_PARAM_MUST_BE_A_NUMBER");
+    }
+
+    public get uitextMustBePositive() {
+        return this.intlService.localizeText("ERROR_PARAM_MUST_BE_POSITIVE");
+    }
+
+    public get uitextMustBeAtLeastTwo() {
+        return sprintf(this.intlService.localizeText("ERROR_PARAM_MUST_BE_AT_LEAST"), 2);
+    }
+
+    public get uitextGeneratePAB() {
+        return this.intlService.localizeText("INFO_CALCULATOR_RESULTS_GENERATE_PAB");
+    }
+
+    public get uitextGenerate() {
+        return this.intlService.localizeText("INFO_OPTION_GENERATE");
+    }
+
+    public get uitextCancel() {
+        return this.intlService.localizeText("INFO_OPTION_CANCEL");
+    }
 }
diff --git a/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.html b/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.html
index 3f42734c8ba1676103d58b21cb70f5c59d028367..dd11243cc6d0ef6fd9cb3c7a2ae70e895f979434 100644
--- a/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.html
+++ b/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.html
@@ -2,27 +2,27 @@
 
 <form id="form-generate-par-simulation">
 
-  <div mat-dialog-content>
-    <div id="generate-par-sim-desc">
-      {{ uitextDescription }}
+    <div mat-dialog-content>
+        <div id="generate-par-sim-desc">
+            {{ uitextDescription }}
+        </div>
+        <mat-form-field>
+            <mat-select id="select-combination" [placeholder]="label" [(value)]="selectedValue">
+                <mat-option *ngFor="let e of entries" [value]="e" [title]="entryLabel(e)">
+                    {{ entryLabel(e) }}
+                </mat-option>
+            </mat-select>
+        </mat-form-field>
     </div>
-    <mat-form-field>
-        <mat-select id="select-combination" [placeholder]="label" [(value)]="selectedValue">
-            <mat-option *ngFor="let e of entries" [value]="e" [title]="entryLabel(e)">
-                {{ entryLabel(e) }}
-            </mat-option>
-        </mat-select>
-    </mat-form-field>
-  </div>
 
-  <div mat-dialog-actions [attr.align]="'end'">
-    <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
-      {{ uitextCancel }}
-    </button>
-    <button mat-raised-button type="submit" color="warn" (click)="generatePARSimulation()" id="do-generate"
-      [disabled]="">
-      {{ uitextGenerate }}
-    </button>
-  </div>
+    <div mat-dialog-actions [attr.align]="'end'">
+        <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
+            {{ uitextCancel }}
+        </button>
+        <button mat-raised-button type="submit" color="warn" (click)="generatePARSimulation()" id="do-generate"
+            [disabled]="">
+            {{ uitextGenerate }}
+        </button>
+    </div>
 
-</form>
+</form>
\ No newline at end of file
diff --git a/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.ts b/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.ts
index dcb9569028dc7588dd3db80e1514ab95b0bdbe19..ff941247e077a8b17258024d630da1701eafa70c 100644
--- a/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.ts
+++ b/src/app/components/dialog-generate-par-simulation/dialog-generate-par-simulation.component.ts
@@ -13,97 +13,97 @@ import { fv, longestVarNgParam } from "../../util";
 })
 export class DialogGeneratePARSimulationComponent {
 
-  public selectedValue: number;
-
-  /** résultats de la ParCalage */
-  private _results: MultiDimensionResults;
-
-  /** size of the longest variable value */
-  private size = 0;
-
-  /** inferred extended values list for each variating parameter */
-  private varValues = [];
-
-  constructor(
-      public dialogRef: MatDialogRef<DialogGeneratePARSimulationComponent>,
-      private intlService: I18nService,
-      @Inject(MAT_DIALOG_DATA) public data: any
-  ) {
-      this._results = data.results;
-      this.selectedValue = 0;
-
-      if (this._results) {
-          // pre-extract variable parameters values
-          this.varValues = [];
-          // find longest list
-          const lvp = longestVarNgParam(this._results.variatedParameters);
-          this.size = lvp.size;
-          // get extended values lists for each variable parameter
-          for (const v of this._results.variatedParameters) {
-              const vv = [];
-              const iter = v.getExtendedValuesIterator(this.size);
-              while (iter.hasNext) {
-                  const nv = iter.next();
-                  vv.push(fv(nv.value));
-              }
-              this.varValues.push(vv);
-          }
-      }
-  }
-
-  public generatePARSimulation() {
-      this.dialogRef.close({
-          generate: true,
-          selected: this.selectedValue,
-          size: this.size
-      });
-  }
-
-  public get uitextDescription() {
-    return this.intlService.localizeText("INFO_DIALOG_PARSIM_DESC");
-  }
-
-  public get uitextGeneratePARSimulation() {
-      return this.intlService.localizeText("INFO_CALCULATOR_RESULTS_GENERATE_PAR_SIMULATION");
-  }
-
-  public get uitextGenerate() {
-      return this.intlService.localizeText("INFO_OPTION_GENERATE");
-  }
-
-  public get uitextCancel() {
-      return this.intlService.localizeText("INFO_OPTION_CANCEL");
-  }
-
-  public get entries(): number[] {
-      const ret: number[] = [];
-      for (let i = 0; i < this.size; i++) {
-          ret.push(i);
-      }
-      return ret;
-  }
-
-  protected entryLabel(index: number): string {
-      const kv = [];
-      for (let i = 0; i < this.varValues.length; i++) {
-          const vv = this.varValues[i];
-          const vp = this._results.variatedParameters[i];
-          let symbol = vp.symbol;
-          // is vp a parameter of a child Nub ?
-          if (
-              vp.paramDefinition.parentNub
-              && vp.paramDefinition.parentNub !== vp.paramDefinition.originNub
-          ) {
-              const pos = vp.paramDefinition.parentNub.findPositionInParent() + 1;
-              symbol = this.intlService.localizeText("INFO_LIB_RADIER_N_COURT") + pos + "_" + symbol;
-          }
-          kv.push(`${symbol} = ${vv[index]}`);
-      }
-      return kv.join(", ");
-  }
-
-  public get label() {
-      return this.intlService.localizeText("INFO_PARAMFIELD_BOUNDARY_CONDITIONS");
-  }
+    public selectedValue: number;
+
+    /** résultats de la ParCalage */
+    private _results: MultiDimensionResults;
+
+    /** size of the longest variable value */
+    private size = 0;
+
+    /** inferred extended values list for each variating parameter */
+    private varValues = [];
+
+    constructor(
+        public dialogRef: MatDialogRef<DialogGeneratePARSimulationComponent>,
+        private intlService: I18nService,
+        @Inject(MAT_DIALOG_DATA) public data: any
+    ) {
+        this._results = data.results;
+        this.selectedValue = 0;
+
+        if (this._results) {
+            // pre-extract variable parameters values
+            this.varValues = [];
+            // find longest list
+            const lvp = longestVarNgParam(this._results.variatedParameters);
+            this.size = lvp.size;
+            // get extended values lists for each variable parameter
+            for (const v of this._results.variatedParameters) {
+                const vv = [];
+                const iter = v.getExtendedValuesIterator(this.size);
+                while (iter.hasNext) {
+                    const nv = iter.next();
+                    vv.push(fv(nv.value));
+                }
+                this.varValues.push(vv);
+            }
+        }
+    }
+
+    public generatePARSimulation() {
+        this.dialogRef.close({
+            generate: true,
+            selected: this.selectedValue,
+            size: this.size
+        });
+    }
+
+    public get uitextDescription() {
+        return this.intlService.localizeText("INFO_DIALOG_PARSIM_DESC");
+    }
+
+    public get uitextGeneratePARSimulation() {
+        return this.intlService.localizeText("INFO_CALCULATOR_RESULTS_GENERATE_PAR_SIMULATION");
+    }
+
+    public get uitextGenerate() {
+        return this.intlService.localizeText("INFO_OPTION_GENERATE");
+    }
+
+    public get uitextCancel() {
+        return this.intlService.localizeText("INFO_OPTION_CANCEL");
+    }
+
+    public get entries(): number[] {
+        const ret: number[] = [];
+        for (let i = 0; i < this.size; i++) {
+            ret.push(i);
+        }
+        return ret;
+    }
+
+    protected entryLabel(index: number): string {
+        const kv = [];
+        for (let i = 0; i < this.varValues.length; i++) {
+            const vv = this.varValues[i];
+            const vp = this._results.variatedParameters[i];
+            let symbol = vp.symbol;
+            // is vp a parameter of a child Nub ?
+            if (
+                vp.paramDefinition.parentNub
+                && vp.paramDefinition.parentNub !== vp.paramDefinition.originNub
+            ) {
+                const pos = vp.paramDefinition.parentNub.findPositionInParent() + 1;
+                symbol = this.intlService.localizeText("INFO_LIB_RADIER_N_COURT") + pos + "_" + symbol;
+            }
+            kv.push(`${symbol} = ${vv[index]}`);
+        }
+        return kv.join(", ");
+    }
+
+    public get label() {
+        return this.intlService.localizeText("INFO_PARAMFIELD_BOUNDARY_CONDITIONS");
+    }
 
 }
diff --git a/src/app/components/dialog-load-predefined-espece/dialog-load-predefined-espece.component.html b/src/app/components/dialog-load-predefined-espece/dialog-load-predefined-espece.component.html
index 13e3945915104f4bf63e36eb83d9df2e381860fa..d82ff2f0734064bf5ea0803d34257bd409984487 100644
--- a/src/app/components/dialog-load-predefined-espece/dialog-load-predefined-espece.component.html
+++ b/src/app/components/dialog-load-predefined-espece/dialog-load-predefined-espece.component.html
@@ -2,24 +2,24 @@
 
 <form id="form-load-predefined-espece">
 
-  <div mat-dialog-content>
-    <mat-form-field>
-        <mat-select id="select-combination" [placeholder]="label" [(value)]="selectedValue">
-            <mat-option *ngFor="let e of entries" [value]="e" [title]="entryLabel(e)">
-                {{ entryLabel(e) }}
-            </mat-option>
-        </mat-select>
-    </mat-form-field>
-  </div>
+    <div mat-dialog-content>
+        <mat-form-field>
+            <mat-select id="select-combination" [placeholder]="label" [(value)]="selectedValue">
+                <mat-option *ngFor="let e of entries" [value]="e" [title]="entryLabel(e)">
+                    {{ entryLabel(e) }}
+                </mat-option>
+            </mat-select>
+        </mat-form-field>
+    </div>
 
-  <div mat-dialog-actions [attr.align]="'end'">
-    <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
-      {{ uitextCancel }}
-    </button>
-    <button mat-raised-button type="submit" color="warn" (click)="loadPredefinedEspece()" id="do-load"
-      [disabled]="">
-      {{ uitextLoad }}
-    </button>
-  </div>
+    <div mat-dialog-actions [attr.align]="'end'">
+        <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
+            {{ uitextCancel }}
+        </button>
+        <button mat-raised-button type="submit" color="warn" (click)="loadPredefinedEspece()" id="do-load"
+            [disabled]="">
+            {{ uitextLoad }}
+        </button>
+    </div>
 
-</form>
+</form>
\ No newline at end of file
diff --git a/src/app/components/dialog-load-session/dialog-load-session.component.html b/src/app/components/dialog-load-session/dialog-load-session.component.html
index ba088e2bfa6021366e8118e3073701683278952b..bbb1ed6f6e4ed95a76afce4b56bf2e5e6bbce69a 100644
--- a/src/app/components/dialog-load-session/dialog-load-session.component.html
+++ b/src/app/components/dialog-load-session/dialog-load-session.component.html
@@ -2,70 +2,71 @@
 
 <form [formGroup]="loadSessionForm">
 
-  <div mat-dialog-content>
+    <div mat-dialog-content>
 
-    <mat-form-field class="file-input-field">
-      <ngx-mat-file-input id="session-file-input" #sessionFile formControlName="file"[placeholder]="uitextLoadSessionFilename"
-        (change)="onFileSelected($event)"></ngx-mat-file-input>
-      <button mat-icon-button matSuffix *ngIf="!sessionFile.empty" (click)="sessionFile.clear($event)">
-        <mat-icon>clear</mat-icon>
-      </button>
-    </mat-form-field>
+        <mat-form-field class="file-input-field">
+            <ngx-mat-file-input id="session-file-input" #sessionFile formControlName="file"
+                [placeholder]="uitextLoadSessionFilename" (change)="onFileSelected($event)"></ngx-mat-file-input>
+            <button mat-icon-button matSuffix *ngIf="!sessionFile.empty" (click)="sessionFile.clear($event)">
+                <mat-icon>clear</mat-icon>
+            </button>
+        </mat-form-field>
 
-    <div class="cb-container">
-      <mat-checkbox [name]="c.uid" *ngFor="let c of calculators" (change)="checkLinkedParamsAndModelsDependencies()"
-        [(ngModel)]="c.selected" [ngModelOptions]="{standalone: true}">
-        {{ c.title }}
-      </mat-checkbox>
-    </div>
+        <div class="cb-container">
+            <mat-checkbox [name]="c.uid" *ngFor="let c of calculators"
+                (change)="checkLinkedParamsAndModelsDependencies()" [(ngModel)]="c.selected"
+                [ngModelOptions]="{standalone: true}">
+                {{ c.title }}
+            </mat-checkbox>
+        </div>
 
-    <div class="btn-container">
-      <button mat-raised-button (click)="selectAll()" [disabled]="calculators.length === 0">
-        {{ uitextAll }}
-      </button>
-      <button mat-raised-button (click)="selectNone()" [disabled]="calculators.length === 0">
-        {{ uitextNone }}
-      </button>
-    </div>
+        <div class="btn-container">
+            <button mat-raised-button (click)="selectAll()" [disabled]="calculators.length === 0">
+                {{ uitextAll }}
+            </button>
+            <button mat-raised-button (click)="selectNone()" [disabled]="calculators.length === 0">
+                {{ uitextNone }}
+            </button>
+        </div>
 
-    <div class="file-problem" *ngIf="fileProblem">
-      <mat-list role="list">
-        <mat-list-item role="listitem">
-          <mat-icon color="warn">error_outline</mat-icon> {{ uitextFileProblem }}
-        </mat-list-item>
-      </mat-list>
-    </div>
+        <div class="file-problem" *ngIf="fileProblem">
+            <mat-list role="list">
+                <mat-list-item role="listitem">
+                    <mat-icon color="warn">error_outline</mat-icon> {{ uitextFileProblem }}
+                </mat-list-item>
+            </mat-list>
+        </div>
 
-    <div class="dependencies-problems" *ngIf="dependenciesProblems.length > 0">
-      <mat-list role="list">
-        <mat-list-item role="listitem" *ngFor="let dp of dependenciesProblems">
-          <mat-icon color="warn">error_outline</mat-icon> {{ dp.message }}
-        </mat-list-item>
-      </mat-list>
-      <p>
-        <button mat-raised-button (click)="fixDependencies()"
-            [matBadge]="dependenciesProblems.length" matBadgeColor="warn">
-          {{ uitextFixMissingDependencies }}
-        </button>
-      </p>
+        <div class="dependencies-problems" *ngIf="dependenciesProblems.length > 0">
+            <mat-list role="list">
+                <mat-list-item role="listitem" *ngFor="let dp of dependenciesProblems">
+                    <mat-icon color="warn">error_outline</mat-icon> {{ dp.message }}
+                </mat-list-item>
+            </mat-list>
+            <p>
+                <button mat-raised-button (click)="fixDependencies()" [matBadge]="dependenciesProblems.length"
+                    matBadgeColor="warn">
+                    {{ uitextFixMissingDependencies }}
+                </button>
+            </p>
+        </div>
     </div>
-  </div>
 
-  <div class="cb-container">
-    <mat-checkbox [(ngModel)]="emptyCurrentSession" [ngModelOptions]="{standalone: true}">
-      {{ uitextEmptyCurrentSession }}
-    </mat-checkbox>
-  </div>
+    <div class="cb-container">
+        <mat-checkbox [(ngModel)]="emptyCurrentSession" [ngModelOptions]="{standalone: true}">
+            {{ uitextEmptyCurrentSession }}
+        </mat-checkbox>
+    </div>
 
-  <div mat-dialog-actions [attr.align]="'end'">
-    <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
-      {{ uitextCancel }}
-    </button>
-    <button mat-raised-button type="submit" color="warn" (click)="loadSession()"
-      [disabled]="(loadSessionForm.invalid || ! atLeastOneCheckboxSelected)">
+    <div mat-dialog-actions [attr.align]="'end'">
+        <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
+            {{ uitextCancel }}
+        </button>
+        <button mat-raised-button type="submit" color="warn" (click)="loadSession()"
+            [disabled]="(loadSessionForm.invalid || ! atLeastOneCheckboxSelected)">
 
-      {{ uitextLoad }}
-    </button>
-  </div>
+            {{ uitextLoad }}
+        </button>
+    </div>
 
-</form>
+</form>
\ No newline at end of file
diff --git a/src/app/components/dialog-load-session/dialog-load-session.component.ts b/src/app/components/dialog-load-session/dialog-load-session.component.ts
index 35db621ebc77890b030842f10f329cc7c0fb59ef..653cf5ff55a9376e8ccdce2a7072cb90fa274801 100644
--- a/src/app/components/dialog-load-session/dialog-load-session.component.ts
+++ b/src/app/components/dialog-load-session/dialog-load-session.component.ts
@@ -38,31 +38,31 @@ export class DialogLoadSessionComponent {
     private loadingComplete = false;
 
     constructor(
-      public dialogRef: MatDialogRef<DialogLoadSessionComponent>,
-      private intlService: I18nService,
-      private fb: FormBuilder,
-      @Inject(MAT_DIALOG_DATA) public data: any
+        public dialogRef: MatDialogRef<DialogLoadSessionComponent>,
+        private intlService: I18nService,
+        private fb: FormBuilder,
+        @Inject(MAT_DIALOG_DATA) public data: any
     ) {
-      this.loadSessionForm = this.fb.group({
-        file: [null, Validators.required]
-      });
-      this.libFormatVersion = config.serialisation.fileFormatVersion;
+        this.loadSessionForm = this.fb.group({
+            file: [null, Validators.required]
+        });
+        this.libFormatVersion = config.serialisation.fileFormatVersion;
     }
 
     public selectAll() {
-      for (const c of this.calculators) {
-        c.selected = true;
-      }
-      // re-run dependency checking
-      this.checkLinkedParamsAndModelsDependencies();
+        for (const c of this.calculators) {
+            c.selected = true;
+        }
+        // re-run dependency checking
+        this.checkLinkedParamsAndModelsDependencies();
     }
 
     public selectNone() {
-      for (const c of this.calculators) {
-        c.selected = false;
-      }
-      // re-run dependency checking
-      this.checkLinkedParamsAndModelsDependencies();
+        for (const c of this.calculators) {
+            c.selected = false;
+        }
+        // re-run dependency checking
+        this.checkLinkedParamsAndModelsDependencies();
     }
 
     /**
@@ -71,186 +71,186 @@ export class DialogLoadSessionComponent {
      *  - PabCloisons depend on their models
      */
     public checkLinkedParamsAndModelsDependencies() {
-      this.dependenciesProblems = [];
-      // for all checked Nubs
-      this.calculators.forEach((c) => {
-        if (c.selected) {
-          // do all required nubs are checked ?
-          c.requires.forEach((r) => {
-            if (! this.isCalculatorOrParentSelected(r)) {
-              const realUid = this.getUidOrParentUid(r);
-              const depTitle = this.getTitleFromUid(realUid);
-              this.dependenciesProblems.push({
-                requiring: c.title,
-                required: depTitle,
-                requiredUid: realUid,
-                message: c.title + " " + this.intlService.localizeText("INFO_REQUIRES") + " " + depTitle
-              });
+        this.dependenciesProblems = [];
+        // for all checked Nubs
+        this.calculators.forEach((c) => {
+            if (c.selected) {
+                // do all required nubs are checked ?
+                c.requires.forEach((r) => {
+                    if (!this.isCalculatorOrParentSelected(r)) {
+                        const realUid = this.getUidOrParentUid(r);
+                        const depTitle = this.getTitleFromUid(realUid);
+                        this.dependenciesProblems.push({
+                            requiring: c.title,
+                            required: depTitle,
+                            requiredUid: realUid,
+                            message: c.title + " " + this.intlService.localizeText("INFO_REQUIRES") + " " + depTitle
+                        });
+                    }
+                });
             }
-          });
-        }
-      });
+        });
     }
 
     public fixDependencies() {
-      for (const dp of this.dependenciesProblems) {
-        this.selectRequiredModule(dp.requiredUid);
-      }
+        for (const dp of this.dependenciesProblems) {
+            this.selectRequiredModule(dp.requiredUid);
+        }
     }
 
     private isCalculatorOrParentSelected(uid: string): boolean {
-      let isSelected = false;
-      this.calculators.forEach((c) => {
-        if (c.uid === uid || c.children.includes(uid)) {
-          isSelected = c.selected;
-        }
-      });
-      return isSelected;
+        let isSelected = false;
+        this.calculators.forEach((c) => {
+            if (c.uid === uid || c.children.includes(uid)) {
+                isSelected = c.selected;
+            }
+        });
+        return isSelected;
     }
 
     private getUidOrParentUid(uid: string): string {
-      let realUid: string;
-      this.calculators.forEach((c) => {
-        if (c.uid === uid || c.children.includes(uid)) {
-          realUid = c.uid;
-        }
-      });
-      return realUid;
+        let realUid: string;
+        this.calculators.forEach((c) => {
+            if (c.uid === uid || c.children.includes(uid)) {
+                realUid = c.uid;
+            }
+        });
+        return realUid;
     }
 
     private getTitleFromUid(uid: string): string {
-      let title: string;
-      this.calculators.forEach((c) => {
-        if (c.uid === uid) {
-          title = c.title;
-        }
-      });
-      return title;
+        let title: string;
+        this.calculators.forEach((c) => {
+            if (c.uid === uid) {
+                title = c.title;
+            }
+        });
+        return title;
     }
 
     private selectRequiredModule(uid: string) {
-      this.calculators.forEach((c) => {
-        if (c.uid === uid) {
-          c.selected = true;
-        }
-      });
-      // re-run dependency checking
-      this.checkLinkedParamsAndModelsDependencies();
+        this.calculators.forEach((c) => {
+            if (c.uid === uid) {
+                c.selected = true;
+            }
+        });
+        // re-run dependency checking
+        this.checkLinkedParamsAndModelsDependencies();
     }
 
     public onFileSelected(event: any) {
-      if (event.target.files && event.target.files.length) {
-        this.file = event.target.files[0];
-        // reinit file infos
-        this.calculators = [];
-        this.fileFormatVersion = "";
-        // reinit flags
-        this.loadingError = false;
-        this.loadingComplete = false;
-
-        const formService = ServiceFactory.formulaireService;
-        formService.calculatorInfosFromSessionFile(this.file).then(
-          calcInfos => {
-            this.fileFormatVersion = calcInfos.formatVersion;
-            this.calculators = calcInfos.nubs;
-            for (const n of this.calculators) {
-              n.selected = true;
-              // if no title was given, generate a default one
-              if (! n.title) {
-                n.title = decode(formService.getLocalisedShortTitleFromCalculatorType(n.type));
-              }
-            }
-            this.loadingComplete = true;
-          }
-        ).catch((err) => {
-          console.error(err);
-          this.loadingError = true;
-        });
-      }
+        if (event.target.files && event.target.files.length) {
+            this.file = event.target.files[0];
+            // reinit file infos
+            this.calculators = [];
+            this.fileFormatVersion = "";
+            // reinit flags
+            this.loadingError = false;
+            this.loadingComplete = false;
+
+            const formService = ServiceFactory.formulaireService;
+            formService.calculatorInfosFromSessionFile(this.file).then(
+                calcInfos => {
+                    this.fileFormatVersion = calcInfos.formatVersion;
+                    this.calculators = calcInfos.nubs;
+                    for (const n of this.calculators) {
+                        n.selected = true;
+                        // if no title was given, generate a default one
+                        if (!n.title) {
+                            n.title = decode(formService.getLocalisedShortTitleFromCalculatorType(n.type));
+                        }
+                    }
+                    this.loadingComplete = true;
+                }
+            ).catch((err) => {
+                console.error(err);
+                this.loadingError = true;
+            });
+        }
     }
 
     public loadSession() {
-      this.dialogRef.close({
-        calculators: this.calculators,
-        file: this.file,
-        emptySession: this.emptyCurrentSession
-      });
+        this.dialogRef.close({
+            calculators: this.calculators,
+            file: this.file,
+            emptySession: this.emptyCurrentSession
+        });
     }
 
     public get atLeastOneCheckboxSelected() {
-      let ok = false;
-      for (const c of this.calculators) {
-        ok = (ok || c.selected);
-      }
-      return ok;
+        let ok = false;
+        for (const c of this.calculators) {
+            ok = (ok || c.selected);
+        }
+        return ok;
     }
 
     /**
      * @returns true if any problem occurred during file loading
      */
     public get fileProblem(): boolean {
-      return (
-        this.loadingError
-        ||
-        this.fileFormatVersionProblem()
-        ||
-        this.fileIsEmpty()
-      );
+        return (
+            this.loadingError
+            ||
+            this.fileFormatVersionProblem()
+            ||
+            this.fileIsEmpty()
+        );
     }
 
     private fileFormatVersionProblem(): boolean {
-      return this.fileFormatVersion && (this.fileFormatVersion !== this.libFormatVersion);
+        return this.fileFormatVersion && (this.fileFormatVersion !== this.libFormatVersion);
     }
 
     private fileIsEmpty(): boolean {
-      return this.loadingComplete && this.calculators.length === 0;
+        return this.loadingComplete && this.calculators.length === 0;
     }
 
     public get uitextLoad() {
-      return this.intlService.localizeText("INFO_OPTION_LOAD");
+        return this.intlService.localizeText("INFO_OPTION_LOAD");
     }
 
     public get uitextCancel() {
-      return this.intlService.localizeText("INFO_OPTION_CANCEL");
+        return this.intlService.localizeText("INFO_OPTION_CANCEL");
     }
 
     public get uitextAll() {
-      return this.intlService.localizeText("INFO_OPTION_ALL");
+        return this.intlService.localizeText("INFO_OPTION_ALL");
     }
 
     public get uitextNone() {
-      return this.intlService.localizeText("INFO_OPTION_NONE");
+        return this.intlService.localizeText("INFO_OPTION_NONE");
     }
 
     public get uitextLoadSessionFilename() {
-      return this.intlService.localizeText("INFO_DIALOG_LOAD_SESSION_FILENAME");
+        return this.intlService.localizeText("INFO_DIALOG_LOAD_SESSION_FILENAME");
     }
 
     public get uitextLoadSessionTitle() {
-      return this.intlService.localizeText("INFO_DIALOG_LOAD_SESSION_TITLE");
+        return this.intlService.localizeText("INFO_DIALOG_LOAD_SESSION_TITLE");
     }
 
     public get uitextFixMissingDependencies() {
-      return this.intlService.localizeText("INFO_DIALOG_FIX_MISSING_DEPENDENCIES");
+        return this.intlService.localizeText("INFO_DIALOG_FIX_MISSING_DEPENDENCIES");
     }
 
     public get uitextEmptyCurrentSession() {
-      return this.intlService.localizeText("INFO_DIALOG_EMPTY_CURRENT_SESSION");
+        return this.intlService.localizeText("INFO_DIALOG_EMPTY_CURRENT_SESSION");
     }
 
     public get uitextFileProblem() {
-      if (this.loadingError) {
-        return this.intlService.localizeText("INFO_DIALOG_ERROR_LOADING_FILE");
-      }
-      if (this.fileFormatVersionProblem()) {
-        return sprintf(
-          this.intlService.localizeText("INFO_DIALOG_FORMAT_VERSIONS_MISMATCH"),
-          this.fileFormatVersion,
-          this.libFormatVersion
-        );
-      }
-      if (this.fileIsEmpty()) {
-        return this.intlService.localizeText("INFO_DIALOG_FILE_IS_EMPTY");
-      }
+        if (this.loadingError) {
+            return this.intlService.localizeText("INFO_DIALOG_ERROR_LOADING_FILE");
+        }
+        if (this.fileFormatVersionProblem()) {
+            return sprintf(
+                this.intlService.localizeText("INFO_DIALOG_FORMAT_VERSIONS_MISMATCH"),
+                this.fileFormatVersion,
+                this.libFormatVersion
+            );
+        }
+        if (this.fileIsEmpty()) {
+            return this.intlService.localizeText("INFO_DIALOG_FILE_IS_EMPTY");
+        }
     }
 }
diff --git a/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.html b/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.html
index a5dd7a17fd6216ee1eec3f6ff2504e15a21a2b7f..ad7493bec95630fb7e629cf9ebdb94e171f6ec35 100644
--- a/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.html
+++ b/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.html
@@ -4,7 +4,7 @@
     <log-entry *ngFor="let m of data.messages" [_message]="m"></log-entry>
 </div>
 <div mat-dialog-actions [attr.align]="'end'">
-  <button mat-raised-button [mat-dialog-close]="true">
-    {{ uitextClose }}
-  </button>
-</div>
+    <button mat-raised-button [mat-dialog-close]="true">
+        {{ uitextClose }}
+    </button>
+</div>
\ No newline at end of file
diff --git a/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.ts b/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.ts
index b9669a32f9330f0301025a41bfc112c11061125f..08be1c7121c29207e0ed708ef54c446700d9012e 100644
--- a/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.ts
+++ b/src/app/components/dialog-log-entries-details/dialog-log-entries-details.component.ts
@@ -15,10 +15,10 @@ export class DialogLogEntriesDetailsComponent {
     ) { }
 
     public get uitextLogEntriesDetailsTitle() {
-      return this.intlService.localizeText("INFO_TITREJOURNAL");
+        return this.intlService.localizeText("INFO_TITREJOURNAL");
     }
 
     public get uitextClose() {
-      return this.intlService.localizeText("INFO_OPTION_CLOSE");
+        return this.intlService.localizeText("INFO_OPTION_CLOSE");
     }
 }
diff --git a/src/app/components/dialog-save-session/dialog-save-session.component.html b/src/app/components/dialog-save-session/dialog-save-session.component.html
index 4e522ee37715e047227c5e56381d47fe263e22c8..4d15ec7f098dcb721ade121c273e2fb65218139b 100644
--- a/src/app/components/dialog-save-session/dialog-save-session.component.html
+++ b/src/app/components/dialog-save-session/dialog-save-session.component.html
@@ -2,48 +2,48 @@
 
 <form>
 
-  <div mat-dialog-content>
-    <div class="cb-container">
-      <mat-checkbox [name]="c.uid" *ngFor="let c of calculators" [(ngModel)]="c.selected"
-        (change)="checkLinkedParamsAndModelsDependencies()">
-        {{ c.title }}
-      </mat-checkbox>
+    <div mat-dialog-content>
+        <div class="cb-container">
+            <mat-checkbox [name]="c.uid" *ngFor="let c of calculators" [(ngModel)]="c.selected"
+                (change)="checkLinkedParamsAndModelsDependencies()">
+                {{ c.title }}
+            </mat-checkbox>
+        </div>
+
+        <div class="btn-container">
+            <button mat-raised-button (click)="selectAll()">{{ uitextAll }}</button>
+            <button mat-raised-button (click)="selectNone()">{{ uitextNone }}</button>
+        </div>
+
+        <div class="dependencies-problems" *ngIf="dependenciesProblems.length > 0">
+            <mat-list role="list">
+                <mat-list-item role="listitem" *ngFor="let dp of dependenciesProblems">
+                    <mat-icon color="warn">error_outline</mat-icon> {{ dp.message }}
+                </mat-list-item>
+            </mat-list>
+            <p>
+                <button mat-raised-button (click)="fixDependencies()" [matBadge]="dependenciesProblems.length"
+                    matBadgeColor="warn">
+                    {{ uitextFixMissingDependencies }}
+                </button>
+            </p>
+        </div>
+
+        <mat-form-field>
+            <input matInput required [placeholder]="uitextFilenameInput" [(ngModel)]="fileName" name="filename"
+                #filename="ngModel" (keydown.enter)="onEnterPressed($event)">
+        </mat-form-field>
     </div>
 
-    <div class="btn-container">
-      <button mat-raised-button (click)="selectAll()">{{ uitextAll }}</button>
-      <button mat-raised-button (click)="selectNone()">{{ uitextNone }}</button>
-    </div>
+    <div mat-dialog-actions [attr.align]="'end'">
+        <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
+            {{ uitextCancel }}
+        </button>
+        <button mat-raised-button type="submit" color="warn" (click)="saveSession()"
+            [disabled]="(! filename.valid) || (! atLeastOneCheckboxSelected)">
 
-    <div class="dependencies-problems" *ngIf="dependenciesProblems.length > 0">
-      <mat-list role="list">
-        <mat-list-item role="listitem" *ngFor="let dp of dependenciesProblems">
-          <mat-icon color="warn">error_outline</mat-icon> {{ dp.message }}
-        </mat-list-item>
-      </mat-list>
-      <p>
-        <button mat-raised-button (click)="fixDependencies()"
-            [matBadge]="dependenciesProblems.length" matBadgeColor="warn">
-          {{ uitextFixMissingDependencies }}
+            {{ uitextSave }}
         </button>
-      </p>
     </div>
 
-    <mat-form-field>
-      <input matInput required [placeholder]="uitextFilenameInput" [(ngModel)]="fileName"
-        name="filename" #filename="ngModel" (keydown.enter)="onEnterPressed($event)">
-    </mat-form-field>
-  </div>
-
-  <div mat-dialog-actions [attr.align]="'end'">
-    <button mat-raised-button color="primary" [mat-dialog-close]="false" cdkFocusInitial>
-      {{ uitextCancel }}
-    </button>
-    <button mat-raised-button type="submit" color="warn" (click)="saveSession()"
-      [disabled]="(! filename.valid) || (! atLeastOneCheckboxSelected)">
-
-      {{ uitextSave }}
-    </button>
-  </div>
-
-</form>
+</form>
\ No newline at end of file
diff --git a/src/app/components/dialog-save-session/dialog-save-session.component.ts b/src/app/components/dialog-save-session/dialog-save-session.component.ts
index 092b245f2b2488233b41b2373af191d4feb7dcbc..b9b5eb10d56a2954927293edf5ec194409b00861 100644
--- a/src/app/components/dialog-save-session/dialog-save-session.component.ts
+++ b/src/app/components/dialog-save-session/dialog-save-session.component.ts
@@ -16,29 +16,29 @@ export class DialogSaveSessionComponent {
     public dependenciesProblems: any[] = [];
 
     constructor(
-      public dialogRef: MatDialogRef<DialogSaveSessionComponent>,
-      private intlService: I18nService,
-      @Inject(MAT_DIALOG_DATA) public data: any
+        public dialogRef: MatDialogRef<DialogSaveSessionComponent>,
+        private intlService: I18nService,
+        @Inject(MAT_DIALOG_DATA) public data: any
     ) {
-      this.calculators = data.calculators;
-      // run dependency checking at first
-      this.checkLinkedParamsAndModelsDependencies();
+        this.calculators = data.calculators;
+        // run dependency checking at first
+        this.checkLinkedParamsAndModelsDependencies();
     }
 
     public selectAll() {
-      for (const c of this.calculators) {
-          c.selected = true;
-      }
-      // re-run dependency checking
-      this.checkLinkedParamsAndModelsDependencies();
+        for (const c of this.calculators) {
+            c.selected = true;
+        }
+        // re-run dependency checking
+        this.checkLinkedParamsAndModelsDependencies();
     }
 
     public selectNone() {
-      for (const c of this.calculators) {
-        c.selected = false;
-      }
-      // re-run dependency checking
-      this.checkLinkedParamsAndModelsDependencies();
+        for (const c of this.calculators) {
+            c.selected = false;
+        }
+        // re-run dependency checking
+        this.checkLinkedParamsAndModelsDependencies();
     }
 
     /**
@@ -47,114 +47,114 @@ export class DialogSaveSessionComponent {
      *  - PabCloisons depend on their models
      */
     public checkLinkedParamsAndModelsDependencies() {
-      this.dependenciesProblems = [];
-      // for all checked Nubs
-      this.calculators.forEach((c) => {
-        if (c.selected) {
-          // do all required nubs are checked ?
-          c.requires.forEach((r) => {
-            if (! this.isCalculatorOrParentSelected(r)) {
-              const realUid = this.getUidOrParentUid(r);
-              const depTitle = this.getTitleFromUid(realUid);
-              this.dependenciesProblems.push({
-                requiring: c.title,
-                required: depTitle,
-                requiredUid: realUid,
-                message: c.title + " " + this.intlService.localizeText("INFO_REQUIRES") + " " + depTitle
-              });
+        this.dependenciesProblems = [];
+        // for all checked Nubs
+        this.calculators.forEach((c) => {
+            if (c.selected) {
+                // do all required nubs are checked ?
+                c.requires.forEach((r) => {
+                    if (!this.isCalculatorOrParentSelected(r)) {
+                        const realUid = this.getUidOrParentUid(r);
+                        const depTitle = this.getTitleFromUid(realUid);
+                        this.dependenciesProblems.push({
+                            requiring: c.title,
+                            required: depTitle,
+                            requiredUid: realUid,
+                            message: c.title + " " + this.intlService.localizeText("INFO_REQUIRES") + " " + depTitle
+                        });
+                    }
+                });
             }
-          });
-        }
-      });
+        });
     }
 
     public fixDependencies() {
-      for (const dp of this.dependenciesProblems) {
-        this.selectRequiredModule(dp.requiredUid);
-      }
+        for (const dp of this.dependenciesProblems) {
+            this.selectRequiredModule(dp.requiredUid);
+        }
     }
 
     private isCalculatorOrParentSelected(uid: string): boolean {
-      let isSelected = false;
-      this.calculators.forEach((c) => {
-        if (c.uid === uid || c.children.includes(uid)) {
-          isSelected = c.selected;
-        }
-      });
-      return isSelected;
+        let isSelected = false;
+        this.calculators.forEach((c) => {
+            if (c.uid === uid || c.children.includes(uid)) {
+                isSelected = c.selected;
+            }
+        });
+        return isSelected;
     }
 
     private getUidOrParentUid(uid: string): string {
-      let realUid: string;
-      this.calculators.forEach((c) => {
-        if (c.uid === uid || c.children.includes(uid)) {
-          realUid = c.uid;
-        }
-      });
-      return realUid;
+        let realUid: string;
+        this.calculators.forEach((c) => {
+            if (c.uid === uid || c.children.includes(uid)) {
+                realUid = c.uid;
+            }
+        });
+        return realUid;
     }
 
     private getTitleFromUid(uid: string): string {
-      let title: string;
-      this.calculators.forEach((c) => {
-        if (c.uid === uid) {
-          title = c.title;
-        }
-      });
-      return title;
+        let title: string;
+        this.calculators.forEach((c) => {
+            if (c.uid === uid) {
+                title = c.title;
+            }
+        });
+        return title;
     }
 
     private selectRequiredModule(uid: string) {
-      this.calculators.forEach((c) => {
-        if (c.uid === uid) {
-          c.selected = true;
-        }
-      });
-      // re-run dependency checking
-      this.checkLinkedParamsAndModelsDependencies();
+        this.calculators.forEach((c) => {
+            if (c.uid === uid) {
+                c.selected = true;
+            }
+        });
+        // re-run dependency checking
+        this.checkLinkedParamsAndModelsDependencies();
     }
 
     public saveSession() {
-      this.dialogRef.close({
-        calculators: this.calculators,
-        filename: this.fileName
-      });
+        this.dialogRef.close({
+            calculators: this.calculators,
+            filename: this.fileName
+        });
     }
 
     public get atLeastOneCheckboxSelected() {
-      let ok = false;
-      for (const c of this.calculators) {
-        ok = (ok || c.selected);
-      }
-      return ok;
+        let ok = false;
+        for (const c of this.calculators) {
+            ok = (ok || c.selected);
+        }
+        return ok;
     }
 
     public get uitextSave() {
-      return this.intlService.localizeText("INFO_OPTION_SAVE");
+        return this.intlService.localizeText("INFO_OPTION_SAVE");
     }
 
     public get uitextCancel() {
-      return this.intlService.localizeText("INFO_OPTION_CANCEL");
+        return this.intlService.localizeText("INFO_OPTION_CANCEL");
     }
 
     public get uitextAll() {
-      return this.intlService.localizeText("INFO_OPTION_ALL");
+        return this.intlService.localizeText("INFO_OPTION_ALL");
     }
 
     public get uitextNone() {
-      return this.intlService.localizeText("INFO_OPTION_NONE");
+        return this.intlService.localizeText("INFO_OPTION_NONE");
     }
 
     public get uitextSaveSessionTitle() {
-      return this.intlService.localizeText("INFO_DIALOG_SAVE_SESSION_TITLE");
+        return this.intlService.localizeText("INFO_DIALOG_SAVE_SESSION_TITLE");
     }
 
     public get uitextFilenameInput() {
-      return this.intlService.localizeText("INFO_DIALOG_SAVE_SESSION_FILENAME");
+        return this.intlService.localizeText("INFO_DIALOG_SAVE_SESSION_FILENAME");
     }
 
     public get uitextFixMissingDependencies() {
-      return this.intlService.localizeText("INFO_DIALOG_FIX_MISSING_DEPENDENCIES");
+        return this.intlService.localizeText("INFO_DIALOG_FIX_MISSING_DEPENDENCIES");
     }
 
     public onEnterPressed(event) {
diff --git a/src/app/components/field-set/field-set.component.html b/src/app/components/field-set/field-set.component.html
index 59f755bbc1c8a46dfd8d56423b9c916274cc2edc..808d883ec6ebc96030ee985ddf107647ff5c820f 100644
--- a/src/app/components/field-set/field-set.component.html
+++ b/src/app/components/field-set/field-set.component.html
@@ -9,25 +9,31 @@
                     {{ i }}
                 </mat-option>
             </mat-select>
-            <button type="button" mat-icon-button (click)="onAddClick()" class="add-structure" [title]="uitextAddStructure">
+            <button type="button" mat-icon-button (click)="onAddClick()" class="add-structure"
+                [title]="uitextAddStructure">
                 <mat-icon>add_box</mat-icon>
             </button>
-            <button type="button" mat-icon-button (click)="onCopyClick()" class="copy-structure" [title]="uitextCopyStructure">
+            <button type="button" mat-icon-button (click)="onCopyClick()" class="copy-structure"
+                [title]="uitextCopyStructure">
                 <mat-icon>content_copy</mat-icon>
             </button>
             |
-            <button type="button" mat-icon-button [disabled]="! enableRemoveButton" (click)="onRemoveClick()" [title]="uitextRemoveStructure">
+            <button type="button" mat-icon-button [disabled]="! enableRemoveButton" (click)="onRemoveClick()"
+                [title]="uitextRemoveStructure">
                 <mat-icon>delete</mat-icon>
             </button>
-            <button type="button" mat-icon-button [disabled]="! enableUpButton" (click)="onMoveUpClick()" [title]="uitextMoveStructureUp">
+            <button type="button" mat-icon-button [disabled]="! enableUpButton" (click)="onMoveUpClick()"
+                [title]="uitextMoveStructureUp">
                 <mat-icon>arrow_upward</mat-icon>
             </button>
-            <button type="button" mat-icon-button [disabled]="! enableDownButton" (click)="onMoveDownClick()" [title]="uitextMoveStructureDown">
+            <button type="button" mat-icon-button [disabled]="! enableDownButton" (click)="onMoveDownClick()"
+                [title]="uitextMoveStructureDown">
                 <mat-icon>arrow_downward</mat-icon>
             </button>
             <span *ngIf="enableHelpButton">|</span>
         </span>
-        <button *ngIf="enableHelpButton" class="help-button" type="button" mat-icon-button  (click)="openHelp()" [title]="uitextOpenHelp">
+        <button *ngIf="enableHelpButton" class="help-button" type="button" mat-icon-button (click)="openHelp()"
+            [title]="uitextOpenHelp">
             <mat-icon id="help-fieldset">help</mat-icon>
         </button>
     </div>
@@ -42,4 +48,4 @@
         <select-field-line *ngIf="isSelectField(p)" [_select]=p>
         </select-field-line>
     </ng-template>
-</mat-card-content>
+</mat-card-content>
\ No newline at end of file
diff --git a/src/app/components/fixedvar-results/fixed-results.component.html b/src/app/components/fixedvar-results/fixed-results.component.html
index 723677e79fb13a4e5c7fa563f1e70426865ec8bc..d9bca96253f0a62db118c20b9cf88b8dd74cd0e9 100644
--- a/src/app/components/fixedvar-results/fixed-results.component.html
+++ b/src/app/components/fixedvar-results/fixed-results.component.html
@@ -12,15 +12,17 @@
 
             <ng-container matColumnDef="parametre">
                 <th mat-header-cell *matHeaderCellDef>{{ uitextParamFixes }}</th>
-                <td mat-cell *matCellDef="let element" [innerHTML]="element.label" [ngClass]="{'highlightedResult': element.isCalcResult}"></td>
+                <td mat-cell *matCellDef="let element" [innerHTML]="element.label"
+                    [ngClass]="{'highlightedResult': element.isCalcResult}"></td>
             </ng-container>
             <ng-container matColumnDef="valeur">
                 <th mat-header-cell *matHeaderCellDef>{{ uitextValeurs }}</th>
-                <td mat-cell *matCellDef="let element" [ngClass]="{'highlightedResult': element.isCalcResult}">{{ element.value }}</td>
+                <td mat-cell *matCellDef="let element" [ngClass]="{'highlightedResult': element.isCalcResult}">
+                    {{ element.value }}</td>
             </ng-container>
 
             <tr mat-header-row *matHeaderRowDef="tableColumns"></tr>
             <tr mat-row *matRowDef="let row; columns: tableColumns;"></tr>
         </table>
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/fixedvar-results/var-results.component.html b/src/app/components/fixedvar-results/var-results.component.html
index d0b7573043567e68b5dc6fc90cf88e524030184b..f09451b74bf318085fa597b5465ff9b8c5497fbf 100644
--- a/src/app/components/fixedvar-results/var-results.component.html
+++ b/src/app/components/fixedvar-results/var-results.component.html
@@ -1,10 +1,12 @@
-<div class="var-results-container" #variableResults *ngIf="hasResults" fxLayout="row wrap" fxLayoutAlign="center center">
+<div class="var-results-container" #variableResults *ngIf="hasResults" fxLayout="row wrap"
+    fxLayoutAlign="center center">
     <div fxFlex="1 1 100%">
         <div class="var-results-buttons">
             <button mat-icon-button (click)="exportAsSpreadsheet()" [title]="uitextExportAsSpreadsheet">
                 <mat-icon color="primary">file_download</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(variableResults)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(variableResults)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
@@ -42,4 +44,4 @@
             </div>
         </div>
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html
index ed13135eece9743da8e163b6ecf7a605df26d52b..f5ccefc0fd6f60664002184281dd7510c3ac9c52 100644
--- a/src/app/components/generic-calculator/calculator.component.html
+++ b/src/app/components/generic-calculator/calculator.component.html
@@ -4,7 +4,8 @@
 
         <div class="hyd-window-btns">
             <!-- bouton d'aide -->
-            <mat-icon id="help-calc" *ngIf="enableHelpButton" (click)="openHelp()" color="accent" [title]="uitextOpenHelp">
+            <mat-icon id="help-calc" *ngIf="enableHelpButton" (click)="openHelp()" color="accent"
+                [title]="uitextOpenHelp">
                 help
             </mat-icon>
             <!-- bouton de duplication -->
@@ -27,7 +28,7 @@
             <h1 [innerHTML]="uitextTitre"></h1>
             <div id="calculator-used-by" *ngIf="calculatorsUsingThisOne.length > 0">
                 {{ uitextUsedBy }}
-                <span *ngFor="let c of calculatorsUsingThisOne; let i = index; trackBy:tbIndex" >
+                <span *ngFor="let c of calculatorsUsingThisOne; let i = index; trackBy:tbIndex">
                     <a class="used-by-item" (click)="toCalc(c.uid)">
                         {{ c.label }}
                     </a>
@@ -48,29 +49,28 @@
             <calc-name id="calculator-name" [title]="uitextCalculatorName"></calc-name>
 
             <button mat-raised-button type="button" color="accent" id="load-predefined-espece" *ngIf="isEspece"
-              (click)="loadPredefinedEspece()" [title]="uitextLoadPredefinedEspece">
+                (click)="loadPredefinedEspece()" [title]="uitextLoadPredefinedEspece">
                 {{ uitextLoadPredefinedEspece }}
             </button>
 
-            <div id="calc-cards-container" class="container"
-              [fxLayout]="isWide ? 'column' : 'row wrap'"
-              [fxLayoutAlign]="isWide ? 'space-around stretch' : 'space-around start'">
+            <div id="calc-cards-container" class="container" [fxLayout]="isWide ? 'column' : 'row wrap'"
+                [fxLayoutAlign]="isWide ? 'space-around stretch' : 'space-around start'">
 
                 <!-- chapitres -->
-                <mat-card id="calc-card-field-sets"
-                  [class.pab-field-sets]="isWide"
-                  [fxFlex.gt-sm]="isWide ? '1 0 auto' : '1 0 400px'"
-                  [fxFlex.lt-md]="isWide ? '1 0 auto' : '1 0 500px'"
-                  [fxFlex.lt-sm]="isWide ? '1 0 auto' : '1 0 300px'">
+                <mat-card id="calc-card-field-sets" [class.pab-field-sets]="isWide"
+                    [fxFlex.gt-sm]="isWide ? '1 0 auto' : '1 0 400px'"
+                    [fxFlex.lt-md]="isWide ? '1 0 auto' : '1 0 500px'"
+                    [fxFlex.lt-sm]="isWide ? '1 0 auto' : '1 0 300px'">
 
                     <ng-template ngFor let-fe [ngForOf]="formElements">
                         <field-set *ngIf="isFieldset(fe)" [style.display]="getElementStyleDisplay(fe.id)" [fieldSet]=fe
-                            (radio)=onRadioClick($event) (validChange)=onElementValid() (inputChange)=onInputChange($event)
-                            (tabPressed)="onTabPressed($event)">
+                            (radio)=onRadioClick($event) (validChange)=onElementValid()
+                            (inputChange)=onInputChange($event) (tabPressed)="onTabPressed($event)">
                         </field-set>
 
-                        <fieldset-container *ngIf="isFieldsetContainer(fe)" [style.display]="getElementStyleDisplay(fe.id)" [_container]=fe
-                            (radio)=onRadioClick($event) (validChange)=onElementValid() (inputChange)=onInputChange($event)
+                        <fieldset-container *ngIf="isFieldsetContainer(fe)"
+                            [style.display]="getElementStyleDisplay(fe.id)" [_container]=fe (radio)=onRadioClick($event)
+                            (validChange)=onElementValid() (inputChange)=onInputChange($event)
                             (tabPressed)="onTabPressed($event)">
                         </fieldset-container>
 
@@ -82,23 +82,23 @@
                     <mat-card-actions>
                         <!-- bouton calculer -->
                         <button type="submit" id="trigger-calculate" mat-raised-button color="accent" name="Calculer"
-                          (click)="doCompute()" [disabled]="isCalculateDisabled" [hidden]="calculateDisabledPermanently">
+                            (click)="doCompute()" [disabled]="isCalculateDisabled"
+                            [hidden]="calculateDisabledPermanently">
                             {{ uitextCalculer }}
                         </button>
                     </mat-card-actions>
                 </mat-card>
 
                 <!-- résultats -->
-                <mat-card id="calc-card-results"
-                  [hidden]="calculateDisabledPermanently"
-                  [class.pab-results]="isWide"
-                  [fxFlex.gt-sm]="isWide ? '1 0 auto' : '1 0 400px'"
-                  [fxFlex.lt-md]="isWide ? '1 0 auto' : '1 0 500px'"
-                  [fxFlex.lt-sm]="isWide ? '1 0 auto' : '1 0 300px'">
+                <mat-card id="calc-card-results" [hidden]="calculateDisabledPermanently" [class.pab-results]="isWide"
+                    [fxFlex.gt-sm]="isWide ? '1 0 auto' : '1 0 400px'"
+                    [fxFlex.lt-md]="isWide ? '1 0 auto' : '1 0 500px'"
+                    [fxFlex.lt-sm]="isWide ? '1 0 auto' : '1 0 300px'">
 
                     <div id="fake-results-anchor"></div>
 
-                    <quicknav [ngClass.lt-xs]="'extraSmall'" [fxHide.gt-sm]="! isWide" [items]="quicknavItems" [currentItem]="'results'" [align]="'left'"></quicknav>
+                    <quicknav [ngClass.lt-xs]="'extraSmall'" [fxHide.gt-sm]="! isWide" [items]="quicknavItems"
+                        [currentItem]="'results'" [align]="'left'"></quicknav>
 
                     <mat-card-header *ngIf="! isWide" [fxHide.lt-md]="! isWide">
                         <mat-card-title>
@@ -106,8 +106,8 @@
                         </mat-card-title>
                     </mat-card-header>
 
-                    <button mat-raised-button color="accent" id="generate-pab" *ngIf="isPABCloisons" (click)="generatePAB()"
-                        [disabled]="! generatePABEnabled" [title]="uitextGeneratePabTitle">
+                    <button mat-raised-button color="accent" id="generate-pab" *ngIf="isPABCloisons"
+                        (click)="generatePAB()" [disabled]="! generatePABEnabled" [title]="uitextGeneratePabTitle">
                         {{ uitextGeneratePAB }}
                     </button>
 
@@ -122,13 +122,14 @@
                         </button>
                     </div>
 
-                    <button mat-raised-button color="accent" id="generate-ru-sp" *ngIf="isRegimeUniforme" (click)="generateRuSp()"
-                        [disabled]="! generateRuSpEnabled" [title]="uitextGenerateRuSpTitle">
+                    <button mat-raised-button color="accent" id="generate-ru-sp" *ngIf="isRegimeUniforme"
+                        (click)="generateRuSp()" [disabled]="! generateRuSpEnabled" [title]="uitextGenerateRuSpTitle">
                         {{ uitextGenerateRuSp }}
                     </button>
 
-                    <button mat-raised-button color="accent" id="generate-par-simulation" *ngIf="isPAR" (click)="generatePARSimulation()"
-                        [disabled]="! generatePARSimulationEnabled" [title]="uitextGenerateParSimulationTitle">
+                    <button mat-raised-button color="accent" id="generate-par-simulation" *ngIf="isPAR"
+                        (click)="generatePARSimulation()" [disabled]="! generatePARSimulationEnabled"
+                        [title]="uitextGenerateParSimulationTitle">
                         {{ uitextGeneratePARSimulation }}
                     </button>
 
@@ -142,4 +143,4 @@
 
     </form>
 
-</mat-card>
+</mat-card>
\ No newline at end of file
diff --git a/src/app/components/generic-input/generic-input.component.html b/src/app/components/generic-input/generic-input.component.html
index 99eea0a6e607473f831fb1e616b0a1817f6f4b94..3b240e96f6840c8bc13c17a7662cbe120c3cc7e6 100644
--- a/src/app/components/generic-input/generic-input.component.html
+++ b/src/app/components/generic-input/generic-input.component.html
@@ -1,6 +1,6 @@
 <mat-form-field>
-    <input matInput #inputControl="ngModel" class="form-control" type="text" inputmode="numeric"
-        [id]="inputId" [name]="inputId" [disabled]="isDisabled" [(ngModel)]="uiValue" [placeholder]="title"
+    <input matInput #inputControl="ngModel" class="form-control" type="text" inputmode="numeric" [id]="inputId"
+        [name]="inputId" [disabled]="isDisabled" [(ngModel)]="uiValue" [placeholder]="title"
         (keydown.Tab)="onTabPressed($event, false)" (keydown.shift.Tab)="onTabPressed($event, true)"
         pattern="^-?([0-9]*\.)?([0-9]+[Ee]-?)?[0-9]+$" [required]="isRequired">
 
@@ -11,4 +11,4 @@
     </div>
 
     <mat-error [innerHTML]="errorMessage"></mat-error>
-</mat-form-field>
+</mat-form-field>
\ No newline at end of file
diff --git a/src/app/components/generic-select/generic-select.component.html b/src/app/components/generic-select/generic-select.component.html
index 7ce468d11bc4299dcdf02bf5de6c6f5de1a2a222..5dcaf95e7f8ff6c617cd2d2792c395720602f020 100644
--- a/src/app/components/generic-select/generic-select.component.html
+++ b/src/app/components/generic-select/generic-select.component.html
@@ -1,17 +1,18 @@
 <mat-form-field>
-    <mat-select [id]="selectId" [placeholder]="label" [(value)]="selectedValue" [multiple]="isMultiple" [disabled]="isDisabled">
+    <mat-select [id]="selectId" [placeholder]="label" [(value)]="selectedValue" [multiple]="isMultiple"
+        [disabled]="isDisabled">
         <mat-select-trigger *ngIf="isMultiple">
-          {{ selectedValue && selectedValue[0] ? entryLabel(selectedValue[0]) : '' }}
-          <span *ngIf="selectedValue?.length > 1" class="multiple-selection-label">
-            (+ {{ selectedValue.length - 1 }} {{ selectedValue?.length === 2 ? uitextAndOther : uitextAndOthers }})
-          </span>
+            {{ selectedValue && selectedValue[0] ? entryLabel(selectedValue[0]) : '' }}
+            <span *ngIf="selectedValue?.length > 1" class="multiple-selection-label">
+                (+ {{ selectedValue.length - 1 }} {{ selectedValue?.length === 2 ? uitextAndOther : uitextAndOthers }})
+            </span>
         </mat-select-trigger>
         <mat-option *ngFor="let e of entries" [value]="e" [title]="entryLabel(e)">
             {{ entryLabel(e) }}
         </mat-option>
     </mat-select>
-    <button mat-button *ngIf="showClearButton" matSuffix mat-icon-button 
-        aria-label="Clear" (click)="selectedValue=[]; $event.stopPropagation()">
+    <button mat-button *ngIf="showClearButton" matSuffix mat-icon-button aria-label="Clear"
+        (click)="selectedValue=[]; $event.stopPropagation()">
         <mat-icon>close</mat-icon>
     </button>
     <div *ngIf="enableHelpButton" class="overlap-select">
@@ -19,4 +20,4 @@
             help
         </mat-icon>
     </div>
-</mat-form-field>
+</mat-form-field>
\ No newline at end of file
diff --git a/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.html b/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.html
index a30d03c37094423e1225f969015f26bfd659bdd9..1087a424a449b1eaa643bbbf4fbe0b961f547b0e 100644
--- a/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.html
+++ b/src/app/components/jet-trajectory-chart/jet-trajectory-chart.component.html
@@ -7,7 +7,8 @@
             <button mat-icon-button (click)="exportAsImage(graphProfile)" [title]="uitextExportImageTitle">
                 <mat-icon color="primary">image</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphProfile)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphProfile)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
diff --git a/src/app/components/log-drawer/log-drawer.component.html b/src/app/components/log-drawer/log-drawer.component.html
index 4b9bbd8eef67da97b107df279071e8e7147e8887..f2139f7c2cac8da90895a812a9cf9de5c61b3e51 100644
--- a/src/app/components/log-drawer/log-drawer.component.html
+++ b/src/app/components/log-drawer/log-drawer.component.html
@@ -19,6 +19,6 @@
                 </div>
             </div>
         </div>
-        
+
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/macrorugo-compound-results/macrorugo-compound-results-table.component.html b/src/app/components/macrorugo-compound-results/macrorugo-compound-results-table.component.html
index d88bb1753fd6f02918ef90a4f3304895e6e93c80..3883c6eb31b56b8833228e0dd0ae3a483e0b497f 100644
--- a/src/app/components/macrorugo-compound-results/macrorugo-compound-results-table.component.html
+++ b/src/app/components/macrorugo-compound-results/macrorugo-compound-results-table.component.html
@@ -1,10 +1,12 @@
-<div class="macrorugo-compound-results-table-container" #mrcResultsTable fxLayout="row wrap" fxLayoutAlign="center center">
+<div class="macrorugo-compound-results-table-container" #mrcResultsTable fxLayout="row wrap"
+    fxLayoutAlign="center center">
     <div fxFlex="1 1 100%">
         <div class="macrorugo-compound-results-table-buttons">
             <button mat-icon-button (click)="exportAsSpreadsheet()" [title]="uitextExportAsSpreadsheet">
                 <mat-icon color="primary">file_download</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(mrcResultsTable)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(mrcResultsTable)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
@@ -28,4 +30,4 @@
             </div>
         </div>
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.html b/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.html
index bfbf59270881f8afaf8f0123df4f283e3e67a9e9..85b150db8a3bbdc7f23bbd2aa6a88f0f7915fb46 100644
--- a/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.html
+++ b/src/app/components/macrorugo-compound-results/macrorugo-compound-results.component.html
@@ -9,21 +9,23 @@
 
     <div>
         <!-- tableau de résultats -->
-        <macrorugo-compound-results-table *ngIf="hasDisplayableResults" [results]="mrcResults"></macrorugo-compound-results-table>
+        <macrorugo-compound-results-table *ngIf="hasDisplayableResults" [results]="mrcResults">
+        </macrorugo-compound-results-table>
     </div>
 
     <div id="mrcLateralInclination" *ngIf="isInclined">
         <strong [innerHTML]="uitextLateralInclination"></strong> {{ lateralInclination }}
     </div>
 
-    <quicknav *ngIf="hasDisplayableResults" [items]="[ 'input', 'results', 'charts' ]"
-        [currentItem]="'charts'" [align]="'left'"></quicknav>
+    <quicknav *ngIf="hasDisplayableResults" [items]="[ 'input', 'results', 'charts' ]" [currentItem]="'charts'"
+        [align]="'left'"></quicknav>
 
-    <div id="macrorugo-compound-graphs-container" class="container" fxLayout="row wrap" fxLayoutAlign="space-around start">
+    <div id="macrorugo-compound-graphs-container" class="container" fxLayout="row wrap"
+        fxLayoutAlign="space-around start">
         <!-- <pab-profile-chart *ngIf="hasDisplayableResults" fxFlex.gt-xs="1 0 400px" fxFlex.lt-sm="1 0 300px">
         </pab-profile-chart> -->
         <results-chart *ngIf="hasDisplayableResults" fxFlex.gt-xs="1 0 400px" fxFlex.lt-sm="1 0 300px">
         </results-chart>
     </div>
 
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/pab-profile-chart/pab-profile-chart.component.html b/src/app/components/pab-profile-chart/pab-profile-chart.component.html
index ae6745863734aab5955aaae0e6946a6565e3f1a6..35c9c9aecdd6b751495e275b5a1e916150faeb31 100644
--- a/src/app/components/pab-profile-chart/pab-profile-chart.component.html
+++ b/src/app/components/pab-profile-chart/pab-profile-chart.component.html
@@ -7,7 +7,8 @@
             <button mat-icon-button (click)="exportAsImage(graphProfile)" [title]="uitextExportImageTitle">
                 <mat-icon color="primary">image</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphProfile)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphProfile)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
diff --git a/src/app/components/pab-results/pab-results-table.component.html b/src/app/components/pab-results/pab-results-table.component.html
index c7334ca62c7b1dd20ae75a6585d8cc3640f5c9d3..c0e77a7b3809e7e2fd53e83e7ada26b823cde63f 100644
--- a/src/app/components/pab-results/pab-results-table.component.html
+++ b/src/app/components/pab-results/pab-results-table.component.html
@@ -4,7 +4,8 @@
             <button mat-icon-button (click)="exportAsSpreadsheet()" [title]="uitextExportAsSpreadsheet">
                 <mat-icon color="primary">file_download</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(pabResultsTable)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(pabResultsTable)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
@@ -28,4 +29,4 @@
             </div>
         </div>
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/pab-results/pab-results.component.html b/src/app/components/pab-results/pab-results.component.html
index 78f7d98451f94d60873f316ca54f794f29fcdb40..9bb311053cb44654634a6785c8f59407d48e36b8 100644
--- a/src/app/components/pab-results/pab-results.component.html
+++ b/src/app/components/pab-results/pab-results.component.html
@@ -12,8 +12,8 @@
         <pab-results-table *ngIf="hasDisplayableResults" [results]="pabResults"></pab-results-table>
     </div>
 
-    <quicknav *ngIf="hasDisplayableResults" [items]="[ 'input', 'results', 'charts' ]"
-        [currentItem]="'charts'" [align]="'left'"></quicknav>
+    <quicknav *ngIf="hasDisplayableResults" [items]="[ 'input', 'results', 'charts' ]" [currentItem]="'charts'"
+        [align]="'left'"></quicknav>
 
     <div id="pab-graphs-container" class="container" fxLayout="row wrap" fxLayoutAlign="space-around start">
         <pab-profile-chart *ngIf="hasDisplayableResults" fxFlex.gt-xs="1 0 400px" fxFlex.lt-sm="1 0 300px">
@@ -22,4 +22,4 @@
         </results-chart>
     </div>
 
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html
index 410b7120a08bd2efab951bbd3b5e630d8e53009d..96efe09a17616653a2c7ab330be912aa9af2cc1a 100644
--- a/src/app/components/pab-table/pab-table.component.html
+++ b/src/app/components/pab-table/pab-table.component.html
@@ -7,8 +7,8 @@
 <mat-card-content>
 
     <div id="pab-table-toolbar">
-        <button type="button" id="edit-pab-table" mat-raised-button color="accent"
-          [disabled]="! enableEditPabButton" (click)="showEditPab()">
+        <button type="button" id="edit-pab-table" mat-raised-button color="accent" [disabled]="! enableEditPabButton"
+            (click)="showEditPab()">
             {{ uitextEditPabTable }}
         </button>
 
@@ -22,31 +22,31 @@
                 </mat-option>
             </mat-select>
             <button type="button" mat-icon-button color="primary" [disabled]="! enableAddButton" (click)="onAddClick()"
-              [title]="uitextAdd">
+                [title]="uitextAdd">
                 <mat-icon>add_box</mat-icon>
             </button>
-            <button type="button" mat-icon-button color="primary" [disabled]="! enableCopyButton" (click)="onCopyClick()"
-              [title]="uitextCopy">
+            <button type="button" mat-icon-button color="primary" [disabled]="! enableCopyButton"
+                (click)="onCopyClick()" [title]="uitextCopy">
                 <mat-icon>content_copy</mat-icon>
             </button>
             |
-            <button type="button" mat-icon-button color="primary" [disabled]="! enableRemoveButton" (click)="onRemoveClick()"
-              [title]="uitextRemove">
+            <button type="button" mat-icon-button color="primary" [disabled]="! enableRemoveButton"
+                (click)="onRemoveClick()" [title]="uitextRemove">
                 <mat-icon>delete</mat-icon>
             </button>
-            <button type="button" mat-icon-button color="primary" [disabled]="! enableUpButton" (click)="onMoveUpClick()"
-              [title]="uitextMoveUp">
+            <button type="button" mat-icon-button color="primary" [disabled]="! enableUpButton"
+                (click)="onMoveUpClick()" [title]="uitextMoveUp">
                 <mat-icon *ngIf="! selectionIsOneDevice">arrow_upward</mat-icon>
                 <mat-icon *ngIf="selectionIsOneDevice">arrow_back</mat-icon>
             </button>
-            <button type="button" mat-icon-button color="primary" [disabled]="! enableDownButton" (click)="onMoveDownClick()"
-              [title]="uitextMoveDown">
+            <button type="button" mat-icon-button color="primary" [disabled]="! enableDownButton"
+                (click)="onMoveDownClick()" [title]="uitextMoveDown">
                 <mat-icon *ngIf="! selectionIsOneDevice">arrow_downward</mat-icon>
                 <mat-icon *ngIf="selectionIsOneDevice">arrow_forward</mat-icon>
             </button>
             |
             <button type="button" mat-icon-button color="primary" (click)="exportAsSpreadsheet()"
-              [title]="uitextExportAsSpreadsheet">
+                [title]="uitextExportAsSpreadsheet">
                 <mat-icon color="primary">file_download</mat-icon>
             </button>
         </div>
@@ -57,20 +57,18 @@
 
         <ng-template pTemplate="header" let-columns>
             <tr>
-                <th *ngFor="let h of headers"
-                  (click)="toggleSelection(h, $event)"
-                  (mousedown)="preventCtrlClickBorder($event)"
-                  [attr.rowspan]="h.rowspan ? h.rowspan : null" [attr.colspan]="h.colspan ? h.colspan : null"
-                  [class.selectable-cell]="isSelectable(h)" [class.selected-cell]="isSelected(h)">
+                <th *ngFor="let h of headers" (click)="toggleSelection(h, $event)"
+                    (mousedown)="preventCtrlClickBorder($event)" [attr.rowspan]="h.rowspan ? h.rowspan : null"
+                    [attr.colspan]="h.colspan ? h.colspan : null" [class.selectable-cell]="isSelectable(h)"
+                    [class.selected-cell]="isSelected(h)">
 
                     {{ h.title }}
                 </th>
             </tr>
             <tr>
-                <th *ngFor="let col of columns"
-                  (click)="toggleSelection(col, $event)"
-                  (mousedown)="preventCtrlClickBorder($event)"
-                  [class.selectable-cell]="isSelectable(col)" [class.selected-cell]="isSelected(col)">
+                <th *ngFor="let col of columns" (click)="toggleSelection(col, $event)"
+                    (mousedown)="preventCtrlClickBorder($event)" [class.selectable-cell]="isSelectable(col)"
+                    [class.selected-cell]="isSelected(col)">
 
                     {{ col.title }}
                 </th>
@@ -79,21 +77,19 @@
 
         <ng-template pTemplate="body" let-row>
             <tr [class.selected-row]="isSelected(row)">
-                <td *ngFor="let cell of row.cells"
-                  (click)="toggleSelection(cell, $event)"
-                  (mousedown)="preventCtrlClickBorder($event)"
-                  [ngClass]="cell.class"
-                  [class.editable-cell]="hasModel(cell)" [class.readonly-cell]="! hasModel(cell)"
-                  [class.selectable-cell]="isSelectable(cell)" [class.selected-cell]="isSelected(cell) && ! isSelected(row)"
-                  [class.invalid-cell]="isInvalid(cell)" [class.select]="isSelect(cell)"
-                  [attr.rowspan]="rowSpan(cell)" [attr.colspan]="colSpan(cell)"
-                  [title]="cellTitle(cell)">
+                <td *ngFor="let cell of row.cells" (click)="toggleSelection(cell, $event)"
+                    (mousedown)="preventCtrlClickBorder($event)" [ngClass]="cell.class"
+                    [class.editable-cell]="hasModel(cell)" [class.readonly-cell]="! hasModel(cell)"
+                    [class.selectable-cell]="isSelectable(cell)"
+                    [class.selected-cell]="isSelected(cell) && ! isSelected(row)" [class.invalid-cell]="isInvalid(cell)"
+                    [class.select]="isSelect(cell)" [attr.rowspan]="rowSpan(cell)" [attr.colspan]="colSpan(cell)"
+                    [title]="cellTitle(cell)">
 
                     <input matInput *ngIf="isNumberInput(cell)" step="0.00000000000001" type="number"
-                      [(ngModel)]="cell.model.singleValue" (input)="inputValueChanged($event, cell)">
+                        [(ngModel)]="cell.model.singleValue" (input)="inputValueChanged($event, cell)">
 
                     <mat-select #selectWidget *ngIf="isSelect(cell)" [value]="cell.modelValue"
-                      (selectionChange)="loiDebitSelected($event, cell)">
+                        (selectionChange)="loiDebitSelected($event, cell)">
 
                         <mat-option *ngFor="let opt of cell.options" [value]="opt.value" [title]="opt.label">
                             {{ opt.label }}
@@ -106,4 +102,4 @@
         </ng-template>
     </p-table>
 
-</mat-card-content>
+</mat-card-content>
\ No newline at end of file
diff --git a/src/app/components/param-computed/param-computed.component.html b/src/app/components/param-computed/param-computed.component.html
index d2d336cfc25540b47b0412423fd880c9e505b000..40320f1ddfc21de3b08313001c1ea11214ee9f39 100644
--- a/src/app/components/param-computed/param-computed.component.html
+++ b/src/app/components/param-computed/param-computed.component.html
@@ -1,7 +1,9 @@
 <!-- a fake input bound to nothing, for the sake of UI consistency -->
 <mat-form-field>
-    <input matInput disabled [id]="inputId" class="form-control" type="text" [ngModel]="infoText" [placeholder]="param.title">
-    <button type="button" *ngIf="isDicho" mat-icon-button class="param-computed-more" (click)="openDialog()" [title]="uitextEditInitialValue">
+    <input matInput disabled [id]="inputId" class="form-control" type="text" [ngModel]="infoText"
+        [placeholder]="param.title">
+    <button type="button" *ngIf="isDicho" mat-icon-button class="param-computed-more" (click)="openDialog()"
+        [title]="uitextEditInitialValue">
         <mat-icon>more_horiz</mat-icon>
     </button>
-</mat-form-field>
+</mat-form-field>
\ No newline at end of file
diff --git a/src/app/components/param-field-line/param-field-line.component.html b/src/app/components/param-field-line/param-field-line.component.html
index 35c1fd0c841425b97aef1cbe4bc4c4d16427d3ee..07d31672d74fa61e868a16c2b971b91949b4a708 100644
--- a/src/app/components/param-field-line/param-field-line.component.html
+++ b/src/app/components/param-field-line/param-field-line.component.html
@@ -1,49 +1,48 @@
-
 <div class="container" fxLayout="row wrap" fxLayoutAlign="space-between start">
 
     <!-- input de saisie de la valeur -->
     <div fxFlex="1 0 120px">
         <!-- composant pour gérer le cas général (valeur numérique à saisir) -->
-        <ngparam-input [title]="param.title" [hidden]="! isRadioFixChecked"
-            (change)="onInputChange($event)" (tabPressed)="onTabPressed($event)">
+        <ngparam-input [title]="param.title" [hidden]="! isRadioFixChecked" (change)="onInputChange($event)"
+            (tabPressed)="onTabPressed($event)">
         </ngparam-input>
- 
+
         <!-- composant pour gérer le cas "paramètre calculé" -->
         <param-computed *ngIf="isRadioCalChecked" [title]="title" [param]="param">
         </param-computed>
 
         <!-- composant pour gérer le cas "paramètre à varier" (min-max/liste de valeurs) -->
-        <param-values *ngIf="isRadioVarChecked" [title]="title" [param]="param"
-            (change)="onInputChange($event)" (valid)=onParamValuesValid($event)>
+        <param-values *ngIf="isRadioVarChecked" [title]="title" [param]="param" (change)="onInputChange($event)"
+            (valid)=onParamValuesValid($event)>
         </param-values>
-    
+
         <!-- composant pour gérer le cas "paramètre lié" -->
-        <param-link *ngIf="isRadioLinkChecked" [title]="title" [param]="param"
-            (change)="onInputChange($event)" (valid)=onParamValuesValid($event)>
+        <param-link *ngIf="isRadioLinkChecked" [title]="title" [param]="param" (change)="onInputChange($event)"
+            (valid)=onParamValuesValid($event)>
         </param-link>
     </div>
 
     <div class="toggle-group-container" fxFlex="0 0 auto">
         <mat-button-toggle-group *ngIf="hasRadioFix() || hasRadioVar() || hasRadioCal() || hasRadioLink()">
 
-            <mat-button-toggle class="radio_fix" value="radio_fix" 
-                (click)="onRadioClick('fix')" [checked]="isRadioFixChecked" [disabled]="! canExitCalcMode()">
+            <mat-button-toggle class="radio_fix" value="radio_fix" (click)="onRadioClick('fix')"
+                [checked]="isRadioFixChecked" [disabled]="! canExitCalcMode()">
                 <span fxHide.xxs>{{ uitextParamFixe }}</span>
                 <span fxHide.gt-xxs>F</span>
             </mat-button-toggle>
-        
-            <mat-button-toggle class="radio_var" value="radio_var" *ngIf="hasRadioVar()"
-                (click)="onRadioClick('var')" [checked]="isRadioVarChecked" [disabled]="! canExitCalcMode()">
+
+            <mat-button-toggle class="radio_var" value="radio_var" *ngIf="hasRadioVar()" (click)="onRadioClick('var')"
+                [checked]="isRadioVarChecked" [disabled]="! canExitCalcMode()">
                 <span fxHide.xxs>{{ uitextParamVarier }}</span>
                 <span fxHide.gt-xxs>V</span>
             </mat-button-toggle>
-        
-            <mat-button-toggle class="radio_cal" value="radio_cal" *ngIf="hasRadioCal()"
-                (click)="onRadioClick('cal')" [checked]="isRadioCalChecked">
+
+            <mat-button-toggle class="radio_cal" value="radio_cal" *ngIf="hasRadioCal()" (click)="onRadioClick('cal')"
+                [checked]="isRadioCalChecked">
                 <span fxHide.xxs>{{ uitextParamCalculer }}</span>
                 <span fxHide.gt-xxs>C</span>
             </mat-button-toggle>
-        
+
             <mat-button-toggle class="radio_link" value="radio_link" *ngIf="hasRadioLink()"
                 (click)="onRadioClick('link')" [checked]="isRadioLinkChecked" [disabled]="! canExitCalcMode()">
                 <span fxHide.xxs>{{ uitextParamLie }}</span>
@@ -53,4 +52,4 @@
         </mat-button-toggle-group>
     </div>
 
-</div>
+</div>
\ 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 f0601b32abfdef3c646dbe41c556f55afc69b6d0..0fd0a4eb2688a3bf127f9da9e0a97d2cfb739399 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
@@ -153,7 +153,7 @@ export class ParamFieldLineComponent implements OnChanges {
     /**
     * calcule la présence du radio "paramètre à calculer"
     */
-   public hasRadioCal(): boolean {
+    public hasRadioCal(): boolean {
         switch (this.param.radioConfig) {
             case ParamRadioConfig.CAL:
                 return true;
@@ -166,7 +166,7 @@ export class ParamFieldLineComponent implements OnChanges {
     /**
     * calcule la présence du radio "paramètre lié" (importé d'un autre module de calcul)
     */
-   public hasRadioLink(): boolean {
+    public hasRadioLink(): boolean {
         if (this._formService.formulaires.length > 0) {
             // au moins 2 modules de calcul ouverts
             if (this._formService.formulaires.length > 1) {
diff --git a/src/app/components/param-link/param-link.component.html b/src/app/components/param-link/param-link.component.html
index eadf8016d6605a44f66637798ec6342b4f030941..d96d4f7543cd5194e1d2dc54014a01b2341fd045 100644
--- a/src/app/components/param-link/param-link.component.html
+++ b/src/app/components/param-link/param-link.component.html
@@ -1,6 +1,5 @@
 <mat-form-field>
-    <mat-select [id]="selectId" [name]="selectId" [placeholder]="param.title"
-        [(ngModel)]="currentLinkedParam" required>
+    <mat-select [id]="selectId" [name]="selectId" [placeholder]="param.title" [(ngModel)]="currentLinkedParam" required>
         <mat-option *ngFor="let e of linkableParams" [value]="e" [title]="selectItemLabel(e)">
             {{ selectItemLabel(e) }}
         </mat-option>
@@ -17,4 +16,4 @@
     <mat-icon [title]="uitextAwaitingCalculation" class="status-info" *ngIf="isAwaitingCalculation">
         timelapse
     </mat-icon>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/param-link/param-link.component.ts b/src/app/components/param-link/param-link.component.ts
index 565638b45ecedac0c4e5022c09bee8f5a0a0a68d..fbe6f22261d082a4615242e43ed8ae4b85a7c79e 100644
--- a/src/app/components/param-link/param-link.component.ts
+++ b/src/app/components/param-link/param-link.component.ts
@@ -179,47 +179,47 @@ export class ParamLinkComponent implements OnChanges, Observer, OnDestroy {
                 , (pos + 1)
             );
         } else
-        // 2. Paramètre / résultat d'une section dans un Nub de type SectionNub
-        if (i.nub instanceof acSection) {
-            if (i.isResult()) {
-                // résultat de section
-                return `${preview} - ` + sprintf(
-                    this.intlService.localizeText("INFO_LINKED_VALUE_SECTION_RESULT"),
-                    s, c
-                );
-            } else {
-                // paramètre de section
-                return `${preview} - ` + sprintf(
-                    this.intlService.localizeText("INFO_LINKED_VALUE_SECTION"),
-                    s, c
-                );
-            }
-        } else
-        // 3. Résultat
-        if (i.isResult()) {
-            return `${preview} - ` + sprintf(
-                this.intlService.localizeText("INFO_LINKED_VALUE_RESULT"),
-                s, c
-            );
-        } else
-        // 4. Résultat complémentaire
-        if (i.isExtraResult()) {
-            if (i.meta["result"]) {
-                // @TODO not used ?
-                return `${preview} - ` + sprintf(
-                    this.intlService.localizeText("INFO_LINKED_VALUE_EXTRA_RESULT_OF"),
-                    s, c, i.meta["result"]
-                );
-            } else {
-                return `${preview} - ` + sprintf(
-                    this.intlService.localizeText("INFO_LINKED_VALUE_EXTRA_RESULT"),
-                    s, c
-                );
-            }
-        } else {
-            // 5. Paramètre (cas général)
-            return `${preview} - ${s} (${c})`;
-        }
+            // 2. Paramètre / résultat d'une section dans un Nub de type SectionNub
+            if (i.nub instanceof acSection) {
+                if (i.isResult()) {
+                    // résultat de section
+                    return `${preview} - ` + sprintf(
+                        this.intlService.localizeText("INFO_LINKED_VALUE_SECTION_RESULT"),
+                        s, c
+                    );
+                } else {
+                    // paramètre de section
+                    return `${preview} - ` + sprintf(
+                        this.intlService.localizeText("INFO_LINKED_VALUE_SECTION"),
+                        s, c
+                    );
+                }
+            } else
+                // 3. Résultat
+                if (i.isResult()) {
+                    return `${preview} - ` + sprintf(
+                        this.intlService.localizeText("INFO_LINKED_VALUE_RESULT"),
+                        s, c
+                    );
+                } else
+                    // 4. Résultat complémentaire
+                    if (i.isExtraResult()) {
+                        if (i.meta["result"]) {
+                            // @TODO not used ?
+                            return `${preview} - ` + sprintf(
+                                this.intlService.localizeText("INFO_LINKED_VALUE_EXTRA_RESULT_OF"),
+                                s, c, i.meta["result"]
+                            );
+                        } else {
+                            return `${preview} - ` + sprintf(
+                                this.intlService.localizeText("INFO_LINKED_VALUE_EXTRA_RESULT"),
+                                s, c
+                            );
+                        }
+                    } else {
+                        // 5. Paramètre (cas général)
+                        return `${preview} - ${s} (${c})`;
+                    }
     }
 
     /**
diff --git a/src/app/components/param-values/param-values.component.html b/src/app/components/param-values/param-values.component.html
index 2561e922040ab17c2b7afce1fce27d7e367f3601..4ffc23cbf03c077b321487381944d7b1b5fd8c43 100644
--- a/src/app/components/param-values/param-values.component.html
+++ b/src/app/components/param-values/param-values.component.html
@@ -1,8 +1,8 @@
 <!-- a fake input bound to nothing, for the sake of UI consistency -->
 <mat-form-field>
-    <input matInput disabled class="form-control" type="text"
-        [id]="inputId" [name]="inputId" [ngModel]="infoText" [placeholder]="param.title">
+    <input matInput disabled class="form-control" type="text" [id]="inputId" [name]="inputId" [ngModel]="infoText"
+        [placeholder]="param.title">
     <button type="button" mat-icon-button class="param-values-more" (click)="openDialog()" [title]="uitextEditValues">
         <mat-icon>more_horiz</mat-icon>
     </button>
-</mat-form-field>
+</mat-form-field>
\ No newline at end of file
diff --git a/src/app/components/quicknav/quicknav.component.html b/src/app/components/quicknav/quicknav.component.html
index 31f1db00b47629aa275cba093bafcd8f4a85cb03..b8d738fcdcbd47637f1bdda9e75f8308b52f32f6 100644
--- a/src/app/components/quicknav/quicknav.component.html
+++ b/src/app/components/quicknav/quicknav.component.html
@@ -1,7 +1,7 @@
-<div class="quicknav-row" [ngStyle]="alignStyle" *ngIf="hasItems" [id]="id"
-    [class.autoPadLeft]="align === 'left'" [class.autoPadRight]="align === 'right'">
+<div class="quicknav-row" [ngStyle]="alignStyle" *ngIf="hasItems" [id]="id" [class.autoPadLeft]="align === 'left'"
+    [class.autoPadRight]="align === 'right'">
 
     <div class="quicknav-item" *ngFor="let i of items" [class.current]="isCurrent(i)" [ngStyle]="paddingStyle">
         <a (click)="scrollTo(i)">{{ label(i) }}</a>
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/remous-results/remous-results.component.html b/src/app/components/remous-results/remous-results.component.html
index 8a51ef96d4ae095aa02c782e212979b90b08f040..ed96cbf12dfdbf619938d462cba2959f7f1b2a83 100644
--- a/src/app/components/remous-results/remous-results.component.html
+++ b/src/app/components/remous-results/remous-results.component.html
@@ -1,10 +1,12 @@
-<div class="remous-results-container" #remousResults *ngIf="hasResults" fxLayout="row wrap" fxLayoutAlign="center center">
+<div class="remous-results-container" #remousResults *ngIf="hasResults" fxLayout="row wrap"
+    fxLayoutAlign="center center">
     <div fxFlex="1 1 100%">
         <div class="remous-results-buttons">
             <button mat-icon-button (click)="exportAsImage(remousResults)" [title]="uitextExportImageTitle">
                 <mat-icon color="primary">image</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(remousResults)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(remousResults)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
@@ -12,19 +14,21 @@
             </button>
         </div>
 
-        <chart id="main-chart" ngClass.lt-sm="height300" ngClass.sm="height400" ngClass.md="height400" ngClass.gt-md="height600"
-            [type]="graph1_type" [data]="graph1_data" [options]="graph1_options">
+        <chart id="main-chart" ngClass.lt-sm="height300" ngClass.sm="height400" ngClass.md="height400"
+            ngClass.gt-md="height600" [type]="graph1_type" [data]="graph1_data" [options]="graph1_options">
         </chart>
     </div>
 </div>
 
-<div class="remous-results-extragraph-container" #remousResultsExtra *ngIf="extraChart" fxLayout="row wrap" fxLayoutAlign="center center">
+<div class="remous-results-extragraph-container" #remousResultsExtra *ngIf="extraChart" fxLayout="row wrap"
+    fxLayoutAlign="center center">
     <div fxFlex="1 1 100%">
         <div class="remous-results-buttons">
             <button mat-icon-button (click)="exportAsImage(remousResultsExtra)" [title]="uitextExportImageTitle">
                 <mat-icon color="primary">image</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(remousResultsExtra)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(remousResultsExtra)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
@@ -40,7 +44,8 @@
 <!-- journal -->
 <log></log>
 
-<div [hidden]="! hasData"><!-- *ngIf breaks @ViewChild availability-->
+<div [hidden]="! hasData">
+    <!-- *ngIf breaks @ViewChild availability-->
     <!-- résultats numériques -->
     <var-results></var-results>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/results-chart/results-chart.component.html b/src/app/components/results-chart/results-chart.component.html
index 7b95757ae948e592f0f80b90739f18a39c5384d2..1cf1336d5b43c0c98f79f967a421166a720e799e 100644
--- a/src/app/components/results-chart/results-chart.component.html
+++ b/src/app/components/results-chart/results-chart.component.html
@@ -7,7 +7,8 @@
             <button mat-icon-button (click)="exportAsImage(graphResults)" [title]="uitextExportImageTitle">
                 <mat-icon color="primary">image</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphResults)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphResults)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
@@ -41,4 +42,4 @@
             </mat-option>
         </mat-select>
     </mat-form-field>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/section-results/section-results.component.html b/src/app/components/section-results/section-results.component.html
index 7911644b140405c606fc05710576ebee9d6d1a4d..ff26a315cad7f386d37b69661a6be7d76becdf7c 100644
--- a/src/app/components/section-results/section-results.component.html
+++ b/src/app/components/section-results/section-results.component.html
@@ -1,11 +1,13 @@
-<div class="section-results-container" #sectionResults *ngIf="hasResults" fxLayout="row wrap" fxLayoutAlign="center center">
+<div class="section-results-container" #sectionResults *ngIf="hasResults" fxLayout="row wrap"
+    fxLayoutAlign="center center">
 
     <div fxFlex="1 1 100%">
         <div class="section-results-buttons">
             <button mat-icon-button (click)="exportAsImage(sectionResults)" [title]="uitextExportImageTitle">
                 <mat-icon color="primary">image</mat-icon>
             </button>
-            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(sectionResults)" [title]="uitextEnterFSTitle">
+            <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(sectionResults)"
+                [title]="uitextEnterFSTitle">
                 <mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
             </button>
             <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle">
@@ -36,4 +38,4 @@
             <var-results [results]=varResults></var-results>
         </div>
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/session-properties/session-properties.component.html b/src/app/components/session-properties/session-properties.component.html
index 13211dc48dc10620103be1624755cfd0f865c0c9..3ad9695b607b77bd0cd6895cfc59f7b907a69d51 100644
--- a/src/app/components/session-properties/session-properties.component.html
+++ b/src/app/components/session-properties/session-properties.component.html
@@ -16,8 +16,8 @@
                 </mat-tab>
                 <mat-tab [label]="uitextEdit">
                     <mat-form-field>
-                        <textarea matInput id="md-editor" [(ngModel)]="content"
-                                cdkTextareaAutosize cdkAutosizeMinRows="15" #autosize="cdkTextareaAutosize"></textarea>
+                        <textarea matInput id="md-editor" [(ngModel)]="content" cdkTextareaAutosize
+                            cdkAutosizeMinRows="15" #autosize="cdkTextareaAutosize"></textarea>
                     </mat-form-field>
                 </mat-tab>
             </mat-tab-group>
@@ -26,4 +26,4 @@
 
     </mat-card>
 
-</div>
+</div>
\ No newline at end of file
diff --git a/src/app/components/session-properties/session-properties.component.ts b/src/app/components/session-properties/session-properties.component.ts
index d9cbf6111f62aab70f2f74ff7cf1ee2b7ac45f11..fe82be8a01d96f36f7f217c1075d7bfc9cc57761 100644
--- a/src/app/components/session-properties/session-properties.component.ts
+++ b/src/app/components/session-properties/session-properties.component.ts
@@ -30,7 +30,7 @@ export class SessionPropertiesComponent implements OnInit {
             throwOnError: false,
             errorColor: "#cc0000"
         };
-        if (! isDevMode()) {
+        if (!isDevMode()) {
             this.matomoTracker.trackPageView("notes");
         }
     }
@@ -57,8 +57,8 @@ export class SessionPropertiesComponent implements OnInit {
 
     public ngOnInit() {
         // if app is started on this page but session is empty, redirect to home page
-        if (! this.hasModules) {
-            this.router.navigate([ "/list" ]);
+        if (!this.hasModules) {
+            this.router.navigate(["/list"]);
         }
         // if notes content is empty, switch to editor
         if (this.content === undefined || this.content === "") {
diff --git a/src/app/services/error.service.ts b/src/app/services/error.service.ts
index 77620c3b7c82ea97996779c5fae0608514da4ecf..25288f4fefb73395bdfa37bf73ca71bf4877382b 100644
--- a/src/app/services/error.service.ts
+++ b/src/app/services/error.service.ts
@@ -4,7 +4,7 @@ import { Observable } from "jalhyd";
 
 @Injectable()
 export class ErrorService extends Observable {
-  // TODO: add explicit constructor
+    // TODO: add explicit constructor
 
     doAlert(m: string) {
         this.notifyObservers(m);
diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts
index 486a296de396d2a4f7952f854caea41c313233d7..89653c92fbae12f2e70af680c9987dd08acaf36e 100644
--- a/src/app/services/formulaire.service.ts
+++ b/src/app/services/formulaire.service.ts
@@ -114,7 +114,7 @@ export class FormulaireService extends Observable {
             });
         } else {
             const f: string = this.getConfigPathPrefix(calc) + lang + ".json";
-                return this._httpService.httpGetRequestPromise(f).then((localisation) => {
+            return this._httpService.httpGetRequestPromise(f).then((localisation) => {
                 this._languageCache[ct] = this._languageCache[ct] || {};
                 this._languageCache[ct][lang] = localisation;
                 return localisation as StringMap;
@@ -182,8 +182,8 @@ export class FormulaireService extends Observable {
             if (match) {
                 // Les libellés correspondants sont INFO OUVRAGE et INFO_LIB_OUVRAGE_XXX
                 s = this.intlService.localizeText(`INFO_${match[1].toUpperCase()}`)
-                + " n°" + (+match[2] + 1) + ": "
-                + this.expandVariableName(calcType, `${match[1].toUpperCase()}_${match[3].toUpperCase()}`);
+                    + " n°" + (+match[2] + 1) + ": "
+                    + this.expandVariableName(calcType, `${match[1].toUpperCase()}_${match[3].toUpperCase()}`);
             } else {
                 s = this.intlService.localizeText("INFO_LIB_" + symbol.toLocaleUpperCase());
             }
diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts
index 3612073bc31cd4c1f5d6cbb00318521e9a61bd8a..5d0833162027e2147e99e72a1a94bb7d3cb62843 100644
--- a/src/environments/environment.prod.ts
+++ b/src/environments/environment.prod.ts
@@ -1,3 +1,3 @@
 export const environment = {
-  production: true
+    production: true
 };