diff --git a/Dockerfile b/Dockerfile
index 3028713cea543bb269e36aed4944c9c6d05eaa8e..931b0ed3d134f257f99e6cc4f3cad9d4ac76de64 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -89,7 +89,8 @@ RUN echo \
     xsi:schemaLocation='http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd'> \
         <localRepository>\${user.home}/work/.m2/repository</localRepository> \
     </settings>" \
-    > $HOME/.sdkman/candidates/maven/current/conf/settings.xml && \
+    > $HOME/.sdkman/candidates/maven/current/conf/settings.xml
+
 ENV NEEDED_WORK_DIRS "$NEEDED_WORK_DIRS .m2"
 
 RUN echo '#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!' >> $HOME/.zshenv && \
@@ -102,6 +103,8 @@ SHELL ["/bin/zsh","-l","-c"]
 RUN curl -L https://sourceforge.net/projects/plantuml/files/plantuml.${PLANTUML_VERSION}.jar/download -o /usr/local/bin/plantuml.jar && \
     echo "$PLANTUML_SHA1 */usr/local/bin/plantuml.jar" | sha1sum -c - 
 
+COPY dependencies/* "$HOME/lib/"
+
 # Adds Java and Maven to the user path
 ENV PATH=/home/jovyan/.sdkman/candidates/maven/current/bin:/home/jovyan/.sdkman/candidates/java/current/bin:$PATH
 
diff --git a/dependencies/checker-qual-3.5.0.jar b/dependencies/checker-qual-3.5.0.jar
new file mode 100644
index 0000000000000000000000000000000000000000..f98cde8b2dd3a5bfa141d16c37b097548db099e1
Binary files /dev/null and b/dependencies/checker-qual-3.5.0.jar differ
diff --git a/dependencies/error_prone_annotations-2.3.4.jar b/dependencies/error_prone_annotations-2.3.4.jar
new file mode 100644
index 0000000000000000000000000000000000000000..c9bea2abc4e3ef344685bed2f1fea53a633979ef
Binary files /dev/null and b/dependencies/error_prone_annotations-2.3.4.jar differ
diff --git a/dependencies/failureaccess-1.0.1.jar b/dependencies/failureaccess-1.0.1.jar
new file mode 100644
index 0000000000000000000000000000000000000000..9b56dc751c1cc7dff75ed80ccbb45f027058e8ce
Binary files /dev/null and b/dependencies/failureaccess-1.0.1.jar differ
diff --git a/dependencies/guava-30.1-jre.jar b/dependencies/guava-30.1-jre.jar
new file mode 100644
index 0000000000000000000000000000000000000000..4244e8a270dc92022f9c6f97791fdce2284a15b3
Binary files /dev/null and b/dependencies/guava-30.1-jre.jar differ
diff --git a/dependencies/j2objc-annotations-1.3.jar b/dependencies/j2objc-annotations-1.3.jar
new file mode 100644
index 0000000000000000000000000000000000000000..a429c7219d30e797d4a6b3cfb579266f323dd030
Binary files /dev/null and b/dependencies/j2objc-annotations-1.3.jar differ
diff --git a/dependencies/javaparser-core-3.19.0.jar b/dependencies/javaparser-core-3.19.0.jar
new file mode 100644
index 0000000000000000000000000000000000000000..8a6d69edbcd75d10b237aed55b45fe9903602455
Binary files /dev/null and b/dependencies/javaparser-core-3.19.0.jar differ
diff --git a/dependencies/javaparser-symbol-solver-core-3.19.0.jar b/dependencies/javaparser-symbol-solver-core-3.19.0.jar
new file mode 100644
index 0000000000000000000000000000000000000000..2762477bcbfe5453937c55a5dce135c69515b4c3
Binary files /dev/null and b/dependencies/javaparser-symbol-solver-core-3.19.0.jar differ
diff --git a/dependencies/javassist-3.27.0-GA.jar b/dependencies/javassist-3.27.0-GA.jar
new file mode 100644
index 0000000000000000000000000000000000000000..092e59b4d68c3d5832cef4e04324212fd319ab48
Binary files /dev/null and b/dependencies/javassist-3.27.0-GA.jar differ
diff --git a/dependencies/jsr305-3.0.2.jar b/dependencies/jsr305-3.0.2.jar
new file mode 100644
index 0000000000000000000000000000000000000000..59222d9ca5e5654f5dcf6680783d0e265baa848f
Binary files /dev/null and b/dependencies/jsr305-3.0.2.jar differ
diff --git a/dependencies/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar b/dependencies/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar
new file mode 100644
index 0000000000000000000000000000000000000000..45832c052a10428a5b18613470458e1a2e0e941a
Binary files /dev/null and b/dependencies/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar differ
diff --git a/magics/JAVA.jshell b/magics/JAVA.jshell
new file mode 100644
index 0000000000000000000000000000000000000000..c049e9ee9eb4f989f4a091114a4e5fe23eac2e22
--- /dev/null
+++ b/magics/JAVA.jshell
@@ -0,0 +1,68 @@
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.io.InputStream;
+import java.util.function.Consumer;
+import java.util.concurrent.Future;
+import io.github.spencerpark.ijava.IJava;
+import io.github.spencerpark.ijava.JavaKernel;
+import io.github.spencerpark.jupyter.kernel.magic.registry.UndefinedMagicException;
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.CompilationUnit;
+
+
+/**
+%%javasrcMethodByAnnotationName Test POST 
+/src/Test.java
+*/
+IJava.getKernelInstance().getMagics().registerCellMagic("javasrcMethodByAnnotationName", (args, body) -> {
+    String filename=body;
+    String className=args.get(0);
+    String annotationName=args.get(1);
+    int index=args.size()==3?Integer.valueOf(args.get(2)):0;
+    CompilationUnit cu = StaticJavaParser.parse(Files.readString(Path.of(filename)));
+            String out = cu.getClassByName(className).get()
+                .getMethods()
+                .stream()
+                .filter(m -> m.getAnnotations().stream().anyMatch(a -> a.getNameAsString().equals(annotationName)))                
+                .skip(index)
+                .findFirst().get().toString();
+     out = "```java\n"+out+"\n```";
+     display(out,"text/markdown");
+     return out;
+});
+
+/**
+%%javasrcMethodByName Test getAll 
+/src/Test.java
+*/
+IJava.getKernelInstance().getMagics().registerCellMagic("javasrcMethodByName", (args, body) -> {
+    String filename=body;
+    String className=args.get(0);
+    String methodName=args.get(1);
+    int index=args.size()==3?Integer.valueOf(args.get(2)):0;
+    CompilationUnit cu = StaticJavaParser.parse(Files.readString(Path.of(filename)));
+            String out = cu.getClassByName(className).get()
+                .getMethodsByName(methodName)                
+                .get(index)
+                .toString();
+     out = "```java\n"+out+"\n```";
+     display(out,"text/markdown");
+     return out;
+});
+
+/**
+%%javasrcClassByName Test 
+/src/Test.java
+*/
+IJava.getKernelInstance().getMagics().registerCellMagic("javasrcClassByName", (args, body) -> {
+    String filename=body;
+    String className=args.get(0);
+    CompilationUnit cu = StaticJavaParser.parse(Files.readString(Path.of(filename)));
+            String out = cu.getClassByName(className).get()
+                .toString();
+     out = "```java\n"+out+"\n```";
+     display(out,"text/markdown");
+     return out;
+});
diff --git a/magics/SHELL.jshell b/magics/SHELL.jshell
new file mode 100644
index 0000000000000000000000000000000000000000..6337fb09aee1ed9c51d58eb8903f0c51ac0f6f4e
--- /dev/null
+++ b/magics/SHELL.jshell
@@ -0,0 +1,40 @@
+import java.io.File;
+import java.io.InputStream;
+import java.util.function.Consumer;
+import java.util.concurrent.Future;
+import io.github.spencerpark.ijava.IJava;
+import io.github.spencerpark.ijava.JavaKernel;
+import io.github.spencerpark.jupyter.kernel.magic.registry.UndefinedMagicException;
+
+
+private static class StreamGobbler implements Runnable {
+    private InputStream inputStream;
+    private Consumer<String> consumer;
+
+    public StreamGobbler(InputStream inputStream, Consumer<String> consumer) {
+        this.inputStream = inputStream;
+        this.consumer = consumer;
+    }
+
+    @Override
+    public void run() {
+        new BufferedReader(new InputStreamReader(inputStream)).lines()
+          .forEach(consumer);
+    }
+}
+
+IJava.getKernelInstance().getMagics().registerCellMagic("shell", (args, body) -> {
+    String[] commands = {"zsh", "-c", body};
+    Process process = new ProcessBuilder()
+        //.redirectErrorStream(true)
+        .command(commands).start();
+
+    StreamGobbler streamGobbler =
+      new StreamGobbler(process.getInputStream(), System.out::println);
+    StreamGobbler streamGobblerErr =
+      new StreamGobbler(process.getErrorStream(), System.err::println);
+    Executors.newSingleThreadExecutor().submit(streamGobbler);
+    Executors.newSingleThreadExecutor().submit(streamGobblerErr);
+    
+    return process.waitFor();
+})
diff --git a/magics/UML.jshell b/magics/UML.jshell
new file mode 100644
index 0000000000000000000000000000000000000000..9257341fb2f8a807a5f3bc5c3986f5c911bacd11
--- /dev/null
+++ b/magics/UML.jshell
@@ -0,0 +1,66 @@
+//%jars /usr/local/bin/plantuml.jar
+
+import io.github.spencerpark.ijava.IJava;
+import net.sourceforge.plantuml.*;
+import net.sourceforge.plantuml.core.DiagramDescription;
+import java.nio.charset.Charset;
+import javax.imageio.ImageIO;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import io.github.spencerpark.ijava.IJava;
+import io.github.spencerpark.ijava.JavaKernel;
+import io.github.spencerpark.jupyter.kernel.magic.registry.UndefinedMagicException;
+
+
+/**
+Render plantUML from cell
+*/
+IJava.getKernelInstance().getMagics().registerCellMagic("plantUML", (args, body) -> {
+        //sets the results mimetype
+        if (args.size()>1) throw new Exception("Max one argument : SVG or PNG");
+        String fileFormat;
+        if (args.size()==0) fileFormat="SVG"; 
+          else fileFormat=args.get(0);    
+        
+        SourceStringReader reader = new SourceStringReader(body);
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+        DiagramDescription desc = reader.outputImage(os, new FileFormatOption(FileFormat.valueOf(fileFormat)));
+        os.close();
+        Object out;
+        if (fileFormat.equals("SVG"))
+            out = new String(os.toByteArray(), Charset.forName("UTF-8"));
+        else 
+            out= ImageIO.read(new ByteArrayInputStream(os.toByteArray()));
+        
+        display(out,fileFormat.equals("SVG")?"image/svg+xml":"image/png");
+        return out;
+        });
+
+/**
+Render plantUML from file
+*/
+IJava.getKernelInstance().getMagics().registerCellMagic("plantUMLFile", (args, body) -> {    
+    //sets the results mimetype
+    if (args.size()>1) throw new Exception("Max one argument : SVG or PNG");
+    String fileFormat;
+    if (args.size()==0) fileFormat="SVG"; 
+    else fileFormat=args.get(0);
+    
+    List<String> l = new ArrayList<>();
+
+    List<Object> outList = new ArrayList<>();
+    body.lines().forEach(filename-> {
+     Object out;        
+     try {        
+        out=cellMagic("plantUML",args,Files.readString(Paths.get(filename)));
+        //display(out,fileFormat.equals("SVG")?"image/svg+xml":"image/png");
+        outList.add(out);
+     } catch (java.io.IOException e) {}
+    });    
+    
+        return outList;
+                
+        });
+    
diff --git a/run.sh b/run.sh
index 0e587df6c79d0950ef743c5227417b9dd2ea56b3..62c17ca870c9d66a0c1e5b3ecfc7bf128b18a256 100755
--- a/run.sh
+++ b/run.sh
@@ -1,15 +1,15 @@
 #!/usr/bin/env bash
 
+WORKDIR=$HOME/JUPYTER_WORK_DIR
+
 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
 . ${DIR}/env.sh
 
 docker run --rm \
 	--name ${PWD##*/} \
-	--volume $PWD/work:/home/jovyan/work \
+	--volume $WORKDIR:/home/jovyan/work \
         --publish 8888:8888 \
         --env NB_UID=$UID \
 	--env JUPYTER_ENABLE_LAB=yes \
-	--env GRANT_SUDO=yes \
-	--env NB_GID=100 \
         ${BASE}:$SHA 
 	#--env CHOWN_HOME_OPTS='-R' --env CHOWN_HOME=yes \