diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2e5f7049aa75412f3db8c5a7ee22ea828018a4db..54d4e6d1290087f140609006a7af5624b4e05160 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -81,6 +81,7 @@ test:
     - tags
     - schedules
     - web
+    - master
   script:
     - npm run e2e
 
@@ -117,7 +118,8 @@ deploy-dev:
     - build
   script:
     # Copie de la branche / du tag
-    - ./scripts/deploy-version.sh $CI_COMMIT_REF_NAME $DEV_LOGIN $DEV_HOST $DEV_PATH
+    - if [[ $CI_COMMIT_REF_NAME != "stable" ]]; then ./scripts/deploy-version.sh $CI_COMMIT_REF_NAME $DEV_LOGIN $DEV_HOST $DEV_PATH; fi
+    - if [[ $CI_COMMIT_REF_NAME == "stable" ]]; then ./scripts/deploy-version.sh $CI_COMMIT_REF_NAME $DEV_LOGIN $DEV_HOST $DEV_PATH/stable; fi
 
 deploy-prod:
   stage: deploy-prod
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8cd5b0cdfb32bdba1cb6b0c679df12c1986b3f39..df70694f584936a0e4dc5e4d6d8311721803bfbf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,22 +5,22 @@
 #### Nouvelles fonctionnalités
 
 * PAB : Variation du débit d'attrait ([nghyd#431](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/431))
