diff --git a/ivette/.eslintignore b/ivette/.eslintignore
index ba02ae7397f98663969ed6a85953c7f336d21644..8744f886e55e783cec65c67ed1630b8bb0bc08c4 100644
--- a/ivette/.eslintignore
+++ b/ivette/.eslintignore
@@ -8,3 +8,6 @@ coverage
 lib
 # don't lint the generated API
 api
+
+# ZMQ Server is not working (yet)
+src/frama-c/client_zmq.ts
diff --git a/ivette/.eslintrc.js b/ivette/.eslintrc.js
index 322375d876f3c51d95ac3358b423fc19b4f04e30..5a3a472d6a2dddb2ad443fbe21354075b6731341 100644
--- a/ivette/.eslintrc.js
+++ b/ivette/.eslintrc.js
@@ -3,6 +3,7 @@ module.exports = {
   parser: '@typescript-eslint/parser',
   plugins: [
     '@typescript-eslint',
+    'import',
   ],
   extends: [
     'airbnb-typescript',
@@ -32,15 +33,13 @@ module.exports = {
     "@typescript-eslint/no-explicit-any": "off",
     // Allow functions without return type, even if exported function should have one
     "@typescript-eslint/explicit-function-return-type": "off",
-    // Allow function hoisting, even if it should be avoided
-    "no-use-before-define": [
-      "error",
-      { functions: false, classes: true, variables: true },
-    ],
-    "@typescript-eslint/no-use-before-define": [
-      "error",
-      { functions: false, classes: true, variables: true, typedefs: true },
-    ],
+    // Allow function hoisting, even if it should be avoided"
+    "@typescript-eslint/lines-between-class-members": "off",
+    "@typescript-eslint/space-before-function-paren": "off",
+    "@typescript-eslint/naming-convention": "off",
+    "no-constant-condition": ["error", { "checkLoops": false }],
+    "no-use-before-define": "off",
+    "@typescript-eslint/no-use-before-define": "off",
     // Prefer const when _all_ destructured values may be const
     "prefer-const": [
       "error",
@@ -51,7 +50,7 @@ module.exports = {
     // Allow return statements even if not strictly needed
     "no-useless-return": "off",
     // Forbid shadowing concerning variables
-    "no-shadow": "error",
+    "no-shadow": "off",
     // Force single class member per line
     "lines-between-class-members": [
       "error", "always", { "exceptAfterSingleLine": true }
diff --git a/ivette/src/dome/main/dome.ts b/ivette/src/dome/main/dome.ts
index 605cfbd5d84d6ec0fdfe602692e0e1221c4acba6..98bdd45a4776033eb6b088758adb8d051377fe00 100644
--- a/ivette/src/dome/main/dome.ts
+++ b/ivette/src/dome/main/dome.ts
@@ -174,9 +174,9 @@ ipcMain.on('dome.ipc.settings.sync', windowSyncSettings);
 // --- Patching Settings
 // --------------------------------------------------------------------------
 
-type patch = { key: string; value: any };
+type Patch = { key: string; value: any };
 
-function applyPatches(data: Store, args: patch[]) {
+function applyPatches(data: Store, args: Patch[]) {
   args.forEach(({ key, value }) => {
     if (value === null) {
       delete data[key];
@@ -186,7 +186,7 @@ function applyPatches(data: Store, args: patch[]) {
   });
 }
 
-function applyWindowSettings(event: IpcMainEvent, args: patch[]) {
+function applyWindowSettings(event: IpcMainEvent, args: Patch[]) {
   const handle = WindowHandles.get(event.sender.id);
   if (handle) {
     applyPatches(handle.settings, args);
@@ -194,7 +194,7 @@ function applyWindowSettings(event: IpcMainEvent, args: patch[]) {
   }
 }
 
-function applyStorageSettings(event: IpcMainEvent, args: patch[]) {
+function applyStorageSettings(event: IpcMainEvent, args: Patch[]) {
   const handle = WindowHandles.get(event.sender.id);
   if (handle) {
     applyPatches(handle.storage, args);
@@ -202,7 +202,7 @@ function applyStorageSettings(event: IpcMainEvent, args: patch[]) {
   }
 }
 
-function applyGlobalSettings(event: IpcMainEvent, args: patch[]) {
+function applyGlobalSettings(event: IpcMainEvent, args: Patch[]) {
   applyPatches(obtainGlobalSettings(), args);
   BrowserWindow.getAllWindows().forEach((w: BrowserWindow) => {
     const contents = w.webContents;
@@ -274,7 +274,7 @@ function getURL() {
   return `file://${__dirname}/index.html`;
 }
 
-function navigateURL(sender: Electron.webContents) {
+function navigateURL(sender: Electron.WebContents) {
   return (event: Electron.Event, url: string) => {
     event.preventDefault();
     const href = new URL(url);
diff --git a/ivette/src/dome/main/menubar.ts b/ivette/src/dome/main/menubar.ts
index d22df5c443ed5515b682d289ec1ff83d01413fcb..21cdb1ee679029ef96dfaa949189e35ffbf1dd3b 100644
--- a/ivette/src/dome/main/menubar.ts
+++ b/ivette/src/dome/main/menubar.ts
@@ -25,9 +25,8 @@
 // --------------------------------------------------------------------------
 
 /* eslint-disable max-len */
-/* eslint-disable @typescript-eslint/camelcase */
 
-import { app, ipcMain, BrowserWindow, Menu, MenuItem, shell } from 'electron';
+import { app, ipcMain, BrowserWindow, Menu, MenuItem, shell, KeyboardEvent } from 'electron';
 import * as System from 'dome/system';
 
 // --------------------------------------------------------------------------
@@ -48,16 +47,33 @@ function reloadWindow() {
   });
 }
 
-function toggleFullScreen(_item: MenuItem, focusedWindow: BrowserWindow) {
+function toggleFullScreen(
+  _item: MenuItem,
+  focusedWindow: BrowserWindow | undefined,
+  _evt: KeyboardEvent,
+) {
   if (focusedWindow)
     focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
 }
 
-function toggleDevTools(_item: MenuItem, focusedWindow: BrowserWindow) {
+function toggleDevTools(
+  _item: MenuItem,
+  focusedWindow: BrowserWindow | undefined,
+  _evt: KeyboardEvent,
+) {
   if (focusedWindow)
     focusedWindow.webContents.toggleDevTools();
 }
 
+function userFindInfo(
+  _item: MenuItem,
+  focusedWindow: BrowserWindow | undefined,
+  _evt: KeyboardEvent,
+) {
+  if (focusedWindow)
+    focusedWindow.webContents.send('dome.ipc.find');
+}
+
 // --------------------------------------------------------------------------
 // --- Menu Utilities
 // --------------------------------------------------------------------------
@@ -131,9 +147,9 @@ const macosAppMenuItems = (appName: string): MenuSpec => [
 // --- File Menu Items (platform dependant)
 // --------------------------------------------------------------------------
 
-const fileMenuItems_custom: MenuSpec = [];
+const fileMenuItemsCustom: MenuSpec = [];
 
-const fileMenuItems_linux: MenuSpec = [
+const fileMenuItemsLinux: MenuSpec = [
   {
     label: 'Preferences…',
     click: () => ipcMain.emit('dome.menu.settings'),
@@ -154,7 +170,7 @@ const fileMenuItems_linux: MenuSpec = [
 // --- Edit Menu Items
 // --------------------------------------------------------------------------
 
-const editMenuItems_custom: MenuSpec = [];
+const editMenuItemsCustom: MenuSpec = [];
 
 const editMenuItems: MenuSpec = [
   {
@@ -188,11 +204,7 @@ const editMenuItems: MenuSpec = [
   {
     label: 'Find',
     accelerator: 'CmdOrCtrl+F',
-    click: (
-      _item: Electron.MenuItem,
-      window: Electron.BrowserWindow,
-      _evt: Electron.KeyboardEvent,
-    ) => window.webContents.send('dome.ipc.find'),
+    click: userFindInfo,
   },
 ];
 
@@ -200,7 +212,7 @@ const editMenuItems: MenuSpec = [
 // --- View Menu Items
 // --------------------------------------------------------------------------
 
-const viewMenuItems_custom: MenuSpec = [];
+const viewMenuItemsCustom: MenuSpec = [];
 
 const viewMenuItems = (osx: boolean): MenuSpec => [
   {
@@ -222,7 +234,7 @@ const viewMenuItems = (osx: boolean): MenuSpec => [
 // --- Window Menu Items
 // --------------------------------------------------------------------------
 
-const windowMenuItems_linux: MenuSpec = [
+const windowMenuItemsLinux: MenuSpec = [
   {
     label: 'Minimize',
     accelerator: 'CmdOrCtrl+M',
@@ -241,7 +253,7 @@ const windowMenuItems_linux: MenuSpec = [
   },
 ];
 
-const windowMenuItems_macos: MenuSpec = windowMenuItems_linux.concat([
+const windowMenuItemsMacos: MenuSpec = windowMenuItemsLinux.concat([
   {
     label: 'Bring All to Front',
     role: 'front',
@@ -292,9 +304,9 @@ const customItems = new Map<string, ItemEntry>();
 
 function findMenu(label: string): MenuSpec | undefined {
   switch (label) {
-    case 'File': return fileMenuItems_custom;
-    case 'Edit': return editMenuItems_custom;
-    case 'View': return viewMenuItems_custom;
+    case 'File': return fileMenuItemsCustom;
+    case 'Edit': return editMenuItemsCustom;
+    case 'View': return viewMenuItemsCustom;
     default: {
       const cm = customMenus.find((m) => m.label === label);
       return cm && cm.submenu;
@@ -317,12 +329,12 @@ export interface CustomMenuItem extends MenuItemSpec {
   key?: string;
 }
 
-export interface Separator {
+export interface SeparatorItem {
   menu: string;
   type: 'separator';
 }
 
-export type CustomMenuItemSpec = Separator | CustomMenuItem;
+export type CustomMenuItemSpec = SeparatorItem | CustomMenuItem;
 
 export function addMenuItem(custom: CustomMenuItemSpec) {
   const menuSpec = findMenu(custom.menu);
@@ -361,10 +373,10 @@ export function addMenuItem(custom: CustomMenuItemSpec) {
     } else {
       if (!spec.click && !spec.role)
         spec.click = (
-          _item: Electron.MenuItem,
-          window: Electron.BrowserWindow,
-          _evt: Electron.KeyboardEvent,
-        ) => window.webContents.send('dome.ipc.menu.clicked', id);
+          _item: MenuItem,
+          window: BrowserWindow | undefined,
+          _evt: KeyboardEvent,
+        ) => window?.webContents.send('dome.ipc.menu.clicked', id);
       customItems.set(id, { spec });
       menuSpec.push(spec);
     }
@@ -392,13 +404,13 @@ function template(): CustomMenu[] {
       return ([] as CustomMenu[]).concat(
         [
           { label: app.name, submenu: macosAppMenuItems(app.name) },
-          { label: 'File', submenu: fileMenuItems_custom },
-          { label: 'Edit', submenu: concatSep(editMenuItems, editMenuItems_custom) },
-          { label: 'View', submenu: concatSep(viewMenuItems_custom, viewMenuItems(true)) },
+          { label: 'File', submenu: fileMenuItemsCustom },
+          { label: 'Edit', submenu: concatSep(editMenuItems, editMenuItemsCustom) },
+          { label: 'View', submenu: concatSep(viewMenuItemsCustom, viewMenuItems(true)) },
         ],
         customMenus,
         [
-          { label: 'Window', role: 'window', submenu: windowMenuItems_macos },
+          { label: 'Window', role: 'window', submenu: windowMenuItemsMacos },
           { label: 'Help', role: 'help', submenu: helpMenuItems },
         ],
       );
@@ -407,13 +419,13 @@ function template(): CustomMenu[] {
     default:
       return ([] as CustomMenu[]).concat(
         [
-          { label: 'File', submenu: concatSep(fileMenuItems_custom, fileMenuItems_linux) },
-          { label: 'Edit', submenu: concatSep(editMenuItems, editMenuItems_custom) },
-          { label: 'View', submenu: concatSep(viewMenuItems_custom, viewMenuItems(false)) },
+          { label: 'File', submenu: concatSep(fileMenuItemsCustom, fileMenuItemsLinux) },
+          { label: 'Edit', submenu: concatSep(editMenuItems, editMenuItemsCustom) },
+          { label: 'View', submenu: concatSep(viewMenuItemsCustom, viewMenuItems(false)) },
         ],
         customMenus,
         [
-          { label: 'Window', submenu: windowMenuItems_linux },
+          { label: 'Window', submenu: windowMenuItemsLinux },
           { label: 'Help', submenu: helpMenuItems },
         ],
       );
@@ -445,9 +457,9 @@ export function install() {
 
 // Called by reload above
 function reset() {
-  fileMenuItems_custom.length = 0;
-  editMenuItems_custom.length = 0;
-  viewMenuItems_custom.length = 0;
+  fileMenuItemsCustom.length = 0;
+  editMenuItemsCustom.length = 0;
+  viewMenuItemsCustom.length = 0;
   customMenus.length = 0;
   customItems.clear();
   install();
diff --git a/ivette/src/dome/misc/system.ts b/ivette/src/dome/misc/system.ts
index 99bcf87c156d06697c1cf614b40227f90fc06f62..df85d83050c5c70b22c7707c5c2d48cd6dc6a0d6 100644
--- a/ivette/src/dome/misc/system.ts
+++ b/ivette/src/dome/misc/system.ts
@@ -36,9 +36,9 @@ import Emitter from 'events';
 import Exec from 'child_process';
 import fspath from 'path';
 import fs from 'fs';
-import { app, remote } from 'electron';
+import { app } from 'electron';
 
-declare const __static: string;
+declare const staticPath: string;
 
 // --------------------------------------------------------------------------
 // --- Platform Specificities
@@ -121,7 +121,7 @@ export function doExit() {
 let COMMAND_WDIR = '.';
 let COMMAND_ARGV: string[] = [];
 
-function SET_COMMAND(argv: string[], wdir: string) {
+function setCommandLine(argv: string[], wdir: string) {
   COMMAND_ARGV = argv;
   COMMAND_WDIR = wdir;
 }
@@ -130,22 +130,20 @@ function SET_COMMAND(argv: string[], wdir: string) {
 // --- User's Directories
 // --------------------------------------------------------------------------
 
-const appProxy = app || remote.app;
-
 /** Returns user's home directory. */
-export function getHome() { return appProxy.getPath('home'); }
+export function getHome() { return app.getPath('home'); }
 
 /** Returns user's desktop directory. */
-export function getDesktop() { return appProxy.getPath('desktop'); }
+export function getDesktop() { return app.getPath('desktop'); }
 
 /** Returns user's documents directory. */
-export function getDocuments() { return appProxy.getPath('documents'); }
+export function getDocuments() { return app.getPath('documents'); }
 
 /** Returns user's downloads directory. */
-export function getDownloads() { return appProxy.getPath('downloads'); }
+export function getDownloads() { return app.getPath('downloads'); }
 
 /** Returns temporary directory. */
-export function getTempDir() { return appProxy.getPath('temp'); }
+export function getTempDir() { return app.getPath('temp'); }
 
 /**
    Working directory (Application Window).
@@ -185,7 +183,7 @@ export function getArguments() { return COMMAND_ARGV; }
     configuration.
 */
 export function getStatic(...path: string[]) {
-  return fspath.join(__static, ...path);
+  return fspath.join(staticPath, ...path);
 }
 
 // --------------------------------------------------------------------------
@@ -308,14 +306,10 @@ export function exists(path: string) {
 /**
    Reads a textual file contents.
 
-   Promisified
-   [Node `fs.readFile`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_readfile_path_options_callback)
-   using `UTF-8` encoding.
+   Promisified `fs.readFile` using `utf-8` encoding.
  */
 export function readFile(path: string): Promise<string> {
-  return new Promise((result, reject) => {
-    fs.readFile(path, 'UTF-8', (err, data) => (err ? reject(err) : result(data)));
-  });
+  return fs.promises.readFile(path, { encoding: 'utf-8' });
 }
 
 // --------------------------------------------------------------------------
@@ -325,14 +319,10 @@ export function readFile(path: string): Promise<string> {
 /**
    Writes a textual content in a file.
 
-   Promisified
-   [Node `fs.writeFile`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_writefile_file_data_options_callback)
-   using `UTF-8` encoding.
+   Promisified `fs.writeFile` using `utf-8` encoding.
  */
-export function writeFile(path: string, content: string): Promise<void> {
-  return new Promise((result, reject) => {
-    fs.writeFile(path, content, 'UTF-8', (err) => (err ? reject(err) : result()));
-  });
+export async function writeFile(path: string, content: string): Promise<void> {
+  return fs.promises.writeFile(path, content, { encoding: 'utf-8' });
 }
 
 // --------------------------------------------------------------------------
@@ -344,14 +334,10 @@ export function writeFile(path: string, content: string): Promise<void> {
    @param srcPath - the source file path
    @param tgtPath - the target file path
 
-   Promisified
-   [Node `fs.copyFile`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_copyfile_src_dest_flags_callback)
-   using `UTF-8` encoding.
+   Promisified `fs.copyFile`.
  */
-export function copyFile(srcPath: string, tgtPath: string): Promise<void> {
-  return new Promise((result, reject) => {
-    fs.copyFile(srcPath, tgtPath, (err) => (err ? reject(err) : result()));
-  });
+export async function copyFile(srcPath: string, tgtPath: string): Promise<void> {
+  return fs.promises.copyFile(srcPath, tgtPath);
 }
 
 // --------------------------------------------------------------------------
@@ -362,24 +348,15 @@ export function copyFile(srcPath: string, tgtPath: string): Promise<void> {
    Reads a directory.
    @returns directory contents (local names)
 
-   Promisified
-   [Node `fs.readdir`](https://nodejs.org/dist/latest-v12.x/docs/api/fs.html#fs_fs_readdir_path_options_callback).
+   Promisified `fs.readdir`.
 
-   Uses `UTF-8` encoding to obtain (relative) file names instead of byte buffers. On MacOS, `.DS_Store` entries
-   are filtered out.
+   Uses `utf-8` encoding to obtain (relative) file names instead of byte buffers.
+   On MacOS, `.DS_Store` entries are filtered out.
 */
-export function readDir(path: string): Promise<string[]> {
+export async function readDir(path: string): Promise<string[]> {
   const filterDir = (f: string) => f !== '.DS_Store';
-  return new Promise((result, reject) => {
-    fs.readdir(
-      path,
-      { encoding: 'UTF-8', withFileTypes: true },
-      (err: NodeJS.ErrnoException | null, files: fs.Dirent[]) => {
-        if (err) reject(err);
-        else result(files.map((fn) => fn.name).filter(filterDir));
-      },
-    );
-  });
+  const entries = await fs.promises.readdir(path, { encoding: 'utf-8', withFileTypes: true });
+  return entries.map((fn) => fn.name).filter(filterDir);
 }
 
 // --------------------------------------------------------------------------
@@ -441,7 +418,8 @@ async function rmDirRec(path: string): Promise<void> {
   try {
     const stats = fs.statSync(path);
     if (stats.isFile()) {
-      return remove(path);
+      await remove(path);
+      return;
     }
     if (stats.isDirectory()) {
       const rmDirSub = (name: string) => {
@@ -506,9 +484,9 @@ atExit(() => {
 export type StdPipe = { path?: string | undefined; mode?: number; pipe?: boolean };
 export type StdOptions = undefined | 'null' | 'ignore' | 'pipe' | StdPipe;
 
-type stdio = { io: number | 'pipe' | 'ignore' | 'ipc'; fd?: number };
+type StdIO = { io: number | 'pipe' | 'ignore' | 'ipc'; fd?: number };
 
-function stdSpec(spec: StdOptions, isOutput: boolean): stdio {
+function stdSpec(spec: StdOptions, isOutput: boolean): StdIO {
   switch (spec) {
     case undefined:
       return { io: isOutput ? 'pipe' : 'ignore' };
@@ -533,7 +511,7 @@ interface Readable {
 
 function pipeTee(std: Readable, fd: number) {
   if (!fd) return;
-  const out = fs.createWriteStream('<ignored>', { fd, encoding: 'UTF-8' });
+  const out = fs.createWriteStream('<ignored>', { fd, encoding: 'utf-8' });
   out.on('error', (err) => {
     console.warn('[Dome] can not pipe:', err);
     std.unpipe(out);
@@ -627,11 +605,11 @@ export function spawn(
     const err = child.stderr;
 
     if (out && stdout.fd) {
-      out.setEncoding('UTF-8');
+      out.setEncoding('utf-8');
       pipeTee(out, stdout.fd);
     }
     if (err && stderr.fd) {
-      err.setEncoding('UTF-8');
+      err.setEncoding('utf-8');
       pipeTee(err, stderr.fd);
     }
 
@@ -651,7 +629,7 @@ const WINDOW_PREFERENCES_ARGV = '--dome-preferences-window';
 // --------------------------------------------------------------------------
 
 export default {
-  SET_COMMAND,
+  setCommandLine,
   WINDOW_APPLICATION_ARGV,
   WINDOW_PREFERENCES_ARGV,
 };
diff --git a/ivette/src/dome/misc/utils.ts b/ivette/src/dome/misc/utils.ts
index b15ff61229e284e6c022a5eea04f439168e90176..2d896660ba950b8c98dc056b8910638dea42ab12 100644
--- a/ivette/src/dome/misc/utils.ts
+++ b/ivette/src/dome/misc/utils.ts
@@ -31,9 +31,9 @@
 
 import type { CSSProperties } from 'react';
 
-type falsy = undefined | boolean | null | '';
+type Falsy = undefined | boolean | null | '';
 
-export type ClassSpec = string | falsy | { [cname: string]: true | falsy };
+export type ClassSpec = string | Falsy | { [cname: string]: true | Falsy };
 
 /**
    Utility function to merge various HTML class properties
@@ -75,7 +75,7 @@ export function classes(
   return buffer.join(' ');
 }
 
-export type StyleSpec = falsy | CSSProperties;
+export type StyleSpec = Falsy | CSSProperties;
 
 /**
    Utility function to merge various CSS style properties
diff --git a/ivette/src/dome/renderer/data/compare.ts b/ivette/src/dome/renderer/data/compare.ts
index 26dc17956720dfca5419f5034286885d1f83baa3..5254f927550462a91c12d75b8b62874f67756b57 100644
--- a/ivette/src/dome/renderer/data/compare.ts
+++ b/ivette/src/dome/renderer/data/compare.ts
@@ -56,10 +56,10 @@ export const isEqual = FastCompare;
 export function equal(_x: any, _y: any): 0 { return 0; }
 
 /** Primitive comparison works on this type. */
-export type bignum = bigint | number;
+export type BigNum = bigint | number;
 
 /** Detect Non-NaN numbers and big-ints. */
-export function isBigNum(x: any): x is bignum {
+export function isBigNum(x: any): x is BigNum {
   return (
     (typeof (x) === 'bigint') ||
     (typeof (x) === 'number' && !Number.isNaN(x))
@@ -91,7 +91,7 @@ export const string: Order<string> = primitive;
 /**
    Primitive comparison for (big) integers (non NaN numbers included).
  */
-export const bignum: Order<bignum> = primitive;
+export const bignum: Order<BigNum> = primitive;
 
 /**
    Primitive comparison for number (NaN included).
@@ -291,13 +291,13 @@ export function byAllFields<A>(order: ByAllFields<A>): Order<A> {
   };
 }
 
-export type dict<A> = undefined | null | { [key: string]: A };
+export type Dict<A> = undefined | null | { [key: string]: A };
 
 /**
    Compare dictionaries _wrt_ lexicographic order of entries.
 */
-export function dictionary<A>(order: Order<A>): Order<dict<A>> {
-  return (x: dict<A>, y: dict<A>) => {
+export function dictionary<A>(order: Order<A>): Order<Dict<A>> {
+  return (x: Dict<A>, y: Dict<A>) => {
     if (x === y) return 0;
     const dx = x ?? {};
     const dy = y ?? {};
@@ -398,29 +398,31 @@ export function tuple5<A, B, C, D, E>(
 // --- Structural Comparison
 // --------------------------------------------------------------------------
 
+/* eslint-disable no-shadow */
+
 /** @internal */
-enum RANK {
+enum IRANK {
   UNDEFINED,
   BOOLEAN, SYMBOL, NAN, BIGNUM,
   STRING,
-  ARRAY, OBJECT, FUNCTION
+  ARRAY, OBJECT, FUNCTION,
 }
 
 /** @internal */
-function rank(x: any): RANK {
+function rank(x: any): IRANK {
   const t = typeof x;
   switch (t) {
-    case 'undefined': return RANK.UNDEFINED;
-    case 'boolean': return RANK.BOOLEAN;
-    case 'symbol': return RANK.SYMBOL;
+    case 'undefined': return IRANK.UNDEFINED;
+    case 'boolean': return IRANK.BOOLEAN;
+    case 'symbol': return IRANK.SYMBOL;
     case 'number':
-      return Number.isNaN(x) ? RANK.NAN : RANK.BIGNUM;
+      return Number.isNaN(x) ? IRANK.NAN : IRANK.BIGNUM;
     case 'bigint':
-      return RANK.BIGNUM;
-    case 'string': return RANK.STRING;
-    case 'function': return RANK.FUNCTION;
+      return IRANK.BIGNUM;
+    case 'string': return IRANK.STRING;
+    case 'function': return IRANK.FUNCTION;
     case 'object':
-      return Array.isArray(x) ? RANK.ARRAY : RANK.OBJECT;
+      return Array.isArray(x) ? IRANK.ARRAY : IRANK.OBJECT;
   }
 }
 
diff --git a/ivette/src/dome/renderer/data/json.ts b/ivette/src/dome/renderer/data/json.ts
index b848fc1671087713f5c981e4b718cf85a3012a64..1d0a52ad8928d2ba45d11b8d1259e2532fed246a 100644
--- a/ivette/src/dome/renderer/data/json.ts
+++ b/ivette/src/dome/renderer/data/json.ts
@@ -32,6 +32,8 @@
 
 import { DEVEL } from 'dome/system';
 
+/* eslint-disable @typescript-eslint/naming-convention, no-shadow */
+
 export type json =
   undefined | null | boolean | number | string |
   json[] | { [key: string]: json };
diff --git a/ivette/src/dome/renderer/dialogs.tsx b/ivette/src/dome/renderer/dialogs.tsx
index bbdda3f02693deb736dca5a2a21142fb060662a7..d0936827972eeca84acf34c07efcaf4593630eb2 100644
--- a/ivette/src/dome/renderer/dialogs.tsx
+++ b/ivette/src/dome/renderer/dialogs.tsx
@@ -27,7 +27,7 @@
  */
 
 import filepath from 'path';
-import { remote } from 'electron';
+import { dialog } from 'electron';
 import * as System from 'dome/system';
 
 // --------------------------------------------------------------------------
@@ -122,8 +122,7 @@ export async function showMessageBox<A>(
 
   if (cancelId === defaultId) cancelId = -1;
 
-  return remote.dialog.showMessageBox(
-    remote.getCurrentWindow(),
+  return dialog.showMessageBox(
     {
       type: kind,
       message,
@@ -197,8 +196,7 @@ export async function showOpenFile(
   props: OpenFileProps,
 ): Promise<string | undefined> {
   const { title, label, path, hidden = false, filters } = props;
-  return remote.dialog.showOpenDialog(
-    remote.getCurrentWindow(),
+  return dialog.showOpenDialog(
     {
       title,
       buttonLabel: label,
@@ -221,8 +219,7 @@ export async function showOpenFiles(
 ): Promise<string[] | undefined> {
   const { title, label, path, hidden, filters } = props;
 
-  return remote.dialog.showOpenDialog(
-    remote.getCurrentWindow(),
+  return dialog.showOpenDialog(
     {
       title,
       buttonLabel: label,
@@ -258,8 +255,7 @@ export async function showSaveFile(
   props: SaveFileProps,
 ): Promise<string | undefined> {
   const { title, label, path, filters } = props;
-  return remote.dialog.showSaveDialog(
-    remote.getCurrentWindow(),
+  return dialog.showSaveDialog(
     {
       title,
       buttonLabel: label,
@@ -292,8 +288,7 @@ export async function showOpenDir(
     default: break;
   }
 
-  return remote.dialog.showOpenDialog(
-    remote.getCurrentWindow(),
+  return dialog.showOpenDialog(
     {
       title,
       buttonLabel: label,
diff --git a/ivette/src/dome/renderer/dome.tsx b/ivette/src/dome/renderer/dome.tsx
index 0edda413386105a2b24ff69313cb8dc09149229b..63386e2fb374fe922ad4098cd04866443be27a9e 100644
--- a/ivette/src/dome/renderer/dome.tsx
+++ b/ivette/src/dome/renderer/dome.tsx
@@ -42,7 +42,7 @@ import _ from 'lodash';
 import React from 'react';
 import ReactDOM from 'react-dom';
 import { AppContainer } from 'react-hot-loader';
-import { remote, ipcRenderer } from 'electron';
+import { Menu, MenuItem, ipcRenderer } from 'electron';
 import SYS, * as System from 'dome/system';
 import * as Json from 'dome/data/json';
 import * as Settings from 'dome/data/settings';
@@ -168,7 +168,7 @@ export function onCommand(
 }
 
 ipcRenderer.on('dome.ipc.command', (_event, argv, wdir) => {
-  SYS.SET_COMMAND(argv, wdir);
+  SYS.setCommandLine(argv, wdir);
   System.emitter.emit('dome.command', argv, wdir);
 });
 
@@ -467,7 +467,6 @@ export function popupMenu(
   items: PopupMenuItem[],
   callback?: (item: string | undefined) => void,
 ) {
-  const { Menu, MenuItem } = remote;
   const menu = new Menu();
   let selected = '';
   let kid = 0;
@@ -489,7 +488,7 @@ export function popupMenu(
     }
   });
   const job = callback ? () => callback(selected) : undefined;
-  menu.popup({ window: remote.getCurrentWindow(), callback: job });
+  menu.popup({ callback: job });
 }
 
 // --------------------------------------------------------------------------
diff --git a/ivette/src/dome/renderer/errors.tsx b/ivette/src/dome/renderer/errors.tsx
index b424ac4ec8832ee2af4999653b2c70f7c83f9bd9..a955124cf33a9dd76ad9d008f1b1e4b27c765555 100644
--- a/ivette/src/dome/renderer/errors.tsx
+++ b/ivette/src/dome/renderer/errors.tsx
@@ -60,7 +60,7 @@ interface CatchState {
 /**
    React Error Boundaries.
  */
-export class Catch extends React.Component<CatchProps, CatchState, {}> {
+export class Catch extends React.Component<CatchProps, CatchState, unknown> {
 
   constructor(props: CatchProps) {
     super(props);
diff --git a/ivette/src/dome/renderer/frame/sidebars.tsx b/ivette/src/dome/renderer/frame/sidebars.tsx
index 7cbe2a4c7478fd2f3534070287e833d49fff7bc1..ab00240d36aeedf21f565b28fd781f1cb442fe2f 100644
--- a/ivette/src/dome/renderer/frame/sidebars.tsx
+++ b/ivette/src/dome/renderer/frame/sidebars.tsx
@@ -68,7 +68,7 @@ export function SideBar(props: SideBarProps) {
 // --------------------------------------------------------------------------
 
 export type BadgeElt = undefined | null | string | number | React.ReactNode;
-export type Badge = BadgeElt | BadgeElt[];
+export type Badges = BadgeElt | BadgeElt[];
 
 const makeBadgeElt = (elt: BadgeElt): React.ReactNode => {
   if (elt === undefined || elt === null) return null;
@@ -81,7 +81,7 @@ const makeBadgeElt = (elt: BadgeElt): React.ReactNode => {
   }
 };
 
-const makeBadge = (elt: Badge): React.ReactNode => {
+const makeBadge = (elt: Badges): React.ReactNode => {
   if (Array.isArray(elt))
     return elt.map(makeBadgeElt);
   return makeBadgeElt(elt);
@@ -120,7 +120,7 @@ export interface SectionProps {
   /** Disabled sections are made unvisible. */
   disabled?: boolean;
   /** Badge summary (only visible when folded). */
-  summary?: Badge;
+  summary?: Badges;
   /** Right-click callback. */
   onContextMenu?: () => void;
   /** Section contents. */
@@ -182,7 +182,7 @@ export interface ItemProps {
   /** Item tooltip text. */
   title?: string;
   /** Badge. */
-  badge?: Badge;
+  badge?: Badges;
   /** Enabled item. */
   enabled?: boolean;
   /** Disabled item (dimmed). */
diff --git a/ivette/src/dome/renderer/frame/toolbars.tsx b/ivette/src/dome/renderer/frame/toolbars.tsx
index 6064de0c647d07e2fae893a4d307073c0c37c6fc..25c1c067ebd2919c46fd200bbb1ec0e3e5b46c45 100644
--- a/ivette/src/dome/renderer/frame/toolbars.tsx
+++ b/ivette/src/dome/renderer/frame/toolbars.tsx
@@ -31,7 +31,6 @@
 
 import React from 'react';
 import { Event, useEvent, find } from 'dome';
-import { debounce } from 'lodash';
 import { SVG } from 'dome/controls/icons';
 import { Label } from 'dome/controls/labels';
 import { classes } from 'dome/misc/utils';
@@ -95,12 +94,6 @@ const KIND = (kind: undefined | string) => (
   kind ? ` dome-xToolBar-${kind}` : ''
 );
 
-interface SELECT<A> {
-  selected?: boolean;
-  selection?: A;
-  value?: A;
-}
-
 export type ButtonKind =
   | 'default' | 'cancel' | 'warning' | 'positive' | 'negative';
 
@@ -268,6 +261,12 @@ export interface SearchFieldProps<A> {
   event?: null | Event<void>;
 }
 
+interface Searching {
+  pattern?: string;
+  timer?: NodeJS.Timeout | undefined;
+  onSearch?: ((p: string) => void);
+}
+
 /**
    Search Bar.
  */
@@ -277,18 +276,24 @@ export function SearchField<A = undefined>(props: SearchFieldProps<A>) {
   const focus = () => inputRef.current?.focus();
   const [value, setValue] = React.useState('');
   const [index, setIndex] = React.useState(-1);
+  const searching = React.useRef<Searching>({});
   const { onHint, onSelect, onSearch, hints = [] } = props;
 
   // Find event trigger
   useEvent(props.event ?? find, focus);
 
   // Lookup trigger
-  const triggerLookup = React.useCallback(
-    debounce((pattern: string) => {
-      if (onSearch) onSearch(pattern);
-    }, DEBOUNCED_SEARCH),
-    [onSearch],
-  );
+  const triggerLookup = React.useCallback((pattern: string) => {
+    const s = searching.current;
+    s.pattern = pattern;
+    s.onSearch = onSearch;
+    if (!s.timer) {
+      s.timer = setTimeout(() => {
+        s.timer = undefined;
+        if (s.onSearch && s.pattern) s.onSearch(s.pattern);
+      }, DEBOUNCED_SEARCH);
+    }
+  }, [onSearch]);
 
   // Blur Event
   const onBlur = () => {
diff --git a/ivette/src/dome/renderer/layout/forms.tsx b/ivette/src/dome/renderer/layout/forms.tsx
index 86183586e91b5cbd51902f9cbe389a1bc3430244..79d96f2f1e7291475ba8d34b99ae8c164341df4c 100644
--- a/ivette/src/dome/renderer/layout/forms.tsx
+++ b/ivette/src/dome/renderer/layout/forms.tsx
@@ -45,12 +45,12 @@ import * as Utils from 'dome/misc/utils';
 import { SVG } from 'dome/controls/icons';
 import { Checkbox, Radio, Select as SelectMenu } from 'dome/controls/buttons';
 
-export type Error =
+export type FieldError =
   | undefined | boolean | string
-  | { [key: string]: Error } | Error[];
-export type Checker<A> = (value: A) => boolean | Error;
-export type Callback<A> = (value: A, error: Error) => void;
-export type FieldState<A> = [A, Error, Callback<A>];
+  | { [key: string]: FieldError } | FieldError[];
+export type Checker<A> = (value: A) => boolean | FieldError;
+export type Callback<A> = (value: A, error: FieldError) => void;
+export type FieldState<A> = [A, FieldError, Callback<A>];
 
 /* --------------------------------------------------------------------------*/
 /* --- State Errors Utilities                                             ---*/
@@ -66,28 +66,28 @@ export function inRange(
 export function validate<A>(
   value: A,
   checker: undefined | Checker<A>,
-): Error {
+): FieldError {
   if (checker) {
     try {
       const r = checker(value);
       if (r === undefined || r === true) return undefined;
       return r;
     } catch (err) {
-      return err.toString() || false;
+      return '' + err || false;
     }
   }
   return undefined;
 }
 
-export function isValid(err: Error): boolean { return !err; }
+export function isValid(err: FieldError): boolean { return !err; }
 
-type ObjectError = { [key: string]: Error };
+type ObjectError = { [key: string]: FieldError };
 
-function isObjectError(err: Error): err is ObjectError {
+function isObjectError(err: FieldError): err is ObjectError {
   return typeof err === 'object' && !Array.isArray(err);
 }
 
-function isArrayError(err: Error): err is Error[] {
+function isArrayError(err: FieldError): err is FieldError[] {
   return Array.isArray(err);
 }
 
@@ -99,7 +99,7 @@ function isValidObject(err: ObjectError): boolean {
   return true;
 }
 
-function isValidArray(err: Error[]): boolean {
+function isValidArray(err: FieldError[]): boolean {
   for (let k = 0; k < err.length; k++) {
     if (!isValid(err[k])) return false;
   }
@@ -117,8 +117,8 @@ export function useState<A>(
   onChange?: Callback<A>,
 ): FieldState<A> {
   const [value, setValue] = React.useState<A>(defaultValue);
-  const [error, setError] = React.useState<Error>(undefined);
-  const setState = React.useCallback((newValue: A, newError: Error) => {
+  const [error, setError] = React.useState<FieldError>(undefined);
+  const setState = React.useCallback((newValue: A, newError: FieldError) => {
     const localError = validate(newValue, checker) || newError;
     setValue(newValue);
     setError(localError);
@@ -133,9 +133,9 @@ export function useValid<A>(
 ): FieldState<A> {
   const [value, setValue] = state;
   const [local, setLocal] = React.useState(value);
-  const [error, setError] = React.useState<Error>(undefined);
+  const [error, setError] = React.useState<FieldError>(undefined);
   const update = React.useCallback(
-    (newValue: A, newError: Error) => {
+    (newValue: A, newError: FieldError) => {
       setLocal(newValue);
       setError(newError);
       if (!newError) setValue(newValue);
@@ -162,7 +162,7 @@ export function useDefined<A>(
 ): FieldState<A | undefined> {
   const [value, error, setState] = state;
   const update = React.useCallback(
-    (newValue: A | undefined, newError: Error) => {
+    (newValue: A | undefined, newError: FieldError) => {
       if (newValue !== undefined) {
         setState(newValue, newError);
       }
@@ -182,7 +182,7 @@ export function useRequired<A>(
   const [value, error, setState] = state;
   const cache = React.useRef(value);
   const update = React.useCallback(
-    (newValue: A | undefined, newError: Error) => {
+    (newValue: A | undefined, newError: FieldError) => {
       if (newValue === undefined) {
         setState(cache.current, onError || 'Required field');
       } else {
@@ -202,7 +202,7 @@ export function useChecker<A>(
   checker?: Checker<A>,
 ): FieldState<A> {
   const [value, error, setState] = state;
-  const update = React.useCallback((newValue: A, newError: Error) => {
+  const update = React.useCallback((newValue: A, newError: FieldError) => {
     const localError = validate(newValue, checker) || newError;
     setState(newValue, localError);
   }, [checker, setState]);
@@ -235,11 +235,11 @@ export function useFilter<A, B>(
 
   const [value, error, setState] = state;
   const [localValue, setLocalValue] = React.useState(defaultValue);
-  const [localError, setLocalError] = React.useState<Error>(undefined);
+  const [localError, setLocalError] = React.useState<FieldError>(undefined);
   const [dangling, setDangling] = React.useState(false);
 
   const update = React.useCallback(
-    (newValue: B, newError: Error) => {
+    (newValue: B, newError: FieldError) => {
       try {
         const outValue = output(newValue);
         setLocalValue(newValue);
@@ -250,7 +250,7 @@ export function useFilter<A, B>(
         }
       } catch (err) {
         setLocalValue(newValue);
-        setLocalError(newError || err.toString() || 'Invalid value');
+        setLocalError(newError || err ? '' + err : 'Invalid value');
         setDangling(true);
       }
     }, [output, setState, setLocalValue, setLocalError],
@@ -262,7 +262,7 @@ export function useFilter<A, B>(
   try {
     return [input(value), error, update];
   } catch (err) {
-    return [localValue, err.toString() || 'Invalid input', update];
+    return [localValue, err ? '' + err : 'Invalid input', update];
   }
 
 }
@@ -284,12 +284,12 @@ export function useLatency<A>(
   const update = React.useMemo(() => {
     if (period > 0) {
       const propagate = debounce(
-        (lateValue: A, lateError: Error) => {
+        (lateValue: A, lateError: FieldError) => {
           setState(lateValue, lateError);
           setDangling(false);
         }, period,
       );
-      return (newValue: A, newError: Error) => {
+      return (newValue: A, newError: FieldError) => {
         setLocalValue(newValue);
         setLocalError(newError);
         setDangling(true);
@@ -315,7 +315,7 @@ export function useProperty<A, K extends keyof A>(
   checker?: Checker<A[K]>,
 ): FieldState<A[K]> {
   const [value, error, setState] = state;
-  const update = React.useCallback((newProp: A[K], newError: Error) => {
+  const update = React.useCallback((newProp: A[K], newError: FieldError) => {
     const newValue = { ...value, [property]: newProp };
     const objError = isObjectError(error) ? error : {};
     const propError = validate(newProp, checker) || newError;
@@ -334,7 +334,7 @@ export function useIndex<A>(
   checker?: Checker<A>,
 ): FieldState<A> {
   const [array, error, setState] = state;
-  const update = React.useCallback((newValue: A, newError: Error) => {
+  const update = React.useCallback((newValue: A, newError: FieldError) => {
     const newArray = array.slice();
     newArray[index] = newValue;
     const localError = isArrayError(error) ? error.slice() : [];
@@ -436,7 +436,7 @@ export interface WarningProps {
   /** Short warning message (displayed on hover). */
   warning?: string;
   /** Error details (if a string is provided, in tooltip). */
-  error?: Error;
+  error?: FieldError;
   /** Label offset. */
   offset?: number;
 }
@@ -494,7 +494,7 @@ export interface SectionProps extends FilterProps, Children {
   /** Warning Error (when unfolded). */
   warning?: string;
   /** Associated Error. */
-  error?: Error;
+  error?: FieldError;
   /** Fold/Unfold settings. */
   settings?: string;
   /** Fold/Unfold state (defaults to false). */
@@ -550,7 +550,7 @@ export interface GenericFieldProps extends FilterProps, Children {
   /** Warning message (in case of error). */
   onError?: string;
   /** Error (if any). */
-  error?: Error;
+  error?: FieldError;
 }
 
 let FIELDID = 0;
@@ -626,7 +626,7 @@ export interface FieldProps<A> extends FilterProps {
 }
 
 type InputEvent = { target: { value: string } };
-type InputState = [string, Error, (evt: InputEvent) => void];
+type InputState = [string, FieldError, (evt: InputEvent) => void];
 
 function useChangeEvent(setState: Callback<string>) {
   return React.useCallback(
@@ -635,17 +635,6 @@ function useChangeEvent(setState: Callback<string>) {
   );
 }
 
-function useTextInputField(
-  props: TextFieldProps,
-  defaultLatency: number,
-): InputState {
-  const checked = useChecker(props.state, props.checker);
-  const period = props.latency ?? defaultLatency;
-  const [value, error, setState] = useLatency(checked, period);
-  const onChange = useChangeEvent(setState);
-  return [value || '', error, onChange];
-}
-
 /* --------------------------------------------------------------------------*/
 /* --- Text Fields                                                        ---*/
 /* --------------------------------------------------------------------------*/
@@ -658,6 +647,17 @@ export interface TextFieldProps extends FieldProps<string | undefined> {
   latency?: number;
 }
 
+function useTextInputField(
+  props: TextFieldProps,
+  defaultLatency: number,
+): InputState {
+  const checked = useChecker(props.state, props.checker);
+  const period = props.latency ?? defaultLatency;
+  const [value, error, setState] = useLatency(checked, period);
+  const onChange = useChangeEvent(setState);
+  return [value || '', error, onChange];
+}
+
 /**
    Text Field.
    @category Text Fields
diff --git a/ivette/src/dome/renderer/table/views.tsx b/ivette/src/dome/renderer/table/views.tsx
index 2c63f9793913c048788823025728365a01006a13..55fddd2c7461206b42cea9c972f658e6e6fa487b 100644
--- a/ivette/src/dome/renderer/table/views.tsx
+++ b/ivette/src/dome/renderer/table/views.tsx
@@ -206,8 +206,8 @@ interface PopupItem {
 type PopupMenu = ('separator' | PopupItem)[];
 
 type Cmap<A> = Map<string, A>;
-type Cprops = ColProps<any>;
 type ColProps<R> = ColumnProps<R, any>;
+type Cprops = ColProps<any>;
 
 // --------------------------------------------------------------------------
 // --- Column Utilities
@@ -239,8 +239,8 @@ function makeRowGetter<Key, Row>(model?: Model<Key, Row>) {
 }
 
 function makeDataGetter(
-  getter: ((row: any, dataKey: string) => any) = defaultGetter,
   dataKey: string,
+  getter: ((row: any, dataKey: string) => any) = defaultGetter,
 ): TableCellDataGetter {
   return (({ rowData }) => {
     try {
@@ -644,7 +644,7 @@ class TableState<Key, Row> {
   computeGetter(id: string, dataKey: string, props: Cprops) {
     const current = this.getter.get(id);
     if (current) return current;
-    const dataGetter = makeDataGetter(props.getter, dataKey);
+    const dataGetter = makeDataGetter(dataKey, props.getter);
     this.getter.set(id, dataGetter);
     return dataGetter;
   }
diff --git a/ivette/src/dome/renderer/text/buffers.ts b/ivette/src/dome/renderer/text/buffers.ts
index 712089fa924a872903f7903c867cd41b43dfdecd..5fe857bd0dd994b3c459503ff52c3b7a79745cd9 100644
--- a/ivette/src/dome/renderer/text/buffers.ts
+++ b/ivette/src/dome/renderer/text/buffers.ts
@@ -113,6 +113,8 @@ function byVisibleTag(lmin: number, lmax: number) {
 // --- Buffer
 // --------------------------------------------------------------------------
 
+type TextMarker = CodeMirror.TextMarker<CodeMirror.MarkerRange>;
+
 export interface RichTextBufferProps {
 
   /**
@@ -184,7 +186,7 @@ export class RichTextBuffer extends Emitter {
   private cssmarkers = new Map<string, CSSMarker>();
 
   // Indexed by marker user identifier
-  private textmarkers = new Map<string, CodeMirror.TextMarker[]>();
+  private textmarkers = new Map<string, TextMarker[]>();
 
   private decorator?: Decorator;
   private edited = false;
@@ -327,7 +329,7 @@ export class RichTextBuffer extends Emitter {
 
   /** Lookup for the text markers associated with a marker identifier.
       Remove the marked tags from the buffered tag array. */
-  findTextMarker(id: string): CodeMirror.TextMarker[] {
+  findTextMarker(id: string): TextMarker[] {
     this.doFlushText();
     this.bufferedTags.forEach((tg, idx) => {
       if (tg?.id === id) {
@@ -470,8 +472,10 @@ export class RichTextBuffer extends Emitter {
       let line = Infinity;
       this.findTextMarker(position).forEach((tm) => {
         const rg = tm.find();
-        const ln = rg.from.line;
-        if (ln < line) line = ln;
+        if (rg && rg.from) {
+          const ln = rg.from.line;
+          if (ln < line) line = ln;
+        }
       });
       if (line !== Infinity)
         this.emit('scroll', line);
@@ -497,7 +501,7 @@ export class RichTextBuffer extends Emitter {
 
   private onChange(
     _editor: CodeMirror.Editor,
-    change: CodeMirror.EditorChangeLinkedList,
+    change: CodeMirror.EditorChange,
   ) {
     if (change.origin !== 'buffer') {
       this.setEdited(true);
diff --git a/ivette/src/dome/renderer/text/editors.tsx b/ivette/src/dome/renderer/text/editors.tsx
index ffa7c9193c00ea62ad7f9aebe63099b80cfc1a5e..cb9036dc52f980dcf660d3c4ee9db864a12b0722 100644
--- a/ivette/src/dome/renderer/text/editors.tsx
+++ b/ivette/src/dome/renderer/text/editors.tsx
@@ -386,7 +386,7 @@ class CodeMirrorWrapper extends React.Component<TextProps> {
   // --- Focus
   // --------------------------------------------------------------------------
 
-  handleKey(_cm: CodeMirror.Editor, key: string, _evt: KeyboardEvent) {
+  handleKey(_cm: CodeMirror.Editor, key: string, _evt: Event) {
     switch (key) {
       case 'Esc':
         this.props.buffer?.setFocused(false);
diff --git a/ivette/src/frama-c/client_socket.ts b/ivette/src/frama-c/client_socket.ts
index 23777c7a5f2f4c742c095202d4662c2c24648ee1..55be45c292f1bae5df6f3d9cb8eb762c812d31dd 100644
--- a/ivette/src/frama-c/client_socket.ts
+++ b/ivette/src/frama-c/client_socket.ts
@@ -21,18 +21,19 @@
 /* ************************************************************************ */
 
 import Net from 'net';
+import { Debug } from 'dome';
 import Emitter from 'events';
 import { json } from 'dome/data/json';
 import { Client } from './client';
 
+const D = new Debug('SocketServer');
+
 // --------------------------------------------------------------------------
 // --- Frama-C Server API
 // --------------------------------------------------------------------------
 
 class SocketClient implements Client {
 
-  constructor() { }
-
   events = new Emitter();
   running = false;
   socket: Net.Socket | undefined;
@@ -45,7 +46,7 @@ class SocketClient implements Client {
       this.socket.destroy();
     }
     this.socket = Net.createConnection(sockaddr, () => {
-      console.log('Socket server connected');
+      D.log('Client connected');
       this.running = true;
       this._flush();
     });
@@ -53,14 +54,14 @@ class SocketClient implements Client {
     this.socket.on('end', () => this.disconnect());
     this.socket.on('data', (data: Buffer) => this._receive(data));
     this.socket.on('error', (err: Error) => {
-      console.warn('Socket error', err);
+      D.warn('Socket error', err);
     });
   }
 
   disconnect(): void {
     this.queue = [];
     if (this.socket) {
-      console.log('Socket disconnected');
+      D.log('Client disconnected');
       this.socket.destroy();
       this.socket = undefined;
     }
@@ -73,19 +74,34 @@ class SocketClient implements Client {
   }
 
   /** Signal ON */
-  sigOn(id: string): void { this.queue.push({ cmd: 'SIGON', id }); this._flush(); }
+  sigOn(id: string): void {
+    this.queue.push({ cmd: 'SIGON', id });
+    this._flush();
+  }
 
   /** Signal ON */
-  sigOff(id: string): void { this.queue.push({ cmd: 'SIGOFF', id }); this._flush(); }
+  sigOff(id: string): void {
+    this.queue.push({ cmd: 'SIGOFF', id });
+    this._flush();
+  }
 
   /** Kill Request */
-  kill(id: string): void { this.queue.push({ cmd: 'KILL', id }); this._flush(); }
+  kill(id: string): void {
+    this.queue.push({ cmd: 'KILL', id });
+    this._flush();
+  }
 
   /** Polling */
-  poll(): void { this.queue.push('POLL'); this._flush(); }
+  poll(): void {
+    this.queue.push('POLL');
+    this._flush();
+  }
 
   /** Shutdown the server */
-  shutdown(): void { this.queue.push('SHUTDOWN'); this._flush(); }
+  shutdown(): void {
+    this.queue.push('SHUTDOWN');
+    this._flush();
+  }
 
   /** Request data callback */
   onData(callback: (id: string, data: json) => void): void {
@@ -163,7 +179,7 @@ class SocketClient implements Client {
 
   _receive(chunk: Buffer) {
     this.buffer = Buffer.concat([this.buffer, chunk]);
-    while (1) {
+    while (true) {
       const data = this._fetch();
       if (data === undefined) break;
       try {
@@ -176,12 +192,12 @@ class SocketClient implements Client {
             case 'REJECTED': this.events.emit('REJECT', cmd.id); break;
             case 'SIGNAL': this.events.emit('SIGNAL', cmd.id); break;
             default:
-              console.log('Unknown command', cmd);
+              D.warn('Unknown command', cmd);
           }
         } else
-          console.log('Misformed data', data);
+          D.warn('Misformed data', data);
       } catch (err) {
-        console.log('Misformed JSON', data, err);
+        D.warn('Misformed JSON', data, err);
       }
     }
   }
diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx
index 76879dcfca9675d4aa1aeffa73711ae6ac734aac..a925d593f89e13bb061e2fa50be05b93d9c5f879 100644
--- a/ivette/src/frama-c/kernel/ASTview.tsx
+++ b/ivette/src/frama-c/kernel/ASTview.tsx
@@ -186,9 +186,11 @@ export default function ASTview() {
             const markers = buffer.findTextMarker(prop.key);
             markers.forEach((marker) => {
               const pos = marker.find();
-              buffer.forEach((cm) => {
-                cm.setGutterMarker(pos.from.line, 'bullet', bullet);
-              });
+              if (pos) {
+                buffer.forEach((cm) => {
+                  cm.setGutterMarker(pos.from.line, 'bullet', bullet);
+                });
+              }
             });
           }
         }
diff --git a/ivette/src/frama-c/kernel/Globals.tsx b/ivette/src/frama-c/kernel/Globals.tsx
index 6c94aedd8590d7a3f1b80d699a6f1fadaa192c48..49799d3ef0f8e4f249f6e7c6a4f4b3bf85909a4a 100644
--- a/ivette/src/frama-c/kernel/Globals.tsx
+++ b/ivette/src/frama-c/kernel/Globals.tsx
@@ -119,7 +119,7 @@ export default () => {
 
   function isSelected(fct: functionsData) {
     return multipleSelection?.allSelections.some(
-      (l) => fct.name === l?.fct
+      (l) => fct.name === l?.fct,
     );
   }
 
diff --git a/ivette/src/frama-c/kernel/Messages.tsx b/ivette/src/frama-c/kernel/Messages.tsx
index c215c943ff3f962b846f3ef0854654311c94df12..68b1a885b96aefea21daaf656c494b75acf60b15 100644
--- a/ivette/src/frama-c/kernel/Messages.tsx
+++ b/ivette/src/frama-c/kernel/Messages.tsx
@@ -53,7 +53,7 @@ interface Search {
 }
 
 type KindFilter = Record<logkind, boolean>;
-type PluginFilter = {[key: string]: boolean};
+type PluginFilter = { [key: string]: boolean };
 type EmitterFilter = {
   kernel: boolean;
   plugins: PluginFilter;
@@ -80,23 +80,23 @@ const kindFilter: KindFilter = {
 /* The fields must be exactly the short names of Frama-C plugins used in
    messages. They are all shown by default. */
 const pluginFilter: PluginFilter = {
-  aorai: true,
-  dive: true,
+  'aorai': true,
+  'dive': true,
   'e-acsl': true,
-  eva: true,
-  from: true,
-  impact: true,
-  inout: true,
-  metrics: true,
-  nonterm: true,
-  pdg: true,
-  report: true,
-  rte: true,
-  scope: true,
-  server: true,
-  slicing: true,
-  variadic: true,
-  wp: true,
+  'eva': true,
+  'from': true,
+  'impact': true,
+  'inout': true,
+  'metrics': true,
+  'nonterm': true,
+  'pdg': true,
+  'report': true,
+  'rte': true,
+  'scope': true,
+  'server': true,
+  'slicing': true,
+  'variadic': true,
+  'wp': true,
 };
 
 const emitterFilter = {
@@ -168,7 +168,7 @@ function searchString(search: string | undefined, msg: string) {
 
 function filterSearched(search: Search, msg: Message) {
   return (searchString(search.message, msg.message) &&
-          searchCategory(search.category, msg.category));
+    searchCategory(search.category, msg.category));
 }
 
 function filterFunction(filter: Filter, kf: string | undefined, msg: Message) {
@@ -179,20 +179,15 @@ function filterFunction(filter: Filter, kf: string | undefined, msg: Message) {
 
 function filterMessage(filter: Filter, kf: string | undefined, msg: Message) {
   return (filterFunction(filter, kf, msg) &&
-          filterSearched(filter.search, msg) &&
-          filterKind(filter.kind, msg) &&
-          filterEmitter(filter.emitter, msg));
+    filterSearched(filter.search, msg) &&
+    filterKind(filter.kind, msg) &&
+    filterEmitter(filter.emitter, msg));
 }
 
 // --------------------------------------------------------------------------
 // --- Filters panel and ratio
 // --------------------------------------------------------------------------
 
-function Checkbox(p: Forms.CheckboxFieldProps) {
-  const lbl = p.label.charAt(0).toUpperCase() + p.label.slice(1).toLowerCase();
-  return <Forms.CheckboxField label={lbl} state={p.state} />;
-}
-
 function Section(p: Forms.SectionProps) {
   const settings = `ivette.messages.filter.${p.label}`;
   return (
@@ -202,28 +197,42 @@ function Section(p: Forms.SectionProps) {
   );
 }
 
-function MessageFilter(props: {filter: State<Filter>}) {
+function MessageKindCheckbox(props: {
+  kind: logkind,
+  kindState: Forms.FieldState<KindFilter>,
+}) {
+  const { kind, kindState } = props;
+  const label = kind.charAt(0).toUpperCase + kind.slice(1).toLowerCase();
+  const state = Forms.useProperty(kindState, kind);
+  return <Forms.CheckboxField label={label} state={state} />;
+}
+
+function PluginCheckbox(props: {
+  plugin: string,
+  pluginState: Forms.FieldState<PluginFilter>,
+}) {
+  const label = props.plugin.toUpperCase();
+  const state = Forms.useProperty(props.pluginState, props.plugin);
+  return <Forms.CheckboxField label={label} state={state} />;
+}
+
+function MessageFilter(props: { filter: State<Filter> }) {
   const state = Forms.useValid(props.filter);
   const search = Forms.useProperty(state, 'search');
   const categoryState = Forms.useProperty(search, 'category');
   const messageState = Forms.useProperty(search, 'message');
-
-  const kind = Forms.useProperty(state, 'kind');
-  const kindState = (key: logkind) => Forms.useProperty(kind, key);
+  const kindState = Forms.useProperty(state, 'kind');
   const kindCheckboxes =
-    Object.keys(kindFilter).map((key) => (
-      <Checkbox key={key} label={key} state={kindState(key as logkind)} />
+    Object.keys(kindFilter).map((k) => (
+      <MessageKindCheckbox key={k} kind={k as logkind} kindState={kindState} />
     ));
-
-  const emitter = Forms.useProperty(state, 'emitter');
-  function EmitterCheckbox(p: {key: 'kernel' | 'others'}) {
-    return <Checkbox label={p.key} state={Forms.useProperty(emitter, p.key)} />;
-  }
-  const plugin = Forms.useProperty(emitter, 'plugins');
-  const pluginState = (key: string) => Forms.useProperty(plugin, key);
+  const emitterState = Forms.useProperty(state, 'emitter');
+  const kernelState = Forms.useProperty(emitterState, 'kernel');
+  const othersState = Forms.useProperty(emitterState, 'others');
+  const pluginState = Forms.useProperty(emitterState, 'plugins');
   const pluginCheckboxes =
-    Object.keys(pluginFilter).map((key) => (
-      <Checkbox key={key} label={key} state={pluginState(key)} />
+    Object.keys(pluginFilter).map((p) => (
+      <PluginCheckbox key={p} plugin={p} pluginState={pluginState} />
     ));
 
   return (
@@ -239,29 +248,29 @@ function MessageFilter(props: {filter: State<Filter>}) {
           state={categoryState}
           placeholder="Category"
           title={'Search in message category.\n'
-               + 'Use -<name> to hide some categories.'}
+            + 'Use -<name> to hide some categories.'}
         />
         <Forms.TextField
           label="Message"
           state={messageState}
           placeholder="Message"
           title={'Search in message text.\n'
-               + 'Case-insensitive by default.\n'
-               + 'Use "text" for an exact case-sensitive search.'}
+            + 'Case-insensitive by default.\n'
+            + 'Use "text" for an exact case-sensitive search.'}
         />
       </Section>
       <Section label="Kind">
-        { kindCheckboxes }
+        {kindCheckboxes}
       </Section>
       <Section label="Emitter">
         <div className="message-emitter-category">
-          { EmitterCheckbox({ key: 'kernel' }) }
+          <Forms.CheckboxField label='Kernel' state={kernelState} />
         </div>
         <div className="message-emitter-category">
-          { pluginCheckboxes }
+          {pluginCheckboxes}
         </div>
         <div className="message-emitter-category">
-          { EmitterCheckbox({ key: 'others' }) }
+          <Forms.CheckboxField label='Others' state={othersState} />
         </div>
       </Section>
     </Forms.Page>
diff --git a/ivette/src/frama-c/kernel/SourceCode.tsx b/ivette/src/frama-c/kernel/SourceCode.tsx
index 4a55284e9eb085403daead8427f2142eab05ce87..a6100ca4aa4daf64774c17888f7e710fd9ddf319 100644
--- a/ivette/src/frama-c/kernel/SourceCode.tsx
+++ b/ivette/src/frama-c/kernel/SourceCode.tsx
@@ -90,10 +90,14 @@ export default function SourceCode() {
     });
 
   // Updating the buffer content.
-  const errorMsg = () => { D.error(`Fail to load source code file ${file}`); };
-  const onError = () => { if (file) errorMsg(); return ''; };
-  const read = () => System.readFile(file).catch(onError);
-  const text = React.useMemo(read, [file, onError]);
+  const text = React.useMemo(async () => {
+    const onError = () => {
+      if (file)
+        D.error(`Fail to load source code file ${file}`);
+      return '';
+    };
+    return System.readFile(file).catch(onError);
+  }, [file]);
   const { result } = Dome.usePromise(text);
   React.useEffect(() => buffer.setValue(result), [buffer, result]);
 
@@ -115,29 +119,31 @@ export default function SourceCode() {
   type position = CodeMirror.Position;
   type editor = CodeMirror.Editor;
 
-  async function select(editor: editor, event: MouseEvent) {
-    const pos = editor.coordsChar({ left: event.x, top: event.y });
-    if (file === '' || !pos) return;
-    const arg = [file, pos.line + 1, pos.ch + 1];
-    Server
-      .send(getMarkerAt, arg)
-      .then(([fct, marker]) => {
-        if (fct || marker) {
-          const location = { fct, marker } as States.Location;
-          selected.current = location;
-          updateSelection({ location });
-        }
-      })
-      .catch((err) => {
-        D.error(`Failed to get marker from source file position: ${err}`);
-        Status.setMessage({
-          text: 'Failed request to Frama-C server',
-          kind: 'error',
+  const selectCallback = React.useCallback(
+    async function select(editor: editor, event: MouseEvent) {
+      const pos = editor.coordsChar({ left: event.x, top: event.y });
+      if (file === '' || !pos) return;
+      const arg = [file, pos.line + 1, pos.ch + 1];
+      Server
+        .send(getMarkerAt, arg)
+        .then(([fct, marker]) => {
+          if (fct || marker) {
+            const location = { fct, marker } as States.Location;
+            selected.current = location;
+            updateSelection({ location });
+          }
+        })
+        .catch((err) => {
+          D.error(`Failed to get marker from source file position: ${err}`);
+          Status.setMessage({
+            text: 'Failed request to Frama-C server',
+            kind: 'error',
+          });
         });
-      });
-  }
+    },
+    [file, updateSelection],
+  );
 
-  const selectCallback = React.useCallback(select, [file]);
   React.useEffect(() => {
     buffer.forEach((cm) => cm.on('mousedown', selectCallback));
     return () => buffer.forEach((cm) => cm.off('mousedown', selectCallback));
diff --git a/ivette/src/frama-c/kernel/Status.tsx b/ivette/src/frama-c/kernel/Status.tsx
index 14c31a6fd0e528abd4224c1a393865b1bf66f9ea..7c0f6ecec41e68267d03bb32e4f3ac580e1afc85 100644
--- a/ivette/src/frama-c/kernel/Status.tsx
+++ b/ivette/src/frama-c/kernel/Status.tsx
@@ -34,17 +34,17 @@ import { GlobalState, useGlobalState } from 'dome/data/states';
 export type kind =
   'none' | 'info' | 'warning' | 'error' | 'success' | 'progress';
 
-export interface Message {
+export interface MessageProps {
   kind: kind;
   text: string;
   title?: string;
 }
 
-const emptyMessage: Message = { text: '', kind: 'none' };
+const emptyMessage: MessageProps = { text: '', kind: 'none' };
 
 const GlobalMessage = new GlobalState(emptyMessage);
 
-export function setMessage(message: Message) {
+export function setMessage(message: MessageProps) {
   GlobalMessage.setValue(message);
 }
 
@@ -54,11 +54,11 @@ export default function Message() {
   return (
     <>
       <Toolbars.Space />
-      { message.kind === 'progress' && <LED status="active" blink /> }
-      { message.kind === 'success' && <Icon id="CHECK" fill="green" /> }
-      { message.kind === 'warning' && <Icon id="ATTENTION" /> }
-      { message.kind === 'error' && <Icon id="CROSS" fill="red" /> }
-      { message.kind === 'info' && <Icon id="CIRC.INFO" /> }
+      {message.kind === 'progress' && <LED status="active" blink />}
+      {message.kind === 'success' && <Icon id="CHECK" fill="green" />}
+      {message.kind === 'warning' && <Icon id="ATTENTION" />}
+      {message.kind === 'error' && <Icon id="CROSS" fill="red" />}
+      {message.kind === 'info' && <Icon id="CIRC.INFO" />}
       <Code label={message.text} title={message.title} />
       <Toolbars.Space />
       <IconButton
diff --git a/ivette/src/frama-c/plugins/dive/index.tsx b/ivette/src/frama-c/plugins/dive/index.tsx
index e121ae5a9b4a92bada905cc84a234f420a3f70e1..a1e890826be099025e3486dc2bcbd32624bb5ae2 100644
--- a/ivette/src/frama-c/plugins/dive/index.tsx
+++ b/ivette/src/frama-c/plugins/dive/index.tsx
@@ -217,10 +217,11 @@ class Dive {
       trigger: 'manual',
       appendTo: document.body,
       lazy: false,
-      onCreate: (instance: Tippy.Instance) => {
+      onCreate: (instance: any) => {
         const { popperInstance } = instance;
-        if (popperInstance)
+        if (popperInstance) {
           popperInstance.reference = (node as any).popperRef();
+        }
       },
     };
 
@@ -231,7 +232,8 @@ class Dive {
         ...common,
         content: node.data().values,
         placement: 'top',
-        distance: 10,
+        //distance: 10,
+        offset: [10, 10],
         arrow: true,
       }));
     }
@@ -241,7 +243,8 @@ class Dive {
         ...common,
         content: node.data().type,
         placement: 'bottom',
-        distance: 20,
+        //distance: 20,
+        offset: [20, 20],
         theme: 'light-border',
         arrow: false,
       }));
diff --git a/ivette/src/frama-c/plugins/eva/CoverageMeter.tsx b/ivette/src/frama-c/plugins/eva/CoverageMeter.tsx
index 39537a19e5caa644252dad7992792ca5405b203c..a6468e552e62c2c1d11c263787bf3a4818ca502e 100644
--- a/ivette/src/frama-c/plugins/eva/CoverageMeter.tsx
+++ b/ivette/src/frama-c/plugins/eva/CoverageMeter.tsx
@@ -22,17 +22,17 @@
 
 import React from 'react';
 
-export interface Coverage {
+export interface CoverageProps {
   reachable: number;
   dead: number;
 }
 
-export function percent(coverage: Coverage): string {
+export function percent(coverage: CoverageProps): string {
   const q = coverage.reachable / (coverage.reachable + coverage.dead);
   return `${(q * 100).toFixed(1)}%`;
 }
 
-export default function (props: {coverage: Coverage}) {
+export default function(props: { coverage: CoverageProps }) {
   const { reachable, dead } = props.coverage;
   const total = reachable + dead;
 
diff --git a/ivette/src/frama-c/plugins/eva/valueinfos.tsx b/ivette/src/frama-c/plugins/eva/valueinfos.tsx
index cd4d920d03361186691bafde4361d4ec3244eb0f..817e64e5f7560d9707fdf4096a5c6b33dfa8a167 100644
--- a/ivette/src/frama-c/plugins/eva/valueinfos.tsx
+++ b/ivette/src/frama-c/plugins/eva/valueinfos.tsx
@@ -48,9 +48,10 @@ interface StmtProps {
 }
 
 export function Stmt(props: StmtProps) {
+  const markersInfo = States.useSyncArray(Ast.markerInfo);
+
   const { stmt, marker, short } = props;
   if (!stmt) return null;
-  const markersInfo = States.useSyncArray(Ast.markerInfo);
   const line = markersInfo.getData(marker)?.sloc?.line;
   const filename = markersInfo.getData(marker)?.sloc?.base;
   const title = markersInfo.getData(stmt)?.descr;
diff --git a/ivette/src/frama-c/server.ts b/ivette/src/frama-c/server.ts
index feebcd4a9d9018864c913dd5dd08e4866463a154..5c2ba0038e98cfab8a8e3f9299915002240374ed 100644
--- a/ivette/src/frama-c/server.ts
+++ b/ivette/src/frama-c/server.ts
@@ -37,7 +37,7 @@ import * as System from 'dome/system';
 import * as Json from 'dome/data/json';
 import { RichTextBuffer } from 'dome/text/buffers';
 import { ChildProcess } from 'child_process';
-import { client } from './client_zmq';
+import { client } from './client_socket';
 
 // --------------------------------------------------------------------------
 // --- Pretty Printing (Browser Console)
@@ -100,7 +100,7 @@ export enum Stage {
   /** Server is restarting. */
   RESTARTING = 'RESTARTING',
   /** Server is off upon failure. */
-  FAILURE = 'FAILURE'
+  FAILURE = 'FAILURE',
 }
 
 export interface OkStatus {
@@ -248,9 +248,10 @@ export async function start() {
         await _launch();
         _status(okStatus(Stage.ON));
       } catch (error) {
-        D.error(error.toString());
-        buffer.append(error.toString(), '\n');
-        _exit(error);
+        const msg = '' + error;
+        D.error(msg);
+        buffer.append(msg, '\n');
+        _exit(msg);
       }
       return;
     case Stage.HALTING:
@@ -480,14 +481,14 @@ async function _launch() {
     if (signal) {
       // [signal] is non-null.
       buffer.log('Signal:', signal);
-      const error = new Error(`Process terminated by the signal ${signal}`);
+      const error = `Process terminated by the signal ${signal}`;
       _exit(error);
       return;
     }
     // [signal] is null, hence [code] is non-null (cf. NodeJS doc).
     if (code) {
       buffer.log('Exit:', code);
-      const error = new Error(`Process exited with code ${code}`);
+      const error = `Process exited with code ${code}`;
       _exit(error);
     } else {
       // [code] is zero: normal exit w/o error.
@@ -543,14 +544,14 @@ async function _shutdown() {
   await killingPromise;
 }
 
-function _exit(error?: Error) {
+function _exit(error?: string) {
   _reset();
   client.disconnect();
   process = undefined;
   if (status.stage === Stage.RESTARTING) {
     setImmediate(start);
   } else if (error) {
-    _status(errorStatus(error.toString()));
+    _status(errorStatus(error));
   } else {
     _status(okStatus(Stage.OFF));
   }
@@ -565,6 +566,7 @@ class SignalHandler {
   event: Dome.Event;
   active: boolean;
   listen: boolean;
+  handler: _.DebouncedFunc<() => void>;
 
   constructor(id: string) {
     this.id = id;
@@ -572,7 +574,7 @@ class SignalHandler {
     this.active = false;
     this.listen = false;
     this.sigon = this.sigon.bind(this);
-    this.sigoff = _.debounce(this.sigoff.bind(this), 1000);
+    this.sigoff = this.handler = _.debounce(this.sigoff.bind(this), 1000);
     this.unplug = this.unplug.bind(this);
   }
 
@@ -617,6 +619,7 @@ class SignalHandler {
 
   unplug() {
     this.listen = false;
+    this.handler.cancel();
   }
 }
 
@@ -633,9 +636,7 @@ function _signal(id: string): SignalHandler {
   return s;
 }
 
-client.onSignal((id: string) => {
-  _signal(id).event.emit();
-})
+client.onSignal((id: string) => { _signal(id).event.emit(); });
 
 // --- External API
 
@@ -686,7 +687,6 @@ READY.on(() => {
 SHUTDOWN.on(() => {
   signals.forEach((h: SignalHandler) => {
     h.unplug();
-    (h.sigoff as unknown as _.Cancelable).cancel();
   });
 });
 
@@ -701,7 +701,7 @@ export enum RqKind {
   /** Used to write data into the Frama-C server. */
   SET = 'SET',
   /** Used to make the Frama-C server execute a task. */
-  EXEC = 'EXEC'
+  EXEC = 'EXEC',
 }
 
 /** Server signal. */
@@ -726,7 +726,7 @@ export type GetRequest<In, Out> = Request<RqKind.GET, In, Out>;
 export type SetRequest<In, Out> = Request<RqKind.SET, In, Out>;
 export type ExecRequest<In, Out> = Request<RqKind.EXEC, In, Out>;
 
-export interface Killable<Data> extends Promise<Data> {
+export interface Response<Data> extends Promise<Data> {
   kill?: () => void;
 }
 
@@ -739,23 +739,30 @@ export interface Killable<Data> extends Promise<Data> {
 export function send<In, Out>(
   request: Request<RqKind, In, Out>,
   param: In,
-): Killable<Out> {
+): Response<Out> {
   if (!isRunning()) return Promise.reject(new Error('Server not running'));
   if (!request.name) return Promise.reject(new Error('Undefined request'));
   const rid = `RQ.${rqCount}`;
   rqCount += 1;
-  const promise: Killable<Out> = new Promise<Out>((resolve, reject) => {
+  const response: Response<Out> = new Promise<Out>((resolve, reject) => {
     const decodedResolve = (js: Json.json) => {
-      const result = Json.jTry(request.output)(js);
-      resolve(result);
+      try {
+        const result = request.output(js);
+        if (result !== undefined)
+          resolve(result);
+        else
+          reject();
+      } catch (err) {
+        reject(err);
+      }
     };
     pending[rid] = [decodedResolve, reject];
   });
-  promise.kill = () => {
+  response.kill = () => {
     if (pending[rid]) client.kill(rid);
   };
   client.send(request.kind, rid, request.name, param);
-  return promise;
+  return response;
 }
 
 client.onData((id: string, data: Json.json) => {
diff --git a/ivette/src/frama-c/states.ts b/ivette/src/frama-c/states.ts
index e5d85c61c9a872f66c4e094b36df3e3b119dc4e3..a3c5081f6481e0e0f8fe49c82e4efe5907d7009e 100644
--- a/ivette/src/frama-c/states.ts
+++ b/ivette/src/frama-c/states.ts
@@ -72,7 +72,7 @@ Server.onReady(async () => {
     currentProject = current.id;
     PROJECT.emit();
   } catch (error) {
-    D.error(`Fail to retrieve the current project. ${error.toString()}`);
+    D.error(`Fail to retrieve the current project. ${error}`);
   }
 });
 
@@ -116,7 +116,7 @@ export async function setProject(project: string) {
       currentProject = project;
       PROJECT.emit();
     } catch (error) {
-      D.error(`Fail to set the current project. ${error.toString()}`);
+      D.error(`Fail to set the current project. ${error}`);
     }
   }
 }
@@ -171,7 +171,7 @@ export function useRequest<In, Out>(
         const r = await Server.send(rq, params);
         update(r);
       } catch (error) {
-        D.error(`Fail in useRequest '${rq.name}'. ${error.toString()}`);
+        D.error(`Fail in useRequest '${rq.name}'. ${error}`);
         update(options.onError);
       }
     } else {
@@ -300,7 +300,7 @@ class SyncState<A> {
     } catch (error) {
       D.error(
         `Fail to set value of SyncState '${this.handler.name}'.`,
-        `${error.toString()}`,
+        `${error}`,
       );
     }
   }
@@ -314,7 +314,7 @@ class SyncState<A> {
     } catch (error) {
       D.error(
         `Fail to update SyncState '${this.handler.name}'.`,
-        `${error.toString()}`,
+        `${error}`,
       );
     }
   }
@@ -407,7 +407,7 @@ class SyncArray<K, A> {
     } catch (error) {
       D.error(
         `Fail to retrieve the value of syncArray '${this.handler.name}.`,
-        `${error.toString()}`,
+        `${error}`,
       );
     } finally {
       this.fetching = false;
@@ -426,7 +426,7 @@ class SyncArray<K, A> {
     } catch (error) {
       D.error(
         `Fail to set reload of syncArray '${this.handler.name}'.`,
-        `${error.toString()}`,
+        `${error}`,
       );
     }
   }
@@ -477,7 +477,7 @@ export function useSyncArray<K, A>(
 ): CompactModel<K, A> {
   Dome.useUpdate(PROJECT);
   const st = lookupSyncArray(arr);
-  React.useEffect(st.update);
+  React.useEffect(() => st.update(), [st]);
   Server.useSignal(arr.signal, st.fetch);
   useModel(st.model, sync);
   return st.model;
@@ -778,7 +778,7 @@ export function useSelection(): [Selection, (a: SelectionActions) => void] {
 /** Resets the selected locations. */
 export async function resetSelection() {
   GlobalSelection.setValue(emptySelection);
-  const main = await Server.send(Ast.getMainFunction, { });
+  const main = await Server.send(Ast.getMainFunction, {});
   // If the selection has already been modified, do not change it.
   if (main && GlobalSelection.getValue() === emptySelection) {
     GlobalSelection.setValue({ ...emptySelection, current: { fct: main } });
diff --git a/ivette/src/renderer/Laboratory.tsx b/ivette/src/renderer/Laboratory.tsx
index 3a41a613e3f2c0a661fcb76ce68272f63e3c1edb..cf3ce8cd5cec0db6eaa8f41ec5351746a210673c 100644
--- a/ivette/src/renderer/Laboratory.tsx
+++ b/ivette/src/renderer/Laboratory.tsx
@@ -51,8 +51,8 @@ const UPDATE = new Dome.Event('labview.library');
 
 class Library {
   modified: boolean;
-  virtual: {};
-  collection: {};
+  virtual: any;
+  collection: any;
   items: any[];
 
   constructor() {