-* Ajouter un bouton "Annuler" sur la saisie des paramètres variables ([jalhyd#300](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/300),[nghyd#507](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/507))
-* Prébarrages : mettre les enfants invalides en rouge dans le schéma ([jalhyd#298](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/298),[nghyd#484](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/484))
+* Ajouter un bouton "Annuler" sur la saisie des paramètres variables ([jalhyd#300](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/300), [nghyd#507](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/507))
+* Prébarrages : mettre les enfants invalides en rouge dans le schéma ([jalhyd#298](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/298), [nghyd#484](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/484))
 
 #### Changements
 
 * Fente Larinier : laisser le coefficient de débit vide ([nghyd#515](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/515))
-* Cloisons : Générer une PAB : vider les champs ([jalhyd#306](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/306),[nghyd#516](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/516))
+* Cloisons : Générer une PAB : vider les champs ([jalhyd#306](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/306), [nghyd#516](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/516))
 
 
 #### Correction de bogues
 
-* Courbe de remous: crash de l'application sur données erronées ([jalhyd#307](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/307),[nghyd#532](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/532))
+* Courbe de remous: crash de l'application sur données erronées ([jalhyd#307](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/307), [nghyd#532](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/532))
   Deux bugs en un, l'appli crashe quand :
     - la hauteur de berge dépasse une certaine valeur avec des paramètres corrects pour effectuer un calcul (par exemple les valeurs par défaut)
     - les deux cotes de l'eau se situent sous les cotes de fond amont et aval
-* Sections : non convergence du calcul du tirant d'eau critique ([jalhyd#301](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/301),[nghyd#528](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/528))
+* Sections : non convergence du calcul du tirant d'eau critique ([jalhyd#301](https://gitlab.irstea.fr/cassiopee/jalhyd/-/issues/301), [nghyd#528](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/528))
 * Remettre le paramètre dans son état initial quand le dialogue "Varier" est annulé ([nghyd#508](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/508))
 * Prébarrages: les champs ne sont pas vides lors des ajouts de bassins et cloisons ([nghyd#503](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/503))
 * Mode "champs vides par défaut" : changer le type d'un ouvrage (ex: dans Cloisons) remplit les champs ([nghyd#480](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/480))
@@ -35,7 +35,7 @@
 
 * Nightly build: clean folder before installation ([nghyd#495](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/495))
 * Transfert du site de production sur OVH ([nghyd#505](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/505))
-* Plantage des tests e2e sur le chargement des exemples ([nghyd#530](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/530),[nghyd#531](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/531))
+* Plantage des tests e2e sur le chargement des exemples ([nghyd#530](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/530), [nghyd#531](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/531))
     - Les champs des exemples chargés sont vides lorsque le mode "champ vides" est activé.
     - Les tests e2e plantent par manque de temporisation
 * CI : les jobs build en schedule de master et devel plantent ([nghyd#527](https://gitlab.irstea.fr/cassiopee/nghyd/-/issues/527))
diff --git a/README.md b/README.md
index a67a239a1c7e9886e7563ced9537ed04f922a3aa..9210051a033f6943508575810c518d0441d00ab4 100644
--- a/README.md
+++ b/README.md
@@ -6,25 +6,35 @@ See also [developers documentation](DEVELOPERS.md) (in french)
 
 ### Requirements
 
+Requirements for developping Cassiopee can be achieved by manually install the required dependencies on your computer or by using the dedicated docker container.
+
+#### Required dependencies
+
  * [jalhyd](https://gitlab.irstea.fr/cassiopee/jalhyd)
  * npm
  * python3
  * pandoc ^2 (optional, for PDF documentation only)
  * texlive (optional, for PDF documentation only)
- 
+
 Building the HTML documentation requires MkDocs and some extensions:
 
 ```sh
 sudo apt install python3-pip python3-setuptools
 python3 -m pip install mkdocs python-markdown-math mkdocs-material
 ```
- 
+
 Building the PDF documentation requires pandoc and a LaTeX distribution (for ex. texlive) with a few packages:
 
 ```sh
 sudo apt install pandoc texlive latexmk texlive-latex-extra texlive-bibtex-extra
 ```
 
+#### Using docker container
+
+Download and use the following docker image: https://hub.docker.com/repository/docker/geaucassiopee/ci-cd-cross-platform-webapp
+
+More details on how to use it on vscode are available at https://gitlab.irstea.fr/cassiopee/cassiopee2-integration
+
 ### Install dependencies
 
 #### JaLHyd
@@ -40,9 +50,11 @@ npm run package
 Then in `nghyd` folder, run :
 
 ```sh
-npm install
+npm ci --force --unsafe-perm
 ```
 
+This installs the exact same version of dependencies as the ones specified in `package.lock.json`.
+The parameter `--unsafe-perm` solves permissions issues for running e2e tests in a docker container.
 
 ### Compile and get a deployable Web app
 
@@ -225,7 +237,7 @@ npm install -g tsviz
 ```
 
 There's currently a bug on debian like distribution due to a wrong declaration of graphviz path in the code: https://github.com/joaompneves/tsviz/issues/5
-As a workaround, you can create a link to the right path: `sudo ln -s /usr/bin/dot /usr/local/bin/dot` 
+As a workaround, you can create a link to the right path: `sudo ln -s /usr/bin/dot /usr/local/bin/dot`
 
 To draw the diagram:
 ```sh
@@ -251,11 +263,11 @@ sudo find /usr/lib/node_modules/protractor -regextype sed -regex "^.*/chromedriv
 
 Use [semantic versioning](https://semver.org/).
 
-**It's discouraged to execute release steps manually, see Release Script below**
+**It's discouraged to execute release steps manually, skip this section and see Release Script below**
 
 Before releasing a new stable version, a new version of JaLHyd should be tagged, see "Release Policy" in [JaLHyd's README.md](https://gitlab.irstea.fr/cassiopee/jalhyd/blob/master/README.md)
 
-Then, one should complete the following files
+Then, one should complete the following files:
  - `CHANGELOG.md`
  - `package.json` (update "version", or use `npm version`)
  - `jalhyd_branch` (be sure that it contains "master" or is empty)
@@ -270,12 +282,16 @@ The `stable` tag should be set **before** the version tag, so that `git describe
 
 **Important:** the release script assumes that you run it from the current nghyd source directory `nghyd`, and that JaLHyd source directory `jalhyd` is present at the same level.
 
+Before running the script:
+ * update `CHANGELOG.md` in both JaLHyd and NgHyd
+ * set the content of `jalhyd_branch` to "master"
+
 This script:
  * checks out "master" branch of JaLHyd, pulls the latest changes, installs dependencies, runs unit tests, commits changes if any
- * updates JaLHyd version, commits changes
+ * updates JaLHyd version in `package.json`, commits changes
  * creates the right tags for JaLHyd and pushes them
  * checks out "master" branch of NgHyd, pulls the latest changes, installs dependencies, commits changes if any
- * updates NgHyd version, commits changes
+ * updates NgHyd version in `package.json`, commits changes
  * creates the right tags for NgHyd and pushes them
 
 It **does not** check that `jalhyd_branch` is OK nor that `jalhyd/CHANGELOG.md` and `nghyd/CHANGELOG.md` are up to date, but reminds you to do it.
diff --git a/e2e/reset-param-mode.e2e-spec.ts b/e2e/reset-param-mode.e2e-spec.ts
index 7cc73c00746d957dac66f214a2609035e281c27d..c4b7548394bbfc131bd31f03bf1ac399085cfab6 100644
--- a/e2e/reset-param-mode.e2e-spec.ts
+++ b/e2e/reset-param-mode.e2e-spec.ts
@@ -16,17 +16,21 @@ describe("ngHyd - check parameter mode is set to its previous value - ", () => {
     it("when min/max/list values dialog is cancelled", async () => {
         // start page
         await listPage.navigateTo();
+        await browser.sleep(500);
 
         // open PAB chute
         await listPage.clickMenuEntryForCalcType(12);
+        await browser.sleep(500);
 
         // click "calc" radio on Z1 parameter
         const z1calcbtn = element(by.id("mat-button-toggle-3"));
         await z1calcbtn.click();
+        await browser.sleep(200);
 
         // click "var" radio on Z1 parameter
         const z1varbtn = element(by.id("mat-button-toggle-2"));
         await z1varbtn.click();
+        await browser.sleep(200);
 
         // click cancel button
         const cancelbtn = element(by.id("btn-cancel"));
diff --git a/jalhyd_branch b/jalhyd_branch
index 626e97d71d9e3364f9abe16f7e3c8d70dea5a7fa..1f7391f92b6a3792204e07e99f71f643cc35e7e1 100644
--- a/jalhyd_branch
+++ b/jalhyd_branch
@@ -1 +1 @@
-devel
\ No newline at end of file
+master
diff --git a/package-lock.json b/package-lock.json
index c8b39b42057aa73838ddb2e87837e9a02722b410..bb49ccdc8395079083a733eb5f1b9427be5a6a3c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "fr.irstea.cassiopee",
-  "version": "4.14.2",
+  "version": "4.15.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -4026,7 +4026,8 @@
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.1.tgz",
       "integrity": "sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA==",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "boxen": {
       "version": "4.2.0",
@@ -11693,11 +11694,13 @@
       "dependencies": {
         "@types/base-64": {
           "version": "0.1.3",
-          "bundled": true
+          "resolved": "https://registry.npmjs.org/@types/base-64/-/base-64-0.1.3.tgz",
+          "integrity": "sha512-DJpw7RKNMXygZ0j2xe6ROBqiJUy7JWEItkzOPBzrT35HUWS7VLYyW9XJX8yCCvE2xg8QD7wesvVyXFg8AVHTMA=="
         },
         "base-64": {
           "version": "0.1.0",
-          "bundled": true
+          "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
+          "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs="
         }
       }
     },
diff --git a/package.json b/package.json
index aaeba42b1ebb61bd252a0212ac0e62300f640e68..14913b0ff6c6c71a7e3478a3c1ca94adba389e2b 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
   "displayName": "Cassiopée",
   "description": "Hydraulic calculators",
   "author": "Inrae",
-  "version": "4.14.2",
+  "version": "4.15.0",
   "main": "main.js",
   "homepage": "https://cassiopee.g-eau.fr",
   "license": "MIT",
diff --git a/protractor.conf.js b/protractor.conf.js
index d474c230b2a8c1592f135dd650a605a8af92ec03..92c3cd8558e8162ce80021cf724b10a79c065f13 100644
--- a/protractor.conf.js
+++ b/protractor.conf.js
@@ -37,11 +37,12 @@ exports.config = {
       args: [
         "--no-sandbox",
         "--headless",
-        "--window-size=1024x768"
+        "--window-size=1024x768",
+        "--disable-dev-shm-usage"
       ],
       prefs: {
         download: {
-            prompt_for_download: false, 
+            prompt_for_download: false,
             directory_upgrade: true,
             // default_directory: '/tmp/e2e-downloads'
         },
diff --git a/scripts/deploy-new-stable-version.sh b/scripts/deploy-new-stable-version.sh
index 3c65c3ae55c602324912c69bb109e17dec36b10a..56b69f87271579c86c970ab904d89cc18d785627 100755
--- a/scripts/deploy-new-stable-version.sh
+++ b/scripts/deploy-new-stable-version.sh
@@ -38,21 +38,22 @@ git checkout master
 git pull --rebase
 npm install
 npm run jasmine
-if [ ! -z "$(git status --porcelain)" ]
-then 
+if [ ! -z "$(git status --untracked-files=no --porcelain)" ]
+then
     echo "commiting changes induced by 'npm install'"
     git commit -a -m "verify dependencies (npm install) before deploying version $VERSION"
 fi
 
 # 1.3 version in package.*
 npm version "$VERSION" --allow-same-version --git-tag-version=false
-if [ ! -z "$(git status --porcelain)" ]
-then 
+if [ ! -z "$(git status --untracked-files=no --porcelain)" ]
+then
     echo "commiting changes induced by 'npm version'"
     git commit -a -m "update package.* to version $VERSION"
 fi
 
 # 1.4 tags
+echo "setting tags to $VERSION version"
 git tag -fa "nghyd_$VERSION" -m "release version $VERSION"
 sleep 1
 git tag -fa stable -m "stable version"
@@ -71,7 +72,7 @@ cd ../nghyd
 git checkout master
 git pull --rebase
 npm install
-if [ ! -z "$(git status --porcelain)" ]
+if [ ! -z "$(git status --untracked-files=no --porcelain)" ]
 then
     echo "commiting changes induced by 'npm install'"
     git commit -a -m "verify dependencies (npm install) before deploying version $VERSION"
@@ -79,13 +80,14 @@ fi
 
 # 2.3 version in package.*
 npm version "$VERSION" --allow-same-version --git-tag-version=false
-if [ ! -z "$(git status --porcelain)" ]
-then 
+if [ ! -z "$(git status --untracked-files=no --porcelain)" ]
+then
     echo "commiting changes induced by 'npm version'"
     git commit -a -m "update package.* to version $VERSION"
 fi
 
 # 2.4 tags
+echo "setting tags to $VERSION version"
 git tag -fa stable -m "stable version"
 sleep 1
 git tag -fa "$VERSION" -m "release version $VERSION"
diff --git a/scripts/release-version.sh b/scripts/release-version.sh
index 1f810669edb9478732e78422e6ef76da8e81ad17..717cb8d87fac37212f2df91174ccd46f614b8725 100755
--- a/scripts/release-version.sh
+++ b/scripts/release-version.sh
@@ -1,6 +1,8 @@
 #!/bin/bash
 
 set -o errexit
+# Output command lines for debugging
+set -x
 
 # Fabrique les exécutables electron/cordova pour une version de Cassiopée $1, les
 # distribue sur le serveur $2@$3 dans le dossier $4, et met à jour le fichier releases.json
@@ -40,11 +42,11 @@ if (( $update_latest )); then
   # fetch current releases file
   scp "$HOST_LOGIN:$RELEASES_FILE" "./$TMP_RELEASES_FILE"
 
-  grep -P "\"latest\": \"$VERSION\"" "$TMP_RELEASES_FILE"
-
-  if [[ $? == 0 ]]; then
+  if [[ -n $(grep -P "\"latest\": \"$VERSION\"" "$TMP_RELEASES_FILE") ]]; then
     echo "$VERSION est déjà la version la plus récente, pas de mise à jour du fichier releases.json"
   else
+    echo "mise à jour du fichier releases.json à la version $VERSION"
+
     sed -i -E "s/\"latest\": .+,/\"latest\": \"$VERSION\",/" "$TMP_RELEASES_FILE"
     echo -e "\t\"$VERSION\": {
 \t\t\"darwin\": \"Cassiopée-${VERSION}-mac.zip\",